|
1 | | -use anyhow::{Result, anyhow, bail}; |
| 1 | +use anyhow::{Context, Result, bail}; |
2 | 2 | use bytes::Bytes; |
3 | 3 | use futures_util::{SinkExt, StreamExt}; |
4 | 4 | use http_body_util::{BodyExt, Full}; |
@@ -943,11 +943,16 @@ impl ProxyService { |
943 | 943 | } |
944 | 944 | Err(err) => { |
945 | 945 | if !err.is_connect() || attempts >= max_attempts { |
946 | | - tracing::error!(?err, "Request error after {} attempts", attempts); |
947 | | - return Err(errors::UpstreamError( |
948 | | - "Failed to connect to runner. Make sure your runners are healthy and do not have any crash logs." |
949 | | - .to_string(), |
950 | | - ) |
| 946 | + tracing::error!( |
| 947 | + ?err, |
| 948 | + ?target, |
| 949 | + "Request error after {} attempts", |
| 950 | + attempts |
| 951 | + ); |
| 952 | + |
| 953 | + return Err(errors::UpstreamError(format!( |
| 954 | + "Failed to connect to runner: {err}. Make sure your runners are healthy." |
| 955 | + )) |
951 | 956 | .build()); |
952 | 957 | } else { |
953 | 958 | // Request connect error, might retry |
@@ -1058,30 +1063,37 @@ impl ProxyService { |
1058 | 1063 | req_parts: &hyper::http::request::Parts, |
1059 | 1064 | target: &RouteTarget, |
1060 | 1065 | ) -> Result<hyper::http::request::Builder> { |
1061 | | - // Build the target URI using the url crate to properly handle IPv6 addresses |
1062 | | - let mut url = Url::parse("http://example.com")?; |
| 1066 | + let scheme = if target.port == 443 { "https" } else { "http" }; |
1063 | 1067 |
|
1064 | | - // Wrap IPv6 addresses in brackets if not already wrapped |
| 1068 | + // Bracket raw IPv6 hosts |
1065 | 1069 | let host = if target.host.contains(':') && !target.host.starts_with('[') { |
1066 | 1070 | format!("[{}]", target.host) |
1067 | 1071 | } else { |
1068 | 1072 | target.host.clone() |
1069 | 1073 | }; |
1070 | 1074 |
|
1071 | | - url.set_host(Some(&host)) |
1072 | | - .map_err(|_| anyhow!("Failed to set host: {}", host))?; |
1073 | | - url.set_port(Some(target.port)) |
1074 | | - .map_err(|_| anyhow!("Failed to set port"))?; |
1075 | | - url.set_path(&target.path); |
1076 | | - let uri = url.to_string(); |
| 1075 | + // Ensure path starts with a leading slash |
| 1076 | + let path = if target.path.starts_with('/') { |
| 1077 | + target.path.clone() |
| 1078 | + } else { |
| 1079 | + format!("/{}", target.path) |
| 1080 | + }; |
| 1081 | + |
| 1082 | + let url = Url::parse(&format!("{scheme}://{host}:{}{}", target.port, path)) |
| 1083 | + .context("invalid scheme/host/port when building URL")?; |
1077 | 1084 |
|
| 1085 | + // Build the proxied request |
1078 | 1086 | let mut builder = hyper::Request::builder() |
1079 | 1087 | .method(req_parts.method.clone()) |
1080 | | - .uri(&uri); |
| 1088 | + .uri(url.to_string()); |
1081 | 1089 |
|
1082 | 1090 | // Add proxy headers |
1083 | | - let headers = builder.headers_mut().unwrap(); |
1084 | | - add_proxy_headers_with_addr(headers, &req_parts.headers, self.remote_addr)?; |
| 1091 | + { |
| 1092 | + let headers = builder |
| 1093 | + .headers_mut() |
| 1094 | + .expect("request builder unexpectedly in error state"); |
| 1095 | + add_proxy_headers_with_addr(headers, &req_parts.headers, self.remote_addr)?; |
| 1096 | + } |
1085 | 1097 |
|
1086 | 1098 | Ok(builder) |
1087 | 1099 | } |
|
0 commit comments