mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-23 19:12:06 +03:00
Support multiple Content-Encoding
This commit is contained in:
parent
9617cba31d
commit
1464a5d908
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -25,3 +25,10 @@ Content-Length: 17
|
||||
Content-Encoding: br
|
||||
Content-Type: text/html; charset=utf-8
|
||||
```Hello World!```
|
||||
|
||||
GET http://localhost:8000/compressed/brotli_identity
|
||||
HTTP/1.0 200
|
||||
Content-Length: 17
|
||||
Content-Encoding: br, identity
|
||||
Content-Type: text/html; charset=utf-8
|
||||
```Hello World!```
|
@ -30,6 +30,17 @@ def compressed_brotli():
|
||||
resp.headers['Content-Encoding'] = 'br'
|
||||
return resp
|
||||
|
||||
|
||||
@app.route("/compressed/brotli_identity")
|
||||
def compressed_brotli_identity():
|
||||
result = BytesIO()
|
||||
|
||||
result.write(b'\x21\x2c\x00\x04\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x03')
|
||||
data = result.getvalue()
|
||||
resp = make_response(data)
|
||||
resp.headers['Content-Encoding'] = 'br, identity'
|
||||
return resp
|
||||
|
||||
@app.route("/compressed/none")
|
||||
def compressed_none():
|
||||
return 'Hello World!'
|
7
integration/tests/error_assert_content_encoding.err
Normal file
7
integration/tests/error_assert_content_encoding.err
Normal file
@ -0,0 +1,7 @@
|
||||
error: Decompression Error
|
||||
--> tests/error_assert_content_encoding.hurl:4:1
|
||||
|
|
||||
4 | ```Hello World!```
|
||||
| ^ Compression unknown is not supported
|
||||
|
|
||||
|
1
integration/tests/error_assert_content_encoding.exit
Normal file
1
integration/tests/error_assert_content_encoding.exit
Normal file
@ -0,0 +1 @@
|
||||
4
|
4
integration/tests/error_assert_content_encoding.hurl
Normal file
4
integration/tests/error_assert_content_encoding.hurl
Normal file
@ -0,0 +1,4 @@
|
||||
# Return an unsupported content encoding
|
||||
GET http://localhost:8000/error/content-encoding
|
||||
HTTP/1.0 200
|
||||
```Hello World!```
|
7
integration/tests/error_assert_content_encoding.py
Normal file
7
integration/tests/error_assert_content_encoding.py
Normal file
@ -0,0 +1,7 @@
|
||||
from tests import app
|
||||
from flask import Response
|
||||
|
||||
@app.route("/error/content-encoding")
|
||||
def error_assert_content_encoding():
|
||||
headers = {'Content-Encoding': 'unknown'}
|
||||
return Response('Hello', headers=headers)
|
@ -1,7 +1,7 @@
|
||||
error: Decompression Error
|
||||
--> tests/error_assert_decompress.hurl:1:1
|
||||
--> tests/error_assert_decompress.hurl:3:1
|
||||
|
|
||||
1 | GET http://localhost:8000/error-assert-decompress
|
||||
3 | ```Hello World!```
|
||||
| ^ Could not uncompress response with gzip
|
||||
|
|
||||
|
||||
|
@ -34,31 +34,49 @@ pub enum Encoding {
|
||||
Identity,
|
||||
}
|
||||
|
||||
impl Encoding {
|
||||
pub fn parse(s: &str) -> Result<Encoding, RunnerError> {
|
||||
match s {
|
||||
"br" => Ok(Encoding::Brotli),
|
||||
"gzip" => Ok(Encoding::Gzip),
|
||||
"deflate" => Ok(Encoding::Deflate),
|
||||
"identity" => Ok(Encoding::Identity),
|
||||
v => Err(RunnerError::UnsupportedContentEncoding(v.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(&self, data: &[u8]) -> Result<Vec<u8>, RunnerError> {
|
||||
match self {
|
||||
Encoding::Identity => Ok(data.to_vec()),
|
||||
Encoding::Gzip => uncompress_gzip(&data[..]),
|
||||
Encoding::Deflate => uncompress_zlib(&data[..]),
|
||||
Encoding::Brotli => uncompress_brotli(&data[..]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl http::Response {
|
||||
fn content_encoding(&self) -> Result<Option<Encoding>, RunnerError> {
|
||||
fn content_encoding(&self) -> Result<Vec<Encoding>, RunnerError> {
|
||||
for header in self.headers.clone() {
|
||||
if header.name.as_str().to_ascii_lowercase() == "content-encoding" {
|
||||
return match header.value.as_str() {
|
||||
"br" => Ok(Some(Encoding::Brotli)),
|
||||
"gzip" => Ok(Some(Encoding::Gzip)),
|
||||
"deflate" => Ok(Some(Encoding::Deflate)),
|
||||
"identity" => Ok(Some(Encoding::Identity)),
|
||||
v => Err(RunnerError::UnsupportedContentEncoding(v.to_string())),
|
||||
};
|
||||
let mut encodings = vec![];
|
||||
for value in header.value.as_str().split(',') {
|
||||
let encoding = Encoding::parse(value.trim())?;
|
||||
encodings.push(encoding);
|
||||
}
|
||||
return Ok(encodings);
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
pub fn uncompress_body(&self) -> Result<Vec<u8>, RunnerError> {
|
||||
let encoding = self.content_encoding()?;
|
||||
match encoding {
|
||||
Some(Encoding::Identity) => Ok(self.body.clone()),
|
||||
Some(Encoding::Gzip) => uncompress_gzip(&self.body[..]),
|
||||
Some(Encoding::Deflate) => uncompress_zlib(&self.body[..]),
|
||||
Some(Encoding::Brotli) => uncompress_brotli(&self.body[..]),
|
||||
None => Ok(self.body.clone()),
|
||||
let encodings = self.content_encoding()?;
|
||||
let mut data = self.body.clone();
|
||||
for encoding in encodings {
|
||||
data = encoding.decode(&data)?
|
||||
}
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +122,15 @@ fn uncompress_zlib(data: &[u8]) -> Result<Vec<u8>, RunnerError> {
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_encoding() {
|
||||
assert_eq!(Encoding::parse("br").unwrap(), Encoding::Brotli);
|
||||
assert_eq!(
|
||||
Encoding::parse("xx").err().unwrap(),
|
||||
RunnerError::UnsupportedContentEncoding("xx".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_content_encoding() {
|
||||
let response = http::Response {
|
||||
@ -112,7 +139,7 @@ pub mod tests {
|
||||
headers: vec![],
|
||||
body: vec![],
|
||||
};
|
||||
assert_eq!(response.content_encoding().unwrap(), None);
|
||||
assert_eq!(response.content_encoding().unwrap(), vec![]);
|
||||
|
||||
let response = http::Response {
|
||||
version: http::Version::Http10,
|
||||
@ -137,9 +164,23 @@ pub mod tests {
|
||||
}],
|
||||
body: vec![],
|
||||
};
|
||||
assert_eq!(response.content_encoding().unwrap(), vec![Encoding::Brotli]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_content_encoding() {
|
||||
let response = http::Response {
|
||||
version: http::Version::Http10,
|
||||
status: 200,
|
||||
headers: vec![http::Header {
|
||||
name: "Content-Encoding".to_string(),
|
||||
value: "br, identity".to_string(),
|
||||
}],
|
||||
body: vec![],
|
||||
};
|
||||
assert_eq!(
|
||||
response.content_encoding().unwrap().unwrap(),
|
||||
Encoding::Brotli
|
||||
response.content_encoding().unwrap(),
|
||||
vec![Encoding::Brotli, Encoding::Identity]
|
||||
);
|
||||
}
|
||||
|
||||
@ -159,6 +200,20 @@ pub mod tests {
|
||||
};
|
||||
assert_eq!(response.uncompress_body().unwrap(), b"Hello World!");
|
||||
|
||||
let response = http::Response {
|
||||
version: http::Version::Http10,
|
||||
status: 200,
|
||||
headers: vec![http::Header {
|
||||
name: "Content-Encoding".to_string(),
|
||||
value: "br, identity".to_string(),
|
||||
}],
|
||||
body: vec![
|
||||
0x21, 0x2c, 0x00, 0x04, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x21,
|
||||
],
|
||||
};
|
||||
assert_eq!(response.uncompress_body().unwrap(), b"Hello World!");
|
||||
|
||||
let response = http::Response {
|
||||
version: http::Version::Http10,
|
||||
status: 200,
|
||||
|
@ -115,8 +115,8 @@ impl Response {
|
||||
Ok(s) => Ok(Value::String(s)),
|
||||
Err(e) => Err(Error {
|
||||
source_info: SourceInfo {
|
||||
start: Pos { line: 1, column: 1 },
|
||||
end: Pos { line: 1, column: 1 },
|
||||
start: body.space0.source_info.end.clone(),
|
||||
end: body.space0.source_info.end.clone(),
|
||||
},
|
||||
inner: e,
|
||||
assert: true,
|
||||
@ -134,8 +134,8 @@ impl Response {
|
||||
Ok(s) => Ok(Value::String(s)),
|
||||
Err(e) => Err(Error {
|
||||
source_info: SourceInfo {
|
||||
start: Pos { line: 1, column: 1 },
|
||||
end: Pos { line: 1, column: 1 },
|
||||
start: body.space0.source_info.end.clone(),
|
||||
end: body.space0.source_info.end.clone(),
|
||||
},
|
||||
inner: e,
|
||||
assert: true,
|
||||
@ -156,8 +156,8 @@ impl Response {
|
||||
Ok(s) => Ok(Value::String(s)),
|
||||
Err(e) => Err(Error {
|
||||
source_info: SourceInfo {
|
||||
start: Pos { line: 1, column: 1 },
|
||||
end: Pos { line: 1, column: 1 },
|
||||
start: body.space0.source_info.end.clone(),
|
||||
end: body.space0.source_info.end.clone(),
|
||||
},
|
||||
inner: e,
|
||||
assert: true,
|
||||
|
Loading…
Reference in New Issue
Block a user