diff options
author | Simon Sapin <simon.sapin@exyr.org> | 2014-07-21 20:23:02 +0100 |
---|---|---|
committer | Simon Sapin <simon.sapin@exyr.org> | 2014-07-21 20:23:02 +0100 |
commit | 3670ee6f1fc5066101cc5a357443494552ea37f2 (patch) | |
tree | 3fa174faace875c0f8bb83cb4f1668f46141948c /src | |
parent | f07d999463fd80ec55cef9e673a1dc08954b6d74 (diff) | |
parent | b84065f5749b42792c4c7b890be23e81651beab5 (diff) | |
download | servo-3670ee6f1fc5066101cc5a357443494552ea37f2.tar.gz servo-3670ee6f1fc5066101cc5a357443494552ea37f2.zip |
Merge pull request #2875 from SimonSapin/rust-url
Start dogfooding rust-url
Diffstat (limited to 'src')
40 files changed, 237 insertions, 442 deletions
diff --git a/src/components/compositing/compositing.rs b/src/components/compositing/compositing.rs index 7e8c4e0fa93..b22c8596403 100644 --- a/src/components/compositing/compositing.rs +++ b/src/components/compositing/compositing.rs @@ -37,7 +37,7 @@ extern crate servo_util = "util"; extern crate libc; extern crate time; -extern crate url; +extern crate url = "url_"; #[cfg(target_os="macos")] extern crate core_graphics; diff --git a/src/components/compositing/compositor.rs b/src/components/compositing/compositor.rs index affbc4cdda7..9a808cfd052 100644 --- a/src/components/compositing/compositor.rs +++ b/src/components/compositing/compositor.rs @@ -42,12 +42,13 @@ use servo_util::geometry::{DevicePixel, PagePx, ScreenPx, ViewportPx}; use servo_util::memory::MemoryProfilerChan; use servo_util::opts::Opts; use servo_util::time::{profile, TimeProfilerChan}; -use servo_util::{memory, time, url}; +use servo_util::{memory, time}; use std::io::timer::sleep; use std::collections::hashmap::HashMap; use std::path::Path; use std::rc::Rc; use time::precise_time_s; +use url::Url; pub struct IOCompositor { @@ -626,7 +627,7 @@ impl IOCompositor { layers"), }; - let msg = LoadUrlMsg(root_pipeline_id, url::parse_url(url_string.as_slice(), None)); + let msg = LoadUrlMsg(root_pipeline_id, Url::parse(url_string.as_slice()).unwrap()); let ConstellationChan(ref chan) = self.constellation_chan; chan.send(msg); } diff --git a/src/components/compositing/constellation.rs b/src/components/compositing/constellation.rs index 91d44d04d94..3ba7a67e63b 100644 --- a/src/components/compositing/constellation.rs +++ b/src/components/compositing/constellation.rs @@ -29,7 +29,6 @@ use servo_net::resource_task; use servo_util::geometry::PagePx; use servo_util::opts::Opts; use servo_util::time::TimeProfilerChan; -use servo_util::url::parse_url; use servo_util::task::spawn_named; use std::cell::RefCell; use std::kinds::marker; @@ -446,7 +445,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { debug!("creating replacement pipeline for about:failure"); let new_id = self.get_next_pipeline_id(); - let pipeline = self.new_pipeline(new_id, subpage_id, parse_url("about:failure", None)); + let pipeline = self.new_pipeline(new_id, subpage_id, Url::parse("about:failure").unwrap()); pipeline.load(); let pipeline_wrapped = Rc::new(pipeline); @@ -576,11 +575,11 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { let source_url = source_pipeline.url.clone(); - let same_script = (source_url.host == url.host && - source_url.port == url.port) && sandbox == IFrameUnsandboxed; + let same_script = (source_url.host() == url.host() && + source_url.port() == url.port()) && sandbox == IFrameUnsandboxed; // FIXME(tkuehn): Need to follow the standardized spec for checking same-origin let pipeline = if same_script { - debug!("Constellation: loading same-origin iframe at {:?}", url); + debug!("Constellation: loading same-origin iframe at {}", url.serialize()); // Reuse the script task if same-origin url's Pipeline::with_script::<LTF>(next_pipeline_id, subpage_id, @@ -616,7 +615,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { } fn handle_load_url_msg(&mut self, source_id: PipelineId, url: Url) { - debug!("Constellation: received message to load {:s}", url.to_str()); + debug!("Constellation: received message to load {:s}", url.serialize()); // Make sure no pending page would be overridden. let source_frame = self.current_frame().get_ref().find(source_id).expect( "Constellation: received a LoadUrlMsg from a pipeline_id associated diff --git a/src/components/layout/construct.rs b/src/components/layout/construct.rs index 113e4a28b60..3764a343eae 100644 --- a/src/components/layout/construct.rs +++ b/src/components/layout/construct.rs @@ -56,9 +56,9 @@ use script::dom::element::{HTMLTableRowElementTypeId, HTMLTableSectionElementTyp use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId}; use script::dom::node::{TextNodeTypeId}; +use script::dom::htmlobjectelement::is_image_data; use servo_util::namespace; use servo_util::range::Range; -use servo_util::url::{is_image_data, parse_url}; use std::mem; use std::sync::atomics::Relaxed; use style::ComputedValues; @@ -249,7 +249,7 @@ impl<'a> FlowConstructor<'a> { IframeFragment(IframeFragmentInfo::new(node)) } Some(ElementNodeTypeId(HTMLObjectElementTypeId)) => { - let data = node.get_object_data(&self.layout_context.url); + let data = node.get_object_data(); self.build_fragment_info_for_image(node, data) } Some(ElementNodeTypeId(HTMLTableElementTypeId)) => TableWrapperFragment, @@ -1007,7 +1007,7 @@ trait ObjectElement { fn has_object_data(&self) -> bool; /// Returns the "data" attribute value parsed as a URL - fn get_object_data(&self, base_url: &Url) -> Option<Url>; + fn get_object_data(&self) -> Option<Url>; } impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> { @@ -1023,9 +1023,9 @@ impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> { } } - fn get_object_data(&self, base_url: &Url) -> Option<Url> { + fn get_object_data(&self) -> Option<Url> { match self.get_type_and_data() { - (None, Some(uri)) if is_image_data(uri) => Some(parse_url(uri, Some(base_url.clone()))), + (None, Some(uri)) if is_image_data(uri) => Url::parse(uri).ok(), _ => None } } diff --git a/src/components/layout/css/select.rs b/src/components/layout/css/select.rs index 9465a6ba290..230feb86e99 100644 --- a/src/components/layout/css/select.rs +++ b/src/components/layout/css/select.rs @@ -3,14 +3,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use style::{Stylesheet, Stylist, UserAgentOrigin, with_errors_silenced}; -use url; +use url::Url; pub fn new_stylist() -> Stylist { let mut stylist = Stylist::new(); let ua_stylesheet = with_errors_silenced(|| Stylesheet::from_bytes( include_bin!("user-agent.css"), - url::from_str("chrome:///user-agent.css").unwrap(), + Url::parse("chrome:///user-agent.css").unwrap(), None, None)); stylist.add_stylesheet(ua_stylesheet, UserAgentOrigin); diff --git a/src/components/layout/layout.rs b/src/components/layout/layout.rs index f17d1225204..8e1f546196c 100644 --- a/src/components/layout/layout.rs +++ b/src/components/layout/layout.rs @@ -33,7 +33,7 @@ extern crate collections; extern crate green; extern crate libc; extern crate sync; -extern crate url; +extern crate url = "url_"; pub mod block; pub mod construct; diff --git a/src/components/layout/layout_task.rs b/src/components/layout/layout_task.rs index cb40a8f011d..bed0096ff69 100644 --- a/src/components/layout/layout_task.rs +++ b/src/components/layout/layout_task.rs @@ -563,7 +563,7 @@ impl LayoutTask { mem::transmute(&mut node) }; - debug!("layout: received layout request for: {:s}", data.url.to_str()); + debug!("layout: received layout request for: {:s}", data.url.serialize()); debug!("layout: damage is {:?}", data.damage); debug!("layout: parsed Node tree"); debug!("{:?}", node.dump()); diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs index 8d69ceece7c..944df69bd43 100644 --- a/src/components/main/servo.rs +++ b/src/components/main/servo.rs @@ -26,7 +26,7 @@ extern crate gfx; extern crate libc; extern crate native; extern crate rustrt; -extern crate url; +extern crate url = "url_"; #[cfg(not(test))] use compositing::{CompositorChan, CompositorTask, Constellation}; @@ -48,8 +48,9 @@ use servo_util::memory::MemoryProfiler; #[cfg(not(test))] use servo_util::opts; + #[cfg(not(test))] -use servo_util::url::parse_url; +use url::{Url, UrlParser}; #[cfg(not(test), not(target_os="android"))] @@ -58,8 +59,6 @@ use std::os; use std::str; #[cfg(not(test))] use rustrt::task::TaskOpts; -#[cfg(not(test))] -use url::Url; #[cfg(not(test), target_os="linux")] @@ -134,16 +133,12 @@ pub fn run(opts: opts::Opts) { font_cache_task, time_profiler_chan_clone); + let base_url = Url::from_directory_path(&os::getcwd()).unwrap(); + let mut url_parser = UrlParser::new(); + let url_parser = url_parser.base_url(&base_url); // Send the URL command to the constellation. - for filename in opts.urls.iter() { - let url = if filename.as_slice().starts_with("data:") { - // As a hack for easier command-line testing, - // assume that data URLs are not URL-encoded. - Url::new("data".to_string(), None, "".to_string(), None, - filename.as_slice().slice_from(5).to_string(), vec!(), None) - } else { - parse_url(filename.as_slice(), None) - }; + for url in opts.urls.iter() { + let url = url_parser.parse(url.as_slice()).ok().expect("URL parsing failed"); let ConstellationChan(ref chan) = constellation_chan; chan.send(InitLoadUrlMsg(url)); diff --git a/src/components/msg/msg.rs b/src/components/msg/msg.rs index 817ffd8c4f3..6679aabc0b8 100644 --- a/src/components/msg/msg.rs +++ b/src/components/msg/msg.rs @@ -13,7 +13,7 @@ extern crate layers; extern crate serialize; extern crate servo_util = "util"; extern crate std; -extern crate url; +extern crate url = "url_"; #[cfg(target_os="macos")] extern crate core_foundation; diff --git a/src/components/net/data_loader.rs b/src/components/net/data_loader.rs index 8aee4907467..aada592d65f 100644 --- a/src/components/net/data_loader.rs +++ b/src/components/net/data_loader.rs @@ -2,12 +2,16 @@ * 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 std::str; + use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, LoaderTask, start_sending}; use serialize::base64::FromBase64; use http::headers::test_utils::from_stream_with_str; use http::headers::content_type::MediaType; +use url::{percent_decode, OtherSchemeData}; + pub fn factory() -> LoaderTask { proc(url, start_chan) { @@ -25,7 +29,18 @@ fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) { let mut metadata = Metadata::default(url.clone()); // Split out content type and data. - let parts: Vec<&str> = url.path.as_slice().splitn(',', 1).collect(); + let mut scheme_data = match url.scheme_data { + OtherSchemeData(scheme_data) => scheme_data, + _ => fail!("Expected a non-relative scheme URL.") + }; + match url.query { + Some(query) => { + scheme_data.push_str("?"); + scheme_data.push_str(query.as_slice()); + }, + None => () + } + let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect(); if parts.len() != 2 { start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string()))); return; @@ -46,23 +61,23 @@ fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) { metadata.set_content_type(&content_type); let progress_chan = start_sending(start_chan, metadata); + let bytes = percent_decode(parts.get(1).as_bytes()); if is_base64 { - match (*parts.get(1)).from_base64() { + // FIXME(#2877): use bytes.as_slice().from_base64() when we upgrade to a Rust version + // that includes https://github.com/rust-lang/rust/pull/15810 + let fake_utf8 = unsafe { str::raw::from_utf8(bytes.as_slice()) }; + match fake_utf8.from_base64() { Err(..) => { progress_chan.send(Done(Err("non-base64 data uri".to_string()))); } Ok(data) => { - let data: Vec<u8> = data; - progress_chan.send(Payload(data.move_iter().collect())); + progress_chan.send(Payload(data)); progress_chan.send(Done(Ok(()))); } } } else { - // FIXME: Since the %-decoded URL is already a str, we can't - // handle UTF8-incompatible encodings. - let bytes: &[u8] = (*parts.get(1)).as_bytes(); - progress_chan.send(Payload(bytes.iter().map(|&x| x).collect())); + progress_chan.send(Payload(bytes)); progress_chan.send(Done(Ok(()))); } } @@ -72,11 +87,11 @@ fn assert_parse(url: &'static str, content_type: Option<(String, String)>, charset: Option<String>, data: Option<Vec<u8>>) { - use std::from_str::FromStr; use std::comm; + use url::Url; let (start_chan, start_port) = comm::channel(); - load(LoadData::new(FromStr::from_str(url).unwrap()), start_chan); + load(LoadData::new(Url::parse(url).unwrap()), start_chan); let response = start_port.recv(); assert_eq!(&response.metadata.content_type, &content_type); diff --git a/src/components/net/file_loader.rs b/src/components/net/file_loader.rs index 8c76ccbdecf..a0a7bb074d1 100644 --- a/src/components/net/file_loader.rs +++ b/src/components/net/file_loader.rs @@ -31,7 +31,7 @@ pub fn factory() -> LoaderTask { assert!("file" == url.scheme.as_slice()); let progress_chan = start_sending(start_chan, Metadata::default(url.clone())); spawn_named("file_loader", proc() { - match File::open_mode(&Path::new(url.path), io::Open, io::Read) { + match File::open_mode(&Path::new(url.serialize_path().unwrap()), io::Open, io::Read) { Ok(ref mut reader) => { let res = read_all(reader as &mut io::Stream, &progress_chan); progress_chan.send(Done(res)); diff --git a/src/components/net/http_loader.rs b/src/components/net/http_loader.rs index 2b7ae74970a..b1f6f6f8c78 100644 --- a/src/components/net/http_loader.rs +++ b/src/components/net/http_loader.rs @@ -56,7 +56,7 @@ fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) { return; } - info!("requesting {:s}", url.to_str()); + info!("requesting {:s}", url.serialize()); let request = RequestWriter::<NetworkStream>::new(load_data.method.clone(), url.clone()); let mut writer = match request { @@ -106,7 +106,7 @@ fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) { if 3 == (response.status.code() / 100) { match response.headers.location { Some(new_url) => { - info!("redirecting to {:s}", new_url.to_str()); + info!("redirecting to {:s}", new_url.serialize()); url = new_url; continue; } diff --git a/src/components/net/image/holder.rs b/src/components/net/image/holder.rs index c739229e9a5..11f055aad9d 100644 --- a/src/components/net/image/holder.rs +++ b/src/components/net/image/holder.rs @@ -27,7 +27,7 @@ pub struct ImageHolder { impl ImageHolder { pub fn new(url: Url, local_image_cache: Arc<Mutex<LocalImageCache>>) -> ImageHolder { - debug!("ImageHolder::new() {}", url.to_str()); + debug!("ImageHolder::new() {}", url.serialize()); let holder = ImageHolder { url: url, image: None, @@ -61,7 +61,7 @@ impl ImageHolder { /// Query and update the current image size. pub fn get_size(&mut self) -> Option<Size2D<int>> { - debug!("get_size() {}", self.url.to_str()); + debug!("get_size() {}", self.url.serialize()); self.get_image().map(|img| { self.cached_size = Size2D(img.width as int, img.height as int); @@ -70,12 +70,12 @@ impl ImageHolder { } pub fn get_image_if_present(&self) -> Option<Arc<Box<Image>>> { - debug!("get_image_if_present() {}", self.url.to_str()); + debug!("get_image_if_present() {}", self.url.serialize()); self.image.clone() } pub fn get_image(&mut self) -> Option<Arc<Box<Image>>> { - debug!("get_image() {}", self.url.to_str()); + debug!("get_image() {}", self.url.serialize()); // If this is the first time we've called this function, load // the image and store it for the future @@ -90,10 +90,10 @@ impl ImageHolder { self.image = Some(image); } ImageNotReady => { - debug!("image not ready for {:s}", self.url.to_str()); + debug!("image not ready for {:s}", self.url.serialize()); } ImageFailed => { - debug!("image decoding failed for {:s}", self.url.to_str()); + debug!("image decoding failed for {:s}", self.url.serialize()); } } } diff --git a/src/components/net/image_cache_task.rs b/src/components/net/image_cache_task.rs index 405748d9d11..c70ebc3ebeb 100644 --- a/src/components/net/image_cache_task.rs +++ b/src/components/net/image_cache_task.rs @@ -5,12 +5,11 @@ use image::base::{Image, load_from_memory}; use resource_task; use resource_task::{LoadData, ResourceTask}; -use servo_util::url::{UrlMap, url_map}; use std::comm::{channel, Receiver, Sender}; +use std::collections::hashmap::HashMap; use std::mem::replace; use std::task::spawn; -use std::to_str::ToStr; use std::result; use sync::{Arc, Mutex}; use serialize::{Encoder, Encodable}; @@ -89,8 +88,8 @@ impl ImageCacheTask { resource_task: resource_task.clone(), port: port, chan: chan_clone, - state_map: url_map(), - wait_map: url_map(), + state_map: HashMap::new(), + wait_map: HashMap::new(), need_exit: None }; cache.run(); @@ -137,9 +136,9 @@ struct ImageCache { /// A copy of the shared chan to give to child tasks chan: Sender<Msg>, /// The state of processsing an image for a URL - state_map: UrlMap<ImageState>, + state_map: HashMap<Url, ImageState>, /// List of clients waiting on a WaitForImage response - wait_map: UrlMap<Arc<Mutex<Vec<Sender<ImageResponseMsg>>>>>, + wait_map: HashMap<Url, Arc<Mutex<Vec<Sender<ImageResponseMsg>>>>>, need_exit: Option<Sender<()>>, } @@ -248,7 +247,7 @@ impl ImageCache { spawn(proc() { let url = url_clone; - debug!("image_cache_task: started fetch for {:s}", url.to_str()); + debug!("image_cache_task: started fetch for {:s}", url.serialize()); let image = load_image_data(url.clone(), resource_task.clone()); @@ -258,7 +257,7 @@ impl ImageCache { Err(()) }; to_cache.send(StorePrefetchedImageData(url.clone(), result)); - debug!("image_cache_task: ended fetch for {:s}", (url.clone()).to_str()); + debug!("image_cache_task: ended fetch for {:s}", url.serialize()); }); self.set_state(url, Prefetching(DoNotDecode)); @@ -317,7 +316,7 @@ impl ImageCache { spawn(proc() { let url = url_clone; - debug!("image_cache_task: started image decode for {:s}", url.to_str()); + debug!("image_cache_task: started image decode for {:s}", url.serialize()); let image = load_from_memory(data.as_slice()); let image = if image.is_some() { Some(Arc::new(box image.unwrap())) @@ -325,7 +324,7 @@ impl ImageCache { None }; to_cache.send(StoreImage(url.clone(), image)); - debug!("image_cache_task: ended image decode for {:s}", url.to_str()); + debug!("image_cache_task: ended image decode for {:s}", url.serialize()); }); self.set_state(url, Decoding); @@ -494,8 +493,8 @@ mod tests { use resource_task; use resource_task::{ResourceTask, Metadata, start_sending}; use image::base::test_image_bin; - use servo_util::url::parse_url; use std::comm; + use url::Url; trait Closure { fn invoke(&self, _response: Sender<resource_task::ProgressMsg>) { } @@ -568,7 +567,8 @@ mod tests { loop { match port.recv() { resource_task::Load(_, response) => { - let chan = start_sending(response, Metadata::default(parse_url("file:///fake", None))); + let chan = start_sending(response, Metadata::default( + Url::parse("file:///fake").unwrap())); on_load.invoke(chan); } resource_task::Exit => break @@ -582,7 +582,6 @@ mod tests { let mock_resource_task = mock_resource_task(box DoesNothing); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let _url = parse_url("file", None); image_cache_task.exit(); mock_resource_task.send(resource_task::Exit); @@ -594,7 +593,7 @@ mod tests { let mock_resource_task = mock_resource_task(box DoesNothing); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let (chan, port) = channel(); image_cache_task.send(GetImage(url, chan)); @@ -608,7 +607,7 @@ mod tests { let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan}); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url)); url_requested.recv(); @@ -623,7 +622,7 @@ mod tests { let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan}); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url)); @@ -643,7 +642,7 @@ mod tests { let mock_resource_task = mock_resource_task(box WaitSendTestImage{wait_port: wait_port}); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Decode(url.clone())); @@ -660,7 +659,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendTestImage); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let join_port = image_cache_task.wait_for_store(); @@ -686,7 +685,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendTestImage); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let join_port = image_cache_task.wait_for_store(); @@ -719,7 +718,8 @@ mod tests { loop { match port.recv() { resource_task::Load(_, response) => { - let chan = start_sending(response, Metadata::default(parse_url("file:///fake", None))); + let chan = start_sending(response, Metadata::default( + Url::parse("file:///fake").unwrap())); chan.send(resource_task::Payload(test_image_bin())); chan.send(resource_task::Done(Ok(()))); image_bin_sent_chan.send(()); @@ -733,7 +733,7 @@ mod tests { }); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); @@ -765,7 +765,8 @@ mod tests { loop { match port.recv() { resource_task::Load(_, response) => { - let chan = start_sending(response, Metadata::default(parse_url("file:///fake", None))); + let chan = start_sending(response, Metadata::default( + Url::parse("file:///fake").unwrap())); chan.send(resource_task::Payload(test_image_bin())); chan.send(resource_task::Done(Err("".to_string()))); image_bin_sent_chan.send(()); @@ -779,7 +780,7 @@ mod tests { }); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Decode(url.clone())); @@ -808,7 +809,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendTestImageErr); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let join_port = image_cache_task.wait_for_store_prefetched(); @@ -834,7 +835,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendTestImageErr); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let join_port = image_cache_task.wait_for_store_prefetched(); @@ -868,7 +869,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendBogusImage); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let join_port = image_cache_task.wait_for_store(); @@ -896,7 +897,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendTestImage); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); let join_port = image_cache_task.wait_for_store(); @@ -924,7 +925,7 @@ mod tests { let mock_resource_task = mock_resource_task(box WaitSendTestImage {wait_port: wait_port}); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Decode(url.clone())); @@ -950,7 +951,7 @@ mod tests { let mock_resource_task = mock_resource_task(box WaitSendTestImageErr{wait_port: wait_port}); let image_cache_task = ImageCacheTask::new(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Decode(url.clone())); @@ -974,7 +975,7 @@ mod tests { let mock_resource_task = mock_resource_task(box SendTestImage); let image_cache_task = ImageCacheTask::new_sync(mock_resource_task.clone()); - let url = parse_url("file", None); + let url = Url::parse("file:///").unwrap(); image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Decode(url.clone())); diff --git a/src/components/net/local_image_cache.rs b/src/components/net/local_image_cache.rs index 7f35ebd2683..1427c831654 100644 --- a/src/components/net/local_image_cache.rs +++ b/src/components/net/local_image_cache.rs @@ -12,7 +12,7 @@ use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotRe use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage}; use std::comm::{Receiver, channel}; -use servo_util::url::{UrlMap, url_map}; +use std::collections::hashmap::HashMap; use servo_util::task::spawn_named; use url::Url; @@ -24,7 +24,7 @@ pub struct LocalImageCache { image_cache_task: ImageCacheTask, round_number: uint, on_image_available: Option<Box<ImageResponder+Send>>, - state_map: UrlMap<ImageState> + state_map: HashMap<Url, ImageState> } impl LocalImageCache { @@ -33,7 +33,7 @@ impl LocalImageCache { image_cache_task: image_cache_task, round_number: 1, on_image_available: None, - state_map: url_map() + state_map: HashMap::new() } } } diff --git a/src/components/net/net.rs b/src/components/net/net.rs index d29abb2c248..9b9692184e7 100644 --- a/src/components/net/net.rs +++ b/src/components/net/net.rs @@ -20,7 +20,7 @@ extern crate serialize; extern crate servo_util = "util"; extern crate stb_image; extern crate sync; -extern crate url; +extern crate url = "url_"; /// Image handling. /// diff --git a/src/components/net/resource_task.rs b/src/components/net/resource_task.rs index 409fd1c7acc..15ede7b28e3 100644 --- a/src/components/net/resource_task.rs +++ b/src/components/net/resource_task.rs @@ -10,6 +10,7 @@ use data_loader; use std::comm::{channel, Receiver, Sender}; use std::task::TaskBuilder; +use std::os; use http::headers::content_type::MediaType; use ResponseHeaderCollection = http::headers::response::HeaderCollection; use RequestHeaderCollection = http::headers::request::HeaderCollection; @@ -19,8 +20,6 @@ use url::Url; use StatusOk = http::status::Ok; use http::status::Status; -#[cfg(test)] -use std::from_str::FromStr; pub enum ControlMsg { /// Request the data associated with a particular URL @@ -164,40 +163,27 @@ each URL scheme */ type LoaderTaskFactory = extern "Rust" fn() -> LoaderTask; -/// Create a ResourceTask with the default loaders +/// Create a ResourceTask pub fn new_resource_task() -> ResourceTask { - let loaders = vec!( - ("file".to_string(), file_loader::factory), - ("http".to_string(), http_loader::factory), - ("data".to_string(), data_loader::factory), - ); - create_resource_task_with_loaders(loaders) -} - -fn create_resource_task_with_loaders(loaders: Vec<(String, LoaderTaskFactory)>) -> ResourceTask { let (setup_chan, setup_port) = channel(); let builder = TaskBuilder::new().named("ResourceManager"); builder.spawn(proc() { let (chan, port) = channel(); setup_chan.send(chan); - ResourceManager::new(port, loaders).start(); + ResourceManager::new(port).start(); }); setup_port.recv() } struct ResourceManager { from_client: Receiver<ControlMsg>, - /// Per-scheme resource loaders - loaders: Vec<(String, LoaderTaskFactory)>, } impl ResourceManager { - fn new(from_client: Receiver<ControlMsg>, loaders: Vec<(String, LoaderTaskFactory)>) - -> ResourceManager { + fn new(from_client: Receiver<ControlMsg>) -> ResourceManager { ResourceManager { from_client : from_client, - loaders : loaders, } } } @@ -217,30 +203,38 @@ impl ResourceManager { } } - fn load(&self, load_data: LoadData, start_chan: Sender<LoadResponse>) { - match self.get_loader_factory(&load_data) { - Some(loader_factory) => { - debug!("resource_task: loading url: {:s}", load_data.url.to_str()); - loader_factory(load_data, start_chan); - } - None => { - debug!("resource_task: no loader for scheme {:s}", load_data.url.scheme); - start_sending(start_chan, Metadata::default(load_data.url)).send(Done(Err("no loader for scheme".to_string()))); - } - } - } - - fn get_loader_factory(&self, load_data: &LoadData) -> Option<LoaderTask> { - for scheme_loader in self.loaders.iter() { - match *scheme_loader { - (ref scheme, ref loader_factory) => { - if (*scheme) == load_data.url.scheme { - return Some((*loader_factory)()); + fn load(&self, mut load_data: LoadData, start_chan: Sender<LoadResponse>) { + let loader = match load_data.url.scheme.as_slice() { + "file" => file_loader::factory(), + "http" => http_loader::factory(), + "data" => data_loader::factory(), + "about" => { + match load_data.url.non_relative_scheme_data().unwrap() { + "crash" => fail!("Loading the about:crash URL."), + "failure" => { + // FIXME: Find a way to load this without relying on the `../src` directory. + let mut path = os::self_exe_path().expect("can't get exe path"); + path.pop(); + path.push_many(["src", "test", "html", "failure.html"]); + load_data.url = Url::from_file_path(&path).unwrap(); + file_loader::factory() + } + _ => { + start_sending(start_chan, Metadata::default(load_data.url)) + .send(Done(Err("Unknown about: URL.".to_string()))); + return } } + }, + _ => { + debug!("resource_task: no loader for scheme {:s}", load_data.url.scheme); + start_sending(start_chan, Metadata::default(load_data.url)) + .send(Done(Err("no loader for scheme".to_string()))); + return } - } - return None; + }; + debug!("resource_task: loading url: {:s}", load_data.url.serialize()); + loader(load_data, start_chan); } } @@ -254,7 +248,8 @@ fn test_exit() { fn test_bad_scheme() { let resource_task = new_resource_task(); let (start_chan, start) = channel(); - resource_task.send(Load(LoadData::new(FromStr::from_str("bogus://whatever").unwrap()), start_chan)); + let url = Url::parse("bogus://whatever").unwrap(); + resource_task.send(Load(LoadData::new(url), start_chan)); let response = start.recv(); match response.progress_port.recv() { Done(result) => { assert!(result.is_err()) } @@ -262,31 +257,3 @@ fn test_bad_scheme() { } resource_task.send(Exit); } - -#[cfg(test)] -static snicklefritz_payload: [u8, ..3] = [1, 2, 3]; - -#[cfg(test)] -fn snicklefritz_loader_factory() -> LoaderTask { - let f: LoaderTask = proc(load_data: LoadData, start_chan: Sender<LoadResponse>) { - let progress_chan = start_sending(start_chan, Metadata::default(load_data.url)); - progress_chan.send(Payload(Vec::from_slice(snicklefritz_payload))); - progress_chan.send(Done(Ok(()))); - }; - f -} - -#[test] -fn should_delegate_to_scheme_loader() { - let loader_factories = vec!(("snicklefritz".to_string(), snicklefritz_loader_factory)); - let resource_task = create_resource_task_with_loaders(loader_factories); - let (start_chan, start) = channel(); - resource_task.send(Load(LoadData::new(FromStr::from_str("snicklefritz://heya").unwrap()), start_chan)); - - let response = start.recv(); - let progress = response.progress_port; - - assert!(progress.recv() == Payload(Vec::from_slice(snicklefritz_payload))); - assert!(progress.recv() == Done(Ok(()))); - resource_task.send(Exit); -} diff --git a/src/components/script/dom/dedicatedworkerglobalscope.rs b/src/components/script/dom/dedicatedworkerglobalscope.rs index 918a054b91c..910ea560c1a 100644 --- a/src/components/script/dom/dedicatedworkerglobalscope.rs +++ b/src/components/script/dom/dedicatedworkerglobalscope.rs @@ -67,14 +67,15 @@ impl DedicatedWorkerGlobalScope { resource_task: ResourceTask, script_chan: ScriptChan) { let mut task_opts = TaskOpts::new(); - task_opts.name = Some(format!("Web Worker at {}", worker_url).into_maybe_owned()); + task_opts.name = Some(format!("Web Worker at {}", worker_url.serialize()) + .into_maybe_owned()); native::task::spawn_opts(task_opts, proc() { let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); - let (filename, source) = match load_whole_resource(&resource_task, worker_url.clone()) { + let (url, source) = match load_whole_resource(&resource_task, worker_url.clone()) { Err(_) => { - println!("error loading script {}", worker_url); + println!("error loading script {}", worker_url.serialize()); return; } Ok((metadata, bytes)) => { @@ -87,7 +88,7 @@ impl DedicatedWorkerGlobalScope { worker_url, js_context.clone(), receiver, resource_task, script_chan).root(); match js_context.evaluate_script( - global.reflector().get_jsobject(), source, filename.to_str(), 1) { + global.reflector().get_jsobject(), source, url.serialize(), 1) { Ok(_) => (), Err(_) => println!("evaluate_script failed") } diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index bee7494ed73..aac4e463df4 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -50,7 +50,7 @@ use servo_util::str::{DOMString, null_str_as_empty_ref}; use std::collections::hashmap::HashMap; use std::ascii::StrAsciiExt; use std::cell::{Cell, RefCell}; -use url::{Url, from_str}; +use url::Url; #[deriving(PartialEq,Encodable)] pub enum IsHTMLDocument { @@ -196,7 +196,7 @@ impl Document { url: Option<Url>, is_html_document: IsHTMLDocument, content_type: Option<DOMString>) -> Document { - let url = url.unwrap_or_else(|| from_str("about:blank").unwrap()); + let url = url.unwrap_or_else(|| Url::parse("about:blank").unwrap()); Document { node: Node::new_without_doc(DocumentNodeTypeId), @@ -337,7 +337,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { // http://dom.spec.whatwg.org/#dom-document-url fn URL(&self) -> DOMString { - self.url().to_str() + self.url().serialize() } // http://dom.spec.whatwg.org/#dom-document-documenturi diff --git a/src/components/script/dom/eventtarget.rs b/src/components/script/dom/eventtarget.rs index 75a7319ee23..cd12200815b 100644 --- a/src/components/script/dom/eventtarget.rs +++ b/src/components/script/dom/eventtarget.rs @@ -171,7 +171,7 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> { scope: *mut JSObject, ty: &str, source: DOMString) { - let url = url.to_str().to_c_str(); + let url = url.serialize().to_c_str(); let name = ty.to_c_str(); let lineno = 0; //XXXjdm need to get a real number here diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs index 83638ad44e1..31a41b9f956 100644 --- a/src/components/script/dom/htmliframeelement.rs +++ b/src/components/script/dom/htmliframeelement.rs @@ -21,11 +21,10 @@ use servo_msg::constellation_msg::{IFrameSandboxed, IFrameUnsandboxed}; use servo_msg::constellation_msg::{ConstellationChan, LoadIframeUrlMsg}; use servo_util::namespace::Null; use servo_util::str::DOMString; -use servo_util::url::try_parse_url; use std::ascii::StrAsciiExt; use std::cell::Cell; -use url::Url; +use url::{Url, UrlParser}; enum SandboxAllowance { AllowNothing = 0x00, @@ -70,8 +69,8 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { let element: &JSRef<Element> = ElementCast::from_ref(self); element.get_attribute(Null, "src").root().and_then(|src| { let window = window_from_node(self).root(); - try_parse_url(src.deref().value().as_slice(), - Some(window.deref().page().get_url())).ok() + UrlParser::new().base_url(&window.deref().page().get_url()) + .parse(src.deref().value().as_slice()).ok() }) } } diff --git a/src/components/script/dom/htmlimageelement.rs b/src/components/script/dom/htmlimageelement.rs index dbf3e6cefca..31eb2687aab 100644 --- a/src/components/script/dom/htmlimageelement.rs +++ b/src/components/script/dom/htmlimageelement.rs @@ -17,10 +17,9 @@ use dom::node::{Node, ElementNodeTypeId, NodeHelpers, window_from_node}; use dom::virtualmethods::VirtualMethods; use servo_util::geometry::to_px; use servo_net::image_cache_task; -use servo_util::url::parse_url; use servo_util::str::DOMString; use std::cell::RefCell; -use url::Url; +use url::{Url, UrlParser}; #[deriving(Encodable)] pub struct HTMLImageElement { @@ -35,13 +34,13 @@ impl HTMLImageElementDerived for EventTarget { } trait PrivateHTMLImageElementHelpers { - fn update_image(&self, value: Option<DOMString>, url: Option<Url>); + fn update_image(&self, value: Option<(DOMString, &Url)>); } impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> { /// Makes the local `image` member match the status of the `src` attribute and starts /// prefetching the image. This method must be called after `src` is changed. - fn update_image(&self, value: Option<DOMString>, url: Option<Url>) { + fn update_image(&self, value: Option<(DOMString, &Url)>) { let node: &JSRef<Node> = NodeCast::from_ref(self); let document = node.owner_doc().root(); let window = document.deref().window.root(); @@ -50,8 +49,10 @@ impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> { None => { *self.image.deref().borrow_mut() = None; } - Some(src) => { - let img_url = parse_url(src.as_slice(), url); + Some((src, base_url)) => { + let img_url = UrlParser::new().base_url(base_url).parse(src.as_slice()); + // FIXME: handle URL parse errors more gracefully. + let img_url = img_url.unwrap(); *self.image.deref().borrow_mut() = Some(img_url.clone()); // inform the image cache to load this, but don't store a @@ -254,8 +255,8 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLImageElement> { if "src" == name.as_slice() { let window = window_from_node(self).root(); - let url = Some(window.deref().get_url()); - self.update_image(Some(value), url); + let url = window.deref().get_url(); + self.update_image(Some((value, &url))); } } @@ -266,7 +267,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLImageElement> { } if "src" == name.as_slice() { - self.update_image(None, None); + self.update_image(None); } } diff --git a/src/components/script/dom/htmlobjectelement.rs b/src/components/script/dom/htmlobjectelement.rs index 7305e480988..eff1718ac69 100644 --- a/src/components/script/dom/htmlobjectelement.rs +++ b/src/components/script/dom/htmlobjectelement.rs @@ -20,9 +20,7 @@ use servo_util::str::DOMString; use servo_net::image_cache_task; use servo_net::image_cache_task::ImageCacheTask; -use servo_util::url::parse_url; use servo_util::namespace::Null; -use servo_util::url::is_image_data; use url::Url; #[deriving(Encodable)] @@ -50,13 +48,13 @@ impl HTMLObjectElement { } trait ProcessDataURL { - fn process_data_url(&self, image_cache: ImageCacheTask, url: Option<Url>); + fn process_data_url(&self, image_cache: ImageCacheTask); } impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> { // Makes the local `data` member match the status of the `data` attribute and starts /// prefetching the image. This method must be called after `data` is changed. - fn process_data_url(&self, image_cache: ImageCacheTask, url: Option<Url>) { + fn process_data_url(&self, image_cache: ImageCacheTask) { let elem: &JSRef<Element> = ElementCast::from_ref(self); // TODO: support other values @@ -64,7 +62,7 @@ impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> { elem.get_attribute(Null, "data").map(|x| x.root().Value())) { (None, Some(uri)) => { if is_image_data(uri.as_slice()) { - let data_url = parse_url(uri.as_slice(), url); + let data_url = Url::parse(uri.as_slice()).unwrap(); // Issue #84 image_cache.send(image_cache_task::Prefetch(data_url)); } @@ -74,6 +72,11 @@ impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> { } } +pub fn is_image_data(uri: &str) -> bool { + static types: &'static [&'static str] = &["data:image/png", "data:image/gif", "data:image/jpeg"]; + types.iter().any(|&type_| uri.starts_with(type_)) +} + pub trait HTMLObjectElementMethods { fn Validity(&self) -> Temporary<ValidityState>; } @@ -99,8 +102,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLObjectElement> { if "data" == name.as_slice() { let window = window_from_node(self).root(); - let url = Some(window.deref().get_url()); - self.process_data_url(window.deref().image_cache_task.clone(), url); + self.process_data_url(window.deref().image_cache_task.clone()); } } } diff --git a/src/components/script/dom/location.rs b/src/components/script/dom/location.rs index d8a1fac08c0..a622f1aac1f 100644 --- a/src/components/script/dom/location.rs +++ b/src/components/script/dom/location.rs @@ -13,7 +13,6 @@ use servo_util::str::DOMString; use serialize::{Encoder, Encodable}; use std::rc::Rc; -use url::query_to_str; #[deriving(Encodable)] pub struct Location { @@ -43,15 +42,13 @@ pub trait LocationMethods { impl<'a> LocationMethods for JSRef<'a, Location> { fn Href(&self) -> DOMString { - self.page.get_url().to_str() + self.page.get_url().serialize() } fn Search(&self) -> DOMString { - let query = query_to_str(&self.page.get_url().query); - if query.as_slice() == "" { - query - } else { - "?".to_string().append(query.as_slice()) + match self.page.get_url().query { + None => "".to_string(), + Some(ref query) => "?".to_string().append(query.as_slice()) } } } diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index b8a1bb8dce5..ee1cce1a22e 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -24,7 +24,6 @@ use servo_msg::compositor_msg::ScriptListener; use servo_net::image_cache_task::ImageCacheTask; use servo_util::str::DOMString; use servo_util::task::{spawn_named}; -use servo_util::url::parse_url; use js::jsapi::JS_CallFunctionValue; use js::jsapi::JSContext; @@ -46,7 +45,7 @@ use std::rc::Rc; use time; use serialize::{Encoder, Encodable}; -use url::Url; +use url::{Url, UrlParser}; #[deriving(PartialEq, Encodable, Eq)] pub struct TimerId(i32); @@ -316,9 +315,11 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { /// Commence a new URL load which will either replace this window or scroll to a fragment. fn load_url(&self, href: DOMString) { - let base_url = Some(self.page().get_url()); + let base_url = self.page().get_url(); debug!("current page url is {:?}", base_url); - let url = parse_url(href.as_slice(), base_url); + let url = UrlParser::new().base_url(&base_url).parse(href.as_slice()); + // FIXME: handle URL parse errors more gracefully. + let url = url.unwrap(); let ScriptChan(ref script_chan) = self.script_chan; if href.as_slice().starts_with("#") { script_chan.send(TriggerFragmentMsg(self.page.id, url)); diff --git a/src/components/script/dom/worker.rs b/src/components/script/dom/worker.rs index bd6ce75486d..74768594cdb 100644 --- a/src/components/script/dom/worker.rs +++ b/src/components/script/dom/worker.rs @@ -12,7 +12,7 @@ use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use dom::eventtarget::{EventTarget, WorkerTypeId}; use servo_util::str::DOMString; -use servo_util::url::try_parse_url; +use url::UrlParser; #[deriving(Encodable)] pub struct Worker { @@ -37,7 +37,8 @@ impl Worker { // http://www.whatwg.org/html/#dom-worker pub fn Constructor(global: &GlobalRef, scriptURL: DOMString) -> Fallible<Temporary<Worker>> { // Step 2-4. - let worker_url = match try_parse_url(scriptURL.as_slice(), Some(global.get_url())) { + let worker_url = match UrlParser::new().base_url(&global.get_url()) + .parse(scriptURL.as_slice()) { Ok(url) => url, Err(_) => return Err(Syntax), }; diff --git a/src/components/script/dom/xmlhttprequest.rs b/src/components/script/dom/xmlhttprequest.rs index 5f26e51bba0..d6813ed253b 100644 --- a/src/components/script/dom/xmlhttprequest.rs +++ b/src/components/script/dom/xmlhttprequest.rs @@ -25,7 +25,7 @@ use dom::xmlhttprequestupload::XMLHttpRequestUpload; use encoding::all::UTF_8; use encoding::label::encoding_from_whatwg_label; -use encoding::types::{DecodeReplace, Encoding, EncodeReplace}; +use encoding::types::{DecodeReplace, Encoding, EncodingRef, EncodeReplace}; use ResponseHeaderCollection = http::headers::response::HeaderCollection; use RequestHeaderCollection = http::headers::request::HeaderCollection; @@ -46,7 +46,6 @@ use net::resource_task::{ResourceTask, Load, LoadData, Payload, Done}; use script_task::{ScriptChan, XHRProgressMsg}; use servo_util::str::DOMString; use servo_util::task::spawn_named; -use servo_util::url::{parse_url, try_parse_url}; use std::ascii::StrAsciiExt; use std::cell::{Cell, RefCell}; @@ -56,7 +55,7 @@ use std::from_str::FromStr; use std::path::BytesContainer; use std::task::TaskBuilder; use time; -use url::Url; +use url::{Url, UrlParser}; use dom::bindings::codegen::UnionTypes::StringOrURLSearchParams::{eString, eURLSearchParams, StringOrURLSearchParams}; pub type SendParam = StringOrURLSearchParams; @@ -113,7 +112,7 @@ pub struct XMLHttpRequest { // Associated concepts request_method: Untraceable<RefCell<Method>>, - request_url: Untraceable<RefCell<Url>>, + request_url: Untraceable<RefCell<Option<Url>>>, request_headers: Untraceable<RefCell<RequestHeaderCollection>>, request_body_len: Traceable<Cell<uint>>, sync: Traceable<Cell<bool>>, @@ -146,7 +145,7 @@ impl XMLHttpRequest { response_headers: Untraceable::new(RefCell::new(ResponseHeaderCollection::new())), request_method: Untraceable::new(RefCell::new(Get)), - request_url: Untraceable::new(RefCell::new(parse_url("", None))), + request_url: Untraceable::new(RefCell::new(None)), request_headers: Untraceable::new(RefCell::new(RequestHeaderCollection::new())), request_body_len: Traceable::new(Cell::new(0)), sync: Traceable::new(Cell::new(false)), @@ -293,7 +292,6 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { Method::from_str_or_new(s.as_slice()) }); // Step 2 - let base: Option<Url> = Some(self.global.root().root_ref().get_url()); match maybe_method { // Step 4 Some(Connect) | Some(Trace) => Err(Security), @@ -303,7 +301,8 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { *self.request_method.deref().borrow_mut() = maybe_method.unwrap(); // Step 6 - let parsed_url = match try_parse_url(url.as_slice(), base) { + let base = self.global.root().root_ref().get_url(); + let parsed_url = match UrlParser::new().base_url(&base).parse(url.as_slice()) { Ok(parsed) => parsed, Err(_) => return Err(Syntax) // Step 7 }; @@ -316,7 +315,7 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { } // XXXManishearth abort existing requests // Step 12 - *self.request_url.deref().borrow_mut() = parsed_url; + *self.request_url.deref().borrow_mut() = Some(parsed_url); *self.request_headers.deref().borrow_mut() = RequestHeaderCollection::new(); self.send_flag.deref().set(false); *self.status_text.deref().borrow_mut() = ByteString::new(vec!()); @@ -487,7 +486,7 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { let global = self.global.root(); let resource_task = global.root_ref().resource_task(); - let mut load_data = LoadData::new(self.request_url.deref().borrow().clone()); + let mut load_data = LoadData::new(self.request_url.deref().borrow().clone().unwrap()); load_data.data = extracted; // Default headers @@ -517,16 +516,8 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { // XXXManishearth this is to be replaced with Origin for CORS (with no path) let referer_url = self.global.root().root_ref().get_url(); - let mut buf = String::new(); - buf.push_str(referer_url.scheme.as_slice()); - buf.push_str("://".as_slice()); - buf.push_str(referer_url.host.as_slice()); - referer_url.port.as_ref().map(|p| { - buf.push_str(":".as_slice()); - buf.push_str(p.as_slice()); - }); - buf.push_str(referer_url.path.as_slice()); - self.request_headers.deref().borrow_mut().referer = Some(buf); + self.request_headers.deref().borrow_mut().referer = + Some(referer_url.serialize_no_fragment()); load_data.headers = (*self.request_headers.deref().borrow()).clone(); load_data.method = (*self.request_method.deref().borrow()).clone(); @@ -910,7 +901,7 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { self.timer.deref().borrow_mut().oneshot(0); } fn text_response(&self) -> DOMString { - let mut encoding = UTF_8 as &Encoding+Send; + let mut encoding = UTF_8 as EncodingRef; match self.response_headers.deref().borrow().content_type { Some(ref x) => { for &(ref name, ref value) in x.parameters.iter() { @@ -945,7 +936,7 @@ trait Extractable { impl Extractable for SendParam { fn extract(&self) -> Vec<u8> { // http://fetch.spec.whatwg.org/#concept-fetchbodyinit-extract - let encoding = UTF_8 as &Encoding+Send; + let encoding = UTF_8 as EncodingRef; match *self { eString(ref s) => encoding.encode(s.as_slice(), EncodeReplace).unwrap(), eURLSearchParams(ref usp) => usp.root().serialize(None) // Default encoding is UTF8 diff --git a/src/components/script/html/cssparse.rs b/src/components/script/html/cssparse.rs index 2f96822770e..473b64c7d76 100644 --- a/src/components/script/html/cssparse.rs +++ b/src/components/script/html/cssparse.rs @@ -29,7 +29,7 @@ fn parse_css(provenance: StylesheetProvenance) -> Stylesheet { match provenance { UrlProvenance(url, resource_task) => { - debug!("cssparse: loading style sheet at {:s}", url.to_str()); + debug!("cssparse: loading style sheet at {:s}", url.serialize()); let (input_chan, input_port) = channel(); resource_task.send(Load(LoadData::new(url), input_chan)); let LoadResponse { metadata: metadata, progress_port: progress_port , ..} diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index db71fdb3e51..11e3ca81610 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -23,13 +23,12 @@ use servo_util::namespace; use servo_util::namespace::{Namespace, Null}; use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS}; use servo_util::task::spawn_named; -use servo_util::url::try_parse_url; use std::ascii::StrAsciiExt; use std::mem; use std::cell::RefCell; use std::comm::{channel, Sender, Receiver}; use style::Stylesheet; -use url::Url; +use url::{Url, UrlParser}; macro_rules! handle_element( ($document: expr, @@ -133,7 +132,7 @@ fn js_script_listener(to_parent: Sender<HtmlDiscoveryMessage>, Ok(JSTaskNewFile(url)) => { match load_whole_resource(&resource_task, url.clone()) { Err(_) => { - error!("error loading script {:s}", url.to_str()); + error!("error loading script {:s}", url.serialize()); } Ok((metadata, bytes)) => { result_vec.push(JSFile { @@ -421,8 +420,9 @@ pub fn parse_html(page: &Page, s.as_slice().eq_ignore_ascii_case("stylesheet") }) => { debug!("found CSS stylesheet: {:s}", *href); - match try_parse_url(href.as_slice(), Some(url2.clone())) { - Ok(url) => css_chan2.send(CSSTaskNewFile(UrlProvenance(url, resource_task.clone()))), + match UrlParser::new().base_url(&url2).parse(href.as_slice()) { + Ok(url) => css_chan2.send(CSSTaskNewFile( + UrlProvenance(url, resource_task.clone()))), Err(e) => debug!("Parsing url {:s} failed: {:s}", *href, e) }; } @@ -504,9 +504,10 @@ pub fn parse_html(page: &Page, match script.get_attribute(Null, "src").root() { Some(src) => { debug!("found script: {:s}", src.deref().Value()); - match try_parse_url(src.deref().value().as_slice(), Some(url3.clone())) { - Ok(new_url) => js_chan2.send(JSTaskNewFile(new_url)), - Err(e) => debug!("Parsing url {:s} failed: {:s}", src.deref().Value(), e) + match UrlParser::new().base_url(&url3) + .parse(src.deref().value().as_slice()) { + Ok(new_url) => js_chan2.send(JSTaskNewFile(new_url)), + Err(e) => debug!("Parsing url {:s} failed: {:s}", src.deref().Value(), e) }; } None => { @@ -541,7 +542,7 @@ pub fn parse_html(page: &Page, parser.parse_chunk(data.as_slice()); } Done(Err(err)) => { - fail!("Failed to load page URL {:s}, error: {:s}", url.to_str(), err); + fail!("Failed to load page URL {:s}, error: {:s}", url.serialize(), err); } Done(..) => { break; diff --git a/src/components/script/script.rs b/src/components/script/script.rs index 54f6f0db30f..9e852930744 100644 --- a/src/components/script/script.rs +++ b/src/components/script/script.rs @@ -40,7 +40,7 @@ extern crate servo_util = "util"; extern crate style; extern crate sync; extern crate servo_msg = "msg"; -extern crate url; +extern crate url = "url_"; pub mod dom { pub mod bindings { diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 4b86bafcdde..87ae7a4752e 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -590,7 +590,7 @@ impl ScriptTask { let global_obj = window.reflector().get_jsobject(); //FIXME: this should have some kind of error handling, or explicitly // drop an exception on the floor. - match cx.evaluate_script(global_obj, file.data.clone(), file.url.to_str(), 1) { + match cx.evaluate_script(global_obj, file.data.clone(), file.url.serialize(), 1) { Ok(_) => (), Err(_) => println!("evaluate_script failed") } diff --git a/src/components/style/properties/common_types.rs b/src/components/style/properties/common_types.rs index 5dbffb81938..6672daa1894 100644 --- a/src/components/style/properties/common_types.rs +++ b/src/components/style/properties/common_types.rs @@ -4,6 +4,8 @@ #![allow(non_camel_case_types)] +use url::{Url, UrlParser}; + pub use servo_util::geometry::Au; pub type CSSFloat = f64; @@ -253,3 +255,8 @@ pub mod computed { } } } + +pub fn parse_url(input: &str, base_url: &Url) -> Url { + UrlParser::new().base_url(base_url).parse(input) + .unwrap_or_else(|_| Url::parse("about:invalid").unwrap()) +} diff --git a/src/components/style/properties/mod.rs.mako b/src/components/style/properties/mod.rs.mako index e6506c4472d..5dc6a22012d 100644 --- a/src/components/style/properties/mod.rs.mako +++ b/src/components/style/properties/mod.rs.mako @@ -7,7 +7,6 @@ pub use std::ascii::StrAsciiExt; use serialize::{Encodable, Encoder}; -pub use servo_util::url::parse_url; use servo_util::logical_geometry::{WritingMode, LogicalMargin}; use sync::Arc; pub use url::Url; @@ -597,7 +596,7 @@ pub mod longhands { pub fn from_component_value(component_value: &ComponentValue, base_url: &Url) -> Option<SpecifiedValue> { match component_value { &ast::URL(ref url) => { - let image_url = parse_url(url.as_slice(), Some(base_url.clone())); + let image_url = parse_url(url.as_slice(), base_url); Some(Some(image_url)) }, &ast::Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Some(None), diff --git a/src/components/style/style.rs b/src/components/style/style.rs index dc70e6e9d5f..276b831cc06 100644 --- a/src/components/style/style.rs +++ b/src/components/style/style.rs @@ -21,7 +21,7 @@ extern crate geom; extern crate num; extern crate serialize; extern crate sync; -extern crate url; +extern crate url = "url_"; extern crate cssparser; extern crate encoding; diff --git a/src/components/util/url.rs b/src/components/util/url.rs deleted file mode 100644 index a9cd24d610e..00000000000 --- a/src/components/util/url.rs +++ /dev/null @@ -1,210 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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 std::collections::hashmap::HashMap; -use std::os; -use std_url; -use std_url::Url; - -/** -Create a URL object from a string. Does various helpful browsery things like - -* If there's no current url and the path looks like a file then it will - create a file url based of the current working directory -* If there's a current url and the new path is relative then the new url - is based off the current url - -*/ -// TODO: about:failure-> -pub fn try_parse_url(str_url: &str, base_url: Option<std_url::Url>) -> Result<std_url::Url, String> { - let str_url = str_url.trim_chars(&[' ', '\t', '\n', '\r', '\x0C']).to_string(); - let schm = std_url::get_scheme(str_url.as_slice()); - let str_url = match schm { - Err(_) => { - if base_url.is_none() { - // Assume we've been given a file path. If it's absolute just return - // it, otherwise make it absolute with the cwd. - if str_url.as_slice().starts_with("/") { - format!("file://{}", str_url) - } else { - let mut path = os::getcwd(); - path.push(str_url); - // FIXME (#1094): not the right way to transform a path - format!("file://{}", path.display().to_str()) - } - } else { - let base_url = base_url.unwrap(); - debug!("parse_url: base_url: {:?}", base_url); - - let mut new_url = base_url.clone(); - new_url.query = vec!(); - new_url.fragment = None; - - if str_url.as_slice().starts_with("//") { - format!("{}:{}", new_url.scheme, str_url) - } else if base_url.path.is_empty() || str_url.as_slice().starts_with("/") { - new_url.path = "/".to_string(); - format!("{}{}", new_url, str_url.as_slice().trim_left_chars('/')) - } else if str_url.as_slice().starts_with("#") { - format!("{}{}", new_url, str_url) - } else { // relative path - let base_path = base_url.path.as_slice().trim_right_chars(|c: char| c != '/'); - new_url.path = base_path.to_string(); - format!("{}{}", new_url, str_url) - } - } - }, - Ok((scheme, page)) => { - match scheme.as_slice() { - "about" => { - match page.as_slice() { - "crash" => { - fail!("about:crash"); - } - "failure" => { - let mut path = os::self_exe_path().expect("can't get exe path"); - path.push("../src/test/html/failure.html"); - // FIXME (#1094): not the right way to transform a path - format!("file://{}", path.display().to_str()) - } - // TODO: handle the rest of the about: pages - _ => str_url.to_string() - } - }, - "data" => { - // Drop whitespace within data: URLs, e.g. newlines within a base64 - // src="..." block. Whitespace intended as content should be - // %-encoded or base64'd. - str_url.as_slice().chars().filter(|&c| !c.is_whitespace()).collect() - }, - _ => str_url.to_string() - } - } - }; - - std_url::from_str(str_url.as_slice()) -} - -pub fn parse_url(str_url: &str, base_url: Option<std_url::Url>) -> std_url::Url { - // FIXME: Need to handle errors - try_parse_url(str_url, base_url).ok().expect("URL parsing failed") -} - - -#[cfg(test)] -mod parse_url_tests { - use super::parse_url; - use std::os; - - #[test] - fn should_create_absolute_file_url_if_base_url_is_none_and_str_url_looks_filey() { - let file = "local.html"; - let url = parse_url(file, None); - debug!("url: {:?}", url); - assert!("file" == url.scheme.as_slice()); - let path = os::getcwd(); - // FIXME (#1094): not the right way to transform a path - assert!(url.path.as_slice().contains(path.display().to_str().as_slice())); - } - - #[test] - fn should_create_url_based_on_old_url_1() { - let old_str = "http://example.com"; - let old_url = parse_url(old_str, None); - let new_str = "index.html"; - let new_url = parse_url(new_str, Some(old_url)); - assert!("http" == new_url.scheme.as_slice()); - assert!("example.com" == new_url.host.as_slice()); - assert!("/index.html" == new_url.path.as_slice()); - } - - #[test] - fn should_create_url_based_on_old_url_2() { - let old_str = "http://example.com/"; - let old_url = parse_url(old_str, None); - let new_str = "index.html"; - let new_url = parse_url(new_str, Some(old_url)); - assert!("http" == new_url.scheme.as_slice()); - assert!("example.com" == new_url.host.as_slice()); - assert!("/index.html" == new_url.path.as_slice()); - } - - #[test] - fn should_create_url_based_on_old_url_3() { - let old_str = "http://example.com/index.html"; - let old_url = parse_url(old_str, None); - let new_str = "crumpet.html"; - let new_url = parse_url(new_str, Some(old_url)); - assert!("http" == new_url.scheme.as_slice()); - assert!("example.com" == new_url.host.as_slice()); - assert!("/crumpet.html" == new_url.path.as_slice()); - } - - #[test] - fn should_create_url_based_on_old_url_4() { - let old_str = "http://example.com/snarf/index.html"; - let old_url = parse_url(old_str, None); - let new_str = "crumpet.html"; - let new_url = parse_url(new_str, Some(old_url)); - assert!("http" == new_url.scheme.as_slice()); - assert!("example.com" == new_url.host.as_slice()); - assert!("/snarf/crumpet.html" == new_url.path.as_slice()); - } - - #[test] - fn should_create_url_based_on_old_url_5() { - let old_str = "http://example.com/index.html"; - let old_url = parse_url(old_str, None); - let new_str = "#top"; - let new_url = parse_url(new_str, Some(old_url)); - - assert!("http" == new_url.scheme.as_slice()); - assert!("example.com" == new_url.host.as_slice()); - assert!("/index.html" == new_url.path.as_slice()); - assert!(new_url.fragment == Some("top".to_string())); - } - - #[test] - fn should_create_url_based_on_old_url_6() { - use std_url::UserInfo; - - let old_str = "http://foo:bar@example.com:8080/index.html"; - let old_url = parse_url(old_str, None); - let new_str = "#top"; - let new_url = parse_url(new_str, Some(old_url)); - - assert!("http" == new_url.scheme.as_slice()); - assert!(new_url.user == Some(UserInfo { user: "foo".to_string(), pass: Some("bar".to_string()) })); - assert!("example.com" == new_url.host.as_slice()); - assert!(new_url.port == Some("8080".to_string())); - assert!("/index.html" == new_url.path.as_slice()); - assert!(new_url.fragment == Some("top".to_string())); - } - - #[test] - fn should_create_url_based_on_old_url_7() { - let old_str = "https://example.com/snarf/index.html"; - let old_url = parse_url(old_str, None); - let new_str = "//example.com/crumpet.html"; - let new_url = parse_url(new_str, Some(old_url)); - assert!("https" == new_url.scheme.as_slice()); - assert!("example.com" == new_url.host.as_slice()); - assert!("/crumpet.html" == new_url.path.as_slice()); - } - -} - -pub type UrlMap<T> = HashMap<std_url::Url, T>; - -pub fn url_map<T: Clone + 'static>() -> UrlMap<T> { - HashMap::new() -} - - -pub fn is_image_data(uri: &str) -> bool { - static types: &'static [&'static str] = &["data:image/png", "data:image/gif", "data:image/jpeg"]; - types.iter().any(|&type_| uri.starts_with(type_)) -} - - diff --git a/src/components/util/util.rs b/src/components/util/util.rs index b378d5074f2..92f1995cce4 100644 --- a/src/components/util/util.rs +++ b/src/components/util/util.rs @@ -28,7 +28,6 @@ extern crate sync; #[cfg(target_os="macos")] extern crate task_info; extern crate std_time = "time"; -extern crate std_url = "url"; extern crate string_cache; pub mod atom; @@ -45,6 +44,5 @@ pub mod sort; pub mod str; pub mod task; pub mod time; -pub mod url; pub mod vec; pub mod workqueue; diff --git a/src/support/http/rust-http b/src/support/http/rust-http -Subproject ae4820bfd19af931bfc84f406b74dfb67ab5ebe +Subproject e95cdaef5f366d9911e6d06340b79b8d23245b7 diff --git a/src/support/url/Makefile.in b/src/support/url/Makefile.in new file mode 100644 index 00000000000..3ae64d01abb --- /dev/null +++ b/src/support/url/Makefile.in @@ -0,0 +1,25 @@ +VPATH=%VPATH% + +RUSTC ?= rustc +RUSTFLAGS ?= +EXT_DEPS ?= + +SRC=$(shell find $(VPATH)/src -type f) + +.PHONY: all +all: liburl.dummy + +liburl.dummy: src/url.rs $(SRC) $(EXT_DEPS) + $(RUSTC) $(RUSTFLAGS) $< --out-dir . + touch $@ + +url-test: src/url.rs $(SRC) + $(RUSTC) $(RUSTFLAGS) $< -o $@ --test + +.PHONY: check +check: url-test + ./url-test $(TEST) + +.PHONY: clean +clean: + rm -f *.o *.a *.so *.dylib *.rlib *.dll *.dummy *-test diff --git a/src/support/url/configure b/src/support/url/configure new file mode 100644 index 00000000000..4e86aec066d --- /dev/null +++ b/src/support/url/configure @@ -0,0 +1,4 @@ +#!/bin/bash + +SRCDIR="$(cd $(dirname $0) && pwd)" +sed "s#%VPATH%#${SRCDIR}/rust-url#" ${SRCDIR}/Makefile.in > Makefile diff --git a/src/support/url/rust-url b/src/support/url/rust-url new file mode 160000 +Subproject 19c1aa0e73c3252761ca3d722cba9cc0ae1ba1c |