dom/base/nsLocation.cpp

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

mercurial