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

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

mercurial