Bug 1151899 - Add RustURL which implements nsIURI,nsIURL,nsIStandardURL,etc draft
authorValentin Gosu <valentin.gosu@gmail.com>
Sat, 05 Nov 2016 17:52:40 +0100
changeset 434396 54a9d6c4c522a11160f0ff37140e5a2c69a9bd04
parent 434395 8c644fb245bccc0b122942c151e499ca3d1426a8
child 434397 1fb75a801bcf71a67fadae84d2dc45bacb03371f
push id34759
push uservalentin.gosu@gmail.com
push dateSat, 05 Nov 2016 16:55:16 +0000
bugs1151899
milestone52.0a1
Bug 1151899 - Add RustURL which implements nsIURI,nsIURL,nsIStandardURL,etc MozReview-Commit-ID: EExfZ8rYPd9
netwerk/base/RustURL.cpp
netwerk/base/RustURL.h
netwerk/base/moz.build
netwerk/base/nsStandardURL.cpp
new file mode 100644
--- /dev/null
+++ b/netwerk/base/RustURL.cpp
@@ -0,0 +1,747 @@
+#include "RustURL.h"
+#include "nsCOMPtr.h"
+#include "nsURLHelper.h"
+
+#ifndef MOZ_RUST_URLPARSE
+  #error "Should be defined"
+#endif
+
+extern "C" int32_t c_fn_set_size(void * container, size_t size)
+{
+  ((nsACString *) container)->SetLength(size);
+  return 0;
+}
+
+extern "C" char * c_fn_get_buffer(void * container)
+{
+  return ((nsACString *) container)->BeginWriting();
+}
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ADDREF(RustURL)
+NS_IMPL_RELEASE(RustURL)
+
+NS_INTERFACE_MAP_BEGIN(RustURL)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL)
+  NS_INTERFACE_MAP_ENTRY(nsIURI)
+  NS_INTERFACE_MAP_ENTRY(nsIURL)
+  // NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL)
+  NS_INTERFACE_MAP_ENTRY(nsIStandardURL)
+  // NS_INTERFACE_MAP_ENTRY(nsISerializable)
+  NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
+  NS_INTERFACE_MAP_ENTRY(nsIMutable)
+  // NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
+  // NS_INTERFACE_MAP_ENTRY(nsISensitiveInfoHiddenURI)
+  NS_INTERFACE_MAP_ENTRY(nsISizeOf)
+NS_INTERFACE_MAP_END
+
+#define ENSURE_MUTABLE() \
+  PR_BEGIN_MACRO \
+    if (!mMutable) { \
+      NS_WARNING("attempt to modify an immutable RustURL"); \
+      return NS_ERROR_ABORT; \
+    } \
+  PR_END_MACRO
+
+RustURL::RustURL()
+  : mMutable(true)
+{
+
+}
+
+RustURL::~RustURL()
+{
+
+}
+
+NS_IMETHODIMP
+RustURL::GetSpec(nsACString & aSpec)
+{
+  return (nsresult) rusturl_get_spec(mURL.get(), &aSpec);
+}
+
+NS_IMETHODIMP
+RustURL::SetSpec(const nsACString & aSpec)
+{
+  ENSURE_MUTABLE();
+
+  rusturl* ptr = rusturl_new(aSpec.BeginReading(), aSpec.Length());
+  if (!ptr) {
+    return NS_ERROR_FAILURE;
+  }
+  mURL.reset(ptr);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetPrePath(nsACString & aPrePath)
+{
+  // TODO: use slicing API to get actual prepath
+  aPrePath.Truncate();
+  nsAutoCString rustResult;
+  nsAutoCString part;
+
+  nsresult rv = GetScheme(part);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rustResult.Append(part);
+  rustResult += "://";
+
+  rv = GetUserPass(part);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (!part.IsEmpty()) {
+      rustResult += part;
+      rustResult += "@";
+  }
+
+  rv = GetHostPort(part);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rustResult += part;
+  aPrePath.Assign(rustResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetScheme(nsACString & aScheme)
+{
+  return (nsresult) rusturl_get_scheme(mURL.get(), &aScheme);
+}
+
+NS_IMETHODIMP
+RustURL::SetScheme(const nsACString & aScheme)
+{
+  ENSURE_MUTABLE();
+
+  return (nsresult) rusturl_set_scheme(mURL.get(), aScheme.BeginReading(), aScheme.Length());;
+}
+
+NS_IMETHODIMP
+RustURL::GetUserPass(nsACString & aUserPass)
+{
+  nsresult rv = GetUsername(aUserPass);
+  if (NS_FAILED(rv)) {
+    aUserPass.Truncate();
+    return rv;
+  }
+
+  nsAutoCString password;
+  rv = GetPassword(password);
+  if (NS_FAILED(rv)) {
+    aUserPass.Truncate();
+    return rv;
+  }
+
+  if (password.Length()) {
+    aUserPass.Append(':');
+    aUserPass.Append(password);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SetUserPass(const nsACString & aUserPass)
+{
+  ENSURE_MUTABLE();
+
+  int32_t colonPos = aUserPass.FindChar(':');
+  nsAutoCString user;
+  nsAutoCString pass;
+  if (colonPos == kNotFound) {
+    user = aUserPass;
+  } else {
+    user = Substring(aUserPass, 0, colonPos);
+    pass = Substring(aUserPass, colonPos + 1, aUserPass.Length());
+  }
+
+  if (rusturl_set_username(mURL.get(), user.BeginReading(), user.Length()) != 0) {
+    return NS_ERROR_FAILURE;
+  }
+  return (nsresult) rusturl_set_password(mURL.get(), pass.BeginReading(), pass.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetUsername(nsACString & aUsername)
+{
+  return (nsresult) rusturl_get_username(mURL.get(), &aUsername);
+}
+
+NS_IMETHODIMP
+RustURL::SetUsername(const nsACString & aUsername)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_username(mURL.get(), aUsername.BeginReading(), aUsername.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetPassword(nsACString & aPassword)
+{
+  return (nsresult) rusturl_get_password(mURL.get(), &aPassword);
+}
+
+NS_IMETHODIMP
+RustURL::SetPassword(const nsACString & aPassword)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_password(mURL.get(), aPassword.BeginReading(), aPassword.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetHostPort(nsACString & aHostPort)
+{
+  nsresult rv = (nsresult) rusturl_get_host(mURL.get(), &aHostPort);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  int32_t port;
+  rv = GetPort(&port);
+  if (NS_FAILED(rv)) {
+      return rv;
+  }
+  if (port >= 0) {
+      aHostPort.Append(':');
+      aHostPort.AppendInt(port);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SetHostPort(const nsACString & aHostPort)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_host_and_port(mURL.get(), aHostPort.BeginReading(), aHostPort.Length());
+}
+
+NS_IMETHODIMP
+RustURL::SetHostAndPort(const nsACString & hostport)
+{
+  ENSURE_MUTABLE();
+  // TODO: check that this behaves properly
+  return (nsresult) rusturl_set_host_and_port(mURL.get(), hostport.BeginReading(), hostport.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetHost(nsACString & aHost)
+{
+  nsAutoCString host;
+  nsresult rv = (nsresult) rusturl_get_host(mURL.get(), &host);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  if (host.Length() > 0 && host.First() == '[' && host.Last() == ']') {
+    aHost = Substring(host, 1, host.Length() - 2);
+    return NS_OK;
+  }
+
+  aHost = host;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SetHost(const nsACString & aHost)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_host(mURL.get(), aHost.BeginReading(), aHost.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetPort(int32_t *aPort)
+{
+  if (!mURL) {
+    return NS_ERROR_FAILURE;
+  }
+  *aPort = rusturl_get_port(mURL.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SetPort(int32_t aPort)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_port_no(mURL.get(), aPort);
+}
+
+NS_IMETHODIMP
+RustURL::GetPath(nsACString & aPath)
+{
+  return (nsresult) rusturl_get_path(mURL.get(), &aPath);
+}
+
+NS_IMETHODIMP
+RustURL::SetPath(const nsACString & aPath)
+{
+  ENSURE_MUTABLE();
+
+  nsAutoCString path;
+  nsresult rv = GetPrePath(path);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  if (aPath.Length() > 0 && aPath.First() != '/') {
+    path.Append('/');
+  }
+  path.Append(aPath);
+
+  return SetSpec(path);
+}
+
+NS_IMETHODIMP
+RustURL::Equals(nsIURI *other, bool *_retval)
+{
+  *_retval = false;
+  nsAutoCString spec;
+  nsresult rv = other->GetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsAutoCString rustSpec;
+  rv = GetSpec(rustSpec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (rustSpec == spec) {
+    *_retval = true;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SchemeIs(const char * aScheme, bool *_retval)
+{
+  *_retval = false;
+  nsAutoCString scheme;
+  nsresult rv = GetScheme(scheme);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (scheme.Equals(aScheme)) {
+    *_retval = true;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::Clone(nsIURI * *_retval)
+{
+  RefPtr<RustURL> url = new RustURL();
+  nsAutoCString spec;
+  nsresult rv = GetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = url->SetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  url.forget(_retval);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::Resolve(const nsACString & relativePath, nsACString & _retval)
+{
+  return (nsresult) rusturl_resolve(mURL.get(), relativePath.BeginReading(), relativePath.Length(), &_retval);
+}
+
+NS_IMETHODIMP
+RustURL::GetAsciiSpec(nsACString & aAsciiSpec)
+{
+  return GetSpec(aAsciiSpec);
+}
+
+NS_IMETHODIMP
+RustURL::GetAsciiHostPort(nsACString & aAsciiHostPort)
+{
+  return GetHostPort(aAsciiHostPort);
+}
+
+NS_IMETHODIMP
+RustURL::GetAsciiHost(nsACString & aAsciiHost)
+{
+  return GetHost(aAsciiHost);
+}
+
+NS_IMETHODIMP
+RustURL::GetOriginCharset(nsACString & aOriginCharset)
+{
+  // TODO: do we want to support other charsets?
+  aOriginCharset.AssignLiteral("UTF-8");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetRef(nsACString & aRef)
+{
+  return (nsresult) rusturl_get_fragment(mURL.get(), &aRef);
+}
+
+NS_IMETHODIMP
+RustURL::SetRef(const nsACString & aRef)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_fragment(mURL.get(), aRef.BeginReading(), aRef.Length());
+}
+
+NS_IMETHODIMP
+RustURL::EqualsExceptRef(nsIURI *other, bool *_retval)
+{
+  *_retval = false;
+  nsAutoCString otherSpec;
+  nsresult rv = other->GetSpecIgnoringRef(otherSpec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsAutoCString thisSpec;
+  rv = GetSpecIgnoringRef(thisSpec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (thisSpec == otherSpec) {
+    *_retval = true;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::CloneIgnoringRef(nsIURI * *_retval)
+{
+  return CloneWithNewRef(NS_LITERAL_CSTRING(""), _retval);
+}
+
+NS_IMETHODIMP
+RustURL::CloneWithNewRef(const nsACString & newRef, nsIURI * *_retval)
+{
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = Clone(getter_AddRefs(uri));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = uri->SetRef(newRef);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  uri.forget(_retval);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetSpecIgnoringRef(nsACString & aSpecIgnoringRef)
+{
+  nsresult rv = GetSpec(aSpecIgnoringRef);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  int32_t pos = aSpecIgnoringRef.FindChar('#');
+  if (pos == kNotFound) {
+    return NS_OK;
+  }
+
+  aSpecIgnoringRef.Truncate(pos);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetHasRef(bool *aHasRef)
+{
+  *aHasRef = false;
+  int32_t rv = rusturl_has_fragment(mURL.get());
+  if (rv == 1) {
+    *aHasRef = true;
+  } else if (rv < 0) {
+    return (nsresult) rv;
+  }
+  return NS_OK;
+}
+
+/// nsIURL
+
+NS_IMETHODIMP
+RustURL::GetFilePath(nsACString & aFilePath)
+{
+  return (nsresult) rusturl_get_path(mURL.get(), &aFilePath);
+}
+
+NS_IMETHODIMP
+RustURL::SetFilePath(const nsACString & aFilePath)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_path(mURL.get(), aFilePath.BeginReading(), aFilePath.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetQuery(nsACString & aQuery)
+{
+  return (nsresult) rusturl_get_query(mURL.get(), &aQuery);
+}
+
+NS_IMETHODIMP
+RustURL::SetQuery(const nsACString & aQuery)
+{
+  ENSURE_MUTABLE();
+  return (nsresult) rusturl_set_query(mURL.get(), aQuery.BeginReading(), aQuery.Length());
+}
+
+NS_IMETHODIMP
+RustURL::GetDirectory(nsACString & aDirectory)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::SetDirectory(const nsACString & aDirectory)
+{
+  ENSURE_MUTABLE();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::GetFileName(nsACString & aFileName)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::SetFileName(const nsACString & aFileName)
+{
+  ENSURE_MUTABLE();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::GetFileBaseName(nsACString & aFileBaseName)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::SetFileBaseName(const nsACString & aFileBaseName)
+{
+  ENSURE_MUTABLE();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::GetFileExtension(nsACString & aFileExtension)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::SetFileExtension(const nsACString & aFileExtension)
+{
+  ENSURE_MUTABLE();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::GetCommonBaseSpec(nsIURI *aURIToCompare, nsACString & _retval)
+{
+  RefPtr<RustURL> url = new RustURL();
+  nsAutoCString spec;
+  nsresult rv = aURIToCompare->GetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = url->SetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return (nsresult) rusturl_common_base_spec(mURL.get(), url->mURL.get(), &_retval);
+}
+
+NS_IMETHODIMP
+RustURL::GetRelativeSpec(nsIURI *aURIToCompare, nsACString & _retval)
+{
+  RefPtr<RustURL> url = new RustURL();
+  nsAutoCString spec;
+  nsresult rv = aURIToCompare->GetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = url->SetSpec(spec);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return (nsresult) rusturl_relative_spec(mURL.get(), url->mURL.get(), &_retval);
+}
+
+// nsIFileURL
+
+
+NS_IMETHODIMP
+RustURL::GetFile(nsIFile * *aFile)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::SetFile(nsIFile *aFile)
+{
+  ENSURE_MUTABLE();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsIStandardURL
+
+NS_IMETHODIMP
+RustURL::Init(uint32_t aUrlType, int32_t aDefaultPort, const nsACString & aSpec, const char * aOriginCharset, nsIURI *aBaseURI)
+{
+  ENSURE_MUTABLE();
+
+  if (aBaseURI && net_IsAbsoluteURL(aSpec)) {
+      aBaseURI = nullptr;
+  }
+
+  if (!aBaseURI) {
+      return SetSpec(aSpec);
+  }
+
+  nsAutoCString buf;
+  nsresult rv = aBaseURI->Resolve(aSpec, buf);
+  if (NS_FAILED(rv)) return rv;
+
+  return SetSpec(buf);
+}
+
+NS_IMETHODIMP
+RustURL::SetDefaultPort(int32_t aNewDefaultPort)
+{
+  ENSURE_MUTABLE();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsISerializable
+
+NS_IMETHODIMP
+RustURL::Read(nsIObjectInputStream *aInputStream)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::Write(nsIObjectOutputStream *aOutputStream)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+RustURL::Serialize(URIParams& aParams)
+{
+  // TODO
+}
+
+bool
+RustURL::Deserialize(const URIParams& aParams)
+{
+  // TODO
+  return false;
+}
+
+// nsIClassInfo
+
+NS_IMETHODIMP
+RustURL::GetInterfaces(uint32_t *count, nsIID ***array)
+{
+  *count = 0;
+  *array = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetScriptableHelper(nsIXPCScriptable * *_retval)
+{
+  *_retval = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetContractID(char * *aContractID)
+{
+  *aContractID = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetClassDescription(char * *aClassDescription)
+{
+  *aClassDescription = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetClassID(nsCID **aClassID)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+RustURL::GetFlags(uint32_t *aFlags)
+{
+  *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/// nsIMutable
+
+NS_IMETHODIMP
+RustURL::GetMutable(bool *value)
+{
+  *value = mMutable;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SetMutable(bool value)
+{
+  if (mMutable || !value) {
+    return NS_ERROR_FAILURE;
+  }
+  mMutable = value;
+  return NS_OK;
+}
+
+// nsISensitiveInfoHiddenURI
+
+NS_IMETHODIMP
+RustURL::GetSensitiveInfoHiddenSpec(nsACString & _retval)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsISizeOf
+
+size_t
+RustURL::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  return mURL.get() ? sizeof_rusturl() : 0;
+}
+
+size_t
+RustURL::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+}
+
+} // namespace net
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/netwerk/base/RustURL.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 RustURL_h__
+#define RustURL_h__
+
+#include "nsISerializable.h"
+#include "nsIFileURL.h"
+#include "nsIStandardURL.h"
+#include "nsIClassInfo.h"
+#include "nsISizeOf.h"
+#include "nsIIPCSerializableURI.h"
+#include "nsISensitiveInfoHiddenURI.h"
+
+#include "rust-url-capi/src/rust-url-capi.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla {
+namespace net {
+
+class RustURL
+  : public nsIFileURL
+  , public nsIStandardURL
+  , public nsISerializable
+  , public nsIClassInfo
+  , public nsISizeOf
+  , public nsIIPCSerializableURI
+  , public nsISensitiveInfoHiddenURI
+{
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIURI
+  NS_DECL_NSIURL
+  NS_DECL_NSIFILEURL
+  NS_DECL_NSISTANDARDURL
+  NS_DECL_NSISERIALIZABLE
+  NS_DECL_NSICLASSINFO
+  NS_DECL_NSIMUTABLE
+  NS_DECL_NSIIPCSERIALIZABLEURI
+  NS_DECL_NSISENSITIVEINFOHIDDENURI
+
+  RustURL();
+  // nsISizeOf
+  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
+  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
+private:
+  virtual ~RustURL();
+
+  struct FreeRustURL { void operator()(rusturl* aPtr) { rusturl_free(aPtr); } };
+  mutable mozilla::UniquePtr<rusturl, FreeRustURL> mURL;
+
+  bool mMutable;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // RustURL_h__
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -253,16 +253,20 @@ UNIFIED_SOURCES += [
     'RequestContextService.cpp',
     'SimpleBuffer.cpp',
     'StreamingProtocolService.cpp',
     'ThrottleQueue.cpp',
     'Tickler.cpp',
     'TLSServerSocket.cpp',
 ]
 
+if CONFIG['MOZ_RUST']:
+    EXPORTS.mozilla.net += [ 'RustURL.h' ]
+    UNIFIED_SOURCES += [ 'RustURL.cpp' ]
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'nsURLHelperWin.cpp',
         'ShutdownLayer.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     SOURCES += [
         'nsURLHelperOSX.cpp',
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -60,29 +60,16 @@ static LazyLogModule gStandardURLLog("ns
     if (!mMutable) { \
         NS_WARNING("attempt to modify an immutable nsStandardURL"); \
         return NS_ERROR_ABORT; \
     } \
   PR_END_MACRO
 
 //----------------------------------------------------------------------------
 
-#ifdef MOZ_RUST_URLPARSE
-extern "C" int32_t c_fn_set_size(void * container, size_t size)
-{
-  ((nsACString *) container)->SetLength(size);
-  return 0;
-}
-
-extern "C" char * c_fn_get_buffer(void * container)
-{
-  return ((nsACString *) container)->BeginWriting();
-}
-#endif
-
 static nsresult
 EncodeString(nsIUnicodeEncoder *encoder, const nsAFlatString &str, nsACString &result)
 {
     nsresult rv;
     int32_t len = str.Length();
     int32_t maxlen;
 
     rv = encoder->GetMaxLength(str.get(), len, &maxlen);