Bug 1151899 - Add RustURL which implements nsIURI,nsIURL,nsIStandardURL,etc; r=bagder
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 08 Nov 2016 00:42:27 +0100
changeset 441149 96f002110a9addfbc4ab5b4935e6eee3fdfcb190
parent 441148 627cc696e6e511f54c5f8e9d8cf49a7fee0a2e33
child 441150 ca90dbb06b74eaaff262624aeb9c0dbbed64b46a
push id36375
push userbmo:rchien@mozilla.com
push dateFri, 18 Nov 2016 16:08:18 +0000
reviewersbagder
bugs1151899
milestone53.0a1
Bug 1151899 - Add RustURL which implements nsIURI,nsIURL,nsIStandardURL,etc; r=bagder MozReview-Commit-ID: 2rVu4t66cfD
netwerk/base/RustURL.cpp
netwerk/base/RustURL.h
netwerk/base/moz.build
netwerk/base/nsStandardURL.cpp
netwerk/base/rust-url-capi/src/lib.rs
netwerk/base/rust-url-capi/src/rust-url-capi.h
new file mode 100644
--- /dev/null
+++ b/netwerk/base/RustURL.cpp
@@ -0,0 +1,752 @@
+#include "RustURL.h"
+#include "nsCOMPtr.h"
+#include "nsURLHelper.h"
+
+#ifndef MOZ_RUST_URLPARSE
+  #error "Should be defined"
+#endif
+
+// the following two functions will be replaced with the Rust
+// nsstring bindings
+// allows Rust to resize a nsACString
+extern "C" int32_t c_fn_set_size(void * container, size_t size)
+{
+  ((nsACString *) container)->SetLength(size);
+  return 0;
+}
+
+// allows Rust to access the backing buffer of an nsACString
+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 static_cast<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 static_cast<nsresult>(rusturl_get_scheme(mURL.get(), &aScheme));
+}
+
+NS_IMETHODIMP
+RustURL::SetScheme(const nsACString & aScheme)
+{
+  ENSURE_MUTABLE();
+
+  return static_cast<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 static_cast<nsresult>(rusturl_set_password(mURL.get(), pass.BeginReading(), pass.Length()));
+}
+
+NS_IMETHODIMP
+RustURL::GetUsername(nsACString & aUsername)
+{
+  return static_cast<nsresult>(rusturl_get_username(mURL.get(), &aUsername));
+}
+
+NS_IMETHODIMP
+RustURL::SetUsername(const nsACString & aUsername)
+{
+  ENSURE_MUTABLE();
+  return static_cast<nsresult>(rusturl_set_username(mURL.get(), aUsername.BeginReading(), aUsername.Length()));
+}
+
+NS_IMETHODIMP
+RustURL::GetPassword(nsACString & aPassword)
+{
+  return static_cast<nsresult>(rusturl_get_password(mURL.get(), &aPassword));
+}
+
+NS_IMETHODIMP
+RustURL::SetPassword(const nsACString & aPassword)
+{
+  ENSURE_MUTABLE();
+  return static_cast<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 static_cast<nsresult>(rusturl_set_host_port(mURL.get(), aHostPort.BeginReading(), aHostPort.Length()));
+}
+
+NS_IMETHODIMP
+RustURL::SetHostAndPort(const nsACString & hostport)
+{
+  ENSURE_MUTABLE();
+  return static_cast<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 static_cast<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 static_cast<nsresult>(rusturl_set_port_no(mURL.get(), aPort));
+}
+
+NS_IMETHODIMP
+RustURL::GetPath(nsACString & aPath)
+{
+  return static_cast<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 *aRetVal)
+{
+  *aRetVal = 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) {
+    *aRetVal = true;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SchemeIs(const char * aScheme, bool *aRetVal)
+{
+  *aRetVal = false;
+  nsAutoCString scheme;
+  nsresult rv = GetScheme(scheme);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (scheme.Equals(aScheme)) {
+    *aRetVal = true;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::Clone(nsIURI * *aRetVal)
+{
+  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(aRetVal);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::Resolve(const nsACString & relativePath, nsACString & aRetVal)
+{
+  return static_cast<nsresult>(rusturl_resolve(mURL.get(), relativePath.BeginReading(), relativePath.Length(), &aRetVal));
+}
+
+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)
+{
+  aOriginCharset.AssignLiteral("UTF-8");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::GetRef(nsACString & aRef)
+{
+  return static_cast<nsresult>(rusturl_get_fragment(mURL.get(), &aRef));
+}
+
+NS_IMETHODIMP
+RustURL::SetRef(const nsACString & aRef)
+{
+  ENSURE_MUTABLE();
+  return static_cast<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 static_cast<nsresult>(rv);
+  }
+  return NS_OK;
+}
+
+/// nsIURL
+
+NS_IMETHODIMP
+RustURL::GetFilePath(nsACString & aFilePath)
+{
+  return static_cast<nsresult>(rusturl_get_path(mURL.get(), &aFilePath));
+}
+
+NS_IMETHODIMP
+RustURL::SetFilePath(const nsACString & aFilePath)
+{
+  ENSURE_MUTABLE();
+  return static_cast<nsresult>(rusturl_set_path(mURL.get(), aFilePath.BeginReading(), aFilePath.Length()));
+}
+
+NS_IMETHODIMP
+RustURL::GetQuery(nsACString & aQuery)
+{
+  return static_cast<nsresult>(rusturl_get_query(mURL.get(), &aQuery));
+}
+
+NS_IMETHODIMP
+RustURL::SetQuery(const nsACString & aQuery)
+{
+  ENSURE_MUTABLE();
+  return static_cast<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 static_cast<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 static_cast<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 *aValue)
+{
+  *aValue = mMutable;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RustURL::SetMutable(bool aValue)
+{
+  if (mMutable || !aValue) {
+    return NS_ERROR_FAILURE;
+  }
+  mMutable = aValue;
+  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
@@ -254,16 +254,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);
--- a/netwerk/base/rust-url-capi/src/lib.rs
+++ b/netwerk/base/rust-url-capi/src/lib.rs
@@ -231,21 +231,38 @@ pub unsafe extern "C" fn rusturl_set_pas
     Some(p) => p,
     None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed
   };
 
   quirks::set_password(url, password_).error_code()
 }
 
 #[no_mangle]
+pub unsafe extern "C" fn rusturl_set_host_port(urlptr: rusturl_ptr, host_port: *mut libc::c_char, len: size_t) -> i32 {
+  if urlptr.is_null() {
+    return NSError::InvalidArg.error_code();
+  }
+  let mut url: &mut Url = mem::transmute(urlptr);
+  let slice = std::slice::from_raw_parts(host_port as *const libc::c_uchar, len as usize);
+
+  let host_port_ = match str::from_utf8(slice).ok() {
+    Some(p) => p,
+    None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed
+  };
+
+  quirks::set_host(url, host_port_).error_code()
+}
+
+#[no_mangle]
 pub unsafe extern "C" fn rusturl_set_host_and_port(urlptr: rusturl_ptr, host_and_port: *mut libc::c_char, len: size_t) -> i32 {
   if urlptr.is_null() {
     return NSError::InvalidArg.error_code();
   }
   let mut url: &mut Url = mem::transmute(urlptr);
+  url.set_port(None);
   let slice = std::slice::from_raw_parts(host_and_port as *const libc::c_uchar, len as usize);
 
   let host_and_port_ = match str::from_utf8(slice).ok() {
     Some(p) => p,
     None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed
   };
 
   quirks::set_host(url, host_and_port_).error_code()
--- a/netwerk/base/rust-url-capi/src/rust-url-capi.h
+++ b/netwerk/base/rust-url-capi/src/rust-url-capi.h
@@ -25,16 +25,17 @@ int32_t rusturl_get_port(rusturl_ptr url
 int32_t rusturl_get_path(rusturl_ptr url, void*);
 int32_t rusturl_get_query(rusturl_ptr url, void*);
 int32_t rusturl_get_fragment(rusturl_ptr url, void*);
 int32_t rusturl_has_fragment(rusturl_ptr url); // 1 true, 0 false, < 0 error
 
 int32_t rusturl_set_scheme(rusturl_ptr url, const char *scheme, size_t len);
 int32_t rusturl_set_username(rusturl_ptr url, const char *user, size_t len);
 int32_t rusturl_set_password(rusturl_ptr url, const char *pass, size_t len);
+int32_t rusturl_set_host_port(rusturl_ptr url, const char *hostport, size_t len);
 int32_t rusturl_set_host_and_port(rusturl_ptr url, const char *hostport, size_t len);
 int32_t rusturl_set_host(rusturl_ptr url, const char *host, size_t len);
 int32_t rusturl_set_port(rusturl_ptr url, const char *port, size_t len);
 int32_t rusturl_set_port_no(rusturl_ptr url, const int32_t port);
 int32_t rusturl_set_path(rusturl_ptr url, const char *path, size_t len);
 int32_t rusturl_set_query(rusturl_ptr url, const char *path, size_t len);
 int32_t rusturl_set_fragment(rusturl_ptr url, const char *path, size_t len);