dom/base/nsLocation.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsLocation.h"
     8 #include "nsIScriptSecurityManager.h"
     9 #include "nsIScriptObjectPrincipal.h"
    10 #include "nsIScriptContext.h"
    11 #include "nsIDocShell.h"
    12 #include "nsIDocShellLoadInfo.h"
    13 #include "nsIWebNavigation.h"
    14 #include "nsCDefaultURIFixup.h"
    15 #include "nsIURIFixup.h"
    16 #include "nsIURL.h"
    17 #include "nsIJARURI.h"
    18 #include "nsNetUtil.h"
    19 #include "nsCOMPtr.h"
    20 #include "nsEscape.h"
    21 #include "nsIDOMWindow.h"
    22 #include "nsIDocument.h"
    23 #include "nsIPresShell.h"
    24 #include "nsPresContext.h"
    25 #include "nsError.h"
    26 #include "nsDOMClassInfoID.h"
    27 #include "nsReadableUtils.h"
    28 #include "nsITextToSubURI.h"
    29 #include "nsJSUtils.h"
    30 #include "nsContentUtils.h"
    31 #include "mozilla/Likely.h"
    32 #include "nsCycleCollectionParticipant.h"
    33 #include "nsNullPrincipal.h"
    34 #include "ScriptSettings.h"
    36 static nsresult
    37 GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
    38 {
    39   aCharset.Truncate();
    41   JSContext *cx = nsContentUtils::GetCurrentJSContext();
    42   if (cx) {
    43     nsCOMPtr<nsPIDOMWindow> window =
    44       do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
    45     NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
    47     if (nsIDocument* doc = window->GetDoc()) {
    48       aCharset = doc->GetDocumentCharacterSet();
    49     }
    50   }
    52   return NS_OK;
    53 }
    55 nsLocation::nsLocation(nsIDocShell *aDocShell)
    56 {
    57   mDocShell = do_GetWeakReference(aDocShell);
    58   nsCOMPtr<nsIDOMWindow> outer = do_GetInterface(aDocShell);
    59   mOuter = do_GetWeakReference(outer);
    60 }
    62 nsLocation::~nsLocation()
    63 {
    64 }
    66 DOMCI_DATA(Location, nsLocation)
    68 // QueryInterface implementation for nsLocation
    69 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsLocation)
    70   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    71   NS_INTERFACE_MAP_ENTRY(nsIDOMLocation)
    72   NS_INTERFACE_MAP_ENTRY(nsISupports)
    73   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location)
    74 NS_INTERFACE_MAP_END
    76 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsLocation)
    77 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsLocation)
    78 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsLocation)
    80 void
    81 nsLocation::SetDocShell(nsIDocShell *aDocShell)
    82 {
    83    mDocShell = do_GetWeakReference(aDocShell);
    84 }
    86 nsIDocShell *
    87 nsLocation::GetDocShell()
    88 {
    89   nsCOMPtr<nsIDocShell> docshell(do_QueryReferent(mDocShell));
    90   return docshell;
    91 }
    93 nsresult
    94 nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
    95 {
    96   *aLoadInfo = nullptr;
    98   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
    99   NS_ENSURE_TRUE(docShell, NS_ERROR_NOT_AVAILABLE);
   101   nsCOMPtr<nsISupports> owner;
   102   nsCOMPtr<nsIURI> sourceURI;
   104   if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
   105     // No cx means that there's no JS running, or at least no JS that
   106     // was run through code that properly pushed a context onto the
   107     // context stack (as all code that runs JS off of web pages
   108     // does). We won't bother with security checks in this case, but
   109     // we need to create the loadinfo etc.
   111     // Get security manager.
   112     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   113     NS_ENSURE_STATE(ssm);
   115     // Check to see if URI is allowed.
   116     nsresult rv = ssm->CheckLoadURIFromScript(cx, aURI);
   117     NS_ENSURE_SUCCESS(rv, rv);
   119     // Make the load's referrer reflect changes to the document's URI caused by
   120     // push/replaceState, if possible.  First, get the document corresponding to
   121     // fp.  If the document's original URI (i.e. its URI before
   122     // push/replaceState) matches the principal's URI, use the document's
   123     // current URI as the referrer.  If they don't match, use the principal's
   124     // URI.
   126     nsCOMPtr<nsIDocument> doc;
   127     nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI, principalURI;
   128     nsCOMPtr<nsPIDOMWindow> incumbent =
   129       do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
   130     if (incumbent) {
   131       doc = incumbent->GetDoc();
   132     }
   133     if (doc) {
   134       docOriginalURI = doc->GetOriginalURI();
   135       docCurrentURI = doc->GetDocumentURI();
   136       rv = doc->NodePrincipal()->GetURI(getter_AddRefs(principalURI));
   137       NS_ENSURE_SUCCESS(rv, rv);
   138     }
   140     bool urisEqual = false;
   141     if (docOriginalURI && docCurrentURI && principalURI) {
   142       principalURI->Equals(docOriginalURI, &urisEqual);
   143     }
   145     if (urisEqual) {
   146       sourceURI = docCurrentURI;
   147     }
   148     else {
   149       // Use principalURI as long as it is not an nsNullPrincipalURI.
   150       // We could add a method such as GetReferrerURI to principals to make this
   151       // cleaner, but given that we need to start using Source Browsing Context
   152       // for referrer (see Bug 960639) this may be wasted effort at this stage.
   153       if (principalURI) {
   154         bool isNullPrincipalScheme;
   155         rv = principalURI->SchemeIs(NS_NULLPRINCIPAL_SCHEME,
   156                                     &isNullPrincipalScheme);
   157         if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
   158           sourceURI = principalURI;
   159         }
   160       }
   161     }
   163     owner = do_QueryInterface(ssm->GetCxSubjectPrincipal(cx));
   164   }
   166   // Create load info
   167   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   168   docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   169   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
   171   loadInfo->SetOwner(owner);
   173   if (sourceURI) {
   174     loadInfo->SetReferrer(sourceURI);
   175   }
   177   loadInfo.swap(*aLoadInfo);
   179   return NS_OK;
   180 }
   182 nsresult
   183 nsLocation::GetURI(nsIURI** aURI, bool aGetInnermostURI)
   184 {
   185   *aURI = nullptr;
   187   nsresult rv;
   188   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   189   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell, &rv));
   190   if (NS_FAILED(rv)) {
   191     return rv;
   192   }
   194   nsCOMPtr<nsIURI> uri;
   195   rv = webNav->GetCurrentURI(getter_AddRefs(uri));
   196   NS_ENSURE_SUCCESS(rv, rv);
   198   // It is valid for docshell to return a null URI. Don't try to fixup
   199   // if this happens.
   200   if (!uri) {
   201     return NS_OK;
   202   }
   204   if (aGetInnermostURI) {
   205     nsCOMPtr<nsIJARURI> jarURI(do_QueryInterface(uri));
   206     while (jarURI) {
   207       jarURI->GetJARFile(getter_AddRefs(uri));
   208       jarURI = do_QueryInterface(uri);
   209     }
   210   }
   212   NS_ASSERTION(uri, "nsJARURI screwed up?");
   214   nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
   215   NS_ENSURE_SUCCESS(rv, rv);
   217   return urifixup->CreateExposableURI(uri, aURI);
   218 }
   220 nsresult
   221 nsLocation::GetWritableURI(nsIURI** aURI)
   222 {
   223   *aURI = nullptr;
   225   nsCOMPtr<nsIURI> uri;
   227   nsresult rv = GetURI(getter_AddRefs(uri));
   228   if (NS_FAILED(rv) || !uri) {
   229     return rv;
   230   }
   232   return uri->Clone(aURI);
   233 }
   235 nsresult
   236 nsLocation::SetURI(nsIURI* aURI, bool aReplace)
   237 {
   238   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   239   if (docShell) {
   240     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   241     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
   243     if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
   244       return NS_ERROR_FAILURE;
   246     if (aReplace) {
   247       loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
   248     } else {
   249       loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
   250     }
   252     // Get the incumbent script's browsing context to set as source.
   253     nsCOMPtr<nsPIDOMWindow> sourceWindow =
   254       do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
   255     if (sourceWindow) {
   256       loadInfo->SetSourceDocShell(sourceWindow->GetDocShell());
   257     }
   259     return docShell->LoadURI(aURI, loadInfo,
   260                              nsIWebNavigation::LOAD_FLAGS_NONE, true);
   261   }
   263   return NS_OK;
   264 }
   266 NS_IMETHODIMP
   267 nsLocation::GetHash(nsAString& aHash)
   268 {
   269   if (!CallerSubsumes())
   270     return NS_ERROR_DOM_SECURITY_ERR;
   272   aHash.SetLength(0);
   274   nsCOMPtr<nsIURI> uri;
   275   nsresult rv = GetURI(getter_AddRefs(uri));
   276   if (NS_FAILED(rv) || !uri) {
   277     return rv;
   278   }
   280   nsAutoCString ref;
   281   nsAutoString unicodeRef;
   283   rv = uri->GetRef(ref);
   284   if (NS_SUCCEEDED(rv)) {
   285     nsCOMPtr<nsITextToSubURI> textToSubURI(
   286         do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
   288     if (NS_SUCCEEDED(rv)) {
   289       nsAutoCString charset;
   290       uri->GetOriginCharset(charset);
   292       rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
   293     }
   295     if (NS_FAILED(rv)) {
   296       // Oh, well.  No intl here!
   297       NS_UnescapeURL(ref);
   298       CopyASCIItoUTF16(ref, unicodeRef);
   299       rv = NS_OK;
   300     }
   301   }
   303   if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
   304     aHash.Assign(char16_t('#'));
   305     aHash.Append(unicodeRef);
   306   }
   308   if (aHash == mCachedHash) {
   309     // Work around ShareThis stupidly polling location.hash every
   310     // 5ms all the time by handing out the same exact string buffer
   311     // we handed out last time.
   312     aHash = mCachedHash;
   313   } else {
   314     mCachedHash = aHash;
   315   }
   317   return rv;
   318 }
   320 NS_IMETHODIMP
   321 nsLocation::SetHash(const nsAString& aHash)
   322 {
   323   nsCOMPtr<nsIURI> uri;
   324   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   325   if (NS_FAILED(rv) || !uri) {
   326     return rv;
   327   }
   329   NS_ConvertUTF16toUTF8 hash(aHash);
   330   if (hash.IsEmpty() || hash.First() != char16_t('#')) {
   331     hash.Insert(char16_t('#'), 0);
   332   }
   333   rv = uri->SetRef(hash);
   334   if (NS_WARN_IF(NS_FAILED(rv))) {
   335     return rv;
   336   }
   338   return SetURI(uri);
   339 }
   341 NS_IMETHODIMP
   342 nsLocation::GetHost(nsAString& aHost)
   343 {
   344   if (!CallerSubsumes())
   345     return NS_ERROR_DOM_SECURITY_ERR;
   347   aHost.Truncate();
   349   nsCOMPtr<nsIURI> uri;
   350   nsresult result;
   352   result = GetURI(getter_AddRefs(uri), true);
   354   if (uri) {
   355     nsAutoCString hostport;
   357     result = uri->GetHostPort(hostport);
   359     if (NS_SUCCEEDED(result)) {
   360       AppendUTF8toUTF16(hostport, aHost);
   361     }
   362   }
   364   return NS_OK;
   365 }
   367 NS_IMETHODIMP
   368 nsLocation::SetHost(const nsAString& aHost)
   369 {
   370   if (!CallerSubsumes())
   371     return NS_ERROR_DOM_SECURITY_ERR;
   373   nsCOMPtr<nsIURI> uri;
   374   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   375   if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   376     return rv;
   377   }
   379   rv = uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
   380   if (NS_WARN_IF(NS_FAILED(rv))) {
   381     return rv;
   382   }
   384   return SetURI(uri);
   385 }
   387 NS_IMETHODIMP
   388 nsLocation::GetHostname(nsAString& aHostname)
   389 {
   390   if (!CallerSubsumes())
   391     return NS_ERROR_DOM_SECURITY_ERR;
   393   aHostname.Truncate();
   395   nsCOMPtr<nsIURI> uri;
   396   nsresult result;
   398   result = GetURI(getter_AddRefs(uri), true);
   400   if (uri) {
   401     nsAutoCString host;
   403     result = uri->GetHost(host);
   405     if (NS_SUCCEEDED(result)) {
   406       AppendUTF8toUTF16(host, aHostname);
   407     }
   408   }
   410   return NS_OK;
   411 }
   413 NS_IMETHODIMP
   414 nsLocation::SetHostname(const nsAString& aHostname)
   415 {
   416   if (!CallerSubsumes())
   417     return NS_ERROR_DOM_SECURITY_ERR;
   419   nsCOMPtr<nsIURI> uri;
   420   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   421   if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   422     return rv;
   423   }
   425   rv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
   426   if (NS_WARN_IF(NS_FAILED(rv))) {
   427     return rv;
   428   }
   430   return SetURI(uri);
   431 }
   433 NS_IMETHODIMP
   434 nsLocation::GetHref(nsAString& aHref)
   435 {
   436   if (!CallerSubsumes())
   437     return NS_ERROR_DOM_SECURITY_ERR;
   439   aHref.Truncate();
   441   nsCOMPtr<nsIURI> uri;
   442   nsresult result;
   444   result = GetURI(getter_AddRefs(uri));
   446   if (uri) {
   447     nsAutoCString uriString;
   449     result = uri->GetSpec(uriString);
   451     if (NS_SUCCEEDED(result)) {
   452       AppendUTF8toUTF16(uriString, aHref);
   453     }
   454   }
   456   return result;
   457 }
   459 NS_IMETHODIMP
   460 nsLocation::SetHref(const nsAString& aHref)
   461 {
   462   nsAutoString oldHref;
   463   nsresult rv = NS_OK;
   465   JSContext *cx = nsContentUtils::GetCurrentJSContext();
   466   if (cx) {
   467     rv = SetHrefWithContext(cx, aHref, false);
   468   } else {
   469     rv = GetHref(oldHref);
   471     if (NS_SUCCEEDED(rv)) {
   472       nsCOMPtr<nsIURI> oldUri;
   474       rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
   476       if (oldUri) {
   477         rv = SetHrefWithBase(aHref, oldUri, false);
   478       }
   479     }
   480   }
   482   return rv;
   483 }
   485 nsresult
   486 nsLocation::SetHrefWithContext(JSContext* cx, const nsAString& aHref,
   487                                bool aReplace)
   488 {
   489   nsCOMPtr<nsIURI> base;
   491   // Get the source of the caller
   492   nsresult result = GetSourceBaseURL(cx, getter_AddRefs(base));
   494   if (NS_FAILED(result)) {
   495     return result;
   496   }
   498   return SetHrefWithBase(aHref, base, aReplace);
   499 }
   501 nsresult
   502 nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
   503                             bool aReplace)
   504 {
   505   nsresult result;
   506   nsCOMPtr<nsIURI> newUri;
   508   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   510   nsAutoCString docCharset;
   511   if (NS_SUCCEEDED(GetDocumentCharacterSetForURI(aHref, docCharset)))
   512     result = NS_NewURI(getter_AddRefs(newUri), aHref, docCharset.get(), aBase);
   513   else
   514     result = NS_NewURI(getter_AddRefs(newUri), aHref, nullptr, aBase);
   516   if (newUri) {
   517     /* Check with the scriptContext if it is currently processing a script tag.
   518      * If so, this must be a <script> tag with a location.href in it.
   519      * we want to do a replace load, in such a situation. 
   520      * In other cases, for example if a event handler or a JS timer
   521      * had a location.href in it, we want to do a normal load,
   522      * so that the new url will be appended to Session History.
   523      * This solution is tricky. Hopefully it isn't going to bite
   524      * anywhere else. This is part of solution for bug # 39938, 72197
   525      * 
   526      */
   527     bool inScriptTag=false;
   528     JSContext *cx = nsContentUtils::GetCurrentJSContext();
   529     if (cx) {
   530       nsIScriptContext *scriptContext =
   531         nsJSUtils::GetDynamicScriptContext(cx);
   533       if (scriptContext) {
   534         if (scriptContext->GetProcessingScriptTag()) {
   535           // Now check to make sure that the script is running in our window,
   536           // since we only want to replace if the location is set by a
   537           // <script> tag in the same window.  See bug 178729.
   538           nsCOMPtr<nsIScriptGlobalObject> ourGlobal(do_GetInterface(docShell));
   539           inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
   540         }
   541       }  
   542     } //cx
   544     return SetURI(newUri, aReplace || inScriptTag);
   545   }
   547   return result;
   548 }
   550 NS_IMETHODIMP
   551 nsLocation::GetOrigin(nsAString& aOrigin)
   552 {
   553   if (!CallerSubsumes())
   554     return NS_ERROR_DOM_SECURITY_ERR;
   556   aOrigin.Truncate();
   558   nsCOMPtr<nsIURI> uri;
   559   nsresult rv = GetURI(getter_AddRefs(uri), true);
   560   NS_ENSURE_SUCCESS(rv, rv);
   561   NS_ENSURE_TRUE(uri, NS_OK);
   563   nsAutoString origin;
   564   rv = nsContentUtils::GetUTFOrigin(uri, origin);
   565   NS_ENSURE_SUCCESS(rv, rv);
   567   aOrigin = origin;
   568   return NS_OK;
   569 }
   571 NS_IMETHODIMP
   572 nsLocation::GetPathname(nsAString& aPathname)
   573 {
   574   if (!CallerSubsumes())
   575     return NS_ERROR_DOM_SECURITY_ERR;
   577   aPathname.Truncate();
   579   nsCOMPtr<nsIURI> uri;
   580   nsresult result = NS_OK;
   582   result = GetURI(getter_AddRefs(uri));
   584   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   585   if (url) {
   586     nsAutoCString file;
   588     result = url->GetFilePath(file);
   590     if (NS_SUCCEEDED(result)) {
   591       AppendUTF8toUTF16(file, aPathname);
   592     }
   593   }
   595   return result;
   596 }
   598 NS_IMETHODIMP
   599 nsLocation::SetPathname(const nsAString& aPathname)
   600 {
   601   if (!CallerSubsumes())
   602     return NS_ERROR_DOM_SECURITY_ERR;
   604   nsCOMPtr<nsIURI> uri;
   605   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   606   if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   607     return rv;
   608   }
   610   rv = uri->SetPath(NS_ConvertUTF16toUTF8(aPathname));
   611   if (NS_WARN_IF(NS_FAILED(rv))) {
   612     return rv;
   613   }
   615   return SetURI(uri);
   616 }
   618 NS_IMETHODIMP
   619 nsLocation::GetPort(nsAString& aPort)
   620 {
   621   if (!CallerSubsumes())
   622     return NS_ERROR_DOM_SECURITY_ERR;
   624   aPort.SetLength(0);
   626   nsCOMPtr<nsIURI> uri;
   627   nsresult result = NS_OK;
   629   result = GetURI(getter_AddRefs(uri), true);
   631   if (uri) {
   632     int32_t port;
   633     result = uri->GetPort(&port);
   635     if (NS_SUCCEEDED(result) && -1 != port) {
   636       nsAutoString portStr;
   637       portStr.AppendInt(port);
   638       aPort.Append(portStr);
   639     }
   641     // Don't propagate this exception to caller
   642     result = NS_OK;
   643   }
   645   return result;
   646 }
   648 NS_IMETHODIMP
   649 nsLocation::SetPort(const nsAString& aPort)
   650 {
   651   if (!CallerSubsumes())
   652     return NS_ERROR_DOM_SECURITY_ERR;
   654   nsCOMPtr<nsIURI> uri;
   655   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   656   if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   657     return rv;
   658   }
   660   // perhaps use nsReadingIterators at some point?
   661   NS_ConvertUTF16toUTF8 portStr(aPort);
   662   const char *buf = portStr.get();
   663   int32_t port = -1;
   665   if (!portStr.IsEmpty() && buf) {
   666     if (*buf == ':') {
   667       port = atol(buf+1);
   668     }
   669     else {
   670       port = atol(buf);
   671     }
   672   }
   674   rv = uri->SetPort(port);
   675   if (NS_WARN_IF(NS_FAILED(rv))) {
   676     return rv;
   677   }
   679   return SetURI(uri);
   680 }
   682 NS_IMETHODIMP
   683 nsLocation::GetProtocol(nsAString& aProtocol)
   684 {
   685   if (!CallerSubsumes())
   686     return NS_ERROR_DOM_SECURITY_ERR;
   688   aProtocol.SetLength(0);
   690   nsCOMPtr<nsIURI> uri;
   691   nsresult result = NS_OK;
   693   result = GetURI(getter_AddRefs(uri));
   695   if (uri) {
   696     nsAutoCString protocol;
   698     result = uri->GetScheme(protocol);
   700     if (NS_SUCCEEDED(result)) {
   701       CopyASCIItoUTF16(protocol, aProtocol);
   702       aProtocol.Append(char16_t(':'));
   703     }
   704   }
   706   return result;
   707 }
   709 NS_IMETHODIMP
   710 nsLocation::SetProtocol(const nsAString& aProtocol)
   711 {
   712   if (!CallerSubsumes())
   713     return NS_ERROR_DOM_SECURITY_ERR;
   715   nsCOMPtr<nsIURI> uri;
   716   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   717   if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   718     return rv;
   719   }
   721   rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol));
   722   if (NS_WARN_IF(NS_FAILED(rv))) {
   723     return rv;
   724   }
   726   return SetURI(uri);
   727 }
   729 NS_IMETHODIMP
   730 nsLocation::GetSearch(nsAString& aSearch)
   731 {
   732   if (!CallerSubsumes())
   733     return NS_ERROR_DOM_SECURITY_ERR;
   735   aSearch.SetLength(0);
   737   nsCOMPtr<nsIURI> uri;
   738   nsresult result = NS_OK;
   740   result = GetURI(getter_AddRefs(uri));
   742   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   744   if (url) {
   745     nsAutoCString search;
   747     result = url->GetQuery(search);
   749     if (NS_SUCCEEDED(result) && !search.IsEmpty()) {
   750       aSearch.Assign(char16_t('?'));
   751       AppendUTF8toUTF16(search, aSearch);
   752     }
   753   }
   755   return NS_OK;
   756 }
   758 NS_IMETHODIMP
   759 nsLocation::SetSearch(const nsAString& aSearch)
   760 {
   761   if (!CallerSubsumes())
   762     return NS_ERROR_DOM_SECURITY_ERR;
   764   nsCOMPtr<nsIURI> uri;
   765   nsresult rv = GetWritableURI(getter_AddRefs(uri));
   767   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   768   if (NS_WARN_IF(NS_FAILED(rv) || !url)) {
   769     return rv;
   770   }
   772   rv = url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
   773   if (NS_WARN_IF(NS_FAILED(rv))) {
   774     return rv;
   775   }
   777   return SetURI(uri);
   778 }
   780 NS_IMETHODIMP
   781 nsLocation::Reload(bool aForceget)
   782 {
   783   if (!CallerSubsumes())
   784     return NS_ERROR_DOM_SECURITY_ERR;
   786   nsresult rv;
   787   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   788   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
   789   nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(docShell));
   791   if (window && window->IsHandlingResizeEvent()) {
   792     // location.reload() was called on a window that is handling a
   793     // resize event. Sites do this since Netscape 4.x needed it, but
   794     // we don't, and it's a horrible experience for nothing. In stead
   795     // of reloading the page, just clear style data and reflow the
   796     // page since some sites may use this trick to work around gecko
   797     // reflow bugs, and this should have the same effect.
   799     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   801     nsIPresShell *shell;
   802     nsPresContext *pcx;
   803     if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
   804       pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
   805     }
   807     return NS_OK;
   808   }
   810   if (webNav) {
   811     uint32_t reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
   813     if (aForceget) {
   814       reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | 
   815                     nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
   816     }
   817     rv = webNav->Reload(reloadFlags);
   818     if (rv == NS_BINDING_ABORTED) {
   819       // This happens when we attempt to reload a POST result and the user says
   820       // no at the "do you want to reload?" prompt.  Don't propagate this one
   821       // back to callers.
   822       rv = NS_OK;
   823     }
   824   } else {
   825     rv = NS_ERROR_FAILURE;
   826   }
   828   return rv;
   829 }
   831 NS_IMETHODIMP
   832 nsLocation::Replace(const nsAString& aUrl)
   833 {
   834   nsresult rv = NS_OK;
   835   if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
   836     return SetHrefWithContext(cx, aUrl, true);
   837   }
   839   nsAutoString oldHref;
   841   rv = GetHref(oldHref);
   842   NS_ENSURE_SUCCESS(rv, rv);
   844   nsCOMPtr<nsIURI> oldUri;
   846   rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
   847   NS_ENSURE_SUCCESS(rv, rv);
   849   return SetHrefWithBase(aUrl, oldUri, true);
   850 }
   852 NS_IMETHODIMP
   853 nsLocation::Assign(const nsAString& aUrl)
   854 {
   855   if (!CallerSubsumes())
   856     return NS_ERROR_DOM_SECURITY_ERR;
   858   nsAutoString oldHref;
   859   nsresult result = NS_OK;
   861   result = GetHref(oldHref);
   863   if (NS_SUCCEEDED(result)) {
   864     nsCOMPtr<nsIURI> oldUri;
   866     result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
   868     if (oldUri) {
   869       result = SetHrefWithBase(aUrl, oldUri, false);
   870     }
   871   }
   873   return result;
   874 }
   876 NS_IMETHODIMP
   877 nsLocation::ToString(nsAString& aReturn)
   878 {
   879   // NB: GetHref checks CallerSubsumes().
   880   return GetHref(aReturn);
   881 }
   883 NS_IMETHODIMP
   884 nsLocation::ValueOf(nsIDOMLocation** aReturn)
   885 {
   886   nsCOMPtr<nsIDOMLocation> loc(this);
   887   loc.forget(aReturn);
   888   return NS_OK;
   889 }
   891 nsresult
   892 nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
   893 {
   895   *sourceURL = nullptr;
   896   nsCOMPtr<nsIScriptGlobalObject> sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
   897   // If this JS context doesn't have an associated DOM window, we effectively
   898   // have no script entry point stack. This doesn't generally happen with the DOM,
   899   // but can sometimes happen with extension code in certain IPC configurations.
   900   // If this happens, try falling back on the current document associated with
   901   // the docshell. If that fails, just return null and hope that the caller passed
   902   // an absolute URI.
   903   if (!sgo && GetDocShell()) {
   904     sgo = do_GetInterface(GetDocShell());
   905   }
   906   NS_ENSURE_TRUE(sgo, NS_OK);
   907   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
   908   NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
   909   nsIDocument* doc = window->GetDoc();
   910   NS_ENSURE_TRUE(doc, NS_OK);
   911   *sourceURL = doc->GetBaseURI().take();
   912   return NS_OK;
   913 }
   915 bool
   916 nsLocation::CallerSubsumes()
   917 {
   918   // Get the principal associated with the location object.
   919   nsCOMPtr<nsIDOMWindow> outer = do_QueryReferent(mOuter);
   920   if (MOZ_UNLIKELY(!outer))
   921     return false;
   922   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(outer);
   923   bool subsumes = false;
   924   nsresult rv = nsContentUtils::GetSubjectPrincipal()->SubsumesConsideringDomain(sop->GetPrincipal(), &subsumes);
   925   NS_ENSURE_SUCCESS(rv, false);
   926   return subsumes;
   927 }

mercurial