net: Make most of the resource task messages serializable.

This commit is contained in:
Patrick Walton 2015-07-09 16:18:38 -07:00
parent 7e77285745
commit 9c9d7dc93b
15 changed files with 373 additions and 105 deletions

View file

@ -10,8 +10,6 @@
#![feature(vec_push_all)]
#![plugin(serde_macros)]
#![plugin(serde_macros)]
extern crate euclid;
extern crate hyper;
extern crate ipc_channel;
@ -24,13 +22,19 @@ extern crate url;
extern crate util;
extern crate msg;
use hyper::header::{ContentType, Headers};
use hyper::header::{ContentType, Header, Headers, HeadersItems};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper::mime::{Mime, Attr};
use msg::constellation_msg::{PipelineId};
use serde::de;
use serde::ser;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use url::Url;
use std::borrow::Cow;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
@ -46,14 +50,14 @@ pub mod image {
pub mod base;
}
#[derive(Clone)]
#[derive(Clone, Deserialize, Serialize)]
pub struct LoadData {
pub url: Url,
pub method: Method,
pub url: SerializableUrl,
pub method: SerializableMethod,
/// Headers that will apply to the initial request only
pub headers: Headers,
pub headers: SerializableHeaders,
/// Headers that will apply to the initial request and any redirects
pub preserved_headers: Headers,
pub preserved_headers: SerializableHeaders,
pub data: Option<Vec<u8>>,
pub cors: Option<ResourceCORSData>,
pub pipeline_id: Option<PipelineId>,
@ -62,10 +66,10 @@ pub struct LoadData {
impl LoadData {
pub fn new(url: Url, id: Option<PipelineId>) -> LoadData {
LoadData {
url: url,
method: Method::Get,
headers: Headers::new(),
preserved_headers: Headers::new(),
url: SerializableUrl(url),
method: SerializableMethod(Method::Get),
headers: SerializableHeaders(Headers::new()),
preserved_headers: SerializableHeaders(Headers::new()),
data: None,
cors: None,
pipeline_id: id,
@ -87,13 +91,14 @@ pub trait AsyncResponseListener {
/// Data for passing between threads/processes to indicate a particular action to
/// take on a provided network listener.
#[derive(Deserialize, Serialize)]
pub enum ResponseAction {
/// Invoke headers_available
HeadersAvailable(Metadata),
/// Invoke data_available
DataAvailable(Vec<u8>),
/// Invoke response_complete
ResponseComplete(Result<(), String>)
ResponseComplete(SerializableStringResult)
}
impl ResponseAction {
@ -102,7 +107,7 @@ impl ResponseAction {
match self {
ResponseAction::HeadersAvailable(m) => listener.headers_available(m),
ResponseAction::DataAvailable(d) => listener.data_available(d),
ResponseAction::ResponseComplete(r) => listener.response_complete(r),
ResponseAction::ResponseComplete(r) => listener.response_complete(r.0),
}
}
}
@ -132,9 +137,9 @@ pub enum ControlMsg {
/// Request the data associated with a particular URL
Load(LoadData, LoadConsumer),
/// Store a set of cookies for a given originating URL
SetCookiesForUrl(Url, String, CookieSource),
SetCookiesForUrl(SerializableUrl, String, CookieSource),
/// Retrieve the stored cookies for a given URL
GetCookiesForUrl(Url, Sender<Option<String>>, CookieSource),
GetCookiesForUrl(SerializableUrl, Sender<Option<String>>, CookieSource),
/// Store a domain's STS information
SetHSTSEntryForHost(String, IncludeSubdomains, Option<u64>),
Exit
@ -210,43 +215,43 @@ pub struct LoadResponse {
pub progress_port: Receiver<ProgressMsg>,
}
#[derive(Clone)]
#[derive(Clone, Deserialize, Serialize)]
pub struct ResourceCORSData {
/// CORS Preflight flag
pub preflight: bool,
/// Origin of CORS Request
pub origin: Url
pub origin: SerializableUrl,
}
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone)]
#[derive(Clone, Deserialize, Serialize)]
pub struct Metadata {
/// Final URL after redirects.
pub final_url: Url,
pub final_url: SerializableUrl,
/// MIME type / subtype.
pub content_type: Option<(ContentType)>,
pub content_type: Option<(SerializableContentType)>,
/// Character set.
pub charset: Option<String>,
/// Headers
pub headers: Option<Headers>,
pub headers: Option<SerializableHeaders>,
/// HTTP Status
pub status: Option<RawStatus>,
pub status: Option<SerializableRawStatus>,
}
impl Metadata {
/// Metadata with defaults for everything optional.
pub fn default(url: Url) -> Self {
Metadata {
final_url: url,
final_url: SerializableUrl(url),
content_type: None,
charset: None,
headers: None,
// https://fetch.spec.whatwg.org/#concept-response-status-message
status: Some(RawStatus(200, "OK".into())),
status: Some(SerializableRawStatus(RawStatus(200, "OK".into()))),
}
}
@ -255,7 +260,7 @@ impl Metadata {
match content_type {
None => (),
Some(mime) => {
self.content_type = Some(ContentType(mime.clone()));
self.content_type = Some(SerializableContentType(ContentType(mime.clone())));
let &Mime(_, _, ref parameters) = mime;
for &(ref k, ref v) in parameters.iter() {
if &Attr::Charset == k {
@ -268,7 +273,7 @@ impl Metadata {
}
/// The creator of a given cookie
#[derive(PartialEq, Copy, Clone)]
#[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum CookieSource {
/// An HTTP API
HTTP,
@ -277,12 +282,12 @@ pub enum CookieSource {
}
/// Messages sent in response to a `Load` message
#[derive(PartialEq,Debug)]
#[derive(PartialEq, Debug, Deserialize, Serialize)]
pub enum ProgressMsg {
/// Binary data - there may be multiple of these
Payload(Vec<u8>),
/// Indicates loading is complete, either successfully or not
Done(Result<(), String>)
Done(SerializableStringResult)
}
/// Convenience function for synchronously loading a whole resource.
@ -296,8 +301,10 @@ pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
loop {
match response.progress_port.recv().unwrap() {
ProgressMsg::Payload(data) => buf.push_all(&data),
ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)),
ProgressMsg::Done(Err(e)) => return Err(e)
ProgressMsg::Done(SerializableStringResult(Ok(()))) => {
return Ok((response.metadata, buf))
}
ProgressMsg::Done(SerializableStringResult(Err(e))) => return Err(e)
}
}
}
@ -321,8 +328,8 @@ impl Iterator for ProgressMsgPortIterator {
fn next(&mut self) -> Option<Vec<u8>> {
match self.progress_port.recv().unwrap() {
ProgressMsg::Payload(data) => Some(data),
ProgressMsg::Done(Ok(())) => None,
ProgressMsg::Done(Err(e)) => {
ProgressMsg::Done(SerializableStringResult(Ok(()))) => None,
ProgressMsg::Done(SerializableStringResult(Err(e))) => {
error!("error receiving bytes: {}", e);
None
}
@ -330,4 +337,226 @@ impl Iterator for ProgressMsgPortIterator {
}
}
#[derive(Clone)]
pub struct SerializableMethod(pub Method);
impl Deref for SerializableMethod {
type Target = Method;
fn deref(&self) -> &Method {
&self.0
}
}
impl Serialize for SerializableMethod {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
format!("{}", self.0).serialize(serializer)
}
}
impl Deserialize for SerializableMethod {
fn deserialize<D>(deserializer: &mut D) -> Result<SerializableMethod, D::Error>
where D: Deserializer {
let string_representation: String = try!(Deserialize::deserialize(deserializer));
Ok(SerializableMethod(FromStr::from_str(&string_representation[..]).unwrap()))
}
}
#[derive(Clone)]
pub struct SerializableHeaders(pub Headers);
impl Deref for SerializableHeaders {
type Target = Headers;
fn deref(&self) -> &Headers {
&self.0
}
}
impl DerefMut for SerializableHeaders {
fn deref_mut(&mut self) -> &mut Headers {
&mut self.0
}
}
impl Serialize for SerializableHeaders {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
struct HeadersVisitor<'a> {
iter: HeadersItems<'a>,
len: usize,
}
impl<'a> ser::MapVisitor for HeadersVisitor<'a> {
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer {
match self.iter.next() {
Some(header_item) => {
try!(serializer.visit_map_elt(header_item.name(),
header_item.value_string()));
Ok(Some(()))
}
None => Ok(None),
}
}
fn len(&self) -> Option<usize> {
Some(self.len)
}
}
serializer.visit_map(HeadersVisitor {
iter: self.iter(),
len: self.len(),
})
}
}
impl Deserialize for SerializableHeaders {
fn deserialize<D>(deserializer: &mut D) -> Result<SerializableHeaders, D::Error>
where D: Deserializer {
struct HeadersVisitor;
impl de::Visitor for HeadersVisitor {
type Value = SerializableHeaders;
fn visit_map<V>(&mut self, mut visitor: V) -> Result<SerializableHeaders, V::Error>
where V: de::MapVisitor {
let mut result = Headers::new();
while let Some((key, value)) = try!(visitor.visit()) {
let (key, value): (String, String) = (key, value);
result.set_raw(key, vec![value.into_bytes()]);
}
try!(visitor.end());
Ok(SerializableHeaders(result))
}
}
let result = SerializableHeaders(Headers::new());
try!(deserializer.visit_map(HeadersVisitor));
Ok(result)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct SerializableUrl(pub Url);
impl Deref for SerializableUrl {
type Target = Url;
fn deref(&self) -> &Url {
&self.0
}
}
impl DerefMut for SerializableUrl {
fn deref_mut(&mut self) -> &mut Url {
&mut self.0
}
}
impl Serialize for SerializableUrl {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
format!("{}", self.0).serialize(serializer)
}
}
impl Deserialize for SerializableUrl {
fn deserialize<D>(deserializer: &mut D) -> Result<SerializableUrl, D::Error>
where D: Deserializer {
let string_representation: String = try!(Deserialize::deserialize(deserializer));
Ok(SerializableUrl(FromStr::from_str(&string_representation[..]).unwrap()))
}
}
#[derive(Clone, PartialEq)]
pub struct SerializableContentType(pub ContentType);
impl Deref for SerializableContentType {
type Target = ContentType;
fn deref(&self) -> &ContentType {
&self.0
}
}
impl Serialize for SerializableContentType {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
format!("{}", self.0).serialize(serializer)
}
}
impl Deserialize for SerializableContentType {
fn deserialize<D>(deserializer: &mut D) -> Result<SerializableContentType, D::Error>
where D: Deserializer {
let string_representation: String = try!(Deserialize::deserialize(deserializer));
Ok(SerializableContentType(Header::parse_header(
&[string_representation.into_bytes()]).unwrap()))
}
}
#[derive(Clone, PartialEq)]
pub struct SerializableRawStatus(pub RawStatus);
impl Deref for SerializableRawStatus {
type Target = RawStatus;
fn deref(&self) -> &RawStatus {
&self.0
}
}
impl Serialize for SerializableRawStatus {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
((self.0).0, (self.0).1.clone().into_owned()).serialize(serializer)
}
}
impl Deserialize for SerializableRawStatus {
fn deserialize<D>(deserializer: &mut D) -> Result<SerializableRawStatus, D::Error>
where D: Deserializer {
let representation: (u16, String) = try!(Deserialize::deserialize(deserializer));
Ok(SerializableRawStatus(RawStatus(representation.0, Cow::Owned(representation.1))))
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct SerializableStringResult(pub Result<(),String>);
#[derive(Deserialize, Serialize)]
enum SerializableStringResultInternal {
Ok(()),
Err(String),
}
impl Deref for SerializableStringResult {
type Target = Result<(),String>;
fn deref(&self) -> &Result<(),String> {
&self.0
}
}
impl Serialize for SerializableStringResult {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
let result = match **self {
Ok(ref value) => SerializableStringResultInternal::Ok(*value),
Err(ref value) => SerializableStringResultInternal::Err((*value).clone()),
};
result.serialize(serializer)
}
}
impl Deserialize for SerializableStringResult {
fn deserialize<D>(deserializer: &mut D) -> Result<SerializableStringResult, D::Error>
where D: Deserializer {
let result: SerializableStringResultInternal =
try!(Deserialize::deserialize(deserializer));
match result {
SerializableStringResultInternal::Ok(value) => Ok(SerializableStringResult(Ok(value))),
SerializableStringResultInternal::Err(value) => {
Ok(SerializableStringResult(Err(value)))
}
}
}
}