Parse bracketed IPv6 file endpoints
ci / test (push) Waiting to run
ci / fuzz-smoke (push) Waiting to run
ci / windows-client (push) Waiting to run
ci / package-release (linux-x86_64, ubuntu-latest) (push) Waiting to run
ci / package-release (macos-aarch64, macos-14) (push) Waiting to run
ci / package-release (macos-x86_64, macos-13) (push) Waiting to run
ci / package-release (windows-x86_64, windows-latest) (push) Waiting to run
ci / publish-gitea-release (push) Blocked by required conditions
ci / remote-bench (push) Waiting to run
ci / test (push) Waiting to run
ci / fuzz-smoke (push) Waiting to run
ci / windows-client (push) Waiting to run
ci / package-release (linux-x86_64, ubuntu-latest) (push) Waiting to run
ci / package-release (macos-aarch64, macos-14) (push) Waiting to run
ci / package-release (macos-x86_64, macos-13) (push) Waiting to run
ci / package-release (windows-x86_64, windows-latest) (push) Waiting to run
ci / publish-gitea-release (push) Blocked by required conditions
ci / remote-bench (push) Waiting to run
This commit is contained in:
+31
-17
@@ -9600,23 +9600,24 @@ mod tests {
|
||||
input_matches_escape, is_local_status_target, is_resume_response_for_client,
|
||||
latest_release_download_url, load_first_native_identity_with_prompt,
|
||||
native_proxy_udp_warning, newest_client_trace_path_from, parse_dynamic_forward,
|
||||
parse_escape_key, parse_local_forward, parse_remote_forward, parse_ssh_config,
|
||||
parse_trace_line, parse_trace_options, parse_trace_report_options, parse_trace_summary,
|
||||
parse_update_options, post_submit_hold_duration, queue_pending_user_input,
|
||||
queue_stale_pending_user_input, raw_contains_host_table, recv_response_until,
|
||||
refresh_live_addr, release_tag_download_url, release_tag_from_effective_url,
|
||||
release_version_from_tag, render_status_clear, render_status_overlay, requested_env,
|
||||
resolved_startup_command, retire_stream_state, retransmit_stream_opens,
|
||||
rewrite_forward_command, sanitize_trace_name, selected_predict_mode, selected_udp_host,
|
||||
server_version_mismatch, should_flush_terminal_input_after_contact,
|
||||
should_health_log_client_start, should_hold_during_startup_gate,
|
||||
should_hold_post_submit_input, should_reconnect_before_input_for_local_sleep,
|
||||
should_repaint_idle_terminal, should_strip_unowned_terminal_reports,
|
||||
split_after_command_submit, split_trace_tokens, ssh_command_target, ssh_config_uses_proxy,
|
||||
ssh_destination_host, ssh_username, ssh_with_user, startup_command, status_ssh_target,
|
||||
strip_stale_mouse_reports, strip_terminal_focus_reports, strip_unowned_terminal_reports,
|
||||
summarize_trace_file, summarize_trace_file_with_mode, terminal_private_mode_transition,
|
||||
toml_bare_key_or_quoted, top_trace_events, trace_report_warnings, unix_update_script,
|
||||
parse_escape_key, parse_local_forward, parse_remote_forward, parse_single_remote_path,
|
||||
parse_ssh_config, parse_trace_line, parse_trace_options, parse_trace_report_options,
|
||||
parse_trace_summary, parse_update_options, post_submit_hold_duration,
|
||||
queue_pending_user_input, queue_stale_pending_user_input, raw_contains_host_table,
|
||||
recv_response_until, refresh_live_addr, release_tag_download_url,
|
||||
release_tag_from_effective_url, release_version_from_tag, render_status_clear,
|
||||
render_status_overlay, requested_env, resolved_startup_command, retire_stream_state,
|
||||
retransmit_stream_opens, rewrite_forward_command, sanitize_trace_name,
|
||||
selected_predict_mode, selected_udp_host, server_version_mismatch,
|
||||
should_flush_terminal_input_after_contact, should_health_log_client_start,
|
||||
should_hold_during_startup_gate, should_hold_post_submit_input,
|
||||
should_reconnect_before_input_for_local_sleep, should_repaint_idle_terminal,
|
||||
should_strip_unowned_terminal_reports, split_after_command_submit, split_trace_tokens,
|
||||
ssh_command_target, ssh_config_uses_proxy, ssh_destination_host, ssh_username,
|
||||
ssh_with_user, startup_command, status_ssh_target, strip_stale_mouse_reports,
|
||||
strip_terminal_focus_reports, strip_unowned_terminal_reports, summarize_trace_file,
|
||||
summarize_trace_file_with_mode, terminal_private_mode_transition, toml_bare_key_or_quoted,
|
||||
top_trace_events, trace_report_warnings, unix_update_script,
|
||||
update_binary_version_for_installer, update_installer_url, update_version_status,
|
||||
upsert_managed_block, valid_forward_host, vscode_safe_alias, wake_repaint_retry_deadline,
|
||||
windows_update_script,
|
||||
@@ -11709,6 +11710,19 @@ mod tests {
|
||||
assert!(valid_forward_host("server.example.com"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_remote_path_accepts_bracketed_ipv6_hosts() {
|
||||
assert_eq!(
|
||||
parse_single_remote_path("[2001:db8::1]:/tmp/file", "cat").unwrap(),
|
||||
("2001:db8::1".to_string(), "/tmp/file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_single_remote_path("[::1]:", "ls").unwrap(),
|
||||
("::1".to_string(), ".".to_string())
|
||||
);
|
||||
assert!(parse_single_remote_path("[::1]", "ls").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recover_removes_only_matching_cached_credentials() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
|
||||
@@ -165,6 +165,12 @@ pub fn parse_copy_endpoint(raw: &str) -> CopyEndpoint {
|
||||
if looks_like_windows_path(raw) {
|
||||
return CopyEndpoint::Local(PathBuf::from(raw));
|
||||
}
|
||||
if let Some((host, path)) = parse_bracketed_remote_endpoint(raw) {
|
||||
return CopyEndpoint::Remote { host, path };
|
||||
}
|
||||
if raw.starts_with('[') {
|
||||
return CopyEndpoint::Local(PathBuf::from(raw));
|
||||
}
|
||||
let Some(index) = raw.find(':') else {
|
||||
return CopyEndpoint::Local(PathBuf::from(raw));
|
||||
};
|
||||
@@ -183,6 +189,25 @@ pub fn parse_copy_endpoint(raw: &str) -> CopyEndpoint {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bracketed_remote_endpoint(raw: &str) -> Option<(String, String)> {
|
||||
let rest = raw.strip_prefix('[')?;
|
||||
let close = rest.find(']')?;
|
||||
let host = &rest[..close];
|
||||
let suffix = &rest[close + 1..];
|
||||
if host.is_empty() || host.contains('/') || host.contains('\\') || !suffix.starts_with(':') {
|
||||
return None;
|
||||
}
|
||||
let path = &suffix[1..];
|
||||
Some((
|
||||
host.to_string(),
|
||||
if path.is_empty() {
|
||||
".".to_string()
|
||||
} else {
|
||||
path.to_string()
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum CopyEndpoint {
|
||||
Local(PathBuf),
|
||||
@@ -277,4 +302,30 @@ mod tests {
|
||||
CopyEndpoint::Local(PathBuf::from("C:\\Users\\palav\\x"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_endpoint_parses_bracketed_ipv6_remote_paths() {
|
||||
assert_eq!(
|
||||
parse_copy_endpoint("[2001:db8::1]:/var/log/syslog"),
|
||||
CopyEndpoint::Remote {
|
||||
host: "2001:db8::1".to_string(),
|
||||
path: "/var/log/syslog".to_string()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_copy_endpoint("[::1]:"),
|
||||
CopyEndpoint::Remote {
|
||||
host: "::1".to_string(),
|
||||
path: ".".to_string()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_copy_endpoint("[bad/host]:path"),
|
||||
CopyEndpoint::Local(PathBuf::from("[bad/host]:path"))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_copy_endpoint("[::1]"),
|
||||
CopyEndpoint::Local(PathBuf::from("[::1]"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user