mirror of
https://github.com/servo/servo.git
synced 2025-07-22 14:53:49 +01:00
Adds tests for gzip/deflate response decoding
This commit is contained in:
parent
6064ee8756
commit
2eaac7e3f9
5 changed files with 112 additions and 59 deletions
|
@ -110,9 +110,6 @@ fn load_for_consumer(load_data: LoadData,
|
|||
Err(LoadError::MaxRedirects(url)) => {
|
||||
send_error(url, "too many redirects".to_string(), start_chan)
|
||||
}
|
||||
Err(LoadError::UnsupportedContentEncodings(url)) => {
|
||||
send_error(url, "no valid content encodings supported".to_string(), start_chan)
|
||||
}
|
||||
Err(LoadError::Cors(url, msg)) |
|
||||
Err(LoadError::InvalidRedirect(url, msg)) |
|
||||
Err(LoadError::Decoding(url, msg)) => {
|
||||
|
@ -139,6 +136,23 @@ pub trait HttpResponse: Read {
|
|||
fn headers(&self) -> &Headers;
|
||||
fn status(&self) -> StatusCode;
|
||||
fn status_raw(&self) -> &RawStatus;
|
||||
|
||||
fn content_encoding(&self) -> Option<Encoding> {
|
||||
match self.headers().get::<ContentEncoding>() {
|
||||
Some(&ContentEncoding(ref encodings)) => {
|
||||
if encodings.contains(&Encoding::Gzip) {
|
||||
Some(Encoding::Gzip)
|
||||
} else if encodings.contains(&Encoding::Deflate) {
|
||||
Some(Encoding::Deflate)
|
||||
} else {
|
||||
// TODO: Is this the correct behaviour?
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WrappedHttpResponse {
|
||||
|
@ -268,8 +282,7 @@ pub enum LoadError {
|
|||
Ssl(Url, String),
|
||||
InvalidRedirect(Url, String),
|
||||
Decoding(Url, String),
|
||||
MaxRedirects(Url),
|
||||
UnsupportedContentEncodings(Url)
|
||||
MaxRedirects(Url)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -357,6 +370,7 @@ pub struct LoadResponse<R: HttpResponse> {
|
|||
pub metadata: Metadata
|
||||
}
|
||||
|
||||
|
||||
impl<R: HttpResponse> Read for LoadResponse<R> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
|
@ -372,6 +386,29 @@ impl<R: HttpResponse> LoadResponse<R> {
|
|||
fn new(m: Metadata, d: Decoders<R>) -> LoadResponse<R> {
|
||||
LoadResponse { metadata: m, decoder: d }
|
||||
}
|
||||
|
||||
fn from_http_response(response: R, m: Metadata) -> Result<LoadResponse<R>, LoadError> {
|
||||
match response.content_encoding() {
|
||||
Some(Encoding::Gzip) => {
|
||||
let result = GzDecoder::new(response);
|
||||
match result {
|
||||
Ok(response_decoding) => {
|
||||
return Ok(LoadResponse::new(m, Decoders::Gzip(response_decoding)));
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(LoadError::Decoding(m.final_url, err.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Encoding::Deflate) => {
|
||||
let response_decoding = DeflateDecoder::new(response);
|
||||
return Ok(LoadResponse::new(m, Decoders::Deflate(response_decoding)));
|
||||
}
|
||||
_ => {
|
||||
return Ok(LoadResponse::new(m, Decoders::Plain(response)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Decoders<R: Read> {
|
||||
|
@ -578,42 +615,7 @@ pub fn load<A>(mut load_data: LoadData,
|
|||
net_event_response))).unwrap();
|
||||
}
|
||||
|
||||
let selected_content_encoding = match response.headers().get::<ContentEncoding>() {
|
||||
Some(&ContentEncoding(ref encodings)) => {
|
||||
if encodings.contains(&Encoding::Gzip) {
|
||||
Some(Encoding::Gzip)
|
||||
} else if encodings.contains(&Encoding::Deflate) {
|
||||
Some(Encoding::Deflate)
|
||||
} else {
|
||||
return Err(LoadError::UnsupportedContentEncodings(url.clone()))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
match selected_content_encoding {
|
||||
Some(Encoding::Gzip) => {
|
||||
let result = GzDecoder::new(response);
|
||||
match result {
|
||||
Ok(response_decoding) => {
|
||||
return Ok(LoadResponse::new(metadata, Decoders::Gzip(response_decoding)));
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(LoadError::Decoding(metadata.final_url, err.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Encoding::Deflate) => {
|
||||
let response_decoding = DeflateDecoder::new(response);
|
||||
return Ok(LoadResponse::new(metadata, Decoders::Deflate(response_decoding)));
|
||||
}
|
||||
None => {
|
||||
return Ok(LoadResponse::new(metadata, Decoders::Plain(response)));
|
||||
}
|
||||
_ => return Err(LoadError::UnsupportedContentEncodings(url.clone()))
|
||||
}
|
||||
return LoadResponse::from_http_response(response, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -1053,6 +1053,7 @@ name = "net_tests"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"cookie 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"net 0.0.1",
|
||||
|
|
|
@ -25,3 +25,4 @@ cookie = "0.1"
|
|||
hyper = "0.6"
|
||||
url = "0.2"
|
||||
time = "0.1"
|
||||
flate2 = "0.2.0"
|
||||
|
|
|
@ -12,18 +12,19 @@ use hyper::method::Method;
|
|||
use hyper::http::RawStatus;
|
||||
use hyper::status::StatusCode;
|
||||
use hyper::header::{Headers, Location, ContentLength};
|
||||
use std::io::{self, Read};
|
||||
use std::cmp::{self};
|
||||
use std::io::{self, Write, Read, Cursor};
|
||||
use flate2::write::{GzEncoder, DeflateEncoder};
|
||||
use flate2::Compression;
|
||||
use std::borrow::Cow;
|
||||
|
||||
fn respond_with(body: Vec<u8>) -> MockResponse {
|
||||
let mut headers = Headers::new();
|
||||
headers.set(ContentLength(body.len() as u64));
|
||||
|
||||
respond_with_headers(body, headers)
|
||||
respond_with_headers(body, &mut headers)
|
||||
}
|
||||
|
||||
fn respond_with_headers(body: Vec<u8>, headers: Headers) -> MockResponse {
|
||||
fn respond_with_headers(body: Vec<u8>, headers: &mut Headers) -> MockResponse {
|
||||
headers.set(ContentLength(body.len() as u64));
|
||||
|
||||
MockResponse::new(
|
||||
headers.clone(),
|
||||
StatusCode::Ok,
|
||||
|
@ -40,7 +41,7 @@ fn read_response(reader: &mut Read) -> String {
|
|||
String::from_utf8(buf).unwrap()
|
||||
},
|
||||
Ok(_) => "".to_string(),
|
||||
_ => panic!("problem reading response")
|
||||
Err(e) => panic!("problem reading response {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,23 +49,18 @@ struct MockResponse {
|
|||
h: Headers,
|
||||
sc: StatusCode,
|
||||
sr: RawStatus,
|
||||
msg: Vec<u8>
|
||||
msg: Cursor<Vec<u8>>
|
||||
}
|
||||
|
||||
impl MockResponse {
|
||||
fn new(h: Headers, sc: StatusCode, sr: RawStatus, msg: Vec<u8>) -> MockResponse {
|
||||
MockResponse { h: h, sc: sc, sr: sr, msg: msg }
|
||||
MockResponse { h: h, sc: sc, sr: sr, msg: Cursor::new(msg) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for MockResponse {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let buf_len = buf.len();
|
||||
for (a, b) in buf.iter_mut().zip(&self.msg[0 .. cmp::min(buf_len, self.msg.len())]) {
|
||||
*a = *b
|
||||
}
|
||||
|
||||
Ok(cmp::min(buf.len(), self.msg.len()))
|
||||
self.msg.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,8 +108,8 @@ fn response_for_request_type(t: RequestType) -> Result<MockResponse, LoadError>
|
|||
RequestType::Text(b) => {
|
||||
Ok(respond_with(b))
|
||||
},
|
||||
RequestType::WithHeaders(b, h) => {
|
||||
Ok(respond_with_headers(b, h))
|
||||
RequestType::WithHeaders(b, mut h) => {
|
||||
Ok(respond_with_headers(b, &mut h))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,6 +208,58 @@ impl HttpRequest for AssertMustHaveBodyRequest {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_should_decode_the_response_as_deflate_when_response_headers_have_content_encoding_deflate() {
|
||||
struct Factory;
|
||||
|
||||
impl HttpRequestFactory for Factory {
|
||||
type R=MockRequest;
|
||||
|
||||
fn create(&self, _: Url, _: Method) -> Result<MockRequest, LoadError> {
|
||||
let mut e = DeflateEncoder::new(Vec::new(), Compression::Default);
|
||||
e.write(b"Yay!").unwrap();
|
||||
let encoded_content = e.finish().unwrap();
|
||||
|
||||
let mut headers = Headers::new();
|
||||
headers.set_raw("Content-Encoding", vec![b"deflate".to_vec()]);
|
||||
Ok(MockRequest::new(RequestType::WithHeaders(encoded_content, headers)))
|
||||
}
|
||||
}
|
||||
|
||||
let url = Url::parse("http://mozilla.com").unwrap();
|
||||
let resource_mgr = new_resource_task(None, None);
|
||||
let load_data = LoadData::new(url.clone(), None);
|
||||
let mut response = load::<MockRequest>(load_data, resource_mgr.clone(), None, &Factory).unwrap();
|
||||
|
||||
assert_eq!(read_response(&mut response), "Yay!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_should_decode_the_response_as_gzip_when_response_headers_have_content_encoding_gzip() {
|
||||
struct Factory;
|
||||
|
||||
impl HttpRequestFactory for Factory {
|
||||
type R=MockRequest;
|
||||
|
||||
fn create(&self, _: Url, _: Method) -> Result<MockRequest, LoadError> {
|
||||
let mut e = GzEncoder::new(Vec::new(), Compression::Default);
|
||||
e.write(b"Yay!").unwrap();
|
||||
let encoded_content = e.finish().unwrap();
|
||||
|
||||
let mut headers = Headers::new();
|
||||
headers.set_raw("Content-Encoding", vec![b"gzip".to_vec()]);
|
||||
Ok(MockRequest::new(RequestType::WithHeaders(encoded_content, headers)))
|
||||
}
|
||||
}
|
||||
|
||||
let url = Url::parse("http://mozilla.com").unwrap();
|
||||
let resource_mgr = new_resource_task(None, None);
|
||||
let load_data = LoadData::new(url.clone(), None);
|
||||
let mut response = load::<MockRequest>(load_data, resource_mgr.clone(), None, &Factory).unwrap();
|
||||
|
||||
assert_eq!(read_response(&mut response), "Yay!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_doesnt_send_request_body_on_any_redirect() {
|
||||
struct Factory;
|
||||
|
@ -494,7 +542,7 @@ fn test_load_follows_a_redirect() {
|
|||
let load_data = LoadData::new(url.clone(), None);
|
||||
|
||||
match load::<MockRequest>(load_data, resource_mgr, None, &Factory) {
|
||||
Err(_) => panic!("expected to follow a redirect"),
|
||||
Err(e) => panic!("expected to follow a redirect {:?}", e),
|
||||
Ok(mut lr) => {
|
||||
let response = read_response(&mut lr);
|
||||
assert_eq!(response, "Yay!".to_string());
|
||||
|
|
|
@ -11,6 +11,7 @@ extern crate url;
|
|||
extern crate util;
|
||||
extern crate time;
|
||||
extern crate hyper;
|
||||
extern crate flate2;
|
||||
|
||||
#[cfg(test)] mod cookie;
|
||||
#[cfg(test)] mod data_loader;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue