Bug 1151899 - Make Necko support rust-url as a parser; r?valentin,ted draft
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 19 Oct 2016 19:01:51 +0530
changeset 427467 d064034027ece0f9029a321af7c255df117ceee2
parent 427101 5f7fb517fd76aac19cc9a135461d46d71d5ec7f1
child 534469 f452ed67373653b98887f9e4fef407280111ad87
push id33019
push userbmo:manishearth@gmail.com
push dateThu, 20 Oct 2016 11:11:16 +0000
reviewersvalentin, ted
bugs1151899
milestone52.0a1
Bug 1151899 - Make Necko support rust-url as a parser; r?valentin,ted MozReview-Commit-ID: 1bZu336Hecx
browser/confvars.sh
modules/libpref/init/all.js
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
netwerk/test/unit/test_rusturl.js
netwerk/test/unit/xpcshell.ini
old-configure.in
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -50,14 +50,15 @@ 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/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1858,16 +1858,18 @@ pref("network.standard-url.escape-utf8",
 
 // This preference controls whether or not URLs are always encoded and sent as
 // UTF-8.
 pref("network.standard-url.encode-utf8", true);
 
 // The maximum allowed length for a URL - 1MB default
 pref("network.standard-url.max-length", 1048576);
 
+pref("network.standard-url.use-rust", false);
+
 // Idle timeout for ftp control connections - 5 minute default
 pref("network.ftp.idleConnectionTimeout", 300);
 
 // directory listing format
 // 2: HTML
 // 3: XUL directory viewer
 // all other values are treated like 2
 pref("network.dir.format", 2);
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -30,17 +30,19 @@
 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);
-
+#ifdef MOZ_RUST_URLPARSE
+static bool sUseRust = false;
+#endif
 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
@@ -60,16 +62,29 @@ 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);
@@ -321,16 +336,20 @@ nsStandardURL::InitGlobalObjects()
     if (prefBranch) {
         nsCOMPtr<nsIObserver> obs( new nsPrefObserver() );
         prefBranch->AddObserver(NS_NET_PREF_ESCAPEUTF8, obs.get(), false);
         prefBranch->AddObserver(NS_NET_PREF_ALWAYSENCODEINUTF8, obs.get(), false);
 
         PrefsChanged(prefBranch, nullptr);
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    Preferences::AddBoolVarCache(&sUseRust, "network.standard-url.use-rust", false);
+#endif
+
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     PR_INIT_CLIST(&gAllURLs);
 #endif
 }
 
 void
 nsStandardURL::ShutdownGlobalObjects()
 {
@@ -1191,24 +1210,75 @@ NS_INTERFACE_MAP_BEGIN(nsStandardURL)
         foundInterface = static_cast<nsIURI *>(this);
     else
     NS_INTERFACE_MAP_ENTRY(nsISizeOf)
 NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------------
 // nsStandardURL::nsIURI
 //----------------------------------------------------------------------------
+ 
+#ifdef MOZ_RUST_URLPARSE
+static void CheckDifference(const char * method, nsACString & standardResult, nsACString & rustResult)
+{
+    if (standardResult != rustResult) {
+        printf("[RUST] Difference occured in ::%s\n", method);
+        printf("\t c++  : %s\n", standardResult.BeginReading());
+        printf("\t rust : %s\n", rustResult.BeginReading());
+    }
+
+    if (sUseRust) {
+        standardResult.Assign(rustResult);
+    }
+}
+
+static void CheckDifference(const char * method, int32_t & standardResult, int32_t & rustResult)
+{
+    if (standardResult != rustResult) {
+        printf("[RUST] Difference occured in ::%s\n", method);
+        printf("\t c++  : %d\n", standardResult);
+        printf("\t rust : %d\n", rustResult);
+    }
+
+    if (sUseRust) {
+        standardResult = rustResult;
+    }
+}
+
+
+static void CheckDifference(const char * method, bool & standardResult, bool & rustResult)
+{
+    if (standardResult != rustResult) {
+        printf("[RUST] Difference occured in ::%s\n", method);
+        printf("\t c++  : %d\n", standardResult);
+        printf("\t rust : %d\n", rustResult);
+    }
+
+    if (sUseRust) {
+        standardResult = rustResult;
+    }
+}
+#endif
+ 
 
 // 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;
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_spec(mURL, &rustResult);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetSensitiveInfoHiddenSpec(nsACString &result)
 {
     result = mSpec;
@@ -1225,87 +1295,224 @@ nsStandardURL::GetSpecIgnoringRef(nsACSt
     // 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;
     }
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+
+    rusturl_get_spec(mURL, &rustResult);
+    int32_t hashPos = rustResult.FindChar('#');
+    if (hashPos != kNotFound) {
+        rustResult.SetLength(hashPos);
+    }
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPrePath(nsACString &result)
 {
     result = Prepath();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+
+    nsAutoCString part;
+
+    rusturl_get_scheme(mURL, &part);
+    rustResult.Append(part);
+    rustResult += "://";
+    part = "";
+
+    rusturl_get_username(mURL, &part);
+    if (!part.IsEmpty()) {
+        rustResult += part;
+    }
+
+    rusturl_get_password(mURL, &part);
+    if (!part.IsEmpty()) {
+        rustResult += ":";
+        rustResult += part;
+    }
+
+    if (!part.IsEmpty()) {
+        rustResult += "@";
+    }
+
+    GetHostPort(part);
+    rustResult += part;
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result is strictly US-ASCII
 NS_IMETHODIMP
 nsStandardURL::GetScheme(nsACString &result)
 {
     result = Scheme();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_scheme(mURL, &rustResult);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetUserPass(nsACString &result)
 {
     result = Userpass();
+
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    nsresult rv = GetUsername(rustResult);
+    if (NS_FAILED(rv)) {
+       return rv;
+    }
+
+    nsAutoCString password;
+    rv = GetPassword(password);
+    if (NS_FAILED(rv)) {
+       return rv;
+    }
+
+    if (password.Length()) {
+       rustResult.Append(':');
+       rustResult.Append(password);
+    }
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetUsername(nsACString &result)
 {
     result = Username();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_username(mURL, &rustResult);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPassword(nsACString &result)
 {
     result = Password();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetHostPort(nsACString &result)
 {
     result = Hostport();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_host(mURL, &rustResult);
+
+    int32_t port;
+    nsresult rv = GetPort(&port);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    if (port>=0) {
+        rustResult.Append(':');
+        rustResult.AppendInt(port);
+    }
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetHost(nsACString &result)
 {
     result = Host();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_host(mURL, &rustResult);
+    if (rustResult.Length() > 0 && rustResult[0] == '[' && rustResult[rustResult.Length()-1] == ']')
+        rustResult = Substring(rustResult, 1, rustResult.Length()-2);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
     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;
+
+#ifdef MOZ_RUST_URLPARSE
+    int32_t rustResult = rusturl_get_port(mURL);
+
+    CheckDifference(__FUNCTION__, *result, rustResult);
+#endif
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPath(nsACString &result)
 {
     result = Path();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_path(mURL, &rustResult);
+
+    nsAutoCString query;
+    rusturl_get_query(mURL, &query);
+
+    nsAutoCString ref;
+    rusturl_get_fragment(mURL, &ref);
+
+    if (!query.IsEmpty()) {
+        rustResult.Append('?');
+        rustResult.Append(query);
+    }
+
+    if (!ref.IsEmpty()) {
+        rustResult.Append('#');
+        rustResult.Append(ref);
+    }
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiSpec(nsACString &result)
 {
     if (mSpecEncoding == eEncoding_Unknown) {
@@ -1351,16 +1558,18 @@ nsStandardURL::GetAsciiHostPort(nsACStri
     // 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);
 
+    // TODO
+
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiHost(nsACString &result)
 {
     if (mHostEncoding == eEncoding_ASCII) {
@@ -1381,16 +1590,18 @@ nsStandardURL::GetAsciiHost(nsACString &
             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);
+
+    // TODO
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetOriginCharset(nsACString &result)
 {
     if (mOriginCharset.IsEmpty())
         result.AssignLiteral("UTF-8");
@@ -1437,16 +1648,20 @@ nsStandardURL::SetSpec(const nsACString 
     // filter out unexpected chars "\r\n\t" if necessary
     nsAutoCString filteredURI;
     net_FilterURIString(flat, filteredURI);
 
     if (filteredURI.Length() == 0) {
         return NS_ERROR_MALFORMED_URI;
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    mURL.Init(input);
+#endif
+
     // Make a backup of the curent URL
     nsStandardURL prevURL(false,false);
     prevURL.CopyMembers(this, eHonorRef, EmptyCString());
     Clear();
 
     if (IsSpecialProtocol(filteredURI)) {
         // Bug 652186: Replace all backslashes with slashes when parsing paths
         // Stop when we reach the query or the hash.
@@ -1500,23 +1715,33 @@ 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));
     }
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustSpec;
+    rusturl_get_spec(mURL, &rustSpec);
+    nsAutoCString cSpec(mSpec);
+    CheckDifference(__FUNCTION__, cSpec, rustSpec);
+#endif
+
     return rv;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetScheme(const nsACString &input)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_scheme(mURL, input.BeginReading(), input.Length());
+#endif
 
     const nsPromiseFlatCString &scheme = PromiseFlatCString(input);
 
     LOG(("nsStandardURL::SetScheme [scheme=%s]\n", scheme.get()));
 
     if (scheme.IsEmpty()) {
         NS_WARNING("cannot remove the scheme from an url");
         return NS_ERROR_UNEXPECTED;
@@ -1544,23 +1769,41 @@ 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);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetUserPass(const nsACString &input)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    {
+        int32_t colonPos = input.FindChar(':');
+        nsAutoCString user;
+        nsAutoCString pass;
+        if (colonPos == kNotFound) {
+            user = input;
+        } else {
+            user = Substring(input, 0, colonPos);
+            pass = Substring(input, colonPos + 1, input.Length());
+        }
+
+        rusturl_set_username(mURL, user.BeginReading(), user.Length());
+        rusturl_set_password(mURL, pass.BeginReading(), pass.Length());
+    }
+#endif
+
 
     const nsPromiseFlatCString &userpass = PromiseFlatCString(input);
 
     LOG(("nsStandardURL::SetUserPass [userpass=%s]\n", userpass.get()));
 
     if (mURLType == URLTYPE_NO_AUTHORITY) {
         if (userpass.IsEmpty())
             return NS_OK;
@@ -1649,23 +1892,27 @@ 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;
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetUsername(const nsACString &input)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_username(mURL, input.BeginReading(), input.Length());
+#endif
 
     const nsPromiseFlatCString &username = PromiseFlatCString(input);
 
     LOG(("nsStandardURL::SetUsername [username=%s]\n", username.get()));
 
     if (mURLType == URLTYPE_NO_AUTHORITY) {
         if (username.IsEmpty())
             return NS_OK;
@@ -1698,23 +1945,27 @@ nsStandardURL::SetUsername(const nsACStr
     else
         shift = ReplaceSegment(mUsername.mPos, mUsername.mLen, escUsername);
 
     if (shift) {
         mUsername.mLen = escUsername.Length();
         mAuthority.mLen += shift;
         ShiftFromPassword(shift);
     }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetPassword(const nsACString &input)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_password(mURL, input.BeginReading(), input.Length());
+#endif
 
     const nsPromiseFlatCString &password = PromiseFlatCString(input);
 
     LOG(("nsStandardURL::SetPassword [password=%s]\n", password.get()));
 
     if (mURLType == URLTYPE_NO_AUTHORITY) {
         if (password.IsEmpty())
             return NS_OK;
@@ -1759,16 +2010,17 @@ nsStandardURL::SetPassword(const nsACStr
     else
         shift = ReplaceSegment(mPassword.mPos, mPassword.mLen, escPassword);
 
     if (shift) {
         mPassword.mLen = escPassword.Length();
         mAuthority.mLen += shift;
         ShiftFromHost(shift);
     }
+
     return NS_OK;
 }
 
 void
 nsStandardURL::FindHostLimit(nsACString::const_iterator& aStart,
                              nsACString::const_iterator& aEnd)
 {
   for (int32_t i = 0; gHostLimitDigits[i]; ++i) {
@@ -1780,16 +2032,19 @@ nsStandardURL::FindHostLimit(nsACString:
 }
 
 // If aValue only has a host part and no port number, the port
 // will not be reset!!!
 NS_IMETHODIMP
 nsStandardURL::SetHostPort(const nsACString &aValue)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_host_and_port(mURL, aValue.BeginReading(), aValue.Length());
+#endif
 
     // We cannot simply call nsIURI::SetHost because that would treat the name as
     // an IPv6 address (like http:://[server:443]/).  We also cannot call
     // nsIURI::SetHostPort because that isn't implemented.  Sadfaces.
 
     nsACString::const_iterator start, end;
     aValue.BeginReading(start);
     aValue.EndReading(end);
@@ -1923,16 +2178,20 @@ nsStandardURL::SetHost(const nsACString 
     // NormalizeIDN always copies if the call was successful
     host = hostBuf.get();
     len = hostBuf.Length();
 
     if (!ValidIPv6orHostname(host, len)) {
         return NS_ERROR_MALFORMED_URI;
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_host(mURL, host, len);
+#endif
+
     if (mHost.mLen < 0) {
         int port_length = 0;
         if (mPort != -1) {
             nsAutoCString buf;
             buf.Assign(':');
             buf.AppendInt(mPort);
             port_length = buf.Length();
         }
@@ -1958,16 +2217,19 @@ nsStandardURL::SetHost(const nsACString 
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetPort(int32_t port)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_port_no(mURL, port);
+#endif
 
     LOG(("nsStandardURL::SetPort [port=%d]\n", port));
 
     if ((port == mPort) || (mPort == -1 && port == mDefaultPort))
         return NS_OK;
 
     // ports must be >= 0 and 16 bit
     // -1 == use default
@@ -2049,27 +2311,32 @@ nsStandardURL::SetPath(const nsACString 
         spec.Assign(mSpec.get(), mPath.mPos);
         if (path.First() != '/')
             spec.Append('/');
         spec.Append(path);
 
         return SetSpec(spec);
     }
     else if (mPath.mLen >= 1) {
+#ifdef MOZ_RUST_URLPARSE
+        rusturl_set_path(mURL, input.BeginReading(), input.Length());
+#endif
+
         mSpec.Cut(mPath.mPos + 1, mPath.mLen - 1);
         // these contain only a '/'
         mPath.mLen = 1;
         mDirectory.mLen = 1;
         mFilepath.mLen = 1;
         // these are no longer defined
         mBasename.mLen = -1;
         mExtension.mLen = -1;
         mQuery.mLen = -1;
         mRef.mLen = -1;
     }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Equals(nsIURI *unknownOther, bool *result)
 {
     return EqualsInternal(unknownOther, eHonorRef, result);
 }
@@ -2098,43 +2365,68 @@ nsStandardURL::EqualsInternal(nsIURI *un
 
     // First, check whether one URIs is an nsIFileURL while the other
     // is not.  If that's the case, they're different.
     if (mSupportsFileURL != other->mSupportsFileURL) {
         *result = false;
         return NS_OK;
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString spec1;
+    GetSpecIgnoringRef(spec1);
+    nsAutoCString spec2;
+    other->GetSpecIgnoringRef(spec2);
+    bool rustResult = spec1 == spec2;
+#endif
+
     // Next check parts of a URI that, if different, automatically make the
     // URIs different
     if (!SegmentIs(mScheme, other->mSpec.get(), other->mScheme) ||
         // Check for host manually, since conversion to file will
         // ignore the host!
         !SegmentIs(mHost, other->mSpec.get(), other->mHost) ||
         !SegmentIs(mQuery, other->mSpec.get(), other->mQuery) ||
         !SegmentIs(mUsername, other->mSpec.get(), other->mUsername) ||
         !SegmentIs(mPassword, other->mSpec.get(), other->mPassword) ||
         Port() != other->Port()) {
         // No need to compare files or other URI parts -- these are different
         // beasties
         *result = false;
+#ifdef MOZ_RUST_URLPARSE
+        CheckDifference(__FUNCTION__, *result, rustResult);
+#endif
         return NS_OK;
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    if (refHandlingMode == eHonorRef) {
+        GetRef(spec1);
+        other->GetRef(spec2);
+        rustResult = spec1 == spec2;
+    }
+#endif
+
     if (refHandlingMode == eHonorRef &&
         !SegmentIs(mRef, other->mSpec.get(), other->mRef)) {
         *result = false;
+#ifdef MOZ_RUST_URLPARSE
+        CheckDifference(__FUNCTION__, *result, rustResult);
+#endif
         return NS_OK;
     }
-    
+
     // Then check for exact identity of URIs.  If we have it, they're equal
     if (SegmentIs(mDirectory, other->mSpec.get(), other->mDirectory) &&
         SegmentIs(mBasename, other->mSpec.get(), other->mBasename) &&
         SegmentIs(mExtension, other->mSpec.get(), other->mExtension)) {
         *result = true;
+#ifdef MOZ_RUST_URLPARSE
+        CheckDifference(__FUNCTION__, *result, rustResult);
+#endif
         return NS_OK;
     }
 
     // At this point, the URIs are not identical, but they only differ in the
     // directory/filename/extension.  If these are file URLs, then get the
     // corresponding file objects and compare those, since two filenames that
     // differ, eg, only in case could still be equal.
     if (mSupportsFileURL) {
@@ -2262,16 +2554,20 @@ nsresult nsStandardURL::CopyMembers(nsSt
     }
 
     if (refHandlingMode == eIgnoreRef) {
         SetRef(EmptyCString());
     } else if (refHandlingMode == eReplaceRef) {
         SetRef(newRef);
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    mURL.Init(mSpec);
+#endif
+
     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
@@ -2292,16 +2588,21 @@ nsStandardURL::Resolve(const nsACString 
     // output.  normalization will occur when the result is used to 
     // initialize a nsStandardURL object.
 
     if (mScheme.mLen < 0) {
         NS_WARNING("unable to Resolve URL: this URL not initialized");
         return NS_ERROR_NOT_INITIALIZED;
     }
 
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_resolve(mURL, relpath, relpathLen, &rustResult);
+#endif
+
     nsresult rv;
     URLSegment scheme;
     char *resultPath = nullptr;
     bool relative = false;
     uint32_t offset = 0;
     netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
 
     // relative urls should never contain a host, so we always want to use
@@ -2444,16 +2745,26 @@ nsStandardURL::Resolve(const nsACString 
         resultPath = PL_strstr(result, "://");
         if (resultPath) {
             resultPath = PL_strchr(resultPath + 3, '/');
             if (resultPath)
                 net_CoalesceDirs(coalesceFlag,resultPath);
         }
     }
     out.Adopt(result);
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString outTest(out);
+    CheckDifference(__FUNCTION__, outTest, rustResult);
+
+    nsAutoCString rustSpec;
+    rusturl_get_spec(mURL, &rustSpec);
+    nsAutoCString cSpec(mSpec);
+    CheckDifference("Resolve-Spec", cSpec, rustSpec);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetCommonBaseSpec(nsIURI *uri2, nsACString &aResult)
 {
     NS_ENSURE_ARG_POINTER(uri2);
@@ -2463,26 +2774,36 @@ nsStandardURL::GetCommonBaseSpec(nsIURI 
     if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
         return GetSpec(aResult);
 
     aResult.Truncate();
 
     // check pre-path; if they don't match, then return empty string
     nsStandardURL *stdurl2;
     nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    if (stdurl2)
+        rusturl_common_base_spec(mURL, stdurl2->mURL, &rustResult);
+#endif
+
     isEquals = NS_SUCCEEDED(rv)
             && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)    
             && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
             && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
             && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
             && (Port() == stdurl2->Port());
     if (!isEquals)
     {
         if (NS_SUCCEEDED(rv))
             NS_RELEASE(stdurl2);
+#ifdef MOZ_RUST_URLPARSE
+        CheckDifference(__FUNCTION__, aResult, rustResult);
+#endif
         return NS_OK;
     }
 
     // scan for first mismatched character
     const char *thisIndex, *thatIndex, *startCharPos;
     startCharPos = mSpec.get() + mDirectory.mPos;
     thisIndex = startCharPos;
     thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
@@ -2497,16 +2818,20 @@ nsStandardURL::GetCommonBaseSpec(nsIURI 
     // todo:  also check for file matches which include '?' and '#'
     while ((thisIndex != startCharPos) && (*(thisIndex-1) != '/'))
         thisIndex--;
 
     // grab spec from beginning to thisIndex
     aResult = Substring(mSpec, mScheme.mPos, thisIndex - mSpec.get());
 
     NS_RELEASE(stdurl2);
+#ifdef MOZ_RUST_URLPARSE
+    CheckDifference(__FUNCTION__, aResult, rustResult);
+#endif
+
     return rv;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetRelativeSpec(nsIURI *uri2, nsACString &aResult)
 {
     NS_ENSURE_ARG_POINTER(uri2);
 
@@ -2514,28 +2839,41 @@ nsStandardURL::GetRelativeSpec(nsIURI *u
 
     // if uri's are equal, then return empty string
     bool isEquals = false;
     if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
         return NS_OK;
 
     nsStandardURL *stdurl2;
     nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    if (stdurl2)
+        rusturl_relative_spec(mURL, stdurl2->mURL, &rustResult);
+#endif
+
     isEquals = NS_SUCCEEDED(rv)
             && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)    
             && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
             && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
             && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
             && (Port() == stdurl2->Port());
     if (!isEquals)
     {
         if (NS_SUCCEEDED(rv))
             NS_RELEASE(stdurl2);
 
+#ifdef MOZ_RUST_URLPARSE
+        uri2->GetSpec(aResult);
+        CheckDifference(__FUNCTION__, aResult, rustResult);
+        return NS_OK;
+#else
         return uri2->GetSpec(aResult);
+#endif
     }
 
     // scan for first mismatched character
     const char *thisIndex, *thatIndex, *startCharPos;
     startCharPos = mSpec.get() + mDirectory.mPos;
     thisIndex = startCharPos;
     thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
 
@@ -2589,90 +2927,187 @@ nsStandardURL::GetRelativeSpec(nsIURI *u
     }
 
     // grab spec from thisIndex to end
     uint32_t startPos = stdurl2->mScheme.mPos + thatIndex - stdurl2->mSpec.get();
     aResult.Append(Substring(stdurl2->mSpec, startPos, 
                              stdurl2->mSpec.Length() - startPos));
 
     NS_RELEASE(stdurl2);
+
+#ifdef MOZ_RUST_URLPARSE
+    CheckDifference(__FUNCTION__, aResult, rustResult);
+#endif
     return rv;
 }
 
 //----------------------------------------------------------------------------
 // nsStandardURL::nsIURL
 //----------------------------------------------------------------------------
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetFilePath(nsACString &result)
 {
     result = Filepath();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_path(mURL, &rustResult);
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetQuery(nsACString &result)
 {
     result = Query();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_query(mURL, &rustResult);
+    CheckDifference(__FUNCTION__, result, rustResult);
+
+    nsAutoCString rustSpec;
+    rusturl_get_spec(mURL, &rustSpec);
+    nsAutoCString cSpec(mSpec);
+    CheckDifference("GetQuery-Spec", cSpec, rustSpec);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetRef(nsACString &result)
 {
     result = Ref();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    rusturl_get_fragment(mURL, &rustResult);
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetHasRef(bool *result)
 {
     *result = (mRef.mLen >= 0);
+
+#ifdef MOZ_RUST_URLPARSE
+    int32_t rustResult = rusturl_has_fragment(mURL);
+
+    if (rustResult != *result) {
+        printf("[RUST] Difference occured in ::%s\n", __FUNCTION__);
+        printf("\t c++  : %d\n", *result);
+        printf("\t rust : %d\n", rustResult);
+    }
+
+    if (sUseRust) {
+        *result = rustResult;
+    }
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetDirectory(nsACString &result)
 {
     result = Directory();
+#ifdef MOZ_RUST_URLPARSE
+
+    nsAutoCString rustResult;
+    GetFilePath(rustResult);
+
+    int32_t slashPos = rustResult.RFindChar('/');
+    if (slashPos != kNotFound)
+        rustResult.SetLength(slashPos+1);
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetFileName(nsACString &result)
 {
     result = Filename();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    GetFilePath(rustResult);
+
+    int32_t slashPos = rustResult.RFindChar('/');
+    if (slashPos != kNotFound)
+        rustResult = Substring(rustResult, slashPos+1);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetFileBaseName(nsACString &result)
 {
     result = Basename();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    GetFileName(rustResult);
+
+    int32_t dotPos = rustResult.RFindChar('.');
+    if (dotPos != kNotFound)
+        rustResult.SetLength(dotPos);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetFileExtension(nsACString &result)
 {
     result = Extension();
+
+#ifdef MOZ_RUST_URLPARSE
+    nsAutoCString rustResult;
+    GetFileName(rustResult);
+
+    int32_t dotPos = rustResult.RFindChar('.');
+    if (dotPos != kNotFound)
+        rustResult = Substring(rustResult, dotPos + 1);
+    else
+        rustResult.SetLength(0);
+
+    CheckDifference(__FUNCTION__, result, rustResult);
+#endif
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetFilePath(const nsACString &input)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_path(mURL, input.BeginReading(), input.Length());
+#endif
 
     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
     const char *filepath = flat.get();
 
     LOG(("nsStandardURL::SetFilePath [filepath=%s]\n", filepath));
 
     // if there isn't a filepath, then there can't be anything
     // after the path either.  this url is likely uninitialized.
@@ -2734,16 +3169,17 @@ nsStandardURL::SetFilePath(const nsACStr
         // these contain only a '/'
         mPath.mLen = 1;
         mDirectory.mLen = 1;
         mFilepath.mLen = 1;
         // these are no longer defined
         mBasename.mLen = -1;
         mExtension.mLen = -1;
     }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetQuery(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
@@ -2758,16 +3194,19 @@ nsStandardURL::SetQuery(const nsACString
     if (mSpec.Length() + input.Length() - Query().Length() > (uint32_t) net_GetURLMaxLength()) {
         return NS_ERROR_MALFORMED_URI;
     }
 
     InvalidateCache();
 
     if (!query || !*query) {
         // remove existing query
+#ifdef MOZ_RUST_URLPARSE
+        rusturl_set_query(mURL, input.BeginReading(), input.Length());
+#endif
         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;
         }
@@ -2806,31 +3245,38 @@ nsStandardURL::SetQuery(const nsACString
 
     int32_t shift = ReplaceSegment(mQuery.mPos, mQuery.mLen, query, queryLen);
 
     if (shift) {
         mQuery.mLen = queryLen;
         mPath.mLen += shift;
         ShiftFromRef(shift);
     }
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_query(mURL, input.BeginReading(), input.Length());
+#endif
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetRef(const nsACString &input)
 {
     ENSURE_MUTABLE();
+#ifdef MOZ_RUST_URLPARSE
+    rusturl_set_fragment(mURL, input.BeginReading(), input.Length());
+#endif
 
     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
     const char *ref = flat.get();
 
     LOG(("nsStandardURL::SetRef [ref=%s]\n", ref));
 
-    if (mPath.mLen < 0)
+    if (mPath.mLen < 0) {
         return SetPath(flat);
+    }
 
     if (mSpec.Length() + input.Length() - Ref().Length() > (uint32_t) net_GetURLMaxLength()) {
         return NS_ERROR_MALFORMED_URI;
     }
 
     InvalidateCache();
 
     if (!ref || !*ref) {
@@ -2871,16 +3317,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;
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetDirectory(const nsACString &input)
 {
     NS_NOTYETIMPLEMENTED("");
     return NS_ERROR_NOT_IMPLEMENTED;
@@ -3321,17 +3768,21 @@ nsStandardURL::Read(nsIObjectInputStream
         // file and start of the query - mPath should include the param,
         // 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);
     }
-    
+
+#ifdef MOZ_RUST_URLPARSE
+    mURL.Init(mSpec);
+#endif
+
     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.");
@@ -3512,16 +3963,19 @@ 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();
 
+#ifdef MOZ_RUST_URLPARSE
+    mURL.Init(mSpec);
+#endif
     // 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
@@ -17,16 +17,21 @@
 #include "nsIClassInfo.h"
 #include "nsISizeOf.h"
 #include "prclist.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsIIPCSerializableURI.h"
 #include "nsISensitiveInfoHiddenURI.h"
 
+#ifdef MOZ_RUST_URLPARSE
+#include "rust-url-capi/src/rust-url-capi.h"
+#endif
+
+
 #ifdef NS_BUILD_REFCNT_LOGGING
 #define DEBUG_DUMP_URLS_AT_SHUTDOWN
 #endif
 
 class nsIBinaryInputStream;
 class nsIBinaryOutputStream;
 class nsIIDNService;
 class nsIPrefBranch;
@@ -249,16 +254,56 @@ private:
     nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);
     nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &);
 
     static void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
 
     void FindHostLimit(nsACString::const_iterator& aStart,
                        nsACString::const_iterator& aEnd);
 
+#ifdef MOZ_RUST_URLPARSE
+    class RustUrlWrapper {
+    public:
+        RustUrlWrapper()
+        {
+            mPtr = nullptr;
+        }
+        nsresult Init(const nsACString &input)
+        {
+            if (input.Length() == 0)
+                return NS_ERROR_FAILURE;
+            struct rusturl* url = rusturl_new(input.BeginReading(), input.Length());
+            if (!url) {
+                printf("[RUST] Parsing error for %s\n", input.BeginReading());
+                return NS_ERROR_FAILURE;
+            }
+            mPtr = url;
+            return NS_OK;
+        }
+        ~RustUrlWrapper()
+        {
+            if (mPtr)
+                rusturl_free(mPtr);
+        }
+        operator rusturl*() const {
+            return mPtr;
+        }
+    private:
+        RustUrlWrapper(struct rusturl* ptr)
+        {
+            mPtr = ptr;
+        }
+        struct rusturl* mPtr;
+    };
+
+
+    RustUrlWrapper mURL;
+#endif
+
+
     // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
     nsCString mSpec;
     int32_t   mDefaultPort;
     int32_t   mPort;
 
     // url parts (relative to mSpec)
     URLSegment mScheme;
     URLSegment mAuthority;
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_rusturl.js
@@ -0,0 +1,95 @@
+const StandardURL = Components.Constructor("@mozilla.org/network/standard-url;1",
+                                           "nsIStandardURL",
+                                           "init");
+const nsIStandardURL = Components.interfaces.nsIStandardURL;
+
+function stringToURL(str) {
+  return (new StandardURL(nsIStandardURL.URLTYPE_AUTHORITY, 80,
+       str, "UTF-8", null))
+         .QueryInterface(Components.interfaces.nsIURL);
+}
+
+function pairToURLs(pair) {
+  do_check_eq(pair.length, 2);
+  return pair.map(stringToURL);
+}
+
+function test_rust() {
+  var url = stringToURL("http://user:password@example.com/path/filename.ext?query=good&param=better#hash");
+  equal(url.spec, "http://user:password@example.com/path/filename.ext?query=good&param=better#hash");
+
+  var url = stringToURL("http://example.com");
+  equal(url.spec, "http://example.com/");
+
+  equal(url.hasRef, false);
+  url.ref = "#a";
+  equal(url.ref, "a");
+  equal(url.hasRef, true);
+  url.ref = "#";
+
+  equal(url.ref, "");
+  equal(url.spec, "http://example.com/#")
+  equal(url.hasRef, true);
+
+  url.ref = "";
+  equal(url.ref, "");
+  equal(url.spec, "http://example.com/")
+  equal(url.hasRef, false);
+
+  url.username = "u";
+  equal(url.username, "u");
+  url.username = "";
+  equal(url.username, "");
+
+  url.username = "u";
+  url.password = "p";
+  equal(url.password, "p");
+  url.password = "";
+  equal(url.password, "");
+
+  equal(url.userPass, "u");
+  url.password = "p";
+  equal(url.userPass, "u:p");
+  url.userPass = "user:password";
+  equal(url.username, "user");
+  equal(url.password, "password");
+  equal(url.userPass, "user:password");
+  url.userPass = "";
+  equal(url.userPass, "");
+
+  url.scheme = "https";
+  equal(url.scheme, "https");
+  url.scheme = "http";
+  equal(url.scheme, "http");
+
+  url.host = "bla";
+  equal(url.host, "bla");
+  url.port = 10;
+  equal(url.port, 10);
+  equal(url.hostPort, "bla:10");
+
+  url.path = "/abc/def";
+  equal(url.path, "/abc/def");
+
+  url = stringToURL("resource://gre-resources/hiddenWindow.html");
+  equal(url.spec, "resource://gre-resources/hiddenWindow.html");
+
+  url = stringToURL("http://host/directory/fileBaseName.fileExtension?query#ref");
+  equal(url.filePath, "/directory/fileBaseName.fileExtension");
+  equal(url.directory, "/directory/");
+  equal(url.fileName, "fileBaseName.fileExtension");
+  equal(url.fileBaseName, "fileBaseName");
+  equal(url.fileExtension, "fileExtension");
+
+  url = stringToURL("http://host/file?query#ref");
+  equal(url.filePath, "/file");
+  equal(url.directory, "/");
+  equal(url.fileName, "file");
+  equal(url.fileBaseName, "file");
+  equal(url.fileExtension, "");
+}
+
+function run_test()
+{
+  test_rust();
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -340,16 +340,17 @@ skip-if = os != "win"
 skip-if = os == "android" || (os == "win" && (os_version == "5.1" || os_version == "5.2"))
 reason = bug 1190674
 firefox-appdir = browser
 [test_tls_server_multiple_clients.js]
 # The local cert service used by this test is not currently shipped on Android
 skip-if = os == "android"
 [test_1073747.js]
 [test_multipart_streamconv_application_package.js]
+[test_rusturl.js]
 [test_safeoutputstream_append.js]
 [test_packaged_app_service.js]
 [test_packaged_app_verifier.js]
 [test_packaged_app_utils.js]
 [test_suspend_channel_before_connect.js]
 [test_inhibit_caching.js]
 [test_dns_disable_ipv4.js]
 [test_dns_disable_ipv6.js]
--- a/old-configure.in
+++ b/old-configure.in
@@ -2459,16 +2459,19 @@ if test -n "$MOZ_MULET"; then
     AC_DEFINE(MOZ_MULET)
 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)
+    fi
 fi
 
 AC_SUBST(MOZ_PHOENIX)
 AC_SUBST(MOZ_XULRUNNER)
 AC_SUBST(MOZ_B2G)
 AC_SUBST(MOZ_MULET)
 AC_SUBST(MOZ_B2G_VERSION)