Bug 1151899 - Add code to run both URL parsers at the same time; r?bagder,valentin draft
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 08 Nov 2016 00:42:36 +0100
changeset 440549 78ad8c0f8259c52c4360f7450772c741db79b797
parent 440543 078297b12d663809fa2e951b2accd1a7f200dab2
child 537403 228def540fdad7152c89570d76ba327ef3064d67
push id36258
push userbmo:manishearth@gmail.com
push dateThu, 17 Nov 2016 19:52:47 +0000
reviewersbagder, valentin
bugs1151899
milestone53.0a1
Bug 1151899 - Add code to run both URL parsers at the same time; r?bagder,valentin MozReview-Commit-ID: Jd2RgPmdPrn
browser/confvars.sh
netwerk/base/RustURL.cpp
netwerk/base/RustURL.h
netwerk/base/moz.build
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
netwerk/base/rust-url-capi/src/lib.rs
old-configure.in
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -24,16 +24,21 @@ if test "$OS_ARCH" = "WINNT"; then
             "$MOZ_UPDATE_CHANNEL" = "release-dev"; then
       if ! test "$MOZ_DEBUG"; then
         MOZ_STUB_INSTALLER=1
       fi
     fi
   fi
 fi
 
+if test "$MOZ_UPDATE_CHANNEL" = "default" -o \
+        "$MOZ_UPDATE_CHANNEL" = "nightly"; then
+  MOZ_RUST_URLPARSE=1
+fi
+
 # Enable building ./signmar and running libmar signature tests
 MOZ_ENABLE_SIGNMAR=1
 
 MOZ_APP_VERSION=$FIREFOX_VERSION
 MOZ_APP_VERSION_DISPLAY=$FIREFOX_VERSION_DISPLAY
 MOZ_EXTENSIONS_DEFAULT=" gio"
 # MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
 # MOZ_BRANDING_DIRECTORY is the default branding directory used when none is
@@ -50,15 +55,14 @@ MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3
 ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
 # The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
 MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBGL_CONFORMANT=1
 MOZ_JSDOWNLOADS=1
 MOZ_RUST_MP4PARSE=1
-MOZ_RUST_URLPARSE=1
 
 # Enable checking that add-ons are signed by the trusted root
 MOZ_ADDON_SIGNING=1
 
 # Include the DevTools client, not just the server (which is the default)
 MOZ_DEVTOOLS=all
--- a/netwerk/base/RustURL.cpp
+++ b/netwerk/base/RustURL.cpp
@@ -27,16 +27,17 @@ 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(nsIURIWithQuery)
   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)
--- a/netwerk/base/RustURL.h
+++ b/netwerk/base/RustURL.h
@@ -26,16 +26,17 @@ class RustURL
   , public nsISerializable
   , public nsIClassInfo
   , public nsISizeOf
   , public nsIIPCSerializableURI
   , public nsISensitiveInfoHiddenURI
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIURI
+  NS_DECL_NSIURIWITHQUERY
   NS_DECL_NSIURL
   NS_DECL_NSIFILEURL
   NS_DECL_NSISTANDARDURL
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
   NS_DECL_NSIMUTABLE
   NS_DECL_NSIIPCSERIALIZABLEURI
   NS_DECL_NSISENSITIVEINFOHIDDENURI
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -254,17 +254,17 @@ UNIFIED_SOURCES += [
     'RequestContextService.cpp',
     'SimpleBuffer.cpp',
     'StreamingProtocolService.cpp',
     'ThrottleQueue.cpp',
     'Tickler.cpp',
     'TLSServerSocket.cpp',
 ]
 
-if CONFIG['MOZ_RUST']:
+if CONFIG['MOZ_RUST'] and CONFIG['MOZ_RUST_URLPARSE']:
     EXPORTS.mozilla.net += [ 'RustURL.h' ]
     UNIFIED_SOURCES += [ 'RustURL.cpp' ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'nsURLHelperWin.cpp',
         'ShutdownLayer.cpp',
     ]
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -22,42 +22,114 @@
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
 #include <algorithm>
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsContentUtils.h"
 #include "prprf.h"
 #include "nsReadableUtils.h"
 
+
+//
+// setenv MOZ_LOG nsStandardURL:5
+//
+static LazyLogModule gStandardURLLog("nsStandardURL");
+
+// The Chromium code defines its own LOG macro which we don't want
+#undef LOG
+#define LOG(args)     MOZ_LOG(gStandardURLLog, LogLevel::Debug, args)
+#undef LOG_ENABLED
+#define LOG_ENABLED() MOZ_LOG_TEST(gStandardURLLog, LogLevel::Debug)
+
+#ifdef MOZ_RUST_URLPARSE
+
+#include "RustURL.h"
+
+// Fall back to CPP-parsed URLs if the Rust one doesn't match.
+#define MOZ_RUST_URLPARSE_FALLBACK
+
+#ifdef MOZ_RUST_URLPARSE_FALLBACK
+#define MOZ_RUST_URLPARSE_FALLBACK_MACRO(expr) expr
+#else
+#define MOZ_RUST_URLPARSE_FALLBACK_MACRO(expr)
+#endif
+
+#define CALL_RUST_SETTER(func, ...)  \
+do {                                 \
+    mRustURL->func(__VA_ARGS__);     \
+    nsAutoCString rustSpec;          \
+    mRustURL->GetSpec(rustSpec);     \
+    if (mSpec != rustSpec) {         \
+        LOG(("Spec diff detected after setter (%s): rust: %s standard-url: %s\n", \
+             #func, rustSpec.get(), mSpec.get())); \
+    }                                \
+} while (0)
+
+#define CALL_RUST_GETTER_STR(result, func, ...)  \
+do {                                             \
+    nsAutoCString backup(result);                \
+    mRustURL->func(__VA_ARGS__);                 \
+    if (backup != result) {                      \
+        LOG(("Diff detected calling getter (%s): rust: %s standard-url: %s\n", \
+             #func, result.BeginReading() , backup.BeginReading())); \
+        MOZ_RUST_URLPARSE_FALLBACK_MACRO(result = backup);          \
+    }                                            \
+} while (0)
+
+#define CALL_RUST_GETTER_INT(result, func, ...)  \
+do {                                             \
+    int32_t backup = *result;                    \
+    mRustURL->func(__VA_ARGS__);                 \
+    if (backup != *result) {                     \
+        LOG(("Diff detected calling getter (%s): rust: %d standard-url: %d\n", \
+             #func, *result , backup)); \
+        MOZ_RUST_URLPARSE_FALLBACK_MACRO(*result = backup);         \
+    }                                            \
+} while (0)
+
+#define COPY_RUST_MEMBER                \
+do {                                    \
+  RefPtr<RustURL> url = new RustURL();  \
+  nsAutoCString spec;                   \
+  GetSpec(spec);                        \
+  url->SetSpec(spec);                   \
+  mRustURL = url;                       \
+} while (0)
+
+#define CALL_RUST_SYNC  mRustURL->SetSpec(mSpec)
+#define CALL_SET_MUTABLE  mRustURL->SetMutable(value)
+#define CALL_RUST_INIT mRustURL->Init(urlType, defaultPort, spec, charset, baseURI)
+
+#else
+
+#define CALL_RUST_SETTER(func, ...)
+#define CALL_RUST_GETTER_STR(expected, func, ...)
+#define CALL_RUST_GETTER_INT(expected, func, ...)
+#define CALL_RUST_INIT
+#define CALL_RUST_SYNC
+#define CALL_SET_MUTABLE
+#define COPY_RUST_MEMBER
+
+#endif // MOZ_RUST_URLPARSE
+
 using mozilla::dom::EncodingUtils;
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
 static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
 
 nsIIDNService *nsStandardURL::gIDN = nullptr;
 bool nsStandardURL::gInitialized = false;
 bool nsStandardURL::gEscapeUTF8 = true;
 bool nsStandardURL::gAlwaysEncodeInUTF8 = true;
 char nsStandardURL::gHostLimitDigits[] = { '/', '\\', '?', '#', 0 };
 
-//
-// setenv MOZ_LOG nsStandardURL:5
-//
-static LazyLogModule gStandardURLLog("nsStandardURL");
-
-// The Chromium code defines its own LOG macro which we don't want
-#undef LOG
-#define LOG(args)     MOZ_LOG(gStandardURLLog, LogLevel::Debug, args)
-#undef LOG_ENABLED
-#define LOG_ENABLED() MOZ_LOG_TEST(gStandardURLLog, LogLevel::Debug)
-
 //----------------------------------------------------------------------------
 
 #define ENSURE_MUTABLE() \
   PR_BEGIN_MACRO \
     if (!mMutable) { \
         NS_WARNING("attempt to modify an immutable nsStandardURL"); \
         return NS_ERROR_ABORT; \
     } \
@@ -272,16 +344,20 @@ nsStandardURL::nsStandardURL(bool aSuppo
     if (NS_IsMainThread()) {
         if (aTrackURL) {
             PR_APPEND_LINK(&mDebugCList, &gAllURLs);
         } else {
             PR_INIT_CLIST(&mDebugCList);
         }
     }
 #endif
+
+#ifdef MOZ_RUST_URLPARSE
+    mRustURL = new RustURL();
+#endif
 }
 
 nsStandardURL::~nsStandardURL()
 {
     LOG(("Destroying nsStandardURL @%p\n", this));
 
     if (mHostA) {
         free(mHostA);
@@ -1200,208 +1276,229 @@ NS_INTERFACE_MAP_END
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetSpec(nsACString &result)
 {
     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
                "The spec should never be this long, we missed a check.");
     result = mSpec;
+    CALL_RUST_GETTER_STR(result, GetSpec, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetSensitiveInfoHiddenSpec(nsACString &result)
 {
     result = mSpec;
     if (mPassword.mLen >= 0) {
       result.Replace(mPassword.mPos, mPassword.mLen, "****");
     }
+    CALL_RUST_GETTER_STR(result, GetSensitiveInfoHiddenSpec, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetSpecIgnoringRef(nsACString &result)
 {
     // URI without ref is 0 to one char before ref
     if (mRef.mLen >= 0) {
         URLSegment noRef(0, mRef.mPos - 1);
 
         result = Segment(noRef);
     } else {
         result = mSpec;
     }
+    CALL_RUST_GETTER_STR(result, GetSpecIgnoringRef, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPrePath(nsACString &result)
 {
     result = Prepath();
+    CALL_RUST_GETTER_STR(result, GetPrePath, result);
     return NS_OK;
 }
 
 // result is strictly US-ASCII
 NS_IMETHODIMP
 nsStandardURL::GetScheme(nsACString &result)
 {
     result = Scheme();
+    CALL_RUST_GETTER_STR(result, GetScheme, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetUserPass(nsACString &result)
 {
     result = Userpass();
+    CALL_RUST_GETTER_STR(result, GetUserPass, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetUsername(nsACString &result)
 {
     result = Username();
+    CALL_RUST_GETTER_STR(result, GetUsername, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPassword(nsACString &result)
 {
     result = Password();
+    CALL_RUST_GETTER_STR(result, GetPassword, result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetHostPort(nsACString &result)
 {
     result = Hostport();
+    CALL_RUST_GETTER_STR(result, GetHostPort, result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetHost(nsACString &result)
 {
     result = Host();
+    CALL_RUST_GETTER_STR(result, GetHost, result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetPort(int32_t *result)
 {
     // should never be more than 16 bit
     MOZ_ASSERT(mPort <= std::numeric_limits<uint16_t>::max());
     *result = mPort;
+    CALL_RUST_GETTER_INT(result, GetPort, result);
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPath(nsACString &result)
 {
     result = Path();
+    CALL_RUST_GETTER_STR(result, GetPath, result);
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiSpec(nsACString &result)
 {
     if (mSpecEncoding == eEncoding_Unknown) {
         if (IsASCII(mSpec))
             mSpecEncoding = eEncoding_ASCII;
         else
             mSpecEncoding = eEncoding_UTF8;
     }
 
     if (mSpecEncoding == eEncoding_ASCII) {
         result = mSpec;
+        CALL_RUST_GETTER_STR(result, GetAsciiSpec, result);
         return NS_OK;
     }
 
     // try to guess the capacity required for result...
     result.SetCapacity(mSpec.Length() + std::min<uint32_t>(32, mSpec.Length()/10));
 
     result = Substring(mSpec, 0, mScheme.mLen + 3);
 
     NS_EscapeURL(Userpass(true), esc_OnlyNonASCII | esc_AlwaysCopy, result);
 
     // get the hostport
     nsAutoCString hostport;
     MOZ_ALWAYS_SUCCEEDS(GetAsciiHostPort(hostport));
     result += hostport;
 
     NS_EscapeURL(Path(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
+    CALL_RUST_GETTER_STR(result, GetAsciiSpec, result);
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiHostPort(nsACString &result)
 {
     if (mHostEncoding == eEncoding_ASCII) {
         result = Hostport();
+        CALL_RUST_GETTER_STR(result, GetAsciiHostPort, result);
         return NS_OK;
     }
 
     MOZ_ALWAYS_SUCCEEDS(GetAsciiHost(result));
 
     // As our mHostEncoding is not eEncoding_ASCII, we know that
     // the our host is not ipv6, and we can avoid looking at it.
     MOZ_ASSERT(result.FindChar(':') == -1, "The host must not be ipv6");
 
     // hostport = "hostA" + ":port"
     uint32_t pos = mHost.mPos + mHost.mLen;
     if (pos < mPath.mPos)
         result += Substring(mSpec, pos, mPath.mPos - pos);
 
+    CALL_RUST_GETTER_STR(result, GetAsciiHostPort, result);
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiHost(nsACString &result)
 {
     if (mHostEncoding == eEncoding_ASCII) {
         result = Host();
+        CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
         return NS_OK;
     }
 
     // perhaps we have it cached...
     if (mHostA) {
         result = mHostA;
+        CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
         return NS_OK;
     }
 
     if (gIDN) {
         nsresult rv;
         rv = gIDN->ConvertUTF8toACE(Host(), result);
+        CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
         if (NS_SUCCEEDED(rv)) {
             mHostA = ToNewCString(result);
             return NS_OK;
         }
         NS_WARNING("nsIDNService::ConvertUTF8toACE failed");
     }
 
     // something went wrong... guess all we can do is URL escape :-/
     NS_EscapeURL(Host(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
+    CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetOriginCharset(nsACString &result)
 {
     if (mOriginCharset.IsEmpty())
         result.AssignLiteral("UTF-8");
     else
         result = mOriginCharset;
+    CALL_RUST_GETTER_STR(result, GetOriginCharset, result);
     return NS_OK;
 }
 
 static bool
 IsSpecialProtocol(const nsACString &input)
 {
     nsACString::const_iterator start, end;
     input.BeginReading(start);
@@ -1496,16 +1593,18 @@ nsStandardURL::SetSpec(const nsACString 
         LOG((" path      = (%u,%d)\n", mPath.mPos,      mPath.mLen));
         LOG((" filepath  = (%u,%d)\n", mFilepath.mPos,  mFilepath.mLen));
         LOG((" directory = (%u,%d)\n", mDirectory.mPos, mDirectory.mLen));
         LOG((" basename  = (%u,%d)\n", mBasename.mPos,  mBasename.mLen));
         LOG((" extension = (%u,%d)\n", mExtension.mPos, mExtension.mLen));
         LOG((" query     = (%u,%d)\n", mQuery.mPos,     mQuery.mLen));
         LOG((" ref       = (%u,%d)\n", mRef.mPos,       mRef.mLen));
     }
+
+    CALL_RUST_SETTER(SetSpec, input);
     return rv;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetScheme(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -1540,16 +1639,17 @@ nsStandardURL::SetScheme(const nsACStrin
         ShiftFromAuthority(shift);
     }
 
     // ensure new scheme is lowercase
     //
     // XXX the string code unfortunately doesn't provide a ToLowerCase
     //     that operates on a substring.
     net_ToLowerCase((char *) mSpec.get(), mScheme.mLen);
+    CALL_RUST_SETTER(SetScheme, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetUserPass(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -1581,16 +1681,18 @@ nsStandardURL::SetUserPass(const nsACStr
                 mUsername.mLen += (mPassword.mLen + 1);
             mUsername.mLen++;
             mSpec.Cut(mUsername.mPos, mUsername.mLen);
             mAuthority.mLen -= mUsername.mLen;
             ShiftFromHost(-mUsername.mLen);
             mUsername.mLen = -1;
             mPassword.mLen = -1;
         }
+
+        CALL_RUST_SETTER(SetUserPass, input);
         return NS_OK;
     }
 
     NS_ASSERTION(mHost.mLen >= 0, "uninitialized");
 
     nsresult rv;
     uint32_t usernamePos, passwordPos;
     int32_t usernameLen, passwordLen;
@@ -1645,16 +1747,18 @@ nsStandardURL::SetUserPass(const nsACStr
         ShiftFromHost(shift);
         mAuthority.mLen += shift;
     }
     // update positions and lengths
     mUsername.mLen = usernameLen;
     mPassword.mLen = passwordLen;
     if (passwordLen)
         mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
+
+    CALL_RUST_SETTER(SetUserPass, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetUsername(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -1694,16 +1798,18 @@ nsStandardURL::SetUsername(const nsACStr
     else
         shift = ReplaceSegment(mUsername.mPos, mUsername.mLen, escUsername);
 
     if (shift) {
         mUsername.mLen = escUsername.Length();
         mAuthority.mLen += shift;
         ShiftFromPassword(shift);
     }
+
+    CALL_RUST_SETTER(SetUsername, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetPassword(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -1731,16 +1837,17 @@ nsStandardURL::SetPassword(const nsACStr
     if (password.IsEmpty()) {
         if (mPassword.mLen >= 0) {
             // cut(":password")
             mSpec.Cut(mPassword.mPos - 1, mPassword.mLen + 1);
             ShiftFromHost(-(mPassword.mLen + 1));
             mAuthority.mLen -= (mPassword.mLen + 1);
             mPassword.mLen = -1;
         }
+        CALL_RUST_SETTER(SetPassword, input);
         return NS_OK;
     }
 
     // escape password if necessary
     nsAutoCString buf;
     GET_SEGMENT_ENCODER(encoder);
     const nsACString &escPassword =
         encoder.EncodeSegment(password, esc_Password, buf);
@@ -1755,16 +1862,17 @@ nsStandardURL::SetPassword(const nsACStr
     else
         shift = ReplaceSegment(mPassword.mPos, mPassword.mLen, escPassword);
 
     if (shift) {
         mPassword.mLen = escPassword.Length();
         mAuthority.mLen += shift;
         ShiftFromHost(shift);
     }
+    CALL_RUST_SETTER(SetPassword, input);
     return NS_OK;
 }
 
 void
 nsStandardURL::FindHostLimit(nsACString::const_iterator& aStart,
                              nsACString::const_iterator& aEnd)
 {
   for (int32_t i = 0; gHostLimitDigits[i]; ++i) {
@@ -1838,29 +1946,30 @@ nsStandardURL::SetHostPort(const nsACStr
                 // Failure parsing port number
                 return NS_ERROR_MALFORMED_URI;
             }
         } else {
             // port number is missing
             return NS_ERROR_MALFORMED_URI;
         }
     }
-
+    CALL_RUST_SETTER(SetHostPort, aValue);
     return NS_OK;
 }
 
 // This function is different than SetHostPort in that the port number will be
 // reset as well if aValue parameter does not contain a port port number.
 NS_IMETHODIMP
 nsStandardURL::SetHostAndPort(const nsACString &aValue)
 {
   // Reset the port and than call SetHostPort. SetHostPort does not reset
   // the port number.
   nsresult rv = SetPort(-1);
   NS_ENSURE_SUCCESS(rv, rv);
+  CALL_RUST_SETTER(SetHostAndPort, aValue);
   return SetHostPort(aValue);
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetHost(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -1952,17 +2061,17 @@ nsStandardURL::SetHost(const nsACString 
     if (shift) {
         mHost.mLen = len;
         mAuthority.mLen += shift;
         ShiftFromPath(shift);
     }
 
     // Now canonicalize the host to lowercase
     net_ToLowerCase(mSpec.BeginWriting() + mHost.mPos, mHost.mLen);
-
+    CALL_RUST_SETTER(SetHost, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetPort(int32_t port)
 {
     ENSURE_MUTABLE();
 
@@ -1984,16 +2093,17 @@ nsStandardURL::SetPort(int32_t port)
     InvalidateCache();
     if (port == mDefaultPort) {
       port = -1;
     }
 
     ReplacePortInSpec(port);
 
     mPort = port;
+    CALL_RUST_SETTER(SetPort, port);
     return NS_OK;
 }
 
 /**
  * Replaces the existing port in mSpec with aNewPort.
  *
  * The caller is responsible for:
  *  - Calling InvalidateCache (since our mSpec is changing).
@@ -2062,16 +2172,17 @@ nsStandardURL::SetPath(const nsACString 
         mDirectory.mLen = 1;
         mFilepath.mLen = 1;
         // these are no longer defined
         mBasename.mLen = -1;
         mExtension.mLen = -1;
         mQuery.mLen = -1;
         mRef.mLen = -1;
     }
+    CALL_RUST_SETTER(SetPath, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Equals(nsIURI *unknownOther, bool *result)
 {
     return EqualsInternal(unknownOther, eHonorRef, result);
 }
@@ -2247,16 +2358,17 @@ nsresult nsStandardURL::CopyMembers(nsSt
     mRef = source->mRef;
     mOriginCharset = source->mOriginCharset;
     mURLType = source->mURLType;
     mParser = source->mParser;
     mMutable = true;
     mSupportsFileURL = source->mSupportsFileURL;
     mHostEncoding = source->mHostEncoding;
 
+    COPY_RUST_MEMBER;
     if (copyCached) {
         mFile = source->mFile;
         mHostA = source->mHostA ? strdup(source->mHostA) : nullptr;
         mSpecEncoding = source->mSpecEncoding;
     } else {
         // The same state as after calling InvalidateCache()
         mFile = nullptr;
         mHostA = nullptr;
@@ -2264,16 +2376,17 @@ nsresult nsStandardURL::CopyMembers(nsSt
     }
 
     if (refHandlingMode == eIgnoreRef) {
         SetRef(EmptyCString());
     } else if (refHandlingMode == eReplaceRef) {
         SetRef(newRef);
     }
 
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Resolve(const nsACString &in, nsACString &out)
 {
     const nsPromiseFlatCString &flat = PromiseFlatCString(in);
     // filter out unexpected chars "\r\n\t" if necessary
@@ -2768,16 +2881,17 @@ nsStandardURL::SetQuery(const nsACString
         if (mQuery.mLen >= 0) {
             // remove query and leading '?'
             mSpec.Cut(mQuery.mPos - 1, mQuery.mLen + 1);
             ShiftFromRef(-(mQuery.mLen + 1));
             mPath.mLen -= (mQuery.mLen + 1);
             mQuery.mPos = 0;
             mQuery.mLen = -1;
         }
+        CALL_RUST_SETTER(SetQuery, input);
         return NS_OK;
     }
 
     int32_t queryLen = flat.Length();
     if (query[0] == '?') {
         query++;
         queryLen--;
     }
@@ -2808,16 +2922,17 @@ nsStandardURL::SetQuery(const nsACString
 
     int32_t shift = ReplaceSegment(mQuery.mPos, mQuery.mLen, query, queryLen);
 
     if (shift) {
         mQuery.mLen = queryLen;
         mPath.mLen += shift;
         ShiftFromRef(shift);
     }
+    CALL_RUST_SETTER(SetQuery, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetRef(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -2839,16 +2954,17 @@ nsStandardURL::SetRef(const nsACString &
         // remove existing ref
         if (mRef.mLen >= 0) {
             // remove ref and leading '#'
             mSpec.Cut(mRef.mPos - 1, mRef.mLen + 1);
             mPath.mLen -= (mRef.mLen + 1);
             mRef.mPos = 0;
             mRef.mLen = -1;
         }
+        CALL_RUST_SETTER(SetRef, input);
         return NS_OK;
     }
 
     int32_t refLen = flat.Length();
     if (ref[0] == '#') {
         ref++;
         refLen--;
     }
@@ -2873,16 +2989,17 @@ nsStandardURL::SetRef(const nsACString &
             ref = buf.get();
             refLen = buf.Length();
         }
     }
 
     int32_t shift = ReplaceSegment(mRef.mPos, mRef.mLen, ref, refLen);
     mPath.mLen += shift;
     mRef.mLen = refLen;
+    CALL_RUST_SETTER(SetRef, input);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetDirectory(const nsACString &input)
 {
     NS_NOTYETIMPLEMENTED("");
     return NS_ERROR_NOT_IMPLEMENTED;
@@ -3152,16 +3269,18 @@ nsStandardURL::Init(uint32_t urlType,
     if (charset != nullptr && *charset != '\0' && !IsUTFCharset(charset)) {
         mOriginCharset = charset;
     }
 
     if (baseURI && net_IsAbsoluteURL(spec)) {
         baseURI = nullptr;
     }
 
+    CALL_RUST_INIT;
+
     if (!baseURI)
         return SetSpec(spec);
 
     nsAutoCString buf;
     nsresult rv = baseURI->Resolve(spec, buf);
     if (NS_FAILED(rv)) return rv;
 
     return SetSpec(buf);
@@ -3199,16 +3318,17 @@ nsStandardURL::GetMutable(bool *value)
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetMutable(bool value)
 {
     NS_ENSURE_ARG(mMutable || !value);
 
     mMutable = value;
+    CALL_SET_MUTABLE;
     return NS_OK;
 }
 
 //----------------------------------------------------------------------------
 // nsStandardURL::nsISerializable
 //----------------------------------------------------------------------------
 
 NS_IMETHODIMP
@@ -3318,16 +3438,17 @@ nsStandardURL::Read(nsIObjectInputStream
         // query and ref already.  Bump the mFilePath and 
         // directory/basename/extension components to include this.
         mFilepath.Merge(mSpec,  ';', old_param);
         mDirectory.Merge(mSpec, ';', old_param);
         mBasename.Merge(mSpec,  ';', old_param);
         mExtension.Merge(mSpec, ';', old_param);
     }
     
+    CALL_RUST_SYNC;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Write(nsIObjectOutputStream *stream)
 {
     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
                "The spec should never be this long, we missed a check.");
@@ -3508,16 +3629,18 @@ nsStandardURL::Deserialize(const URIPara
     mExtension = FromIPCSegment(params.extension());
     mQuery = FromIPCSegment(params.query());
     mRef = FromIPCSegment(params.ref());
     mOriginCharset = params.originCharset();
     mMutable = params.isMutable();
     mSupportsFileURL = params.supportsFileURL();
     mHostEncoding = params.hostEncoding();
 
+    CALL_RUST_SYNC;
+
     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
     return true;
 }
 
 //----------------------------------------------------------------------------
 // nsStandardURL::nsIClassInfo
 //----------------------------------------------------------------------------
 
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -16,16 +16,17 @@
 #include "nsURLHelper.h"
 #include "nsIClassInfo.h"
 #include "nsISizeOf.h"
 #include "prclist.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsIIPCSerializableURI.h"
 #include "nsISensitiveInfoHiddenURI.h"
+#include "RustURL.h"
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 #define DEBUG_DUMP_URLS_AT_SHUTDOWN
 #endif
 
 class nsIBinaryInputStream;
 class nsIBinaryOutputStream;
 class nsIIDNService;
@@ -305,16 +306,20 @@ private:
     static bool                         gAlwaysEncodeInUTF8;
     static bool                         gEncodeQueryInUTF8;
 
 public:
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     PRCList mDebugCList;
     void PrintSpec() const { printf("  %s\n", mSpec.get()); }
 #endif
+
+#ifdef MOZ_RUST_URLPARSE
+    RefPtr<RustURL>                    mRustURL;
+#endif
 };
 
 #define NS_THIS_STANDARDURL_IMPL_CID                 \
 { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */         \
     0xb8e3e97b,                                      \
     0x1ccd,                                          \
     0x4b45,                                          \
     {0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7} \
--- a/netwerk/base/rust-url-capi/src/lib.rs
+++ b/netwerk/base/rust-url-capi/src/lib.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate url;
-use url::{Url, ParseError, ParseOptions};
+use url::{Url, ParseError, ParseOptions, Position};
 use url::quirks;
 extern crate libc;
 use libc::size_t;
 
 
 use std::mem;
 use std::str;
 
@@ -139,17 +139,17 @@ pub unsafe extern "C" fn rusturl_get_por
 pub unsafe extern "C" fn rusturl_get_path(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 {
   if urlptr.is_null() {
     return NSError::InvalidArg.error_code();
   }
   let url: &Url = mem::transmute(urlptr);
   if url.cannot_be_a_base() {
       cont.set_size(0)
   } else {
-      cont.assign(url.path())
+      cont.assign(&url[Position::BeforePath..])
   }
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn rusturl_get_query(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 {
   if urlptr.is_null() {
     return NSError::InvalidArg.error_code();
   }
--- a/old-configure.in
+++ b/old-configure.in
@@ -2437,16 +2437,17 @@ fi
 
 # Propagate feature switches for code written in rust from confvars.sh
 if test -n "$MOZ_RUST"; then
     if test -n "$MOZ_RUST_MP4PARSE"; then
         AC_DEFINE(MOZ_RUST_MP4PARSE)
     fi
     if test -n "$MOZ_RUST_URLPARSE"; then
         AC_DEFINE(MOZ_RUST_URLPARSE)
+        AC_SUBST(MOZ_RUST_URLPARSE)
     fi
 fi
 
 AC_SUBST(MOZ_PHOENIX)
 AC_SUBST(MOZ_XULRUNNER)
 AC_SUBST(MOZ_B2G)
 AC_SUBST(MOZ_MULET)
 AC_SUBST(MOZ_B2G_VERSION)