Bug 1174731 - patch 1 - Make searchParams attribute readonly, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 24 Jun 2015 12:15:59 -0700
changeset 280931 9c93813baadc699066a79ea770cf041975d61d56
parent 280930 60fe089face1b86480c1951c23234342607b0baa
child 280932 44002ebe4e2cf60cc69e1f0bf1388172b87c1836
push idunknown
push userunknown
push dateunknown
reviewerssmaug
bugs1174731
milestone41.0a1
Bug 1174731 - patch 1 - Make searchParams attribute readonly, r=smaug
caps/BasePrincipal.cpp
dom/base/Link.cpp
dom/base/Link.h
dom/base/URL.cpp
dom/base/URL.h
dom/base/URLSearchParams.cpp
dom/base/URLSearchParams.h
dom/base/test/test_urlSearchParams.html
dom/fetch/Fetch.cpp
dom/html/HTMLAreaElement.h
dom/webidl/URLUtils.webidl
dom/workers/URL.cpp
dom/workers/URL.h
dom/workers/test/urlSearchParams_worker.js
toolkit/components/places/tests/cpp/mock_Link.h
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -23,17 +23,17 @@ namespace mozilla {
 
 using dom::URLSearchParams;
 
 void
 OriginAttributes::CreateSuffix(nsACString& aStr) const
 {
   MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
 
-  nsRefPtr<URLSearchParams> usp = new URLSearchParams();
+  nsRefPtr<URLSearchParams> usp = new URLSearchParams(nullptr);
   nsAutoString value;
 
   if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
     value.AppendInt(mAppId);
     usp->Set(NS_LITERAL_STRING("appId"), value);
   }
 
   if (mInBrowser) {
@@ -103,18 +103,18 @@ OriginAttributes::PopulateFromSuffix(con
   if (aStr.IsEmpty()) {
     return true;
   }
 
   if (aStr[0] != '!') {
     return false;
   }
 
-  nsRefPtr<URLSearchParams> usp = new URLSearchParams();
-  usp->ParseInput(Substring(aStr, 1, aStr.Length() - 1), nullptr);
+  nsRefPtr<URLSearchParams> usp = new URLSearchParams(nullptr);
+  usp->ParseInput(Substring(aStr, 1, aStr.Length() - 1));
 
   PopulateFromSuffixIterator iterator(this);
   return usp->ForEach(iterator);
 }
 
 void
 OriginAttributes::CookieJar(nsACString& aStr)
 {
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -574,31 +574,16 @@ Link::SizeOfExcludingThis(mozilla::Mallo
 URLSearchParams*
 Link::SearchParams()
 {
   CreateSearchParamsIfNeeded();
   return mSearchParams;
 }
 
 void
-Link::SetSearchParams(URLSearchParams& aSearchParams)
-{
-  if (mSearchParams) {
-    mSearchParams->RemoveObserver(this);
-  }
-
-  mSearchParams = &aSearchParams;
-  mSearchParams->AddObserver(this);
-
-  nsAutoString search;
-  mSearchParams->Serialize(search);
-  SetSearchInternal(search);
-}
-
-void
 Link::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
 {
   MOZ_ASSERT(mSearchParams);
   MOZ_ASSERT(mSearchParams == aSearchParams);
 
   nsString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
@@ -616,34 +601,32 @@ Link::UpdateURLSearchParams()
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (url) {
     nsresult rv = url->GetQuery(search);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to get the query from a nsIURL.");
     }
   }
 
-  mSearchParams->ParseInput(search, this);
+  mSearchParams->ParseInput(search);
 }
 
 void
 Link::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
-    mSearchParams = new URLSearchParams();
-    mSearchParams->AddObserver(this);
+    mSearchParams = new URLSearchParams(this);
     UpdateURLSearchParams();
   }
 }
 
 void
 Link::Unlink()
 {
   if (mSearchParams) {
-    mSearchParams->RemoveObserver(this);
     mSearchParams = nullptr;
   }
 }
 
 void
 Link::Traverse(nsCycleCollectionTraversalCallback &cb)
 {
   Link* tmp = this;
--- a/dom/base/Link.h
+++ b/dom/base/Link.h
@@ -59,17 +59,16 @@ public:
    */
   void SetProtocol(const nsAString &aProtocol, ErrorResult& aError);
   void SetUsername(const nsAString &aUsername, ErrorResult& aError);
   void SetPassword(const nsAString &aPassword, ErrorResult& aError);
   void SetHost(const nsAString &aHost, ErrorResult& aError);
   void SetHostname(const nsAString &aHostname, ErrorResult& aError);
   void SetPathname(const nsAString &aPathname, ErrorResult& aError);
   void SetSearch(const nsAString &aSearch, ErrorResult& aError);
-  void SetSearchParams(mozilla::dom::URLSearchParams& aSearchParams);
   void SetPort(const nsAString &aPort, ErrorResult& aError);
   void SetHash(const nsAString &aHash, ErrorResult& aError);
   void GetOrigin(nsAString &aOrigin, ErrorResult& aError);
   void GetProtocol(nsAString &_protocol, ErrorResult& aError);
   void GetUsername(nsAString &aUsername, ErrorResult& aError);
   void GetPassword(nsAString &aPassword, ErrorResult& aError);
   void GetHost(nsAString &_host, ErrorResult& aError);
   void GetHostname(nsAString &_hostname, ErrorResult& aError);
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -22,17 +22,16 @@
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(URL)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
   if (tmp->mSearchParams) {
-    tmp->mSearchParams->RemoveObserver(tmp);
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -369,17 +368,17 @@ URL::UpdateURLSearchParams()
   nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
   if (url) {
     nsresult rv = url->GetQuery(search);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to get the query from a nsIURL.");
     }
   }
 
-  mSearchParams->ParseInput(search, this);
+  mSearchParams->ParseInput(search);
 }
 
 void
 URL::GetHostname(nsAString& aHostname, ErrorResult& aRv) const
 {
   aHostname.Truncate();
   nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
 }
@@ -496,32 +495,16 @@ URL::SetSearchInternal(const nsAString& 
 URLSearchParams*
 URL::SearchParams()
 {
   CreateSearchParamsIfNeeded();
   return mSearchParams;
 }
 
 void
-URL::SetSearchParams(URLSearchParams& aSearchParams)
-{
-  if (mSearchParams) {
-    mSearchParams->RemoveObserver(this);
-  }
-
-  // the observer will be cleared using the cycle collector.
-  mSearchParams = &aSearchParams;
-  mSearchParams->AddObserver(this);
-
-  nsAutoString search;
-  mSearchParams->Serialize(search);
-  SetSearchInternal(search);
-}
-
-void
 URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
 {
   aHash.Truncate();
 
   nsAutoCString ref;
   nsresult rv = mURI->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     aHash.Assign(char16_t('#'));
@@ -545,16 +528,15 @@ bool IsChromeURI(nsIURI* aURI)
       return isChrome;
   return false;
 }
 
 void
 URL::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
-    mSearchParams = new URLSearchParams();
-    mSearchParams->AddObserver(this);
+    mSearchParams = new URLSearchParams(this);
     UpdateURLSearchParams();
   }
 }
 
 }
 }
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -114,18 +114,16 @@ public:
   void SetPathname(const nsAString& aPathname, ErrorResult& aRv);
 
   void GetSearch(nsAString& aRetval, ErrorResult& aRv) const;
 
   void SetSearch(const nsAString& aArg, ErrorResult& aRv);
 
   URLSearchParams* SearchParams();
 
-  void SetSearchParams(URLSearchParams& aSearchParams);
-
   void GetHash(nsAString& aRetval, ErrorResult& aRv) const;
 
   void SetHash(const nsAString& aArg, ErrorResult& aRv);
 
   void Stringify(nsAString& aRetval, ErrorResult& aRv) const
   {
     GetHref(aRetval, aRv);
   }
--- a/dom/base/URLSearchParams.cpp
+++ b/dom/base/URLSearchParams.cpp
@@ -7,26 +7,27 @@
 #include "URLSearchParams.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsDOMString.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObservers)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObserver)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-URLSearchParams::URLSearchParams()
+URLSearchParams::URLSearchParams(URLSearchParamsObserver* aObserver)
+  : mObserver(aObserver)
 {
 }
 
 URLSearchParams::~URLSearchParams()
 {
   DeleteAll();
 }
 
@@ -36,34 +37,33 @@ URLSearchParams::WrapObject(JSContext* a
   return URLSearchParamsBinding::Wrap(aCx, this, aGivenProto);
 }
 
 /* static */ already_AddRefed<URLSearchParams>
 URLSearchParams::Constructor(const GlobalObject& aGlobal,
                              const nsAString& aInit,
                              ErrorResult& aRv)
 {
-  nsRefPtr<URLSearchParams> sp = new URLSearchParams();
-  sp->ParseInput(NS_ConvertUTF16toUTF8(aInit), nullptr);
+  nsRefPtr<URLSearchParams> sp = new URLSearchParams(nullptr);
+  sp->ParseInput(NS_ConvertUTF16toUTF8(aInit));
   return sp.forget();
 }
 
 /* static */ already_AddRefed<URLSearchParams>
 URLSearchParams::Constructor(const GlobalObject& aGlobal,
                              URLSearchParams& aInit,
                              ErrorResult& aRv)
 {
-  nsRefPtr<URLSearchParams> sp = new URLSearchParams();
+  nsRefPtr<URLSearchParams> sp = new URLSearchParams(nullptr);
   sp->mSearchParams = aInit.mSearchParams;
   return sp.forget();
 }
 
 void
-URLSearchParams::ParseInput(const nsACString& aInput,
-                            URLSearchParamsObserver* aObserver)
+URLSearchParams::ParseInput(const nsACString& aInput)
 {
   // Remove all the existing data before parsing a new input.
   DeleteAll();
 
   nsACString::const_iterator start, end;
   aInput.BeginReading(start);
   aInput.EndReading(end);
   nsACString::const_iterator iter(start);
@@ -103,18 +103,16 @@ URLSearchParams::ParseInput(const nsACSt
     nsAutoString decodedName;
     DecodeString(name, decodedName);
 
     nsAutoString decodedValue;
     DecodeString(value, decodedValue);
 
     AppendInternal(decodedName, decodedValue);
   }
-
-  NotifyObservers(aObserver);
 }
 
 void
 URLSearchParams::DecodeString(const nsACString& aInput, nsAString& aOutput)
 {
   nsACString::const_iterator start, end;
   aInput.BeginReading(start);
   aInput.EndReading(end);
@@ -204,37 +202,16 @@ URLSearchParams::ConvertString(const nsA
   }
 
   if (newOutputLength < outputLength) {
     aOutput.Truncate(newOutputLength);
   }
 }
 
 void
-URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
-{
-  MOZ_ASSERT(aObserver);
-  MOZ_ASSERT(!mObservers.Contains(aObserver));
-  mObservers.AppendElement(aObserver);
-}
-
-void
-URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver)
-{
-  MOZ_ASSERT(aObserver);
-  mObservers.RemoveElement(aObserver);
-}
-
-void
-URLSearchParams::RemoveObservers()
-{
-  mObservers.Clear();
-}
-
-void
 URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
 {
   SetDOMStringToNull(aRetval);
 
   for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
     if (mSearchParams[i].mKey.Equals(aName)) {
       aRetval.Assign(mSearchParams[i].mValue);
       break;
@@ -275,24 +252,24 @@ URLSearchParams::Set(const nsAString& aN
 
   if (!param) {
     param = mSearchParams.AppendElement();
     param->mKey = aName;
   }
 
   param->mValue = aValue;
 
-  NotifyObservers(nullptr);
+  NotifyObserver();
 }
 
 void
 URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
 {
   AppendInternal(aName, aValue);
-  NotifyObservers(nullptr);
+  NotifyObserver();
 }
 
 void
 URLSearchParams::AppendInternal(const nsAString& aName, const nsAString& aValue)
 {
   Param* param = mSearchParams.AppendElement();
   param->mKey = aName;
   param->mValue = aValue;
@@ -319,17 +296,17 @@ URLSearchParams::Delete(const nsAString&
       mSearchParams.RemoveElementAt(i);
       found = true;
     } else {
       ++i;
     }
   }
 
   if (found) {
-    NotifyObservers(nullptr);
+    NotifyObserver();
   }
 }
 
 void
 URLSearchParams::DeleteAll()
 {
   mSearchParams.Clear();
 }
@@ -375,19 +352,17 @@ URLSearchParams::Serialize(nsAString& aV
 
     SerializeString(NS_ConvertUTF16toUTF8(mSearchParams[i].mKey), aValue);
     aValue.Append('=');
     SerializeString(NS_ConvertUTF16toUTF8(mSearchParams[i].mValue), aValue);
   }
 }
 
 void
-URLSearchParams::NotifyObservers(URLSearchParamsObserver* aExceptObserver)
+URLSearchParams::NotifyObserver()
 {
-  for (uint32_t i = 0; i < mObservers.Length(); ++i) {
-    if (mObservers[i] != aExceptObserver) {
-      mObservers[i]->URLSearchParamsUpdated(this);
-    }
+  if (mObserver) {
+    mObserver->URLSearchParamsUpdated(this);
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/URLSearchParams.h
+++ b/dom/base/URLSearchParams.h
@@ -35,17 +35,17 @@ class URLSearchParams final : public nsI
                               public nsWrapperCache
 {
   ~URLSearchParams();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URLSearchParams)
 
-  URLSearchParams();
+  explicit URLSearchParams(URLSearchParamsObserver* aObserver);
 
   // WebIDL methods
   nsISupports* GetParentObject() const
   {
     return nullptr;
   }
 
   virtual JSObject*
@@ -54,22 +54,17 @@ public:
   static already_AddRefed<URLSearchParams>
   Constructor(const GlobalObject& aGlobal, const nsAString& aInit,
               ErrorResult& aRv);
 
   static already_AddRefed<URLSearchParams>
   Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
               ErrorResult& aRv);
 
-  void ParseInput(const nsACString& aInput,
-                  URLSearchParamsObserver* aObserver);
-
-  void AddObserver(URLSearchParamsObserver* aObserver);
-  void RemoveObserver(URLSearchParamsObserver* aObserver);
-  void RemoveObservers();
+  void ParseInput(const nsACString& aInput);
 
   void Serialize(nsAString& aValue) const;
 
   void Get(const nsAString& aName, nsString& aRetval);
 
   void GetAll(const nsAString& aName, nsTArray<nsString >& aRetval);
 
   void Set(const nsAString& aName, const nsAString& aValue);
@@ -108,26 +103,26 @@ public:
 private:
   void AppendInternal(const nsAString& aName, const nsAString& aValue);
 
   void DeleteAll();
 
   void DecodeString(const nsACString& aInput, nsAString& aOutput);
   void ConvertString(const nsACString& aInput, nsAString& aOutput);
 
-  void NotifyObservers(URLSearchParamsObserver* aExceptObserver);
+  void NotifyObserver();
 
   struct Param
   {
     nsString mKey;
     nsString mValue;
   };
 
   nsTArray<Param> mSearchParams;
 
-  nsTArray<nsRefPtr<URLSearchParamsObserver>> mObservers;
+  nsRefPtr<URLSearchParamsObserver> mObserver;
   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_URLSearchParams_h */
--- a/dom/base/test/test_urlSearchParams.html
+++ b/dom/base/test/test_urlSearchParams.html
@@ -119,140 +119,51 @@ https://bugzilla.mozilla.org/show_bug.cg
     ok(url.searchParams.has('a'), "URL.searchParams.has('a')");
     is(url.searchParams.get('a'), 'b', "URL.searchParams.get('a')");
     ok(url.searchParams.has('c'), "URL.searchParams.has('c')");
     is(url.searchParams.get('c'), 'd', "URL.searchParams.get('c')");
 
     url.searchParams.set('e', 'f');
     ok(url.href.indexOf('e=f') != 1, 'URL right');
 
-    var u = new URLSearchParams();
-    u.append('foo', 'bar');
-    url.searchParams = u;
-    is(url.searchParams, u, "URL.searchParams is the same object");
-    is(url.searchParams.get('foo'), 'bar', "URL.searchParams.get('foo')");
-    is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
-
-    try {
-      url.searchParams = null;
-      ok(false, "URLSearchParams is not nullable");
-    } catch(e) {
-      ok(true, "URLSearchParams is not nullable");
-    }
-
-    var url2 = new URL('http://www.example.net?e=f');
-    url.searchParams = url2.searchParams;
-    is(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
-    is(url.searchParams.get('e'), 'f', "URL.searchParams.get('e')");
-
-    url.href = "http://www.example.net?bar=foo";
-    is(url.searchParams.get('bar'), 'foo', "URL.searchParams.get('bar')");
-
     runTest();
   }
 
   function testElement(e) {
     ok(e, 'element exists');
     ok(e.searchParams, "e.searchParams exists!");
     ok(e.searchParams.has('a'), "e.searchParams.has('a')");
     is(e.searchParams.get('a'), 'b', "e.searchParams.get('a')");
     ok(e.searchParams.has('c'), "e.searchParams.has('c')");
     is(e.searchParams.get('c'), 'd', "e.searchParams.get('c')");
 
     e.searchParams.set('e', 'f');
     ok(e.href.indexOf('e=f') != 1, 'e is right');
 
-    var u = new URLSearchParams();
-    u.append('foo', 'bar');
-    e.searchParams = u;
-    is(e.searchParams, u, "e.searchParams is the same object");
-    is(e.searchParams.get('foo'), 'bar', "e.searchParams.get('foo')");
-    is(e.href, 'http://www.example.net/?foo=bar', 'e is right');
-
-    try {
-      e.searchParams = null;
-      ok(false, "URLSearchParams is not nullable");
-    } catch(e) {
-      ok(true, "URLSearchParams is not nullable");
-    }
-
-    var url2 = new URL('http://www.example.net?e=f');
-    e.searchParams = url2.searchParams;
-    is(e.searchParams, url2.searchParams, "e.searchParams is not the same object");
-    is(e.searchParams.get('e'), 'f', "e.searchParams.get('e')");
-
-    e.href = "http://www.example.net?bar=foo";
-    is(e.searchParams.get('bar'), 'foo', "e.searchParams.get('bar')");
-
-    e.setAttribute('href', "http://www.example.net?bar2=foo2");
-    is(e.searchParams.get('bar2'), 'foo2', "e.searchParams.get('bar2')");
-
     runTest();
   }
 
   function testEncoding() {
     var encoding = [ [ '1', '1' ],
                      [ 'a b', 'a+b' ],
                      [ '<>', '%3C%3E' ],
                      [ '\u0541', '%D5%81'] ];
 
     for (var i = 0; i < encoding.length; ++i) {
-      var a = new URLSearchParams();
-      a.set('a', encoding[i][0]);
-
       var url = new URL('http://www.example.net');
-      url.searchParams = a;
+      url.searchParams.set('a', encoding[i][0]);
       is(url.href, 'http://www.example.net/?a=' + encoding[i][1]);
 
       var url2 = new URL(url.href);
       is(url2.searchParams.get('a'), encoding[i][0], 'a is still there');
     }
 
     runTest();
   }
 
-  function testMultiURL() {
-    var a = new URL('http://www.example.net?a=b&c=d');
-    var b = new URL('http://www.example.net?e=f');
-    var c = document.createElement('a');
-    var d = document.createElement('area');
-    ok(a.searchParams.has('a'), "a.searchParams.has('a')");
-    ok(a.searchParams.has('c'), "a.searchParams.has('c')");
-    ok(b.searchParams.has('e'), "b.searchParams.has('e')");
-    ok(c.searchParams, "c.searchParams");
-    ok(d.searchParams, "d.searchParams");
-
-    var u = new URLSearchParams();
-    a.searchParams = b.searchParams = c.searchParams = d.searchParams = u;
-    is(a.searchParams, u, "a.searchParams === u");
-    is(b.searchParams, u, "b.searchParams === u");
-    is(c.searchParams, u, "c.searchParams === u");
-    is(d.searchParams, u, "d.searchParams === u");
-    ok(!a.searchParams.has('a'), "!a.searchParams.has('a')");
-    ok(!a.searchParams.has('c'), "!a.searchParams.has('c')");
-    ok(!b.searchParams.has('e'), "!b.searchParams.has('e')");
-
-    u.append('foo', 'bar');
-    is(a.searchParams.get('foo'), 'bar', "a has foo=bar");
-    is(b.searchParams.get('foo'), 'bar', "b has foo=bar");
-    is(c.searchParams.get('foo'), 'bar', "c has foo=bar");
-    is(d.searchParams.get('foo'), 'bar', "d has foo=bar");
-    is(a + "", b + "", "stringify a == b");
-    is(c.searchParams + "", b.searchParams + "", "stringify c.searchParams == b.searchParams");
-    is(d.searchParams + "", b.searchParams + "", "stringify d.searchParams == b.searchParams");
-
-    a.search = "?bar=foo";
-    is(a.searchParams.get('bar'), 'foo', "a has bar=foo");
-    is(b.searchParams.get('bar'), 'foo', "b has bar=foo");
-    is(c.searchParams.get('bar'), 'foo', "c has bar=foo");
-    is(d.searchParams.get('bar'), 'foo', "d has bar=foo");
-
-    runTest();
-  }
-
   function testOrdering() {
     var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
     is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
     is(a.getAll('a').length, 3, "Correct length of getAll()");
 
     var b = new URLSearchParams();
     b.append('a', '1');
     b.append('b', '2');
@@ -329,17 +240,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   var tests = [
     testSimpleURLSearchParams,
     testCopyURLSearchParams,
     testParserURLSearchParams,
     testURL,
     function() { testElement(document.getElementById('anchor')) },
     function() { testElement(document.getElementById('area')) },
     testEncoding,
-    testMultiURL,
     testOrdering,
     testDelete,
     testGetNULL,
     testSet
   ];
 
   function runTest() {
     if (!tests.length) {
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -1595,18 +1595,18 @@ FetchBody<Derived>::ContinueConsumeBody(
         NS_NAMED_LITERAL_CSTRING(urlDataMimeType, "application/x-www-form-urlencoded");
         bool isValidUrlEncodedMimeType = StringBeginsWith(mMimeType, urlDataMimeType);
 
         if (isValidUrlEncodedMimeType && mMimeType.Length() > urlDataMimeType.Length()) {
           isValidUrlEncodedMimeType = mMimeType[urlDataMimeType.Length()] == ';';
         }
 
         if (isValidUrlEncodedMimeType) {
-          nsRefPtr<URLSearchParams> params = new URLSearchParams();
-          params->ParseInput(data, /* aObserver */ nullptr);
+          nsRefPtr<URLSearchParams> params = new URLSearchParams(nullptr);
+          params->ParseInput(data);
 
           nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
           FillFormIterator iterator(fd);
           DebugOnly<bool> status = params->ForEach(iterator);
           MOZ_ASSERT(status);
 
           localPromise->MaybeResolve(fd);
         } else {
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -153,17 +153,16 @@ public:
 
   using Link::GetSearch;
   using Link::SetSearch;
 
   using Link::GetHash;
   using Link::SetHash;
 
   // The Link::GetSearchParams is OK for us
-  // The Link::SetSearchParams is OK for us
 
   bool NoHref() const
   {
     return GetBoolAttr(nsGkAtoms::nohref);
   }
 
   void SetNoHref(bool aValue, ErrorResult& aError)
   {
--- a/dom/webidl/URLUtils.webidl
+++ b/dom/webidl/URLUtils.webidl
@@ -46,10 +46,10 @@ interface URLUtils {
   // Bug 824857 should remove this.
   [Throws]
   stringifier;
 };
 
 [NoInterfaceObject,
  Exposed=(Window, Worker)]
 interface URLUtilsSearchParams {
-           attribute URLSearchParams searchParams;
+ readonly attribute URLSearchParams searchParams;
 };
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -834,31 +834,16 @@ URL::SetSearchInternal(const nsAString& 
 mozilla::dom::URLSearchParams*
 URL::SearchParams()
 {
   CreateSearchParamsIfNeeded();
   return mSearchParams;
 }
 
 void
-URL::SetSearchParams(URLSearchParams& aSearchParams)
-{
-  if (mSearchParams) {
-    mSearchParams->RemoveObserver(this);
-  }
-
-  mSearchParams = &aSearchParams;
-  mSearchParams->AddObserver(this);
-
-  nsAutoString search;
-  mSearchParams->Serialize(search);
-  SetSearchInternal(search);
-}
-
-void
 URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
 {
   nsRefPtr<GetterRunnable> runnable =
     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHash, aHash,
                        mURLProxy);
 
   if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
     JS_ReportPendingException(mWorkerPrivate->GetJSContext());
@@ -954,23 +939,22 @@ URL::URLSearchParamsUpdated(URLSearchPar
 
 void
 URL::UpdateURLSearchParams()
 {
   if (mSearchParams) {
     nsAutoString search;
     ErrorResult rv;
     GetSearch(search, rv);
-    mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)), this);
+    mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
   }
 }
 
 void
 URL::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
-    mSearchParams = new URLSearchParams();
-    mSearchParams->AddObserver(this);
+    mSearchParams = new URLSearchParams(this);
     UpdateURLSearchParams();
   }
 }
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/URL.h
+++ b/dom/workers/URL.h
@@ -103,18 +103,16 @@ public:
   void SetPathname(const nsAString& aPathname, ErrorResult& aRv);
 
   void GetSearch(nsAString& aSearch, ErrorResult& aRv) const;
 
   void SetSearch(const nsAString& aSearch, ErrorResult& aRv);
 
   URLSearchParams* SearchParams();
 
-  void SetSearchParams(URLSearchParams& aSearchParams);
-
   void GetHash(nsAString& aHost, ErrorResult& aRv) const;
 
   void SetHash(const nsAString& aHash, ErrorResult& aRv);
 
   void Stringify(nsAString& aRetval, ErrorResult& aRv) const
   {
     GetHref(aRetval, aRv);
   }
--- a/dom/workers/test/urlSearchParams_worker.js
+++ b/dom/workers/test/urlSearchParams_worker.js
@@ -111,95 +111,43 @@ onmessage = function() {
     ok(url.searchParams.has('a'), "URL.searchParams.has('a')");
     is(url.searchParams.get('a'), 'b', "URL.searchParams.get('a')");
     ok(url.searchParams.has('c'), "URL.searchParams.has('c')");
     is(url.searchParams.get('c'), 'd', "URL.searchParams.get('c')");
 
     url.searchParams.set('e', 'f');
     ok(url.href.indexOf('e=f') != 1, 'URL right');
 
-    var u = new URLSearchParams();
-    u.append('foo', 'bar');
-    url.searchParams = u;
-    is(url.searchParams, u, "URL.searchParams is the same object");
-    is(url.searchParams.get('foo'), 'bar', "URL.searchParams.get('foo')");
-    is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
-
-    try {
-      url.searchParams = null;
-      ok(false, "URLSearchParams is not nullable");
-    } catch(e) {
-      ok(true, "URLSearchParams is not nullable");
-    }
-
-    var url2 = new URL('http://www.example.net?e=f');
-    url.searchParams = url2.searchParams;
-    is(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
-    is(url.searchParams.get('e'), 'f', "URL.searchParams.get('e')");
-
-    url.href = "http://www.example.net?bar=foo";
-    is(url.searchParams.get('bar'), 'foo', "URL.searchParams.get('bar')");
-
     runTest();
   }
 
   function testEncoding() {
     var encoding = [ [ '1', '1' ],
                      [ 'a b', 'a+b' ],
                      [ '<>', '%3C%3E' ],
                      [ '\u0541', '%D5%81'] ];
 
     for (var i = 0; i < encoding.length; ++i) {
-      var a = new URLSearchParams();
-      a.set('a', encoding[i][0]);
-
       var url = new URL('http://www.example.net');
-      url.searchParams = a;
+      url.searchParams.set('a', encoding[i][0]);
       is(url.href, 'http://www.example.net/?a=' + encoding[i][1]);
 
       var url2 = new URL(url.href);
       is(url2.searchParams.get('a'), encoding[i][0], 'a is still there');
     }
 
     runTest();
   }
 
-  function testMultiURL() {
-    var a = new URL('http://www.example.net?a=b&c=d');
-    var b = new URL('http://www.example.net?e=f');
-    ok(a.searchParams.has('a'), "a.searchParams.has('a')");
-    ok(a.searchParams.has('c'), "a.searchParams.has('c')");
-    ok(b.searchParams.has('e'), "b.searchParams.has('e')");
-
-    var u = new URLSearchParams();
-    a.searchParams = b.searchParams = u;
-    is(a.searchParams, u, "a.searchParams === u");
-    is(b.searchParams, u, "b.searchParams === u");
-    ok(!a.searchParams.has('a'), "!a.searchParams.has('a')");
-    ok(!a.searchParams.has('c'), "!a.searchParams.has('c')");
-    ok(!b.searchParams.has('e'), "!b.searchParams.has('e')");
-
-    u.append('foo', 'bar');
-    is(a.searchParams.get('foo'), 'bar', "a has foo=bar");
-    is(b.searchParams.get('foo'), 'bar', "b has foo=bar");
-    is(a + "", b + "", "stringify a == b");
-
-    a.search = "?bar=foo";
-    is(a.searchParams.get('bar'), 'foo', "a has bar=foo");
-    is(b.searchParams.get('bar'), 'foo', "b has bar=foo");
-
-    runTest();
-  }
   var tests = [
     testSimpleURLSearchParams,
     testCopyURLSearchParams,
     testParserURLSearchParams,
     testURL,
     testEncoding,
-    testMultiURL
   ];
 
   function runTest() {
     if (!tests.length) {
       postMessage({type: 'finish' });
       return;
     }
 
--- a/toolkit/components/places/tests/cpp/mock_Link.h
+++ b/toolkit/components/places/tests/cpp/mock_Link.h
@@ -140,50 +140,37 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearc
 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 
-URLSearchParams::URLSearchParams()
+URLSearchParams::URLSearchParams(URLSearchParamsObserver* aObserver)
 {
 }
 
 URLSearchParams::~URLSearchParams()
 {
 }
 
 JSObject*
 URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return nullptr;
 }
 
 void
-URLSearchParams::ParseInput(const nsACString& aInput,
-                            URLSearchParamsObserver* aObserver)
+URLSearchParams::ParseInput(const nsACString& aInput)
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::ParseInput");
 }
 
 void
-URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
-{
-  NS_NOTREACHED("Unexpected call to URLSearchParams::SetObserver");
-}
-
-void
-URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver)
-{
-  NS_NOTREACHED("Unexpected call to URLSearchParams::SetObserver");
-}
-
-void
 URLSearchParams::Serialize(nsAString& aValue) const
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::Serialize");
 }
 
 void
 URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
 {
@@ -229,17 +216,17 @@ URLSearchParams::Delete(const nsAString&
 
 void
 URLSearchParams::DeleteAll()
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::DeleteAll");
 }
 
 void
-URLSearchParams::NotifyObservers(URLSearchParamsObserver* aExceptObserver)
+URLSearchParams::NotifyObserver()
 {
-  NS_NOTREACHED("Unexpected call to URLSearchParams::NotifyObservers");
+  NS_NOTREACHED("Unexpected call to URLSearchParams::NotifyObserver");
 }
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mock_Link_h__