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 +}