Tests rewriting redirects of POST as GET

This commit is contained in:
Sam Gibson 2015-08-16 17:34:34 +10:00
parent 2eaac7e3f9
commit 04b7ce0afa
2 changed files with 36 additions and 7 deletions

View file

@ -417,7 +417,7 @@ enum Decoders<R: Read> {
Plain(R) Plain(R)
} }
pub fn load<A>(mut load_data: LoadData, pub fn load<A>(load_data: LoadData,
resource_mgr_chan: IpcSender<ControlMsg>, resource_mgr_chan: IpcSender<ControlMsg>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>, devtools_chan: Option<Sender<DevtoolsControlMsg>>,
request_factory: &HttpRequestFactory<R=A>) request_factory: &HttpRequestFactory<R=A>)
@ -433,6 +433,7 @@ pub fn load<A>(mut load_data: LoadData,
// specified in the hosts file. // specified in the hosts file.
let mut url = replace_hosts(&load_data.url); let mut url = replace_hosts(&load_data.url);
let mut redirected_to = HashSet::new(); let mut redirected_to = HashSet::new();
let mut method = load_data.method.clone();
// If the URL is a view-source scheme then the scheme data contains the // If the URL is a view-source scheme then the scheme data contains the
// real URL that should be used for which the source is to be viewed. // real URL that should be used for which the source is to be viewed.
@ -488,11 +489,11 @@ pub fn load<A>(mut load_data: LoadData,
set_request_cookies(doc_url.clone(), &mut request_headers, &resource_mgr_chan); set_request_cookies(doc_url.clone(), &mut request_headers, &resource_mgr_chan);
// --- Send the request // --- Send the request
let mut req = try!(request_factory.create(url.clone(), load_data.method.clone())); let mut req = try!(request_factory.create(url.clone(), method.clone()));
*req.headers_mut() = request_headers; *req.headers_mut() = request_headers;
if log_enabled!(log::LogLevel::Info) { if log_enabled!(log::LogLevel::Info) {
info!("{}", load_data.method); info!("{}", method);
for header in req.headers_mut().iter() { for header in req.headers_mut().iter() {
info!(" - {}", header); info!(" - {}", header);
} }
@ -522,7 +523,7 @@ pub fn load<A>(mut load_data: LoadData,
let request_id = uuid::Uuid::new_v4().to_simple_string(); let request_id = uuid::Uuid::new_v4().to_simple_string();
if let Some(ref chan) = devtools_chan { if let Some(ref chan) = devtools_chan {
let net_event = NetworkEvent::HttpRequest(load_data.url.clone(), let net_event = NetworkEvent::HttpRequest(load_data.url.clone(),
load_data.method.clone(), method.clone(),
load_data.headers.clone(), load_data.headers.clone(),
load_data.data.clone()); load_data.data.clone());
chan.send(DevtoolsControlMsg::FromChrome( chan.send(DevtoolsControlMsg::FromChrome(
@ -559,22 +560,24 @@ pub fn load<A>(mut load_data: LoadData,
} }
_ => {} _ => {}
} }
let new_doc_url = match UrlParser::new().base_url(&doc_url).parse(&new_url) { let new_doc_url = match UrlParser::new().base_url(&doc_url).parse(&new_url) {
Ok(u) => u, Ok(u) => u,
Err(e) => { Err(e) => {
return Err(LoadError::InvalidRedirect(doc_url, e.to_string())); return Err(LoadError::InvalidRedirect(doc_url, e.to_string()));
} }
}; };
info!("redirecting to {}", new_doc_url); info!("redirecting to {}", new_doc_url);
url = replace_hosts(&new_doc_url); url = replace_hosts(&new_doc_url);
doc_url = new_doc_url; doc_url = new_doc_url;
// According to https://tools.ietf.org/html/rfc7231#section-6.4.2, // According to https://tools.ietf.org/html/rfc7231#section-6.4.2,
// historically UAs have rewritten POST->GET on 301 and 302 responses. // historically UAs have rewritten POST->GET on 301 and 302 responses.
if load_data.method == Method::Post && if method == Method::Post &&
(response.status() == StatusCode::MovedPermanently || (response.status() == StatusCode::MovedPermanently ||
response.status() == StatusCode::Found) { response.status() == StatusCode::Found) {
load_data.method = Method::Get; method = Method::Get;
} }
if redirected_to.contains(&url) { if redirected_to.contains(&url) {
@ -593,8 +596,8 @@ pub fn load<A>(mut load_data: LoadData,
if viewing_source { if viewing_source {
adjusted_headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![]))); adjusted_headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
} }
let mut metadata: Metadata = Metadata::default(doc_url.clone());
let mut metadata: Metadata = Metadata::default(doc_url.clone());
metadata.set_content_type(match adjusted_headers.get() { metadata.set_content_type(match adjusted_headers.get() {
Some(&ContentType(ref mime)) => Some(mime), Some(&ContentType(ref mime)) => Some(mime),
None => None None => None

View file

@ -208,6 +208,32 @@ impl HttpRequest for AssertMustHaveBodyRequest {
} }
} }
#[test]
fn test_load_when_redirecting_from_a_post_should_rewrite_next_request_as_get() {
struct Factory;
impl HttpRequestFactory for Factory {
type R=MockRequest;
fn create(&self, url: Url, method: Method) -> Result<MockRequest, LoadError> {
if url.domain().unwrap() == "mozilla.com" {
assert_eq!(Method::Post, method);
Ok(MockRequest::new(RequestType::Redirect("http://mozilla.org".to_string())))
} else {
assert_eq!(Method::Get, method);
Ok(MockRequest::new(RequestType::Text(<[_]>::to_vec("Yay!".as_bytes()))))
}
}
}
let url = Url::parse("http://mozilla.com").unwrap();
let resource_mgr = new_resource_task(None, None);
let mut load_data = LoadData::new(url.clone(), None);
load_data.method = Method::Post;
let _ = load::<MockRequest>(load_data, resource_mgr, None, &Factory);
}
#[test] #[test]
fn test_load_should_decode_the_response_as_deflate_when_response_headers_have_content_encoding_deflate() { fn test_load_should_decode_the_response_as_deflate_when_response_headers_have_content_encoding_deflate() {
struct Factory; struct Factory;