Skip to content

Commit 2c029e6

Browse files
committed
Fix request pseudo-header construction for CONNECT & OPTION methods
CONNECT & OPTIONS request has special requirements regarding :path & :scheme pseudo-header which were not met. Construction of pseudo-header was fixed to not include :path & :scheme fields for CONNECT method. Empty :path field for OPTIONS requests now translates to '*' value sent in :path field. CONNECT request changes were tested against server based on hyper 1.2.
1 parent e2168de commit 2c029e6

File tree

1 file changed

+28
-16
lines changed

1 file changed

+28
-16
lines changed

src/frame/headers.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -554,32 +554,44 @@ impl Pseudo {
554554
pub fn request(method: Method, uri: Uri, protocol: Option<Protocol>) -> Self {
555555
let parts = uri::Parts::from(uri);
556556

557-
let mut path = parts
558-
.path_and_query
559-
.map(|v| BytesStr::from(v.as_str()))
560-
.unwrap_or(BytesStr::from_static(""));
561-
562-
match method {
563-
Method::OPTIONS | Method::CONNECT => {}
564-
_ if path.is_empty() => {
565-
path = BytesStr::from_static("/");
566-
}
567-
_ => {}
568-
}
557+
let (scheme, path) = if method == Method::CONNECT {
558+
// CONNECT requests MUST NOT include :scheme & :path pseudo-header fields
559+
// See: https://datatracker.ietf.org/doc/html/rfc9113#section-8.5
560+
(None, None)
561+
} else {
562+
let path = parts
563+
.path_and_query
564+
.map(|v| BytesStr::from(v.as_str()))
565+
.unwrap_or(BytesStr::from_static(""));
566+
567+
let path = if !path.is_empty() {
568+
path
569+
} else {
570+
if method == Method::OPTIONS {
571+
// An OPTIONS request for an "http" or "https" URI that does not include a path component;
572+
// these MUST include a ":path" pseudo-header field with a value of '*' (see Section 7.1 of [HTTP]).
573+
// See: https://datatracker.ietf.org/doc/html/rfc9113#section-8.3.1
574+
// TODO: Validate URI is "http" or "https".
575+
BytesStr::from_static("*")
576+
} else {
577+
BytesStr::from_static("/")
578+
}
579+
};
580+
581+
(parts.scheme, Some(path).filter(|p| !p.is_empty()))
582+
};
569583

570584
let mut pseudo = Pseudo {
571585
method: Some(method),
572586
scheme: None,
573587
authority: None,
574-
path: Some(path).filter(|p| !p.is_empty()),
588+
path,
575589
protocol,
576590
status: None,
577591
};
578592

579593
// If the URI includes a scheme component, add it to the pseudo headers
580-
//
581-
// TODO: Scheme must be set...
582-
if let Some(scheme) = parts.scheme {
594+
if let Some(scheme) = scheme {
583595
pseudo.set_scheme(scheme);
584596
}
585597

0 commit comments

Comments
 (0)