Skip to content

Commit

Permalink
Parse accept header with quotes (#338)
Browse files Browse the repository at this point in the history
* Parse accept header with quotes

* cargo fmt

* minimum mime version

* commit suggestion

* cargo fmt

* Rework tests

* cargo fmt
  • Loading branch information
82marbag authored Apr 26, 2023
1 parent 8f02848 commit d22f200
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 18 deletions.
2 changes: 1 addition & 1 deletion tower-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async-compression = { version = "0.3", optional = true, features = ["tokio"] }
base64 = { version = "0.20", optional = true }
http-range-header = "0.3.0"
iri-string = { version = "0.7.0", optional = true }
mime = { version = "0.3", optional = true, default_features = false }
mime = { version = "0.3.17", optional = true, default_features = false }
mime_guess = { version = "2", optional = true, default_features = false }
percent-encoding = { version = "2.1.0", optional = true }
tokio = { version = "1.6", optional = true, default_features = false }
Expand Down
67 changes: 50 additions & 17 deletions tower-http/src/validate_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@

use http::{header, Request, Response, StatusCode};
use http_body::Body;
use mime::Mime;
use mime::{Mime, MimeIter};
use pin_project_lite::pin_project;
use std::{
fmt,
Expand Down Expand Up @@ -379,25 +379,24 @@ where
.headers()
.get_all(header::ACCEPT)
.into_iter()
.flat_map(|header| {
header
.to_str()
.ok()
.into_iter()
.flat_map(|s| s.split(",").map(|typ| typ.trim()))
})
.filter_map(|header| header.to_str().ok())
.any(|h| {
h.parse::<Mime>()
MimeIter::new(&h)
.map(|mim| {
let typ = self.header_value.type_();
let subtype = self.header_value.subtype();
match (mim.type_(), mim.subtype()) {
(t, s) if t == typ && s == subtype => true,
(t, mime::STAR) if t == typ => true,
(mime::STAR, mime::STAR) => true,
_ => false,
if let Ok(mim) = mim {
let typ = self.header_value.type_();
let subtype = self.header_value.subtype();
match (mim.type_(), mim.subtype()) {
(t, s) if t == typ && s == subtype => true,
(t, mime::STAR) if t == typ => true,
(mime::STAR, mime::STAR) => true,
_ => false,
}
} else {
false
}
})
.reduce(|acc, mim| acc || mim)
.unwrap_or(false)
})
{
Expand All @@ -413,7 +412,7 @@ where
mod tests {
#[allow(unused_imports)]
use super::*;
use http::header;
use http::{header, StatusCode};
use hyper::Body;
use tower::{BoxError, ServiceBuilder, ServiceExt};

Expand Down Expand Up @@ -545,6 +544,40 @@ mod tests {
assert_eq!(res.status(), StatusCode::OK);
}

#[tokio::test]
async fn accepted_header_with_quotes_valid() {
let value = "foo/bar; parisien=\"baguette, text/html, jambon, fromage\", application/*";
let mut service = ServiceBuilder::new()
.layer(ValidateRequestHeaderLayer::accept("application/xml"))
.service_fn(echo);

let request = Request::get("/")
.header(header::ACCEPT, value)
.body(Body::empty())
.unwrap();

let res = service.ready().await.unwrap().call(request).await.unwrap();

assert_eq!(res.status(), StatusCode::OK);
}

#[tokio::test]
async fn accepted_header_with_quotes_invalid() {
let value = "foo/bar; parisien=\"baguette, text/html, jambon, fromage\"";
let mut service = ServiceBuilder::new()
.layer(ValidateRequestHeaderLayer::accept("text/html"))
.service_fn(echo);

let request = Request::get("/")
.header(header::ACCEPT, value)
.body(Body::empty())
.unwrap();

let res = service.ready().await.unwrap().call(request).await.unwrap();

assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
}

async fn echo(req: Request<Body>) -> Result<Response<Body>, BoxError> {
Ok(Response::new(req.into_body()))
}
Expand Down

0 comments on commit d22f200

Please sign in to comment.