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 440270 ab9cb3dad2aff80e5bfea1506a903b5b371b1ea0
parent 440269 98eb390b4eee1bda1906f35cb866c6a63a3c9c67
child 537341 51323d3c2f63c79016425d60434cba4810d4175d
push id36190
push userbmo:manishearth@gmail.com
push dateThu, 17 Nov 2016 07:26:16 +0000
reviewersbagder, valentin
bugs1151899
milestone52.0a1
Bug 1151899 - Add code to run both URL parsers at the same time; r?bagder,valentin MozReview-Commit-ID: Jd2RgPmdPrn
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
netwerk/base/rust-url-capi/src/lib.rs
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -22,16 +22,84 @@
 #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"
 
+#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) {         \
+        printf("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) {                      \
+        printf("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) {                     \
+        printf("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);
@@ -272,16 +340,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);
@@ -1199,208 +1271,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);
@@ -1495,16 +1588,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();
 
@@ -1539,16 +1634,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();
 
@@ -1580,16 +1676,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;
@@ -1644,16 +1742,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();
 
@@ -1693,16 +1793,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();
 
@@ -1730,16 +1832,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);
@@ -1754,16 +1857,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) {
@@ -1837,29 +1941,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();
 
@@ -1945,17 +2050,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();
 
@@ -1977,16 +2082,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).
@@ -2055,16 +2161,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);
 }
@@ -2240,16 +2347,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;
@@ -2257,16 +2365,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
@@ -2761,16 +2870,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--;
     }
@@ -2801,16 +2911,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();
 
@@ -2832,16 +2943,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--;
     }
@@ -2866,16 +2978,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;
@@ -3145,16 +3258,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);
@@ -3192,16 +3307,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
@@ -3311,16 +3427,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.");
@@ -3501,16 +3618,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;
@@ -304,16 +305,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();
   }