Skip to content

Commit

Permalink
Allow setting raw path in request
Browse files Browse the repository at this point in the history
Also fix an issue where a new uri using set_uri may not be used if the
raw_path_fallback was also in use.
  • Loading branch information
drcaramelsyrup authored and eaufavor committed Jan 31, 2025
1 parent 3ea78a8 commit e6b823c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .bleep
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d7f2b1ec2803e6fcabceea6ddbaac023585cacb2
f11c835e139cb0a0468183e2af3b142742794d7b
61 changes: 43 additions & 18 deletions pingora-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,7 @@ impl RequestHeader {
req.base.method = method
.try_into()
.explain_err(InvalidHTTPHeader, |_| "invalid method")?;
if let Ok(p) = std::str::from_utf8(path) {
let uri = Uri::builder()
.path_and_query(p)
.build()
.explain_err(InvalidHTTPHeader, |_| format!("invalid uri {}", p))?;
req.base.uri = uri;
// keep raw_path empty, no need to store twice
} else {
// put a valid utf-8 path into base for read only access
let lossy_str = String::from_utf8_lossy(path);
let uri = Uri::builder()
.path_and_query(lossy_str.as_ref())
.build()
.explain_err(InvalidHTTPHeader, |_| format!("invalid uri {}", lossy_str))?;
req.base.uri = uri;
req.raw_path_fallback = path.to_vec();
}

req.set_raw_path(path)?;
Ok(req)
}

Expand Down Expand Up @@ -212,6 +195,34 @@ impl RequestHeader {
/// Set the request URI
pub fn set_uri(&mut self, uri: http::Uri) {
self.base.uri = uri;
// Clear out raw_path_fallback, or it will be used when serializing
self.raw_path_fallback = vec![];
}

/// Set the request URI directly via raw bytes.
///
/// Generally prefer [Self::set_uri()] to modify the header's URI if able.
///
/// This API is to allow supporting non UTF-8 cases.
pub fn set_raw_path(&mut self, path: &[u8]) -> Result<()> {
if let Ok(p) = std::str::from_utf8(path) {
let uri = Uri::builder()
.path_and_query(p)
.build()
.explain_err(InvalidHTTPHeader, |_| format!("invalid uri {}", p))?;
self.base.uri = uri;
// keep raw_path empty, no need to store twice
} else {
// put a valid utf-8 path into base for read only access
let lossy_str = String::from_utf8_lossy(path);
let uri = Uri::builder()
.path_and_query(lossy_str.as_ref())
.build()
.explain_err(InvalidHTTPHeader, |_| format!("invalid uri {}", lossy_str))?;
self.base.uri = uri;
self.raw_path_fallback = path.to_vec();
}
Ok(())
}

/// Set whether we send an END_STREAM on H2 request HEADERS if body is empty.
Expand Down Expand Up @@ -722,6 +733,20 @@ mod tests {
assert_eq!(raw_path, req.raw_path());
}

#[cfg(feature = "patched_http1")]
#[test]
fn test_override_invalid_path() {
let raw_path = b"Hello\xF0\x90\x80World";
let mut req = RequestHeader::build("GET", &raw_path[..], None).unwrap();
assert_eq!("Hello�World", req.uri.path_and_query().unwrap());
assert_eq!(raw_path, req.raw_path());

let new_path = "/HelloWorld";
req.set_uri(Uri::builder().path_and_query(new_path).build().unwrap());
assert_eq!(new_path, req.uri.path_and_query().unwrap());
assert_eq!(new_path.as_bytes(), req.raw_path());
}

#[test]
fn test_reason_phrase() {
let mut resp = ResponseHeader::new(None);
Expand Down

0 comments on commit e6b823c

Please # to comment.