dom/base/nsLocation.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/base/nsLocation.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,927 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "nsLocation.h"
    1.11 +#include "nsIScriptSecurityManager.h"
    1.12 +#include "nsIScriptObjectPrincipal.h"
    1.13 +#include "nsIScriptContext.h"
    1.14 +#include "nsIDocShell.h"
    1.15 +#include "nsIDocShellLoadInfo.h"
    1.16 +#include "nsIWebNavigation.h"
    1.17 +#include "nsCDefaultURIFixup.h"
    1.18 +#include "nsIURIFixup.h"
    1.19 +#include "nsIURL.h"
    1.20 +#include "nsIJARURI.h"
    1.21 +#include "nsNetUtil.h"
    1.22 +#include "nsCOMPtr.h"
    1.23 +#include "nsEscape.h"
    1.24 +#include "nsIDOMWindow.h"
    1.25 +#include "nsIDocument.h"
    1.26 +#include "nsIPresShell.h"
    1.27 +#include "nsPresContext.h"
    1.28 +#include "nsError.h"
    1.29 +#include "nsDOMClassInfoID.h"
    1.30 +#include "nsReadableUtils.h"
    1.31 +#include "nsITextToSubURI.h"
    1.32 +#include "nsJSUtils.h"
    1.33 +#include "nsContentUtils.h"
    1.34 +#include "mozilla/Likely.h"
    1.35 +#include "nsCycleCollectionParticipant.h"
    1.36 +#include "nsNullPrincipal.h"
    1.37 +#include "ScriptSettings.h"
    1.38 +
    1.39 +static nsresult
    1.40 +GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
    1.41 +{
    1.42 +  aCharset.Truncate();
    1.43 +
    1.44 +  JSContext *cx = nsContentUtils::GetCurrentJSContext();
    1.45 +  if (cx) {
    1.46 +    nsCOMPtr<nsPIDOMWindow> window =
    1.47 +      do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
    1.48 +    NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
    1.49 +
    1.50 +    if (nsIDocument* doc = window->GetDoc()) {
    1.51 +      aCharset = doc->GetDocumentCharacterSet();
    1.52 +    }
    1.53 +  }
    1.54 +
    1.55 +  return NS_OK;
    1.56 +}
    1.57 +
    1.58 +nsLocation::nsLocation(nsIDocShell *aDocShell)
    1.59 +{
    1.60 +  mDocShell = do_GetWeakReference(aDocShell);
    1.61 +  nsCOMPtr<nsIDOMWindow> outer = do_GetInterface(aDocShell);
    1.62 +  mOuter = do_GetWeakReference(outer);
    1.63 +}
    1.64 +
    1.65 +nsLocation::~nsLocation()
    1.66 +{
    1.67 +}
    1.68 +
    1.69 +DOMCI_DATA(Location, nsLocation)
    1.70 +
    1.71 +// QueryInterface implementation for nsLocation
    1.72 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsLocation)
    1.73 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    1.74 +  NS_INTERFACE_MAP_ENTRY(nsIDOMLocation)
    1.75 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
    1.76 +  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location)
    1.77 +NS_INTERFACE_MAP_END
    1.78 +
    1.79 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsLocation)
    1.80 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsLocation)
    1.81 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsLocation)
    1.82 +
    1.83 +void
    1.84 +nsLocation::SetDocShell(nsIDocShell *aDocShell)
    1.85 +{
    1.86 +   mDocShell = do_GetWeakReference(aDocShell);
    1.87 +}
    1.88 +
    1.89 +nsIDocShell *
    1.90 +nsLocation::GetDocShell()
    1.91 +{
    1.92 +  nsCOMPtr<nsIDocShell> docshell(do_QueryReferent(mDocShell));
    1.93 +  return docshell;
    1.94 +}
    1.95 +
    1.96 +nsresult
    1.97 +nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
    1.98 +{
    1.99 +  *aLoadInfo = nullptr;
   1.100 +
   1.101 +  nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   1.102 +  NS_ENSURE_TRUE(docShell, NS_ERROR_NOT_AVAILABLE);
   1.103 +
   1.104 +  nsCOMPtr<nsISupports> owner;
   1.105 +  nsCOMPtr<nsIURI> sourceURI;
   1.106 +
   1.107 +  if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
   1.108 +    // No cx means that there's no JS running, or at least no JS that
   1.109 +    // was run through code that properly pushed a context onto the
   1.110 +    // context stack (as all code that runs JS off of web pages
   1.111 +    // does). We won't bother with security checks in this case, but
   1.112 +    // we need to create the loadinfo etc.
   1.113 +
   1.114 +    // Get security manager.
   1.115 +    nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   1.116 +    NS_ENSURE_STATE(ssm);
   1.117 +
   1.118 +    // Check to see if URI is allowed.
   1.119 +    nsresult rv = ssm->CheckLoadURIFromScript(cx, aURI);
   1.120 +    NS_ENSURE_SUCCESS(rv, rv);
   1.121 +
   1.122 +    // Make the load's referrer reflect changes to the document's URI caused by
   1.123 +    // push/replaceState, if possible.  First, get the document corresponding to
   1.124 +    // fp.  If the document's original URI (i.e. its URI before
   1.125 +    // push/replaceState) matches the principal's URI, use the document's
   1.126 +    // current URI as the referrer.  If they don't match, use the principal's
   1.127 +    // URI.
   1.128 +
   1.129 +    nsCOMPtr<nsIDocument> doc;
   1.130 +    nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI, principalURI;
   1.131 +    nsCOMPtr<nsPIDOMWindow> incumbent =
   1.132 +      do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
   1.133 +    if (incumbent) {
   1.134 +      doc = incumbent->GetDoc();
   1.135 +    }
   1.136 +    if (doc) {
   1.137 +      docOriginalURI = doc->GetOriginalURI();
   1.138 +      docCurrentURI = doc->GetDocumentURI();
   1.139 +      rv = doc->NodePrincipal()->GetURI(getter_AddRefs(principalURI));
   1.140 +      NS_ENSURE_SUCCESS(rv, rv);
   1.141 +    }
   1.142 +
   1.143 +    bool urisEqual = false;
   1.144 +    if (docOriginalURI && docCurrentURI && principalURI) {
   1.145 +      principalURI->Equals(docOriginalURI, &urisEqual);
   1.146 +    }
   1.147 +
   1.148 +    if (urisEqual) {
   1.149 +      sourceURI = docCurrentURI;
   1.150 +    }
   1.151 +    else {
   1.152 +      // Use principalURI as long as it is not an nsNullPrincipalURI.
   1.153 +      // We could add a method such as GetReferrerURI to principals to make this
   1.154 +      // cleaner, but given that we need to start using Source Browsing Context
   1.155 +      // for referrer (see Bug 960639) this may be wasted effort at this stage.
   1.156 +      if (principalURI) {
   1.157 +        bool isNullPrincipalScheme;
   1.158 +        rv = principalURI->SchemeIs(NS_NULLPRINCIPAL_SCHEME,
   1.159 +                                    &isNullPrincipalScheme);
   1.160 +        if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
   1.161 +          sourceURI = principalURI;
   1.162 +        }
   1.163 +      }
   1.164 +    }
   1.165 +
   1.166 +    owner = do_QueryInterface(ssm->GetCxSubjectPrincipal(cx));
   1.167 +  }
   1.168 +
   1.169 +  // Create load info
   1.170 +  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   1.171 +  docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   1.172 +  NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
   1.173 +
   1.174 +  loadInfo->SetOwner(owner);
   1.175 +
   1.176 +  if (sourceURI) {
   1.177 +    loadInfo->SetReferrer(sourceURI);
   1.178 +  }
   1.179 +
   1.180 +  loadInfo.swap(*aLoadInfo);
   1.181 +
   1.182 +  return NS_OK;
   1.183 +}
   1.184 +
   1.185 +nsresult
   1.186 +nsLocation::GetURI(nsIURI** aURI, bool aGetInnermostURI)
   1.187 +{
   1.188 +  *aURI = nullptr;
   1.189 +
   1.190 +  nsresult rv;
   1.191 +  nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   1.192 +  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell, &rv));
   1.193 +  if (NS_FAILED(rv)) {
   1.194 +    return rv;
   1.195 +  }
   1.196 +
   1.197 +  nsCOMPtr<nsIURI> uri;
   1.198 +  rv = webNav->GetCurrentURI(getter_AddRefs(uri));
   1.199 +  NS_ENSURE_SUCCESS(rv, rv);
   1.200 +
   1.201 +  // It is valid for docshell to return a null URI. Don't try to fixup
   1.202 +  // if this happens.
   1.203 +  if (!uri) {
   1.204 +    return NS_OK;
   1.205 +  }
   1.206 +
   1.207 +  if (aGetInnermostURI) {
   1.208 +    nsCOMPtr<nsIJARURI> jarURI(do_QueryInterface(uri));
   1.209 +    while (jarURI) {
   1.210 +      jarURI->GetJARFile(getter_AddRefs(uri));
   1.211 +      jarURI = do_QueryInterface(uri);
   1.212 +    }
   1.213 +  }
   1.214 +
   1.215 +  NS_ASSERTION(uri, "nsJARURI screwed up?");
   1.216 +
   1.217 +  nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
   1.218 +  NS_ENSURE_SUCCESS(rv, rv);
   1.219 +
   1.220 +  return urifixup->CreateExposableURI(uri, aURI);
   1.221 +}
   1.222 +
   1.223 +nsresult
   1.224 +nsLocation::GetWritableURI(nsIURI** aURI)
   1.225 +{
   1.226 +  *aURI = nullptr;
   1.227 +
   1.228 +  nsCOMPtr<nsIURI> uri;
   1.229 +
   1.230 +  nsresult rv = GetURI(getter_AddRefs(uri));
   1.231 +  if (NS_FAILED(rv) || !uri) {
   1.232 +    return rv;
   1.233 +  }
   1.234 +
   1.235 +  return uri->Clone(aURI);
   1.236 +}
   1.237 +
   1.238 +nsresult
   1.239 +nsLocation::SetURI(nsIURI* aURI, bool aReplace)
   1.240 +{
   1.241 +  nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   1.242 +  if (docShell) {
   1.243 +    nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   1.244 +    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
   1.245 +
   1.246 +    if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
   1.247 +      return NS_ERROR_FAILURE;
   1.248 +
   1.249 +    if (aReplace) {
   1.250 +      loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
   1.251 +    } else {
   1.252 +      loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
   1.253 +    }
   1.254 +
   1.255 +    // Get the incumbent script's browsing context to set as source.
   1.256 +    nsCOMPtr<nsPIDOMWindow> sourceWindow =
   1.257 +      do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
   1.258 +    if (sourceWindow) {
   1.259 +      loadInfo->SetSourceDocShell(sourceWindow->GetDocShell());
   1.260 +    }
   1.261 +
   1.262 +    return docShell->LoadURI(aURI, loadInfo,
   1.263 +                             nsIWebNavigation::LOAD_FLAGS_NONE, true);
   1.264 +  }
   1.265 +
   1.266 +  return NS_OK;
   1.267 +}
   1.268 +
   1.269 +NS_IMETHODIMP
   1.270 +nsLocation::GetHash(nsAString& aHash)
   1.271 +{
   1.272 +  if (!CallerSubsumes())
   1.273 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.274 +
   1.275 +  aHash.SetLength(0);
   1.276 +
   1.277 +  nsCOMPtr<nsIURI> uri;
   1.278 +  nsresult rv = GetURI(getter_AddRefs(uri));
   1.279 +  if (NS_FAILED(rv) || !uri) {
   1.280 +    return rv;
   1.281 +  }
   1.282 +
   1.283 +  nsAutoCString ref;
   1.284 +  nsAutoString unicodeRef;
   1.285 +
   1.286 +  rv = uri->GetRef(ref);
   1.287 +  if (NS_SUCCEEDED(rv)) {
   1.288 +    nsCOMPtr<nsITextToSubURI> textToSubURI(
   1.289 +        do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
   1.290 +
   1.291 +    if (NS_SUCCEEDED(rv)) {
   1.292 +      nsAutoCString charset;
   1.293 +      uri->GetOriginCharset(charset);
   1.294 +        
   1.295 +      rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
   1.296 +    }
   1.297 +      
   1.298 +    if (NS_FAILED(rv)) {
   1.299 +      // Oh, well.  No intl here!
   1.300 +      NS_UnescapeURL(ref);
   1.301 +      CopyASCIItoUTF16(ref, unicodeRef);
   1.302 +      rv = NS_OK;
   1.303 +    }
   1.304 +  }
   1.305 +
   1.306 +  if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
   1.307 +    aHash.Assign(char16_t('#'));
   1.308 +    aHash.Append(unicodeRef);
   1.309 +  }
   1.310 +
   1.311 +  if (aHash == mCachedHash) {
   1.312 +    // Work around ShareThis stupidly polling location.hash every
   1.313 +    // 5ms all the time by handing out the same exact string buffer
   1.314 +    // we handed out last time.
   1.315 +    aHash = mCachedHash;
   1.316 +  } else {
   1.317 +    mCachedHash = aHash;
   1.318 +  }
   1.319 +
   1.320 +  return rv;
   1.321 +}
   1.322 +
   1.323 +NS_IMETHODIMP
   1.324 +nsLocation::SetHash(const nsAString& aHash)
   1.325 +{
   1.326 +  nsCOMPtr<nsIURI> uri;
   1.327 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.328 +  if (NS_FAILED(rv) || !uri) {
   1.329 +    return rv;
   1.330 +  }
   1.331 +
   1.332 +  NS_ConvertUTF16toUTF8 hash(aHash);
   1.333 +  if (hash.IsEmpty() || hash.First() != char16_t('#')) {
   1.334 +    hash.Insert(char16_t('#'), 0);
   1.335 +  }
   1.336 +  rv = uri->SetRef(hash);
   1.337 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.338 +    return rv;
   1.339 +  }
   1.340 +
   1.341 +  return SetURI(uri);
   1.342 +}
   1.343 +
   1.344 +NS_IMETHODIMP
   1.345 +nsLocation::GetHost(nsAString& aHost)
   1.346 +{
   1.347 +  if (!CallerSubsumes())
   1.348 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.349 +
   1.350 +  aHost.Truncate();
   1.351 +
   1.352 +  nsCOMPtr<nsIURI> uri;
   1.353 +  nsresult result;
   1.354 +
   1.355 +  result = GetURI(getter_AddRefs(uri), true);
   1.356 +
   1.357 +  if (uri) {
   1.358 +    nsAutoCString hostport;
   1.359 +
   1.360 +    result = uri->GetHostPort(hostport);
   1.361 +
   1.362 +    if (NS_SUCCEEDED(result)) {
   1.363 +      AppendUTF8toUTF16(hostport, aHost);
   1.364 +    }
   1.365 +  }
   1.366 +
   1.367 +  return NS_OK;
   1.368 +}
   1.369 +
   1.370 +NS_IMETHODIMP
   1.371 +nsLocation::SetHost(const nsAString& aHost)
   1.372 +{
   1.373 +  if (!CallerSubsumes())
   1.374 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.375 +
   1.376 +  nsCOMPtr<nsIURI> uri;
   1.377 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.378 +  if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   1.379 +    return rv;
   1.380 +  }
   1.381 +
   1.382 +  rv = uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
   1.383 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.384 +    return rv;
   1.385 +  }
   1.386 +
   1.387 +  return SetURI(uri);
   1.388 +}
   1.389 +
   1.390 +NS_IMETHODIMP
   1.391 +nsLocation::GetHostname(nsAString& aHostname)
   1.392 +{
   1.393 +  if (!CallerSubsumes())
   1.394 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.395 +
   1.396 +  aHostname.Truncate();
   1.397 +
   1.398 +  nsCOMPtr<nsIURI> uri;
   1.399 +  nsresult result;
   1.400 +
   1.401 +  result = GetURI(getter_AddRefs(uri), true);
   1.402 +
   1.403 +  if (uri) {
   1.404 +    nsAutoCString host;
   1.405 +
   1.406 +    result = uri->GetHost(host);
   1.407 +
   1.408 +    if (NS_SUCCEEDED(result)) {
   1.409 +      AppendUTF8toUTF16(host, aHostname);
   1.410 +    }
   1.411 +  }
   1.412 +
   1.413 +  return NS_OK;
   1.414 +}
   1.415 +
   1.416 +NS_IMETHODIMP
   1.417 +nsLocation::SetHostname(const nsAString& aHostname)
   1.418 +{
   1.419 +  if (!CallerSubsumes())
   1.420 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.421 +
   1.422 +  nsCOMPtr<nsIURI> uri;
   1.423 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.424 +  if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   1.425 +    return rv;
   1.426 +  }
   1.427 +
   1.428 +  rv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
   1.429 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.430 +    return rv;
   1.431 +  }
   1.432 +
   1.433 +  return SetURI(uri);
   1.434 +}
   1.435 +
   1.436 +NS_IMETHODIMP
   1.437 +nsLocation::GetHref(nsAString& aHref)
   1.438 +{
   1.439 +  if (!CallerSubsumes())
   1.440 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.441 +
   1.442 +  aHref.Truncate();
   1.443 +
   1.444 +  nsCOMPtr<nsIURI> uri;
   1.445 +  nsresult result;
   1.446 +
   1.447 +  result = GetURI(getter_AddRefs(uri));
   1.448 +
   1.449 +  if (uri) {
   1.450 +    nsAutoCString uriString;
   1.451 +
   1.452 +    result = uri->GetSpec(uriString);
   1.453 +
   1.454 +    if (NS_SUCCEEDED(result)) {
   1.455 +      AppendUTF8toUTF16(uriString, aHref);
   1.456 +    }
   1.457 +  }
   1.458 +
   1.459 +  return result;
   1.460 +}
   1.461 +
   1.462 +NS_IMETHODIMP
   1.463 +nsLocation::SetHref(const nsAString& aHref)
   1.464 +{
   1.465 +  nsAutoString oldHref;
   1.466 +  nsresult rv = NS_OK;
   1.467 +
   1.468 +  JSContext *cx = nsContentUtils::GetCurrentJSContext();
   1.469 +  if (cx) {
   1.470 +    rv = SetHrefWithContext(cx, aHref, false);
   1.471 +  } else {
   1.472 +    rv = GetHref(oldHref);
   1.473 +
   1.474 +    if (NS_SUCCEEDED(rv)) {
   1.475 +      nsCOMPtr<nsIURI> oldUri;
   1.476 +
   1.477 +      rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
   1.478 +
   1.479 +      if (oldUri) {
   1.480 +        rv = SetHrefWithBase(aHref, oldUri, false);
   1.481 +      }
   1.482 +    }
   1.483 +  }
   1.484 +
   1.485 +  return rv;
   1.486 +}
   1.487 +
   1.488 +nsresult
   1.489 +nsLocation::SetHrefWithContext(JSContext* cx, const nsAString& aHref,
   1.490 +                               bool aReplace)
   1.491 +{
   1.492 +  nsCOMPtr<nsIURI> base;
   1.493 +
   1.494 +  // Get the source of the caller
   1.495 +  nsresult result = GetSourceBaseURL(cx, getter_AddRefs(base));
   1.496 +
   1.497 +  if (NS_FAILED(result)) {
   1.498 +    return result;
   1.499 +  }
   1.500 +
   1.501 +  return SetHrefWithBase(aHref, base, aReplace);
   1.502 +}
   1.503 +
   1.504 +nsresult
   1.505 +nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
   1.506 +                            bool aReplace)
   1.507 +{
   1.508 +  nsresult result;
   1.509 +  nsCOMPtr<nsIURI> newUri;
   1.510 +
   1.511 +  nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   1.512 +
   1.513 +  nsAutoCString docCharset;
   1.514 +  if (NS_SUCCEEDED(GetDocumentCharacterSetForURI(aHref, docCharset)))
   1.515 +    result = NS_NewURI(getter_AddRefs(newUri), aHref, docCharset.get(), aBase);
   1.516 +  else
   1.517 +    result = NS_NewURI(getter_AddRefs(newUri), aHref, nullptr, aBase);
   1.518 +
   1.519 +  if (newUri) {
   1.520 +    /* Check with the scriptContext if it is currently processing a script tag.
   1.521 +     * If so, this must be a <script> tag with a location.href in it.
   1.522 +     * we want to do a replace load, in such a situation. 
   1.523 +     * In other cases, for example if a event handler or a JS timer
   1.524 +     * had a location.href in it, we want to do a normal load,
   1.525 +     * so that the new url will be appended to Session History.
   1.526 +     * This solution is tricky. Hopefully it isn't going to bite
   1.527 +     * anywhere else. This is part of solution for bug # 39938, 72197
   1.528 +     * 
   1.529 +     */
   1.530 +    bool inScriptTag=false;
   1.531 +    JSContext *cx = nsContentUtils::GetCurrentJSContext();
   1.532 +    if (cx) {
   1.533 +      nsIScriptContext *scriptContext =
   1.534 +        nsJSUtils::GetDynamicScriptContext(cx);
   1.535 +
   1.536 +      if (scriptContext) {
   1.537 +        if (scriptContext->GetProcessingScriptTag()) {
   1.538 +          // Now check to make sure that the script is running in our window,
   1.539 +          // since we only want to replace if the location is set by a
   1.540 +          // <script> tag in the same window.  See bug 178729.
   1.541 +          nsCOMPtr<nsIScriptGlobalObject> ourGlobal(do_GetInterface(docShell));
   1.542 +          inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
   1.543 +        }
   1.544 +      }  
   1.545 +    } //cx
   1.546 +
   1.547 +    return SetURI(newUri, aReplace || inScriptTag);
   1.548 +  }
   1.549 +
   1.550 +  return result;
   1.551 +}
   1.552 +
   1.553 +NS_IMETHODIMP
   1.554 +nsLocation::GetOrigin(nsAString& aOrigin)
   1.555 +{
   1.556 +  if (!CallerSubsumes())
   1.557 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.558 +
   1.559 +  aOrigin.Truncate();
   1.560 +
   1.561 +  nsCOMPtr<nsIURI> uri;
   1.562 +  nsresult rv = GetURI(getter_AddRefs(uri), true);
   1.563 +  NS_ENSURE_SUCCESS(rv, rv);
   1.564 +  NS_ENSURE_TRUE(uri, NS_OK);
   1.565 +
   1.566 +  nsAutoString origin;
   1.567 +  rv = nsContentUtils::GetUTFOrigin(uri, origin);
   1.568 +  NS_ENSURE_SUCCESS(rv, rv);
   1.569 +
   1.570 +  aOrigin = origin;
   1.571 +  return NS_OK;
   1.572 +}
   1.573 +
   1.574 +NS_IMETHODIMP
   1.575 +nsLocation::GetPathname(nsAString& aPathname)
   1.576 +{
   1.577 +  if (!CallerSubsumes())
   1.578 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.579 +
   1.580 +  aPathname.Truncate();
   1.581 +
   1.582 +  nsCOMPtr<nsIURI> uri;
   1.583 +  nsresult result = NS_OK;
   1.584 +
   1.585 +  result = GetURI(getter_AddRefs(uri));
   1.586 +
   1.587 +  nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   1.588 +  if (url) {
   1.589 +    nsAutoCString file;
   1.590 +
   1.591 +    result = url->GetFilePath(file);
   1.592 +
   1.593 +    if (NS_SUCCEEDED(result)) {
   1.594 +      AppendUTF8toUTF16(file, aPathname);
   1.595 +    }
   1.596 +  }
   1.597 +
   1.598 +  return result;
   1.599 +}
   1.600 +
   1.601 +NS_IMETHODIMP
   1.602 +nsLocation::SetPathname(const nsAString& aPathname)
   1.603 +{
   1.604 +  if (!CallerSubsumes())
   1.605 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.606 +
   1.607 +  nsCOMPtr<nsIURI> uri;
   1.608 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.609 +  if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   1.610 +    return rv;
   1.611 +  }
   1.612 +
   1.613 +  rv = uri->SetPath(NS_ConvertUTF16toUTF8(aPathname));
   1.614 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.615 +    return rv;
   1.616 +  }
   1.617 +
   1.618 +  return SetURI(uri);
   1.619 +}
   1.620 +
   1.621 +NS_IMETHODIMP
   1.622 +nsLocation::GetPort(nsAString& aPort)
   1.623 +{
   1.624 +  if (!CallerSubsumes())
   1.625 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.626 +
   1.627 +  aPort.SetLength(0);
   1.628 +
   1.629 +  nsCOMPtr<nsIURI> uri;
   1.630 +  nsresult result = NS_OK;
   1.631 +
   1.632 +  result = GetURI(getter_AddRefs(uri), true);
   1.633 +
   1.634 +  if (uri) {
   1.635 +    int32_t port;
   1.636 +    result = uri->GetPort(&port);
   1.637 +
   1.638 +    if (NS_SUCCEEDED(result) && -1 != port) {
   1.639 +      nsAutoString portStr;
   1.640 +      portStr.AppendInt(port);
   1.641 +      aPort.Append(portStr);
   1.642 +    }
   1.643 +
   1.644 +    // Don't propagate this exception to caller
   1.645 +    result = NS_OK;
   1.646 +  }
   1.647 +
   1.648 +  return result;
   1.649 +}
   1.650 +
   1.651 +NS_IMETHODIMP
   1.652 +nsLocation::SetPort(const nsAString& aPort)
   1.653 +{
   1.654 +  if (!CallerSubsumes())
   1.655 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.656 +
   1.657 +  nsCOMPtr<nsIURI> uri;
   1.658 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.659 +  if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   1.660 +    return rv;
   1.661 +  }
   1.662 +
   1.663 +  // perhaps use nsReadingIterators at some point?
   1.664 +  NS_ConvertUTF16toUTF8 portStr(aPort);
   1.665 +  const char *buf = portStr.get();
   1.666 +  int32_t port = -1;
   1.667 +
   1.668 +  if (!portStr.IsEmpty() && buf) {
   1.669 +    if (*buf == ':') {
   1.670 +      port = atol(buf+1);
   1.671 +    }
   1.672 +    else {
   1.673 +      port = atol(buf);
   1.674 +    }
   1.675 +  }
   1.676 +
   1.677 +  rv = uri->SetPort(port);
   1.678 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.679 +    return rv;
   1.680 +  }
   1.681 +
   1.682 +  return SetURI(uri);
   1.683 +}
   1.684 +
   1.685 +NS_IMETHODIMP
   1.686 +nsLocation::GetProtocol(nsAString& aProtocol)
   1.687 +{
   1.688 +  if (!CallerSubsumes())
   1.689 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.690 +
   1.691 +  aProtocol.SetLength(0);
   1.692 +
   1.693 +  nsCOMPtr<nsIURI> uri;
   1.694 +  nsresult result = NS_OK;
   1.695 +
   1.696 +  result = GetURI(getter_AddRefs(uri));
   1.697 +
   1.698 +  if (uri) {
   1.699 +    nsAutoCString protocol;
   1.700 +
   1.701 +    result = uri->GetScheme(protocol);
   1.702 +
   1.703 +    if (NS_SUCCEEDED(result)) {
   1.704 +      CopyASCIItoUTF16(protocol, aProtocol);
   1.705 +      aProtocol.Append(char16_t(':'));
   1.706 +    }
   1.707 +  }
   1.708 +
   1.709 +  return result;
   1.710 +}
   1.711 +
   1.712 +NS_IMETHODIMP
   1.713 +nsLocation::SetProtocol(const nsAString& aProtocol)
   1.714 +{
   1.715 +  if (!CallerSubsumes())
   1.716 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.717 +
   1.718 +  nsCOMPtr<nsIURI> uri;
   1.719 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.720 +  if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
   1.721 +    return rv;
   1.722 +  }
   1.723 +
   1.724 +  rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol));
   1.725 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.726 +    return rv;
   1.727 +  }
   1.728 +
   1.729 +  return SetURI(uri);
   1.730 +}
   1.731 +
   1.732 +NS_IMETHODIMP
   1.733 +nsLocation::GetSearch(nsAString& aSearch)
   1.734 +{
   1.735 +  if (!CallerSubsumes())
   1.736 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.737 +
   1.738 +  aSearch.SetLength(0);
   1.739 +
   1.740 +  nsCOMPtr<nsIURI> uri;
   1.741 +  nsresult result = NS_OK;
   1.742 +
   1.743 +  result = GetURI(getter_AddRefs(uri));
   1.744 +
   1.745 +  nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   1.746 +
   1.747 +  if (url) {
   1.748 +    nsAutoCString search;
   1.749 +
   1.750 +    result = url->GetQuery(search);
   1.751 +
   1.752 +    if (NS_SUCCEEDED(result) && !search.IsEmpty()) {
   1.753 +      aSearch.Assign(char16_t('?'));
   1.754 +      AppendUTF8toUTF16(search, aSearch);
   1.755 +    }
   1.756 +  }
   1.757 +
   1.758 +  return NS_OK;
   1.759 +}
   1.760 +
   1.761 +NS_IMETHODIMP
   1.762 +nsLocation::SetSearch(const nsAString& aSearch)
   1.763 +{
   1.764 +  if (!CallerSubsumes())
   1.765 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.766 +
   1.767 +  nsCOMPtr<nsIURI> uri;
   1.768 +  nsresult rv = GetWritableURI(getter_AddRefs(uri));
   1.769 +
   1.770 +  nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   1.771 +  if (NS_WARN_IF(NS_FAILED(rv) || !url)) {
   1.772 +    return rv;
   1.773 +  }
   1.774 +
   1.775 +  rv = url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
   1.776 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.777 +    return rv;
   1.778 +  }
   1.779 +
   1.780 +  return SetURI(uri);
   1.781 +}
   1.782 +
   1.783 +NS_IMETHODIMP
   1.784 +nsLocation::Reload(bool aForceget)
   1.785 +{
   1.786 +  if (!CallerSubsumes())
   1.787 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.788 +
   1.789 +  nsresult rv;
   1.790 +  nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   1.791 +  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
   1.792 +  nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(docShell));
   1.793 +
   1.794 +  if (window && window->IsHandlingResizeEvent()) {
   1.795 +    // location.reload() was called on a window that is handling a
   1.796 +    // resize event. Sites do this since Netscape 4.x needed it, but
   1.797 +    // we don't, and it's a horrible experience for nothing. In stead
   1.798 +    // of reloading the page, just clear style data and reflow the
   1.799 +    // page since some sites may use this trick to work around gecko
   1.800 +    // reflow bugs, and this should have the same effect.
   1.801 +
   1.802 +    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   1.803 +
   1.804 +    nsIPresShell *shell;
   1.805 +    nsPresContext *pcx;
   1.806 +    if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
   1.807 +      pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
   1.808 +    }
   1.809 +
   1.810 +    return NS_OK;
   1.811 +  }
   1.812 +
   1.813 +  if (webNav) {
   1.814 +    uint32_t reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
   1.815 +
   1.816 +    if (aForceget) {
   1.817 +      reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | 
   1.818 +                    nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
   1.819 +    }
   1.820 +    rv = webNav->Reload(reloadFlags);
   1.821 +    if (rv == NS_BINDING_ABORTED) {
   1.822 +      // This happens when we attempt to reload a POST result and the user says
   1.823 +      // no at the "do you want to reload?" prompt.  Don't propagate this one
   1.824 +      // back to callers.
   1.825 +      rv = NS_OK;
   1.826 +    }
   1.827 +  } else {
   1.828 +    rv = NS_ERROR_FAILURE;
   1.829 +  }
   1.830 +
   1.831 +  return rv;
   1.832 +}
   1.833 +
   1.834 +NS_IMETHODIMP
   1.835 +nsLocation::Replace(const nsAString& aUrl)
   1.836 +{
   1.837 +  nsresult rv = NS_OK;
   1.838 +  if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
   1.839 +    return SetHrefWithContext(cx, aUrl, true);
   1.840 +  }
   1.841 +
   1.842 +  nsAutoString oldHref;
   1.843 +
   1.844 +  rv = GetHref(oldHref);
   1.845 +  NS_ENSURE_SUCCESS(rv, rv);
   1.846 +
   1.847 +  nsCOMPtr<nsIURI> oldUri;
   1.848 +
   1.849 +  rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
   1.850 +  NS_ENSURE_SUCCESS(rv, rv);
   1.851 +
   1.852 +  return SetHrefWithBase(aUrl, oldUri, true);
   1.853 +}
   1.854 +
   1.855 +NS_IMETHODIMP
   1.856 +nsLocation::Assign(const nsAString& aUrl)
   1.857 +{
   1.858 +  if (!CallerSubsumes())
   1.859 +    return NS_ERROR_DOM_SECURITY_ERR;
   1.860 +
   1.861 +  nsAutoString oldHref;
   1.862 +  nsresult result = NS_OK;
   1.863 +
   1.864 +  result = GetHref(oldHref);
   1.865 +
   1.866 +  if (NS_SUCCEEDED(result)) {
   1.867 +    nsCOMPtr<nsIURI> oldUri;
   1.868 +
   1.869 +    result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
   1.870 +
   1.871 +    if (oldUri) {
   1.872 +      result = SetHrefWithBase(aUrl, oldUri, false);
   1.873 +    }
   1.874 +  }
   1.875 +
   1.876 +  return result;
   1.877 +}
   1.878 +
   1.879 +NS_IMETHODIMP
   1.880 +nsLocation::ToString(nsAString& aReturn)
   1.881 +{
   1.882 +  // NB: GetHref checks CallerSubsumes().
   1.883 +  return GetHref(aReturn);
   1.884 +}
   1.885 +
   1.886 +NS_IMETHODIMP
   1.887 +nsLocation::ValueOf(nsIDOMLocation** aReturn)
   1.888 +{
   1.889 +  nsCOMPtr<nsIDOMLocation> loc(this);
   1.890 +  loc.forget(aReturn);
   1.891 +  return NS_OK;
   1.892 +}
   1.893 +
   1.894 +nsresult
   1.895 +nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
   1.896 +{
   1.897 +
   1.898 +  *sourceURL = nullptr;
   1.899 +  nsCOMPtr<nsIScriptGlobalObject> sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
   1.900 +  // If this JS context doesn't have an associated DOM window, we effectively
   1.901 +  // have no script entry point stack. This doesn't generally happen with the DOM,
   1.902 +  // but can sometimes happen with extension code in certain IPC configurations.
   1.903 +  // If this happens, try falling back on the current document associated with
   1.904 +  // the docshell. If that fails, just return null and hope that the caller passed
   1.905 +  // an absolute URI.
   1.906 +  if (!sgo && GetDocShell()) {
   1.907 +    sgo = do_GetInterface(GetDocShell());
   1.908 +  }
   1.909 +  NS_ENSURE_TRUE(sgo, NS_OK);
   1.910 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
   1.911 +  NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
   1.912 +  nsIDocument* doc = window->GetDoc();
   1.913 +  NS_ENSURE_TRUE(doc, NS_OK);
   1.914 +  *sourceURL = doc->GetBaseURI().take();
   1.915 +  return NS_OK;
   1.916 +}
   1.917 +
   1.918 +bool
   1.919 +nsLocation::CallerSubsumes()
   1.920 +{
   1.921 +  // Get the principal associated with the location object.
   1.922 +  nsCOMPtr<nsIDOMWindow> outer = do_QueryReferent(mOuter);
   1.923 +  if (MOZ_UNLIKELY(!outer))
   1.924 +    return false;
   1.925 +  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(outer);
   1.926 +  bool subsumes = false;
   1.927 +  nsresult rv = nsContentUtils::GetSubjectPrincipal()->SubsumesConsideringDomain(sop->GetPrincipal(), &subsumes);
   1.928 +  NS_ENSURE_SUCCESS(rv, false);
   1.929 +  return subsumes;
   1.930 +}

mercurial