mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Abstract everything but the response from hyper
Because we're using unsized types not for requesting, there's not a satisfactory way of doing this without boxing the request... Once unsized stuff lands in rust 1.2/1.3(???) then this should be implemented with Rc's instead of Box's. For the time being I'm not sure what else to do. servo/servo#6727
This commit is contained in:
parent
6cba33a50b
commit
7633cd54c2
2 changed files with 57 additions and 44 deletions
|
@ -23,11 +23,11 @@ use hyper::header::StrictTransportSecurity;
|
|||
use hyper::header::{AcceptEncoding, Accept, ContentLength, ContentType, Host, Location, qitem, Quality, QualityItem};
|
||||
use hyper::client::{Request, Response};
|
||||
use hyper::header::{AcceptEncoding, Accept, ContentLength, ContentType, Host, Location, qitem, StrictTransportSecurity};
|
||||
use hyper::header::{Quality, QualityItem};
|
||||
use hyper::header::{Quality, QualityItem, Headers};
|
||||
use hyper::Error as HttpError;
|
||||
use hyper::method::Method;
|
||||
use hyper::mime::{Mime, TopLevel, SubLevel};
|
||||
use hyper::net::{Fresh, HttpsConnector, Openssl, NetworkConnector, NetworkStream};
|
||||
use hyper::net::{Fresh, Streaming, HttpsConnector, Openssl, NetworkConnector, NetworkStream};
|
||||
use hyper::status::{StatusCode, StatusClass};
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use log;
|
||||
|
@ -164,20 +164,52 @@ impl NetworkHttpRequester {
|
|||
}
|
||||
}
|
||||
|
||||
impl HttpRequester for NetworkHttpRequester {
|
||||
fn send(&self, request: Request<Fresh>) -> Result<Response, LoadError> {
|
||||
unimplemented!()
|
||||
pub trait HttpRequest {
|
||||
fn headers(&self) -> &Headers;
|
||||
fn headers_mut(&mut self) -> &mut Headers;
|
||||
fn send(self: Box<Self>) -> Result<Response, LoadError>;
|
||||
}
|
||||
|
||||
struct NetworkHttpRequest {
|
||||
fresh: Request<Fresh>
|
||||
}
|
||||
|
||||
impl HttpRequest for NetworkHttpRequest {
|
||||
fn headers(&self) -> &Headers {
|
||||
self.fresh.headers()
|
||||
}
|
||||
|
||||
fn build(&self, url: Url, method: Method) -> Result<Request<Fresh>, LoadError> {
|
||||
fn headers_mut(&mut self) -> &mut Headers {
|
||||
self.fresh.headers_mut()
|
||||
}
|
||||
|
||||
fn send(self: Box<Self>) -> Result<Response, LoadError> {
|
||||
let connected = match self.fresh.start() {
|
||||
Ok(streaming) => streaming,
|
||||
Err(e) => return Err(LoadError::Connection(Url::parse("http://example.com").unwrap(), e.description().to_string()))
|
||||
};
|
||||
|
||||
match connected.send() {
|
||||
Ok(w) => Ok(w),
|
||||
Err(e) => return Err(LoadError::Connection(Url::parse("http://example.com").unwrap(), e.description().to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpRequester for NetworkHttpRequester {
|
||||
fn send(&self, request: Box<HttpRequest>) -> Result<Response, LoadError> {
|
||||
request.send()
|
||||
}
|
||||
|
||||
fn build(&self, url: Url, method: Method) -> Result<Box<HttpRequest>, LoadError> {
|
||||
let connection = Request::with_connector(method, url.clone(), &self.connector);
|
||||
|
||||
let ssl_err_string = "Some(OpenSslErrors([UnknownError { library: \"SSL routines\", \
|
||||
function: \"SSL3_GET_SERVER_CERTIFICATE\", \
|
||||
reason: \"certificate verify failed\" }]))";
|
||||
|
||||
match connection {
|
||||
Ok(req) => Ok(req),
|
||||
let request = match connection {
|
||||
Ok(req) => req,
|
||||
|
||||
Err(HttpError::Io(ref io_error)) if (
|
||||
io_error.kind() == io::ErrorKind::Other &&
|
||||
|
@ -185,7 +217,7 @@ impl HttpRequester for NetworkHttpRequester {
|
|||
// FIXME: This incredibly hacky. Make it more robust, and at least test it.
|
||||
format!("{:?}", io_error.cause()) == ssl_err_string
|
||||
) => {
|
||||
Err(
|
||||
return Err(
|
||||
LoadError::Ssl(
|
||||
url.clone(),
|
||||
format!("ssl error {:?}: {:?} {:?}", io_error.kind(), io_error.description(), io_error.cause())
|
||||
|
@ -193,15 +225,17 @@ impl HttpRequester for NetworkHttpRequester {
|
|||
)
|
||||
},
|
||||
Err(e) => {
|
||||
Err(LoadError::Connection(url, e.description().to_string()))
|
||||
return Err(LoadError::Connection(url, e.description().to_string()))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Box::new(NetworkHttpRequest { fresh: request }))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HttpRequester {
|
||||
fn build(&self, url: Url, method: Method) -> Result<Request<Fresh>, LoadError>;
|
||||
fn send(&self, request: Request<Fresh>) -> Result<Response, LoadError>;
|
||||
fn build(&self, url: Url, method: Method) -> Result<Box<HttpRequest>, LoadError>;
|
||||
fn send(&self, request: Box<HttpRequest>) -> Result<Response, LoadError>;
|
||||
}
|
||||
|
||||
pub enum LoadError {
|
||||
|
@ -321,35 +355,23 @@ pub fn load(mut load_data: LoadData,
|
|||
|
||||
// --- Start sending the request
|
||||
// Avoid automatically sending request body if a redirect has occurred.
|
||||
let writer = match load_data.data {
|
||||
let response = match load_data.data {
|
||||
Some(ref data) if iters == 1 => {
|
||||
req.headers_mut().set(ContentLength(data.len() as u64));
|
||||
|
||||
let mut writer = match req.start() {
|
||||
match requester.send(req) {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
return Err(LoadError::Connection(url, e.description().to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
match writer.write_all(&*data) {
|
||||
Err(e) => {
|
||||
return Err(LoadError::Connection(url, e.description().to_string()));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
writer
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
match load_data.method {
|
||||
Method::Get | Method::Head => (),
|
||||
_ => req.headers_mut().set(ContentLength(0))
|
||||
}
|
||||
match req.start() {
|
||||
match requester.send(req) {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
return Err(LoadError::Connection(url, e.description().to_string()));
|
||||
}
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -368,14 +390,6 @@ pub fn load(mut load_data: LoadData,
|
|||
net_event))).unwrap();
|
||||
}
|
||||
|
||||
// --- Finish writing the request and read the response
|
||||
let response = match writer.send() {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Err(LoadError::Connection(url, e.description().to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
// Dump headers, but only do the iteration if info!() is enabled.
|
||||
info!("got HTTP response {}, headers:", response.status);
|
||||
if log_enabled!(log::LogLevel::Info) {
|
||||
|
|
|
@ -2,24 +2,23 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net::http_loader::{load, LoadError, HttpRequester};
|
||||
use net::http_loader::{load, LoadError, HttpRequester, HttpRequest};
|
||||
use url::Url;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use ipc_channel::ipc;
|
||||
use net_traits::LoadData;
|
||||
use net::hsts::HSTSList;
|
||||
use hyper::client::{Request, Response};
|
||||
use hyper::net::Fresh;
|
||||
use hyper::client::Response;
|
||||
use hyper::method::Method;
|
||||
|
||||
struct MockHttpRequester;
|
||||
|
||||
impl HttpRequester for MockHttpRequester {
|
||||
fn build(&self, url: Url, _: Method) -> Result<Request<Fresh>, LoadError> {
|
||||
fn build(&self, url: Url, _: Method) -> Result<Box<HttpRequest>, LoadError> {
|
||||
Err(LoadError::Connection(url.clone(), "shouldn't connect".to_string()))
|
||||
}
|
||||
|
||||
fn send(&self, _: Request<Fresh>) -> Result<Response, LoadError> {
|
||||
fn send(&self, _: Box<HttpRequest>) -> Result<Response, LoadError> {
|
||||
Err(LoadError::Connection(Url::parse("http://example.com").unwrap(), "shouldn't connect".to_string()))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue