servo: Merge #14246 - Urlmageddon (from emilio:servo-url); r=SimonSapin
authorEmilio Cobos Álvarez <ecoal95@gmail.com>
Thu, 17 Nov 2016 15:34:47 -0600
changeset 340236 8be38313f7cc5276e35045ba70a25928daefd4cc
parent 340235 241d1acf9ae05d7c5f505ff234c86ed5e42bd7e4
child 340237 96c5d29970d37ba67cb9ab80577bdabe58454563
push id86548
push userkwierso@gmail.com
push dateSat, 04 Feb 2017 01:35:21 +0000
treeherdermozilla-inbound@e7b96d015d03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersSimonSapin
servo: Merge #14246 - Urlmageddon (from emilio:servo-url); r=SimonSapin <!-- Please describe your changes on the following line: --> Still needs a bunch of code in net to be converted in order to get more advantage of this for images and stuff, but meanwhile this should help quite a bit with #13778. Still wanted to get this in. r? @SimonSapin Source-Repo: https://github.com/servo/servo Source-Revision: 22aebdf5d41a3509cd6515ccf5edcdf33715a76d
servo/components/compositing/Cargo.toml
servo/components/compositing/compositor.rs
servo/components/compositing/compositor_thread.rs
servo/components/compositing/lib.rs
servo/components/compositing/windowing.rs
servo/components/constellation/Cargo.toml
servo/components/constellation/constellation.rs
servo/components/constellation/lib.rs
servo/components/constellation/pipeline.rs
servo/components/devtools_traits/Cargo.toml
servo/components/devtools_traits/lib.rs
servo/components/gfx/Cargo.toml
servo/components/gfx/font_cache_thread.rs
servo/components/gfx/lib.rs
servo/components/gfx/platform/macos/font_template.rs
servo/components/layout/Cargo.toml
servo/components/layout/construct.rs
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/fragment.rs
servo/components/layout/lib.rs
servo/components/layout_thread/Cargo.toml
servo/components/layout_thread/lib.rs
servo/components/layout_traits/Cargo.toml
servo/components/layout_traits/lib.rs
servo/components/net/Cargo.toml
servo/components/net/about_loader.rs
servo/components/net/blob_loader.rs
servo/components/net/chrome_loader.rs
servo/components/net/cookie.rs
servo/components/net/cookie_storage.rs
servo/components/net/data_loader.rs
servo/components/net/fetch/cors_cache.rs
servo/components/net/fetch/methods.rs
servo/components/net/file_loader.rs
servo/components/net/http_loader.rs
servo/components/net/image_cache_thread.rs
servo/components/net/lib.rs
servo/components/net/resource_thread.rs
servo/components/net/storage_thread.rs
servo/components/net/websocket_loader.rs
servo/components/net_traits/Cargo.toml
servo/components/net_traits/blob_url_store.rs
servo/components/net_traits/hosts.rs
servo/components/net_traits/image_cache_thread.rs
servo/components/net_traits/lib.rs
servo/components/net_traits/request.rs
servo/components/net_traits/response.rs
servo/components/net_traits/storage_thread.rs
servo/components/script/Cargo.toml
servo/components/script/document_loader.rs
servo/components/script/dom/bindings/trace.rs
servo/components/script/dom/canvasrenderingcontext2d.rs
servo/components/script/dom/client.rs
servo/components/script/dom/dedicatedworkerglobalscope.rs
servo/components/script/dom/document.rs
servo/components/script/dom/element.rs
servo/components/script/dom/eventsource.rs
servo/components/script/dom/eventtarget.rs
servo/components/script/dom/globalscope.rs
servo/components/script/dom/htmlanchorelement.rs
servo/components/script/dom/htmlbaseelement.rs
servo/components/script/dom/htmlbodyelement.rs
servo/components/script/dom/htmlcanvaselement.rs
servo/components/script/dom/htmlformelement.rs
servo/components/script/dom/htmliframeelement.rs
servo/components/script/dom/htmlimageelement.rs
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmediaelement.rs
servo/components/script/dom/htmlscriptelement.rs
servo/components/script/dom/location.rs
servo/components/script/dom/node.rs
servo/components/script/dom/request.rs
servo/components/script/dom/response.rs
servo/components/script/dom/serviceworker.rs
servo/components/script/dom/serviceworkerglobalscope.rs
servo/components/script/dom/serviceworkerregistration.rs
servo/components/script/dom/servoparser/html.rs
servo/components/script/dom/servoparser/mod.rs
servo/components/script/dom/servoparser/xml.rs
servo/components/script/dom/storage.rs
servo/components/script/dom/url.rs
servo/components/script/dom/urlhelper.rs
servo/components/script/dom/websocket.rs
servo/components/script/dom/window.rs
servo/components/script/dom/workerglobalscope.rs
servo/components/script/dom/workerlocation.rs
servo/components/script/dom/xmldocument.rs
servo/components/script/dom/xmlhttprequest.rs
servo/components/script/fetch.rs
servo/components/script/layout_wrapper.rs
servo/components/script/lib.rs
servo/components/script/origin.rs
servo/components/script/script_thread.rs
servo/components/script/serviceworker_manager.rs
servo/components/script/webdriver_handlers.rs
servo/components/script_layout_interface/Cargo.toml
servo/components/script_layout_interface/lib.rs
servo/components/script_layout_interface/message.rs
servo/components/script_layout_interface/wrapper_traits.rs
servo/components/script_traits/Cargo.toml
servo/components/script_traits/lib.rs
servo/components/script_traits/script_msg.rs
servo/components/script_traits/webdriver_msg.rs
servo/components/servo/Cargo.toml
servo/components/servo/lib.rs
servo/components/style/Cargo.toml
servo/components/style/attr.rs
servo/components/style/font_face.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/lib.rs
servo/components/style/parser.rs
servo/components/style/properties/declaration_block.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/stylesheets.rs
servo/components/style/values/specified/image.rs
servo/components/style/values/specified/url.rs
servo/components/url/Cargo.toml
servo/components/url/lib.rs
servo/components/util/Cargo.toml
servo/components/util/lib.rs
servo/components/util/opts.rs
servo/components/webdriver_server/Cargo.toml
servo/components/webdriver_server/lib.rs
servo/ports/cef/Cargo.lock
servo/ports/cef/Cargo.toml
servo/ports/cef/lib.rs
servo/ports/cef/window.rs
servo/ports/geckolib/Cargo.lock
servo/ports/geckolib/Cargo.toml
servo/ports/geckolib/glue.rs
servo/ports/geckolib/lib.rs
servo/ports/glutin/Cargo.toml
servo/ports/glutin/lib.rs
servo/ports/glutin/window.rs
servo/ports/servo/Cargo.lock
servo/tests/unit/net/Cargo.toml
servo/tests/unit/net/chrome_loader.rs
servo/tests/unit/net/cookie.rs
servo/tests/unit/net/cookie_http_state.rs
servo/tests/unit/net/data_loader.rs
servo/tests/unit/net/fetch.rs
servo/tests/unit/net/http_loader.rs
servo/tests/unit/net/lib.rs
servo/tests/unit/net/resource_thread.rs
servo/tests/unit/script/Cargo.toml
servo/tests/unit/script/lib.rs
servo/tests/unit/script/origin.rs
servo/tests/unit/style/Cargo.toml
servo/tests/unit/style/lib.rs
servo/tests/unit/style/media_queries.rs
servo/tests/unit/style/parsing/border.rs
servo/tests/unit/style/parsing/font.rs
servo/tests/unit/style/parsing/image.rs
servo/tests/unit/style/parsing/inherited_text.rs
servo/tests/unit/style/parsing/mask.rs
servo/tests/unit/style/parsing/mod.rs
servo/tests/unit/style/stylesheets.rs
servo/tests/unit/style/viewport.rs
servo/tests/unit/stylo/Cargo.toml
servo/tests/unit/stylo/lib.rs
--- a/servo/components/compositing/Cargo.toml
+++ b/servo/components/compositing/Cargo.toml
@@ -18,19 +18,19 @@ ipc-channel = "0.5"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 script_traits = {path = "../script_traits"}
 serde = "0.8"
 serde_derive = "0.8"
+servo_url = {path = "../url", features = ["servo"]}
 style_traits = {path = "../style_traits"}
 time = "0.1.17"
-url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../util"}
 
 [dependencies.webrender]
 git = "https://github.com/servo/webrender"
 default-features = false
 features = ["serde_derive"]
 
 [dependencies.webrender_traits]
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -21,25 +21,25 @@ use msg::constellation_msg::{Key, KeyMod
 use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId, TraversalDirection};
 use net_traits::image::base::{Image, PixelFormat};
 use profile_traits::time::{self, ProfilerCategory, profile};
 use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
 use script_traits::{ConstellationMsg, LayoutControlMsg, LoadData, MouseButton};
 use script_traits::{MouseEventType, StackingContextScrollState};
 use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType};
 use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent};
+use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::fs::File;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use style_traits::{PagePx, ViewportPx};
 use style_traits::viewport::ViewportConstraints;
 use time::{precise_time_ns, precise_time_s};
 use touch::{TouchHandler, TouchAction};
-use url::Url;
 use util::geometry::ScreenPx;
 use util::opts;
 use util::prefs::PREFS;
 use webrender;
 use webrender_traits::{self, ScrollEventPhase};
 use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
 
 #[derive(Debug, PartialEq)]
@@ -692,17 +692,17 @@ impl<Window: WindowMethods> IOCompositor
         let set_title = self.root_pipeline.as_ref().map_or(false, |root_pipeline| {
             root_pipeline.id == pipeline_id
         });
         if set_title {
             self.window.set_page_title(title);
         }
     }
 
-    fn change_page_url(&mut self, _: PipelineId, url: Url) {
+    fn change_page_url(&mut self, _: PipelineId, url: ServoUrl) {
         self.window.set_page_url(url);
     }
 
     fn set_frame_tree(&mut self,
                       frame_tree: &SendableFrameTree,
                       response_chan: IpcSender<()>) {
         debug!("Setting the frame tree for pipeline {}", frame_tree.pipeline.id);
         if let Err(e) = response_chan.send(()) {
@@ -876,17 +876,17 @@ impl<Window: WindowMethods> IOCompositor
         self.window_size = new_size;
 
         self.send_window_size(WindowSizeType::Resize);
     }
 
     fn on_load_url_window_event(&mut self, url_string: String) {
         debug!("osmain: loading URL `{}`", url_string);
         self.got_load_complete_message = false;
-        match Url::parse(&url_string) {
+        match ServoUrl::parse(&url_string) {
             Ok(url) => {
                 self.window.set_page_url(url.clone());
                 let msg = match self.root_pipeline {
                     Some(ref pipeline) => ConstellationMsg::LoadUrl(pipeline.id, LoadData::new(url, None, None)),
                     None => ConstellationMsg::InitLoadUrl(url)
                 };
                 if let Err(e) = self.constellation_chan.send(msg) {
                     warn!("Sending load url to constellation failed ({}).", e);
--- a/servo/components/compositing/compositor_thread.rs
+++ b/servo/components/compositing/compositor_thread.rs
@@ -9,21 +9,21 @@ use compositor::CompositingReason;
 use euclid::point::Point2D;
 use euclid::size::Size2D;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId};
 use net_traits::image::base::Image;
 use profile_traits::mem;
 use profile_traits::time;
 use script_traits::{AnimationState, ConstellationMsg, EventResult};
+use servo_url::ServoUrl;
 use std::fmt::{Debug, Error, Formatter};
 use std::sync::mpsc::{Receiver, Sender};
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
-use url::Url;
 use webrender;
 use webrender_traits;
 
 /// Sends messages to the compositor. This is a trait supplied by the port because the method used
 /// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
 /// process, and so forth.
 pub trait CompositorProxy : 'static + Send {
     /// Sends a message to the compositor.
@@ -71,17 +71,17 @@ pub enum Msg {
     /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
     ShutdownComplete,
 
     /// Scroll a page in a window
     ScrollFragmentPoint(PipelineId, Point2D<f32>, bool),
     /// Alerts the compositor that the current page has changed its title.
     ChangePageTitle(PipelineId, Option<String>),
     /// Alerts the compositor that the current page has changed its URL.
-    ChangePageUrl(PipelineId, Url),
+    ChangePageUrl(PipelineId, ServoUrl),
     /// Alerts the compositor that the given pipeline has changed whether it is running animations.
     ChangeRunningAnimationsState(PipelineId, AnimationState),
     /// Replaces the current frame tree, typically called during main frame navigation.
     SetFrameTree(SendableFrameTree, IpcSender<()>),
     /// The load of a page has begun: (can go back, can go forward).
     LoadStart(bool, bool),
     /// The load of a page has completed: (can go back, can go forward, is root frame).
     LoadComplete(bool, bool, bool),
@@ -97,17 +97,17 @@ pub enum Msg {
     SetCursor(Cursor),
     /// Composite to a PNG file and return the Image over a passed channel.
     CreatePng(IpcSender<Option<Image>>),
     /// Alerts the compositor that the viewport has been constrained in some manner
     ViewportConstrained(PipelineId, ViewportConstraints),
     /// A reply to the compositor asking if the output image is stable.
     IsReadyToSaveImageReply(bool),
     /// A favicon was detected
-    NewFavicon(Url),
+    NewFavicon(ServoUrl),
     /// <head> tag finished parsing
     HeadParsed,
     /// A status message to be displayed by the browser chrome.
     Status(Option<String>),
     /// Get Window Informations size and position
     GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
     /// Move the window to a point
     MoveTo(Point2D<i32>),
--- a/servo/components/compositing/lib.rs
+++ b/servo/components/compositing/lib.rs
@@ -18,19 +18,19 @@ extern crate ipc_channel;
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 #[macro_use]
 extern crate profile_traits;
 extern crate script_traits;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_url;
 extern crate style_traits;
 extern crate time;
-extern crate url;
 #[macro_use]
 extern crate util;
 extern crate webrender;
 extern crate webrender_traits;
 
 pub use compositor_thread::CompositorProxy;
 pub use compositor::IOCompositor;
 use euclid::size::TypedSize2D;
--- a/servo/components/compositing/windowing.rs
+++ b/servo/components/compositing/windowing.rs
@@ -8,19 +8,19 @@ use compositor_thread::{CompositorProxy,
 use euclid::{Point2D, Size2D};
 use euclid::point::TypedPoint2D;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use gfx_traits::DevicePixel;
 use msg::constellation_msg::{Key, KeyModifiers, KeyState};
 use net_traits::net_error_list::NetError;
 use script_traits::{MouseButton, TouchEventType, TouchId, TouchpadPressurePhase};
+use servo_url::ServoUrl;
 use std::fmt::{Debug, Error, Formatter};
 use style_traits::cursor::Cursor;
-use url::Url;
 use util::geometry::ScreenPx;
 
 #[derive(Clone)]
 pub enum MouseWindowEvent {
     Click(MouseButton, TypedPoint2D<f32, DevicePixel>),
     MouseDown(MouseButton, TypedPoint2D<f32, DevicePixel>),
     MouseUp(MouseButton, TypedPoint2D<f32, DevicePixel>),
 }
@@ -118,17 +118,17 @@ pub trait WindowMethods {
     /// Set the size inside of borders and head
     fn set_inner_size(&self, size: Size2D<u32>);
     /// Set the window position
     fn set_position(&self, point: Point2D<i32>);
 
     /// Sets the page title for the current page.
     fn set_page_title(&self, title: Option<String>);
     /// Sets the load data for the current page.
-    fn set_page_url(&self, url: Url);
+    fn set_page_url(&self, url: ServoUrl);
     /// Called when the browser chrome should display a status message.
     fn status(&self, Option<String>);
     /// Called when the browser has started loading a frame.
     fn load_start(&self, back: bool, forward: bool);
     /// Called when the browser is done loading a frame.
     fn load_end(&self, back: bool, forward: bool, root: bool);
     /// Called when the browser encounters an error while loading a URL
     fn load_error(&self, code: NetError, url: String);
@@ -155,10 +155,10 @@ pub trait WindowMethods {
 
     /// Process a key event.
     fn handle_key(&self, ch: Option<char>, key: Key, mods: KeyModifiers);
 
     /// Does this window support a clipboard
     fn supports_clipboard(&self) -> bool;
 
     /// Add a favicon
-    fn set_favicon(&self, url: Url);
+    fn set_favicon(&self, url: ServoUrl);
 }
--- a/servo/components/constellation/Cargo.toml
+++ b/servo/components/constellation/Cargo.toml
@@ -28,17 +28,17 @@ net_traits = {path = "../net_traits"}
 offscreen_gl_context = "0.4"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rand = "0.3"
 script_traits = {path = "../script_traits"}
 serde = "0.8"
 serde_derive = "0.8"
 style_traits = {path = "../style_traits"}
-url = {version = "1.2", features = ["heap_size"]}
+servo_url = {path = "../url", features = ["servo"]}
 util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
 
 [target.'cfg(not(target_os = "windows"))'.dependencies]
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -41,33 +41,33 @@ use rand::{Rng, SeedableRng, StdRng, ran
 use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
 use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg};
 use script_traits::{DocumentState, LayoutControlMsg, LoadData};
 use script_traits::{IFrameLoadInfo, IFrameSandboxState, TimerEventRequest};
 use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
 use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
 use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData};
 use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType};
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::{HashMap, VecDeque};
 use std::io::Error as IOError;
 use std::iter::once;
 use std::marker::PhantomData;
 use std::mem::replace;
 use std::process;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::thread;
 use std::time::Instant;
 use style_traits::PagePx;
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
 use timer_scheduler::TimerScheduler;
-use url::Url;
 use util::opts;
 use util::prefs::PREFS;
 use util::remutex::ReentrantMutex;
 use util::thread::spawn_named;
 use webrender_traits;
 
 #[derive(Debug, PartialEq)]
 enum ReadyToSave {
@@ -1042,25 +1042,25 @@ impl<Message, LTF, STF> Constellation<Me
             }
             FromLayoutMsg::ViewportConstrained(pipeline_id, constraints) => {
                 debug!("constellation got viewport-constrained event message");
                 self.handle_viewport_constrained_msg(pipeline_id, constraints);
             }
         }
     }
 
-    fn handle_register_serviceworker(&self, scope_things: ScopeThings, scope: Url) {
+    fn handle_register_serviceworker(&self, scope_things: ScopeThings, scope: ServoUrl) {
         if let Some(ref mgr) = self.swmanager_chan {
             let _ = mgr.send(ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope));
         } else {
             warn!("sending scope info to service worker manager failed");
         }
     }
 
-    fn handle_broadcast_storage_event(&self, pipeline_id: PipelineId, storage: StorageType, url: Url,
+    fn handle_broadcast_storage_event(&self, pipeline_id: PipelineId, storage: StorageType, url: ServoUrl,
                                       key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
         let origin = url.origin();
         for pipeline in self.pipelines.values() {
             if (pipeline.id != pipeline_id) && (pipeline.url.origin() == origin) {
                 let msg = ConstellationControlMsg::DispatchStorageEvent(
                     pipeline.id, storage, url.clone(), key.clone(), old_value.clone(), new_value.clone()
                 );
                 if let Err(err) = pipeline.script_chan.send(msg) {
@@ -1199,17 +1199,17 @@ impl<Message, LTF, STF> Constellation<Me
 
             while let Some(pending_pipeline_id) = self.pending_frames.iter().find(|pending| {
                 pending.old_pipeline_id == Some(pipeline_id)
             }).map(|frame| frame.new_pipeline_id) {
                 warn!("removing pending frame change for failed pipeline");
                 self.close_pipeline(pending_pipeline_id, ExitPipelineMode::Force);
             }
 
-            let failure_url = Url::parse("about:failure").expect("infallible");
+            let failure_url = ServoUrl::parse("about:failure").expect("infallible");
 
             if let Some(pipeline_url) = pipeline_url {
                 if pipeline_url == failure_url {
                     return error!("about:failure failed");
                 }
             }
 
             warn!("creating replacement pipeline for about:failure");
@@ -1240,17 +1240,17 @@ impl<Message, LTF, STF> Constellation<Me
                 if WARNINGS_BUFFER_SIZE <= self.handled_warnings.len() {
                     self.handled_warnings.pop_front();
                 }
                 self.handled_warnings.push_back((thread_name, reason));
             },
         }
     }
 
-    fn handle_init_load(&mut self, url: Url) {
+    fn handle_init_load(&mut self, url: ServoUrl) {
         let window_size = self.window_size.visible_viewport;
         let root_pipeline_id = PipelineId::new();
         let root_frame_id = self.root_frame_id;
         self.new_pipeline(root_pipeline_id, root_frame_id, None, None, Some(window_size), None,
                           LoadData::new(url.clone(), None, None), false);
         self.handle_load_start_msg(root_pipeline_id);
         self.pending_frames.push(FrameChange {
             frame_id: self.root_frame_id,
@@ -1326,17 +1326,17 @@ impl<Message, LTF, STF> Constellation<Me
                 Some(source_pipeline) => source_pipeline,
                 None => return warn!("Script loaded url in closed iframe {}.", load_info.parent_pipeline_id),
             };
 
             // If no url is specified, reload.
             let load_data = load_info.load_data.unwrap_or_else(|| {
                 let url = match old_pipeline {
                     Some(old_pipeline) => old_pipeline.url.clone(),
-                    None => Url::parse("about:blank").expect("infallible"),
+                    None => ServoUrl::parse("about:blank").expect("infallible"),
                 };
 
                 // TODO - loaddata here should have referrer info (not None, None)
                 LoadData::new(url, None, None)
             });
 
             // Compare the pipeline's url to the new url. If the origin is the same,
             // then reuse the script thread in creating the new pipeline
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -31,18 +31,18 @@ extern crate net_traits;
 extern crate offscreen_gl_context;
 #[macro_use]
 extern crate profile_traits;
 extern crate rand;
 extern crate script_traits;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_url;
 extern crate style_traits;
-extern crate url;
 #[macro_use]
 extern crate util;
 extern crate webrender_traits;
 
 mod constellation;
 mod pipeline;
 #[cfg(not(target_os = "windows"))]
 mod sandboxing;
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -21,25 +21,25 @@ use msg::constellation_msg::{FrameId, Fr
 use net_traits::{IpcSend, ResourceThreads};
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::mem as profile_mem;
 use profile_traits::time;
 use script_traits::{ConstellationControlMsg, InitialScriptState};
 use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent};
 use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
 use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
+use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::env;
 use std::ffi::OsStr;
 use std::io::Error as IOError;
 use std::process;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use style_traits::{PagePx, ViewportPx};
-use url::Url;
 use util::opts::{self, Opts};
 use util::prefs::{PREFS, Pref};
 use webrender_traits;
 
 pub enum ChildProcess {
     #[cfg(not(target_os = "windows"))]
     Sandboxed(gaol::platform::process::Process),
     #[cfg(not(target_os = "windows"))]
@@ -53,17 +53,17 @@ pub struct Pipeline {
     pub frame_id: FrameId,
     pub parent_info: Option<(PipelineId, FrameType)>,
     pub script_chan: Rc<ScriptChan>,
     /// A channel to layout, for performing reflows and shutdown.
     pub layout_chan: IpcSender<LayoutControlMsg>,
     /// A channel to the compositor.
     pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
     /// URL corresponding to the most recently-loaded page.
-    pub url: Url,
+    pub url: ServoUrl,
     /// The title of the most recently-loaded page.
     pub title: Option<String>,
     pub size: Option<TypedSize2D<f32, PagePx>>,
     /// Whether this pipeline is currently running animations. Pipelines that are running
     /// animations cause composites to be continually scheduled.
     pub running_animations: bool,
     pub children: Vec<FrameId>,
     /// Whether this pipeline is considered distinct from public pipelines.
@@ -259,17 +259,17 @@ impl Pipeline {
 
     fn new(id: PipelineId,
            frame_id: FrameId,
            parent_info: Option<(PipelineId, FrameType)>,
            script_chan: Rc<ScriptChan>,
            layout_chan: IpcSender<LayoutControlMsg>,
            compositor_proxy: Box<CompositorProxy + 'static + Send>,
            is_private: bool,
-           url: Url,
+           url: ServoUrl,
            size: Option<TypedSize2D<f32, PagePx>>,
            visible: bool)
            -> Pipeline {
         Pipeline {
             id: id,
             frame_id: frame_id,
             parent_info: parent_info,
             script_chan: script_chan,
--- a/servo/components/devtools_traits/Cargo.toml
+++ b/servo/components/devtools_traits/Cargo.toml
@@ -14,10 +14,10 @@ bitflags = "0.7"
 heapsize = "0.3.0"
 heapsize_derive = "0.1"
 hyper = "0.9.9"
 hyper_serde = "0.1.4"
 ipc-channel = "0.5"
 msg = {path = "../msg"}
 serde = "0.8"
 serde_derive = "0.8"
+servo_url = {path = "../url"}
 time = "0.1"
-url = {version = "1.2", features = ["heap_size"]}
--- a/servo/components/devtools_traits/lib.rs
+++ b/servo/components/devtools_traits/lib.rs
@@ -19,34 +19,34 @@
 extern crate bitflags;
 extern crate heapsize;
 #[macro_use] extern crate heapsize_derive;
 extern crate hyper;
 extern crate ipc_channel;
 extern crate msg;
 extern crate serde;
 #[macro_use] extern crate serde_derive;
+extern crate servo_url;
 extern crate time;
-extern crate url;
 
 use hyper::header::Headers;
 use hyper::method::Method;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
+use servo_url::ServoUrl;
 use std::net::TcpStream;
 use time::Duration;
 use time::Tm;
-use url::Url;
 
 // Information would be attached to NewGlobal to be received and show in devtools.
 // Extend these fields if we need more information.
 #[derive(Debug, Deserialize, Serialize)]
 pub struct DevtoolsPageInfo {
     pub title: String,
-    pub url: Url
+    pub url: ServoUrl,
 }
 
 #[derive(Debug, Deserialize, HeapSizeOf, Serialize, Clone)]
 pub struct CSSError {
     pub filename: String,
     pub line: usize,
     pub column: usize,
     pub msg: String
@@ -287,17 +287,17 @@ pub struct ConsoleAPI {
 #[derive(Debug, Deserialize, Serialize)]
 pub enum CachedConsoleMessage {
     PageError(PageError),
     ConsoleAPI(ConsoleAPI),
 }
 
 #[derive(Debug, PartialEq)]
 pub struct HttpRequest {
-    pub url: Url,
+    pub url: ServoUrl,
     pub method: Method,
     pub headers: Headers,
     pub body: Option<Vec<u8>>,
     pub pipeline_id: PipelineId,
     pub startedDateTime: Tm,
     pub timeStamp: i64,
     pub connect_time: u64,
     pub send_time: u64,
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -27,23 +27,23 @@ log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 ordered-float = "0.2.2"
 plugins = {path = "../plugins"}
 range = {path = "../range"}
 rustc-serialize = "0.3"
 serde = "0.8"
 servo_atoms = {path = "../atoms"}
+servo_url = {path = "../url"}
 serde_derive = "0.8"
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
-url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../util"}
 xi-unicode = "0.0.1"
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
 
--- a/servo/components/gfx/font_cache_thread.rs
+++ b/servo/components/gfx/font_cache_thread.rs
@@ -10,25 +10,25 @@ use net_traits::request::{Destination, R
 use platform::font_context::FontContextHandle;
 use platform::font_list::SANS_SERIF_FONT_FAMILY;
 use platform::font_list::for_each_available_family;
 use platform::font_list::for_each_variation;
 use platform::font_list::last_resort_font_families;
 use platform::font_list::system_default_family;
 use platform::font_template::FontTemplateData;
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::mem;
 use std::ops::Deref;
 use std::sync::{Arc, Mutex};
 use std::u32;
 use style::font_face::{EffectiveSources, Source};
 use style::properties::longhands::font_family::computed_value::FontFamily;
-use url::Url;
 use util::thread::spawn_named;
 use webrender_traits;
 
 /// A list of font templates that make up a given font family.
 struct FontTemplates {
     templates: Vec<FontTemplate>,
 }
 
@@ -101,17 +101,17 @@ impl FontTemplates {
 }
 
 /// Commands that the FontContext sends to the font cache thread.
 #[derive(Deserialize, Serialize, Debug)]
 pub enum Command {
     GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender<Reply>),
     GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender<Reply>),
     AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
-    AddDownloadedWebFont(LowercaseString, Url, Vec<u8>, IpcSender<()>),
+    AddDownloadedWebFont(LowercaseString, ServoUrl, Vec<u8>, IpcSender<()>),
     Exit(IpcSender<()>),
 }
 
 /// Reply messages sent from the font cache thread to the FontContext caller.
 #[derive(Deserialize, Serialize, Debug)]
 pub enum Reply {
     GetFontTemplateReply(Option<FontTemplateInfo>),
 }
@@ -201,17 +201,21 @@ impl FontCache {
         if !self.web_families.contains_key(&family_name) {
             let templates = FontTemplates::new();
             self.web_families.insert(family_name.clone(), templates);
         }
 
         match src {
             Source::Url(url_source) => {
                 // https://drafts.csswg.org/css-fonts/#font-fetching-requirements
-                let url = url_source.url;
+                let url = match url_source.url.url() {
+                    Some(url) => url.clone(),
+                    None => return,
+                };
+
                 let request = RequestInit {
                     url: url.clone(),
                     type_: RequestType::Font,
                     destination: Destination::Font,
                     origin: url.clone(),
                     .. RequestInit::default()
                 };
 
@@ -237,17 +241,17 @@ impl FontCache {
                                 return;
                             }
                             let bytes = mem::replace(&mut *bytes.lock().unwrap(), vec![]);
                             let bytes = match fontsan::process(&bytes) {
                                 Ok(san) => san,
                                 Err(_) => {
                                     // FIXME(servo/fontsan#1): get an error message
                                     debug!("Sanitiser rejected web font: \
-                                            family={:?} url={}", family_name, url);
+                                            family={:?} url={:?}", family_name, url);
                                     let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone());
                                     channel_to_self.send(msg).unwrap();
                                     return;
                                 },
                             };
                             let command =
                                 Command::AddDownloadedWebFont(family_name.clone(),
                                                               url.clone(),
--- a/servo/components/gfx/lib.rs
+++ b/servo/components/gfx/lib.rs
@@ -58,27 +58,25 @@ extern crate msg;
 extern crate net_traits;
 extern crate ordered_float;
 #[macro_use]
 extern crate range;
 extern crate rustc_serialize;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
-
+extern crate servo_url;
+#[macro_use] extern crate servo_atoms;
 #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
 extern crate simd;
-
-#[macro_use] extern crate servo_atoms;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate time;
 extern crate unicode_script;
-extern crate url;
 extern crate util;
 extern crate webrender_traits;
 extern crate xi_unicode;
 
 #[deny(unsafe_code)]
 pub mod display_list;
 
 // Fonts
--- a/servo/components/gfx/platform/macos/font_template.rs
+++ b/servo/components/gfx/platform/macos/font_template.rs
@@ -5,23 +5,23 @@
 use app_units::Au;
 use core_graphics::data_provider::CGDataProvider;
 use core_graphics::font::CGFont;
 use core_text;
 use core_text::font::CTFont;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
 use serde::de::{Error, Visitor};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::fs::File;
 use std::io::{Read, Error as IoError};
 use std::ops::Deref;
 use std::sync::Mutex;
-use url::Url;
 
 /// Platform specific font representation for mac.
 /// The identifier is a PostScript font name. The
 /// CTFont object is cached here for use by the
 /// paint functions that create CGFont references.
 #[derive(Deserialize, Serialize, Debug)]
 pub struct FontTemplateData {
     /// The `CTFont` object, if present. This is cached here so that we don't have to keep creating
@@ -81,23 +81,23 @@ impl FontTemplateData {
     /// operation (depending on the platform) which performs synchronous disk I/O
     /// and should never be done lightly.
     pub fn bytes(&self) -> Vec<u8> {
         match self.bytes_if_in_memory() {
             Some(font_data) => return font_data,
             None => {}
         }
 
-        let path = Url::parse(&*self.ctfont(0.0)
+        let path = ServoUrl::parse(&*self.ctfont(0.0)
                                     .expect("No Core Text font available!")
                                     .url()
                                     .expect("No URL for Core Text font!")
                                     .get_string()
                                     .to_string()).expect("Couldn't parse Core Text font URL!")
-                                                 .to_file_path()
+                                                 .as_url().unwrap().to_file_path()
                                                  .expect("Core Text font didn't name a path!");
         let mut bytes = Vec::new();
         File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap();
         bytes
     }
 
     /// Returns a clone of the bytes in this font if they are in memory. This function never
     /// performs disk I/O.
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -34,20 +34,20 @@ range = {path = "../range"}
 rayon = "0.5"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = "0.14"
 serde = "0.8"
 serde_derive = "0.8"
 serde_json = "0.8"
 servo_atoms = {path = "../atoms"}
+servo_url = {path = "../url"}
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 unicode-bidi = "0.2"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
-url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -33,16 +33,17 @@ use gfx::display_list::OpaqueNode;
 use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow};
 use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT};
 use linked_list::prepend_from;
 use list_item::{ListItemFlow, ListStyleTypeContent};
 use multicol::{MulticolColumnFlow, MulticolFlow};
 use parallel;
 use script_layout_interface::{LayoutElementType, LayoutNodeType, is_image_data};
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::LinkedList;
 use std::marker::PhantomData;
 use std::mem;
 use std::sync::Arc;
 use std::sync::atomic::Ordering;
 use style::computed_values::{caption_side, display, empty_cells, float, list_style_image, list_style_position};
 use style::computed_values::content::ContentItem;
@@ -57,17 +58,16 @@ use table::TableFlow;
 use table_caption::TableCaptionFlow;
 use table_cell::TableCellFlow;
 use table_colgroup::TableColGroupFlow;
 use table_row::TableRowFlow;
 use table_rowgroup::TableRowGroupFlow;
 use table_wrapper::TableWrapperFlow;
 use text::TextRunScanner;
 use traversal::PostorderNodeMutTraversal;
-use url::Url;
 use util::opts;
 use wrapper::{LayoutNodeLayoutData, TextContent, ThreadSafeLayoutNodeHelpers};
 
 /// The results of flow construction for a DOM node.
 #[derive(Clone)]
 pub enum ConstructionResult {
     /// This node contributes nothing at all (`display: none`). Alternately, this is what newly
     /// created nodes have their `ConstructionResult` set to.
@@ -1202,17 +1202,17 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
     fn build_flow_for_list_item(&mut self,
                                 node: &ConcreteThreadSafeLayoutNode,
                                 flotation: float::T)
                                 -> ConstructionResult {
         let flotation = FloatKind::from_property(flotation);
         let marker_fragments = match node.style(self.style_context()).get_list().list_style_image {
             list_style_image::T::Url(ref url_value) => {
                 let image_info = box ImageFragmentInfo::new(node,
-                                                            url_value.url().map(|u| (**u).clone()),
+                                                            url_value.url().map(|u| u.clone()),
                                                             &self.layout_context.shared);
                 vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)]
             }
             list_style_image::T::None => {
                 match ListStyleTypeContent::from_list_style_type(node.style(self.style_context())
                                                                      .get_list()
                                                                      .list_style_type) {
                     ListStyleTypeContent::None => Vec::new(),
@@ -1670,40 +1670,40 @@ impl<ConcreteThreadSafeLayoutNode> NodeU
 }
 
 /// Methods for interacting with HTMLObjectElement nodes
 trait ObjectElement {
     /// Returns true if this node has object data that is correct uri.
     fn has_object_data(&self) -> bool;
 
     /// Returns the "data" attribute value parsed as a URL
-    fn object_data(&self) -> Option<Url>;
+    fn object_data(&self) -> Option<ServoUrl>;
 }
 
 impl<N> ObjectElement for N  where N: ThreadSafeLayoutNode {
     fn has_object_data(&self) -> bool {
         let elem = self.as_element().unwrap();
         let type_and_data = (
             elem.get_attr(&ns!(), &local_name!("type")),
             elem.get_attr(&ns!(), &local_name!("data")),
         );
         match type_and_data {
             (None, Some(uri)) => is_image_data(uri),
             _ => false
         }
     }
 
-    fn object_data(&self) -> Option<Url> {
+    fn object_data(&self) -> Option<ServoUrl> {
         let elem = self.as_element().unwrap();
         let type_and_data = (
             elem.get_attr(&ns!(), &local_name!("type")),
             elem.get_attr(&ns!(), &local_name!("data")),
         );
         match type_and_data {
-            (None, Some(uri)) if is_image_data(uri) => Url::parse(uri).ok(),
+            (None, Some(uri)) if is_image_data(uri) => ServoUrl::parse(uri).ok(),
             _ => None
         }
     }
 }
 
 // This must not be public because only the layout constructor can call these
 // methods.
 trait FlowConstructionUtils {
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -12,23 +12,23 @@ use gfx::display_list::WebRenderImageInf
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context::FontContext;
 use heapsize::HeapSizeOf;
 use ipc_channel::ipc;
 use net_traits::image::base::Image;
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread, ImageResponse, ImageState};
 use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
 use parking_lot::RwLock;
+use servo_url::ServoUrl;
 use std::cell::{RefCell, RefMut};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
 use style::context::{LocalStyleContext, StyleContext, SharedStyleContext};
-use url::Url;
 use util::opts;
 
 struct LocalLayoutContext {
     style_context: LocalStyleContext,
 
     font_context: RefCell<FontContext>,
 }
 
@@ -78,17 +78,17 @@ pub struct SharedLayoutContext {
 
     /// A channel for the image cache to send responses to.
     pub image_cache_sender: Mutex<ImageCacheChan>,
 
     /// Interface to the font cache thread.
     pub font_cache_thread: Mutex<FontCacheThread>,
 
     /// A cache of WebRender image info.
-    pub webrender_image_cache: Arc<RwLock<HashMap<(Url, UsePlaceholder),
+    pub webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder),
                                                   WebRenderImageInfo,
                                                   BuildHasherDefault<FnvHasher>>>>,
 }
 
 pub struct LayoutContext<'a> {
     pub shared: &'a SharedLayoutContext,
     cached_local_layout_context: Rc<LocalLayoutContext>,
 }
@@ -120,17 +120,17 @@ impl<'a> LayoutContext<'a> {
 
     #[inline(always)]
     pub fn font_context(&self) -> RefMut<FontContext> {
         self.cached_local_layout_context.font_context.borrow_mut()
     }
 }
 
 impl SharedLayoutContext {
-    fn get_or_request_image_synchronously(&self, url: Url, use_placeholder: UsePlaceholder)
+    fn get_or_request_image_synchronously(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
                                           -> Option<Arc<Image>> {
         debug_assert!(opts::get().output_file.is_some() || opts::get().exit_after_load);
 
         // See if the image is already available
         let result = self.image_cache_thread.lock().unwrap()
                                             .find_image(url.clone(), use_placeholder);
 
         match result {
@@ -156,17 +156,17 @@ impl SharedLayoutContext {
                         }
                         ImageResponse::None | ImageResponse::MetadataLoaded(_) => {}
                     }
                 }
             }
         }
     }
 
-    pub fn get_or_request_image_or_meta(&self, url: Url, use_placeholder: UsePlaceholder)
+    pub fn get_or_request_image_or_meta(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
                                 -> Option<ImageOrMetadataAvailable> {
         // If we are emitting an output file, load the image synchronously.
         if opts::get().output_file.is_some() || opts::get().exit_after_load {
             return self.get_or_request_image_synchronously(url, use_placeholder)
                        .map(|img| ImageOrMetadataAvailable::ImageAvailable(img));
         }
         // See if the image is already available
         let result = self.image_cache_thread.lock().unwrap()
@@ -185,33 +185,33 @@ impl SharedLayoutContext {
             }
             // Image has been requested, is still pending. Return no image for this paint loop.
             // When the image loads it will trigger a reflow and/or repaint.
             Err(ImageState::Pending) => None,
         }
     }
 
     pub fn get_webrender_image_for_url(&self,
-                                       url: &Url,
+                                       url: ServoUrl,
                                        use_placeholder: UsePlaceholder)
                                        -> Option<WebRenderImageInfo> {
         if let Some(existing_webrender_image) = self.webrender_image_cache
                                                     .read()
-                                                    .get(&((*url).clone(), use_placeholder)) {
+                                                    .get(&(url.clone(), use_placeholder)) {
             return Some((*existing_webrender_image).clone())
         }
 
-        match self.get_or_request_image_or_meta((*url).clone(), use_placeholder) {
+        match self.get_or_request_image_or_meta(url.clone(), use_placeholder) {
             Some(ImageOrMetadataAvailable::ImageAvailable(image)) => {
                 let image_info = WebRenderImageInfo::from_image(&*image);
                 if image_info.key.is_none() {
                     Some(image_info)
                 } else {
                     let mut webrender_image_cache = self.webrender_image_cache.write();
-                    webrender_image_cache.insert(((*url).clone(), use_placeholder),
+                    webrender_image_cache.insert((url, use_placeholder),
                                                  image_info);
                     Some(image_info)
                 }
             }
             None | Some(ImageOrMetadataAvailable::MetadataAvailable(_)) => None,
         }
     }
 }
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -31,16 +31,17 @@ use gfx::display_list::{TextDisplayItem,
 use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId};
 use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
 use ipc_channel::ipc;
 use list_item::ListItemFlow;
 use model::{self, MaybeAuto, ToGfxMatrix};
 use net_traits::image::base::PixelFormat;
 use net_traits::image_cache_thread::UsePlaceholder;
 use range::Range;
+use servo_url::ServoUrl;
 use std::{cmp, f32};
 use std::collections::HashMap;
 use std::default::Default;
 use std::mem;
 use std::sync::Arc;
 use style::computed_values::{background_attachment, background_clip, background_origin};
 use style::computed_values::{background_repeat, background_size, border_style};
 use style::computed_values::{cursor, image_rendering, overflow_x};
@@ -52,17 +53,16 @@ use style::logical_geometry::{LogicalPoi
 use style::properties::{self, ServoComputedValues};
 use style::properties::style_structs;
 use style::servo::restyle_damage::REPAINT;
 use style::values::{self, Either, RGBA, computed};
 use style::values::computed::{Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
 use style_traits::cursor::Cursor;
 use table_cell::CollapsedBordersForCell;
-use url::Url;
 use util::opts;
 use webrender_traits::{ColorF, GradientStop};
 
 trait RgbColor {
     fn rgb(r: u8, g: u8, b: u8) -> Self;
 }
 
 impl RgbColor for ColorF {
@@ -355,17 +355,17 @@ pub trait FragmentDisplayListBuilding {
     /// Adds the display items necessary to paint the background image of this fragment to the
     /// appropriate section of the display list.
     fn build_display_list_for_background_image(&self,
                                                state: &mut DisplayListBuildState,
                                                style: &ServoComputedValues,
                                                display_list_section: DisplayListSection,
                                                absolute_bounds: &Rect<Au>,
                                                clip: &ClippingRegion,
-                                               image_url: &Url,
+                                               image_url: &ServoUrl,
                                                background_index: usize);
 
     /// Adds the display items necessary to paint the background linear gradient of this fragment
     /// to the appropriate section of the display list.
     fn build_display_list_for_background_gradient(&self,
                                                   state: &mut DisplayListBuildState,
                                                   display_list_section: DisplayListSection,
                                                   absolute_bounds: &Rect<Au>,
@@ -687,21 +687,21 @@ impl FragmentDisplayListBuilding for Fra
     }
 
     fn build_display_list_for_background_image(&self,
                                                state: &mut DisplayListBuildState,
                                                style: &ServoComputedValues,
                                                display_list_section: DisplayListSection,
                                                absolute_bounds: &Rect<Au>,
                                                clip: &ClippingRegion,
-                                               image_url: &Url,
+                                               image_url: &ServoUrl,
                                                index: usize) {
         let background = style.get_background();
         let webrender_image = state.shared_layout_context
-                                   .get_webrender_image_for_url(image_url,
+                                   .get_webrender_image_for_url(image_url.clone(),
                                                                 UsePlaceholder::No);
 
         if let Some(webrender_image) = webrender_image {
             debug!("(building display list) building background image");
 
             // Use `background-size` to get the size.
             let mut bounds = *absolute_bounds;
             let image_size = self.compute_background_image_size(style, &bounds,
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -27,16 +27,17 @@ use model::{self, IntrinsicISizes, Intri
 use msg::constellation_msg::PipelineId;
 use net_traits::image::base::{Image, ImageMetadata};
 use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
 use range::*;
 use script_layout_interface::HTMLCanvasData;
 use script_layout_interface::SVGSVGData;
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
 use serde::{Serialize, Serializer};
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::cmp::{max, min};
 use std::collections::LinkedList;
 use std::fmt;
 use std::sync::{Arc, Mutex};
 use style::arc_ptr_eq;
 use style::computed_values::{border_collapse, box_sizing, clear, color, display, mix_blend_mode};
 use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration};
@@ -49,17 +50,16 @@ use style::properties::ServoComputedValu
 use style::selector_impl::RestyleDamage;
 use style::servo::restyle_damage::RECONSTRUCT_FLOW;
 use style::str::char_is_whitespace;
 use style::values::Either;
 use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::computed::LengthOrPercentageOrNone;
 use text;
 use text::TextRunScanner;
-use url::Url;
 
 // From gfxFontConstants.h in Firefox.
 static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
 static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
 
 /// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
 /// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
 /// specification:
@@ -414,17 +414,17 @@ pub struct ImageFragmentInfo {
     pub metadata: Option<ImageMetadata>,
 }
 
 impl ImageFragmentInfo {
     /// Creates a new image fragment from the given URL and local image cache.
     ///
     /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
     /// sense to me.
-    pub fn new<N: ThreadSafeLayoutNode>(node: &N, url: Option<Url>,
+    pub fn new<N: ThreadSafeLayoutNode>(node: &N, url: Option<ServoUrl>,
                                         shared_layout_context: &SharedLayoutContext)
                                         -> ImageFragmentInfo {
         let image_or_metadata = url.and_then(|url| {
             shared_layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes)
         });
 
         let (image, metadata) = match image_or_metadata {
             Some(ImageOrMetadataAvailable::ImageAvailable(i)) => {
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -47,22 +47,22 @@ extern crate range;
 extern crate rayon;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate serde_json;
 #[macro_use] extern crate servo_atoms;
+extern crate servo_url;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate unicode_bidi;
 extern crate unicode_script;
-extern crate url;
 extern crate util;
 extern crate webrender_traits;
 
 #[macro_use]
 pub mod layout_debug;
 
 pub mod animation;
 mod block;
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -19,26 +19,27 @@ heapsize = "0.3.0"
 heapsize_derive = "0.1"
 ipc-channel = "0.5"
 layout = {path = "../layout"}
 layout_traits = {path = "../layout_traits"}
 lazy_static = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
+style_traits = {path = "../style_traits"}
 parking_lot = {version = "0.3.3", features = ["nightly"]}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rayon = "0.5"
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = "0.14"
 serde_derive = "0.8"
 serde_json = "0.8"
+servo_url = {path = "../url"}
 style = {path = "../style"}
-url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -35,18 +35,19 @@ extern crate parking_lot;
 #[macro_use]
 extern crate profile_traits;
 extern crate rayon;
 extern crate script;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate selectors;
 extern crate serde_json;
+extern crate servo_url;
 extern crate style;
-extern crate url;
+extern crate style_traits;
 extern crate util;
 extern crate webrender_traits;
 
 use app_units::Au;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::Size2D;
@@ -89,16 +90,17 @@ use profile_traits::time::{TimerMetadata
 use script::layout_wrapper::{ServoLayoutDocument, ServoLayoutNode};
 use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
 use script_layout_interface::reporter::CSSErrorReporter;
 use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
 use script_layout_interface::wrapper_traits::LayoutNode;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
 use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
 use selectors::Element;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::ops::{Deref, DerefMut};
 use std::process;
 use std::sync::{Arc, Mutex, MutexGuard};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::mpsc::{Receiver, Sender, channel};
@@ -109,30 +111,29 @@ use style::error_reporting::{ParseErrorR
 use style::logical_geometry::LogicalPoint;
 use style::media_queries::{Device, MediaType};
 use style::parser::ParserContextExtraData;
 use style::selector_matching::Stylist;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
 use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
 use style::thread_state;
 use style::timer::Timer;
-use url::Url;
 use util::geometry::max_rect;
 use util::opts;
 use util::prefs::PREFS;
 use util::resource_files::read_resource_file;
 use util::thread;
 
 /// Information needed by the layout thread.
 pub struct LayoutThread {
     /// The ID of the pipeline that we belong to.
     id: PipelineId,
 
     /// The URL of the pipeline that we belong to.
-    url: Url,
+    url: ServoUrl,
 
     /// Is the current reflow of an iframe, as opposed to a root window?
     is_iframe: bool,
 
     /// The port on which we receive messages from the script thread.
     port: Receiver<Msg>,
 
     /// The port on which we receive messages from the constellation.
@@ -208,17 +209,17 @@ pub struct LayoutThread {
     /// structures, while still letting the LayoutThread modify them.
     ///
     /// All the other elements of this struct are read-only.
     rw_data: Arc<Mutex<LayoutThreadData>>,
 
     /// The CSS error reporter for all CSS loaded in this layout thread
     error_reporter: CSSErrorReporter,
 
-    webrender_image_cache: Arc<RwLock<HashMap<(Url, UsePlaceholder),
+    webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder),
                                               WebRenderImageInfo,
                                               BuildHasherDefault<FnvHasher>>>>,
 
     // Webrender interface.
     webrender_api: webrender_traits::RenderApi,
 
     /// The timer object to control the timing of the animations. This should
     /// only be a test-mode timer during testing for animations.
@@ -229,17 +230,17 @@ pub struct LayoutThread {
     layout_threads: usize,
 }
 
 impl LayoutThreadFactory for LayoutThread {
     type Message = Msg;
 
     /// Spawns a new layout thread.
     fn create(id: PipelineId,
-              url: Url,
+              url: ServoUrl,
               is_iframe: bool,
               chan: (Sender<Msg>, Receiver<Msg>),
               pipeline_port: IpcReceiver<LayoutControlMsg>,
               constellation_chan: IpcSender<ConstellationMsg>,
               script_chan: IpcSender<ConstellationControlMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
@@ -249,28 +250,28 @@ impl LayoutThreadFactory for LayoutThrea
               layout_threads: usize) {
         thread::spawn_named(format!("LayoutThread {:?}", id),
                       move || {
             thread_state::initialize(thread_state::LAYOUT);
             PipelineId::install(id);
             { // Ensures layout thread is destroyed before we send shutdown message
                 let sender = chan.0;
                 let layout = LayoutThread::new(id,
-                                             url,
-                                             is_iframe,
-                                             chan.1,
-                                             pipeline_port,
-                                             constellation_chan,
-                                             script_chan,
-                                             image_cache_thread,
-                                             font_cache_thread,
-                                             time_profiler_chan,
-                                             mem_profiler_chan.clone(),
-                                             webrender_api_sender,
-                                             layout_threads);
+                                               url,
+                                               is_iframe,
+                                               chan.1,
+                                               pipeline_port,
+                                               constellation_chan,
+                                               script_chan,
+                                               image_cache_thread,
+                                               font_cache_thread,
+                                               time_profiler_chan,
+                                               mem_profiler_chan.clone(),
+                                               webrender_api_sender,
+                                               layout_threads);
 
                 let reporter_name = format!("layout-reporter-{}", id);
                 mem_profiler_chan.run_with_memory_reporting(|| {
                     layout.start();
                 }, reporter_name, sender, Msg::CollectReports);
             }
             let _ = content_process_shutdown_chan.send(());
         });
@@ -360,17 +361,17 @@ fn add_font_face_rules(stylesheet: &Styl
                                           (*font_cache_sender).clone());
         })
     }
 }
 
 impl LayoutThread {
     /// Creates a new `LayoutThread` structure.
     fn new(id: PipelineId,
-           url: Url,
+           url: ServoUrl,
            is_iframe: bool,
            port: Receiver<Msg>,
            pipeline_port: IpcReceiver<LayoutControlMsg>,
            constellation_chan: IpcSender<ConstellationMsg>,
            script_chan: IpcSender<ConstellationControlMsg>,
            image_cache_thread: ImageCacheThread,
            font_cache_thread: FontCacheThread,
            time_profiler_chan: time::ProfilerChan,
@@ -1521,17 +1522,17 @@ fn get_root_flow_background_color(flow: 
                   .to_gfx_color()
 }
 
 fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
     fn parse_ua_stylesheet(filename: &'static str) -> Result<Stylesheet, &'static str> {
         let res = try!(read_resource_file(filename).map_err(|_| filename));
         Ok(Stylesheet::from_bytes(
             &res,
-            Url::parse(&format!("chrome://resources/{:?}", filename)).unwrap(),
+            ServoUrl::parse(&format!("chrome://resources/{:?}", filename)).unwrap(),
             None,
             None,
             Origin::UserAgent,
             Box::new(StdoutErrorReporter),
             ParserContextExtraData::default()))
     }
 
     let mut user_or_user_agent_stylesheets = vec!();
--- a/servo/components/layout_traits/Cargo.toml
+++ b/servo/components/layout_traits/Cargo.toml
@@ -11,14 +11,14 @@ path = "lib.rs"
 
 [dependencies]
 gfx = {path = "../gfx"}
 script_traits = {path = "../script_traits"}
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 profile_traits = {path = "../profile_traits"}
 ipc-channel = "0.5"
-url = {version = "1.2", features = ["heap_size"]}
+servo_url = {path = "../url"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
--- a/servo/components/layout_traits/lib.rs
+++ b/servo/components/layout_traits/lib.rs
@@ -5,40 +5,40 @@
 #![deny(unsafe_code)]
 
 extern crate gfx;
 extern crate ipc_channel;
 extern crate msg;
 extern crate net_traits;
 extern crate profile_traits;
 extern crate script_traits;
-extern crate url;
+extern crate servo_url;
 extern crate webrender_traits;
 
 // This module contains traits in layout used generically
 //   in the rest of Servo.
 // The traits are here instead of in layout so
 //   that these modules won't have to depend on layout.
 
 use gfx::font_cache_thread::FontCacheThread;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use msg::constellation_msg::PipelineId;
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::{mem, time};
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
 use script_traits::LayoutMsg as ConstellationMsg;
+use servo_url::ServoUrl;
 use std::sync::mpsc::{Receiver, Sender};
-use url::Url;
 
 // A static method creating a layout thread
 // Here to remove the compositor -> layout dependency
 pub trait LayoutThreadFactory {
     type Message;
     fn create(id: PipelineId,
-              url: Url,
+              url: ServoUrl,
               is_iframe: bool,
               chan: (Sender<Self::Message>, Receiver<Self::Message>),
               pipeline_port: IpcReceiver<LayoutControlMsg>,
               constellation_chan: IpcSender<ConstellationMsg>,
               script_chan: IpcSender<ConstellationControlMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
--- a/servo/components/net/Cargo.toml
+++ b/servo/components/net/Cargo.toml
@@ -29,16 +29,17 @@ msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 openssl = "0.7.6"
 openssl-verify = "0.1"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rustc-serialize = "0.3"
 serde = "0.8"
 serde_derive = "0.8"
+servo_url = {path = "../url"}
 threadpool = "1.0"
 time = "0.1.17"
 unicase = "1.4.0"
 url = {version = "1.2", features = ["heap_size", "rustc-serialize"]}
 util = {path = "../util"}
 uuid = {version = "0.3.1", features = ["v4"]}
 websocket = "0.17"
 
--- a/servo/components/net/about_loader.rs
+++ b/servo/components/net/about_loader.rs
@@ -6,26 +6,27 @@ use file_loader;
 use hyper::header::ContentType;
 use hyper::mime::{Mime, SubLevel, TopLevel};
 use hyper_serde::Serde;
 use mime_classifier::MimeClassifier;
 use net_traits::{LoadConsumer, LoadData, Metadata, NetworkError};
 use net_traits::ProgressMsg::Done;
 use net_traits::response::HttpsState;
 use resource_thread::{CancellationListener, send_error, start_sending_sniffed_opt};
+use servo_url::ServoUrl;
 use std::io;
 use std::sync::Arc;
 use url::Url;
 use util::resource_files::resources_dir_path;
 
 fn url_from_non_relative_scheme(load_data: &mut LoadData, filename: &str) -> io::Result<()> {
     let mut path = try!(resources_dir_path());
     path.push(filename);
     assert!(path.exists());
-    load_data.url = Url::from_file_path(&*path).unwrap();
+    load_data.url = ServoUrl::from_url(Url::from_file_path(&*path).unwrap());
     Ok(())
 }
 
 pub fn factory(mut load_data: LoadData,
                start_chan: LoadConsumer,
                classifier: Arc<MimeClassifier>,
                cancel_listener: CancellationListener) {
     let url = load_data.url.clone();
--- a/servo/components/net/blob_loader.rs
+++ b/servo/components/net/blob_loader.rs
@@ -11,19 +11,19 @@ use mime::{Attr, Mime};
 use mime_classifier::MimeClassifier;
 use net_traits::{LoadConsumer, LoadData, Metadata, NetworkError};
 use net_traits::ProgressMsg::{Done, Payload};
 use net_traits::blob_url_store::parse_blob_url;
 use net_traits::filemanager_thread::{FileManagerThreadMsg, ReadFileProgress};
 use net_traits::response::HttpsState;
 use resource_thread::{send_error, start_sending_sniffed_opt};
 use resource_thread::CancellationListener;
+use servo_url::ServoUrl;
 use std::boxed::FnBox;
 use std::sync::Arc;
-use url::Url;
 use util::thread::spawn_named;
 
 // TODO: Check on GET
 // https://w3c.github.io/FileAPI/#requestResponseModel
 
 pub fn factory<UI: 'static + UIProvider>(filemanager: FileManager<UI>)
               -> Box<FnBox(LoadData, LoadConsumer, Arc<MimeClassifier>, CancellationListener) + Send> {
     box move |load_data: LoadData, start_chan, classifier, cancel_listener| {
@@ -119,17 +119,17 @@ fn load_blob<UI: 'static + UIProvider>
         let format_err = NetworkError::Internal(e);
         send_error(load_data.url.clone(), format_err, start_chan);
     }
 }
 
 /// https://fetch.spec.whatwg.org/#concept-basic-fetch (partial)
 // TODO: make async.
 pub fn load_blob_sync<UI: 'static + UIProvider>
-            (url: Url,
+            (url: ServoUrl,
              filemanager: FileManager<UI>)
              -> Result<(Headers, Vec<u8>), NetworkError> {
     let (id, origin) = match parse_blob_url(&url) {
         Ok((id, origin, _fragment)) => (id, origin),
         Err(()) => {
             let e = format!("Invalid blob URL format {:?}", url);
             return Err(NetworkError::Internal(e));
         }
--- a/servo/components/net/chrome_loader.rs
+++ b/servo/components/net/chrome_loader.rs
@@ -1,40 +1,40 @@
 /* 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 file_loader;
 use mime_classifier::MimeClassifier;
 use net_traits::{LoadConsumer, LoadData, NetworkError};
 use resource_thread::{CancellationListener, send_error};
+use servo_url::ServoUrl;
 use std::fs::canonicalize;
 use std::sync::Arc;
-use url::Url;
 use url::percent_encoding::percent_decode;
 use util::resource_files::resources_dir_path;
 
-pub fn resolve_chrome_url(url: &Url) -> Result<Url, ()> {
+pub fn resolve_chrome_url(url: &ServoUrl) -> Result<ServoUrl, ()> {
     assert_eq!(url.scheme(), "chrome");
     if url.host_str() != Some("resources") {
         return Err(())
     }
     let resources = canonicalize(resources_dir_path().expect("Error finding resource folder"))
         .expect("Error canonicalizing path to the resources directory");
     let mut path = resources.clone();
     for segment in url.path_segments().unwrap() {
         match percent_decode(segment.as_bytes()).decode_utf8() {
             // Check ".." to prevent access to files outside of the resources directory.
             Ok(segment) => path.push(&*segment),
             _ => return Err(())
         }
     }
     match canonicalize(path) {
         Ok(ref path) if path.starts_with(&resources) && path.exists() => {
-            Ok(Url::from_file_path(path).unwrap())
+            Ok(ServoUrl::from_file_path(path).unwrap())
         }
         _ => Err(())
     }
 }
 
 pub fn factory(mut load_data: LoadData,
                start_chan: LoadConsumer,
                classifier: Arc<MimeClassifier>,
--- a/servo/components/net/cookie.rs
+++ b/servo/components/net/cookie.rs
@@ -3,37 +3,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Implementation of cookie creation and matching as specified by
 //! http://tools.ietf.org/html/rfc6265
 
 use cookie_rs;
 use net_traits::CookieSource;
 use net_traits::pub_domains::is_pub_domain;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::net::{Ipv4Addr, Ipv6Addr};
 use time::{Tm, now, at, Duration};
-use url::Url;
 
 /// A stored cookie that wraps the definition in cookie-rs. This is used to implement
 /// various behaviours defined in the spec that rely on an associated request URL,
 /// which cookie-rs and hyper's header parsing do not support.
 #[derive(Clone, Debug, RustcDecodable, RustcEncodable)]
 pub struct Cookie {
     pub cookie: cookie_rs::Cookie,
     pub host_only: bool,
     pub persistent: bool,
     pub creation_time: Tm,
     pub last_access: Tm,
     pub expiry_time: Option<Tm>,
 }
 
 impl Cookie {
     /// http://tools.ietf.org/html/rfc6265#section-5.3
-    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &Url, source: CookieSource)
+    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &ServoUrl, source: CookieSource)
                        -> Option<Cookie> {
         // Step 3
         let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
             (&Some(max_age), _) => {
                 (true, Some(at(now().to_timespec() + Duration::seconds(max_age as i64))))
             }
             (_, &Some(expires)) => (true, Some(expires)),
             _ => (false, None)
@@ -140,17 +140,17 @@ impl Cookie {
             string.parse::<Ipv4Addr>().is_err() &&
             string.parse::<Ipv6Addr>().is_err() {
             return true;
         }
         false
     }
 
     // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
-    pub fn appropriate_for_url(&self, url: &Url, source: CookieSource) -> bool {
+    pub fn appropriate_for_url(&self, url: &ServoUrl, source: CookieSource) -> bool {
         let domain = url.host_str();
         if self.host_only {
             if self.cookie.domain.as_ref().map(String::as_str) != domain {
                 return false;
             }
         } else {
             if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                 if !Cookie::domain_match(domain, cookie_domain) {
--- a/servo/components/net/cookie_storage.rs
+++ b/servo/components/net/cookie_storage.rs
@@ -3,18 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Implementation of cookie storage as specified in
 //! http://tools.ietf.org/html/rfc6265
 
 use cookie::Cookie;
 use cookie_rs;
 use net_traits::CookieSource;
+use servo_url::ServoUrl;
 use std::cmp::Ordering;
-use url::Url;
 
 #[derive(Clone, RustcDecodable, RustcEncodable)]
 pub struct CookieStorage {
     version: u32,
     cookies: Vec<Cookie>
 }
 
 impl CookieStorage {
@@ -79,17 +79,17 @@ impl CookieStorage {
             }
             // Ensure that longer paths are sorted earlier than shorter paths
             Ordering::Greater => Ordering::Less,
             Ordering::Less => Ordering::Greater,
         }
     }
 
     // http://tools.ietf.org/html/rfc6265#section-5.4
-    pub fn cookies_for_url(&mut self, url: &Url, source: CookieSource) -> Option<String> {
+    pub fn cookies_for_url(&mut self, url: &ServoUrl, source: CookieSource) -> Option<String> {
         let filterer = |c: &&mut Cookie| -> bool {
             info!(" === SENT COOKIE : {} {} {:?} {:?}",
                   c.cookie.name, c.cookie.value, c.cookie.domain, c.cookie.path);
             info!(" === SENT COOKIE RESULT {}", c.appropriate_for_url(url, source));
             // Step 1
             c.appropriate_for_url(url, source)
         };
 
@@ -111,16 +111,16 @@ impl CookieStorage {
 
         info!(" === COOKIES SENT: {}", result);
         match result.len() {
             0 => None,
             _ => Some(result)
         }
     }
 
-    pub fn cookies_data_for_url<'a>(&'a mut self, url: &'a Url,
+    pub fn cookies_data_for_url<'a>(&'a mut self, url: &'a ServoUrl,
                                     source: CookieSource) -> Box<Iterator<Item=cookie_rs::Cookie> + 'a> {
         Box::new(self.cookies.iter_mut().filter(move |c| { c.appropriate_for_url(url, source) }).map(|c| {
             c.touch();
             c.cookie.clone()
         }))
     }
 }
--- a/servo/components/net/data_loader.rs
+++ b/servo/components/net/data_loader.rs
@@ -4,18 +4,19 @@
 
 use hyper::mime::{Attr, Mime, SubLevel, TopLevel, Value};
 use mime_classifier::MimeClassifier;
 use net_traits::{LoadData, Metadata, NetworkError};
 use net_traits::LoadConsumer;
 use net_traits::ProgressMsg::{Done, Payload};
 use resource_thread::{CancellationListener, send_error, start_sending_sniffed_opt};
 use rustc_serialize::base64::FromBase64;
+use servo_url::ServoUrl;
 use std::sync::Arc;
-use url::{Position, Url};
+use url::Position;
 use url::percent_encoding::percent_decode;
 
 pub fn factory(load_data: LoadData,
                senders: LoadConsumer,
                classifier: Arc<MimeClassifier>,
                cancel_listener: CancellationListener) {
     // NB: we don't spawn a new thread.
     // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
@@ -26,20 +27,20 @@ pub fn factory(load_data: LoadData,
 
 pub enum DecodeError {
     InvalidDataUri,
     NonBase64DataUri,
 }
 
 pub type DecodeData = (Mime, Vec<u8>);
 
-pub fn decode(url: &Url) -> Result<DecodeData, DecodeError> {
-    assert!(url.scheme() == "data");
+pub fn decode(url: &ServoUrl) -> Result<DecodeData, DecodeError> {
+    assert_eq!(url.scheme(), "data");
     // Split out content type and data.
-    let parts: Vec<&str> = url[Position::BeforePath..Position::AfterQuery].splitn(2, ',').collect();
+    let parts: Vec<&str> = url.as_url().unwrap()[Position::BeforePath..Position::AfterQuery].splitn(2, ',').collect();
     if parts.len() != 2 {
         return Err(DecodeError::InvalidDataUri);
     }
 
     // ";base64" must come at the end of the content type, per RFC 2397.
     // rust-http will fail to parse it because there's no =value part.
     let mut ct_str = parts[0];
     let is_base64 = ct_str.ends_with(";base64");
@@ -56,17 +57,17 @@ pub fn decode(url: &Url) -> Result<Decod
         Mime(TopLevel::Text, SubLevel::Plain,
              vec![(Attr::Charset, Value::Ext("US-ASCII".to_owned()))])
     });
 
     let mut bytes = percent_decode(parts[1].as_bytes()).collect::<Vec<_>>();
     if is_base64 {
         // FIXME(#2909): It’s unclear what to do with non-alphabet characters,
         // but Acid 3 apparently depends on spaces being ignored.
-        bytes = bytes.into_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
+        bytes = bytes.into_iter().filter(|&b| b != b' ').collect::<Vec<u8>>();
         match bytes.from_base64() {
             Err(..) => return Err(DecodeError::NonBase64DataUri),
             Ok(data) => bytes = data,
         }
     }
     Ok((content_type, bytes))
 }
 
--- a/servo/components/net/fetch/cors_cache.rs
+++ b/servo/components/net/fetch/cors_cache.rs
@@ -6,19 +6,19 @@
 //! For now this library is XHR-specific.
 //! For stuff involving `<img>`, `<iframe>`, `<form>`, etc please check what
 //! the request mode should be and compare with the fetch spec
 //! This library will eventually become the core of the Fetch crate
 //! with CORSRequest being expanded into FetchRequest (etc)
 
 use hyper::method::Method;
 use net_traits::request::{CredentialsMode, Origin, Request};
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use time::{self, Timespec};
-use url::Url;
 
 /// Union type for CORS cache entries
 ///
 /// Each entry might pertain to a header or method
 #[derive(Clone, Debug)]
 pub enum HeaderOrMethod {
     HeaderData(String),
     MethodData(Method)
@@ -39,25 +39,25 @@ impl HeaderOrMethod {
         }
     }
 }
 
 /// An entry in the CORS cache
 #[derive(Clone, Debug)]
 pub struct CorsCacheEntry {
     pub origin: Origin,
-    pub url: Url,
+    pub url: ServoUrl,
     pub max_age: u32,
     pub credentials: bool,
     pub header_or_method: HeaderOrMethod,
     created: Timespec
 }
 
 impl CorsCacheEntry {
-    fn new(origin: Origin, url: Url, max_age: u32, credentials: bool,
+    fn new(origin: Origin, url: ServoUrl, max_age: u32, credentials: bool,
             header_or_method: HeaderOrMethod) -> CorsCacheEntry {
         CorsCacheEntry {
             origin: origin,
             url: url,
             max_age: max_age,
             credentials: credentials,
             header_or_method: header_or_method,
             created: time::now().to_timespec()
--- a/servo/components/net/fetch/methods.rs
+++ b/servo/components/net/fetch/methods.rs
@@ -24,28 +24,29 @@ use hyper::status::StatusCode;
 use hyper_serde::Serde;
 use mime_guess::guess_mime_type;
 use net_traits::{FetchTaskTarget, FetchMetadata, NetworkError, ReferrerPolicy};
 use net_traits::request::{CacheMode, CredentialsMode, Destination};
 use net_traits::request::{RedirectMode, Referrer, Request, RequestMode, ResponseTainting};
 use net_traits::request::{Type, Origin, Window};
 use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
 use resource_thread::CancellationListener;
+use servo_url::ServoUrl;
 use std::borrow::Cow;
 use std::collections::HashSet;
 use std::error::Error;
 use std::fs::File;
 use std::io::Read;
 use std::iter::FromIterator;
 use std::mem::swap;
 use std::ops::Deref;
 use std::rc::Rc;
 use std::sync::mpsc::{channel, Sender, Receiver};
 use unicase::UniCase;
-use url::{Origin as UrlOrigin, Url};
+use url::{Origin as UrlOrigin};
 use util::thread::spawn_named;
 use uuid;
 
 pub type Target = Option<Box<FetchTaskTarget + Send>>;
 
 enum Data {
     Payload(Vec<u8>),
     Done,
@@ -1300,17 +1301,17 @@ fn cors_check(request: Rc<Request>, resp
     if credentials.is_some() {
         return Ok(());
     }
 
     // Step 8
     Err(())
 }
 
-fn has_credentials(url: &Url) -> bool {
+fn has_credentials(url: &ServoUrl) -> bool {
     !url.username().is_empty() || url.password().is_some()
 }
 
 fn is_no_store_cache(headers: &Headers) -> bool {
     headers.has::<IfModifiedSince>() | headers.has::<IfNoneMatch>() |
     headers.has::<IfUnmodifiedSince>() | headers.has::<IfMatch>() |
     headers.has::<IfRange>()
 }
--- a/servo/components/net/file_loader.rs
+++ b/servo/components/net/file_loader.rs
@@ -5,40 +5,40 @@
 use about_loader;
 use mime_classifier::MimeClassifier;
 use mime_guess::guess_mime_type;
 use msg::constellation_msg::PipelineId;
 use net_traits::{LoadConsumer, LoadData, LoadOrigin, Metadata, NetworkError, ReferrerPolicy};
 use net_traits::ProgressMsg::{Done, Payload};
 use resource_thread::{CancellationListener, ProgressSender};
 use resource_thread::{send_error, start_sending_sniffed_opt};
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::error::Error;
 use std::fs::File;
 use std::io::Read;
 use std::path::Path;
 use std::sync::Arc;
-use url::Url;
 use util::thread::spawn_named;
 
 static READ_SIZE: usize = 8192;
 
 enum ReadStatus {
     Partial(Vec<u8>),
     EOF,
 }
 
 enum LoadResult {
     Cancelled,
     Finished,
 }
 
 struct FileLoadOrigin;
 impl LoadOrigin for FileLoadOrigin {
-    fn referrer_url(&self) -> Option<Url> {
+    fn referrer_url(&self) -> Option<ServoUrl> {
         None
     }
     fn referrer_policy(&self) -> Option<ReferrerPolicy> {
         None
     }
     fn pipeline_id(&self) -> Option<PipelineId> {
         None
     }
@@ -92,17 +92,17 @@ pub fn factory(load_data: LoadData,
         };
         let mut file = File::open(&file_path);
         let reader = match file {
             Ok(ref mut reader) => reader,
             Err(_) => {
                 // this should be one of the three errors listed in
                 // http://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
                 // but, we'll go for a "file not found!"
-                let url = Url::parse("about:not-found").unwrap();
+                let url = ServoUrl::parse("about:not-found").unwrap();
                 let load_data_404 = LoadData::new(load_data.context, url, &FileLoadOrigin);
                 about_loader::factory(load_data_404, senders, classifier, cancel_listener);
                 return;
             }
         };
 
         if cancel_listener.is_cancelled() {
             if let Ok(progress_chan) = get_progress_chan(load_data, &file_path,
--- a/servo/components/net/http_loader.rs
+++ b/servo/components/net/http_loader.rs
@@ -34,30 +34,31 @@ use net_traits::{CustomResponse, CustomR
 use net_traits::ProgressMsg::{Done, Payload};
 use net_traits::hosts::replace_hosts;
 use net_traits::response::HttpsState;
 use openssl;
 use openssl::ssl::error::{OpensslError, SslError};
 use profile_traits::time::{ProfilerCategory, ProfilerChan, TimerMetadata, profile};
 use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
 use resource_thread::{AuthCache, AuthCacheEntry, CancellationListener, send_error, start_sending_sniffed_opt};
+use servo_url::ServoUrl;
 use std::borrow::{Cow, ToOwned};
 use std::boxed::FnBox;
 use std::collections::HashSet;
 use std::error::Error;
 use std::fmt;
 use std::io::{self, Cursor, Read, Write};
 use std::ops::Deref;
 use std::sync::{Arc, RwLock};
 use std::sync::mpsc::Sender;
 use time;
 use time::Tm;
 #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
 use tinyfiledialogs;
-use url::{Position, Url, Origin};
+use url::{Position, Origin};
 use util::thread::spawn_named;
 use uuid;
 
 pub fn factory(user_agent: Cow<'static, str>,
                http_state: HttpState,
                devtools_chan: Option<Sender<DevtoolsControlMsg>>,
                profiler_chan: ProfilerChan,
                swmanager_chan: Option<IpcSender<CustomResponseMediator>>,
@@ -241,29 +242,31 @@ impl Read for ReadableCustomResponse {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.body.read(buf)
     }
 }
 
 pub trait HttpRequestFactory {
     type R: HttpRequest;
 
-    fn create(&self, url: Url, method: Method, headers: Headers) -> Result<Self::R, LoadError>;
+    fn create(&self, url: ServoUrl, method: Method, headers: Headers) -> Result<Self::R, LoadError>;
 }
 
 pub struct NetworkHttpRequestFactory {
     pub connector: Arc<Pool<Connector>>,
 }
 
 impl HttpRequestFactory for NetworkHttpRequestFactory {
     type R = WrappedHttpRequest;
 
-    fn create(&self, url: Url, method: Method, headers: Headers)
+    fn create(&self, url: ServoUrl, method: Method, headers: Headers)
               -> Result<WrappedHttpRequest, LoadError> {
-        let connection = Request::with_connector(method, url.clone(), &*self.connector);
+        let connection = Request::with_connector(method,
+                                                 url.clone().into_url().unwrap(),
+                                                 &*self.connector);
 
         if let Err(HttpError::Ssl(ref error)) = connection {
             let error: &(Error + Send + 'static) = &**error;
             if let Some(&SslError::OpenSslErrors(ref errors)) = error.downcast_ref::<SslError>() {
                 if errors.iter().any(is_cert_verify_error) {
                     let mut error_report = vec![format!("ssl error ({}):", openssl::version::version())];
                     let mut suggestion = None;
                     for err in errors {
@@ -303,17 +306,17 @@ pub trait HttpRequest {
 pub struct WrappedHttpRequest {
     request: Request<Fresh>
 }
 
 impl HttpRequest for WrappedHttpRequest {
     type R = WrappedHttpResponse;
 
     fn send(self, body: &Option<Vec<u8>>) -> Result<WrappedHttpResponse, LoadError> {
-        let url = self.request.url.clone();
+        let url = ServoUrl::from_url(self.request.url.clone());
         let mut request_writer = match self.request.start() {
             Ok(streaming) => streaming,
             Err(e) => return Err(LoadError::new(url, LoadErrorType::Connection { reason: e.description().to_owned() })),
         };
 
         if let Some(ref data) = *body {
             if let Err(e) = request_writer.write_all(&data) {
                 return Err(LoadError::new(url, LoadErrorType::Connection { reason: e.description().to_owned() }))
@@ -330,22 +333,22 @@ impl HttpRequest for WrappedHttpRequest 
         };
 
         Ok(WrappedHttpResponse { response: response })
     }
 }
 
 #[derive(Debug)]
 pub struct LoadError {
-    pub url: Url,
+    pub url: ServoUrl,
     pub error: LoadErrorType,
 }
 
 impl LoadError {
-    pub fn new(url: Url, error: LoadErrorType) -> LoadError {
+    pub fn new(url: ServoUrl, error: LoadErrorType) -> LoadError {
         LoadError {
             url: url,
             error: error,
         }
     }
 }
 
 #[derive(Eq, PartialEq, Debug)]
@@ -424,60 +427,63 @@ pub fn set_default_accept_language(heade
     en.language = Some("en".to_owned());
     headers.set(AcceptLanguage(vec![
         qitem(en_us),
         QualityItem::new(en, Quality(500)),
     ]));
 }
 
 /// https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-state-no-referrer-when-downgrade
-fn no_referrer_when_downgrade_header(referrer_url: Url, url: Url) -> Option<Url> {
+fn no_referrer_when_downgrade_header(referrer_url: ServoUrl, url: ServoUrl) -> Option<ServoUrl> {
     if referrer_url.scheme() == "https" && url.scheme() != "https" {
         return None;
     }
     return strip_url(referrer_url, false);
 }
 
 /// https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin
-fn strict_origin(referrer_url: Url, url: Url) -> Option<Url> {
+fn strict_origin(referrer_url: ServoUrl, url: ServoUrl) -> Option<ServoUrl> {
     if referrer_url.scheme() == "https" && url.scheme() != "https" {
         return None;
     }
     strip_url(referrer_url, true)
 }
 
 /// https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin-when-cross-origin
-fn strict_origin_when_cross_origin(referrer_url: Url, url: Url) -> Option<Url> {
+fn strict_origin_when_cross_origin(referrer_url: ServoUrl, url: ServoUrl) -> Option<ServoUrl> {
     if referrer_url.scheme() == "https" && url.scheme() != "https" {
         return None;
     }
     let cross_origin = referrer_url.origin() != url.origin();
     strip_url(referrer_url, cross_origin)
 }
 
 /// https://w3c.github.io/webappsec-referrer-policy/#strip-url
-fn strip_url(mut referrer_url: Url, origin_only: bool) -> Option<Url> {
+fn strip_url(mut referrer_url: ServoUrl, origin_only: bool) -> Option<ServoUrl> {
     if referrer_url.scheme() == "https" || referrer_url.scheme() == "http" {
-        referrer_url.set_username("").unwrap();
-        referrer_url.set_password(None).unwrap();
-        referrer_url.set_fragment(None);
-        if origin_only {
-            referrer_url.set_path("");
-            referrer_url.set_query(None);
+        {
+            let referrer = referrer_url.as_mut_url().unwrap();
+            referrer.set_username("").unwrap();
+            referrer.set_password(None).unwrap();
+            referrer.set_fragment(None);
+            if origin_only {
+                referrer.set_path("");
+                referrer.set_query(None);
+            }
         }
         return Some(referrer_url);
     }
     return None;
 }
 
 /// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
 pub fn determine_request_referrer(headers: &mut Headers,
                                   referrer_policy: Option<ReferrerPolicy>,
-                                  referrer_url: Option<Url>,
-                                  url: Url) -> Option<Url> {
+                                  referrer_url: Option<ServoUrl>,
+                                  url: ServoUrl) -> Option<ServoUrl> {
     //TODO - algorithm step 2 not addressed
     assert!(!headers.has::<Referer>());
     if let Some(ref_url) = referrer_url {
         let cross_origin = ref_url.origin() != url.origin();
         return match referrer_policy {
             Some(ReferrerPolicy::NoReferrer) => None,
             Some(ReferrerPolicy::Origin) => strip_url(ref_url, true),
             Some(ReferrerPolicy::SameOrigin) => if cross_origin { None } else { strip_url(ref_url, false) },
@@ -487,54 +493,54 @@ pub fn determine_request_referrer(header
             Some(ReferrerPolicy::StrictOriginWhenCrossOrigin) => strict_origin_when_cross_origin(ref_url, url),
             Some(ReferrerPolicy::NoReferrerWhenDowngrade) | None =>
                 no_referrer_when_downgrade_header(ref_url, url),
         };
     }
     return None;
 }
 
-pub fn set_request_cookies(url: &Url, headers: &mut Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) {
+pub fn set_request_cookies(url: &ServoUrl, headers: &mut Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) {
     let mut cookie_jar = cookie_jar.write().unwrap();
     if let Some(cookie_list) = cookie_jar.cookies_for_url(url, CookieSource::HTTP) {
         let mut v = Vec::new();
         v.push(cookie_list.into_bytes());
         headers.set_raw("Cookie".to_owned(), v);
     }
 }
 
 fn set_cookie_for_url(cookie_jar: &Arc<RwLock<CookieStorage>>,
-                      request: &Url,
+                      request: &ServoUrl,
                       cookie_val: String) {
     let mut cookie_jar = cookie_jar.write().unwrap();
     let source = CookieSource::HTTP;
     let header = Header::parse_header(&[cookie_val.into_bytes()]);
 
     if let Ok(SetCookie(cookies)) = header {
         for bare_cookie in cookies {
             if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, request, source) {
                 cookie_jar.push(cookie, source);
             }
         }
     }
 }
 
-pub fn set_cookies_from_headers(url: &Url, headers: &Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) {
+pub fn set_cookies_from_headers(url: &ServoUrl, headers: &Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) {
     if let Some(cookies) = headers.get_raw("set-cookie") {
         for cookie in cookies.iter() {
             if let Ok(cookie_value) = String::from_utf8(cookie.clone()) {
                 set_cookie_for_url(&cookie_jar,
                                    &url,
                                    cookie_value);
             }
         }
     }
 }
 
-fn update_sts_list_from_response(url: &Url, response: &HttpResponse, hsts_list: &Arc<RwLock<HstsList>>) {
+fn update_sts_list_from_response(url: &ServoUrl, response: &HttpResponse, hsts_list: &Arc<RwLock<HstsList>>) {
     if url.scheme() != "https" {
         return;
     }
 
     if let Some(header) = response.headers().get::<StrictTransportSecurity>() {
         if let Some(host) = url.domain() {
             let mut hsts_list = hsts_list.write().unwrap();
             let include_subdomains = if header.include_subdomains {
@@ -608,17 +614,17 @@ impl StreamedResponse {
 enum Decoder {
     Gzip(GzDecoder<Box<HttpResponse>>),
     Deflate(DeflateDecoder<Box<HttpResponse>>),
     Brotli(Decompressor<Box<HttpResponse>>),
     Plain(Box<HttpResponse>)
 }
 
 fn prepare_devtools_request(request_id: String,
-                            url: Url,
+                            url: ServoUrl,
                             method: Method,
                             headers: Headers,
                             body: Option<Vec<u8>>,
                             pipeline_id: PipelineId,
                             now: Tm,
                             connect_time: u64,
                             send_time: u64,
                             is_xhr: bool) -> ChromeToDevtoolsControlMsg {
@@ -651,28 +657,28 @@ pub fn send_response_to_devtools(devtool
                              pipeline_id: PipelineId) {
     let response = DevtoolsHttpResponse { headers: headers, status: status, body: None, pipeline_id: pipeline_id };
     let net_event_response = NetworkEvent::HttpResponse(response);
 
     let msg = ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event_response);
     let _ = devtools_chan.send(DevtoolsControlMsg::FromChrome(msg));
 }
 
-fn request_must_be_secured(url: &Url, hsts_list: &Arc<RwLock<HstsList>>) -> bool {
+fn request_must_be_secured(url: &ServoUrl, hsts_list: &Arc<RwLock<HstsList>>) -> bool {
     match url.domain() {
         Some(domain) => hsts_list.read().unwrap().is_host_secure(domain),
         None => false
     }
 }
 
 pub fn modify_request_headers(headers: &mut Headers,
-                              url: &Url,
+                              url: &ServoUrl,
                               user_agent: &str,
                               referrer_policy: Option<ReferrerPolicy>,
-                              referrer_url: &mut Option<Url>) {
+                              referrer_url: &mut Option<ServoUrl>) {
     // Ensure that the host header is set from the original url
     let host = Host {
         hostname: url.host_str().unwrap().to_owned(),
         port: url.port_or_known_default()
     };
     headers.set(host);
 
     // If the user-agent has not already been set, then use the
@@ -695,17 +701,17 @@ pub fn modify_request_headers(headers: &
                                                url.clone());
 
     if let Some(referrer_val) = referrer_url.clone() {
         headers.set(Referer(referrer_val.into_string()));
     }
 }
 
 fn set_auth_header(headers: &mut Headers,
-                   url: &Url,
+                   url: &ServoUrl,
                    auth_cache: &Arc<RwLock<AuthCache>>) {
     if !headers.has::<Authorization<Basic>>() {
         if let Some(auth) = auth_from_url(url) {
             headers.set(auth);
         } else {
             if let Some(basic) = auth_from_cache(auth_cache, &url.origin()) {
                 headers.set(Authorization(basic));
             }
@@ -718,30 +724,30 @@ pub fn auth_from_cache(auth_cache: &Arc<
         let user_name = auth_entry.user_name.clone();
         let password  = Some(auth_entry.password.clone());
         Some(Basic { username: user_name, password: password })
     } else {
         None
     }
 }
 
-fn auth_from_url(doc_url: &Url) -> Option<Authorization<Basic>> {
+fn auth_from_url(doc_url: &ServoUrl) -> Option<Authorization<Basic>> {
     let username = doc_url.username();
     if username != "" {
         Some(Authorization(Basic {
             username: username.to_owned(),
             password: Some(doc_url.password().unwrap_or("").to_owned())
         }))
     } else {
         None
     }
 }
 
 pub fn process_response_headers(response: &HttpResponse,
-                                url: &Url,
+                                url: &ServoUrl,
                                 cookie_jar: &Arc<RwLock<CookieStorage>>,
                                 hsts_list: &Arc<RwLock<HstsList>>,
                                 load_data: &LoadData) {
     info!("got HTTP response {}, headers:", response.status());
     if log_enabled!(log::LogLevel::Info) {
         for header in response.headers().iter() {
             info!(" - {}", header);
         }
@@ -750,17 +756,17 @@ pub fn process_response_headers(response
     // https://fetch.spec.whatwg.org/#concept-http-network-fetch step 9
     if load_data.credentials_flag {
         set_cookies_from_headers(url, response.headers(), cookie_jar);
     }
     update_sts_list_from_response(url, response, hsts_list);
 }
 
 pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>,
-                          url: &Url,
+                          url: &ServoUrl,
                           method: &Method,
                           request_headers: &Headers,
                           cancel_listener: &CancellationListener,
                           data: &Option<Vec<u8>>,
                           load_data_method: &Method,
                           pipeline_id: &Option<PipelineId>,
                           iters: u32,
                           request_id: Option<&str>,
@@ -920,26 +926,26 @@ pub fn load<A, B>(load_data: &LoadData,
     }
 
     // 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.
     // Change our existing URL to that and keep note that we are viewing
     // the source rather than rendering the contents of the URL.
     let viewing_source = doc_url.scheme() == "view-source";
     if viewing_source {
-        doc_url = Url::parse(&load_data.url[Position::BeforeUsername..]).unwrap();
+        doc_url = ServoUrl::parse(&load_data.url.as_url().unwrap()[Position::BeforeUsername..]).unwrap();
     }
 
     // Loop to handle redirects.
     loop {
         iters = iters + 1;
 
         if doc_url.scheme() == "http" && request_must_be_secured(&doc_url, &http_state.hsts_list) {
             info!("{} is in the strict transport security list, requesting secure host", doc_url);
-            doc_url = secure_url(&doc_url);
+            doc_url = ServoUrl::from_url(secure_url(&doc_url.as_url().unwrap()));
         }
 
         if iters > 20 {
             return Err(LoadError::new(doc_url, LoadErrorType::MaxRedirects(iters - 1)));
         }
 
         if !matches!(doc_url.scheme(), "http" | "https") {
             let scheme = doc_url.scheme().to_owned();
@@ -953,17 +959,17 @@ pub fn load<A, B>(load_data: &LoadData,
         let mut block_cookies = false;
         if let Some(ref rules) = *http_state.blocked_content {
             let same_origin =
                 load_data.referrer_url.as_ref()
                          .map(|url| url.origin() == doc_url.origin())
                          .unwrap_or(false);
             let load_type = if same_origin { LoadType::FirstParty } else { LoadType::ThirdParty };
             let actions = process_rules_for_request(rules, &CBRequest {
-                url: &doc_url,
+                url: doc_url.as_url().unwrap(),
                 resource_type: to_resource_type(&load_data.context),
                 load_type: load_type,
             });
             for action in actions {
                 match action {
                     Reaction::Block => {
                         return Err(LoadError::new(doc_url, LoadErrorType::ContentBlocked));
                     },
--- a/servo/components/net/image_cache_thread.rs
+++ b/servo/components/net/image_cache_thread.rs
@@ -6,26 +6,26 @@ use immeta::load_from_buf;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use net_traits::{CoreResourceThread, NetworkError, fetch_async, FetchResponseMsg, FetchMetadata, Metadata};
 use net_traits::image::base::{Image, ImageMetadata, PixelFormat, load_from_memory};
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheCommand, ImageCacheThread, ImageState};
 use net_traits::image_cache_thread::{ImageCacheResult, ImageOrMetadataAvailable, ImageResponse, UsePlaceholder};
 use net_traits::image_cache_thread::ImageResponder;
 use net_traits::request::{Destination, RequestInit, Type as RequestType};
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::fs::File;
 use std::io::{self, Read};
 use std::mem;
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use threadpool::ThreadPool;
-use url::Url;
 use util::resource_files::resources_dir_path;
 use util::thread::spawn_named;
 use webrender_traits;
 
 ///
 /// TODO(gw): Remaining work on image cache:
 ///     * Make use of the prefetch support in various parts of the code.
 ///     * Profile time in GetImageIfAvailable - might be worth caching these results per paint / layout thread.
@@ -44,27 +44,27 @@ struct PendingLoad {
     metadata: Option<ImageMetadata>,
 
     // Once loading is complete, the result of the operation.
     result: Option<Result<(), NetworkError>>,
     listeners: Vec<ImageListener>,
 
     // The url being loaded. Do not forget that this may be several Mb
     // if we are loading a data: url.
-    url: Arc<Url>
+    url: ServoUrl,
 }
 
 enum LoadResult {
     Loaded(Image),
     PlaceholderLoaded(Arc<Image>),
     None
 }
 
 impl PendingLoad {
-    fn new(url: Arc<Url>) -> PendingLoad {
+    fn new(url: ServoUrl) -> PendingLoad {
         PendingLoad {
             bytes: vec!(),
             metadata: None,
             result: None,
             listeners: vec!(),
             url: url,
         }
     }
@@ -78,17 +78,17 @@ impl PendingLoad {
 // performance reasons, loads are indexed by a dedicated load key.
 struct AllPendingLoads {
     // The loads, indexed by a load key. Used during most operations,
     // for performance reasons.
     loads: HashMap<LoadKey, PendingLoad>,
 
     // Get a load key from its url. Used ony when starting and
     // finishing a load or when adding a new listener.
-    url_to_load_key: HashMap<Arc<Url>, LoadKey>,
+    url_to_load_key: HashMap<ServoUrl, LoadKey>,
 
     // A counter used to generate instances of LoadKey
     keygen: LoadKeyGenerator,
 }
 
 // Result of accessing a cache.
 #[derive(Eq, PartialEq)]
 enum CacheResult {
@@ -113,32 +113,32 @@ impl AllPendingLoads {
 
     // get a PendingLoad from its LoadKey. Prefer this to `get_by_url`,
     // for performance reasons.
     fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> {
         self.loads.get_mut(key)
     }
 
     // get a PendingLoad from its url. When possible, prefer `get_by_key_mut`.
-    fn get_by_url(&self, url: &Url) -> Option<&PendingLoad> {
+    fn get_by_url(&self, url: &ServoUrl) -> Option<&PendingLoad> {
         self.url_to_load_key.get(url).
             and_then(|load_key|
                 self.loads.get(load_key)
                 )
     }
 
     fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
         self.loads.remove(key).
             and_then(|pending_load| {
                 self.url_to_load_key.remove(&pending_load.url).unwrap();
                 Some(pending_load)
             })
     }
 
-    fn get_cached(&mut self, url: Arc<Url>) -> (CacheResult, LoadKey, &mut PendingLoad) {
+    fn get_cached(&mut self, url: ServoUrl) -> (CacheResult, LoadKey, &mut PendingLoad) {
         match self.url_to_load_key.entry(url.clone()) {
             Occupied(url_entry) => {
                 let load_key = url_entry.get();
                 (CacheResult::Hit, *load_key, self.loads.get_mut(load_key).unwrap())
             }
             Vacant(url_entry) => {
                 let load_key = self.keygen.next();
                 url_entry.insert(load_key);
@@ -250,17 +250,17 @@ struct ImageCache {
 
     // Resource thread handle
     core_resource_thread: CoreResourceThread,
 
     // Images that are loading over network, or decoding.
     pending_loads: AllPendingLoads,
 
     // Images that have finished loading (successful or not)
-    completed_loads: HashMap<Arc<Url>, CompletedLoad>,
+    completed_loads: HashMap<ServoUrl, CompletedLoad>,
 
     // The placeholder image used when an image fails to load
     placeholder_image: Option<Arc<Image>>,
 
     // Webrender API instance.
     webrender_api: webrender_traits::RenderApi,
 }
 
@@ -493,58 +493,58 @@ impl ImageCache {
 
         let image_response = match load_result {
             LoadResult::Loaded(image) => ImageResponse::Loaded(Arc::new(image)),
             LoadResult::PlaceholderLoaded(image) => ImageResponse::PlaceholderLoaded(image),
             LoadResult::None => ImageResponse::None,
         };
 
         let completed_load = CompletedLoad::new(image_response.clone());
-        self.completed_loads.insert(pending_load.url, completed_load);
+        self.completed_loads.insert(pending_load.url.into(), completed_load);
 
         for listener in pending_load.listeners {
             listener.notify(image_response.clone());
         }
     }
 
     // Request an image from the cache.  If the image hasn't been
     // loaded/decoded yet, it will be loaded/decoded in the
     // background. If send_metadata_msg is set, the channel will be notified
     // that image metadata is available, possibly before the image has finished
     // loading.
     fn request_image(&mut self,
-                     url: Url,
+                     url: ServoUrl,
                      result_chan: ImageCacheChan,
                      responder: Option<ImageResponder>,
                      send_metadata_msg: bool) {
         let image_listener = ImageListener::new(result_chan, responder, send_metadata_msg);
-        // Let's avoid copying url everywhere.
-        let ref_url = Arc::new(url);
 
         // Check if already completed
-        match self.completed_loads.get(&ref_url) {
+        match self.completed_loads.get(&url) {
             Some(completed_load) => {
                 // It's already completed, return a notify straight away
                 image_listener.notify(completed_load.image_response.clone());
             }
             None => {
                 // Check if the load is already pending
-                let (cache_result, load_key, mut pending_load) = self.pending_loads.get_cached(ref_url.clone());
+                let (cache_result, load_key, mut pending_load) = self.pending_loads.get_cached(url.clone());
                 pending_load.add_listener(image_listener);
                 match cache_result {
                     CacheResult::Miss => {
                         // A new load request! Request the load from
                         // the resource thread.
                         // https://html.spec.whatwg.org/multipage/#update-the-image-data
                         // step 12.
+                        //
+                        // TODO(emilio): ServoUrl in more places please!
                         let request = RequestInit {
-                            url: (*ref_url).clone(),
+                            url: url.clone(),
                             type_: RequestType::Image,
                             destination: Destination::Image,
-                            origin: (*ref_url).clone(),
+                            origin: url.clone(),
                             .. RequestInit::default()
                         };
 
                         let progress_sender = self.progress_sender.clone();
                         fetch_async(request, &self.core_resource_thread, move |action| {
                             let action = match action {
                                 FetchResponseMsg::ProcessRequestBody |
                                 FetchResponseMsg::ProcessRequestEOF => return,
@@ -573,29 +573,29 @@ impl ImageCache {
                         // Request is already on its way.
                     }
                 }
             }
         }
     }
 
     fn get_image_if_available(&mut self,
-                                   url: Url,
-                                   placeholder: UsePlaceholder, )
-                                   -> Result<Arc<Image>, ImageState> {
+                              url: ServoUrl,
+                              placeholder: UsePlaceholder, )
+                              -> Result<Arc<Image>, ImageState> {
        let img_or_metadata = self.get_image_or_meta_if_available(url, placeholder);
        match img_or_metadata {
             Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => Ok(image),
             Ok(ImageOrMetadataAvailable::MetadataAvailable(_)) => Err(ImageState::Pending),
             Err(err) => Err(err),
        }
     }
 
     fn get_image_or_meta_if_available(&mut self,
-                                      url: Url,
+                                      url: ServoUrl,
                                       placeholder: UsePlaceholder)
                                       -> Result<ImageOrMetadataAvailable, ImageState> {
         match self.completed_loads.get(&url) {
             Some(completed_load) => {
                 match (completed_load.image_response.clone(), placeholder) {
                     (ImageResponse::Loaded(image), _) |
                     (ImageResponse::PlaceholderLoaded(image), UsePlaceholder::Yes) => {
                         Ok(ImageOrMetadataAvailable::ImageAvailable(image))
@@ -619,19 +619,19 @@ impl ImageCache {
                 };
 
                 Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone()))
             }
         }
     }
 
     fn store_decode_image(&mut self,
-                          ref_url: Url,
+                          ref_url: ServoUrl,
                           loaded_bytes: Vec<u8>) {
-        let (cache_result, load_key, _) = self.pending_loads.get_cached(Arc::new(ref_url));
+        let (cache_result, load_key, _) = self.pending_loads.get_cached(ref_url.clone());
         assert!(cache_result == CacheResult::Miss);
         let action = ResponseAction::DataAvailable(loaded_bytes);
         let _ = self.progress_sender.send(ResourceLoadInfo {
             action: action,
             key: load_key,
         });
         let action = ResponseAction::ResponseComplete(Ok(()));
         let _ = self.progress_sender.send(ResourceLoadInfo {
--- a/servo/components/net/lib.rs
+++ b/servo/components/net/lib.rs
@@ -31,16 +31,17 @@ extern crate mime_guess;
 extern crate msg;
 extern crate net_traits;
 extern crate openssl;
 extern crate openssl_verify;
 extern crate profile_traits;
 extern crate rustc_serialize;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_url;
 extern crate threadpool;
 extern crate time;
 #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
 extern crate tinyfiledialogs;
 extern crate unicase;
 extern crate url;
 extern crate util;
 extern crate uuid;
--- a/servo/components/net/resource_thread.rs
+++ b/servo/components/net/resource_thread.rs
@@ -30,30 +30,30 @@ use net_traits::{CustomResponseMediator,
 use net_traits::{ResourceThreads, WebSocketCommunicate, WebSocketConnectData};
 use net_traits::LoadContext;
 use net_traits::ProgressMsg::Done;
 use net_traits::request::{Request, RequestInit};
 use net_traits::storage_thread::StorageThreadMsg;
 use profile_traits::time::ProfilerChan;
 use rustc_serialize::{Decodable, Encodable};
 use rustc_serialize::json;
+use servo_url::ServoUrl;
 use std::borrow::{Cow, ToOwned};
 use std::boxed::FnBox;
 use std::cell::Cell;
 use std::collections::HashMap;
 use std::error::Error;
 use std::fs::File;
 use std::io::prelude::*;
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
 use std::sync::{Arc, RwLock};
 use std::sync::mpsc::{Receiver, Sender, channel};
 use storage_thread::StorageThreadFactory;
-use url::Url;
 use util::prefs::PREFS;
 use util::thread::spawn_named;
 use websocket_loader;
 
 const TFD_PROVIDER: &'static TFDProvider = &TFDProvider;
 
 pub enum ProgressSender {
     Channel(IpcSender<ProgressMsg>),
@@ -71,17 +71,17 @@ impl ProgressSender {
     //XXXjdm return actual error
     pub fn send(&self, msg: ProgressMsg) -> Result<(), ()> {
         match *self {
             ProgressSender::Channel(ref c) => c.send(msg).map_err(|_| ()),
         }
     }
 }
 
-pub fn send_error(url: Url, err: NetworkError, start_chan: LoadConsumer) {
+pub fn send_error(url: ServoUrl, err: NetworkError, start_chan: LoadConsumer) {
     let mut metadata: Metadata = Metadata::default(url);
     metadata.status = None;
 
     if let Ok(p) = start_sending_opt(start_chan, metadata) {
         p.send(Done(Err(err))).unwrap();
     }
 }
 
@@ -472,32 +472,32 @@ impl CoreResourceManager {
             profiler_chan: profiler_chan,
             filemanager: FileManager::new(TFD_PROVIDER),
             cancel_load_map: HashMap::new(),
             next_resource_id: ResourceId(0),
         }
     }
 
     fn set_cookies_for_url(&mut self,
-                           request: Url,
+                           request: ServoUrl,
                            cookie_list: String,
                            source: CookieSource,
                            resource_group: &ResourceGroup) {
         let header = Header::parse_header(&[cookie_list.into_bytes()]);
         if let Ok(SetCookie(cookies)) = header {
             for bare_cookie in cookies {
                 if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, &request, source) {
                     let mut cookie_jar = resource_group.cookie_jar.write().unwrap();
                     cookie_jar.push(cookie, source);
                 }
             }
         }
     }
 
-    fn set_cookies_for_url_with_data(&mut self, request: Url, cookie: cookie_rs::Cookie, source: CookieSource,
+    fn set_cookies_for_url_with_data(&mut self, request: ServoUrl, cookie: cookie_rs::Cookie, source: CookieSource,
                                      resource_group: &ResourceGroup) {
         if let Some(cookie) = cookie::Cookie::new_wrapped(cookie, &request, source) {
             let mut cookie_jar = resource_group.cookie_jar.write().unwrap();
             cookie_jar.push(cookie, source)
         }
     }
 
     fn load(&mut self,
--- a/servo/components/net/storage_thread.rs
+++ b/servo/components/net/storage_thread.rs
@@ -1,20 +1,20 @@
 /* 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 ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use net_traits::storage_thread::{StorageThreadMsg, StorageType};
 use resource_thread;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::BTreeMap;
 use std::collections::HashMap;
 use std::path::PathBuf;
-use url::Url;
 use util::thread::spawn_named;
 
 const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024;
 
 pub trait StorageThreadFactory {
     fn new(config_dir: Option<PathBuf>) -> Self;
 }
 
@@ -100,54 +100,54 @@ impl StorageManager {
     fn select_data_mut(&mut self, storage_type: StorageType)
                        -> &mut HashMap<String, (usize, BTreeMap<String, String>)> {
         match storage_type {
             StorageType::Session => &mut self.session_data,
             StorageType::Local => &mut self.local_data
         }
     }
 
-    fn length(&self, sender: IpcSender<usize>, url: Url, storage_type: StorageType) {
+    fn length(&self, sender: IpcSender<usize>, url: ServoUrl, storage_type: StorageType) {
         let origin = self.origin_as_string(url);
         let data = self.select_data(storage_type);
         sender.send(data.get(&origin).map_or(0, |&(_, ref entry)| entry.len())).unwrap();
     }
 
     fn key(&self,
            sender: IpcSender<Option<String>>,
-           url: Url,
+           url: ServoUrl,
            storage_type: StorageType,
            index: u32) {
         let origin = self.origin_as_string(url);
         let data = self.select_data(storage_type);
         let key = data.get(&origin)
                       .and_then(|&(_, ref entry)| entry.keys().nth(index as usize))
                       .cloned();
         sender.send(key).unwrap();
     }
 
     fn keys(&self,
             sender: IpcSender<Vec<String>>,
-            url: Url,
+            url: ServoUrl,
             storage_type: StorageType) {
         let origin = self.origin_as_string(url);
         let data = self.select_data(storage_type);
         let keys = data.get(&origin)
                        .map_or(vec![], |&(_, ref entry)| entry.keys().cloned().collect());
 
         sender.send(keys).unwrap();
     }
 
     /// Sends Ok(changed, Some(old_value)) in case there was a previous
     /// value with the same key name but with different value name
     /// otherwise sends Err(()) to indicate that the operation would result in
     /// exceeding the quota limit
     fn set_item(&mut self,
                 sender: IpcSender<Result<(bool, Option<String>), ()>>,
-                url: Url,
+                url: ServoUrl,
                 storage_type: StorageType,
                 name: String,
                 value: String) {
         let origin = self.origin_as_string(url);
 
         let (this_storage_size, other_storage_size) = {
             let local_data = self.select_data(StorageType::Local);
             let session_data = self.select_data(StorageType::Session);
@@ -186,53 +186,53 @@ impl StorageManager {
             *total = new_total_size;
             message
         }).unwrap();
         sender.send(message).unwrap();
     }
 
     fn request_item(&self,
                 sender: IpcSender<Option<String>>,
-                url: Url,
+                url: ServoUrl,
                 storage_type: StorageType,
                 name: String) {
         let origin = self.origin_as_string(url);
         let data = self.select_data(storage_type);
         sender.send(data.get(&origin)
                     .and_then(|&(_, ref entry)| entry.get(&name))
                     .map(String::clone)).unwrap();
     }
 
     /// Sends Some(old_value) in case there was a previous value with the key name, otherwise sends None
     fn remove_item(&mut self,
                    sender: IpcSender<Option<String>>,
-                   url: Url,
+                   url: ServoUrl,
                    storage_type: StorageType,
                    name: String) {
         let origin = self.origin_as_string(url);
         let data = self.select_data_mut(storage_type);
         let old_value = data.get_mut(&origin).and_then(|&mut (ref mut total, ref mut entry)| {
             entry.remove(&name).and_then(|old| {
                 *total -= name.as_bytes().len() + old.as_bytes().len();
                 Some(old)
             })
         });
         sender.send(old_value).unwrap();
     }
 
-    fn clear(&mut self, sender: IpcSender<bool>, url: Url, storage_type: StorageType) {
+    fn clear(&mut self, sender: IpcSender<bool>, url: ServoUrl, storage_type: StorageType) {
         let origin = self.origin_as_string(url);
         let data = self.select_data_mut(storage_type);
         sender.send(data.get_mut(&origin)
                     .map_or(false, |&mut (ref mut total, ref mut entry)| {
                         if !entry.is_empty() {
                             entry.clear();
                             *total = 0;
                             true
                         } else {
                             false
                         }})).unwrap();
     }
 
-    fn origin_as_string(&self, url: Url) -> String {
+    fn origin_as_string(&self, url: ServoUrl) -> String {
         url.origin().ascii_serialization()
     }
 }
--- a/servo/components/net/websocket_loader.rs
+++ b/servo/components/net/websocket_loader.rs
@@ -4,35 +4,35 @@
 
 use cookie_storage::CookieStorage;
 use http_loader;
 use hyper::header::Host;
 use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
 use net_traits::MessageData;
 use net_traits::hosts::replace_hosts;
 use net_traits::unwrap_websocket_protocol;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::sync::{Arc, Mutex, RwLock};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::thread;
 use util::thread::spawn_named;
 use websocket::{Client, Message};
-use websocket::client::request::Url;
 use websocket::header::{Headers, Origin, WebSocketProtocol};
 use websocket::message::Type;
 use websocket::receiver::Receiver;
 use websocket::result::{WebSocketError, WebSocketResult};
 use websocket::sender::Sender;
 use websocket::stream::WebSocketStream;
 use websocket::ws::receiver::Receiver as WSReceiver;
 use websocket::ws::sender::Sender as Sender_Object;
 use websocket::ws::util::url::parse_url;
 
 /// *Establish a WebSocket Connection* as defined in RFC 6455.
-fn establish_a_websocket_connection(resource_url: &Url, net_url: (Host, String, bool),
+fn establish_a_websocket_connection(resource_url: &ServoUrl, net_url: (Host, String, bool),
                                     origin: String, protocols: Vec<String>,
                                     cookie_jar: Arc<RwLock<CookieStorage>>)
     -> WebSocketResult<(Headers, Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
     let host = Host {
         hostname: resource_url.host_str().unwrap().to_owned(),
         port: resource_url.port_or_known_default(),
     };
 
@@ -66,17 +66,17 @@ fn establish_a_websocket_connection(reso
 pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData, cookie_jar: Arc<RwLock<CookieStorage>>) {
     spawn_named(format!("WebSocket connection to {}", connect_data.resource_url), move || {
         // Step 8: Protocols.
 
         // Step 9.
 
         // URL that we actually fetch from the network, after applying the replacements
         // specified in the hosts file.
-        let net_url_result = parse_url(&replace_hosts(&connect_data.resource_url));
+        let net_url_result = parse_url(replace_hosts(&connect_data.resource_url).as_url().unwrap());
         let net_url = match net_url_result {
             Ok(net_url) => net_url,
             Err(e) => {
                 debug!("Failed to establish a WebSocket connection: {:?}", e);
                 let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
                 return;
             }
         };
--- a/servo/components/net_traits/Cargo.toml
+++ b/servo/components/net_traits/Cargo.toml
@@ -19,16 +19,17 @@ heapsize_derive = "0.1"
 hyper = "0.9.9"
 hyper_serde = "0.1.4"
 image = "0.10"
 lazy_static = "0.2"
 log = "0.3.5"
 num-traits = "0.1.32"
 serde = "0.8"
 serde_derive = "0.8"
+servo_url = {path = "../url", features = ["servo"]}
 url = {version = "1.2", features = ["heap_size"]}
 websocket = "0.17"
 uuid = { version = "0.3.1", features = ["v4", "serde"] }
 cookie = {version = "0.2.5", features = ["serialize-rustc"]}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
--- a/servo/components/net_traits/blob_url_store.rs
+++ b/servo/components/net_traits/blob_url_store.rs
@@ -1,13 +1,14 @@
 /* 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 filemanager_thread::FileOrigin;
+use servo_url::ServoUrl;
 use std::str::FromStr;
 use url::Url;
 use uuid::Uuid;
 
 /// Errors returned to Blob URL Store request
 #[derive(Clone, Debug, Serialize, Deserialize)]
 pub enum BlobURLStoreError {
     /// Invalid File UUID
@@ -29,30 +30,32 @@ pub struct BlobBuf {
     /// Size of content in bytes
     pub size: u64,
     /// Content of blob
     pub bytes: Vec<u8>,
 }
 
 /// Parse URL as Blob URL scheme's definition
 /// https://w3c.github.io/FileAPI/#DefinitionOfScheme
-pub fn parse_blob_url(url: &Url) -> Result<(Uuid, FileOrigin, Option<String>), ()> {
+pub fn parse_blob_url(url: &ServoUrl) -> Result<(Uuid, FileOrigin, Option<String>), ()> {
     let url_inner = try!(Url::parse(url.path()).map_err(|_| ()));
     let fragment = url_inner.fragment().map(|s| s.to_string());
-    let mut segs = try!(url_inner.path_segments().ok_or(()));
-    let id = try!(segs.nth(0).ok_or(()));
-    let id = try!(Uuid::from_str(id).map_err(|_| ()));
-    Ok((id, get_blob_origin(&url_inner), fragment))
+    let id = {
+        let mut segs = try!(url_inner.path_segments().ok_or(()));
+        let id = try!(segs.nth(0).ok_or(()));
+        try!(Uuid::from_str(id).map_err(|_| ()))
+    };
+    Ok((id, get_blob_origin(&ServoUrl::from_url(url_inner)), fragment))
 }
 
 /// Given an URL, returning the Origin that a Blob created under this
 /// URL should have.
 /// HACK(izgzhen): Not well-specified on spec, and it is a bit a hack
 /// both due to ambiguity of spec and that we have to serialization the
 /// Origin here.
-pub fn get_blob_origin(url: &Url) -> FileOrigin {
+pub fn get_blob_origin(url: &ServoUrl) -> FileOrigin {
     if url.scheme() == "file" {
         // NOTE: by default this is "null" (Opaque), which is not ideal
         "file://".to_string()
     } else {
         url.origin().unicode_serialization()
     }
 }
--- a/servo/components/net_traits/hosts.rs
+++ b/servo/components/net_traits/hosts.rs
@@ -1,18 +1,18 @@
 /* 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 servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::env;
 use std::fs::File;
 use std::io::{BufReader, Read};
 use std::net::IpAddr;
-use url::Url;
 
 lazy_static! {
     static ref HOST_TABLE: Option<HashMap<String, IpAddr>> = create_host_table();
 }
 
 fn create_host_table() -> Option<HashMap<String, IpAddr>> {
     //TODO: handle bad file path
     let path = match env::var("HOST_FILE") {
@@ -47,22 +47,22 @@ pub fn parse_hostsfile(hostsfile_content
                     host_table.insert((*token).to_owned(), address);
                 }
             }
         }
     }
     host_table
 }
 
-pub fn replace_hosts(url: &Url) -> Url {
+pub fn replace_hosts(url: &ServoUrl) -> ServoUrl {
     HOST_TABLE.as_ref().map_or_else(|| url.clone(), |host_table| {
         host_replacement(host_table, url)
     })
 }
 
 pub fn host_replacement(host_table: &HashMap<String, IpAddr>,
-                        url: &Url) -> Url {
+                        url: &ServoUrl) -> ServoUrl {
     url.domain().and_then(|domain| host_table.get(domain).map(|ip| {
         let mut new_url = url.clone();
         new_url.set_ip_host(*ip).unwrap();
         new_url
     })).unwrap_or_else(|| url.clone())
 }
--- a/servo/components/net_traits/image_cache_thread.rs
+++ b/servo/components/net_traits/image_cache_thread.rs
@@ -1,16 +1,16 @@
 /* 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 image::base::{Image, ImageMetadata};
 use ipc_channel::ipc::{self, IpcSender};
+use servo_url::ServoUrl;
 use std::sync::Arc;
-use url::Url;
 
 /// This is optionally passed to the image cache when requesting
 /// and image, and returned to the specified event loop when the
 /// image load completes. It is typically used to trigger a reflow
 /// and/or repaint.
 #[derive(Clone, Deserialize, Serialize)]
 pub struct ImageResponder {
     sender: IpcSender<ImageResponse>,
@@ -69,37 +69,37 @@ pub struct ImageCacheResult {
 }
 
 /// Commands that the image cache understands.
 #[derive(Deserialize, Serialize)]
 pub enum ImageCacheCommand {
     /// Request an image asynchronously from the cache. Supply a channel
     /// to receive the result, and optionally an image responder
     /// that is passed to the result channel.
-    RequestImage(Url, ImageCacheChan, Option<ImageResponder>),
+    RequestImage(ServoUrl, ImageCacheChan, Option<ImageResponder>),
 
     /// Requests an image and a "metadata-ready" notification message asynchronously from the
     /// cache. The cache will make an effort to send metadata before the image is completely
     /// loaded. Supply a channel to receive the results, and optionally an image responder
     /// that is passed to the result channel.
-    RequestImageAndMetadata(Url, ImageCacheChan, Option<ImageResponder>),
+    RequestImageAndMetadata(ServoUrl, ImageCacheChan, Option<ImageResponder>),
 
     /// Synchronously check the state of an image in the cache.
     /// TODO(gw): Profile this on some real world sites and see
     /// if it's worth caching the results of this locally in each
     /// layout / paint thread.
-    GetImageIfAvailable(Url, UsePlaceholder, IpcSender<Result<Arc<Image>, ImageState>>),
+    GetImageIfAvailable(ServoUrl, UsePlaceholder, IpcSender<Result<Arc<Image>, ImageState>>),
 
     /// Synchronously check the state of an image in the cache. If the image is in a loading
     /// state and but its metadata has been made available, it will be sent as a response.
-    GetImageOrMetadataIfAvailable(Url, UsePlaceholder, IpcSender<Result<ImageOrMetadataAvailable, ImageState>>),
+    GetImageOrMetadataIfAvailable(ServoUrl, UsePlaceholder, IpcSender<Result<ImageOrMetadataAvailable, ImageState>>),
 
     /// Instruct the cache to store this data as a newly-complete network request and continue
     /// decoding the result into pixel data
-    StoreDecodeImage(Url, Vec<u8>),
+    StoreDecodeImage(ServoUrl, Vec<u8>),
 
     /// Clients must wait for a response before shutting down the ResourceThread
     Exit(IpcSender<()>),
 }
 
 #[derive(Copy, Clone, PartialEq, Hash, Eq, Deserialize, Serialize)]
 pub enum UsePlaceholder {
     No,
@@ -119,56 +119,58 @@ impl ImageCacheThread {
     pub fn new(chan: IpcSender<ImageCacheCommand>) -> ImageCacheThread {
         ImageCacheThread {
             chan: chan,
         }
     }
 
     /// Asynchronously request an image. See ImageCacheCommand::RequestImage.
     pub fn request_image(&self,
-                         url: Url,
+                         url: ServoUrl,
                          result_chan: ImageCacheChan,
                          responder: Option<ImageResponder>) {
         let msg = ImageCacheCommand::RequestImage(url, result_chan, responder);
         let _ = self.chan.send(msg);
     }
 
     /// Asynchronously request an image and metadata.
     /// See ImageCacheCommand::RequestImageAndMetadata
     pub fn request_image_and_metadata(&self,
-                                      url: Url,
+                                      url: ServoUrl,
                                       result_chan: ImageCacheChan,
                                       responder: Option<ImageResponder>) {
         let msg = ImageCacheCommand::RequestImageAndMetadata(url, result_chan, responder);
         let _ = self.chan.send(msg);
     }
 
     /// Get the current state of an image. See ImageCacheCommand::GetImageIfAvailable.
-    pub fn find_image(&self, url: Url, use_placeholder: UsePlaceholder)
+    pub fn find_image(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
                                   -> Result<Arc<Image>, ImageState> {
         let (sender, receiver) = ipc::channel().unwrap();
         let msg = ImageCacheCommand::GetImageIfAvailable(url, use_placeholder, sender);
         let _ = self.chan.send(msg);
         try!(receiver.recv().map_err(|_| ImageState::LoadError))
     }
 
     /// Get the current state of an image, returning its metadata if available.
     /// See ImageCacheCommand::GetImageOrMetadataIfAvailable.
-    pub fn find_image_or_metadata(&self, url: Url, use_placeholder: UsePlaceholder)
+    ///
+    /// FIXME: We shouldn't do IPC for data uris!
+    pub fn find_image_or_metadata(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
                                   -> Result<ImageOrMetadataAvailable, ImageState> {
         let (sender, receiver) = ipc::channel().unwrap();
         let msg = ImageCacheCommand::GetImageOrMetadataIfAvailable(url, use_placeholder, sender);
         let _ = self.chan.send(msg);
         try!(receiver.recv().map_err(|_| ImageState::LoadError))
     }
 
     /// Decode the given image bytes and cache the result for the given URL.
     pub fn store_complete_image_bytes(&self,
-                                   url: Url,
-                                   image_data: Vec<u8>) {
+                                      url: ServoUrl,
+                                      image_data: Vec<u8>) {
         let msg = ImageCacheCommand::StoreDecodeImage(url, image_data);
         let _ = self.chan.send(msg);
     }
 
     /// Shutdown the image cache thread.
     pub fn exit(&self) {
         let (response_chan, response_port) = ipc::channel().unwrap();
         let _ = self.chan.send(ImageCacheCommand::Exit(response_chan));
--- a/servo/components/net_traits/lib.rs
+++ b/servo/components/net_traits/lib.rs
@@ -22,16 +22,17 @@ extern crate ipc_channel;
 extern crate lazy_static;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate num_traits;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_url;
 extern crate url;
 extern crate util;
 extern crate uuid;
 extern crate webrender_traits;
 extern crate websocket;
 
 use bluetooth_traits::{BluetoothResponseListener, BluetoothResponseResult};
 use cookie_rs::Cookie;
@@ -42,19 +43,19 @@ use hyper::http::RawStatus;
 use hyper::method::Method;
 use hyper::mime::{Attr, Mime};
 use hyper_serde::Serde;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use msg::constellation_msg::PipelineId;
 use request::{Request, RequestInit};
 use response::{HttpsState, Response};
+use servo_url::ServoUrl;
 use std::io::Error as IOError;
 use storage_thread::StorageThreadMsg;
-use url::Url;
 use websocket::header;
 
 pub mod blob_url_store;
 pub mod filemanager_thread;
 pub mod hosts;
 pub mod image_cache_thread;
 pub mod net_error_list;
 pub mod pub_domains;
@@ -103,17 +104,17 @@ impl CustomResponse {
     pub fn new(headers: Headers, raw_status: RawStatus, body: Vec<u8>) -> CustomResponse {
         CustomResponse { headers: headers, raw_status: raw_status, body: body }
     }
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub struct CustomResponseMediator {
     pub response_chan: IpcSender<Option<CustomResponse>>,
-    pub load_url: Url
+    pub load_url: ServoUrl,
 }
 
 /// [Policies](https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states)
 /// for providing a referrer header for a request
 #[derive(Clone, Copy, Debug, Deserialize, HeapSizeOf, Serialize)]
 pub enum ReferrerPolicy {
     /// "no-referrer"
     NoReferrer,
@@ -130,17 +131,17 @@ pub enum ReferrerPolicy {
     /// "strict-origin"
     StrictOrigin,
     /// "strict-origin-when-cross-origin"
     StrictOriginWhenCrossOrigin,
 }
 
 #[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
 pub struct LoadData {
-    pub url: Url,
+    pub url: ServoUrl,
     #[ignore_heap_size_of = "Defined in hyper"]
     #[serde(deserialize_with = "::hyper_serde::deserialize",
             serialize_with = "::hyper_serde::serialize")]
     pub method: Method,
     #[ignore_heap_size_of = "Defined in hyper"]
     #[serde(deserialize_with = "::hyper_serde::deserialize",
             serialize_with = "::hyper_serde::serialize")]
     /// Headers that will apply to the initial request only
@@ -154,22 +155,22 @@ pub struct LoadData {
     pub data: Option<Vec<u8>>,
     pub cors: Option<ResourceCorsData>,
     pub pipeline_id: Option<PipelineId>,
     // https://fetch.spec.whatwg.org/#concept-http-fetch step 4.3
     pub credentials_flag: bool,
     pub context: LoadContext,
     /// The policy and referring URL for the originator of this request
     pub referrer_policy: Option<ReferrerPolicy>,
-    pub referrer_url: Option<Url>
+    pub referrer_url: Option<ServoUrl>
 }
 
 impl LoadData {
     pub fn new(context: LoadContext,
-               url: Url,
+               url: ServoUrl,
                load_origin: &LoadOrigin) -> LoadData {
         LoadData {
             url: url,
             method: Method::Get,
             headers: Headers::new(),
             preserved_headers: Headers::new(),
             data: None,
             cors: None,
@@ -178,17 +179,17 @@ impl LoadData {
             context: context,
             referrer_policy: load_origin.referrer_policy(),
             referrer_url: load_origin.referrer_url().clone(),
         }
     }
 }
 
 pub trait LoadOrigin {
-    fn referrer_url(&self) -> Option<Url>;
+    fn referrer_url(&self) -> Option<ServoUrl>;
     fn referrer_policy(&self) -> Option<ReferrerPolicy>;
     fn pipeline_id(&self) -> Option<PipelineId>;
 }
 
 #[derive(Deserialize, Serialize)]
 pub enum FetchResponseMsg {
     // todo: should have fields for transmitted/total bytes
     ProcessRequestBody,
@@ -401,42 +402,42 @@ pub enum WebSocketNetworkEvent {
 #[derive(Deserialize, Serialize)]
 pub struct WebSocketCommunicate {
     pub event_sender: IpcSender<WebSocketNetworkEvent>,
     pub action_receiver: IpcReceiver<WebSocketDomAction>,
 }
 
 #[derive(Deserialize, Serialize)]
 pub struct WebSocketConnectData {
-    pub resource_url: Url,
+    pub resource_url: ServoUrl,
     pub origin: String,
     pub protocols: Vec<String>,
 }
 
 #[derive(Deserialize, Serialize)]
 pub enum CoreResourceMsg {
     /// Request the data associated with a particular URL
     Load(LoadData, LoadConsumer, Option<IpcSender<ResourceId>>),
     Fetch(RequestInit, IpcSender<FetchResponseMsg>),
     /// Try to make a websocket connection to a URL.
     WebsocketConnect(WebSocketCommunicate, WebSocketConnectData),
     /// Store a set of cookies for a given originating URL
-    SetCookiesForUrl(Url, String, CookieSource),
+    SetCookiesForUrl(ServoUrl, String, CookieSource),
     /// Store a set of cookies for a given originating URL
     SetCookiesForUrlWithData(
-        Url,
+        ServoUrl,
         #[serde(deserialize_with = "::hyper_serde::deserialize",
                 serialize_with = "::hyper_serde::serialize")]
         Cookie,
         CookieSource
     ),
     /// Retrieve the stored cookies for a given URL
-    GetCookiesForUrl(Url, IpcSender<Option<String>>, CookieSource),
+    GetCookiesForUrl(ServoUrl, IpcSender<Option<String>>, CookieSource),
     /// Get a cookie by name for a given originating URL
-    GetCookiesDataForUrl(Url, IpcSender<Vec<Serde<Cookie>>>, CookieSource),
+    GetCookiesDataForUrl(ServoUrl, IpcSender<Vec<Serde<Cookie>>>, CookieSource),
     /// Cancel a network request corresponding to a given `ResourceId`
     Cancel(ResourceId),
     /// Synchronization message solely for knowing the state of the ResourceChannelManager loop
     Synchronize(IpcSender<()>),
     /// Send the network sender in constellation to CoreResourceThread
     NetworkMediator(IpcSender<CustomResponseMediator>),
     /// Message forwarded to file manager's handler
     ToFileManager(FileManagerThreadMsg),
@@ -471,24 +472,24 @@ pub struct LoadResponse {
     pub progress_port: IpcReceiver<ProgressMsg>,
 }
 
 #[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
 pub struct ResourceCorsData {
     /// CORS Preflight flag
     pub preflight: bool,
     /// Origin of CORS Request
-    pub origin: Url,
+    pub origin: ServoUrl,
 }
 
 /// Metadata about a loaded resource, such as is obtained from HTTP headers.
 #[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
 pub struct Metadata {
     /// Final URL after redirects.
-    pub final_url: Url,
+    pub final_url: ServoUrl,
 
     #[ignore_heap_size_of = "Defined in hyper"]
     /// MIME type / subtype.
     pub content_type: Option<Serde<ContentType>>,
 
     /// Character set.
     pub charset: Option<String>,
 
@@ -498,22 +499,22 @@ pub struct Metadata {
 
     /// HTTP Status
     pub status: Option<(u16, Vec<u8>)>,
 
     /// Is successful HTTPS connection
     pub https_state: HttpsState,
 
     /// Referrer Url
-    pub referrer: Option<Url>,
+    pub referrer: Option<ServoUrl>,
 }
 
 impl Metadata {
     /// Metadata with defaults for everything optional.
-    pub fn default(url: Url) -> Self {
+    pub fn default(url: ServoUrl) -> Self {
         Metadata {
             final_url:    url,
             content_type: None,
             charset:      None,
             headers: None,
             // https://fetch.spec.whatwg.org/#concept-response-status-message
             status: Some((200, b"OK".to_vec())),
             https_state: HttpsState::None,
@@ -609,17 +610,17 @@ pub enum ConstellationMsg {
 
 /// Network errors that have to be exported out of the loaders
 #[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, HeapSizeOf)]
 pub enum NetworkError {
     /// Could be any of the internal errors, like unsupported scheme, connection errors, etc.
     Internal(String),
     LoadCancelled,
     /// SSL validation error that has to be handled in the HTML parser
-    SslValidation(Url, String),
+    SslValidation(ServoUrl, String),
 }
 
 /// Normalize `slice`, as defined by
 /// [the Fetch Spec](https://fetch.spec.whatwg.org/#concept-header-value-normalize).
 pub fn trim_http_whitespace(mut slice: &[u8]) -> &[u8] {
     const HTTP_WS_BYTES: &'static [u8] = b"\x09\x0A\x0D\x20";
 
     loop {
--- a/servo/components/net_traits/request.rs
+++ b/servo/components/net_traits/request.rs
@@ -1,20 +1,21 @@
 /* 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 ReferrerPolicy;
 use hyper::header::Headers;
 use hyper::method::Method;
 use msg::constellation_msg::PipelineId;
+use servo_url::ServoUrl;
 use std::cell::{Cell, RefCell};
 use std::default::Default;
 use std::mem::swap;
-use url::{Origin as UrlOrigin, Url};
+use url::{Origin as UrlOrigin};
 
 /// An [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator)
 #[derive(Copy, Clone, PartialEq, HeapSizeOf)]
 pub enum Initiator {
     None,
     Download,
     ImageSet,
     Manifest,
@@ -44,17 +45,17 @@ pub enum Origin {
 }
 
 /// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
 #[derive(Clone, PartialEq, HeapSizeOf)]
 pub enum Referrer {
     NoReferrer,
     /// Default referrer if nothing is specified
     Client,
-    ReferrerUrl(Url)
+    ReferrerUrl(ServoUrl)
 }
 
 /// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
 #[derive(Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
 pub enum RequestMode {
     Navigate,
     SameOrigin,
     NoCors,
@@ -112,17 +113,17 @@ pub enum CorsSettings {
 }
 
 #[derive(Serialize, Deserialize, Clone, HeapSizeOf)]
 pub struct RequestInit {
     #[serde(deserialize_with = "::hyper_serde::deserialize",
             serialize_with = "::hyper_serde::serialize")]
     #[ignore_heap_size_of = "Defined in hyper"]
     pub method: Method,
-    pub url: Url,
+    pub url: ServoUrl,
     #[serde(deserialize_with = "::hyper_serde::deserialize",
             serialize_with = "::hyper_serde::serialize")]
     #[ignore_heap_size_of = "Defined in hyper"]
     pub headers: Headers,
     pub unsafe_request: bool,
     pub body: Option<Vec<u8>>,
     // TODO: client object
     pub type_: Type,
@@ -130,41 +131,41 @@ pub struct RequestInit {
     pub synchronous: bool,
     pub mode: RequestMode,
     pub cache_mode: CacheMode,
     pub use_cors_preflight: bool,
     pub credentials_mode: CredentialsMode,
     pub use_url_credentials: bool,
     // this should actually be set by fetch, but fetch
     // doesn't have info about the client right now
-    pub origin: Url,
+    pub origin: ServoUrl,
     // XXXManishearth these should be part of the client object
-    pub referrer_url: Option<Url>,
+    pub referrer_url: Option<ServoUrl>,
     pub referrer_policy: Option<ReferrerPolicy>,
     pub pipeline_id: Option<PipelineId>,
     pub redirect_mode: RedirectMode,
 }
 
 impl Default for RequestInit {
     fn default() -> RequestInit {
         RequestInit {
             method: Method::Get,
-            url: Url::parse("about:blank").unwrap(),
+            url: ServoUrl::parse("about:blank").unwrap(),
             headers: Headers::new(),
             unsafe_request: false,
             body: None,
             type_: Type::None,
             destination: Destination::None,
             synchronous: false,
             mode: RequestMode::NoCors,
             cache_mode: CacheMode::Default,
             use_cors_preflight: false,
             credentials_mode: CredentialsMode::Omit,
             use_url_credentials: false,
-            origin: Url::parse("about:blank").unwrap(),
+            origin: ServoUrl::parse("about:blank").unwrap(),
             referrer_url: None,
             referrer_policy: None,
             pipeline_id: None,
             redirect_mode: RedirectMode::Follow,
         }
     }
 }
 
@@ -200,24 +201,24 @@ pub struct Request {
     pub use_cors_preflight: bool,
     pub credentials_mode: CredentialsMode,
     pub use_url_credentials: bool,
     pub cache_mode: Cell<CacheMode>,
     pub redirect_mode: Cell<RedirectMode>,
     pub integrity_metadata: RefCell<String>,
     // Use the last method on url_list to act as spec current url field, and
     // first method to act as spec url field
-    pub url_list: RefCell<Vec<Url>>,
+    pub url_list: RefCell<Vec<ServoUrl>>,
     pub redirect_count: Cell<u32>,
     pub response_tainting: Cell<ResponseTainting>,
     pub done: Cell<bool>,
 }
 
 impl Request {
-    pub fn new(url: Url,
+    pub fn new(url: ServoUrl,
                origin: Option<Origin>,
                is_service_worker_global_scope: bool,
                pipeline_id: Option<PipelineId>) -> Request {
         Request {
             method: RefCell::new(Method::Get),
             local_urls_only: false,
             sandboxed_storage_area_urls: false,
             headers: RefCell::new(Headers::new()),
@@ -272,21 +273,21 @@ impl Request {
             Referrer::NoReferrer
         };
         req.referrer_policy.set(init.referrer_policy);
         req.pipeline_id.set(init.pipeline_id);
         req.redirect_mode.set(init.redirect_mode);
         req
     }
 
-    pub fn url(&self) -> Url {
+    pub fn url(&self) -> ServoUrl {
         self.url_list.borrow().first().unwrap().clone()
     }
 
-    pub fn current_url(&self) -> Url {
+    pub fn current_url(&self) -> ServoUrl {
         self.url_list.borrow().last().unwrap().clone()
     }
 
     pub fn is_navigation_request(&self) -> bool {
         self.destination == Destination::Document
     }
 
     pub fn is_subresource_request(&self) -> bool {
@@ -296,30 +297,30 @@ impl Request {
                 | Destination::Style | Destination::XSLT
                 | Destination::None => true,
             _ => false
         }
     }
 }
 
 impl Referrer {
-    pub fn to_url(&self) -> Option<&Url> {
+    pub fn to_url(&self) -> Option<&ServoUrl> {
         match *self {
             Referrer::NoReferrer | Referrer::Client => None,
             Referrer::ReferrerUrl(ref url) => Some(url)
         }
     }
-    pub fn from_url(url: Option<Url>) -> Self {
+    pub fn from_url(url: Option<ServoUrl>) -> Self {
         if let Some(url) = url {
             Referrer::ReferrerUrl(url)
         } else {
             Referrer::NoReferrer
         }
     }
-    pub fn take(&mut self) -> Option<Url> {
+    pub fn take(&mut self) -> Option<ServoUrl> {
         let mut new = Referrer::Client;
         swap(self, &mut new);
         match new {
             Referrer::NoReferrer | Referrer::Client => None,
             Referrer::ReferrerUrl(url) => Some(url)
         }
     }
 }
--- a/servo/components/net_traits/response.rs
+++ b/servo/components/net_traits/response.rs
@@ -3,20 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The [Response](https://fetch.spec.whatwg.org/#responses) object
 //! resulting from a [fetch operation](https://fetch.spec.whatwg.org/#concept-fetch)
 use {FetchMetadata, FilteredMetadata, Metadata, NetworkError};
 use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
 use hyper::status::StatusCode;
 use hyper_serde::Serde;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::cell::{Cell, RefCell};
 use std::sync::{Arc, Mutex};
-use url::Url;
 
 /// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize, HeapSizeOf)]
 pub enum ResponseType {
     Basic,
     Cors,
     Default,
     Error(NetworkError),
@@ -74,38 +74,38 @@ pub enum ResponseMsg {
     Errored
 }
 
 /// A [Response](https://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec
 #[derive(Debug, Clone, HeapSizeOf)]
 pub struct Response {
     pub response_type: ResponseType,
     pub termination_reason: Option<TerminationReason>,
-    url: Option<Url>,
-    pub url_list: RefCell<Vec<Url>>,
+    url: Option<ServoUrl>,
+    pub url_list: RefCell<Vec<ServoUrl>>,
     /// `None` can be considered a StatusCode of `0`.
     #[ignore_heap_size_of = "Defined in hyper"]
     pub status: Option<StatusCode>,
     pub raw_status: Option<(u16, Vec<u8>)>,
     #[ignore_heap_size_of = "Defined in hyper"]
     pub headers: Headers,
     #[ignore_heap_size_of = "Mutex heap size undefined"]
     pub body: Arc<Mutex<ResponseBody>>,
     pub cache_state: CacheState,
     pub https_state: HttpsState,
-    pub referrer: Option<Url>,
+    pub referrer: Option<ServoUrl>,
     /// [Internal response](https://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response
     /// is a filtered response
     pub internal_response: Option<Box<Response>>,
     /// whether or not to try to return the internal_response when asked for actual_response
     pub return_internal: Cell<bool>,
 }
 
 impl Response {
-    pub fn new(url: Url) -> Response {
+    pub fn new(url: ServoUrl) -> Response {
         Response {
             response_type: ResponseType::Default,
             termination_reason: None,
             url: Some(url),
             url_list: RefCell::new(Vec::new()),
             status: Some(StatusCode::Ok),
             raw_status: Some((200, b"OK".to_vec())),
             headers: Headers::new(),
@@ -131,17 +131,17 @@ impl Response {
             cache_state: CacheState::None,
             https_state: HttpsState::None,
             referrer: None,
             internal_response: None,
             return_internal: Cell::new(true)
         }
     }
 
-    pub fn url(&self) -> Option<&Url> {
+    pub fn url(&self) -> Option<&ServoUrl> {
         self.url.as_ref()
     }
 
     pub fn is_network_error(&self) -> bool {
         match self.response_type {
             ResponseType::Error(..) => true,
             _ => false
         }
@@ -237,17 +237,17 @@ impl Response {
                 response.cache_state = CacheState::None;
             }
         }
 
         response
     }
 
     pub fn metadata(&self) -> Result<FetchMetadata, NetworkError> {
-        fn init_metadata(response: &Response, url: &Url) -> Metadata {
+        fn init_metadata(response: &Response, url: &ServoUrl) -> Metadata {
             let mut metadata = Metadata::default(url.clone());
             metadata.set_content_type(match response.headers.get() {
                 Some(&ContentType(ref mime)) => Some(mime),
                 None => None
             });
             metadata.headers = Some(Serde(response.headers.clone()));
             metadata.status = response.raw_status.clone();
             metadata.https_state = response.https_state;
--- a/servo/components/net_traits/storage_thread.rs
+++ b/servo/components/net_traits/storage_thread.rs
@@ -1,40 +1,40 @@
 /* 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 ipc_channel::ipc::IpcSender;
-use url::Url;
+use servo_url::ServoUrl;
 
 #[derive(Copy, Clone, Deserialize, Serialize, HeapSizeOf)]
 pub enum StorageType {
     Session,
     Local
 }
 
 /// Request operations on the storage data associated with a particular url
 #[derive(Deserialize, Serialize)]
 pub enum StorageThreadMsg {
     /// gets the number of key/value pairs present in the associated storage data
-    Length(IpcSender<usize>, Url, StorageType),
+    Length(IpcSender<usize>, ServoUrl, StorageType),
 
     /// gets the name of the key at the specified index in the associated storage data
-    Key(IpcSender<Option<String>>, Url, StorageType, u32),
+    Key(IpcSender<Option<String>>, ServoUrl, StorageType, u32),
 
     /// Gets the available keys in the associated storage data
-    Keys(IpcSender<Vec<String>>, Url, StorageType),
+    Keys(IpcSender<Vec<String>>, ServoUrl, StorageType),
 
     /// gets the value associated with the given key in the associated storage data
-    GetItem(IpcSender<Option<String>>, Url, StorageType, String),
+    GetItem(IpcSender<Option<String>>, ServoUrl, StorageType, String),
 
     /// sets the value of the given key in the associated storage data
-    SetItem(IpcSender<Result<(bool, Option<String>), ()>>, Url, StorageType, String, String),
+    SetItem(IpcSender<Result<(bool, Option<String>), ()>>, ServoUrl, StorageType, String, String),
 
     /// removes the key/value pair for the given key in the associated storage data
-    RemoveItem(IpcSender<Option<String>>, Url, StorageType, String),
+    RemoveItem(IpcSender<Option<String>>, ServoUrl, StorageType, String),
 
     /// clears the associated storage data by removing all the key/value pairs
-    Clear(IpcSender<bool>, Url, StorageType),
+    Clear(IpcSender<bool>, ServoUrl, StorageType),
 
     /// send a reply when done cleaning up thread resources and then shut it down
     Exit(IpcSender<()>)
 }
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -64,16 +64,17 @@ range = {path = "../range"}
 ref_slice = "1.0"
 regex = "0.1.43"
 rustc-serialize = "0.3"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = "0.14"
 serde = "0.8"
 servo_atoms = {path = "../atoms"}
+servo_url = {path = "../url", features = ["servo"] }
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 url = {version = "1.2", features = ["heap_size", "query_encoding"]}
 util = {path = "../util"}
 uuid = {version = "0.3.1", features = ["v4"]}
 websocket = "0.17"
--- a/servo/components/script/document_loader.rs
+++ b/servo/components/script/document_loader.rs
@@ -5,31 +5,31 @@
 //! Tracking of pending loads in a document.
 //! https://html.spec.whatwg.org/multipage/#the-end
 
 use dom::bindings::js::JS;
 use dom::document::Document;
 use ipc_channel::ipc::IpcSender;
 use net_traits::{CoreResourceMsg, FetchResponseMsg, ResourceThreads, IpcSend};
 use net_traits::request::RequestInit;
+use servo_url::ServoUrl;
 use std::thread;
-use url::Url;
 
 #[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
 pub enum LoadType {
-    Image(Url),
-    Script(Url),
-    Subframe(Url),
-    Stylesheet(Url),
-    PageSource(Url),
-    Media(Url),
+    Image(ServoUrl),
+    Script(ServoUrl),
+    Subframe(ServoUrl),
+    Stylesheet(ServoUrl),
+    PageSource(ServoUrl),
+    Media(ServoUrl),
 }
 
 impl LoadType {
-    fn url(&self) -> &Url {
+    fn url(&self) -> &ServoUrl {
         match *self {
             LoadType::Image(ref url) |
             LoadType::Script(ref url) |
             LoadType::Subframe(ref url) |
             LoadType::Stylesheet(ref url) |
             LoadType::Media(ref url) |
             LoadType::PageSource(ref url) => url,
         }
@@ -62,17 +62,17 @@ impl LoadBlocker {
     pub fn terminate(blocker: &mut Option<LoadBlocker>) {
         if let Some(this) = blocker.as_mut() {
             this.doc.finish_load(this.load.take().unwrap());
         }
         *blocker = None;
     }
 
     /// Return the url associated with this load.
-    pub fn url(&self) -> Option<&Url> {
+    pub fn url(&self) -> Option<&ServoUrl> {
         self.load.as_ref().map(LoadType::url)
     }
 }
 
 impl Drop for LoadBlocker {
     fn drop(&mut self) {
         if !thread::panicking() {
             debug_assert!(self.load.is_none());
@@ -88,17 +88,17 @@ pub struct DocumentLoader {
 }
 
 impl DocumentLoader {
     pub fn new(existing: &DocumentLoader) -> DocumentLoader {
         DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
     }
 
     pub fn new_with_threads(resource_threads: ResourceThreads,
-                            initial_load: Option<Url>) -> DocumentLoader {
+                            initial_load: Option<ServoUrl>) -> DocumentLoader {
         debug!("Initial blocking load {:?}.", initial_load);
         let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
 
         DocumentLoader {
             resource_threads: resource_threads,
             blocking_loads: initial_loads,
             events_inhibited: false,
         }
--- a/servo/components/script/dom/bindings/trace.rs
+++ b/servo/components/script/dom/bindings/trace.rs
@@ -75,16 +75,17 @@ use profile_traits::time::ProfilerChan a
 use script_layout_interface::OpaqueStyleAndLayoutData;
 use script_layout_interface::reporter::CSSErrorReporter;
 use script_layout_interface::rpc::LayoutRPC;
 use script_runtime::ScriptChan;
 use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase};
 use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
 use serde::{Deserialize, Serialize};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use smallvec::SmallVec;
 use std::boxed::FnBox;
 use std::cell::{Cell, UnsafeCell};
 use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
 use std::hash::{BuildHasher, Hash};
 use std::ops::{Deref, DerefMut};
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -95,17 +96,16 @@ use std::time::{SystemTime, Instant};
 use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
 use style::element_state::*;
 use style::media_queries::MediaList;
 use style::properties::PropertyDeclarationBlock;
 use style::selector_impl::{PseudoElement, Snapshot};
 use style::values::specified::Length;
 use time::Duration;
 use url::Origin as UrlOrigin;
-use url::Url;
 use uuid::Uuid;
 use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
 use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId};
 
 /// A trait to allow tracing (only) DOM objects.
 pub trait JSTraceable {
     /// Trace `self`.
     fn trace(&self, trc: *mut JSTracer);
@@ -297,17 +297,17 @@ impl<A: JSTraceable, B: JSTraceable, C: 
     fn trace(&self, trc: *mut JSTracer) {
         let (ref a, ref b, ref c) = *self;
         a.trace(trc);
         b.trace(trc);
         c.trace(trc);
     }
 }
 
-no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char);
+no_jsmanaged_fields!(bool, f32, f64, String, ServoUrl, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char);
 no_jsmanaged_fields!(usize, u8, u16, u32, u64);
 no_jsmanaged_fields!(isize, i8, i16, i32, i64);
 no_jsmanaged_fields!(Sender<T>);
 no_jsmanaged_fields!(Receiver<T>);
 no_jsmanaged_fields!(Point2D<T>);
 no_jsmanaged_fields!(Rect<T>);
 no_jsmanaged_fields!(Size2D<T>);
 no_jsmanaged_fields!(Arc<T>);
--- a/servo/components/script/dom/canvasrenderingcontext2d.rs
+++ b/servo/components/script/dom/canvasrenderingcontext2d.rs
@@ -37,21 +37,21 @@ use euclid::matrix2d::Matrix2D;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::size::Size2D;
 use ipc_channel::ipc::{self, IpcSender};
 use net_traits::image::base::PixelFormat;
 use net_traits::image_cache_thread::ImageResponse;
 use num_traits::ToPrimitive;
 use script_traits::ScriptMsg as ConstellationMsg;
+use servo_url::ServoUrl;
 use std::{cmp, fmt};
 use std::cell::Cell;
 use std::str::FromStr;
 use unpremultiplytable::UNPREMULTIPLY_TABLE;
-use url::Url;
 
 #[must_root]
 #[derive(JSTraceable, Clone, HeapSizeOf)]
 #[allow(dead_code)]
 enum CanvasFillOrStrokeStyle {
     Color(RGBA),
     Gradient(JS<CanvasGradient>),
     Pattern(JS<CanvasPattern>),
@@ -446,17 +446,17 @@ impl CanvasRenderingContext2D {
             PixelFormat::RGB8 => panic!("RGB8 color type not supported"),
             PixelFormat::KA8 => panic!("KA8 color type not supported"),
         };
 
         Some((image_data, image_size))
     }
 
     #[inline]
-    fn request_image_from_cache(&self, url: Url) -> ImageResponse {
+    fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
         let window = window_from_node(&*self.canvas);
         canvas_utils::request_image_from_cache(&window, url)
     }
 
     fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> {
         if !([x, y, w, h].iter().all(|val| val.is_finite())) {
             return None;
         }
--- a/servo/components/script/dom/client.rs
+++ b/servo/components/script/dom/client.rs
@@ -5,31 +5,31 @@
 use dom::bindings::codegen::Bindings::ClientBinding::{ClientMethods, Wrap};
 use dom::bindings::codegen::Bindings::ClientBinding::FrameType;
 use dom::bindings::js::JS;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{Reflector, reflect_dom_object};
 use dom::bindings::str::{DOMString, USVString};
 use dom::serviceworker::ServiceWorker;
 use dom::window::Window;
-use url::Url;
+use servo_url::ServoUrl;
 use uuid::Uuid;
 
 #[dom_struct]
 pub struct Client {
     reflector_: Reflector,
     active_worker: Option<JS<ServiceWorker>>,
     url: USVString,
     frame_type: FrameType,
     #[ignore_heap_size_of = "Defined in uuid"]
     id: Uuid
 }
 
 impl Client {
-    fn new_inherited(url: Url) -> Client {
+    fn new_inherited(url: ServoUrl) -> Client {
         Client {
             reflector_: Reflector::new(),
             active_worker: None,
             url: USVString(url.as_str().to_owned()),
             frame_type: FrameType::None,
             id: Uuid::new_v4()
         }
     }
--- a/servo/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/servo/components/script/dom/dedicatedworkerglobalscope.rs
@@ -28,22 +28,22 @@ use js::jsval::UndefinedValue;
 use js::rust::Runtime;
 use msg::constellation_msg::PipelineId;
 use net_traits::{IpcSend, load_whole_resource};
 use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
 use rand::random;
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
 use script_runtime::ScriptThreadEventCategory::WorkerEvent;
 use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
+use servo_url::ServoUrl;
 use std::mem::replace;
 use std::sync::{Arc, Mutex};
 use std::sync::atomic::AtomicBool;
 use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
 use style::thread_state;
-use url::Url;
 use util::thread::spawn_named;
 
 /// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
 /// value for the duration of this object's lifetime. This ensures that the related Worker
 /// object only lives as long as necessary (ie. while events are being executed), while
 /// providing a reference that can be cloned freely.
 struct AutoWorkerReset<'a> {
     workerscope: &'a DedicatedWorkerGlobalScope,
@@ -87,17 +87,17 @@ pub struct DedicatedWorkerGlobalScope {
     worker: DOMRefCell<Option<TrustedWorkerAddress>>,
     #[ignore_heap_size_of = "Can't measure trait objects"]
     /// Sender to the parent thread.
     parent_sender: Box<ScriptChan + Send>,
 }
 
 impl DedicatedWorkerGlobalScope {
     fn new_inherited(init: WorkerGlobalScopeInit,
-                     worker_url: Url,
+                     worker_url: ServoUrl,
                      from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
                      runtime: Runtime,
                      parent_sender: Box<ScriptChan + Send>,
                      own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
                      receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
                      timer_event_chan: IpcSender<TimerEvent>,
                      timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
                      closing: Arc<AtomicBool>)
@@ -114,17 +114,17 @@ impl DedicatedWorkerGlobalScope {
             timer_event_port: timer_event_port,
             parent_sender: parent_sender,
             worker: DOMRefCell::new(None),
         }
     }
 
     #[allow(unsafe_code)]
     pub fn new(init: WorkerGlobalScopeInit,
-               worker_url: Url,
+               worker_url: ServoUrl,
                from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
                runtime: Runtime,
                parent_sender: Box<ScriptChan + Send>,
                own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
                receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
                timer_event_chan: IpcSender<TimerEvent>,
                timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
                closing: Arc<AtomicBool>)
@@ -142,17 +142,17 @@ impl DedicatedWorkerGlobalScope {
                                                                   closing);
         unsafe {
             DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope)
         }
     }
 
     #[allow(unsafe_code)]
     pub fn run_worker_scope(init: WorkerGlobalScopeInit,
-                            worker_url: Url,
+                            worker_url: ServoUrl,
                             from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
                             worker_rt_for_mainthread: Arc<Mutex<Option<SharedRt>>>,
                             worker: TrustedWorkerAddress,
                             parent_sender: Box<ScriptChan + Send>,
                             own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
                             receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
                             worker_load_origin: WorkerScriptLoadOrigin,
                             closing: Arc<AtomicBool>) {
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -103,16 +103,17 @@ use num_traits::ToPrimitive;
 use origin::Origin;
 use script_layout_interface::message::{Msg, ReflowQueryType};
 use script_thread::{MainThreadScriptMsg, Runnable};
 use script_traits::{AnimationState, CompositorEvent, MouseButton, MouseEventType, MozBrowserEvent};
 use script_traits::{ScriptMsg as ConstellationMsg, TouchpadPressurePhase};
 use script_traits::{TouchEventType, TouchId};
 use script_traits::UntrustedNodeAddress;
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::boxed::FnBox;
 use std::cell::{Cell, Ref, RefMut};
 use std::collections::HashMap;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::default::Default;
 use std::iter::once;
@@ -122,17 +123,16 @@ use std::sync::Arc;
 use std::time::{Duration, Instant};
 use style::attr::AttrValue;
 use style::context::ReflowGoal;
 use style::restyle_hints::RestyleHint;
 use style::selector_impl::{RestyleDamage, Snapshot};
 use style::str::{split_html_space_chars, str_join};
 use style::stylesheets::Stylesheet;
 use time;
-use url::Url;
 use url::percent_encoding::percent_decode;
 use util::prefs::PREFS;
 
 pub enum TouchEventResult {
     Processed(bool),
     Forwarded,
 }
 
@@ -187,17 +187,17 @@ pub struct Document {
     /// https://html.spec.whatwg.org/multipage/#concept-document-bc
     browsing_context: Option<JS<BrowsingContext>>,
     implementation: MutNullableHeap<JS<DOMImplementation>>,
     location: MutNullableHeap<JS<Location>>,
     content_type: DOMString,
     last_modified: Option<String>,
     encoding: Cell<EncodingRef>,
     is_html_document: bool,
-    url: Url,
+    url: ServoUrl,
     quirks_mode: Cell<QuirksMode>,
     /// Caches for the getElement methods
     id_map: DOMRefCell<HashMap<Atom, Vec<JS<Element>>>>,
     tag_map: DOMRefCell<HashMap<LocalName, JS<HTMLCollection>>>,
     tagns_map: DOMRefCell<HashMap<QualName, JS<HTMLCollection>>>,
     classes_map: DOMRefCell<HashMap<Vec<Atom>, JS<HTMLCollection>>>,
     images: MutNullableHeap<JS<HTMLCollection>>,
     embeds: MutNullableHeap<JS<HTMLCollection>>,
@@ -393,30 +393,30 @@ impl Document {
         true
     }
 
     pub fn origin(&self) -> &Origin {
         &self.origin
     }
 
     // https://dom.spec.whatwg.org/#concept-document-url
-    pub fn url(&self) -> &Url {
+    pub fn url(&self) -> &ServoUrl {
         &self.url
     }
 
     // https://html.spec.whatwg.org/multipage/#fallback-base-url
-    pub fn fallback_base_url(&self) -> Url {
+    pub fn fallback_base_url(&self) -> ServoUrl {
         // Step 1: iframe srcdoc (#4767).
         // Step 2: about:blank with a creator browsing context.
         // Step 3.
         self.url().clone()
     }
 
     // https://html.spec.whatwg.org/multipage/#document-base-url
-    pub fn base_url(&self) -> Url {
+    pub fn base_url(&self) -> ServoUrl {
         match self.base_element() {
             // Step 1.
             None => self.fallback_base_url(),
             // Step 2.
             Some(base) => base.frozen_base_url(),
         }
     }
 
@@ -1757,36 +1757,36 @@ impl LayoutDocumentHelpers for LayoutJS<
 
     #[inline]
     unsafe fn will_paint(&self) {
         (*self.unsafe_get()).needs_paint.set(false)
     }
 }
 
 /// https://url.spec.whatwg.org/#network-scheme
-fn url_has_network_scheme(url: &Url) -> bool {
+fn url_has_network_scheme(url: &ServoUrl) -> bool {
     match url.scheme() {
         "ftp" | "http" | "https" => true,
         _ => false,
     }
 }
 
 impl Document {
     pub fn new_inherited(window: &Window,
                          browsing_context: Option<&BrowsingContext>,
-                         url: Option<Url>,
+                         url: Option<ServoUrl>,
                          is_html_document: IsHTMLDocument,
                          content_type: Option<DOMString>,
                          last_modified: Option<String>,
                          source: DocumentSource,
                          doc_loader: DocumentLoader,
                          referrer: Option<String>,
                          referrer_policy: Option<ReferrerPolicy>)
                          -> Document {
-        let url = url.unwrap_or_else(|| Url::parse("about:blank").unwrap());
+        let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
 
         let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
             (DocumentReadyState::Loading, false)
         } else {
             (DocumentReadyState::Complete, true)
         };
 
         // Incomplete implementation of Document origin specification at
@@ -1887,17 +1887,17 @@ impl Document {
                          DocumentSource::NotFromParser,
                          docloader,
                          None,
                          None))
     }
 
     pub fn new(window: &Window,
                browsing_context: Option<&BrowsingContext>,
-               url: Option<Url>,
+               url: Option<ServoUrl>,
                doctype: IsHTMLDocument,
                content_type: Option<DOMString>,
                last_modified: Option<String>,
                source: DocumentSource,
                doc_loader: DocumentLoader,
                referrer: Option<String>,
                referrer_policy: Option<ReferrerPolicy>)
                -> Root<Document> {
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -378,17 +378,17 @@ impl LayoutElementHelpers for LayoutJS<E
             None
         };
 
         if let Some(url) = background {
             hints.push(from_declaration(
                 PropertyDeclaration::BackgroundImage(DeclaredValue::Value(
                     background_image::SpecifiedValue(vec![
                         background_image::single_value::SpecifiedValue(Some(
-                            specified::Image::for_cascade(Some(Arc::new(url)), specified::url::UrlExtraData { })
+                            specified::Image::for_cascade(Some(url.into()), specified::url::UrlExtraData { })
                         ))
                     ])))));
         }
 
         let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
             this.get_color()
         } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
             // https://html.spec.whatwg.org/multipage/#the-page:the-body-element-20
--- a/servo/components/script/dom/eventsource.rs
+++ b/servo/components/script/dom/eventsource.rs
@@ -26,23 +26,23 @@ use js::jsapi::JSAutoCompartment;
 use js::jsval::UndefinedValue;
 use mime::{Mime, TopLevel, SubLevel};
 use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseMsg, FetchResponseListener, NetworkError};
 use net_traits::request::{CacheMode, CorsSettings, CredentialsMode};
 use net_traits::request::{RequestInit, RequestMode};
 use network_listener::{NetworkListener, PreInvoke};
 use script_thread::Runnable;
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::cell::Cell;
 use std::mem;
 use std::str::{Chars, FromStr};
 use std::sync::{Arc, Mutex};
 use task_source::TaskSource;
 use timers::OneshotTimerCallback;
-use url::Url;
 
 header! { (LastEventId, "Last-Event-ID") => [String] }
 
 const DEFAULT_RECONNECTION_TIME: u64 = 5000;
 
 #[derive(JSTraceable, PartialEq, Copy, Clone, Debug, HeapSizeOf)]
 struct GenerationId(u32);
 
@@ -52,17 +52,17 @@ enum ReadyState {
     Connecting = 0,
     Open = 1,
     Closed = 2
 }
 
 #[dom_struct]
 pub struct EventSource {
     eventtarget: EventTarget,
-    url: Url,
+    url: ServoUrl,
     request: DOMRefCell<Option<RequestInit>>,
     last_event_id: DOMRefCell<DOMString>,
     reconnection_time: Cell<u64>,
     generation_id: Cell<GenerationId>,
 
     ready_state: Cell<ReadyState>,
     with_credentials: bool,
 }
@@ -304,31 +304,31 @@ impl FetchResponseListener for EventSour
 
 impl PreInvoke for EventSourceContext {
     fn should_invoke(&self) -> bool {
         self.event_source.root().generation_id.get() == self.gen_id
     }
 }
 
 impl EventSource {
-    fn new_inherited(url: Url, with_credentials: bool) -> EventSource {
+    fn new_inherited(url: ServoUrl, with_credentials: bool) -> EventSource {
         EventSource {
             eventtarget: EventTarget::new_inherited(),
             url: url,
             request: DOMRefCell::new(None),
             last_event_id: DOMRefCell::new(DOMString::from("")),
             reconnection_time: Cell::new(DEFAULT_RECONNECTION_TIME),
             generation_id: Cell::new(GenerationId(0)),
 
             ready_state: Cell::new(ReadyState::Connecting),
             with_credentials: with_credentials,
         }
     }
 
-    fn new(global: &GlobalScope, url: Url, with_credentials: bool) -> Root<EventSource> {
+    fn new(global: &GlobalScope, url: ServoUrl, with_credentials: bool) -> Root<EventSource> {
         reflect_dom_object(box EventSource::new_inherited(url, with_credentials),
                            global,
                            Wrap)
     }
 
     pub fn request(&self) -> RequestInit {
         self.request.borrow().clone().unwrap()
     }
--- a/servo/components/script/dom/eventtarget.rs
+++ b/servo/components/script/dom/eventtarget.rs
@@ -28,26 +28,26 @@ use dom::node::document_from_node;
 use dom::virtualmethods::VirtualMethods;
 use dom::window::Window;
 use fnv::FnvHasher;
 use heapsize::HeapSizeOf;
 use js::jsapi::{CompileFunction, JS_GetFunctionObject, JSAutoCompartment};
 use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper};
 use libc::{c_char, size_t};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::default::Default;
 use std::ffi::CString;
 use std::hash::BuildHasherDefault;
 use std::mem;
 use std::ops::{Deref, DerefMut};
 use std::ptr;
 use std::rc::Rc;
-use url::Url;
 
 #[derive(PartialEq, Clone, JSTraceable)]
 pub enum CommonEventHandler {
     EventHandler(Rc<EventHandlerNonNull>),
     ErrorEventHandler(Rc<OnErrorEventHandlerNonNull>),
     BeforeUnloadEventHandler(Rc<OnBeforeUnloadEventHandlerNonNull>),
 }
 
@@ -66,17 +66,17 @@ pub enum ListenerPhase {
     Capturing,
     Bubbling,
 }
 
 /// https://html.spec.whatwg.org/multipage/#internal-raw-uncompiled-handler
 #[derive(JSTraceable, Clone, PartialEq)]
 pub struct InternalRawUncompiledHandler {
     source: DOMString,
-    url: Url,
+    url: ServoUrl,
     line: usize,
 }
 
 /// A representation of an event handler, either compiled or uncompiled raw source, or null.
 #[derive(JSTraceable, PartialEq, Clone)]
 pub enum InlineEventListener {
     Uncompiled(InternalRawUncompiledHandler),
     Compiled(CommonEventHandler),
@@ -343,17 +343,17 @@ impl EventTarget {
     fn get_inline_event_listener(&self, ty: &Atom) -> Option<CommonEventHandler> {
         let mut handlers = self.handlers.borrow_mut();
         handlers.get_mut(ty).and_then(|entry| entry.get_inline_listener(self, ty))
     }
 
     /// Store the raw uncompiled event handler for on-demand compilation later.
     /// https://html.spec.whatwg.org/multipage/#event-handler-attributes:event-handler-content-attributes-3
     pub fn set_event_handler_uncompiled(&self,
-                                        url: Url,
+                                        url: ServoUrl,
                                         line: usize,
                                         ty: &str,
                                         source: DOMString) {
         let handler = InternalRawUncompiledHandler {
             source: source,
             line: line,
             url: url,
         };
--- a/servo/components/script/dom/globalscope.rs
+++ b/servo/components/script/dom/globalscope.rs
@@ -31,27 +31,27 @@ use libc;
 use msg::constellation_msg::PipelineId;
 use net_traits::{CoreResourceThread, ResourceThreads, IpcSend};
 use profile_traits::{mem, time};
 use script_runtime::{CommonScriptMsg, EnqueuedPromiseCallback, ScriptChan};
 use script_runtime::{ScriptPort, maybe_take_panic_result};
 use script_thread::{MainThreadScriptChan, RunnableWrapper, ScriptThread};
 use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEvent};
 use script_traits::{TimerEventId, TimerEventRequest, TimerSource};
+use servo_url::ServoUrl;
 use std::cell::Cell;
 use std::collections::HashMap;
 use std::collections::hash_map::Entry;
 use std::ffi::CString;
 use std::panic;
 use task_source::file_reading::FileReadingTaskSource;
 use task_source::networking::NetworkingTaskSource;
 use time::{Timespec, get_time};
 use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle};
 use timers::{OneshotTimers, TimerCallback};
-use url::Url;
 
 #[dom_struct]
 pub struct GlobalScope {
     eventtarget: EventTarget,
     crypto: MutNullableHeap<JS<Crypto>>,
     next_worker_id: Cell<WorkerId>,
 
     /// Pipeline id associated with this global.
@@ -234,30 +234,30 @@ impl GlobalScope {
 
     /// Get the `PipelineId` for this global scope.
     pub fn pipeline_id(&self) -> PipelineId {
         self.pipeline_id
     }
 
     /// Get the [base url](https://html.spec.whatwg.org/multipage/#api-base-url)
     /// for this global scope.
-    pub fn api_base_url(&self) -> Url {
+    pub fn api_base_url(&self) -> ServoUrl {
         if let Some(window) = self.downcast::<Window>() {
             // https://html.spec.whatwg.org/multipage/#script-settings-for-browsing-contexts:api-base-url
             return window.Document().base_url();
         }
         if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
             // https://html.spec.whatwg.org/multipage/#script-settings-for-workers:api-base-url
             return worker.get_url().clone();
         }
         unreachable!();
     }
 
     /// Get the URL for this global scope.
-    pub fn get_url(&self) -> Url {
+    pub fn get_url(&self) -> ServoUrl {
         if let Some(window) = self.downcast::<Window>() {
             return window.get_url();
         }
         if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
             return worker.get_url().clone();
         }
         unreachable!();
     }
--- a/servo/components/script/dom/htmlanchorelement.rs
+++ b/servo/components/script/dom/htmlanchorelement.rs
@@ -23,26 +23,26 @@ use dom::htmlimageelement::HTMLImageElem
 use dom::mouseevent::MouseEvent;
 use dom::node::{Node, document_from_node, window_from_node};
 use dom::urlhelper::UrlHelper;
 use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
 use net_traits::ReferrerPolicy;
 use num_traits::ToPrimitive;
 use script_traits::MozBrowserEvent;
+use servo_url::ServoUrl;
 use std::default::Default;
 use style::attr::AttrValue;
-use url::Url;
 use util::prefs::PREFS;
 
 #[dom_struct]
 pub struct HTMLAnchorElement {
     htmlelement: HTMLElement,
     rel_list: MutNullableHeap<JS<DOMTokenList>>,
-    url: DOMRefCell<Option<Url>>,
+    url: DOMRefCell<Option<ServoUrl>>,
 }
 
 impl HTMLAnchorElement {
     fn new_inherited(local_name: LocalName,
                      prefix: Option<DOMString>,
                      document: &Document) -> HTMLAnchorElement {
         HTMLAnchorElement {
             htmlelement:
--- a/servo/components/script/dom/htmlbaseelement.rs
+++ b/servo/components/script/dom/htmlbaseelement.rs
@@ -9,18 +9,18 @@ use dom::bindings::inheritance::Castable
 use dom::bindings::js::Root;
 use dom::bindings::str::DOMString;
 use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::htmlelement::HTMLElement;
 use dom::node::{Node, UnbindContext, document_from_node};
 use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
+use servo_url::ServoUrl;
 use style::attr::AttrValue;
-use url::Url;
 
 #[dom_struct]
 pub struct HTMLBaseElement {
     htmlelement: HTMLElement
 }
 
 impl HTMLBaseElement {
     fn new_inherited(local_name: LocalName, prefix: Option<DOMString>, document: &Document) -> HTMLBaseElement {
@@ -34,17 +34,17 @@ impl HTMLBaseElement {
                prefix: Option<DOMString>,
                document: &Document) -> Root<HTMLBaseElement> {
         Node::reflect_node(box HTMLBaseElement::new_inherited(local_name, prefix, document),
                            document,
                            HTMLBaseElementBinding::Wrap)
     }
 
     /// https://html.spec.whatwg.org/multipage/#frozen-base-url
-    pub fn frozen_base_url(&self) -> Url {
+    pub fn frozen_base_url(&self) -> ServoUrl {
         let href = self.upcast::<Element>().get_attribute(&ns!(), &local_name!("href"))
             .expect("The frozen base url is only defined for base elements \
                      that have a base url.");
         let document = document_from_node(self);
         let base = document.fallback_base_url();
         let parsed = base.join(&href.value());
         parsed.unwrap_or(base)
     }
--- a/servo/components/script/dom/htmlbodyelement.rs
+++ b/servo/components/script/dom/htmlbodyelement.rs
@@ -14,19 +14,19 @@ use dom::document::Document;
 use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::htmlelement::HTMLElement;
 use dom::node::{Node, document_from_node, window_from_node};
 use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
 use script_traits::ScriptMsg as ConstellationMsg;
+use servo_url::ServoUrl;
 use style::attr::AttrValue;
 use time;
-use url::Url;
 
 /// How long we should wait before performing the initial reflow after `<body>` is parsed, in
 /// nanoseconds.
 const INITIAL_REFLOW_DELAY: u64 = 200_000_000;
 
 #[dom_struct]
 pub struct HTMLBodyElement {
     htmlelement: HTMLElement,
@@ -80,17 +80,17 @@ impl HTMLBodyElementMethods for HTMLBody
 
     // https://html.spec.whatwg.org/multipage/#windoweventhandlers
     window_event_handlers!(ForwardToWindow);
 }
 
 pub trait HTMLBodyElementLayoutHelpers {
     fn get_background_color(&self) -> Option<RGBA>;
     fn get_color(&self) -> Option<RGBA>;
-    fn get_background(&self) -> Option<Url>;
+    fn get_background(&self) -> Option<ServoUrl>;
 }
 
 impl HTMLBodyElementLayoutHelpers for LayoutJS<HTMLBodyElement> {
     #[allow(unsafe_code)]
     fn get_background_color(&self) -> Option<RGBA> {
         unsafe {
             (*self.upcast::<Element>().unsafe_get())
                 .get_attr_for_layout(&ns!(), &local_name!("bgcolor"))
@@ -105,17 +105,17 @@ impl HTMLBodyElementLayoutHelpers for La
             (*self.upcast::<Element>().unsafe_get())
                 .get_attr_for_layout(&ns!(), &local_name!("text"))
                 .and_then(AttrValue::as_color)
                 .cloned()
         }
     }
 
     #[allow(unsafe_code)]
-    fn get_background(&self) -> Option<Url> {
+    fn get_background(&self) -> Option<ServoUrl> {
         unsafe {
             (*self.upcast::<Element>().unsafe_get())
                 .get_attr_for_layout(&ns!(), &local_name!("background"))
                 .and_then(AttrValue::as_url)
                 .cloned()
         }
     }
 }
--- a/servo/components/script/dom/htmlcanvaselement.rs
+++ b/servo/components/script/dom/htmlcanvaselement.rs
@@ -336,18 +336,18 @@ impl<'a> From<&'a WebGLContextAttributes
         }
     }
 }
 
 pub mod utils {
     use dom::window::Window;
     use ipc_channel::ipc;
     use net_traits::image_cache_thread::{ImageCacheChan, ImageResponse};
-    use url::Url;
+    use servo_url::ServoUrl;
 
-    pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
+    pub fn request_image_from_cache(window: &Window, url: ServoUrl) -> ImageResponse {
         let image_cache = window.image_cache_thread();
         let (response_chan, response_port) = ipc::channel().unwrap();
-        image_cache.request_image(url, ImageCacheChan(response_chan), None);
+        image_cache.request_image(url.into(), ImageCacheChan(response_chan), None);
         let result = response_port.recv().unwrap();
         result.image_response
     }
 }
--- a/servo/components/script/dom/htmlformelement.rs
+++ b/servo/components/script/dom/htmlformelement.rs
@@ -375,40 +375,44 @@ impl HTMLFormElement {
             _ => return,
         }
     }
 
     // https://html.spec.whatwg.org/multipage/#submit-mutate-action
     fn mutate_action_url(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, encoding: EncodingRef) {
         let charset = &*encoding.whatwg_name().unwrap();
 
-        load_data.url.query_pairs_mut().clear()
-                 .encoding_override(Some(self.pick_encoding()))
-                 .extend_pairs(form_data.into_iter()
-                                        .map(|field| (field.name.clone(), field.replace_value(charset))));
+        if let Some(ref mut url) = load_data.url.as_mut_url() {
+            url.query_pairs_mut().clear()
+               .encoding_override(Some(self.pick_encoding()))
+               .extend_pairs(form_data.into_iter()
+                                      .map(|field| (field.name.clone(), field.replace_value(charset))));
+        }
 
         self.plan_to_navigate(load_data);
     }
 
     // https://html.spec.whatwg.org/multipage/#submit-body
     fn submit_entity_body(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData,
                           enctype: FormEncType, encoding: EncodingRef) {
         let boundary = generate_boundary();
         let bytes = match enctype {
             FormEncType::UrlEncoded => {
-                let mut url = load_data.url.clone();
                 let charset = &*encoding.whatwg_name().unwrap();
                 load_data.headers.set(ContentType::form_url_encoded());
 
-                url.query_pairs_mut().clear()
-                   .encoding_override(Some(self.pick_encoding()))
-                   .extend_pairs(form_data.into_iter()
-                                          .map(|field| (field.name.clone(), field.replace_value(charset))));
 
-                url.query().unwrap_or("").to_string().into_bytes()
+                if let Some(ref mut url) = load_data.url.as_mut_url() {
+                    url.query_pairs_mut().clear()
+                       .encoding_override(Some(self.pick_encoding()))
+                       .extend_pairs(form_data.into_iter()
+                       .map(|field| (field.name.clone(), field.replace_value(charset))));
+                }
+
+                load_data.url.query().unwrap_or("").to_string().into_bytes()
             }
             FormEncType::FormDataEncoded => {
                 let mime = mime!(Multipart / FormData; Boundary =(&boundary));
                 load_data.headers.set(ContentType(mime));
                 encode_multipart_form_data(form_data, boundary, encoding)
             }
             FormEncType::TextPlainEncoded => {
                 load_data.headers.set(ContentType(mime!(Text / Plain)));
--- a/servo/components/script/dom/htmliframeelement.rs
+++ b/servo/components/script/dom/htmliframeelement.rs
@@ -41,20 +41,20 @@ use js::jsapi::{JSAutoCompartment, JSCon
 use js::jsval::{NullValue, UndefinedValue};
 use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection};
 use net_traits::response::HttpsState;
 use script_layout_interface::message::ReflowQueryType;
 use script_thread::ScriptThread;
 use script_traits::{IFrameLoadInfo, LoadData, MozBrowserEvent, ScriptMsg as ConstellationMsg};
 use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::cell::Cell;
 use style::attr::{AttrValue, LengthOrPercentageOrAuto};
 use style::context::ReflowGoal;
-use url::Url;
 use util::prefs::PREFS;
 use util::servo_version;
 
 bitflags! {
     #[derive(JSTraceable, HeapSizeOf)]
     flags SandboxAllowance: u8 {
         const ALLOW_NOTHING = 0x00,
         const ALLOW_SAME_ORIGIN = 0x01,
@@ -79,26 +79,26 @@ pub struct HTMLIFrameElement {
 
 impl HTMLIFrameElement {
     pub fn is_sandboxed(&self) -> bool {
         self.sandbox_allowance.get().is_some()
     }
 
     /// <https://html.spec.whatwg.org/multipage/#otherwise-steps-for-iframe-or-frame-elements>,
     /// step 1.
-    fn get_url(&self) -> Url {
+    fn get_url(&self) -> ServoUrl {
         let element = self.upcast::<Element>();
         element.get_attribute(&ns!(), &local_name!("src")).and_then(|src| {
             let url = src.value();
             if url.is_empty() {
                 None
             } else {
                 document_from_node(self).base_url().join(&url).ok()
             }
-        }).unwrap_or_else(|| Url::parse("about:blank").unwrap())
+        }).unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap())
     }
 
     pub fn generate_new_pipeline_id(&self) -> (Option<PipelineId>, PipelineId) {
         let old_pipeline_id = self.pipeline_id.get();
         let new_pipeline_id = PipelineId::new();
         self.pipeline_id.set(Some(new_pipeline_id));
         (old_pipeline_id, new_pipeline_id)
     }
--- a/servo/components/script/dom/htmlimageelement.rs
+++ b/servo/components/script/dom/htmlimageelement.rs
@@ -22,48 +22,48 @@ use dom::node::{Node, NodeDamage, docume
 use dom::values::UNSIGNED_LONG_MAX;
 use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
 use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use net_traits::image::base::{Image, ImageMetadata};
 use net_traits::image_cache_thread::{ImageResponder, ImageResponse};
 use script_thread::Runnable;
+use servo_url::ServoUrl;
 use std::i32;
 use std::sync::Arc;
 use style::attr::{AttrValue, LengthOrPercentageOrAuto};
 use task_source::TaskSource;
-use url::Url;
 
 #[derive(JSTraceable, HeapSizeOf)]
 #[allow(dead_code)]
 enum State {
     Unavailable,
     PartiallyAvailable,
     CompletelyAvailable,
     Broken,
 }
 #[derive(JSTraceable, HeapSizeOf)]
 struct ImageRequest {
     state: State,
-    parsed_url: Option<Url>,
+    parsed_url: Option<ServoUrl>,
     source_url: Option<DOMString>,
     #[ignore_heap_size_of = "Arc"]
     image: Option<Arc<Image>>,
     metadata: Option<ImageMetadata>,
 }
 #[dom_struct]
 pub struct HTMLImageElement {
     htmlelement: HTMLElement,
     current_request: DOMRefCell<ImageRequest>,
     pending_request: DOMRefCell<ImageRequest>,
 }
 
 impl HTMLImageElement {
-    pub fn get_url(&self) -> Option<Url> {
+    pub fn get_url(&self) -> Option<ServoUrl> {
         self.current_request.borrow().parsed_url.clone()
     }
 }
 
 
 struct ImageResponseHandlerRunnable {
     element: Trusted<HTMLImageElement>,
     image: ImageResponse,
@@ -115,17 +115,17 @@ impl Runnable for ImageResponseHandlerRu
         let window = window_from_node(&*document);
         window.add_pending_reflow();
     }
 }
 
 impl 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)>) {
+    fn update_image(&self, value: Option<(DOMString, ServoUrl)>) {
         let document = document_from_node(self);
         let window = document.window();
         let image_cache = window.image_cache_thread();
         match value {
             None => {
                 self.current_request.borrow_mut().parsed_url = None;
                 self.current_request.borrow_mut().source_url = None;
                 self.current_request.borrow_mut().image = None;
@@ -144,17 +144,17 @@ impl HTMLImageElement {
                         // Return the image via a message to the script thread, which marks the element
                         // as dirty and triggers a reflow.
                         let image_response = message.to().unwrap();
                         let runnable = box ImageResponseHandlerRunnable::new(
                             trusted_node.clone(), image_response);
                         let _ = task_source.queue_with_wrapper(runnable, &wrapper);
                     });
 
-                    image_cache.request_image_and_metadata(img_url,
+                    image_cache.request_image_and_metadata(img_url.into(),
                                               window.image_cache_chan(),
                                               Some(ImageResponder::new(responder_sender)));
                 } else {
                     // https://html.spec.whatwg.org/multipage/#update-the-image-data
                     // Step 11 (error substeps)
                     debug!("Failed to parse URL {} with base {}", src, base_url);
                     let mut req = self.current_request.borrow_mut();
 
@@ -236,30 +236,30 @@ impl HTMLImageElement {
     }
 }
 
 pub trait LayoutHTMLImageElementHelpers {
     #[allow(unsafe_code)]
     unsafe fn image(&self) -> Option<Arc<Image>>;
 
     #[allow(unsafe_code)]
-    unsafe fn image_url(&self) -> Option<Url>;
+    unsafe fn image_url(&self) -> Option<ServoUrl>;
 
     fn get_width(&self) -> LengthOrPercentageOrAuto;
     fn get_height(&self) -> LengthOrPercentageOrAuto;
 }
 
 impl LayoutHTMLImageElementHelpers for LayoutJS<HTMLImageElement> {
     #[allow(unsafe_code)]
     unsafe fn image(&self) -> Option<Arc<Image>> {
         (*self.unsafe_get()).current_request.borrow_for_layout().image.clone()
     }
 
     #[allow(unsafe_code)]
-    unsafe fn image_url(&self) -> Option<Url> {
+    unsafe fn image_url(&self) -> Option<ServoUrl> {
         (*self.unsafe_get()).current_request.borrow_for_layout().parsed_url.clone()
     }
 
     #[allow(unsafe_code)]
     fn get_width(&self) -> LengthOrPercentageOrAuto {
         unsafe {
             (*self.upcast::<Element>().unsafe_get())
                 .get_attr_for_layout(&ns!(), &local_name!("width"))
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -31,28 +31,28 @@ use hyper::mime::{Mime, TopLevel, SubLev
 use hyper_serde::Serde;
 use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError, ReferrerPolicy};
 use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
 use network_listener::{NetworkListener, PreInvoke};
 use script_layout_interface::message::Msg;
 use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::default::Default;
 use std::mem;
 use std::sync::{Arc, Mutex};
 use style::attr::AttrValue;
 use style::media_queries::{MediaList, parse_media_query_list};
 use style::parser::ParserContextExtraData;
 use style::str::HTML_SPACE_CHARACTERS;
 use style::stylesheets::{Stylesheet, Origin};
-use url::Url;
 
 no_jsmanaged_fields!(Stylesheet);
 
 #[dom_struct]
 pub struct HTMLLinkElement {
     htmlelement: HTMLElement,
     rel_list: MutNullableHeap<JS<DOMTokenList>>,
     #[ignore_heap_size_of = "Arc"]
@@ -313,17 +313,17 @@ struct StylesheetContext {
     /// The element that initiated the request.
     elem: Trusted<HTMLLinkElement>,
     media: Option<MediaList>,
     /// The response body received to date.
     data: Vec<u8>,
     /// The response metadata received to date.
     metadata: Option<Metadata>,
     /// The initial URL requested.
-    url: Url,
+    url: ServoUrl,
 }
 
 impl PreInvoke for StylesheetContext {}
 
 impl FetchResponseListener for StylesheetContext {
     fn process_request_body(&mut self) {}
 
     fn process_request_eof(&mut self) {}
--- a/servo/components/script/dom/htmlmediaelement.rs
+++ b/servo/components/script/dom/htmlmediaelement.rs
@@ -30,35 +30,35 @@ use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
 use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError};
 use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
 use network_listener::{NetworkListener, PreInvoke};
 use script_thread::{Runnable, ScriptThread};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::cell::Cell;
 use std::sync::{Arc, Mutex};
 use task_source::TaskSource;
 use time::{self, Timespec, Duration};
-use url::Url;
 
 struct HTMLMediaElementContext {
     /// The element that initiated the request.
     elem: Trusted<HTMLMediaElement>,
     /// The response body received to date.
     data: Vec<u8>,
     /// The response metadata received to date.
     metadata: Option<Metadata>,
     /// The generation of the media element when this fetch started.
     generation_id: u32,
     /// Time of last progress notification.
     next_progress_event: Timespec,
     /// Url of resource requested.
-    url: Url,
+    url: ServoUrl,
     /// Whether the media metadata has been completely received.
     have_metadata: bool,
     /// True if this response is invalid and should be ignored.
     ignore_response: bool,
 }
 
 impl FetchResponseListener for HTMLMediaElementContext {
     fn process_request_body(&mut self) {}
@@ -159,17 +159,17 @@ impl FetchResponseListener for HTMLMedia
 impl PreInvoke for HTMLMediaElementContext {
     fn should_invoke(&self) -> bool {
         //TODO: finish_load needs to run at some point if the generation changes.
         self.elem.root().generation_id.get() == self.generation_id
     }
 }
 
 impl HTMLMediaElementContext {
-    fn new(elem: &HTMLMediaElement, url: Url) -> HTMLMediaElementContext {
+    fn new(elem: &HTMLMediaElement, url: ServoUrl) -> HTMLMediaElementContext {
         HTMLMediaElementContext {
             elem: Trusted::new(elem),
             data: vec![],
             metadata: None,
             generation_id: elem.generation_id.get(),
             next_progress_event: time::get_time() + Duration::milliseconds(350),
             url: url,
             have_metadata: false,
@@ -432,17 +432,17 @@ impl HTMLMediaElement {
         // TODO step 3 (delay load event)
 
         // Step 4
         let doc = document_from_node(self);
         ScriptThread::await_stable_state(ResourceSelectionTask::new(self, doc.base_url()));
     }
 
     // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
-    fn resource_selection_algorithm_sync(&self, base_url: Url) {
+    fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) {
         // TODO step 5 (populate pending text tracks)
 
         // Step 6
         let mode = if false {
             // TODO media provider object
             ResourceSelectionMode::Object
         } else if let Some(attr) = self.upcast::<Element>().get_attribute(&ns!(), &local_name!("src")) {
             ResourceSelectionMode::Attribute(attr.Value().to_string())
@@ -809,21 +809,21 @@ impl Runnable for FireSimpleEventTask {
     fn handler(self: Box<FireSimpleEventTask>) {
         let elem = self.elem.root();
         elem.fire_simple_event(self.type_);
     }
 }
 
 struct ResourceSelectionTask {
     elem: Trusted<HTMLMediaElement>,
-    base_url: Url,
+    base_url: ServoUrl,
 }
 
 impl ResourceSelectionTask {
-    fn new(elem: &HTMLMediaElement, url: Url) -> ResourceSelectionTask {
+    fn new(elem: &HTMLMediaElement, url: ServoUrl) -> ResourceSelectionTask {
         ResourceSelectionTask {
             elem: Trusted::new(elem),
             base_url: url,
         }
     }
 }
 
 impl Runnable for ResourceSelectionTask {
@@ -880,10 +880,10 @@ impl Runnable for PauseIfNotInDocumentTa
 enum ResourceSelectionMode {
     Object,
     Attribute(String),
     Children(Root<HTMLSourceElement>),
 }
 
 enum Resource {
     Object,
-    Url(Url),
+    Url(ServoUrl),
 }
--- a/servo/components/script/dom/htmlscriptelement.rs
+++ b/servo/components/script/dom/htmlscriptelement.rs
@@ -30,21 +30,21 @@ use encoding::types::{DecoderTrap, Encod
 use html5ever_atoms::LocalName;
 use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use js::jsval::UndefinedValue;
 use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
 use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType};
 use network_listener::{NetworkListener, PreInvoke};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::cell::Cell;
 use std::sync::{Arc, Mutex};
 use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec};
-use url::Url;
 
 #[dom_struct]
 pub struct HTMLScriptElement {
     htmlelement: HTMLElement,
 
     /// https://html.spec.whatwg.org/multipage/#already-started
     already_started: Cell<bool>,
 
@@ -110,30 +110,30 @@ static SCRIPT_JS_MIMES: StaticStringVec 
     "text/livescript",
     "text/x-ecmascript",
     "text/x-javascript",
 ];
 
 #[derive(HeapSizeOf, JSTraceable)]
 pub struct ScriptOrigin {
     text: DOMString,
-    url: Url,
+    url: ServoUrl,
     external: bool,
 }
 
 impl ScriptOrigin {
-    fn internal(text: DOMString, url: Url) -> ScriptOrigin {
+    fn internal(text: DOMString, url: ServoUrl) -> ScriptOrigin {
         ScriptOrigin {
             text: text,
             url: url,
             external: false,
         }
     }
 
-    fn external(text: DOMString, url: Url) -> ScriptOrigin {
+    fn external(text: DOMString, url: ServoUrl) -> ScriptOrigin {
         ScriptOrigin {
             text: text,
             url: url,
             external: true,
         }
     }
 }
 
@@ -144,17 +144,17 @@ struct ScriptContext {
     /// The (fallback) character encoding argument to the "fetch a classic
     /// script" algorithm.
     character_encoding: EncodingRef,
     /// The response body received to date.
     data: Vec<u8>,
     /// The response metadata received to date.
     metadata: Option<Metadata>,
     /// The initial URL requested.
-    url: Url,
+    url: ServoUrl,
     /// Indicates whether the request failed, and why
     status: Result<(), NetworkError>
 }
 
 impl FetchResponseListener for ScriptContext {
     fn process_request_body(&mut self) {} // TODO(KiChjang): Perhaps add custom steps to perform fetch here?
 
     fn process_request_eof(&mut self) {} // TODO(KiChjang): Perhaps add custom steps to perform fetch here?
@@ -214,17 +214,17 @@ impl FetchResponseListener for ScriptCon
         document.finish_load(LoadType::Script(self.url.clone()));
     }
 }
 
 impl PreInvoke for ScriptContext {}
 
 /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script
 fn fetch_a_classic_script(script: &HTMLScriptElement,
-                          url: Url,
+                          url: ServoUrl,
                           cors_setting: Option<CorsSettings>,
                           character_encoding: EncodingRef) {
     let doc = document_from_node(script);
 
     // Step 1, 2.
     let request = RequestInit {
         url: url.clone(),
         type_: RequestType::Script,
--- a/servo/components/script/dom/location.rs
+++ b/servo/components/script/dom/location.rs
@@ -5,17 +5,17 @@
 use dom::bindings::codegen::Bindings::LocationBinding;
 use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
 use dom::bindings::error::{Error, ErrorResult};
 use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::{Reflector, reflect_dom_object};
 use dom::bindings::str::{DOMString, USVString};
 use dom::urlhelper::UrlHelper;
 use dom::window::Window;
-use url::Url;
+use servo_url::ServoUrl;
 
 #[dom_struct]
 pub struct Location {
     reflector_: Reflector,
     window: JS<Window>,
 }
 
 impl Location {
@@ -27,22 +27,22 @@ impl Location {
     }
 
     pub fn new(window: &Window) -> Root<Location> {
         reflect_dom_object(box Location::new_inherited(window),
                            window,
                            LocationBinding::Wrap)
     }
 
-    fn get_url(&self) -> Url {
+    fn get_url(&self) -> ServoUrl {
         self.window.get_url()
     }
 
     fn set_url_component(&self, value: USVString,
-                         setter: fn(&mut Url, USVString)) {
+                         setter: fn(&mut ServoUrl, USVString)) {
         let mut url = self.window.get_url();
         setter(&mut url, value);
         self.window.load_url(url, false, None);
     }
 }
 
 impl LocationMethods for Location {
     // https://html.spec.whatwg.org/multipage/#dom-location-assign
--- a/servo/components/script/dom/node.rs
+++ b/servo/components/script/dom/node.rs
@@ -68,29 +68,29 @@ use msg::constellation_msg::PipelineId;
 use ref_slice::ref_slice;
 use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
 use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
 use script_layout_interface::message::Msg;
 use script_traits::UntrustedNodeAddress;
 use selectors::matching::{MatchingReason, matches};
 use selectors::parser::Selector;
 use selectors::parser::parse_author_origin_selector_list_from_str;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::cell::{Cell, UnsafeCell};
 use std::cmp::max;
 use std::default::Default;
 use std::iter;
 use std::mem;
 use std::ops::Range;
 use std::sync::Arc;
 use style::dom::OpaqueNode;
 use style::selector_impl::ServoSelectorImpl;
 use style::stylesheets::Stylesheet;
 use style::thread_state;
-use url::Url;
 use uuid::Uuid;
 
 //
 // The basic Node structure
 //
 
 /// An HTML node.
 #[dom_struct]
@@ -963,17 +963,17 @@ pub trait LayoutNodeHelpers {
     unsafe fn children_count(&self) -> u32;
 
     unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
     unsafe fn init_style_and_layout_data(&self, OpaqueStyleAndLayoutData);
     unsafe fn take_style_and_layout_data(&self) -> OpaqueStyleAndLayoutData;
 
     fn text_content(&self) -> String;
     fn selection(&self) -> Option<Range<usize>>;
-    fn image_url(&self) -> Option<Url>;
+    fn image_url(&self) -> Option<ServoUrl>;
     fn canvas_data(&self) -> Option<HTMLCanvasData>;
     fn svg_data(&self) -> Option<SVGSVGData>;
     fn iframe_pipeline_id(&self) -> PipelineId;
     fn opaque(&self) -> OpaqueNode;
 }
 
 impl LayoutNodeHelpers for LayoutJS<Node> {
     #[inline]
@@ -1098,17 +1098,17 @@ impl LayoutNodeHelpers for LayoutJS<Node
         if let Some(input) = self.downcast::<HTMLInputElement>() {
             return unsafe { input.selection_for_layout() };
         }
 
         None
     }
 
     #[allow(unsafe_code)]
-    fn image_url(&self) -> Option<Url> {
+    fn image_url(&self) -> Option<ServoUrl> {
         unsafe {
             self.downcast::<HTMLImageElement>()
                 .expect("not an image!")
                 .image_url()
         }
     }
 
     fn canvas_data(&self) -> Option<HTMLCanvasData> {
--- a/servo/components/script/dom/request.rs
+++ b/servo/components/script/dom/request.rs
@@ -30,51 +30,51 @@ use net_traits::request::{Origin, Window
 use net_traits::request::CacheMode as NetTraitsRequestCache;
 use net_traits::request::CredentialsMode as NetTraitsRequestCredentials;
 use net_traits::request::Destination as NetTraitsRequestDestination;
 use net_traits::request::RedirectMode as NetTraitsRequestRedirect;
 use net_traits::request::Referrer as NetTraitsRequestReferrer;
 use net_traits::request::Request as NetTraitsRequest;
 use net_traits::request::RequestMode as NetTraitsRequestMode;
 use net_traits::request::Type as NetTraitsRequestType;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::cell::{Cell, Ref};
 use std::rc::Rc;
-use url::Url;
 
 #[dom_struct]
 pub struct Request {
     reflector_: Reflector,
     request: DOMRefCell<NetTraitsRequest>,
     body_used: Cell<bool>,
     headers: MutNullableHeap<JS<Headers>>,
     mime_type: DOMRefCell<Vec<u8>>,
     #[ignore_heap_size_of = "Rc"]
     body_promise: DOMRefCell<Option<(Rc<Promise>, BodyType)>>,
 }
 
 impl Request {
     fn new_inherited(global: &GlobalScope,
-                     url: Url,
+                     url: ServoUrl,
                      is_service_worker_global_scope: bool) -> Request {
         Request {
             reflector_: Reflector::new(),
             request: DOMRefCell::new(
                 net_request_from_global(global,
                                         url,
                                         is_service_worker_global_scope)),
             body_used: Cell::new(false),
             headers: Default::default(),
             mime_type: DOMRefCell::new("".to_string().into_bytes()),
             body_promise: DOMRefCell::new(None),
         }
     }
 
     pub fn new(global: &GlobalScope,
-               url: Url,
+               url: ServoUrl,
                is_service_worker_global_scope: bool) -> Root<Request> {
         reflect_dom_object(box Request::new_inherited(global,
                                                       url,
                                                       is_service_worker_global_scope),
                            global, RequestBinding::Wrap)
     }
 
     // https://fetch.spec.whatwg.org/#dom-request
@@ -463,17 +463,17 @@ impl Request {
     }
 
     pub fn get_request(&self) -> NetTraitsRequest {
         self.request.borrow().clone()
     }
 }
 
 fn net_request_from_global(global: &GlobalScope,
-                           url: Url,
+                           url: ServoUrl,
                            is_service_worker_global_scope: bool) -> NetTraitsRequest {
     let origin = Origin::Origin(global.get_url().origin());
     let pipeline_id = global.pipeline_id();
     NetTraitsRequest::new(url,
                           Some(origin),
                           is_service_worker_global_scope,
                           Some(pipeline_id))
 }
@@ -519,17 +519,17 @@ fn is_forbidden_method(m: &ByteString) -
 // https://fetch.spec.whatwg.org/#cors-safelisted-method
 fn is_cors_safelisted_method(m: &HttpMethod) -> bool {
     m == &HttpMethod::Get ||
         m == &HttpMethod::Head ||
         m == &HttpMethod::Post
 }
 
 // https://url.spec.whatwg.org/#include-credentials
-fn includes_credentials(input: &Url) -> bool {
+fn includes_credentials(input: &ServoUrl) -> bool {
     !input.username().is_empty() || input.password().is_some()
 }
 
 // TODO: `Readable Stream` object is not implemented in Servo yet.
 // https://fetch.spec.whatwg.org/#concept-body-disturbed
 fn request_is_disturbed(_input: &Request) -> bool {
     false
 }
--- a/servo/components/script/dom/response.rs
+++ b/servo/components/script/dom/response.rs
@@ -17,36 +17,36 @@ use dom::globalscope::GlobalScope;
 use dom::headers::{Headers, Guard};
 use dom::headers::{is_vchar, is_obs_text};
 use dom::promise::Promise;
 use dom::xmlhttprequest::Extractable;
 use hyper::header::Headers as HyperHeaders;
 use hyper::status::StatusCode;
 use hyper_serde::Serde;
 use net_traits::response::{ResponseBody as NetTraitsResponseBody};
+use servo_url::ServoUrl;
 use std::cell::Ref;
 use std::mem;
 use std::rc::Rc;
 use std::str::FromStr;
 use url::Position;
-use url::Url;
 
 #[dom_struct]
 pub struct Response {
     reflector_: Reflector,
     headers_reflector: MutNullableHeap<JS<Headers>>,
     mime_type: DOMRefCell<Vec<u8>>,
     body_used: Cell<bool>,
     /// `None` can be considered a StatusCode of `0`.
     #[ignore_heap_size_of = "Defined in hyper"]
     status: DOMRefCell<Option<StatusCode>>,
     raw_status: DOMRefCell<Option<(u16, Vec<u8>)>>,
     response_type: DOMRefCell<DOMResponseType>,
-    url: DOMRefCell<Option<Url>>,
-    url_list: DOMRefCell<Vec<Url>>,
+    url: DOMRefCell<Option<ServoUrl>>,
+    url_list: DOMRefCell<Vec<ServoUrl>>,
     // For now use the existing NetTraitsResponseBody enum
     body: DOMRefCell<NetTraitsResponseBody>,
     #[ignore_heap_size_of = "Rc"]
     body_promise: DOMRefCell<Option<(Rc<Promise>, BodyType)>>,
 }
 
 impl Response {
     pub fn new_inherited() -> Response {
@@ -151,17 +151,17 @@ impl Response {
         // Step 1
         // TODO: `entry settings object` is not implemented in Servo yet.
         let base_url = global.get_url();
         let parsed_url = base_url.join(&url.0);
 
         // Step 2
         let url = match parsed_url {
             Ok(url) => url,
-            Err(_) => return Err(Error::Type("Url could not be parsed".to_string())),
+            Err(_) => return Err(Error::Type("ServoUrl could not be parsed".to_string())),
         };
 
         // Step 3
         if !is_redirect_status(status) {
             return Err(Error::Range("status is not a redirect status".to_string()));
         }
 
         // Step 4
@@ -352,18 +352,18 @@ impl ResponseMethods for Response {
 
     #[allow(unrooted_must_root)]
     // https://fetch.spec.whatwg.org/#dom-body-json
     fn Json(&self) -> Rc<Promise> {
         consume_body(self, BodyType::Json)
     }
 }
 
-fn serialize_without_fragment(url: &Url) -> &str {
-    &url[..Position::AfterQuery]
+fn serialize_without_fragment(url: &ServoUrl) -> &str {
+    &url.as_url().unwrap()[..Position::AfterQuery]
 }
 
 impl Response {
     pub fn set_type(&self, new_response_type: DOMResponseType) {
         *self.response_type.borrow_mut() = new_response_type;
     }
 
     pub fn set_headers(&self, option_hyper_headers: Option<Serde<HyperHeaders>>) {
@@ -372,17 +372,17 @@ impl Response {
             None => HyperHeaders::new(),
         });
     }
 
     pub fn set_raw_status(&self, status: Option<(u16, Vec<u8>)>) {
         *self.raw_status.borrow_mut() = status;
     }
 
-    pub fn set_final_url(&self, final_url: Url) {
+    pub fn set_final_url(&self, final_url: ServoUrl) {
         *self.url.borrow_mut() = Some(final_url);
     }
 
     #[allow(unrooted_must_root)]
     pub fn finish(&self, body: Vec<u8>) {
         *self.body.borrow_mut() = NetTraitsResponseBody::Done(body);
         if let Some((p, body_type)) = self.body_promise.borrow_mut().take() {
             consume_body_with_promise(self, body_type, &p);
--- a/servo/components/script/dom/serviceworker.rs
+++ b/servo/components/script/dom/serviceworker.rs
@@ -13,64 +13,64 @@ use dom::bindings::refcounted::Trusted;
 use dom::bindings::reflector::{Reflectable, reflect_dom_object};
 use dom::bindings::str::USVString;
 use dom::bindings::structuredclone::StructuredCloneData;
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use js::jsapi::{HandleValue, JSContext};
 use script_thread::Runnable;
 use script_traits::{ScriptMsg, DOMMessage};
+use servo_url::ServoUrl;
 use std::cell::Cell;
-use url::Url;
 
 pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
 
 #[dom_struct]
 pub struct ServiceWorker {
     eventtarget: EventTarget,
     script_url: DOMRefCell<String>,
-    scope_url: Url,
+    scope_url: ServoUrl,
     state: Cell<ServiceWorkerState>,
     skip_waiting: Cell<bool>
 }
 
 impl ServiceWorker {
     fn new_inherited(script_url: &str,
                      skip_waiting: bool,
-                     scope_url: Url) -> ServiceWorker {
+                     scope_url: ServoUrl) -> ServiceWorker {
         ServiceWorker {
             eventtarget: EventTarget::new_inherited(),
             script_url: DOMRefCell::new(String::from(script_url)),
             state: Cell::new(ServiceWorkerState::Installing),
             scope_url: scope_url,
             skip_waiting: Cell::new(skip_waiting)
         }
     }
 
     pub fn install_serviceworker(global: &GlobalScope,
-                script_url: Url,
-                scope_url: Url,
+                script_url: ServoUrl,
+                scope_url: ServoUrl,
                 skip_waiting: bool) -> Root<ServiceWorker> {
         reflect_dom_object(box ServiceWorker::new_inherited(script_url.as_str(),
                                                             skip_waiting,
                                                             scope_url), global, Wrap)
     }
 
     pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) {
         let service_worker = address.root();
         service_worker.upcast().fire_event(atom!("error"));
     }
 
     pub fn set_transition_state(&self, state: ServiceWorkerState) {
         self.state.set(state);
         self.upcast::<EventTarget>().fire_event(atom!("statechange"));
     }
 
-    pub fn get_script_url(&self) -> Url {
-        Url::parse(&self.script_url.borrow().clone()).unwrap()
+    pub fn get_script_url(&self) -> ServoUrl {
+        ServoUrl::parse(&self.script_url.borrow().clone()).unwrap()
     }
 }
 
 impl ServiceWorkerMethods for ServiceWorker {
     // https://w3c.github.io/ServiceWorker/#service-worker-state-attribute
     fn State(&self) -> ServiceWorkerState {
         self.state.get()
     }
--- a/servo/components/script/dom/serviceworkerglobalscope.rs
+++ b/servo/components/script/dom/serviceworkerglobalscope.rs
@@ -23,21 +23,21 @@ use ipc_channel::router::ROUTER;
 use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext};
 use js::jsval::UndefinedValue;
 use js::rust::Runtime;
 use net_traits::{load_whole_resource, IpcSend, CustomResponseMediator};
 use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
 use rand::random;
 use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan};
 use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg, WorkerScriptLoadOrigin};
+use servo_url::ServoUrl;
 use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
 use std::thread;
 use std::time::Duration;
 use style::thread_state::{self, IN_WORKER, SCRIPT};
-use url::Url;
 use util::prefs::PREFS;
 use util::thread::spawn_named;
 
 /// Messages used to control service worker event loop
 pub enum ServiceWorkerScriptMsg {
     /// Message common to all workers
     CommonWorker(WorkerScriptMsg),
     // Message to request a custom response by the service worker
@@ -75,30 +75,30 @@ pub struct ServiceWorkerGlobalScope {
     #[ignore_heap_size_of = "Defined in std"]
     receiver: Receiver<ServiceWorkerScriptMsg>,
     #[ignore_heap_size_of = "Defined in std"]
     own_sender: Sender<ServiceWorkerScriptMsg>,
     #[ignore_heap_size_of = "Defined in std"]
     timer_event_port: Receiver<()>,
     #[ignore_heap_size_of = "Defined in std"]
     swmanager_sender: IpcSender<ServiceWorkerMsg>,
-    scope_url: Url,
+    scope_url: ServoUrl,
 }
 
 impl ServiceWorkerGlobalScope {
     fn new_inherited(init: WorkerGlobalScopeInit,
-                     worker_url: Url,
+                     worker_url: ServoUrl,
                      from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
                      runtime: Runtime,
                      own_sender: Sender<ServiceWorkerScriptMsg>,
                      receiver: Receiver<ServiceWorkerScriptMsg>,
                      timer_event_chan: IpcSender<TimerEvent>,
                      timer_event_port: Receiver<()>,
                      swmanager_sender: IpcSender<ServiceWorkerMsg>,
-                     scope_url: Url)
+                     scope_url: ServoUrl)
                      -> ServiceWorkerGlobalScope {
         ServiceWorkerGlobalScope {
             workerglobalscope: WorkerGlobalScope::new_inherited(init,
                                                                 worker_url,
                                                                 runtime,
                                                                 from_devtools_receiver,
                                                                 timer_event_chan,
                                                                 None),
@@ -107,25 +107,25 @@ impl ServiceWorkerGlobalScope {
             own_sender: own_sender,
             swmanager_sender: swmanager_sender,
             scope_url: scope_url
         }
     }
 
     #[allow(unsafe_code)]
     pub fn new(init: WorkerGlobalScopeInit,
-               worker_url: Url,
+               worker_url: ServoUrl,
                from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
                runtime: Runtime,
                own_sender: Sender<ServiceWorkerScriptMsg>,
                receiver: Receiver<ServiceWorkerScriptMsg>,
                timer_event_chan: IpcSender<TimerEvent>,
                timer_event_port: Receiver<()>,
                swmanager_sender: IpcSender<ServiceWorkerMsg>,
-               scope_url: Url)
+               scope_url: ServoUrl)
                -> Root<ServiceWorkerGlobalScope> {
         let cx = runtime.cx();
         let scope = box ServiceWorkerGlobalScope::new_inherited(init,
                                                                   worker_url,
                                                                   from_devtools_receiver,
                                                                   runtime,
                                                                   own_sender,
                                                                   receiver,
@@ -139,17 +139,17 @@ impl ServiceWorkerGlobalScope {
     }
 
     #[allow(unsafe_code)]
     pub fn run_serviceworker_scope(scope_things: ScopeThings,
                             own_sender: Sender<ServiceWorkerScriptMsg>,
                             receiver: Receiver<ServiceWorkerScriptMsg>,
                             devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
                             swmanager_sender: IpcSender<ServiceWorkerMsg>,
-                            scope_url: Url) {
+                            scope_url: ServoUrl) {
         let ScopeThings { script_url,
                           init,
                           worker_load_origin,
                           .. } = scope_things;
 
         let serialized_worker_url = script_url.to_string();
         spawn_named(format!("ServiceWorker for {}", serialized_worker_url), move || {
             thread_state::initialize(SCRIPT | IN_WORKER);
--- a/servo/components/script/dom/serviceworkerregistration.rs
+++ b/servo/components/script/dom/serviceworkerregistration.rs
@@ -8,53 +8,53 @@ use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::USVString;
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::serviceworker::ServiceWorker;
 use dom::serviceworkercontainer::Controllable;
 use dom::workerglobalscope::prepare_workerscope_init;
 use script_traits::{WorkerScriptLoadOrigin, ScopeThings};
-use url::Url;
+use servo_url::ServoUrl;
 
 #[dom_struct]
 pub struct ServiceWorkerRegistration {
     eventtarget: EventTarget,
     active: Option<JS<ServiceWorker>>,
     installing: Option<JS<ServiceWorker>>,
     waiting: Option<JS<ServiceWorker>>,
     scope: String
 }
 
 impl ServiceWorkerRegistration {
-    fn new_inherited(active_sw: &ServiceWorker, scope: Url) -> ServiceWorkerRegistration {
+    fn new_inherited(active_sw: &ServiceWorker, scope: ServoUrl) -> ServiceWorkerRegistration {
         ServiceWorkerRegistration {
             eventtarget: EventTarget::new_inherited(),
             active: Some(JS::from_ref(active_sw)),
             installing: None,
             waiting: None,
             scope: scope.as_str().to_owned(),
         }
     }
     #[allow(unrooted_must_root)]
     pub fn new(global: &GlobalScope,
-               script_url: Url,
-               scope: Url,
+               script_url: ServoUrl,
+               scope: ServoUrl,
                container: &Controllable) -> Root<ServiceWorkerRegistration> {
         let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), scope.clone(), true);
         active_worker.set_transition_state(ServiceWorkerState::Installed);
         container.set_controller(&*active_worker.clone());
         reflect_dom_object(box ServiceWorkerRegistration::new_inherited(&*active_worker, scope), global, Wrap)
     }
 
     pub fn get_installed(&self) -> &ServiceWorker {
         self.active.as_ref().unwrap()
     }
 
-    pub fn create_scope_things(global: &GlobalScope, script_url: Url) -> ScopeThings {
+    pub fn create_scope_things(global: &GlobalScope, script_url: ServoUrl) -> ScopeThings {
         let worker_load_origin = WorkerScriptLoadOrigin {
             referrer_url: None,
             referrer_policy: None,
             pipeline_id: Some(global.pipeline_id())
         };
 
         let worker_id = global.get_next_worker_id();
         let devtools_chan = global.devtools_chan().cloned();
@@ -64,17 +64,17 @@ impl ServiceWorkerRegistration {
             init: init,
             worker_load_origin: worker_load_origin,
             devtools_chan: devtools_chan,
             worker_id: worker_id
         }
     }
 }
 
-pub fn longest_prefix_match(stored_scope: &Url, potential_match: &Url) -> bool {
+pub fn longest_prefix_match(stored_scope: &ServoUrl, potential_match: &ServoUrl) -> bool {
     if stored_scope.origin() != potential_match.origin() {
         return false;
     }
     let scope_chars = stored_scope.path().chars();
     let matching_chars = potential_match.path().chars();
     if scope_chars.count() > matching_chars.count() {
         return false;
     }
--- a/servo/components/script/dom/servoparser/html.rs
+++ b/servo/components/script/dom/servoparser/html.rs
@@ -26,34 +26,34 @@ use html5ever::serialize::TraversalScope
 use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
 use html5ever::tendril::StrTendril;
 use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts, TokenizerResult};
 use html5ever::tokenizer::buffer_queue::BufferQueue;
 use html5ever::tree_builder::{NodeOrText, QuirksMode};
 use html5ever::tree_builder::{Tracer as HtmlTracer, TreeBuilder, TreeBuilderOpts, TreeSink};
 use html5ever_atoms::QualName;
 use js::jsapi::JSTracer;
+use servo_url::ServoUrl;
 use std::borrow::Cow;
 use std::io::{self, Write};
 use super::{FragmentContext, Sink};
-use url::Url;
 
 #[derive(HeapSizeOf, JSTraceable)]
 #[must_root]
 pub struct Tokenizer {
     #[ignore_heap_size_of = "Defined in html5ever"]
     inner: HtmlTokenizer<TreeBuilder<JS<Node>, Sink>>,
     #[ignore_heap_size_of = "Defined in html5ever"]
     input_buffer: BufferQueue,
 }
 
 impl Tokenizer {
     pub fn new(
             document: &Document,
-            url: Url,
+            url: ServoUrl,
             fragment_context: Option<FragmentContext>)
             -> Self {
         let sink = Sink {
             base_url: url,
             document: JS::from_ref(document),
         };
 
         let options = TreeBuilderOpts {
--- a/servo/components/script/dom/servoparser/mod.rs
+++ b/servo/components/script/dom/servoparser/mod.rs
@@ -24,19 +24,19 @@ use hyper::header::ContentType;
 use hyper::mime::{Mime, SubLevel, TopLevel};
 use hyper_serde::Serde;
 use msg::constellation_msg::PipelineId;
 use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
 use network_listener::PreInvoke;
 use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
 use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
 use script_thread::ScriptThread;
+use servo_url::ServoUrl;
 use std::cell::Cell;
 use std::collections::VecDeque;
-use url::Url;
 use util::resource_files::read_resource_file;
 
 mod html;
 mod xml;
 
 #[dom_struct]
 pub struct ServoParser {
     reflector: Reflector,
@@ -60,17 +60,17 @@ enum LastChunkState {
     Received,
     NotReceived,
 }
 
 impl ServoParser {
     pub fn parse_html_document(
             document: &Document,
             input: DOMString,
-            url: Url,
+            url: ServoUrl,
             owner: Option<PipelineId>) {
         let parser = ServoParser::new(
             document,
             owner,
             Tokenizer::Html(self::html::Tokenizer::new(document, url, None)),
             LastChunkState::NotReceived);
         parser.parse_chunk(String::from(input));
     }
@@ -117,17 +117,17 @@ impl ServoParser {
         for child in root_element.upcast::<Node>().children() {
             output.AppendChild(&child).unwrap();
         }
     }
 
     pub fn parse_xml_document(
             document: &Document,
             input: DOMString,
-            url: Url,
+            url: ServoUrl,
             owner: Option<PipelineId>) {
         let parser = ServoParser::new(
             document,
             owner,
             Tokenizer::Xml(self::xml::Tokenizer::new(document, url)),
             LastChunkState::NotReceived);
         parser.parse_chunk(String::from(input));
     }
@@ -282,17 +282,17 @@ impl ServoParser {
 enum Tokenizer {
     Html(self::html::Tokenizer),
     Xml(self::xml::Tokenizer),
 }
 
 #[derive(JSTraceable, HeapSizeOf)]
 #[must_root]
 struct Sink {
-    pub base_url: Url,
+    pub base_url: ServoUrl,
     pub document: JS<Document>,
 }
 
 impl Tokenizer {
     fn feed(&mut self, input: String) {
         match *self {
             Tokenizer::Html(ref mut tokenizer) => tokenizer.feed(input),
             Tokenizer::Xml(ref mut tokenizer) => tokenizer.feed(input.into()),
@@ -333,21 +333,21 @@ impl Tokenizer {
 pub struct ParserContext {
     /// The parser that initiated the request.
     parser: Option<Trusted<ServoParser>>,
     /// Is this a synthesized document
     is_synthesized_document: bool,
     /// The pipeline associated with this document.
     id: PipelineId,
     /// The URL for this document.
-    url: Url,
+    url: ServoUrl,
 }
 
 impl ParserContext {
-    pub fn new(id: PipelineId, url: Url) -> ParserContext {
+    pub fn new(id: PipelineId, url: ServoUrl) -> ParserContext {
         ParserContext {
             parser: None,
             is_synthesized_document: false,
             id: id,
             url: url,
         }
     }
 }
--- a/servo/components/script/dom/servoparser/xml.rs
+++ b/servo/components/script/dom/servoparser/xml.rs
@@ -14,33 +14,33 @@ use dom::document::Document;
 use dom::documenttype::DocumentType;
 use dom::element::{Element, ElementCreator};
 use dom::htmlscriptelement::HTMLScriptElement;
 use dom::node::Node;
 use dom::processinginstruction::ProcessingInstruction;
 use dom::text::Text;
 use html5ever_atoms::{Prefix, QualName};
 use js::jsapi::JSTracer;
+use servo_url::ServoUrl;
 use std::borrow::Cow;
 use super::Sink;
-use url::Url;
 use xml5ever::tendril::StrTendril;
 use xml5ever::tokenizer::{Attribute, QName, XmlTokenizer};
 use xml5ever::tree_builder::{NextParserState, NodeOrText};
 use xml5ever::tree_builder::{Tracer as XmlTracer, TreeSink, XmlTreeBuilder};
 
 #[derive(HeapSizeOf, JSTraceable)]
 #[must_root]
 pub struct Tokenizer {
     #[ignore_heap_size_of = "Defined in xml5ever"]
     inner: XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>>,
 }
 
 impl Tokenizer {
-    pub fn new(document: &Document, url: Url) -> Self {
+    pub fn new(document: &Document, url: ServoUrl) -> Self {
         let sink = Sink {
             base_url: url,
             document: JS::from_ref(document),
         };
 
         let tb = XmlTreeBuilder::new(sink);
         let tok = XmlTokenizer::new(tb, Default::default());
 
--- a/servo/components/script/dom/storage.rs
+++ b/servo/components/script/dom/storage.rs
@@ -13,18 +13,18 @@ use dom::bindings::str::DOMString;
 use dom::event::{Event, EventBubbles, EventCancelable};
 use dom::globalscope::GlobalScope;
 use dom::storageevent::StorageEvent;
 use ipc_channel::ipc::{self, IpcSender};
 use net_traits::IpcSend;
 use net_traits::storage_thread::{StorageThreadMsg, StorageType};
 use script_thread::{Runnable, ScriptThread};
 use script_traits::ScriptMsg;
+use servo_url::ServoUrl;
 use task_source::TaskSource;
-use url::Url;
 
 #[dom_struct]
 pub struct Storage {
     reflector_: Reflector,
     storage_type: StorageType
 }
 
 impl Storage {
@@ -34,17 +34,17 @@ impl Storage {
             storage_type: storage_type
         }
     }
 
     pub fn new(global: &GlobalScope, storage_type: StorageType) -> Root<Storage> {
         reflect_dom_object(box Storage::new_inherited(storage_type), global, StorageBinding::Wrap)
     }
 
-    fn get_url(&self) -> Url {
+    fn get_url(&self) -> ServoUrl {
         self.global().get_url()
     }
 
     fn get_storage_thread(&self) -> IpcSender<StorageThreadMsg> {
         self.global().resource_threads().sender()
     }
 
 }
@@ -153,39 +153,39 @@ impl Storage {
         let pipeline_id = self.global().pipeline_id();
         let storage = self.storage_type;
         let url = self.get_url();
         let msg = ScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value);
         self.global().constellation_chan().send(msg).unwrap();
     }
 
     /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
-    pub fn queue_storage_event(&self, url: Url,
+    pub fn queue_storage_event(&self, url: ServoUrl,
                                key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
         let global = self.global();
         let window = global.as_window();
         let task_source = window.dom_manipulation_task_source();
         let trusted_storage = Trusted::new(self);
         task_source
             .queue(
                 box StorageEventRunnable::new(trusted_storage, url, key, old_value, new_value), &global)
             .unwrap();
     }
 }
 
 pub struct StorageEventRunnable {
     element: Trusted<Storage>,
-    url: Url,
+    url: ServoUrl,
     key: Option<String>,
     old_value: Option<String>,
     new_value: Option<String>
 }
 
 impl StorageEventRunnable {
-    fn new(storage: Trusted<Storage>, url: Url,
+    fn new(storage: Trusted<Storage>, url: ServoUrl,
            key: Option<String>, old_value: Option<String>, new_value: Option<String>) -> StorageEventRunnable {
         StorageEventRunnable { element: storage, url: url, key: key, old_value: old_value, new_value: new_value }
     }
 }
 
 impl Runnable for StorageEventRunnable {
     fn name(&self) -> &'static str { "StorageEventRunnable" }
 
--- a/servo/components/script/dom/url.rs
+++ b/servo/components/script/dom/url.rs
@@ -12,78 +12,79 @@ use dom::bindings::str::{DOMString, USVS
 use dom::blob::Blob;
 use dom::globalscope::GlobalScope;
 use dom::urlhelper::UrlHelper;
 use dom::urlsearchparams::URLSearchParams;
 use ipc_channel::ipc;
 use net_traits::{CoreResourceMsg, IpcSend};
 use net_traits::blob_url_store::{get_blob_origin, parse_blob_url};
 use net_traits::filemanager_thread::FileManagerThreadMsg;
+use servo_url::ServoUrl;
 use std::default::Default;
-use url::Url;
 use uuid::Uuid;
 
 // https://url.spec.whatwg.org/#url
 #[dom_struct]
 pub struct URL {
     reflector_: Reflector,
 
     // https://url.spec.whatwg.org/#concept-url-url
-    url: DOMRefCell<Url>,
+    url: DOMRefCell<ServoUrl>,
 
     // https://url.spec.whatwg.org/#dom-url-searchparams
     search_params: MutNullableHeap<JS<URLSearchParams>>,
 }
 
 impl URL {
-    fn new_inherited(url: Url) -> URL {
+    fn new_inherited(url: ServoUrl) -> URL {
         URL {
             reflector_: Reflector::new(),
             url: DOMRefCell::new(url),
             search_params: Default::default(),
         }
     }
 
-    pub fn new(global: &GlobalScope, url: Url) -> Root<URL> {
+    pub fn new(global: &GlobalScope, url: ServoUrl) -> Root<URL> {
         reflect_dom_object(box URL::new_inherited(url),
                            global, URLBinding::Wrap)
     }
 
     pub fn query_pairs(&self) -> Vec<(String, String)> {
-        self.url.borrow().query_pairs().into_owned().collect()
+        self.url.borrow().as_url().unwrap().query_pairs().into_owned().collect()
     }
 
     pub fn set_query_pairs(&self, pairs: &[(String, String)]) {
-        let mut url = self.url.borrow_mut();
-        url.query_pairs_mut().clear().extend_pairs(pairs);
+        if let Some(ref mut url) = self.url.borrow_mut().as_mut_url() {
+            url.query_pairs_mut().clear().extend_pairs(pairs);
+        }
     }
 }
 
 impl URL {
     // https://url.spec.whatwg.org/#constructors
     pub fn Constructor(global: &GlobalScope, url: USVString,
                        base: Option<USVString>)
                        -> Fallible<Root<URL>> {
         let parsed_base = match base {
             None => {
                 // Step 1.
                 None
             },
             Some(base) =>
                 // Step 2.1.
-                match Url::parse(&base.0) {
+                match ServoUrl::parse(&base.0) {
                     Ok(base) => Some(base),
                     Err(error) => {
                         // Step 2.2.
                         return Err(Error::Type(format!("could not parse base: {}", error)));
                     }
                 }
         };
         // Step 3.
-        let parsed_url = match Url::options().base_url(parsed_base.as_ref()).parse(&url.0) {
+        let parsed_url = match ServoUrl::parse_with_base(parsed_base.as_ref(), &url.0) {
             Ok(url) => url,
             Err(error) => {
                 // Step 4.
                 return Err(Error::Type(format!("could not parse URL: {}", error)));
             }
         };
         // Step 5: Skip (see step 8 below).
         // Steps 6-7.
@@ -119,17 +120,17 @@ impl URL {
             if the value provided for the url argument does not have an entry in the Blob URL Store,
 
             this method call does nothing. User agents may display a message on the error console.
 
             NOTE: The first step is unnecessary, since closed blobs do not exist in the store
         */
         let origin = get_blob_origin(&global.get_url());
 
-        if let Ok(url) = Url::parse(&url) {
+        if let Ok(url) = ServoUrl::parse(&url) {
              if let Ok((id, _, _)) = parse_blob_url(&url) {
                 let resource_threads = global.resource_threads();
                 let (tx, rx) = ipc::channel().unwrap();
                 let msg = FileManagerThreadMsg::RevokeBlobURL(id, origin, tx);
                 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
 
                 let _ = rx.recv().unwrap();
             }
@@ -187,17 +188,17 @@ impl URLMethods for URL {
 
     // https://url.spec.whatwg.org/#dom-url-href
     fn Href(&self) -> USVString {
         UrlHelper::Href(&self.url.borrow())
     }
 
     // https://url.spec.whatwg.org/#dom-url-href
     fn SetHref(&self, value: USVString) -> ErrorResult {
-        match Url::parse(&value.0) {
+        match ServoUrl::parse(&value.0) {
             Ok(url) => {
                 *self.url.borrow_mut() = url;
                 self.search_params.set(None);  // To be re-initialized in the SearchParams getter.
                 Ok(())
             },
             Err(error) => {
                 Err(Error::Type(format!("could not parse URL: {}", error)))
             },
@@ -253,17 +254,17 @@ impl URLMethods for URL {
     fn Search(&self) -> USVString {
         UrlHelper::Search(&self.url.borrow())
     }
 
     // https://url.spec.whatwg.org/#dom-url-search
     fn SetSearch(&self, value: USVString) {
         UrlHelper::SetSearch(&mut self.url.borrow_mut(), value);
         if let Some(search_params) = self.search_params.get() {
-            search_params.set_list(self.url.borrow().query_pairs().into_owned().collect());
+            search_params.set_list(self.query_pairs());
         }
     }
 
     // https://url.spec.whatwg.org/#dom-url-searchparams
     fn SearchParams(&self) -> Root<URLSearchParams> {
         self.search_params.or_init(|| {
             URLSearchParams::new(&self.global(), Some(self))
         })
--- a/servo/components/script/dom/urlhelper.rs
+++ b/servo/components/script/dom/urlhelper.rs
@@ -1,34 +1,95 @@
 /* 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 dom::bindings::str::USVString;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
-use url::{Url, quirks};
+use url::quirks;
 
 #[derive(HeapSizeOf)]
 pub struct UrlHelper;
 
 impl UrlHelper {
-    pub fn SameOrigin(url_a: &Url, url_b: &Url) -> bool { url_a.origin() == url_b.origin() }
-    pub fn Origin(url: &Url) -> USVString { USVString(quirks::origin(url)) }
-    pub fn Href(url: &Url) -> USVString { USVString(quirks::href(url).to_owned()) }
-    pub fn Hash(url: &Url) -> USVString { USVString(quirks::hash(url).to_owned()) }
-    pub fn Host(url: &Url) -> USVString { USVString(quirks::host(url).to_owned()) }
-    pub fn Port(url: &Url) -> USVString { USVString(quirks::port(url).to_owned()) }
-    pub fn Search(url: &Url) -> USVString { USVString(quirks::search(url).to_owned()) }
-    pub fn Hostname(url: &Url) -> USVString { USVString(quirks::hostname(url).to_owned()) }
-    pub fn Password(url: &Url) -> USVString { USVString(quirks::password(url).to_owned()) }
-    pub fn Pathname(url: &Url) -> USVString { USVString(quirks::pathname(url).to_owned()) }
-    pub fn Protocol(url: &Url) -> USVString { USVString(quirks::protocol(url).to_owned()) }
-    pub fn Username(url: &Url) -> USVString { USVString(quirks::username(url).to_owned()) }
-    pub fn SetHash(url: &mut Url, value: USVString) { quirks::set_hash(url, &value.0) }
-    pub fn SetHost(url: &mut Url, value: USVString) { let _ = quirks::set_host(url, &value.0); }
-    pub fn SetPort(url: &mut Url, value: USVString) { let _ = quirks::set_port(url, &value.0); }
-    pub fn SetSearch(url: &mut Url, value: USVString) { quirks::set_search(url, &value.0) }
-    pub fn SetPathname(url: &mut Url, value: USVString) { quirks::set_pathname(url, &value.0) }
-    pub fn SetHostname(url: &mut Url, value: USVString) { let _ = quirks::set_hostname(url, &value.0); }
-    pub fn SetPassword(url: &mut Url, value: USVString) { let _ = quirks::set_password(url, &value.0); }
-    pub fn SetProtocol(url: &mut Url, value: USVString) { let _ = quirks::set_protocol(url, &value.0); }
-    pub fn SetUsername(url: &mut Url, value: USVString) { let _ = quirks::set_username(url, &value.0); }
+    pub fn SameOrigin(url_a: &ServoUrl, url_b: &ServoUrl) -> bool {
+        url_a.origin() == url_b.origin()
+    }
+    pub fn Origin(url: &ServoUrl) -> USVString {
+        USVString(quirks::origin(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Href(url: &ServoUrl) -> USVString {
+        USVString(quirks::href(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Hash(url: &ServoUrl) -> USVString {
+        USVString(quirks::hash(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Host(url: &ServoUrl) -> USVString {
+        USVString(quirks::host(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Port(url: &ServoUrl) -> USVString {
+        USVString(quirks::port(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Search(url: &ServoUrl) -> USVString {
+        USVString(quirks::search(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Hostname(url: &ServoUrl) -> USVString {
+        USVString(quirks::hostname(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Password(url: &ServoUrl) -> USVString {
+        USVString(quirks::password(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Pathname(url: &ServoUrl) -> USVString {
+        USVString(quirks::pathname(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Protocol(url: &ServoUrl) -> USVString {
+        USVString(quirks::protocol(url.as_url().unwrap()).to_owned())
+    }
+    pub fn Username(url: &ServoUrl) -> USVString {
+        USVString(quirks::username(url.as_url().unwrap()).to_owned())
+    }
+    pub fn SetHash(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            quirks::set_hash(url, &value.0)
+        }
+    }
+    pub fn SetHost(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            let _ = quirks::set_host(url, &value.0);
+        }
+    }
+    pub fn SetPort(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            let _ = quirks::set_port(url, &value.0);
+        }
+    }
+    pub fn SetSearch(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            quirks::set_search(url, &value.0)
+        }
+    }
+    pub fn SetPathname(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            quirks::set_pathname(url, &value.0)
+        }
+    }
+    pub fn SetHostname(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            let _ = quirks::set_hostname(url, &value.0);
+        }
+    }
+    pub fn SetPassword(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            let _ = quirks::set_password(url, &value.0);
+        }
+    }
+    pub fn SetProtocol(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            let _ = quirks::set_protocol(url, &value.0);
+        }
+    }
+    pub fn SetUsername(url: &mut ServoUrl, value: USVString) {
+        if let Some(ref mut url) = url.as_mut_url() {
+            let _ = quirks::set_username(url, &value.0);
+        }
+    }
 }
--- a/servo/components/script/dom/websocket.rs
+++ b/servo/components/script/dom/websocket.rs
@@ -31,24 +31,24 @@ use net_traits::{WebSocketCommunicate, W
 use net_traits::CookieSource::HTTP;
 use net_traits::CoreResourceMsg::{SetCookiesForUrl, WebsocketConnect};
 use net_traits::MessageData;
 use net_traits::hosts::replace_hosts;
 use net_traits::unwrap_websocket_protocol;
 use script_runtime::CommonScriptMsg;
 use script_runtime::ScriptThreadEventCategory::WebSocketEvent;
 use script_thread::{Runnable, RunnableWrapper};
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::ptr;
 use std::thread;
 use task_source::TaskSource;
 use task_source::networking::NetworkingTaskSource;
-use websocket::client::request::Url;
 use websocket::header::{Headers, WebSocketProtocol};
 use websocket::ws::util::url::parse_url;
 
 #[derive(JSTraceable, PartialEq, Copy, Clone, Debug, HeapSizeOf)]
 enum WebSocketRequestState {
     Connecting = 0,
     Open = 1,
     Closing = 2,
@@ -166,54 +166,54 @@ pub fn fail_the_websocket_connection(add
         reason: None,
     };
     task_source.queue_with_wrapper(close_task, &wrapper).unwrap();
 }
 
 #[dom_struct]
 pub struct WebSocket {
     eventtarget: EventTarget,
-    url: Url,
+    url: ServoUrl,
     ready_state: Cell<WebSocketRequestState>,
     buffered_amount: Cell<u64>,
     clearing_buffer: Cell<bool>, //Flag to tell if there is a running thread to clear buffered_amount
     #[ignore_heap_size_of = "Defined in std"]
     sender: DOMRefCell<Option<IpcSender<WebSocketDomAction>>>,
     binary_type: Cell<BinaryType>,
     protocol: DOMRefCell<String>, //Subprotocol selected by server
 }
 
 impl WebSocket {
-    fn new_inherited(url: Url) -> WebSocket {
+    fn new_inherited(url: ServoUrl) -> WebSocket {
         WebSocket {
             eventtarget: EventTarget::new_inherited(),
             url: url,
             ready_state: Cell::new(WebSocketRequestState::Connecting),
             buffered_amount: Cell::new(0),
             clearing_buffer: Cell::new(false),
             sender: DOMRefCell::new(None),
             binary_type: Cell::new(BinaryType::Blob),
             protocol: DOMRefCell::new("".to_owned()),
         }
     }
 
-    fn new(global: &GlobalScope, url: Url) -> Root<WebSocket> {
+    fn new(global: &GlobalScope, url: ServoUrl) -> Root<WebSocket> {
         reflect_dom_object(box WebSocket::new_inherited(url),
                            global, WebSocketBinding::Wrap)
     }
 
     pub fn Constructor(global: &GlobalScope,
                        url: DOMString,
                        protocols: Option<StringOrStringSequence>)
                        -> Fallible<Root<WebSocket>> {
         // Step 1.
-        let resource_url = try!(Url::parse(&url).map_err(|_| Error::Syntax));
+        let resource_url = try!(ServoUrl::parse(&url).map_err(|_| Error::Syntax));
         // Although we do this replace and parse operation again in the resource thread,
         // we try here to be able to immediately throw a syntax error on failure.
-        let _ = try!(parse_url(&replace_hosts(&resource_url)).map_err(|_| Error::Syntax));
+        let _ = try!(parse_url(&replace_hosts(&resource_url).as_url().unwrap()).map_err(|_| Error::Syntax));
         // Step 2: Disallow https -> ws connections.
 
         // Step 3: Potentially block access to some ports.
         let port: u16 = resource_url.port_or_known_default().unwrap();
 
         if BLOCKED_PORTS_LIST.iter().any(|&p| p == port) {
             return Err(Error::Security);
         }
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -71,16 +71,17 @@ use script_layout_interface::rpc::{Margi
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory};
 use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper};
 use script_thread::SendableMainThreadScriptChan;
 use script_traits::{ConstellationControlMsg, LoadData, MozBrowserEvent, UntrustedNodeAddress};
 use script_traits::{DocumentState, TimerEvent, TimerEventId};
 use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, WindowSizeData, WindowSizeType};
 use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::collections::{HashMap, HashSet};
 use std::default::Default;
 use std::io::{Write, stderr, stdout};
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
@@ -97,17 +98,16 @@ use task_source::dom_manipulation::DOMMa
 use task_source::file_reading::FileReadingTaskSource;
 use task_source::history_traversal::HistoryTraversalTaskSource;
 use task_source::networking::NetworkingTaskSource;
 use task_source::user_interaction::UserInteractionTaskSource;
 use time;
 use timers::{IsInterval, TimerCallback};
 #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
 use tinyfiledialogs::{self, MessageBoxIcon};
-use url::Url;
 use util::geometry::{self, max_rect};
 use util::opts;
 use util::prefs::PREFS;
 use webdriver_handlers::jsval_to_webdriver;
 
 /// Current state of the window object
 #[derive(JSTraceable, Copy, Clone, Debug, PartialEq, HeapSizeOf)]
 enum WindowState {
@@ -628,17 +628,17 @@ impl WindowMethods for Window {
         // Step 3-5.
         let origin = match &origin[..] {
             "*" => None,
             "/" => {
                 // TODO(#12715): Should be the origin of the incumbent settings
                 //               object, not self's.
                 Some(self.Document().origin().copy())
             },
-            url => match Url::parse(&url) {
+            url => match ServoUrl::parse(&url) {
                 Ok(url) => Some(Origin::new(&url)),
                 Err(_) => return Err(Error::Syntax),
             }
         };
 
         // Step 1-2, 6-8.
         // TODO(#12717): Should implement the `transfer` argument.
         let data = try!(StructuredCloneData::write(cx, message));
@@ -864,17 +864,17 @@ impl WindowMethods for Window {
 
     // https://html.spec.whatwg.org/multipage/#dom-window-status
     fn SetStatus(&self, status: DOMString) {
         *self.status.borrow_mut() = status
     }
 
     // check-tidy: no specs after this line
     fn OpenURLInDefaultBrowser(&self, href: DOMString) -> ErrorResult {
-        let url = try!(Url::parse(&href).map_err(|e| {
+        let url = try!(ServoUrl::parse(&href).map_err(|e| {
             Error::Type(format!("Couldn't parse URL: {}", e))
         }));
         match open::that(url.as_str()) {
             Ok(_) => Ok(()),
             Err(e) => Err(Error::Type(format!("Couldn't open URL: {}", e))),
         }
     }
 
@@ -1326,17 +1326,17 @@ impl Window {
         self.browsing_context.set(Some(&browsing_context));
         let window = self.reflector().get_jsobject();
         let cx = self.get_cx();
         let _ac = JSAutoCompartment::new(cx, window.get());
         unsafe { SetWindowProxy(cx, window, browsing_context.reflector().get_jsobject()); }
     }
 
     /// Commence a new URL load which will either replace this window or scroll to a fragment.
-    pub fn load_url(&self, url: Url, replace: bool, referrer_policy: Option<ReferrerPolicy>) {
+    pub fn load_url(&self, url: ServoUrl, replace: bool, referrer_policy: Option<ReferrerPolicy>) {
         let doc = self.Document();
         let referrer_policy = referrer_policy.or(doc.get_referrer_policy());
 
         self.main_thread_script_chan().send(
             MainThreadScriptMsg::Navigate(self.upcast::<GlobalScope>().pipeline_id(),
                 LoadData::new(url, referrer_policy, Some(doc.url().clone())),
                 replace)).unwrap();
     }
@@ -1359,17 +1359,17 @@ impl Window {
     pub fn set_window_size(&self, size: WindowSizeData) {
         self.window_size.set(Some(size));
     }
 
     pub fn window_size(&self) -> Option<WindowSizeData> {
         self.window_size.get()
     }
 
-    pub fn get_url(&self) -> Url {
+    pub fn get_url(&self) -> ServoUrl {
         (*self.Document().url()).clone()
     }
 
     pub fn layout_chan(&self) -> &Sender<Msg> {
         &self.layout_chan
     }
 
     pub fn windowproxy_handler(&self) -> WindowProxyHandler {
--- a/servo/components/script/dom/workerglobalscope.rs
+++ b/servo/components/script/dom/workerglobalscope.rs
@@ -29,26 +29,26 @@ use js::jsval::UndefinedValue;
 use js::rust::Runtime;
 use net_traits::{IpcSend, load_whole_resource};
 use net_traits::request::{CredentialsMode, Destination, RequestInit as NetRequestInit, Type as RequestType};
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, maybe_take_panic_result};
 use script_runtime::{ScriptThreadEventCategory, PromiseJobQueue, EnqueuedPromiseCallback};
 use script_thread::{Runnable, RunnableWrapper};
 use script_traits::{TimerEvent, TimerEventId};
 use script_traits::WorkerGlobalScopeInit;
+use servo_url::ServoUrl;
 use std::default::Default;
 use std::panic;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::mpsc::Receiver;
 use task_source::file_reading::FileReadingTaskSource;
 use task_source::networking::NetworkingTaskSource;
 use timers::{IsInterval, TimerCallback};
-use url::Url;
 
 pub fn prepare_workerscope_init(global: &GlobalScope,
                                 devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>) -> WorkerGlobalScopeInit {
     let init = WorkerGlobalScopeInit {
             resource_threads: global.resource_threads().clone(),
             mem_profiler_chan: global.mem_profiler_chan().clone(),
             to_devtools_sender: global.devtools_chan().cloned(),
             time_profiler_chan: global.time_profiler_chan().clone(),
@@ -63,17 +63,17 @@ pub fn prepare_workerscope_init(global: 
 }
 
 // https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface
 #[dom_struct]
 pub struct WorkerGlobalScope {
     globalscope: GlobalScope,
 
     worker_id: WorkerId,
-    worker_url: Url,
+    worker_url: ServoUrl,
     #[ignore_heap_size_of = "Arc"]
     closing: Option<Arc<AtomicBool>>,
     #[ignore_heap_size_of = "Defined in js"]
     runtime: Runtime,
     location: MutNullableHeap<JS<WorkerLocation>>,
     navigator: MutNullableHeap<JS<WorkerNavigator>>,
 
     #[ignore_heap_size_of = "Defined in ipc-channel"]
@@ -86,17 +86,17 @@ pub struct WorkerGlobalScope {
     /// `IpcSender` doesn't exist
     from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
 
     promise_job_queue: PromiseJobQueue,
 }
 
 impl WorkerGlobalScope {
     pub fn new_inherited(init: WorkerGlobalScopeInit,
-                         worker_url: Url,
+                         worker_url: ServoUrl,
                          runtime: Runtime,
                          from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
                          timer_event_chan: IpcSender<TimerEvent>,
                          closing: Option<Arc<AtomicBool>>)
                          -> WorkerGlobalScope {
         WorkerGlobalScope {
             globalscope:
                 GlobalScope::new_inherited(
@@ -139,17 +139,17 @@ impl WorkerGlobalScope {
     pub fn is_closing(&self) -> bool {
         if let Some(ref closing) = self.closing {
             closing.load(Ordering::SeqCst)
         } else {
             false
         }
     }
 
-    pub fn get_url(&self) -> &Url {
+    pub fn get_url(&self) -> &ServoUrl {
         &self.worker_url
     }
 
     pub fn get_worker_id(&self) -> WorkerId {
         self.worker_id.clone()
     }
 
     pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
--- a/servo/components/script/dom/workerlocation.rs
+++ b/servo/components/script/dom/workerlocation.rs
@@ -4,34 +4,34 @@
 
 use dom::bindings::codegen::Bindings::WorkerLocationBinding;
 use dom::bindings::codegen::Bindings::WorkerLocationBinding::WorkerLocationMethods;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{Reflector, reflect_dom_object};
 use dom::bindings::str::{DOMString, USVString};
 use dom::urlhelper::UrlHelper;
 use dom::workerglobalscope::WorkerGlobalScope;
-use url::Url;
+use servo_url::ServoUrl;
 
 // https://html.spec.whatwg.org/multipage/#worker-locations
 #[dom_struct]
 pub struct WorkerLocation {
     reflector_: Reflector,
-    url: Url,
+    url: ServoUrl,
 }
 
 impl WorkerLocation {
-    fn new_inherited(url: Url) -> WorkerLocation {
+    fn new_inherited(url: ServoUrl) -> WorkerLocation {
         WorkerLocation {
             reflector_: Reflector::new(),
             url: url,
         }
     }
 
-    pub fn new(global: &WorkerGlobalScope, url: Url) -> Root<WorkerLocation> {
+    pub fn new(global: &WorkerGlobalScope, url: ServoUrl) -> Root<WorkerLocation> {
         reflect_dom_object(box WorkerLocation::new_inherited(url),
                            global,
                            WorkerLocationBinding::Wrap)
     }
 }
 
 impl WorkerLocationMethods for WorkerLocation {
     // https://html.spec.whatwg.org/multipage/#dom-workerlocation-hash
--- a/servo/components/script/dom/xmldocument.rs
+++ b/servo/components/script/dom/xmldocument.rs
@@ -11,28 +11,28 @@ use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 use dom::browsingcontext::BrowsingContext;
 use dom::document::{Document, DocumentSource, IsHTMLDocument};
 use dom::location::Location;
 use dom::node::Node;
 use dom::window::Window;
 use js::jsapi::{JSContext, JSObject};
-use url::Url;
+use servo_url::ServoUrl;
 
 // https://dom.spec.whatwg.org/#xmldocument
 #[dom_struct]
 pub struct XMLDocument {
     document: Document,
 }
 
 impl XMLDocument {
     fn new_inherited(window: &Window,
                      browsing_context: Option<&BrowsingContext>,
-                     url: Option<Url>,
+                     url: Option<ServoUrl>,
                      is_html_document: IsHTMLDocument,
                      content_type: Option<DOMString>,
                      last_modified: Option<String>,
                      source: DocumentSource,
                      doc_loader: DocumentLoader) -> XMLDocument {
         XMLDocument {
             document: Document::new_inherited(window,
                                               browsing_context,
@@ -44,17 +44,17 @@ impl XMLDocument {
                                               doc_loader,
                                               None,
                                               None),
         }
     }
 
     pub fn new(window: &Window,
                browsing_context: Option<&BrowsingContext>,
-               url: Option<Url>,
+               url: Option<ServoUrl>,
                doctype: IsHTMLDocument,
                content_type: Option<DOMString>,
                last_modified: Option<String>,
                source: DocumentSource,
                doc_loader: DocumentLoader)
                -> Root<XMLDocument> {
         let doc = reflect_dom_object(
             box XMLDocument::new_inherited(window,
--- a/servo/components/script/dom/xmlhttprequest.rs
+++ b/servo/components/script/dom/xmlhttprequest.rs
@@ -50,26 +50,27 @@ use js::jsval::{JSVal, NullValue, Undefi
 use msg::constellation_msg::PipelineId;
 use net_traits::{FetchMetadata, FilteredMetadata};
 use net_traits::{FetchResponseListener, LoadOrigin, NetworkError, ReferrerPolicy};
 use net_traits::CoreResourceMsg::Fetch;
 use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
 use net_traits::trim_http_whitespace;
 use network_listener::{NetworkListener, PreInvoke};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::default::Default;
 use std::str;
 use std::sync::{Arc, Mutex};
 use task_source::networking::NetworkingTaskSource;
 use time;
 use timers::{OneshotTimerCallback, OneshotTimerHandle};
-use url::{Position, Url};
+use url::Position;
 use util::prefs::PREFS;
 
 #[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
 enum XMLHttpRequestState {
     Unsent = 0,
     Opened = 1,
     HeadersReceived = 2,
     Loading = 3,
@@ -132,29 +133,29 @@ pub struct XMLHttpRequest {
     #[ignore_heap_size_of = "Defined in hyper"]
     override_mime_type: DOMRefCell<Option<Mime>>,
     #[ignore_heap_size_of = "Defined in rust-encoding"]
     override_charset: DOMRefCell<Option<EncodingRef>>,
 
     // Associated concepts
     #[ignore_heap_size_of = "Defined in hyper"]
     request_method: DOMRefCell<Method>,
-    request_url: DOMRefCell<Option<Url>>,
+    request_url: DOMRefCell<Option<ServoUrl>>,
     #[ignore_heap_size_of = "Defined in hyper"]
     request_headers: DOMRefCell<Headers>,
     request_body_len: Cell<usize>,
     sync: Cell<bool>,
     upload_complete: Cell<bool>,
     send_flag: Cell<bool>,
 
     timeout_cancel: DOMRefCell<Option<OneshotTimerHandle>>,
     fetch_time: Cell<i64>,
     generation_id: Cell<GenerationId>,
     response_status: Cell<Result<(), ()>>,
-    referrer_url: Option<Url>,
+    referrer_url: Option<ServoUrl>,
     referrer_policy: Option<ReferrerPolicy>,
 }
 
 impl XMLHttpRequest {
     fn new_inherited(global: &GlobalScope) -> XMLHttpRequest {
         //TODO - update this when referrer policy implemented for workers
         let (referrer_url, referrer_policy) = if let Some(window) = global.downcast::<Window>() {
             let document = window.Document();
@@ -164,17 +165,17 @@ impl XMLHttpRequest {
         };
 
         XMLHttpRequest {
             eventtarget: XMLHttpRequestEventTarget::new_inherited(),
             ready_state: Cell::new(XMLHttpRequestState::Unsent),
             timeout: Cell::new(0u32),
             with_credentials: Cell::new(false),
             upload: JS::from_ref(&*XMLHttpRequestUpload::new(global)),
-            response_url: DOMRefCell::new(String::from("")),
+            response_url: DOMRefCell::new(String::new()),
             status: Cell::new(0),
             status_text: DOMRefCell::new(ByteString::new(vec!())),
             response: DOMRefCell::new(ByteString::new(vec!())),
             response_type: Cell::new(XMLHttpRequestResponseType::_empty),
             response_xml: Default::default(),
             response_blob: Default::default(),
             response_json: MutHeapJSVal::new(),
             response_headers: DOMRefCell::new(Headers::new()),
@@ -267,17 +268,17 @@ impl XMLHttpRequest {
         ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
             listener.notify_fetch(message.to().unwrap());
         });
         global.core_resource_thread().send(Fetch(init, action_sender)).unwrap();
     }
 }
 
 impl LoadOrigin for XMLHttpRequest {
-    fn referrer_url(&self) -> Option<Url> {
+    fn referrer_url(&self) -> Option<ServoUrl> {
         return self.referrer_url.clone();
     }
 
     fn referrer_policy(&self) -> Option<ReferrerPolicy> {
         return self.referrer_policy;
     }
 
     fn pipeline_id(&self) -> Option<PipelineId> {
@@ -855,33 +856,34 @@ impl XMLHttpRequest {
         let event = Event::new(&self.global(),
                                atom!("readystatechange"),
                                EventBubbles::DoesNotBubble,
                                EventCancelable::Cancelable);
         event.fire(self.upcast());
     }
 
     fn process_headers_available(&self,
-                                 gen_id: GenerationId, metadata: Result<FetchMetadata, NetworkError>)
+                                 gen_id: GenerationId,
+                                 metadata: Result<FetchMetadata, NetworkError>)
                                  -> Result<(), Error> {
         let metadata = match metadata {
             Ok(meta) => match meta {
                 FetchMetadata::Unfiltered(m) => m,
                 FetchMetadata::Filtered { filtered, .. } => match filtered {
                     FilteredMetadata::Opaque => return Err(Error::Network),
                     FilteredMetadata::Transparent(m) => m
                 }
             },
             Err(_) => {
                 self.process_partial_response(XHRProgress::Errored(gen_id, Error::Network));
                 return Err(Error::Network);
             },
         };
 
-        *self.response_url.borrow_mut() = metadata.final_url[..Position::AfterQuery].to_owned();
+        *self.response_url.borrow_mut() = metadata.final_url.as_url().unwrap()[..Position::AfterQuery].to_owned();
 
         // XXXManishearth Clear cache entries in case of a network error
         self.process_partial_response(XHRProgress::HeadersReceived(
             gen_id,
             metadata.headers.map(Serde::into_inner),
             metadata.status));
         Ok(())
     }
--- a/servo/components/script/fetch.rs
+++ b/servo/components/script/fetch.rs
@@ -19,28 +19,28 @@ use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use js::jsapi::JSAutoCompartment;
 use net_traits::{FetchResponseListener, NetworkError};
 use net_traits::{FilteredMetadata, FetchMetadata, Metadata};
 use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
 use net_traits::request::Request as NetTraitsRequest;
 use net_traits::request::RequestInit as NetTraitsRequestInit;
 use network_listener::{NetworkListener, PreInvoke};
+use servo_url::ServoUrl;
 use std::mem;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
-use url::Url;
 
 struct FetchContext {
     fetch_promise: Option<TrustedPromise>,
     response_object: Trusted<Response>,
     body: Vec<u8>,
 }
 
-fn from_referrer_to_referrer_url(request: &NetTraitsRequest) -> Option<Url> {
+fn from_referrer_to_referrer_url(request: &NetTraitsRequest) -> Option<ServoUrl> {
     let referrer = request.referrer.borrow();
     referrer.to_url().map(|url| url.clone())
 }
 
 fn request_init_from_request(request: NetTraitsRequest) -> NetTraitsRequestInit {
     NetTraitsRequestInit {
         method: request.method.borrow().clone(),
         url: request.url(),
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -46,16 +46,17 @@ use parking_lot::RwLock;
 use range::Range;
 use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
 use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
 use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
 use selectors::matching::ElementFlags;
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::fmt;
 use std::marker::PhantomData;
 use std::mem::transmute;
 use std::sync::Arc;
 use std::sync::atomic::Ordering;
 use style::atomic_refcell::{AtomicRef, AtomicRefCell};
 use style::attr::AttrValue;
 use style::computed_values::display;
@@ -64,17 +65,16 @@ use style::data::ElementData;
 use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TElement, TNode};
 use style::dom::UnsafeNode;
 use style::element_state::*;
 use style::properties::{ComputedValues, PropertyDeclarationBlock};
 use style::selector_impl::{NonTSPseudoClass, PseudoElement, RestyleDamage, ServoSelectorImpl};
 use style::selector_matching::ApplicableDeclarationBlock;
 use style::sink::Push;
 use style::str::is_whitespace;
-use url::Url;
 
 #[derive(Copy, Clone)]
 pub struct ServoLayoutNode<'a> {
     /// The wrapped node.
     node: LayoutJS<Node>,
 
     /// Being chained to a PhantomData prevents `LayoutNode`s from escaping.
     chain: PhantomData<&'a ()>,
@@ -905,17 +905,17 @@ impl<'ln> ThreadSafeLayoutNode for Servo
         let this = unsafe { self.get_jsmanaged() };
 
         this.selection().map(|range| {
             Range::new(ByteIndex(range.start as isize),
                        ByteIndex(range.len() as isize))
         })
     }
 
-    fn image_url(&self) -> Option<Url> {
+    fn image_url(&self) -> Option<ServoUrl> {
         let this = unsafe { self.get_jsmanaged() };
         this.image_url()
     }
 
     fn canvas_data(&self) -> Option<HTMLCanvasData> {
         let this = unsafe { self.get_jsmanaged() };
         this.canvas_data()
     }
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -77,16 +77,17 @@ extern crate range;
 extern crate ref_slice;
 extern crate regex;
 extern crate rustc_serialize;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate selectors;
 extern crate serde;
 #[macro_use] extern crate servo_atoms;
+extern crate servo_url;
 extern crate smallvec;
 #[macro_use]
 extern crate style;
 extern crate style_traits;
 extern crate time;
 #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
 extern crate tinyfiledialogs;
 extern crate url;
--- a/servo/components/script/origin.rs
+++ b/servo/components/script/origin.rs
@@ -1,14 +1,15 @@
 /* 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 servo_url::ServoUrl;
 use std::sync::Arc;
-use url::{Host, Url};
+use url::Host;
 use url::Origin as UrlOrigin;
 
 /// A representation of an [origin](https://html.spec.whatwg.org/multipage/#origin-2).
 #[derive(HeapSizeOf, JSTraceable)]
 pub struct Origin {
     #[ignore_heap_size_of = "Arc<T> has unclear ownership semantics"]
     inner: Arc<UrlOrigin>,
 }
@@ -17,17 +18,17 @@ impl Origin {
     /// Create a new origin comprising a unique, opaque identifier.
     pub fn opaque_identifier() -> Origin {
         Origin {
             inner: Arc::new(UrlOrigin::new_opaque()),
         }
     }
 
     /// Create a new origin for the given URL.
-    pub fn new(url: &Url) -> Origin {
+    pub fn new(url: &ServoUrl) -> Origin {
         Origin {
             inner: Arc::new(url.origin()),
         }
     }
 
     /// Does this origin represent a host/scheme/port tuple?
     pub fn is_scheme_host_port_tuple(&self) -> bool {
         self.inner.is_tuple()
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -85,16 +85,17 @@ use script_runtime::{ScriptPort, StackRo
 use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
 use script_traits::{InitialScriptState, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
 use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
 use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
 use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
 use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent};
 use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent};
 use script_traits::webdriver_msg::WebDriverScriptCommand;
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::collections::{hash_map, HashMap, HashSet};
 use std::option::Option;
 use std::ptr;
 use std::rc::Rc;
 use std::result::Result;
 use std::sync::{Arc, Mutex};
@@ -105,17 +106,17 @@ use style::dom::{TNode, UnsafeNode};
 use style::thread_state;
 use task_source::TaskSource;
 use task_source::dom_manipulation::{DOMManipulationTask, DOMManipulationTaskSource};
 use task_source::file_reading::FileReadingTaskSource;
 use task_source::history_traversal::HistoryTraversalTaskSource;
 use task_source::networking::NetworkingTaskSource;
 use task_source::user_interaction::{UserInteractionTask, UserInteractionTaskSource};
 use time::Tm;
-use url::{Position, Url};
+use url::Position;
 use util::opts;
 use util::thread;
 use webdriver_handlers;
 
 thread_local!(pub static STACK_ROOTS: Cell<Option<RootCollectionPtr>> = Cell::new(None));
 thread_local!(static SCRIPT_THREAD_ROOT: Cell<Option<*const ScriptThread>> = Cell::new(None));
 
 pub unsafe fn trace_thread(tr: *mut JSTracer) {
@@ -145,27 +146,27 @@ struct InProgressLoad {
     layout_chan: Sender<message::Msg>,
     /// The current viewport clipping rectangle applying to this pipeline, if any.
     clip_rect: Option<Rect<f32>>,
     /// Window is frozen (navigated away while loading for example).
     is_frozen: bool,
     /// Window is visible.
     is_visible: bool,
     /// The requested URL of the load.
-    url: Url,
+    url: ServoUrl,
 }
 
 impl InProgressLoad {
     /// Create a new InProgressLoad object.
     fn new(id: PipelineId,
            frame_id: FrameId,
            parent_info: Option<(PipelineId, FrameType)>,
            layout_chan: Sender<message::Msg>,
            window_size: Option<WindowSizeData>,
-           url: Url) -> InProgressLoad {
+           url: ServoUrl) -> InProgressLoad {
         InProgressLoad {
             pipeline_id: id,
             frame_id: frame_id,
             parent_info: parent_info,
             layout_chan: layout_chan,
             window_size: window_size,
             clip_rect: None,
             is_frozen: false,
@@ -392,17 +393,17 @@ impl<'a> Iterator for DocumentsIter<'a> 
 // ScriptThread instances are rooted on creation, so this is okay
 #[allow(unrooted_must_root)]
 pub struct ScriptThread {
     /// The documents for pipelines managed by this thread
     documents: DOMRefCell<Documents>,
     /// A list of data pertaining to loads that have not yet received a network response
     incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
     /// A map to store service worker registrations for a given origin
-    registration_map: DOMRefCell<HashMap<Url, JS<ServiceWorkerRegistration>>>,
+    registration_map: DOMRefCell<HashMap<ServoUrl, JS<ServiceWorkerRegistration>>>,
     /// A handle to the image cache thread.
     image_cache_thread: ImageCacheThread,
     /// A handle to the resource thread. This is an `Arc` to avoid running out of file descriptors if
     /// there are many iframes.
     resource_threads: ResourceThreads,
     /// A handle to the bluetooth thread.
     bluetooth_thread: IpcSender<BluetoothRequest>,
 
@@ -558,17 +559,17 @@ impl ScriptThread {
                                   -> Option<Root<ServoParser>> {
         SCRIPT_THREAD_ROOT.with(|root| {
             let script_thread = unsafe { &*root.get().unwrap() };
             script_thread.handle_page_headers_available(id, metadata)
         })
     }
 
     // stores a service worker registration
-    pub fn set_registration(scope_url: Url, registration:&ServiceWorkerRegistration, pipeline_id: PipelineId) {
+    pub fn set_registration(scope_url: ServoUrl, registration:&ServiceWorkerRegistration, pipeline_id: PipelineId) {
         SCRIPT_THREAD_ROOT.with(|root| {
             let script_thread = unsafe { &*root.get().unwrap() };
             script_thread.handle_serviceworker_registration(scope_url, registration, pipeline_id);
         });
     }
 
     pub fn parsing_complete(id: PipelineId) {
         SCRIPT_THREAD_ROOT.with(|root| {
@@ -1443,17 +1444,17 @@ impl ScriptThread {
             None => {
                 assert!(self.closed_pipelines.borrow().contains(id));
                 None
             }
         }
     }
 
     fn handle_serviceworker_registration(&self,
-                                         scope: Url,
+                                         scope: ServoUrl,
                                          registration: &ServiceWorkerRegistration,
                                          pipeline_id: PipelineId) {
         {
             let ref mut reg_ref = *self.registration_map.borrow_mut();
             // according to spec we should replace if an older registration exists for
             // same scope otherwise just insert the new one
             let _ = reg_ref.remove(&scope);
             reg_ref.insert(scope.clone(), JS::from_ref(registration));
@@ -1575,17 +1576,17 @@ impl ScriptThread {
     /// Handles a Web font being loaded. Does nothing if the page no longer exists.
     fn handle_web_font_loaded(&self, pipeline_id: PipelineId) {
         if let Some(document) = self.documents.borrow().find_document(pipeline_id)  {
             self.rebuild_and_force_reflow(&document, ReflowReason::WebFontLoaded);
         }
     }
 
     /// Notify a window of a storage event
-    fn handle_storage_event(&self, pipeline_id: PipelineId, storage_type: StorageType, url: Url,
+    fn handle_storage_event(&self, pipeline_id: PipelineId, storage_type: StorageType, url: ServoUrl,
                             key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
         let storage = match self.documents.borrow().find_window(pipeline_id) {
             None => return warn!("Storage event sent to closed pipeline {}.", pipeline_id),
             Some(window) => match storage_type {
                 StorageType::Local => window.LocalStorage(),
                 StorageType::Session => window.SessionStorage(),
             },
         };
@@ -1747,17 +1748,17 @@ impl ScriptThread {
 
             // Turn javascript: URL into JS code to eval, according to the steps in
             // https://html.spec.whatwg.org/multipage/#javascript-protocol
 
             // This slice of the URL’s serialization is equivalent to (5.) to (7.):
             // Start with the scheme data of the parsed URL;
             // append question mark and query component, if any;
             // append number sign and fragment component if any.
-            let encoded = &incomplete.url[Position::BeforePath..];
+            let encoded = &incomplete.url.as_url().unwrap()[Position::BeforePath..];
 
             // Percent-decode (8.) and UTF-8 decode (9.)
             let script_source = percent_decode(encoded.as_bytes()).decode_utf8_lossy();
 
             // Script source is ready to be evaluated (11.)
             unsafe {
                 let _ac = JSAutoCompartment::new(self.get_cx(), window.reflector().get_jsobject().get());
                 rooted!(in(self.get_cx()) let mut jsval = UndefinedValue());
@@ -1807,17 +1808,17 @@ impl ScriptThread {
 
         if !incomplete.is_visible {
             self.alter_resource_utilization(incomplete.pipeline_id, false);
         }
 
         document.get_current_parser().unwrap()
     }
 
-    fn notify_devtools(&self, title: DOMString, url: Url, ids: (PipelineId, Option<WorkerId>)) {
+    fn notify_devtools(&self, title: DOMString, url: ServoUrl, ids: (PipelineId, Option<WorkerId>)) {
         if let Some(ref chan) = self.devtools_chan {
             let page_info = DevtoolsPageInfo {
                 title: String::from(title),
                 url: url,
             };
             chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
                         ids,
                         self.devtools_sender.clone(),
@@ -1989,21 +1990,23 @@ impl ScriptThread {
         // Step 7.
         {
             let nurl = &load_data.url;
             if let Some(fragment) = nurl.fragment() {
                 let document = match self.documents.borrow().find_document(parent_pipeline_id) {
                     Some(document) => document,
                     None => return warn!("Message sent to closed pipeline {}.", parent_pipeline_id),
                 };
-                let url = document.url();
-                if &url[..Position::AfterQuery] == &nurl[..Position::AfterQuery] &&
-                    load_data.method == Method::Get {
-                    self.check_and_scroll_fragment(fragment, parent_pipeline_id, &document);
-                    return;
+                let nurl = nurl.as_url().unwrap();
+                if let Some(url) = document.url().as_url() {
+                    if &url[..Position::AfterQuery] == &nurl[..Position::AfterQuery] &&
+                        load_data.method == Method::Get {
+                        self.check_and_scroll_fragment(fragment, parent_pipeline_id, &document);
+                        return;
+                    }
                 }
             }
         }
 
         match frame_id {
             Some(frame_id) => {
                 if let Some(iframe) = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id) {
                     iframe.navigate_or_reload_child_browsing_context(Some(load_data), replace);
@@ -2063,17 +2066,17 @@ impl ScriptThread {
             task_source: self.networking_task_source.clone(),
             wrapper: None,
         };
         ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
             listener.notify_fetch(message.to().unwrap());
         });
 
         if load_data.url.scheme() == "javascript" {
-            load_data.url = Url::parse("about:blank").unwrap();
+            load_data.url = ServoUrl::parse("about:blank").unwrap();
         }
 
         let request = RequestInit {
             url: load_data.url.clone(),
             method: load_data.method,
             destination: Destination::Document,
             credentials_mode: CredentialsMode::Include,
             use_url_credentials: true,
--- a/servo/components/script/serviceworker_manager.rs
+++ b/servo/components/script/serviceworker_manager.rs
@@ -11,32 +11,32 @@ use devtools_traits::{DevtoolsPageInfo, 
 use dom::abstractworker::WorkerScriptMsg;
 use dom::bindings::structuredclone::StructuredCloneData;
 use dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg};
 use dom::serviceworkerregistration::longest_prefix_match;
 use ipc_channel::ipc::{self, IpcSender};
 use ipc_channel::router::ROUTER;
 use net_traits::{CustomResponseMediator, CoreResourceMsg};
 use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
+use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
-use url::Url;
 use util::prefs::PREFS;
 use util::thread::spawn_named;
 
 enum Message {
     FromResource(CustomResponseMediator),
     FromConstellation(ServiceWorkerMsg)
 }
 
 pub struct ServiceWorkerManager {
     // map of registered service worker descriptors
-    registered_workers: HashMap<Url, ScopeThings>,
+    registered_workers: HashMap<ServoUrl, ScopeThings>,
     // map of active service worker descriptors
-    active_workers: HashMap<Url, Sender<ServiceWorkerScriptMsg>>,
+    active_workers: HashMap<ServoUrl, Sender<ServiceWorkerScriptMsg>>,
     // own sender to send messages here
     own_sender: IpcSender<ServiceWorkerMsg>,
     // receiver to receive messages from constellation
     own_port: Receiver<ServiceWorkerMsg>,
     // to receive resource messages
     resource_receiver: Receiver<CustomResponseMediator>
 }
 
@@ -62,26 +62,26 @@ impl ServiceWorkerManager {
         let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone()));
         spawn_named("ServiceWorkerManager".to_owned(), move || {
             ServiceWorkerManager::new(own_sender,
                                       from_constellation,
                                       resource_port).handle_message();
         });
     }
 
-    pub fn get_matching_scope(&self, load_url: &Url) -> Option<Url> {
+    pub fn get_matching_scope(&self, load_url: &ServoUrl) -> Option<ServoUrl> {
         for scope in self.registered_workers.keys() {
             if longest_prefix_match(&scope, load_url) {
                 return Some(scope.clone());
             }
         }
         None
     }
 
-    pub fn wakeup_serviceworker(&mut self, scope_url: Url) -> Option<Sender<ServiceWorkerScriptMsg>> {
+    pub fn wakeup_serviceworker(&mut self, scope_url: ServoUrl) -> Option<Sender<ServiceWorkerScriptMsg>> {
         let scope_things = self.registered_workers.get(&scope_url);
         if let Some(scope_things) = scope_things {
             let (sender, receiver) = channel();
             let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
             if let Some(ref chan) = scope_things.devtools_chan {
                 let title = format!("ServiceWorker for {}", scope_things.script_url);
                 let page_info = DevtoolsPageInfo {
                     title: title,
--- a/servo/components/script/webdriver_handlers.rs
+++ b/servo/components/script/webdriver_handlers.rs
@@ -31,17 +31,17 @@ use js::jsapi::{HandleValue, JSContext};
 use js::jsval::UndefinedValue;
 use msg::constellation_msg::PipelineId;
 use net_traits::CookieSource::{HTTP, NonHTTP};
 use net_traits::CoreResourceMsg::{GetCookiesDataForUrl, SetCookiesForUrlWithData};
 use net_traits::IpcSend;
 use script_thread::Documents;
 use script_traits::webdriver_msg::{WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue};
 use script_traits::webdriver_msg::WebDriverCookieError;
-use url::Url;
+use servo_url::ServoUrl;
 
 fn find_node_by_unique_id(documents: &Documents,
                           pipeline: PipelineId,
                           node_id: String)
                           -> Option<Root<Node>> {
     documents.find_document(pipeline).and_then(|document|
         document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
     )
@@ -356,21 +356,21 @@ pub fn handle_get_css(documents: &Docume
                 window.GetComputedStyle(&elem, None).GetPropertyValue(DOMString::from(name))))
         },
         None => Err(())
     }).unwrap();
 }
 
 pub fn handle_get_url(documents: &Documents,
                       pipeline: PipelineId,
-                      reply: IpcSender<Url>) {
+                      reply: IpcSender<ServoUrl>) {
     // TODO: Return an error if the pipeline doesn't exist.
     let url = documents.find_document(pipeline)
         .map(|document| document.url().clone())
-        .unwrap_or_else(|| Url::parse("about:blank").expect("infallible"));
+        .unwrap_or_else(|| ServoUrl::parse("about:blank").expect("infallible"));
     reply.send(url).unwrap();
 }
 
 pub fn handle_is_enabled(documents: &Documents,
                          pipeline: PipelineId,
                          element_id: String,
                          reply: IpcSender<Result<bool, ()>>) {
     reply.send(match find_node_by_unique_id(&documents, pipeline, element_id) {
--- a/servo/components/script_layout_interface/Cargo.toml
+++ b/servo/components/script_layout_interface/Cargo.toml
@@ -25,10 +25,10 @@ log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 script_traits = {path = "../script_traits"}
 selectors = "0.14"
 servo_atoms = {path = "../atoms"}
+servo_url = {path = "../url"}
 style = {path = "../style"}
-url = {version = "1.2", features = ["heap_size"]}
--- a/servo/components/script_layout_interface/lib.rs
+++ b/servo/components/script_layout_interface/lib.rs
@@ -31,18 +31,18 @@ extern crate libc;
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 extern crate profile_traits;
 extern crate range;
 extern crate script_traits;
 extern crate selectors;
 #[macro_use] extern crate servo_atoms;
+extern crate servo_url;
 extern crate style;
-extern crate url;
 
 pub mod message;
 pub mod reporter;
 pub mod rpc;
 pub mod wrapper_traits;
 
 use canvas_traits::CanvasMsg;
 use core::nonzero::NonZero;
--- a/servo/components/script_layout_interface/message.rs
+++ b/servo/components/script_layout_interface/message.rs
@@ -10,22 +10,22 @@ use gfx_traits::Epoch;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use msg::constellation_msg::PipelineId;
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::mem::ReportsChan;
 use rpc::LayoutRPC;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
 use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
 use servo_atoms::Atom;
+use servo_url::ServoUrl;
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender};
 use style::context::ReflowGoal;
 use style::selector_impl::PseudoElement;
 use style::stylesheets::Stylesheet;
-use url::Url;
 
 /// Asynchronous messages that script can send to layout.
 pub enum Msg {
     /// Adds the given stylesheet to the document.
     AddStylesheet(Arc<Stylesheet>),
 
     /// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
     SetQuirksMode,
@@ -74,17 +74,17 @@ pub enum Msg {
     GetWebFontLoadState(IpcSender<bool>),
 
     /// Creates a new layout thread.
     ///
     /// This basically exists to keep the script-layout dependency one-way.
     CreateLayoutThread(NewLayoutThreadInfo),
 
     /// Set the final Url.
-    SetFinalUrl(Url),
+    SetFinalUrl(ServoUrl),
 
     /// Tells layout about the new scrolling offsets of each scrollable stacking context.
     SetStackingContextScrollStates(Vec<StackingContextScrollState>),
 }
 
 
 /// Any query to perform with this reflow.
 #[derive(PartialEq)]
@@ -130,17 +130,17 @@ pub struct ScriptReflow {
 impl Drop for ScriptReflow {
     fn drop(&mut self) {
         self.script_join_chan.send(()).unwrap();
     }
 }
 
 pub struct NewLayoutThreadInfo {
     pub id: PipelineId,
-    pub url: Url,
+    pub url: ServoUrl,
     pub is_parent: bool,
     pub layout_pair: (Sender<Msg>, Receiver<Msg>),
     pub pipeline_port: IpcReceiver<LayoutControlMsg>,
     pub constellation_chan: IpcSender<ConstellationMsg>,
     pub script_chan: IpcSender<ConstellationControlMsg>,
     pub image_cache_thread: ImageCacheThread,
     pub content_process_shutdown_chan: IpcSender<()>,
     pub layout_threads: usize,
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -7,27 +7,27 @@
 use HTMLCanvasData;
 use LayoutNodeType;
 use OpaqueStyleAndLayoutData;
 use SVGSVGData;
 use gfx_traits::ByteIndex;
 use html5ever_atoms::{Namespace, LocalName};
 use msg::constellation_msg::PipelineId;
 use range::Range;
+use servo_url::ServoUrl;
 use std::fmt::Debug;
 use std::sync::Arc;
 use style::atomic_refcell::AtomicRefCell;
 use style::computed_values::display;
 use style::context::SharedStyleContext;
 use style::data::ElementData;
 use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TNode};
 use style::dom::OpaqueNode;
 use style::properties::ServoComputedValues;
 use style::selector_impl::{PseudoElement, PseudoElementCascadeType, RestyleDamage, ServoSelectorImpl};
-use url::Url;
 
 #[derive(Copy, PartialEq, Clone, Debug)]
 pub enum PseudoElementType<T> {
     Normal,
     Before(T),
     After(T),
     DetailsSummary(T),
     DetailsContent(T),
@@ -244,19 +244,17 @@ pub trait ThreadSafeLayoutNode: Clone + 
     fn can_be_fragmented(&self) -> bool;
 
     fn node_text_content(&self) -> String;
 
     /// If the insertion point is within this node, returns it. Otherwise, returns `None`.
     fn selection(&self) -> Option<Range<ByteIndex>>;
 
     /// If this is an image element, returns its URL. If this is not an image element, fails.
-    ///
-    /// FIXME(pcwalton): Don't copy URLs.
-    fn image_url(&self) -> Option<Url>;
+    fn image_url(&self) -> Option<ServoUrl>;
 
     fn canvas_data(&self) -> Option<HTMLCanvasData>;
 
     fn svg_data(&self) -> Option<SVGSVGData>;
 
     /// If this node is an iframe element, returns its pipeline ID. If this node is
     /// not an iframe element, fails.
     fn iframe_pipeline_id(&self) -> PipelineId;
--- a/servo/components/script_traits/Cargo.toml
+++ b/servo/components/script_traits/Cargo.toml
@@ -26,11 +26,12 @@ libc = "0.2"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 offscreen_gl_context = "0.4"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rustc-serialize = "0.3.4"
 serde = "0.8"
 serde_derive = "0.8"
+servo_url = {path = "../url", features = ["servo"]}
 style_traits = {path = "../style_traits", features = ["servo"]}
 time = "0.1.12"
 url = {version = "1.2", features = ["heap_size"]}
--- a/servo/components/script_traits/lib.rs
+++ b/servo/components/script_traits/lib.rs
@@ -26,19 +26,19 @@ extern crate libc;
 extern crate msg;
 extern crate net_traits;
 extern crate offscreen_gl_context;
 extern crate profile_traits;
 extern crate rustc_serialize;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_url;
 extern crate style_traits;
 extern crate time;
-extern crate url;
 
 mod script_msg;
 pub mod webdriver_msg;
 
 use bluetooth_traits::BluetoothRequest;
 use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
 use euclid::Size2D;
 use euclid::length::Length;
@@ -59,21 +59,21 @@ use msg::constellation_msg::{PipelineId,
 use net_traits::{ReferrerPolicy, ResourceThreads};
 use net_traits::image::base::Image;
 use net_traits::image_cache_thread::ImageCacheThread;
 use net_traits::response::HttpsState;
 use net_traits::storage_thread::StorageType;
 use profile_traits::mem;
 use profile_traits::time as profile_time;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::fmt;
 use std::sync::mpsc::{Receiver, Sender};
 use style_traits::{PagePx, UnsafeNode, ViewportPx};
-use url::Url;
 use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
 
 pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
 pub use script_msg::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
 
 /// The address of a node. Layout sends these back. They must be validated via
 /// `from_untrusted_node_address` before they can be used, because we do not trust layout.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -126,36 +126,36 @@ pub enum LayoutControlMsg {
 }
 
 /// Similar to `net::resource_thread::LoadData`
 /// can be passed to `LoadUrl` to load a page with GET/POST
 /// parameters or headers
 #[derive(Clone, Deserialize, Serialize)]
 pub struct LoadData {
     /// The URL.
-    pub url: Url,
+    pub url: ServoUrl,
     /// The method.
     #[serde(deserialize_with = "::hyper_serde::deserialize",
             serialize_with = "::hyper_serde::serialize")]
     pub method: Method,
     /// The headers.
     #[serde(deserialize_with = "::hyper_serde::deserialize",
             serialize_with = "::hyper_serde::serialize")]
     pub headers: Headers,
     /// The data.
     pub data: Option<Vec<u8>>,
     /// The referrer policy.
     pub referrer_policy: Option<ReferrerPolicy>,
     /// The referrer URL.
-    pub referrer_url: Option<Url>,
+    pub referrer_url: Option<ServoUrl>,
 }
 
 impl LoadData {
     /// Create a new `LoadData` object.
-    pub fn new(url: Url, referrer_policy: Option<ReferrerPolicy>, referrer_url: Option<Url>) -> LoadData {
+    pub fn new(url: ServoUrl, referrer_policy: Option<ReferrerPolicy>, referrer_url: Option<ServoUrl>) -> LoadData {
         LoadData {
             url: url,
             method: Method::Get,
             headers: Headers::new(),
             data: None,
             referrer_policy: referrer_policy,
             referrer_url: referrer_url,
         }
@@ -242,17 +242,17 @@ pub enum ConstellationControlMsg {
         target: FrameId,
         /// The pipeline that contains a frame loading the target pipeline.
         parent: PipelineId,
         /// The pipeline that has completed loading.
         child: PipelineId,
     },
     /// Cause a `storage` event to be dispatched at the appropriate window.
     /// The strings are key, old value and new value.
-    DispatchStorageEvent(PipelineId, StorageType, Url, Option<String>, Option<String>, Option<String>),
+    DispatchStorageEvent(PipelineId, StorageType, ServoUrl, Option<String>, Option<String>, Option<String>),
     /// Notifies a parent pipeline that one of its child frames is now active.
     /// PipelineId is for the parent, FrameId is the child frame.
     FramedContentChanged(PipelineId, FrameId),
     /// Report an error from a CSS parser for the given pipeline
     ReportCSSError(PipelineId, String, usize, usize, String),
     /// Reload the given page.
     Reload(PipelineId)
 }
@@ -677,17 +677,17 @@ pub enum ConstellationMsg {
     /// Request that the constellation send the current pipeline id for the provided frame
     /// id, or for the root frame if this is None, over a provided channel.
     /// Also returns a boolean saying whether the document has finished loading or not.
     GetPipeline(Option<FrameId>, IpcSender<Option<(PipelineId, bool)>>),
     /// Requests that the constellation inform the compositor of the title of the pipeline
     /// immediately.
     GetPipelineTitle(PipelineId),
     /// Request to load the initial page.
-    InitLoadUrl(Url),
+    InitLoadUrl(ServoUrl),
     /// Query the constellation to see if the current compositor output is stable
     IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
     /// Inform the constellation of a key event.
     KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
     /// Request to load a page.
     LoadUrl(PipelineId, LoadData),
     /// Request to traverse the joint session history.
     TraverseHistory(Option<PipelineId>, TraversalDirection),
@@ -725,14 +725,14 @@ pub struct WorkerGlobalScopeInit {
     /// The pipeline id
     pub pipeline_id: PipelineId,
 }
 
 /// Common entities representing a network load origin
 #[derive(Deserialize, Serialize, Clone)]
 pub struct WorkerScriptLoadOrigin {
     /// referrer url
-    pub referrer_url: Option<Url>,
+    pub referrer_url: Option<ServoUrl>,
     /// the referrer policy which is used
     pub referrer_policy: Option<ReferrerPolicy>,
     /// the pipeline id of the entity requesting the load
     pub pipeline_id: Option<PipelineId>
 }
--- a/servo/components/script_traits/script_msg.rs
+++ b/servo/components/script_traits/script_msg.rs
@@ -15,19 +15,19 @@ use devtools_traits::{ScriptToDevtoolsCo
 use euclid::point::Point2D;
 use euclid::size::Size2D;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::{Key, KeyModifiers, KeyState};
 use msg::constellation_msg::{PipelineId, TraversalDirection};
 use net_traits::CoreResourceMsg;
 use net_traits::storage_thread::StorageType;
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
+use servo_url::ServoUrl;
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
-use url::Url;
 
 /// Messages from the layout to the constellation.
 #[derive(Deserialize, Serialize)]
 pub enum LayoutMsg {
     /// Indicates whether this pipeline is currently running animations.
     ChangeRunningAnimationsState(PipelineId, AnimationState),
     /// Requests that the constellation inform the compositor of the a cursor change.
     SetCursor(Cursor),
@@ -57,17 +57,17 @@ pub enum LogEntry {
     Warn(String)
 }
 
 /// Messages from the script to the constellation.
 #[derive(Deserialize, Serialize)]
 pub enum ScriptMsg {
     /// Broadcast a storage event to every same-origin pipeline.
     /// The strings are key, old value and new value.
-    BroadcastStorageEvent(PipelineId, StorageType, Url, Option<String>, Option<String>, Option<String>),
+    BroadcastStorageEvent(PipelineId, StorageType, ServoUrl, Option<String>, Option<String>, Option<String>),
     /// Indicates whether this pipeline is currently running animations.
     ChangeRunningAnimationsState(PipelineId, AnimationState),
     /// Requests that a new 2D canvas thread be created. (This is done in the constellation because
     /// 2D canvases may use the GPU and we don't want to give untrusted content access to the GPU.)
     CreateCanvasPaintThread(Size2D<i32>, IpcSender<IpcSender<CanvasMsg>>),
     /// Requests that a new WebGL thread be created. (This is done in the constellation because
     /// WebGL uses the GPU and we don't want to give untrusted content access to the GPU.)
     CreateWebGLPaintThread(Size2D<i32>,
@@ -90,17 +90,17 @@ pub enum ScriptMsg {
     /// Dispatch a mozbrowser event to the parent of this pipeline.
     /// The first PipelineId is for the parent, the second is for the originating pipeline.
     MozBrowserEvent(PipelineId, PipelineId, MozBrowserEvent),
     /// HTMLIFrameElement Forward or Back traversal.
     TraverseHistory(Option<PipelineId>, TraversalDirection),
     /// Gets the length of the joint session history from the constellation.
     JointSessionHistoryLength(PipelineId, IpcSender<u32>),
     /// Favicon detected
-    NewFavicon(Url),
+    NewFavicon(ServoUrl),
     /// Status message to be displayed in the chrome, eg. a link URL on mouseover.
     NodeStatus(Option<String>),
     /// Notification that this iframe should be removed.
     RemoveIFrame(PipelineId, Option<IpcSender<()>>),
     /// Change pipeline visibility
     SetVisible(PipelineId, bool),
     /// Notifies constellation that an iframe's visibility has been changed.
     VisibilityChangeComplete(PipelineId, bool),
@@ -108,17 +108,17 @@ pub enum ScriptMsg {
     ScriptLoadedURLInIFrame(IFrameLoadInfo),
     /// Requests that the constellation set the contents of the clipboard
     SetClipboardContents(String),
     /// Mark a new document as active
     ActivateDocument(PipelineId),
     /// Set the document state for a pipeline (used by screenshot / reftests)
     SetDocumentState(PipelineId, DocumentState),
     /// Update the pipeline Url, which can change after redirections.
-    SetFinalUrl(PipelineId, Url),
+    SetFinalUrl(PipelineId, ServoUrl),
     /// Check if an alert dialog box should be presented
     Alert(PipelineId, String, IpcSender<bool>),
     /// Scroll a page in a window
     ScrollFragmentPoint(PipelineId, Point2D<f32>, bool),
     /// Set title of current page
     /// https://html.spec.whatwg.org/multipage/#document.title
     SetTitle(PipelineId, Option<String>),
     /// Send a key event
@@ -132,28 +132,28 @@ pub enum ScriptMsg {
     /// Script has handled a touch event, and either prevented or allowed default actions.
     TouchEventProcessed(EventResult),
     /// A log entry, with the pipeline id and thread name
     LogEntry(Option<PipelineId>, Option<String>, LogEntry),
     /// Notifies the constellation that this pipeline has exited.
     PipelineExited(PipelineId),
     /// Send messages from postMessage calls from serviceworker
     /// to constellation for storing in service worker manager
-    ForwardDOMMessage(DOMMessage, Url),
+    ForwardDOMMessage(DOMMessage, ServoUrl),
     /// Store the data required to activate a service worker for the given scope
-    RegisterServiceWorker(ScopeThings, Url),
+    RegisterServiceWorker(ScopeThings, ServoUrl),
     /// Requests that the compositor shut down.
     Exit
 }
 
 /// Entities required to spawn service workers
 #[derive(Deserialize, Serialize, Clone)]
 pub struct ScopeThings {
     /// script resource url
-    pub script_url: Url,
+    pub script_url: ServoUrl,
     /// network load origin of the resource
     pub worker_load_origin: WorkerScriptLoadOrigin,
     /// base resources required to create worker global scopes
     pub init: WorkerGlobalScopeInit,
     /// the port to receive devtools message from
     pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
     /// service worker id
     pub worker_id: WorkerId,
@@ -170,21 +170,21 @@ pub struct SWManagerSenders {
     /// sender for communicating with resource thread
     pub resource_sender: IpcSender<CoreResourceMsg>
 }
 
 /// Messages sent to Service Worker Manager thread
 #[derive(Deserialize, Serialize)]
 pub enum ServiceWorkerMsg {
     /// Message to register the service worker
-    RegisterServiceWorker(ScopeThings, Url),
+    RegisterServiceWorker(ScopeThings, ServoUrl),
     /// Timeout message sent by active service workers
-    Timeout(Url),
+    Timeout(ServoUrl),
     /// Message sent by constellation to forward to a running service worker
-    ForwardDOMMessage(DOMMessage, Url),
+    ForwardDOMMessage(DOMMessage, ServoUrl),
     /// Exit the service worker manager
     Exit,
 }
 
 /// Messages outgoing from the Service Worker Manager thread to constellation
 #[derive(Deserialize, Serialize)]
 pub enum SWManagerMsg {
     /// Provide the constellation with a means of communicating with the Service Worker Manager
--- a/servo/components/script_traits/webdriver_msg.rs
+++ b/servo/components/script_traits/webdriver_msg.rs
@@ -5,17 +5,17 @@
 #![allow(missing_docs)]
 
 use cookie_rs::Cookie;
 use euclid::rect::Rect;
 use hyper_serde::Serde;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
 use rustc_serialize::json::{Json, ToJson};
-use url::Url;
+use servo_url::ServoUrl;
 
 #[derive(Deserialize, Serialize)]
 pub enum WebDriverScriptCommand {
     AddCookie(
         #[serde(deserialize_with = "::hyper_serde::deserialize",
                 serialize_with = "::hyper_serde::serialize")]
         Cookie,
         IpcSender<Result<(), WebDriverCookieError>>
@@ -29,17 +29,17 @@ pub enum WebDriverScriptCommand {
     GetCookie(String, IpcSender<Vec<Serde<Cookie>>>),
     GetCookies(IpcSender<Vec<Serde<Cookie>>>),
     GetElementAttribute(String, String, IpcSender<Result<Option<String>, ()>>),
     GetElementCSS(String, String, IpcSender<Result<String, ()>>),
     GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>),
     GetElementTagName(String, IpcSender<Result<String, ()>>),
     GetElementText(String, IpcSender<Result<String, ()>>),
     GetFrameId(WebDriverFrameId, IpcSender<Result<Option<PipelineId>, ()>>),
-    GetUrl(IpcSender<Url>),
+    GetUrl(IpcSender<ServoUrl>),
     IsEnabled(String, IpcSender<Result<bool, ()>>),
     IsSelected(String, IpcSender<Result<bool, ()>>),
     GetTitle(IpcSender<String>)
 }
 
 #[derive(Deserialize, Serialize)]
 pub enum WebDriverCookieError {
     InvalidDomain,
--- a/servo/components/servo/Cargo.toml
+++ b/servo/components/servo/Cargo.toml
@@ -52,16 +52,17 @@ msg = {path = "../msg"}
 net = {path = "../net"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins", optional = true}
 profile = {path = "../profile"}
 profile_traits = {path = "../profile_traits"}
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
+servo_url = {path = "../url"}
 style = {path = "../style", features = ["servo"]}
 url = "1.2"
 util = {path = "../util"}
 webdriver_server = {path = "../webdriver_server", optional = true}
 
 [dependencies.webrender]
 git = "https://github.com/servo/webrender"
 default-features = false
--- a/servo/components/servo/lib.rs
+++ b/servo/components/servo/lib.rs
@@ -40,16 +40,17 @@ pub extern crate layout_thread;
 pub extern crate msg;
 pub extern crate net;
 pub extern crate net_traits;
 pub extern crate profile;
 pub extern crate profile_traits;
 pub extern crate script;
 pub extern crate script_traits;
 pub extern crate script_layout_interface;
+pub extern crate servo_url;
 pub extern crate style;
 pub extern crate url;
 pub extern crate util;
 
 #[cfg(feature = "webdriver")]
 extern crate webdriver_server;
 
 extern crate webrender;
@@ -82,22 +83,22 @@ use log::{Log, LogMetadata, LogRecord};
 use net::image_cache_thread::new_image_cache_thread;
 use net::resource_thread::new_resource_threads;
 use net_traits::IpcSend;
 use profile::mem as profile_mem;
 use profile::time as profile_time;
 use profile_traits::mem;
 use profile_traits::time;
 use script_traits::{ConstellationMsg, SWManagerSenders, ScriptMsg};
+use servo_url::ServoUrl;
 use std::borrow::Cow;
 use std::cmp::max;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
-use url::Url;
 use util::opts;
 use util::prefs::PREFS;
 use util::resource_files::resources_dir_path;
 
 pub use gleam::gl;
 
 /// The in-process interface to Servo.
 ///
@@ -244,17 +245,17 @@ impl<Window> Browser<Window> where Windo
             max_log_level.set(filter);
             Box::new(logger)
         }).expect("Failed to set logger.")
     }
 }
 
 fn create_constellation(user_agent: Cow<'static, str>,
                         config_dir: Option<PathBuf>,
-                        url: Option<Url>,
+                        url: Option<ServoUrl>,
                         compositor_proxy: Box<CompositorProxy + Send>,
                         time_profiler_chan: time::ProfilerChan,
                         mem_profiler_chan: mem::ProfilerChan,
                         debugger_chan: Option<debugger::Sender>,
                         devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                         supports_clipboard: bool,
                         webrender_api_sender: webrender_traits::RenderApiSender)
                         -> (Sender<ConstellationMsg>, SWManagerSenders) {
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -12,17 +12,17 @@ name = "style"
 path = "lib.rs"
 doctest = false
 
 [features]
 gecko = ["nsstring_vendor", "num_cpus", "rayon/unstable"]
 servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive",
          "style_traits/servo", "app_units/plugins", "servo_atoms", "html5ever-atoms",
          "cssparser/heap_size", "cssparser/serde-serialization",
-         "url/heap_size", "plugins", "rayon/unstable"]
+         "plugins", "rayon/unstable", "servo_url/servo"]
 testing = []
 
 [dependencies]
 app_units = "0.3"
 bitflags = "0.7"
 cfg-if = "0.1.0"
 cssparser = "0.7"
 encoding = "0.2"
@@ -45,19 +45,19 @@ rand = "0.3"
 rayon = "0.5"
 rustc-serialize = "0.3"
 selectors = "0.14"
 serde = {version = "0.8", optional = true}
 serde_derive = {version = "0.8", optional = true}
 servo_atoms = {path = "../atoms", optional = true}
 smallvec = "0.1"
 style_traits = {path = "../style_traits"}
+servo_url = {path = "../url"}
 time = "0.1"
 unicode-segmentation = "0.1.2"
-url = "1.2"
 util = {path = "../util"}
 plugins = {path = "../plugins", optional = true}
 
 [dependencies.num_cpus]
 optional = true
 version = "1.0"
 
 [target.'cfg(windows)'.dependencies]
--- a/servo/components/style/attr.rs
+++ b/servo/components/style/attr.rs
@@ -6,22 +6,22 @@
 //!
 //! [attr]: https://dom.spec.whatwg.org/#interface-attr
 
 use {Atom, Prefix, Namespace, LocalName};
 use app_units::Au;
 use cssparser::{self, Color, RGBA};
 use euclid::num::Zero;
 use num_traits::ToPrimitive;
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::str::FromStr;
 use str::{HTML_SPACE_CHARACTERS, read_exponent, read_fraction};
 use str::{read_numbers, split_commas, split_html_space_chars};
 #[cfg(not(feature = "gecko"))] use str::str_join;
-use url::Url;
 use values::specified::Length;
 
 // Duplicated from script::dom::values.
 const UNSIGNED_LONG_MAX: u32 = 2147483647;
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum LengthOrPercentageOrAuto {
@@ -37,17 +37,17 @@ pub enum AttrValue {
     TokenList(String, Vec<Atom>),
     UInt(String, u32),
     Int(String, i32),
     Double(String, f64),
     Atom(Atom),
     Length(String, Option<Length>),
     Color(String, Option<RGBA>),
     Dimension(String, LengthOrPercentageOrAuto),
-    Url(String, Option<Url>),
+    Url(String, Option<ServoUrl>),
 }
 
 /// Shared implementation to parse an integer according to
 /// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-integers> or
 /// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-negative-integers>
 fn do_parse_integer<T: Iterator<Item=char>>(input: T) -> Result<i64, ()> {
     let mut input = input.skip_while(|c| {
         HTML_SPACE_CHARACTERS.iter().any(|s| s == c)
@@ -203,17 +203,17 @@ impl AttrValue {
         AttrValue::UInt(string, result)
     }
 
     pub fn from_atomic(string: String) -> AttrValue {
         let value = Atom::from(string);
         AttrValue::Atom(value)
     }
 
-    pub fn from_url(base: &Url, url: String) -> AttrValue {
+    pub fn from_url(base: &ServoUrl, url: String) -> AttrValue {
         let joined = base.join(&url).ok();
         AttrValue::Url(url, joined)
     }
 
     pub fn from_legacy_color(string: String) -> AttrValue {
         let parsed = parse_legacy_color(&string).ok();
         AttrValue::Color(string, parsed)
     }
@@ -288,17 +288,17 @@ impl AttrValue {
         }
     }
 
     /// Assumes the `AttrValue` is a `Url` and returns its value
     ///
     /// ## Panics
     ///
     /// Panics if the `AttrValue` is not a `Url`
-    pub fn as_url(&self) -> Option<&Url> {
+    pub fn as_url(&self) -> Option<&ServoUrl> {
         match *self {
             AttrValue::Url(_, ref url) => url.as_ref(),
             _ => panic!("Url not found"),
         }
     }
 
     /// Return the AttrValue as its integer representation, if any.
     /// This corresponds to attribute values returned as `AttrValue::UInt(_)`
--- a/servo/components/style/font_face.rs
+++ b/servo/components/style/font_face.rs
@@ -6,29 +6,29 @@
 //!
 //! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule
 
 use computed_values::font_family::FontFamily;
 use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
 use parser::{ParserContext, log_css_error};
 use properties::longhands::font_family::parse_one_family;
 use std::iter;
-use url::Url;
+use values::specified::url::SpecifiedUrl;
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
 pub enum Source {
     Url(UrlSource),
     Local(FontFamily),
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
 pub struct UrlSource {
-    pub url: Url,
+    pub url: SpecifiedUrl,
     pub format_hints: Vec<String>,
 }
 
 #[derive(Debug, PartialEq, Eq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct FontFaceRule {
     pub family: FontFamily,
     pub sources: Vec<Source>,
@@ -134,19 +134,18 @@ impl<'a, 'b> DeclarationParser for FontF
         }
     }
 }
 
 fn parse_one_src(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
     if input.try(|input| input.expect_function_matching("local")).is_ok() {
         return Ok(Source::Local(try!(input.parse_nested_block(parse_one_family))))
     }
-    let url = try!(input.expect_url());
-    let url = context.base_url.join(&url).unwrap_or_else(
-        |_error| Url::parse("about:invalid").unwrap());
+
+    let url = try!(SpecifiedUrl::parse(context, input));
 
     // Parsing optional format()
     let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
         try!(input.parse_nested_block(|input| {
             input.parse_comma_separated(|input| {
                 Ok((try!(input.expect_string())).into_owned())
             })
         }))
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -31,22 +31,22 @@ use gecko_bindings::structs::{nsIAtom, n
 use parking_lot::RwLock;
 use parser::ParserContextExtraData;
 use properties::{ComputedValues, parse_style_attribute};
 use properties::PropertyDeclarationBlock;
 use selector_impl::ElementExt;
 use selector_matching::ApplicableDeclarationBlock;
 use selectors::Element;
 use selectors::parser::{AttrSelector, NamespaceConstraint};
+use servo_url::ServoUrl;
 use sink::Push;
 use std::fmt;
 use std::ptr;
 use std::sync::Arc;
 use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
-use url::Url;
 
 // Important: We don't currently refcount the DOM, because the wrapper lifetime
 // magic guarantees that our LayoutFoo references won't outlive the root, and
 // we don't mutate any of the references on the Gecko side during restyle. We
 // could implement refcounting if need be (at a potentially non-trivial
 // performance cost) by implementing Drop and making LayoutFoo non-Copy.
 #[derive(Clone, Copy)]
 pub struct GeckoNode<'ln>(pub &'ln RawGeckoNode);
@@ -276,18 +276,18 @@ impl<'le> GeckoElement<'le> {
                 self.raw_node().mServoData.set(ptr);
                 unsafe { &* ptr }
             },
         }
     }
 }
 
 lazy_static! {
-    pub static ref DUMMY_BASE_URL: Url = {
-        Url::parse("http://www.example.org").unwrap()
+    pub static ref DUMMY_BASE_URL: ServoUrl = {
+        ServoUrl::parse("http://www.example.org").unwrap()
     };
 }
 
 impl<'le> TElement for GeckoElement<'le> {
     type ConcreteNode = GeckoNode<'le>;
 
     fn as_node(&self) -> Self::ConcreteNode {
         unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -74,23 +74,23 @@ extern crate parking_lot;
 extern crate quickersort;
 extern crate rayon;
 extern crate rustc_serialize;
 extern crate selectors;
 #[cfg(feature = "servo")]
 extern crate serde;
 #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
 #[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
+extern crate servo_url;
 extern crate smallvec;
 #[macro_use]
 extern crate style_traits;
 extern crate time;
 #[allow(unused_extern_crates)]
 extern crate unicode_segmentation;
-extern crate url;
 extern crate util;
 
 pub mod animation;
 pub mod atomic_refcell;
 pub mod attr;
 pub mod bezier;
 pub mod cache;
 pub mod cascade_info;
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -5,18 +5,18 @@
 //! The context within which CSS code is parsed.
 
 use cssparser::{Parser, SourcePosition};
 use error_reporting::ParseErrorReporter;
 #[cfg(feature = "gecko")]
 use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
 use selector_impl::TheSelectorImpl;
 use selectors::parser::ParserContext as SelectorParserContext;
+use servo_url::ServoUrl;
 use stylesheets::Origin;
-use url::Url;
 
 #[cfg(not(feature = "gecko"))]
 pub struct ParserContextExtraData;
 
 #[cfg(feature = "gecko")]
 pub struct ParserContextExtraData {
     pub base: Option<GeckoArcURI>,
     pub referrer: Option<GeckoArcURI>,
@@ -32,39 +32,39 @@ impl ParserContextExtraData {
     #[cfg(feature = "gecko")]
     pub fn default() -> ParserContextExtraData {
         ParserContextExtraData { base: None, referrer: None, principal: None }
     }
 }
 
 pub struct ParserContext<'a> {
     pub stylesheet_origin: Origin,
-    pub base_url: &'a Url,
+    pub base_url: &'a ServoUrl,
     pub selector_context: SelectorParserContext<TheSelectorImpl>,
     pub error_reporter: Box<ParseErrorReporter + Send>,
     pub extra_data: ParserContextExtraData,
 }
 
 impl<'a> ParserContext<'a> {
-    pub fn new_with_extra_data(stylesheet_origin: Origin, base_url: &'a Url,
+    pub fn new_with_extra_data(stylesheet_origin: Origin, base_url: &'a ServoUrl,
                                error_reporter: Box<ParseErrorReporter + Send>,
                                extra_data: ParserContextExtraData)
                                -> ParserContext<'a> {
         let mut selector_context = SelectorParserContext::new();
         selector_context.in_user_agent_stylesheet = stylesheet_origin == Origin::UserAgent;
         ParserContext {
             stylesheet_origin: stylesheet_origin,
             base_url: base_url,
             selector_context: selector_context,
             error_reporter: error_reporter,
             extra_data: extra_data,
         }
     }
 
-    pub fn new(stylesheet_origin: Origin, base_url: &'a Url, error_reporter: Box<ParseErrorReporter + Send>)
+    pub fn new(stylesheet_origin: Origin, base_url: &'a ServoUrl, error_reporter: Box<ParseErrorReporter + Send>)
                -> ParserContext<'a> {
         let extra_data = ParserContextExtraData::default();
         ParserContext::new_with_extra_data(stylesheet_origin, base_url, error_reporter, extra_data)
     }
 }
 
 /// Defaults to a no-op.
 /// Set a `RUST_LOG=style::errors` environment variable
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -1,23 +1,23 @@
 /* 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 cssparser::{DeclarationListParser, parse_important};
 use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
 use error_reporting::ParseErrorReporter;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
+use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::boxed::Box as StdBox;
 use std::fmt;
 use style_traits::ToCss;
 use stylesheets::Origin;
 use super::*;
-use url::Url;
 
 
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum Importance {
     /// Indicates a declaration without `!important`.
     Normal,
 
@@ -418,24 +418,29 @@ pub fn append_serialization<'a, W, I>(de
          },
          &AppendableValue::DeclarationsForShorthand(..) => try!(write!(dest, " "))
     }
 
     try!(append_declaration_value(dest, appendable_value, importance));
     write!(dest, ";")
 }
 
-pub fn parse_style_attribute(input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
+pub fn parse_style_attribute(input: &str,
+                             base_url: &ServoUrl,
+                             error_reporter: StdBox<ParseErrorReporter + Send>,
                              extra_data: ParserContextExtraData)
                              -> PropertyDeclarationBlock {
     let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
     parse_property_declaration_list(&context, &mut Parser::new(input))
 }
 
-pub fn parse_one_declaration(name: &str, input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
+pub fn parse_one_declaration(name: &str,
+                             input: &str,
+                             base_url: &ServoUrl,
+                             error_reporter: StdBox<ParseErrorReporter + Send>,
                              extra_data: ParserContextExtraData)
                              -> Result<Vec<PropertyDeclaration>, ()> {
     let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
     let mut results = vec![];
     match PropertyDeclaration::parse(name, &context, &mut Parser::new(input), &mut results, false) {
         PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(results),
         _ => Err(())
     }
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -16,24 +16,24 @@ use std::collections::HashSet;
 use std::fmt::{self, Write};
 use std::sync::Arc;
 
 use Atom;
 use app_units::Au;
 #[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
 use cssparser::{Parser, TokenSerializationType};
 use error_reporting::ParseErrorReporter;
-use url::Url;
 #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
 use euclid::size::Size2D;
 use computed_values;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
 use logical_geometry::WritingMode;
 use parser::{Parse, ParserContext, ParserContextExtraData};
+use servo_url::ServoUrl;
 use style_traits::ToCss;
 use stylesheets::Origin;
 #[cfg(feature = "servo")] use values::Either;
 use values::{HasViewportPercentage, computed};
 use cascade_info::CascadeInfo;
 use rule_tree::StrongRuleNode;
 #[cfg(feature = "servo")] use values::specified::BorderStyle;
 
@@ -235,17 +235,17 @@ mod property_bit_field {
             }
         }
 
         #[allow(non_snake_case)]
         #[inline(never)]
         fn substitute_variables_${property.ident}_slow<F>(
                 css: &String,
                 first_token_type: TokenSerializationType,
-                base_url: &Url,
+                base_url: &ServoUrl,
                 from_shorthand: Option<Shorthand>,
                 custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
                 f: F,
                 error_reporter: &mut StdBox<ParseErrorReporter + Send>,
                 extra_data: ParserContextExtraData)
                 where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>) {
             f(&
                 ::custom_properties::substitute(css, first_token_type, custom_properties)
@@ -488,17 +488,17 @@ impl Shorthand {
 
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum DeclaredValue<T> {
     Value(T),
     WithVariables {
         css: String,
         first_token_type: TokenSerializationType,
-        base_url: Url,
+        base_url: ServoUrl,
         from_shorthand: Option<Shorthand>,
     },
     Initial,
     Inherit,
     // There is no Unset variant here.
     // The 'unset' keyword is represented as either Initial or Inherit,
     // depending on whether the property is inherited.
 }
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -13,21 +13,21 @@ use error_reporting::ParseErrorReporter;
 use font_face::{FontFaceRule, parse_font_face_block};
 use keyframes::{Keyframe, parse_keyframe_list};
 use media_queries::{Device, MediaList, parse_media_query_list};
 use parking_lot::RwLock;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
 use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
 use selector_impl::TheSelectorImpl;
 use selectors::parser::{Selector, parse_selector_list};
+use servo_url::ServoUrl;
 use std::cell::Cell;
 use std::fmt;
 use std::sync::Arc;
 use style_traits::ToCss;
-use url::Url;
 use viewport::ViewportRule;
 
 
 /// Each style rule has an origin, which determines where it enters the cascade.
 ///
 /// http://dev.w3.org/csswg/css-cascade/#cascading-origins
 #[derive(Clone, PartialEq, Eq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -166,44 +166,44 @@ impl ToCss for StyleRule {
         try!(dest.write_str("}"));
         Ok(())
     }
 }
 
 
 impl Stylesheet {
     pub fn from_bytes_iter<I: Iterator<Item=Vec<u8>>>(
-            input: I, base_url: Url, protocol_encoding_label: Option<&str>,
+            input: I, base_url: ServoUrl, protocol_encoding_label: Option<&str>,
             environment_encoding: Option<EncodingRef>, origin: Origin,
             error_reporter: Box<ParseErrorReporter + Send>,
             extra_data: ParserContextExtraData) -> Stylesheet {
         let mut bytes = vec![];
         // TODO: incremental decoding and tokenization/parsing
         for chunk in input {
             bytes.extend_from_slice(&chunk)
         }
         Stylesheet::from_bytes(&bytes, base_url, protocol_encoding_label,
                                environment_encoding, origin, error_reporter,
                                extra_data)
     }
 
     pub fn from_bytes(bytes: &[u8],
-                      base_url: Url,
+                      base_url: ServoUrl,
                       protocol_encoding_label: Option<&str>,
                       environment_encoding: Option<EncodingRef>,
                       origin: Origin, error_reporter: Box<ParseErrorReporter + Send>,
                       extra_data: ParserContextExtraData)
                       -> Stylesheet {
         // TODO: bytes.as_slice could be bytes.container_as_bytes()
         let (string, _) = decode_stylesheet_bytes(
             bytes, protocol_encoding_label, environment_encoding);
         Stylesheet::from_str(&string, base_url, origin, error_reporter, extra_data)
     }
 
-    pub fn from_str(css: &str, base_url: Url, origin: Origin,
+    pub fn from_str(css: &str, base_url: ServoUrl, origin: Origin,
                     error_reporter: Box<ParseErrorReporter + Send>,
                     extra_data: ParserContextExtraData) -> Stylesheet {
         let rule_parser = TopLevelRuleParser {
             context: ParserContext::new_with_extra_data(origin, &base_url, error_reporter.clone(),
                                                         extra_data),
             state: Cell::new(State::Start),
         };
         let mut input = Parser::new(css);
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -4,21 +4,20 @@
 
 //! CSS handling for the specified value of
 //! [`image`][image]s
 //!
 //! [image]: https://drafts.csswg.org/css-images/#image-values
 
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
+use servo_url::ServoUrl;
 use std::f32::consts::PI;
 use std::fmt;
-use std::sync::Arc;
 use style_traits::ToCss;
-use url::Url;
 use values::computed::ComputedValueAsSpecified;
 use values::specified::{Angle, CSSColor, Length, LengthOrPercentage};
 use values::specified::position::Position;
 use values::specified::url::{SpecifiedUrl, UrlExtraData};
 
 /// Specified values for an image according to CSS-IMAGES.
 /// https://drafts.csswg.org/css-images/#image-values
 #[derive(Clone, PartialEq, Debug)]
@@ -43,17 +42,17 @@ impl Image {
             return Ok(Image::Url(url));
         }
 
         Ok(Image::Gradient(try!(Gradient::parse_function(input))))
     }
 
     /// Creates an already specified image value from an already resolved URL
     /// for insertion in the cascade.
-    pub fn for_cascade(url: Option<Arc<Url>>, extra_data: UrlExtraData) -> Self {
+    pub fn for_cascade(url: Option<ServoUrl>, extra_data: UrlExtraData) -> Self {
         Image::Url(SpecifiedUrl::for_cascade(url, extra_data))
     }
 }
 
 /// Specified values for a CSS gradient.
 /// https://drafts.csswg.org/css-images/#gradients
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
--- a/servo/components/style/values/specified/url.rs
+++ b/servo/components/style/values/specified/url.rs
@@ -5,25 +5,25 @@
 //! Common handling for the specified value CSS url() values.
 
 use cssparser::{CssStringWriter, Parser};
 #[cfg(feature = "gecko")]
 use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
 use parser::ParserContext;
 #[cfg(feature = "gecko")]
 use parser::ParserContextExtraData;
+use servo_url::ServoUrl;
 use std::fmt::{self, Write};
 use std::ptr;
 use std::sync::Arc;
 use style_traits::ToCss;
-use url::Url;
 use values::computed::ComputedValueAsSpecified;
 
 #[derive(PartialEq, Clone, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize, Eq))]
 pub struct UrlExtraData {
     #[cfg(feature = "gecko")]
     pub base: GeckoArcURI,
     #[cfg(feature = "gecko")]
     pub referrer: GeckoArcURI,
     #[cfg(feature = "gecko")]
     pub principal: GeckoArcPrincipal,
 }
@@ -50,28 +50,28 @@ impl UrlExtraData {
             },
             _ => None,
         }
     }
 }
 
 /// A specified url() value.
 #[derive(Clone, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize))]
 pub struct SpecifiedUrl {
     /// The original URI. This might be optional since we may insert computed
     /// values of images into the cascade directly, and we don't bother to
     /// convert their serialization.
     ///
     /// Refcounted since cloning this should be cheap and data: uris can be
     /// really large.
     original: Option<Arc<String>>,
 
     /// The resolved value for the url, if valid.
-    resolved: Option<Arc<Url>>,
+    resolved: Option<ServoUrl>,
 
     /// Extra data used for Stylo.
     extra_data: UrlExtraData,
 }
 
 impl SpecifiedUrl {
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         let url = try!(input.expect_url());
@@ -83,70 +83,71 @@ impl SpecifiedUrl {
                 // when parsing style attributes and re-parsing due to CSS
                 // Variables.
                 println!("stylo: skipping declaration without ParserContextExtraData");
                 return Err(())
             },
         };
 
         let serialization = Arc::new(url.into_owned());
-        let resolved = context.base_url.join(&serialization).ok().map(Arc::new);
+        let resolved = context.base_url.join(&serialization).ok();
         Ok(SpecifiedUrl {
             original: Some(serialization),
             resolved: resolved,
             extra_data: extra_data,
         })
     }
 
     pub fn extra_data(&self) -> &UrlExtraData {
         &self.extra_data
     }
 
-    pub fn url(&self) -> Option<&Arc<Url>> {
+    pub fn url(&self) -> Option<&ServoUrl> {
         self.resolved.as_ref()
     }
 
     /// Little helper for Gecko's ffi.
     pub fn as_slice_components(&self) -> (*const u8, usize) {
         match self.resolved {
             Some(ref url) => (url.as_str().as_ptr(), url.as_str().len()),
             None => (ptr::null(), 0),
         }
     }
 
     /// Creates an already specified url value from an already resolved URL
     /// for insertion in the cascade.
-    pub fn for_cascade(url: Option<Arc<Url>>, extra_data: UrlExtraData) -> Self {
+    pub fn for_cascade(url: Option<ServoUrl>, extra_data: UrlExtraData) -> Self {
         SpecifiedUrl {
             original: None,
             resolved: url,
             extra_data: extra_data,
         }
     }
 
-    // Just for unit tests, don't use outside of them!
     #[cfg(feature = "servo")]
     pub fn new_for_testing(url: &str) -> Self {
         SpecifiedUrl {
             original: Some(Arc::new(url.into())),
-            resolved: Url::parse(url).ok().map(Arc::new),
+            resolved: ServoUrl::parse(url).ok(),
             extra_data: UrlExtraData {}
         }
     }
 }
 
 impl PartialEq for SpecifiedUrl {
     fn eq(&self, other: &Self) -> bool {
         // TODO(emilio): maybe we care about equality of the specified values if
         // present? Seems not.
         self.resolved == other.resolved &&
             self.extra_data == other.extra_data
     }
 }
 
+impl Eq for SpecifiedUrl {}
+
 impl ToCss for SpecifiedUrl {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         try!(dest.write_str("url(\""));
         let string = match self.original {
             Some(ref original) => &**original,
             None => match self.resolved {
                 Some(ref url) => url.as_str(),
                 // This can only happen if the url wasn't specified by the
new file mode 100644
--- /dev/null
+++ b/servo/components/url/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "servo_url"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+publish = false
+
+[lib]
+name = "servo_url"
+path = "lib.rs"
+
+[features]
+servo = ["heapsize", "heapsize_derive", "serde", "serde_derive",
+         "url/heap_size"]
+
+
+[dependencies]
+url = "1.2"
+heapsize = {version = "0.3.0", optional = true}
+heapsize_derive = {version = "0.1", optional = true}
+serde = {version = "0.8", optional = true}
+serde_derive = {version = "0.8", optional = true}
new file mode 100644
--- /dev/null
+++ b/servo/components/url/lib.rs
@@ -0,0 +1,150 @@
+/* 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/. */
+
+#![deny(unsafe_code)]
+
+#![crate_name = "servo_url"]
+#![crate_type = "rlib"]
+
+#![cfg_attr(feature = "servo", feature(plugin))]
+#![cfg_attr(feature = "servo", feature(proc_macro))]
+
+#[cfg(feature = "servo")] extern crate serde;
+#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
+#[cfg(feature = "servo")] extern crate heapsize;
+#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
+
+extern crate url;
+
+use std::fmt;
+use std::net::IpAddr;
+use std::path::Path;
+use std::sync::Arc;
+use url::{Url, Origin};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize))]
+pub struct ServoUrl(Arc<Url>);
+
+impl ServoUrl {
+    pub fn from_url(url: Url) -> Self {
+        ServoUrl(Arc::new(url))
+    }
+
+    pub fn parse_with_base(base: Option<&Self>, input: &str) -> Result<Self, url::ParseError> {
+        Url::options().base_url(base.map(|b| &*b.0)).parse(input).map(Self::from_url)
+    }
+
+    pub fn into_string(self) -> String {
+        Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()).into_string()
+    }
+
+    // NOTE: These methods return options that are always true temporarily until
+    // we special-case some urls to avoid going through rust-url.
+    pub fn into_url(self) -> Option<Url> {
+        Some(Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()))
+    }
+
+    pub fn as_url(&self) -> Option<&Arc<Url>> {
+        Some(&self.0)
+    }
+
+    pub fn parse(input: &str) -> Result<Self, url::ParseError> {
+        Url::parse(input).map(Self::from_url)
+    }
+
+    pub fn cannot_be_a_base(&self) -> bool {
+        self.0.cannot_be_a_base()
+    }
+
+    pub fn domain(&self) -> Option<&str> {
+        self.0.domain()
+    }
+
+    pub fn fragment(&self) -> Option<&str> {
+        self.0.fragment()
+    }
+
+    pub fn path(&self) -> &str {
+        self.0.path()
+    }
+
+    pub fn origin(&self) -> Origin {
+        self.0.origin()
+    }
+
+    pub fn scheme(&self) -> &str {
+        self.0.scheme()
+    }
+
+    pub fn as_str(&self) -> &str {
+        self.0.as_str()
+    }
+
+    pub fn as_mut_url(&mut self) -> Option<&mut Url> {
+        Some(Arc::make_mut(&mut self.0))
+    }
+
+    pub fn set_username(&mut self, user: &str) -> Result<(), ()> {
+        Arc::make_mut(&mut self.0).set_username(user)
+    }
+
+    pub fn set_ip_host(&mut self, addr: IpAddr) -> Result<(), ()> {
+        Arc::make_mut(&mut self.0).set_ip_host(addr)
+    }
+
+    pub fn set_password(&mut self, pass: Option<&str>) -> Result<(), ()> {
+        Arc::make_mut(&mut self.0).set_password(pass)
+    }
+
+    pub fn username(&self) -> &str {
+        self.0.username()
+    }
+
+    pub fn password(&self) -> Option<&str> {
+        self.0.password()
+    }
+
+    pub fn to_file_path(&self) -> Result<::std::path::PathBuf, ()> {
+        self.0.to_file_path()
+    }
+
+    pub fn host(&self) -> Option<url::Host<&str>> {
+        self.0.host()
+    }
+
+    pub fn host_str(&self) -> Option<&str> {
+        self.0.host_str()
+    }
+
+    pub fn port(&self) -> Option<u16> {
+        self.0.port()
+    }
+
+    pub fn port_or_known_default(&self) -> Option<u16> {
+        self.0.port_or_known_default()
+    }
+
+    pub fn join(&self, input: &str) -> Result<ServoUrl, url::ParseError> {
+        self.0.join(input).map(Self::from_url)
+    }
+
+    pub fn path_segments(&self) -> Option<::std::str::Split<char>> {
+        self.0.path_segments()
+    }
+
+    pub fn query(&self) -> Option<&str> {
+        self.0.query()
+    }
+
+    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Self, ()> {
+        Ok(Self::from_url(try!(Url::from_file_path(path))))
+    }
+}
+
+impl fmt::Display for ServoUrl {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(formatter)
+    }
+}
--- a/servo/components/util/Cargo.toml
+++ b/servo/components/util/Cargo.toml
@@ -21,16 +21,17 @@ euclid = "0.10.1"
 getopts = "0.2.11"
 heapsize = "0.3.0"
 lazy_static = "0.2"
 log = "0.3.5"
 num_cpus = "1.1.0"
 rustc-serialize = "0.3"
 serde = {version = "0.8", optional = true}
 serde_derive = {version = "0.8", optional = true}
+servo_url = {path = "../url"}
+plugins = {path = "../plugins", optional = true}
 url = "1.2"
-plugins = {path = "../plugins", optional = true}
 
 [dev-dependencies]
 env_logger = "0.3"
 
 [target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))'.dependencies]
 xdg = "2.0"
--- a/servo/components/util/lib.rs
+++ b/servo/components/util/lib.rs
@@ -16,16 +16,17 @@ extern crate core;
 extern crate getopts;
 #[macro_use] extern crate heapsize;
 #[allow(unused_extern_crates)] #[macro_use] extern crate lazy_static;
 #[macro_use] extern crate log;
 extern crate num_cpus;
 extern crate rustc_serialize;
 #[cfg(feature = "servo")] extern crate serde;
 #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
+extern crate servo_url;
 extern crate url;
 #[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
 extern crate xdg;
 
 pub mod basedir;
 pub mod geometry;
 #[allow(unsafe_code)] pub mod opts;
 pub mod prefs;
--- a/servo/components/util/opts.rs
+++ b/servo/components/util/opts.rs
@@ -6,16 +6,17 @@
 //! from command line arguments.
 
 use euclid::size::TypedSize2D;
 use geometry::ScreenPx;
 use getopts::Options;
 use num_cpus;
 use prefs::{self, PrefValue, PREFS};
 use resource_files::set_resources_path;
+use servo_url::ServoUrl;
 use std::borrow::Cow;
 use std::cmp;
 use std::default::Default;
 use std::env;
 use std::fs::{self, File};
 use std::io::{self, Read, Write};
 use std::path::{Path, PathBuf};
 use std::process;
@@ -25,17 +26,17 @@ use url::{self, Url};
 
 /// Global flags for Servo, currently set on the command line.
 #[derive(Clone)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 pub struct Opts {
     pub is_running_problem_test: bool,
 
     /// The initial URL to load.
-    pub url: Option<Url>,
+    pub url: Option<ServoUrl>,
 
     /// How many threads to use for CPU painting (`-t`).
     ///
     /// Note that painting is sequentialized when using GPU painting.
     pub paint_threads: usize,
 
     /// The maximum size of each tile in pixels (`-s`).
     pub tile_size: usize,
@@ -58,17 +59,17 @@ pub struct Opts {
 
     pub nonincremental_layout: bool,
 
     /// Where to load userscripts from, if any. An empty string will load from
     /// the resources/user-agent-js directory, and if the option isn't passed userscripts
     /// won't be loaded
     pub userscripts: Option<String>,
 
-    pub user_stylesheets: Vec<(Vec<u8>, Url)>,
+    pub user_stylesheets: Vec<(Vec<u8>, ServoUrl)>,
 
     pub output_file: Option<String>,
 
     /// Replace unpaires surrogates in DOM strings with U+FFFD.
     /// See https://github.com/servo/servo/issues/6564
     pub replace_surrogates: bool,
 
     /// Log GC passes and their durations.
@@ -497,17 +498,17 @@ fn default_user_agent_string(agent: User
 const DEFAULT_USER_AGENT: UserAgent = UserAgent::Android;
 
 #[cfg(not(target_os = "android"))]
 const DEFAULT_USER_AGENT: UserAgent = UserAgent::Desktop;
 
 pub fn default_opts() -> Opts {
     Opts {
         is_running_problem_test: false,
-        url: Some(Url::parse("about:blank").unwrap()),
+        url: Some(ServoUrl::parse("about:blank").unwrap()),
         paint_threads: 1,
         tile_size: 512,
         device_pixels_per_px: None,
         time_profiling: None,
         time_profiler_trace_path: None,
         mem_profiler_period: None,
         nonincremental_layout: false,
         userscripts: None,
@@ -783,17 +784,17 @@ pub fn from_cmdline_args(args: &[String]
         Some(ref ua) if ua == "android" => default_user_agent_string(UserAgent::Android).into(),
         Some(ref ua) if ua == "desktop" => default_user_agent_string(UserAgent::Desktop).into(),
         Some(ua) => ua.into(),
         None => default_user_agent_string(DEFAULT_USER_AGENT).into(),
     };
 
     let user_stylesheets = opt_match.opt_strs("user-stylesheet").iter().map(|filename| {
         let path = cwd.join(filename);
-        let url = Url::from_file_path(&path).unwrap();
+        let url = ServoUrl::from_url(Url::from_file_path(&path).unwrap());
         let mut contents = Vec::new();
         File::open(path)
             .unwrap_or_else(|err| args_fail(&format!("Couldn't open {}: {}", filename, err)))
             .read_to_end(&mut contents)
             .unwrap_or_else(|err| args_fail(&format!("Couldn't read {}: {}", filename, err)));
         (contents, url)
     }).collect();
 
@@ -931,21 +932,21 @@ pub fn set_defaults(opts: Opts) {
     }
 }
 
 #[inline]
 pub fn get() -> &'static Opts {
     &OPTIONS
 }
 
-pub fn parse_url_or_filename(cwd: &Path, input: &str) -> Result<Url, ()> {
-    match Url::parse(input) {
+pub fn parse_url_or_filename(cwd: &Path, input: &str) -> Result<ServoUrl, ()> {
+    match ServoUrl::parse(input) {
         Ok(url) => Ok(url),
         Err(url::ParseError::RelativeUrlWithoutBase) => {
-            Url::from_file_path(&*cwd.join(input))
+            Url::from_file_path(&*cwd.join(input)).map(ServoUrl::from_url)
         }
         Err(_) => Err(()),
     }
 }
 
 impl Opts {
     pub fn should_use_osmesa(&self) -> bool {
         self.headless
--- a/servo/components/webdriver_server/Cargo.toml
+++ b/servo/components/webdriver_server/Cargo.toml
@@ -17,12 +17,13 @@ image = "0.10"
 ipc-channel = "0.5"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins"}
 regex = "0.1.55"
 rustc-serialize = "0.3.4"
 script_traits = {path = "../script_traits"}
+servo_url = {path = "../url", features = ["servo"]}
 url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../util"}
 uuid = { version = "0.3.1", features = ["v4"] }
 webdriver = "0.15"
--- a/servo/components/webdriver_server/lib.rs
+++ b/servo/components/webdriver_server/lib.rs
@@ -17,17 +17,17 @@ extern crate image;
 extern crate ipc_channel;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 extern crate regex;
 extern crate rustc_serialize;
 extern crate script_traits;
-extern crate url;
+extern crate servo_url;
 extern crate util;
 extern crate uuid;
 extern crate webdriver;
 
 mod keys;
 
 use euclid::Size2D;
 use hyper::method::Method::{self, Post};
@@ -37,23 +37,23 @@ use keys::keycodes_to_keys;
 use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection};
 use net_traits::image::base::PixelFormat;
 use regex::Captures;
 use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
 use rustc_serialize::json::{Json, ToJson};
 use script_traits::{ConstellationMsg, LoadData, WebDriverCommandMsg};
 use script_traits::webdriver_msg::{LoadStatus, WebDriverCookieError, WebDriverFrameId};
 use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult, WebDriverScriptCommand};
+use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::BTreeMap;
 use std::net::{SocketAddr, SocketAddrV4};
 use std::sync::mpsc::Sender;
 use std::thread;
 use std::time::Duration;
-use url::Url;
 use util::prefs::{PREFS, PrefValue};
 use util::thread::spawn_named;
 use uuid::Uuid;
 use webdriver::command::{AddCookieParameters, GetParameters, JavascriptCommandParameters};
 use webdriver::command::{LocatorParameters, Parameters};
 use webdriver::command::{SendKeysParameters, SwitchToFrameParameters, TimeoutsParameters};
 use webdriver::command::{WebDriverCommand, WebDriverExtensionCommand, WebDriverMessage};
 use webdriver::command::WindowSizeParameters;
@@ -332,17 +332,17 @@ impl Handler {
 
     #[inline]
     fn root_script_command(&self, cmd_msg: WebDriverScriptCommand) -> WebDriverResult<()> {
         Ok(self.constellation_chan.send(ConstellationMsg::WebDriverCommand(
                 WebDriverCommandMsg::ScriptCommand(try!(self.root_pipeline()), cmd_msg))).unwrap())
     }
 
     fn handle_get(&self, parameters: &GetParameters) -> WebDriverResult<WebDriverResponse> {
-        let url = match Url::parse(&parameters.url[..]) {
+        let url = match ServoUrl::parse(&parameters.url[..]) {
             Ok(url) => url,
             Err(_) => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                "Invalid URL"))
         };
 
         let pipeline_id = try!(self.root_pipeline());
 
         let (sender, receiver) = ipc::channel().unwrap();
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -12,18 +12,18 @@ dependencies = [
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "libservo 0.0.1",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "script_traits 0.0.1",
+ "servo_url 0.0.1",
  "style_traits 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "aho-corasick"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -327,19 +327,19 @@ dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "webrender 0.9.0 (git+https://github.com/servo/webrender)",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "constellation"
 version = "0.0.1"
@@ -362,18 +362,18 @@ dependencies = [
  "net_traits 0.0.1",
  "offscreen_gl_context 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "style_traits 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "content-blocker"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -527,18 +527,18 @@ dependencies = [
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper_serde 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dlib"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -786,23 +786,23 @@ dependencies = [
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "range 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_url 0.0.1",
  "simd 0.1.1 (git+https://github.com/huonw/simd)",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
  "xi-unicode 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gfx_traits"
 version = "0.0.1"
@@ -862,18 +862,18 @@ dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "osmesa-src 12.0.1 (git+https://github.com/servo/osmesa-src)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-glutin 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "style_traits 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glx"
@@ -1158,22 +1158,22 @@ dependencies = [
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "layout_thread"
 version = "0.0.1"
 dependencies = [
@@ -1196,33 +1196,34 @@ dependencies = [
  "profile_traits 0.0.1",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "style 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "style_traits 0.0.1",
  "util 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "layout_traits"
 version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -1297,16 +1298,17 @@ dependencies = [
  "msg 0.0.1",
  "net 0.0.1",
  "net_traits 0.0.1",
  "profile 0.0.1",
  "profile_traits 0.0.1",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
+ "servo_url 0.0.1",
  "sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "webdriver_server 0.0.1",
  "webrender 0.9.0 (git+https://github.com/servo/webrender)",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
@@ -1483,16 +1485,17 @@ dependencies = [
  "net_traits 0.0.1",
  "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
  "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
@@ -1524,16 +1527,17 @@ dependencies = [
  "image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2013,16 +2017,17 @@ dependencies = [
  "ref_slice 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2050,18 +2055,18 @@ dependencies = [
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_url 0.0.1",
  "style 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "script_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
@@ -2079,16 +2084,17 @@ dependencies = [
  "msg 0.0.1",
  "net_traits 0.0.1",
  "offscreen_gl_context 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "selectors"
 version = "0.14.0"
@@ -2240,16 +2246,27 @@ dependencies = [
 name = "servo_atoms"
 version = "0.0.1"
 dependencies = [
  "string_cache 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_codegen 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "servo_url"
+version = "0.0.1"
+dependencies = [
+ "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "heapsize_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "sha1"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "shared_library"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2356,21 +2373,21 @@ dependencies = [
  "quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "walkdir 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
@@ -2647,16 +2664,17 @@ dependencies = [
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_url 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "uuid"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2755,16 +2773,17 @@ dependencies = [
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
+ "servo_url 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webdriver 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender"
--- a/servo/ports/cef/Cargo.toml
+++ b/servo/ports/cef/Cargo.toml
@@ -20,24 +20,24 @@ debugmozjs = ["libservo/debugmozjs"]
 [dependencies]
 compositing = {path = "../../components/compositing"}
 devtools = {path = "../../components/devtools"}
 euclid = "0.10.1"
 gfx_traits = {path = "../../components/gfx_traits"}
 gleam = "0.2.8"
 glutin_app = {path = "../glutin"}
 libc = "0.2"
+libservo = {path = "../../components/servo"}
 log = {version = "0.3.5", features = ["release_max_level_info"]}
 msg = {path = "../../components/msg"}
 net_traits = {path = "../../components/net_traits"}
 plugins = {path = "../../components/plugins"}
 script_traits = {path = "../../components/script_traits"}
-libservo = {path = "../../components/servo"}
+servo_url = {path = "../../components/url"}
 style_traits = {path = "../../components/style_traits"}
-url = "1.2"
 util = {path = "../../components/util"}
 
 [target.'cfg(target_os="macos")'.dependencies]
 objc = "0.2"
 cocoa = "0.5"
 
 [target.'cfg(target_os="linux")'.dependencies]
 x11 = "2.3"
--- a/servo/ports/cef/lib.rs
+++ b/servo/ports/cef/lib.rs
@@ -19,24 +19,24 @@ extern crate servo;
 extern crate compositing;
 
 extern crate euclid;
 extern crate gfx_traits;
 extern crate gleam;
 extern crate glutin_app;
 extern crate rustc_unicode;
 extern crate script_traits;
+extern crate servo_url;
+extern crate style_traits;
 
 extern crate net_traits;
 extern crate msg;
 extern crate util;
-extern crate style_traits;
 
 extern crate libc;
-extern crate url as std_url;
 
 #[cfg(target_os="macos")]
 #[link_args="-Xlinker -undefined -Xlinker dynamic_lookup"]
 extern { }
 
 #[cfg(target_os="macos")]
 extern crate cocoa;
 #[cfg(target_os="macos")]
--- a/servo/ports/cef/window.rs
+++ b/servo/ports/cef/window.rs
@@ -28,17 +28,17 @@ use gleam::gl;
 use msg::constellation_msg::{Key, KeyModifiers};
 use net_traits::net_error_list::NetError;
 use std::cell::RefCell;
 use std::ffi::CString;
 use std::os::raw::{c_char, c_void};
 use std::ptr;
 use std::rc::Rc;
 use std::sync::mpsc::{Sender, channel};
-use std_url::Url;
+use servo_url::ServoUrl;
 use style_traits::cursor::Cursor;
 use util::geometry::ScreenPx;
 #[cfg(target_os="linux")]
 extern crate x11;
 #[cfg(target_os="linux")]
 use self::x11::xlib::{XInitThreads,XOpenDisplay};
 
 #[cfg(target_os="linux")]
@@ -307,23 +307,23 @@ impl WindowMethods for Window {
                         browser.get_host().get_client().get_render_handler().paint(browser.clone(), width, height);
                     }
                     false
                 }
             }
         }
     }
 
-    fn set_favicon(&self, url: Url) {
+    fn set_favicon(&self, url: ServoUrl) {
         let browser = self.cef_browser.borrow();
         let browser = match *browser {
             None => return,
             Some(ref browser) => browser,
         };
-        browser.downcast().favicons.borrow_mut().push(url.to_string().clone());
+        browser.downcast().favicons.borrow_mut().push(url.into_string());
     }
 
     fn status(&self, info: Option<String>) {
         let browser = self.cef_browser.borrow();
         let browser = match *browser {
             None => return,
             Some(ref browser) => browser,
         };
@@ -439,30 +439,30 @@ impl WindowMethods for Window {
         match &mut *title_visitor {
             &mut None => {},
             &mut Some(ref mut visitor) => {
                 visitor.visit(&str);
             }
         };
     }
 
-    fn set_page_url(&self, url: Url) {
+    fn set_page_url(&self, url: ServoUrl) {
         // it seems to be the case that load start is always called
         // IMMEDIATELY before address change, so just stick it here
         on_load_start(self);
         let browser = self.cef_browser.borrow();
         let browser = match *browser {
             None => return,
             Some(ref browser) => browser,
         };
         let frame = browser.get_main_frame();
         let servoframe = frame.downcast();
         // FIXME(https://github.com/rust-lang/rust/issues/23338)
         let mut frame_url = servoframe.url.borrow_mut();
-        *frame_url = url.to_string();
+        *frame_url = url.into_string();
         let utf16_chars: Vec<u16> = Utf16Encoder::new((*frame_url).chars()).collect();
         if check_ptr_exist!(browser.get_host().get_client(), get_display_handler) &&
            check_ptr_exist!(browser.get_host().get_client().get_display_handler(), on_address_change) {
             browser.get_host().get_client().get_display_handler().on_address_change((*browser).clone(), frame.clone(), utf16_chars.as_slice());
         }
     }
 
     fn handle_key(&self, _: Option<cha