Bug 1444151 - Part 3: Only create a single allocation for MozURL objects, which is managed by rust, r=valentin
authorNika Layzell <nika@thelayzells.com>
Thu, 08 Mar 2018 13:01:11 -0500
changeset 412768 a0c94bfa5a40a7a8106ba0d8320c40c58fc6449d
parent 412767 06e75a3b8d8e8562a1126bbc96758e402170dc94
child 412769 239b9760cb6754828e4055fb1605590ba9ab3a81
push id33818
push userapavel@mozilla.com
push dateWed, 11 Apr 2018 14:36:40 +0000
treeherdermozilla-central@cfe6399e142c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1444151
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1444151 - Part 3: Only create a single allocation for MozURL objects, which is managed by rust, r=valentin This patch rewrites the rust-url-capi crate as the mozurl crate, which provides a threadsafe MozURL object which is compatible with the previous MozURL class. Creating a MozURL this way performs a single allocation, which contains only a rust-url Url object and an atomic refcnt, however it is fully compatible with the C++ RefPtr type. This patch also exposes methods for accessing dependent substrings of the serialized spec, meaning that string copies can be avoided in many situations when inspecting attributes of the MozURL.
Cargo.lock
netwerk/base/MozURL.cpp
netwerk/base/MozURL.h
netwerk/base/moz.build
netwerk/base/mozurl/.gitignore
netwerk/base/mozurl/Cargo.toml
netwerk/base/mozurl/MozURL.h
netwerk/base/mozurl/MozURL_ffi.h
netwerk/base/mozurl/moz.build
netwerk/base/mozurl/src/lib.rs
netwerk/base/nsStandardURL.cpp
netwerk/base/rust-url-capi/.gitignore
netwerk/base/rust-url-capi/Cargo.toml
netwerk/base/rust-url-capi/src/lib.rs
netwerk/base/rust-url-capi/src/rust-url-capi.h
netwerk/test/gtest/TestMozURL.cpp
toolkit/library/rust/shared/Cargo.toml
toolkit/library/rust/shared/lib.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -825,23 +825,23 @@ dependencies = [
  "audioipc-server 0.2.2",
  "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb-pulse 0.2.0",
  "cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "geckoservo 0.0.1",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mozurl 0.0.1",
  "mp4parse_capi 0.10.1",
  "netwerk_helper 0.0.1",
  "nserror 0.1.0",
  "nsstring 0.1.0",
  "prefs_parser 0.0.1",
  "rsdparsa_capi 0.1.0",
- "rust_url_capi 0.0.1",
  "u2fhid 0.1.0",
  "webrender_bindings 0.1.0",
  "xpcom 0.1.0",
 ]
 
 [[package]]
 name = "gl_generator"
 version = "0.8.0"
@@ -1259,16 +1259,26 @@ name = "mozrunner"
 version = "0.6.1"
 dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozprofile 0.3.0",
  "winreg 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "mozurl"
+version = "0.0.1"
+dependencies = [
+ "nserror 0.1.0",
+ "nsstring 0.1.0",
+ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xpcom 0.1.0",
+]
+
+[[package]]
 name = "mozversion"
 version = "0.1.3"
 dependencies = [
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rust-ini 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1666,26 +1676,16 @@ source = "registry+https://github.com/ru
 name = "rust-ini"
 version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
-name = "rust_url_capi"
-version = "0.0.1"
-dependencies = [
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "nserror 0.1.0",
- "nsstring 0.1.0",
- "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
 name = "rustc-serialize"
 version = "0.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "safemem"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
deleted file mode 100644
--- a/netwerk/base/MozURL.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MozURL.h"
-#include "rust-url-capi/src/rust-url-capi.h"
-
-namespace mozilla {
-namespace net {
-
-NS_IMPL_ADDREF(MozURL)
-NS_IMPL_RELEASE(MozURL)
-
-/* static */ nsresult
-MozURL::Init(MozURL** aURL, const nsACString& aSpec, const MozURL* aBaseURL)
-{
-  rusturl* base = aBaseURL ? aBaseURL->mURL.get() : nullptr;
-  rusturl* ptr = rusturl_new(&aSpec, base);
-  if (!ptr) {
-    return NS_ERROR_FAILURE;
-  }
-  RefPtr<MozURL> url = new MozURL(ptr);
-  url.forget(aURL);
-  return NS_OK;
-}
-
-nsresult
-MozURL::GetScheme(nsACString& aScheme)
-{
-  return rusturl_get_scheme(mURL.get(), &aScheme);
-}
-
-nsresult
-MozURL::GetSpec(nsACString& aSpec)
-{
-  return rusturl_get_spec(mURL.get(), &aSpec);
-}
-
-nsresult
-MozURL::GetUsername(nsACString& aUser)
-{
-  return rusturl_get_username(mURL.get(), &aUser);
-}
-
-nsresult
-MozURL::GetPassword(nsACString& aPassword)
-{
-  return rusturl_get_password(mURL.get(), &aPassword);
-}
-
-nsresult
-MozURL::GetHostname(nsACString& aHost)
-{
-  return rusturl_get_host(mURL.get(), &aHost);
-}
-
-nsresult
-MozURL::GetHostPort(nsACString& aHostPort)
-{
-  nsresult rv = rusturl_get_host(mURL.get(), &aHostPort);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  int32_t port;
-  rv = GetPort(&port);
-  if (NS_FAILED(rv)) {
-    aHostPort.Truncate();
-    return rv;
-  }
-  if (port != -1) {
-    aHostPort.AppendLiteral(":");
-    aHostPort.AppendInt(port);
-  }
-
-  return NS_OK;
-}
-
-nsresult
-MozURL::GetPort(int32_t* aPort)
-{
-  return rusturl_get_port(mURL.get(), aPort);
-}
-
-nsresult
-MozURL::GetFilePath(nsACString& aPath)
-{
-  return rusturl_get_filepath(mURL.get(), &aPath);
-}
-
-nsresult
-MozURL::GetQuery(nsACString& aQuery)
-{
-  return rusturl_get_query(mURL.get(), &aQuery);
-}
-
-nsresult
-MozURL::GetRef(nsACString& aRef)
-{
-  return rusturl_get_fragment(mURL.get(), &aRef);
-}
-
-nsresult
-MozURL::GetOrigin(nsACString& aOrigin)
-{
-  return rusturl_get_origin(mURL.get(), &aOrigin);
-}
-
-// MozURL::Mutator
-
-MozURL::Mutator::Mutator(MozURL* url)
-  : mURL(rusturl_clone(url->mURL.get()))
-  , mFinalized(false)
-  , mStatus(NS_OK)
-{
-}
-
-// This macro ensures that the mutator is still valid, meaning it hasn't been
-// finalized, and none of the setters have returned an error code.
-#define ENSURE_VALID()                          \
-  PR_BEGIN_MACRO                                \
-    if (mFinalized) {                           \
-      mStatus = NS_ERROR_NOT_AVAILABLE;         \
-    }                                           \
-    if (NS_FAILED(mStatus)) {                   \
-      return *this;                             \
-    }                                           \
-  PR_END_MACRO
-
-nsresult
-MozURL::Mutator::Finalize(MozURL** aURL)
-{
-  if (mFinalized) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  mFinalized = true;
-  if (NS_FAILED(mStatus)) {
-    return mStatus;
-  }
-  RefPtr<MozURL> result = new MozURL(mURL.release());
-  result.forget(aURL);
-  return NS_OK;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetScheme(const nsACString& aScheme)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_scheme(mURL.get(), &aScheme);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetUsername(const nsACString& aUser)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_username(mURL.get(), &aUser);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetPassword(const nsACString& aPassword)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_password(mURL.get(), &aPassword);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetHostname(const nsACString& aHost)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_host(mURL.get(), &aHost);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetHostPort(const nsACString& aHostPort)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_host_port(mURL.get(), &aHostPort);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetFilePath(const nsACString& aPath)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_path(mURL.get(), &aPath);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetQuery(const nsACString& aQuery)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_query(mURL.get(), &aQuery);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetRef(const nsACString& aRef)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_fragment(mURL.get(), &aRef);
-  return *this;
-}
-
-MozURL::Mutator&
-MozURL::Mutator::SetPort(int32_t aPort)
-{
-  ENSURE_VALID();
-  mStatus = rusturl_set_port_no(mURL.get(), aPort);
-  return *this;
-}
-
-void
-MozURL::FreeRustURL::operator()(rusturl* aPtr)
-{
-  rusturl_free(aPtr);
-}
-
-} // namespace net
-} // namespace mozilla
deleted file mode 100644
--- a/netwerk/base/MozURL.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozURL_h__
-#define mozURL_h__
-
-#include "mozilla/UniquePtr.h"
-
-extern "C" {
-struct rusturl;
-}
-
-namespace mozilla {
-namespace net {
-
-// This class provides a thread-safe, immutable URL parser.
-// As long as there is RefPtr to the object, you may use it on any thread.
-// The constructor is private. One can instantiate the object by
-// calling the Init() method as such:
-//
-// RefPtr<MozURL> url;
-// nsAutoCString href("http://example.com/path?query#ref");
-// nsresult rv = MozURL::Init(getter_AddRefs(url), href);
-// if (NS_SUCCEEDED(rv)) { /* use url */ }
-//
-// When changing the URL is needed, you need to call the Mutate() method.
-// This gives you a Mutator object, on which you can perform setter operations.
-// Calling Finalize() on the Mutator will result in a new MozURL and a status
-// code. If any of the setter operations failed, it will be reflected in the
-// status code, and a null MozURL.
-//
-// Note: In the case of a domain name containing non-ascii characters,
-// GetSpec and GetHostname will return the IDNA(punycode) version of the host.
-// Also note that for now, MozURL only supports the UTF-8 charset.
-class MozURL final
-{
-public:
-  static nsresult Init(MozURL** aURL, const nsACString& aSpec,
-                       const MozURL* aBaseURL = nullptr);
-
-  nsresult GetScheme(nsACString& aScheme);
-  nsresult GetSpec(nsACString& aSpec);
-  nsresult GetUsername(nsACString& aUser);
-  nsresult GetPassword(nsACString& aPassword);
-  // Will return the hostname of URL. If the hostname is an IPv6 address,
-  // it will be enclosed in square brackets, such as `[::1]`
-  nsresult GetHostname(nsACString& aHost);
-  // If the URL's port number is equal to the default port, will only return the
-  // hostname, otherwise it will return a string of the form `{host}:{port}`
-  // See: https://url.spec.whatwg.org/#default-port
-  nsresult GetHostPort(nsACString& aHostPort);
-  // Will return the port number, if specified, or -1
-  nsresult GetPort(int32_t* aPort);
-  nsresult GetFilePath(nsACString& aPath);
-  nsresult GetQuery(nsACString& aQuery);
-  nsresult GetRef(nsACString& aRef);
-  nsresult GetOrigin(nsACString& aOrigin);
-
-private:
-  explicit MozURL(rusturl* rawPtr)
-    : mURL(rawPtr)
-  {
-  }
-  virtual ~MozURL() {}
-  struct FreeRustURL
-  {
-    void operator()(rusturl* aPtr);
-  };
-  mozilla::UniquePtr<rusturl, FreeRustURL> mURL;
-
-public:
-  class MOZ_STACK_CLASS Mutator
-  {
-  public:
-    // Calling this method will result in the creation of a new MozURL that
-    // adopts the mutator's mURL.
-    // If any of the setters failed with an error code, that error code will be
-    // returned here. It will also return an error code if Finalize is called
-    // more than once on the Mutator.
-    nsresult Finalize(MozURL** aURL);
-
-    // These setter methods will return a reference to `this` so that you may
-    // chain setter operations as such:
-    //
-    // RefPtr<MozURL> url2;
-    // nsresult rv = url->Mutate().SetHostname(NS_LITERAL_CSTRING("newhost"))
-    //                            .SetFilePath(NS_LITERAL_CSTRING("new/file/path"))
-    //                            .Finalize(getter_AddRefs(url2));
-    // if (NS_SUCCEEDED(rv)) { /* use url2 */ }
-    Mutator& SetScheme(const nsACString& aScheme);
-    Mutator& SetUsername(const nsACString& aUser);
-    Mutator& SetPassword(const nsACString& aPassword);
-    Mutator& SetHostname(const nsACString& aHost);
-    Mutator& SetHostPort(const nsACString& aHostPort);
-    Mutator& SetFilePath(const nsACString& aPath);
-    Mutator& SetQuery(const nsACString& aQuery);
-    Mutator& SetRef(const nsACString& aRef);
-    Mutator& SetPort(int32_t aPort);
-
-    // This method returns the status code of the setter operations.
-    // If any of the setters failed, it will return the code of the first error
-    // that occured. If none of the setters failed, it will return NS_OK.
-    // This method is useful to avoid doing expensive operations when the result
-    // would not be used because an error occurred. For example:
-    //
-    // RefPtr<MozURL> url2;
-    // MozURL::Mutator mut = url->Mutate();
-    // mut.SetScheme("!@#$"); // this would fail
-    // if (NS_SUCCEDED(mut.GetStatus())) {
-    //   nsAutoCString host(ExpensiveComputing());
-    //   rv = mut.SetHostname(host).Finalize(getter_AddRefs(url2));
-    // }
-    // if (NS_SUCCEEDED(rv)) { /* use url2 */ }
-    nsresult GetStatus() { return mStatus; }
-  private:
-    explicit Mutator(MozURL* url);
-    mozilla::UniquePtr<rusturl, FreeRustURL> mURL;
-    bool mFinalized;
-    nsresult mStatus;
-    friend class MozURL;
-  };
-
-  Mutator Mutate() { return Mutator(this); }
-
-// These are used to avoid inheriting from nsISupports
-public:
-  NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
-  NS_IMETHOD_(MozExternalRefCountType) Release(void);
-  typedef mozilla::TrueType HasThreadSafeRefCnt;
-protected:
-  ::mozilla::ThreadSafeAutoRefCnt mRefCnt;
-  NS_DECL_OWNINGTHREAD
-};
-
-} // namespace net
-} // namespace mozilla
-
-#endif // mozURL_h__
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -168,17 +168,16 @@ EXPORTS.mozilla += [
 
 EXPORTS.mozilla.net += [
     'CaptivePortalService.h',
     'ChannelDiverterChild.h',
     'ChannelDiverterParent.h',
     'Dashboard.h',
     'DashboardTypes.h',
     'MemoryDownloader.h',
-    'MozURL.h',
     'PartiallySeekableInputStream.h',
     'Predictor.h',
     'ReferrerPolicy.h',
     'SimpleChannelParent.h',
     'TCPFastOpen.h',
 ]
 
 UNIFIED_SOURCES += [
@@ -187,17 +186,16 @@ UNIFIED_SOURCES += [
     'CaptivePortalService.cpp',
     'ChannelDiverterChild.cpp',
     'ChannelDiverterParent.cpp',
     'Dashboard.cpp',
     'EventTokenBucket.cpp',
     'LoadContextInfo.cpp',
     'LoadInfo.cpp',
     'MemoryDownloader.cpp',
-    'MozURL.cpp',
     'NetworkActivityMonitor.cpp',
     'nsAsyncRedirectVerifyHelper.cpp',
     'nsAsyncStreamCopier.cpp',
     'nsAuthInformationHolder.cpp',
     'nsBase64Encoder.cpp',
     'nsBaseChannel.cpp',
     'nsBaseContentStream.cpp',
     'nsBufferedStreams.cpp',
@@ -286,16 +284,18 @@ elif CONFIG['OS_ARCH'] == 'Linux':
         'NetworkInfoServiceLinux.cpp',
         'nsNetworkInfoService.cpp',
     ]
 
 EXTRA_JS_MODULES += [
     'NetUtil.jsm',
 ]
 
+DIRS += [ 'mozurl' ]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/netwerk/protocol/http',
rename from netwerk/base/rust-url-capi/.gitignore
rename to netwerk/base/mozurl/.gitignore
new file mode 100644
--- /dev/null
+++ b/netwerk/base/mozurl/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "mozurl"
+version = "0.0.1"
+authors = ["Nika Layzell <nika@thelayzells.com>"]
+
+[dependencies]
+url = "1.5.1"
+nsstring = { path = "../../../servo/support/gecko/nsstring" }
+nserror = { path = "../../../xpcom/rust/nserror" }
+xpcom = { path = "../../../xpcom/rust/xpcom" }
new file mode 100644
--- /dev/null
+++ b/netwerk/base/mozurl/MozURL.h
@@ -0,0 +1,277 @@
+/* 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/. */
+
+#ifndef mozURL_h__
+#define mozURL_h__
+
+#include "mozilla/net/MozURL_ffi.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace net {
+
+// This class provides a thread-safe, immutable URL parser.
+// As long as there is RefPtr to the object, you may use it on any thread.
+// The constructor is private. One can instantiate the object by
+// calling the Init() method as such:
+//
+// RefPtr<MozURL> url;
+// nsAutoCString href("http://example.com/path?query#ref");
+// nsresult rv = MozURL::Init(getter_AddRefs(url), href);
+// if (NS_SUCCEEDED(rv)) { /* use url */ }
+//
+// When changing the URL is needed, you need to call the Mutate() method.
+// This gives you a Mutator object, on which you can perform setter operations.
+// Calling Finalize() on the Mutator will result in a new MozURL and a status
+// code. If any of the setter operations failed, it will be reflected in the
+// status code, and a null MozURL.
+//
+// Note: In the case of a domain name containing non-ascii characters,
+// GetSpec and GetHostname will return the IDNA(punycode) version of the host.
+// Also note that for now, MozURL only supports the UTF-8 charset.
+//
+// Implementor Note: This type is only a holder for methods in C++, and does not
+// reflect the actual layout of the type.
+class MozURL final
+{
+public:
+  static nsresult Init(MozURL** aURL, const nsACString& aSpec,
+                       const MozURL* aBaseURL = nullptr)
+  {
+    return mozurl_new(aURL, &aSpec, aBaseURL);
+  }
+
+  nsDependentCSubstring Spec() const {
+    return mozurl_spec(this);
+  }
+  nsDependentCSubstring Scheme() const {
+    return mozurl_scheme(this);
+  }
+  nsDependentCSubstring Username() const {
+    return mozurl_username(this);
+  }
+  nsDependentCSubstring Password() const {
+    return mozurl_password(this);
+  }
+  nsDependentCSubstring Host() const {
+    return mozurl_host(this);
+  }
+  int32_t Port() const {
+    return mozurl_port(this);
+  }
+  nsDependentCSubstring HostPort() const {
+    return mozurl_host_port(this);
+  }
+  nsDependentCSubstring FilePath() const {
+    return mozurl_filepath(this);
+  }
+  nsDependentCSubstring Path() const {
+    return mozurl_path(this);
+  }
+  nsDependentCSubstring Query() const {
+    return mozurl_query(this);
+  }
+  nsDependentCSubstring Ref() const {
+    return mozurl_fragment(this);
+  }
+  bool HasFragment() const {
+    return mozurl_has_fragment(this);
+  }
+
+  // WARNING: This does not match the definition of origins in nsIPrincipal for
+  // all URIs.
+  // XXX: Consider bringing these implementations in sync with one-another?
+  void Origin(nsACString& aOrigin) const {
+    mozurl_origin(this, &aOrigin);
+  }
+
+  nsresult GetCommonBase(const MozURL* aOther, MozURL** aCommon) const {
+    return mozurl_common_base(this, aOther, aCommon);
+  }
+  nsresult GetRelative(const MozURL* aOther, nsACString* aRelative) const {
+    return mozurl_relative(this, aOther, aRelative);
+  }
+
+  // Legacy XPCOM-style getters
+  nsresult GetScheme(nsACString& aScheme) const {
+    aScheme.Assign(Scheme());
+    return NS_OK;
+  }
+  nsresult GetSpec(nsACString& aSpec) const {
+    aSpec.Assign(Spec());
+    return NS_OK;
+  }
+  nsresult GetUsername(nsACString& aUser) const {
+    aUser.Assign(Username());
+    return NS_OK;
+  }
+  nsresult GetPassword(nsACString& aPassword) const {
+    aPassword.Assign(Password());
+    return NS_OK;
+  }
+  // Will return the hostname of URL. If the hostname is an IPv6 address,
+  // it will be enclosed in square brackets, such as `[::1]`
+  nsresult GetHostname(nsACString& aHost) const {
+    aHost.Assign(Host());
+    return NS_OK;
+  }
+  // If the URL's port number is equal to the default port, will only return the
+  // hostname, otherwise it will return a string of the form `{host}:{port}`
+  // See: https://url.spec.whatwg.org/#default-port
+  nsresult GetHostPort(nsACString& aHostPort) const {
+    aHostPort.Assign(HostPort());
+    return NS_OK;
+  }
+  // Will return the port number, if specified, or -1
+  nsresult GetPort(int32_t* aPort) const {
+    *aPort = Port();
+    return NS_OK;
+  }
+  nsresult GetFilePath(nsACString& aPath) const {
+    aPath.Assign(FilePath());
+    return NS_OK;
+  }
+  nsresult GetQuery(nsACString& aQuery) const {
+    aQuery.Assign(Query());
+    return NS_OK;
+  }
+  nsresult GetRef(nsACString& aRef) const {
+    aRef.Assign(Ref());
+    return NS_OK;
+  }
+  nsresult GetOrigin(nsACString& aOrigin) const {
+    Origin(aOrigin);
+    return NS_OK;
+  }
+
+  class MOZ_STACK_CLASS Mutator
+  {
+  public:
+    // Calling this method will result in the creation of a new MozURL that
+    // adopts the mutator's mURL.
+    // If any of the setters failed with an error code, that error code will be
+    // returned here. It will also return an error code if Finalize is called
+    // more than once on the Mutator.
+    nsresult Finalize(MozURL** aURL) {
+      nsresult rv = GetStatus();
+      if (NS_SUCCEEDED(rv)) {
+        mURL.forget(aURL);
+      } else {
+        *aURL = nullptr;
+      }
+      return rv;
+    }
+
+    // These setter methods will return a reference to `this` so that you may
+    // chain setter operations as such:
+    //
+    // RefPtr<MozURL> url2;
+    // nsresult rv = url->Mutate().SetHostname(NS_LITERAL_CSTRING("newhost"))
+    //                            .SetFilePath(NS_LITERAL_CSTRING("new/file/path"))
+    //                            .Finalize(getter_AddRefs(url2));
+    // if (NS_SUCCEEDED(rv)) { /* use url2 */ }
+    Mutator& SetScheme(const nsACString& aScheme) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_scheme(mURL, &aScheme);
+      }
+      return *this;
+    }
+    Mutator& SetUsername(const nsACString& aUser) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_username(mURL, &aUser);
+      }
+      return *this;
+    }
+    Mutator& SetPassword(const nsACString& aPassword) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_password(mURL, &aPassword);
+      }
+      return *this;
+    }
+    Mutator& SetHostname(const nsACString& aHost) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_hostname(mURL, &aHost);
+      }
+      return *this;
+    }
+    Mutator& SetHostPort(const nsACString& aHostPort) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_host_port(mURL, &aHostPort);
+      }
+      return *this;
+    }
+    Mutator& SetFilePath(const nsACString& aPath) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_pathname(mURL, &aPath);
+      }
+      return *this;
+    }
+    Mutator& SetQuery(const nsACString& aQuery) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_query(mURL, &aQuery);
+      }
+      return *this;
+    }
+    Mutator& SetRef(const nsACString& aRef) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_fragment(mURL, &aRef);
+      }
+      return *this;
+    }
+    Mutator& SetPort(int32_t aPort) {
+      if (NS_SUCCEEDED(GetStatus())) {
+        mStatus = mozurl_set_port_no(mURL, aPort);
+      }
+      return *this;
+    }
+
+    // This method returns the status code of the setter operations.
+    // If any of the setters failed, it will return the code of the first error
+    // that occured. If none of the setters failed, it will return NS_OK.
+    // This method is useful to avoid doing expensive operations when the result
+    // would not be used because an error occurred. For example:
+    //
+    // RefPtr<MozURL> url2;
+    // MozURL::Mutator mut = url->Mutate();
+    // mut.SetScheme("!@#$"); // this would fail
+    // if (NS_SUCCEDED(mut.GetStatus())) {
+    //   nsAutoCString host(ExpensiveComputing());
+    //   rv = mut.SetHostname(host).Finalize(getter_AddRefs(url2));
+    // }
+    // if (NS_SUCCEEDED(rv)) { /* use url2 */ }
+    nsresult GetStatus() {
+      return mURL ? mStatus : NS_ERROR_NOT_AVAILABLE;
+    }
+  private:
+    explicit Mutator(MozURL* aUrl) : mStatus(NS_OK) {
+      mozurl_clone(aUrl, getter_AddRefs(mURL));
+    }
+    RefPtr<MozURL> mURL;
+    nsresult mStatus;
+    friend class MozURL;
+  };
+
+  Mutator Mutate() { return Mutator(this); }
+
+  // AddRef and Release are non-virtual on this type, and always call into rust.
+  nsrefcnt AddRef() {
+    return mozurl_addref(this);
+  }
+  nsrefcnt Release() {
+    return mozurl_release(this);
+  }
+
+private:
+  // Make it a compile time error for C++ code to ever create, destruct, or copy
+  // MozURL objects. All of these operations will be performed by rust.
+  MozURL(); /* never defined */
+  ~MozURL(); /* never defined */
+  MozURL(const MozURL&) = delete;
+  MozURL& operator=(const MozURL&) = delete;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozURL_h__
new file mode 100644
--- /dev/null
+++ b/netwerk/base/mozurl/MozURL_ffi.h
@@ -0,0 +1,99 @@
+/* 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/. */
+
+#ifndef mozilla_net_MozURL_ffi_h
+#define mozilla_net_MozURL_ffi_h
+
+// The MozURL type is implemented in Rust code, and uses extern "C" FFI calls to
+// operate on the internal data structure. This file contains C declarations of
+// these files.
+//
+// WARNING: DO NOT CALL ANY OF THESE FUNCTIONS. USE |MozURL| INSTEAD!
+
+#include "nsString.h"
+#include "nsError.h"
+
+namespace mozilla {
+namespace net {
+class MozURL;
+} // namespace net
+} // namespace mozilla
+
+extern "C" {
+
+// FFI-compatible string slice struct used internally by MozURL.
+// Coerces to nsDependentCSubstring.
+struct MozURLSpecSlice {
+  char* mData;
+  uint32_t mLen;
+
+  operator nsDependentCSubstring() {
+    return nsDependentCSubstring(mData, mLen);
+  }
+};
+
+nsrefcnt mozurl_addref(const mozilla::net::MozURL*);
+nsrefcnt mozurl_release(const mozilla::net::MozURL*);
+
+nsresult mozurl_new(mozilla::net::MozURL** aResult,
+                    const nsACString* aSpec,
+                    /* optional */ const mozilla::net::MozURL* aBase);
+
+void mozurl_clone(const mozilla::net::MozURL* aThis,
+                  mozilla::net::MozURL** aResult);
+
+// Spec segment getters
+MozURLSpecSlice mozurl_spec(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_scheme(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_username(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_password(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_host(const mozilla::net::MozURL*);
+int32_t mozurl_port(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_host_port(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_filepath(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_path(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_query(const mozilla::net::MozURL*);
+MozURLSpecSlice mozurl_fragment(const mozilla::net::MozURL*);
+
+bool mozurl_has_fragment(const mozilla::net::MozURL*);
+void mozurl_origin(const mozilla::net::MozURL*, nsACString* aResult);
+
+nsresult mozurl_common_base(const mozilla::net::MozURL* aUrl1,
+                            const mozilla::net::MozURL* aUrl2,
+                            mozilla::net::MozURL** aResult);
+nsresult mozurl_relative(const mozilla::net::MozURL* aUrl1,
+                         const mozilla::net::MozURL* aUrl2,
+                         nsACString* aResult);
+
+// Mutators. These must only be called when a MozURL is uniquely owned.
+// This is debug_assert-ed in the rust code.
+nsresult mozurl_set_scheme(mozilla::net::MozURL* aUrl,
+                           const nsACString* aScheme);
+nsresult mozurl_set_username(mozilla::net::MozURL* aUrl,
+                             const nsACString* aUsername);
+nsresult mozurl_set_password(mozilla::net::MozURL* aUrl,
+                             const nsACString* aPassword);
+nsresult mozurl_set_host_port(mozilla::net::MozURL* aUrl,
+                              const nsACString* aHostPort);
+nsresult mozurl_set_hostname(mozilla::net::MozURL* aUrl,
+                             const nsACString* aHostname);
+nsresult mozurl_set_port_no(mozilla::net::MozURL* aUrl,
+                            int32_t port);
+nsresult mozurl_set_pathname(mozilla::net::MozURL* aUrl,
+                             const nsACString* aPath);
+nsresult mozurl_set_query(mozilla::net::MozURL* aUrl,
+                          const nsACString* aQuery);
+nsresult mozurl_set_fragment(mozilla::net::MozURL* aUrl,
+                             const nsACString* aFragment);
+
+// Utility function for parsing IPv6 addresses, used by nsStandardURL.h
+//
+// This function does not follow the mozurl_ naming convention, as it does not
+// work on MozURL objects.
+nsresult rusturl_parse_ipv6addr(const nsACString* aHost,
+                                nsACString* aAddr);
+
+} // extern "C"
+
+#endif // !defined(mozilla_net_MozURL_ffi_h)
new file mode 100644
--- /dev/null
+++ b/netwerk/base/mozurl/moz.build
@@ -0,0 +1,12 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla.net += [
+    'MozURL.h',
+    'MozURL_ffi.h',
+]
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/netwerk/base/mozurl/src/lib.rs
@@ -0,0 +1,412 @@
+/* -*- Mode: rust; rust-indent-offset: 2 -*- */
+/* 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/. */
+
+extern crate url;
+use url::{Url, ParseOptions, Position};
+use url::quirks;
+
+extern crate nsstring;
+use nsstring::{nsCString, nsACString};
+
+extern crate nserror;
+use nserror::*;
+
+extern crate xpcom;
+use xpcom::{AtomicRefcnt, RefPtr, RefCounted};
+use xpcom::interfaces::nsrefcnt;
+
+use std::str;
+use std::ptr;
+use std::ops;
+use std::marker::PhantomData;
+use std::fmt::Write;
+
+/// Helper macro. If the expression $e is Ok(t) evaluates to t, otherwise,
+/// returns NS_ERROR_MALFORMED_URI.
+macro_rules! try_or_malformed {
+  ($e:expr) => (
+    match $e {
+      Ok(v) => v,
+      Err(_) => return NS_ERROR_MALFORMED_URI,
+    }
+  )
+}
+
+fn parser<'a>() -> ParseOptions<'a> {
+  Url::options()
+}
+
+fn default_port(scheme: &str) -> Option<u16> {
+  match scheme {
+    "ftp" => Some(21),
+    "gopher" => Some(70),
+    "http" => Some(80),
+    "https" => Some(443),
+    "ws" => Some(80),
+    "wss" => Some(443),
+    "rtsp" => Some(443),
+    "moz-anno" => Some(443),
+    "android" => Some(443),
+    _ => None,
+  }
+}
+
+/// A slice into the backing string. This type is only valid as long as the
+/// MozURL which it was pulled from is valid. In C++, this type implicitly
+/// converts to a nsDependentCString, and is an implementation detail.
+///
+/// This type exists because, unlike &str, this type is safe to return over FFI.
+#[repr(C)]
+pub struct SpecSlice<'a> {
+  data: *const u8,
+  len: u32,
+  _marker: PhantomData<&'a [u8]>,
+}
+
+impl<'a> From<&'a str> for SpecSlice<'a> {
+  fn from(s: &'a str) -> SpecSlice<'a> {
+    assert!(s.len() < u32::max_value() as usize);
+    SpecSlice {
+      data: s.as_ptr(),
+      len: s.len() as u32,
+      _marker: PhantomData,
+    }
+  }
+}
+
+/// The MozURL reference-counted threadsafe URL type. This type intentionally
+/// implements no XPCOM interfaces, and all method calls are non-virtual.
+#[repr(C)]
+pub struct MozURL {
+  pub url: Url,
+  refcnt: AtomicRefcnt,
+}
+
+impl MozURL {
+  pub fn from_url(url: Url) -> RefPtr<MozURL> {
+    // Actually allocate the URL on the heap. This is the only place we actually
+    // create a MozURL, other than in clone().
+    unsafe {
+      RefPtr::from_raw(Box::into_raw(Box::new(MozURL {
+        url: url,
+        refcnt: AtomicRefcnt::new(),
+      }))).unwrap()
+    }
+  }
+}
+
+impl ops::Deref for MozURL {
+  type Target = Url;
+  fn deref(&self) -> &Url {
+    &self.url
+  }
+}
+impl ops::DerefMut for MozURL {
+  fn deref_mut(&mut self) -> &mut Url {
+    &mut self.url
+  }
+}
+
+// Memory Management for MozURL
+#[no_mangle]
+pub unsafe extern "C" fn mozurl_addref(url: &MozURL) -> nsrefcnt {
+  url.refcnt.inc()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mozurl_release(url: &MozURL) -> nsrefcnt {
+  let rc = url.refcnt.dec();
+  if rc == 0 {
+    Box::from_raw(url as *const MozURL as *mut MozURL);
+  }
+  rc
+}
+
+// xpcom::RefPtr support
+unsafe impl RefCounted for MozURL {
+  unsafe fn addref(&self) {
+    mozurl_addref(self);
+  }
+  unsafe fn release(&self) {
+    mozurl_release(self);
+  }
+}
+
+// Allocate a new MozURL object with a RefCnt of 1, and store a pointer to it
+// into url.
+#[no_mangle]
+pub extern "C" fn mozurl_new(
+  result: &mut *const MozURL,
+  spec: &nsACString,
+  base: Option<&MozURL>,
+) -> nsresult {
+  *result = ptr::null_mut();
+
+  let spec = try_or_malformed!(str::from_utf8(spec));
+  let url = if let Some(base) = base {
+    try_or_malformed!(base.url.join(spec))
+  } else {
+    try_or_malformed!(parser().parse(spec))
+  };
+
+  MozURL::from_url(url).forget(result);
+  NS_OK
+}
+
+/// Allocate a new MozURL object which is a clone of the original, and store a
+/// pointer to it into newurl.
+#[no_mangle]
+pub extern "C" fn mozurl_clone(url: &MozURL, newurl: &mut *const MozURL) {
+  MozURL::from_url(url.url.clone()).forget(newurl);
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_spec(url: &MozURL) -> SpecSlice {
+  url.as_ref().into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_scheme(url: &MozURL) -> SpecSlice {
+  url.scheme().into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_username(url: &MozURL) -> SpecSlice {
+  if url.cannot_be_a_base() {
+    "".into()
+  } else {
+    url.username().into()
+  }
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_password(url: &MozURL) -> SpecSlice {
+  url.password().unwrap_or("").into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_host(url: &MozURL) -> SpecSlice {
+  url.host_str().unwrap_or("").into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_port(url: &MozURL) -> i32 {
+  // NOTE: Gecko uses -1 to represent the default port.
+  url.port().map(|p| p as i32).unwrap_or(-1)
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_host_port(url: &MozURL) -> SpecSlice {
+  (&url[Position::BeforeHost..Position::BeforePath]).into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_filepath(url: &MozURL) -> SpecSlice {
+  url.path().into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_path(url: &MozURL) -> SpecSlice {
+  (&url[Position::BeforePath..]).into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_query(url: &MozURL) -> SpecSlice {
+  url.query().unwrap_or("").into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_fragment(url: &MozURL) -> SpecSlice {
+  url.fragment().unwrap_or("").into()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_has_fragment(url: &MozURL) -> bool {
+  url.fragment().is_some()
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_origin(url: &MozURL, origin: &mut nsACString) {
+  // NOTE: Try to re-use the allocation we got from rust-url, and transfer
+  // ownership of the buffer to C++.
+  let mut o = nsCString::from(url.origin().ascii_serialization());
+  origin.take_from(&mut o);
+}
+
+// Helper macro for debug asserting that we're the only reference to MozURL.
+macro_rules! debug_assert_mut {
+  ($e:expr) => {
+    debug_assert_eq!(
+      $e.refcnt.get(), 1,
+      "Cannot mutate an aliased MozURL!"
+    );
+  }
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_scheme(url: &mut MozURL, scheme: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let scheme = try_or_malformed!(str::from_utf8(scheme));
+  try_or_malformed!(quirks::set_protocol(url, scheme));
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_username(url: &mut MozURL, username: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let username = try_or_malformed!(str::from_utf8(username));
+  try_or_malformed!(quirks::set_username(url, username));
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_password(url: &mut MozURL, password: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let password = try_or_malformed!(str::from_utf8(password));
+  try_or_malformed!(quirks::set_password(url, password));
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_host_port(url: &mut MozURL, hostport: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let hostport = try_or_malformed!(str::from_utf8(hostport));
+  try_or_malformed!(quirks::set_host(url, hostport));
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_hostname(url: &mut MozURL, host: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let host = try_or_malformed!(str::from_utf8(host));
+  try_or_malformed!(quirks::set_hostname(url, host));
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_port_no(url: &mut MozURL, new_port: i32) -> nsresult {
+  debug_assert_mut!(url);
+  if url.cannot_be_a_base() {
+    return NS_ERROR_MALFORMED_URI;
+  }
+
+  let port = match new_port {
+    new if new < 0 || u16::max_value() as i32 > new => None,
+    new if Some(new as u16) == default_port(url.scheme()) => None,
+    new => Some(new as u16),
+  };
+  try_or_malformed!(url.set_port(port));
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_pathname(url: &mut MozURL, path: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let path = try_or_malformed!(str::from_utf8(path));
+  quirks::set_pathname(url, path);
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_query(url: &mut MozURL, query: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let query = try_or_malformed!(str::from_utf8(query));
+  quirks::set_search(url, query);
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_set_fragment(url: &mut MozURL, fragment: &nsACString) -> nsresult {
+  debug_assert_mut!(url);
+  let fragment = try_or_malformed!(str::from_utf8(fragment));
+  quirks::set_hash(url, fragment);
+  NS_OK
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_common_base(url1: &MozURL, url2: &MozURL, result: &mut *const MozURL) -> nsresult {
+  *result = ptr::null();
+  if url1.url == url2.url {
+    RefPtr::new(url1).forget(result);
+    return NS_OK;
+  }
+
+  if url1.scheme() != url2.scheme() ||
+     url1.host() != url2.host() ||
+     url1.username() != url2.username() ||
+     url1.password() != url2.password() ||
+     url1.port() != url2.port() {
+    return NS_OK;
+  }
+
+  match (url1.path_segments(), url2.path_segments()) {
+    (Some(path1), Some(path2)) => {
+      // Take the shared prefix of path segments
+      let mut url = url1.url.clone();
+      if let Ok(mut segs) = url.path_segments_mut() {
+        segs.clear();
+        segs.extend(path1.zip(path2)
+                         .take_while(|&(a, b)| a == b)
+                         .map(|p| p.0));
+      } else {
+        return NS_OK;
+      }
+
+      MozURL::from_url(url).forget(result);
+      NS_OK
+    }
+    _ => NS_OK,
+  }
+}
+
+#[no_mangle]
+pub extern "C" fn mozurl_relative(url1: &MozURL, url2: &MozURL, result: &mut nsACString) -> nsresult {
+  if url1.url == url2.url {
+    result.truncate();
+    return NS_OK;
+  }
+
+  if url1.scheme() != url2.scheme() ||
+     url1.host() != url2.host() ||
+     url1.username() != url2.username() ||
+     url1.password() != url2.password() ||
+     url1.port() != url2.port() {
+    result.assign(url2.as_ref());
+    return NS_OK;
+  }
+
+  match (url1.path_segments(), url2.path_segments()) {
+    (Some(mut path1), Some(mut path2)) => {
+      // Exhaust the part of the iterators that match
+      while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) {
+        if p1 != p2 {
+          break;
+        }
+      }
+
+      result.truncate();
+      for _ in path1 {
+        result.append("../");
+      }
+      for p2 in path2 {
+        result.append(p2);
+        result.append("/");
+      }
+    }
+    _ => {
+      result.assign(url2.as_ref());
+    }
+  }
+  NS_OK
+}
+
+/// This type is used by nsStandardURL
+#[no_mangle]
+pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, addr: &mut nsACString) -> nsresult {
+  let ip6 = try_or_malformed!(str::from_utf8(input));
+  let host = try_or_malformed!(url::Host::parse(ip6));
+  let _ = write!(addr, "{}", host);
+  NS_OK
+}
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -19,17 +19,17 @@
 #include "nsIURLParser.h"
 #include "nsNetCID.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
 #include <algorithm>
 #include "nsContentUtils.h"
 #include "prprf.h"
 #include "nsReadableUtils.h"
-#include "rust-url-capi/src/rust-url-capi.h"
+#include "mozilla/net/MozURL_ffi.h"
 
 
 //
 // setenv MOZ_LOG nsStandardURL:5
 //
 static LazyLogModule gStandardURLLog("nsStandardURL");
 
 // The Chromium code defines its own LOG macro which we don't want
deleted file mode 100644
--- a/netwerk/base/rust-url-capi/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "rust_url_capi"
-version = "0.0.1"
-authors = ["Valentin Gosu <valentin.gosu@gmail.com>"]
-
-[lib]
-name = "rust_url_capi"
-
-[dependencies]
-libc = "0.2.0"
-url = "1.5.1"
-nsstring = { path = "../../../servo/support/gecko/nsstring" }
-nserror = { path = "../../../xpcom/rust/nserror" }
deleted file mode 100644
--- a/netwerk/base/rust-url-capi/src/lib.rs
+++ /dev/null
@@ -1,611 +0,0 @@
-/* -*- Mode: rust; rust-indent-offset: 2 -*- */
-/* 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/. */
-
-extern crate url;
-use url::{Url, ParseOptions, Position};
-use url::quirks;
-
-extern crate libc;
-use libc::size_t;
-
-extern crate nsstring;
-use nsstring::nsACString;
-
-extern crate nserror;
-use nserror::*;
-
-use std::mem;
-use std::str;
-use std::ptr;
-
-fn parser<'a>() -> ParseOptions<'a> {
-   Url::options()
-}
-
-fn default_port(scheme: &str) -> Option<u32> {
-    match scheme {
-        "ftp" => Some(21),
-        "gopher" => Some(70),
-        "http" => Some(80),
-        "https" => Some(443),
-        "ws" => Some(80),
-        "wss" => Some(443),
-        "rtsp" => Some(443),
-        "moz-anno" => Some(443),
-        "android" => Some(443),
-        _ => None,
-    }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_new(spec: &nsACString, baseptr: Option<&Url>) -> *mut Url {
-  let url_spec = match str::from_utf8(spec) {
-    Ok(spec) => spec,
-    Err(_) => return ptr::null_mut(),
-  };
-
-  if let Some(base) = baseptr {
-    match base.join(url_spec) {
-         Ok(url) => return Box::into_raw(Box::new(url)),
-         Err(_) => return ptr::null_mut()
-    };
-  }
-
-  match parser().parse(url_spec) {
-    Ok(url) => Box::into_raw(Box::new(url)),
-    Err(_) => return ptr::null_mut(),
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_clone(urlptr: Option<&Url>) -> *mut Url {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return ptr::null_mut();
-  };
-
-  return Box::into_raw(Box::new(url.clone()));
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rusturl_free(urlptr: *mut Url) {
-  if urlptr.is_null() {
-    return;
-  }
-  Box::from_raw(urlptr);
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_spec(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(url.as_ref());
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_scheme(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(&url.scheme());
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_username(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  if url.cannot_be_a_base() {
-      cont.assign("");
-  } else {
-      cont.assign(url.username());
-  }
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_password(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(url.password().unwrap_or(""));
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_host(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(url.host_str().unwrap_or(""));
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_port(urlptr: Option<&Url>, port: &mut i32) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  match url.port() {
-    Some(p) => {
-      *port = p as i32;
-    }
-    None => {
-      // NOTE: Gecko uses -1 to represent the default port
-      *port = -1;
-    }
-  }
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_filepath(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(&url.path());
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_path(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(&url[Position::BeforePath..]);
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_query(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(url.query().unwrap_or(""));
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_fragment(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign(url.fragment().unwrap_or(""));
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_has_fragment(urlptr: Option<&Url>, has_fragment: &mut bool) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  *has_fragment = url.fragment().is_some();
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_get_origin(urlptr: Option<&Url>, origin: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  origin.assign(&url.origin().ascii_serialization());
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_scheme(urlptr: Option<&mut Url>, scheme: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let scheme_ = match str::from_utf8(scheme) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_protocol(url, scheme_) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_username(urlptr: Option<&mut Url>, username: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let username_ = match str::from_utf8(username) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_username(url, username_) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_password(urlptr: Option<&mut Url>, password: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let password_ = match str::from_utf8(password) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_password(url, password_) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_host_port(urlptr: Option<&mut Url>, host_port: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let host_port_ = match str::from_utf8(host_port) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_host(url, host_port_) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_host_and_port(urlptr: Option<&mut Url>, host_and_port: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let _ = url.set_port(None);
-  let host_and_port_ = match str::from_utf8(host_and_port) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_host(url, host_and_port_) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_host(urlptr: Option<&mut Url>, host: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let hostname = match str::from_utf8(host) {
-    Ok(h) => h,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_hostname(url, hostname) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_port(urlptr: Option<&mut Url>, port: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let port_ = match str::from_utf8(port) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  match quirks::set_port(url, port_) {
-    Ok(()) => NS_OK,
-    Err(()) => NS_ERROR_MALFORMED_URI,
-  }
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_port_no(urlptr: Option<&mut Url>, new_port: i32) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  if url.cannot_be_a_base() {
-    return NS_ERROR_MALFORMED_URI;
-  }
-
-  if url.scheme() == "file" {
-    return NS_ERROR_MALFORMED_URI;
-  }
-  match default_port(url.scheme()) {
-    Some(def_port) => if new_port == def_port as i32 {
-      let _ = url.set_port(None);
-      return NS_OK;
-    },
-    None => {}
-  };
-
-  if new_port > std::u16::MAX as i32 || new_port < 0 {
-      let _ = url.set_port(None);
-  } else {
-      let _ = url.set_port(Some(new_port as u16));
-  }
-
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_path(urlptr: Option<&mut Url>, path: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let path_ = match str::from_utf8(path) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  quirks::set_pathname(url, path_);
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_query(urlptr: Option<&mut Url>, query: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let query_ = match str::from_utf8(query) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  quirks::set_search(url, query_);
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_set_fragment(urlptr: Option<&mut Url>, fragment: &nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let fragment_ = match str::from_utf8(fragment) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
-  };
-
-  quirks::set_hash(url, fragment_);
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_resolve(urlptr: Option<&Url>, resolve: &nsACString, cont: &mut nsACString) -> nsresult {
-  let url = if let Some(url) = urlptr {
-    url
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  let resolve_ = match str::from_utf8(resolve) {
-    Ok(p) => p,
-    Err(_) => return NS_ERROR_FAILURE,
-  };
-
-  if let Ok(ref u) = parser().base_url(Some(&url)).parse(resolve_) {
-    cont.assign(u.as_ref());
-  } else {
-    cont.assign("");
-  }
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_common_base_spec(urlptr1: Option<&Url>, urlptr2: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let (url1, url2) = if let (Some(url1), Some(url2)) = (urlptr1, urlptr2) {
-    (url1, url2)
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign("");
-
-  if url1 == url2 {
-    cont.assign(url1.as_ref());
-    return NS_OK;
-  }
-
-  if url1.scheme() != url2.scheme() ||
-     url1.host() != url2.host() ||
-     url1.username() != url2.username() ||
-     url1.password() != url2.password() ||
-     url1.port() != url2.port() {
-    return NS_OK;
-  }
-
-  let path1 = match url1.path_segments() {
-    Some(path) => path,
-    None => return NS_OK,
-  };
-  let path2 = match url2.path_segments() {
-    Some(path) => path,
-    None => return NS_OK,
-  };
-
-  let mut url = url1.clone();
-  url.set_query(None);
-  let _ = url.set_host(None);
-  {
-    let mut new_segments = if let Ok(segments) = url.path_segments_mut() {
-      segments
-    } else {
-      return NS_OK;
-    };
-
-    for (p1, p2) in path1.zip(path2) {
-      if p1 != p2 {
-        break;
-      } else {
-        new_segments.push(p1);
-      }
-    }
-  }
-
-  cont.assign(url.as_ref());
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_relative_spec(urlptr1: Option<&Url>, urlptr2: Option<&Url>, cont: &mut nsACString) -> nsresult {
-  let (url1, url2) = if let (Some(url1), Some(url2)) = (urlptr1, urlptr2) {
-    (url1, url2)
-  } else {
-    return NS_ERROR_INVALID_ARG;
-  };
-
-  cont.assign("");
-
-  if url1 == url2 {
-    return NS_OK;
-  }
-
-  if url1.scheme() != url2.scheme() ||
-     url1.host() != url2.host() ||
-     url1.username() != url2.username() ||
-     url1.password() != url2.password() ||
-     url1.port() != url2.port() {
-    cont.assign(url2.as_ref());
-    return NS_OK;
-  }
-
-  let mut path1 = match url1.path_segments() {
-    Some(path) => path,
-    None => {
-      cont.assign(url2.as_ref());
-      return NS_OK;
-    }
-  };
-  let mut path2 = match url2.path_segments() {
-    Some(path) => path,
-    None => {
-      cont.assign(url2.as_ref());
-      return NS_OK;
-    }
-  };
-
-  // TODO: file:// on WIN?
-
-  // Exhaust the part of the iterators that match
-  while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) {
-    if p1 != p2 {
-      break;
-    }
-  }
-
-  let mut buffer = String::new();
-  for _ in path1 {
-    buffer.push_str("../");
-  }
-  for p2 in path2 {
-    buffer.push_str(p2);
-    buffer.push('/');
-  }
-
-  cont.assign(&buffer);
-  NS_OK
-}
-
-#[no_mangle]
-pub extern "C" fn sizeof_rusturl() -> size_t {
-  mem::size_of::<Url>()
-}
-
-#[no_mangle]
-pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, cont: &mut nsACString) -> nsresult {
-  let ip6 = match str::from_utf8(input) {
-    Ok(content) => content,
-    Err(_) => return NS_ERROR_FAILURE,
-  };
-
-  let h = match url::Host::parse(ip6) {
-    Ok(host) => host,
-    // XXX: Do we want to change our error message based on the error type?
-    Err(_) => return NS_ERROR_MALFORMED_URI,
-  };
-
-  cont.assign(&h.to_string());
-  NS_OK
-}
deleted file mode 100644
--- a/netwerk/base/rust-url-capi/src/rust-url-capi.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef __RUST_URL_CAPI
-#define __RUST_URL_CAPI
-#include <stdlib.h>
-#include "nsString.h"
-
-extern "C" {
-
-// NOTE: Preconditions
-// * All nsACString* pointers are unchecked, and must be non-null
-// * The int32_t* and bool* outparameter pointer is unchecked, and must
-//   be non-null.
-// * All rusturl* pointers must refer to pointers which are returned
-//   by rusturl_new, and must be freed with rusturl_free.
-
-// The `rusturl` opaque type is equivalent to the rust type `::url::Url`
-struct rusturl;
-
-rusturl* rusturl_new(const nsACString* spec, const rusturl* base);
-rusturl* rusturl_clone(const rusturl* url);
-/* unsafe */ void rusturl_free(rusturl* url);
-
-nsresult rusturl_get_spec(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_scheme(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_username(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_password(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_host(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_port(const rusturl* url, int32_t* port);
-nsresult rusturl_get_filepath(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_path(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_query(const rusturl* url, nsACString* cont);
-nsresult rusturl_get_fragment(const rusturl* url, nsACString* cont);
-nsresult rusturl_has_fragment(const rusturl* url, bool* has_fragment);
-nsresult rusturl_get_origin(const rusturl* url, nsACString* origin);
-
-nsresult rusturl_set_scheme(rusturl* url, const nsACString* scheme);
-nsresult rusturl_set_username(rusturl* url, const nsACString* user);
-nsresult rusturl_set_password(rusturl* url, const nsACString* password);
-nsresult rusturl_set_host_port(rusturl* url, const nsACString* hostport);
-nsresult rusturl_set_host_and_port(rusturl* url, const nsACString* hostport);
-nsresult rusturl_set_host(rusturl* url, const nsACString* host);
-nsresult rusturl_set_port(rusturl* url, const nsACString* port);
-nsresult rusturl_set_port_no(rusturl* url, const int32_t port);
-nsresult rusturl_set_path(rusturl* url, const nsACString* path);
-nsresult rusturl_set_query(rusturl* url, const nsACString* query);
-nsresult rusturl_set_fragment(rusturl* url, const nsACString* fragment);
-
-nsresult rusturl_resolve(const rusturl* url, const nsACString* relative, nsACString* cont);
-nsresult rusturl_common_base_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
-nsresult rusturl_relative_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
-
-nsresult rusturl_parse_ipv6addr(const nsACString* input, nsACString* cont);
-
-size_t sizeof_rusturl();
-
-}
-
-#endif // __RUST_URL_CAPI
--- a/netwerk/test/gtest/TestMozURL.cpp
+++ b/netwerk/test/gtest/TestMozURL.cpp
@@ -1,13 +1,13 @@
 #include "gtest/gtest.h"
 #include "gtest/MozGTestBench.h" // For MOZ_GTEST_BENCH
 
 #include "nsCOMPtr.h"
-#include "../../base/MozURL.h"
+#include "mozilla/net/MozURL.h"
 
 using namespace mozilla::net;
 
 TEST(TestMozURL, Getters)
 {
   nsAutoCString href("http://user:pass@example.com/path?query#ref");
   RefPtr<MozURL> url;
   ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
@@ -35,17 +35,17 @@ TEST(TestMozURL, Getters)
   ASSERT_EQ(url->GetQuery(out), NS_OK);
   ASSERT_TRUE(out.EqualsLiteral("query"));
 
   ASSERT_EQ(url->GetRef(out), NS_OK);
   ASSERT_TRUE(out.EqualsLiteral("ref"));
 
   url = nullptr;
   ASSERT_EQ(MozURL::Init(getter_AddRefs(url), NS_LITERAL_CSTRING("")),
-            NS_ERROR_FAILURE);
+            NS_ERROR_MALFORMED_URI);
   ASSERT_EQ(url, nullptr);
 }
 
 TEST(TestMozURL, MutatorChain)
 {
   nsAutoCString href("http://user:pass@example.com/path?query#ref");
   RefPtr<MozURL> url;
   ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -8,17 +8,17 @@ description = "Shared Rust code for libx
 [dependencies]
 geckoservo = { path = "../../../../servo/ports/geckolib", optional = true }
 mp4parse_capi = { path = "../../../../media/mp4parse-rust/mp4parse_capi" }
 nsstring = { path = "../../../../servo/support/gecko/nsstring" }
 nserror = { path = "../../../../xpcom/rust/nserror" }
 netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }
 xpcom = { path = "../../../../xpcom/rust/xpcom" }
 prefs_parser = { path = "../../../../modules/libpref/parser" }
-rust_url_capi = { path = "../../../../netwerk/base/rust-url-capi" }
+mozurl = { path = "../../../../netwerk/base/mozurl" }
 webrender_bindings = { path = "../../../../gfx/webrender_bindings", optional = true }
 cubeb-pulse = { path = "../../../../media/libcubeb/cubeb-pulse-rs", optional = true, features=["pulse-dlopen"] }
 cubeb-sys = { version = "0.5.0", optional = true, features=["gecko-in-tree"] }
 encoding_c = "0.8.0"
 encoding_glue = { path = "../../../../intl/encoding_glue" }
 audioipc-client = { path = "../../../../media/audioipc/client", optional = true }
 audioipc-server = { path = "../../../../media/audioipc/server", optional = true }
 u2fhid = { path = "../../../../dom/webauthn/u2f-hid-rs" }
--- a/toolkit/library/rust/shared/lib.rs
+++ b/toolkit/library/rust/shared/lib.rs
@@ -6,17 +6,17 @@
 extern crate geckoservo;
 
 extern crate mp4parse_capi;
 extern crate nsstring;
 extern crate nserror;
 extern crate xpcom;
 extern crate netwerk_helper;
 extern crate prefs_parser;
-extern crate rust_url_capi;
+extern crate mozurl;
 #[cfg(feature = "quantum_render")]
 extern crate webrender_bindings;
 #[cfg(feature = "cubeb_pulse_rust")]
 extern crate cubeb_pulse;
 extern crate encoding_c;
 extern crate encoding_glue;
 #[cfg(feature = "cubeb-remoting")]
 extern crate audioipc_client;