1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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 "Location.h"
8 #include "nsIScriptObjectPrincipal.h"
9 #include "nsIScriptContext.h"
10 #include "nsDocShellLoadState.h"
11 #include "nsIWebNavigation.h"
12 #include "nsIOService.h"
13 #include "nsIURL.h"
14 #include "nsIJARURI.h"
15 #include "nsIURIMutator.h"
16 #include "nsNetUtil.h"
17 #include "nsCOMPtr.h"
18 #include "nsEscape.h"
19 #include "nsPresContext.h"
20 #include "nsError.h"
21 #include "nsReadableUtils.h"
22 #include "nsJSUtils.h"
23 #include "nsContentUtils.h"
24 #include "nsDocShell.h"
25 #include "nsGlobalWindow.h"
26 #include "mozilla/Likely.h"
27 #include "nsCycleCollectionParticipant.h"
28 #include "mozilla/Components.h"
29 #include "mozilla/NullPrincipal.h"
30 #include "mozilla/Unused.h"
31 #include "mozilla/dom/Document.h"
32 #include "mozilla/dom/DocumentInlines.h"
33 #include "mozilla/dom/LocationBinding.h"
34 #include "mozilla/dom/ScriptSettings.h"
35 #include "ReferrerInfo.h"
36 
37 namespace mozilla {
38 namespace dom {
39 
Location(nsPIDOMWindowInner * aWindow,BrowsingContext * aBrowsingContext)40 Location::Location(nsPIDOMWindowInner* aWindow,
41                    BrowsingContext* aBrowsingContext)
42     : mInnerWindow(aWindow) {
43   // aBrowsingContext can be null if it gets called after nsDocShell::Destory().
44   if (aBrowsingContext) {
45     mBrowsingContextId = aBrowsingContext->Id();
46   }
47 }
48 
49 Location::~Location() = default;
50 
51 // QueryInterface implementation for Location
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Location)52 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Location)
53   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
54   NS_INTERFACE_MAP_ENTRY(nsISupports)
55 NS_INTERFACE_MAP_END
56 
57 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Location, mInnerWindow)
58 
59 NS_IMPL_CYCLE_COLLECTING_ADDREF(Location)
60 NS_IMPL_CYCLE_COLLECTING_RELEASE(Location)
61 
62 BrowsingContext* Location::GetBrowsingContext() {
63   RefPtr<BrowsingContext> bc = BrowsingContext::Get(mBrowsingContextId);
64   return bc.get();
65 }
66 
GetDocShell()67 already_AddRefed<nsIDocShell> Location::GetDocShell() {
68   if (RefPtr<BrowsingContext> bc = GetBrowsingContext()) {
69     return do_AddRef(bc->GetDocShell());
70   }
71   return nullptr;
72 }
73 
GetURI(nsIURI ** aURI,bool aGetInnermostURI)74 nsresult Location::GetURI(nsIURI** aURI, bool aGetInnermostURI) {
75   *aURI = nullptr;
76 
77   nsCOMPtr<nsIDocShell> docShell(GetDocShell());
78   if (!docShell) {
79     return NS_OK;
80   }
81 
82   nsresult rv;
83   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell, &rv));
84   if (NS_FAILED(rv)) {
85     return rv;
86   }
87 
88   nsCOMPtr<nsIURI> uri;
89   rv = webNav->GetCurrentURI(getter_AddRefs(uri));
90   NS_ENSURE_SUCCESS(rv, rv);
91 
92   // It is valid for docshell to return a null URI. Don't try to fixup
93   // if this happens.
94   if (!uri) {
95     return NS_OK;
96   }
97 
98   if (aGetInnermostURI) {
99     nsCOMPtr<nsIJARURI> jarURI(do_QueryInterface(uri));
100     while (jarURI) {
101       jarURI->GetJARFile(getter_AddRefs(uri));
102       jarURI = do_QueryInterface(uri);
103     }
104   }
105 
106   NS_ASSERTION(uri, "nsJARURI screwed up?");
107   nsCOMPtr<nsIURI> exposableURI = net::nsIOService::CreateExposableURI(uri);
108   exposableURI.forget(aURI);
109   return NS_OK;
110 }
111 
GetHash(nsAString & aHash,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)112 void Location::GetHash(nsAString& aHash, nsIPrincipal& aSubjectPrincipal,
113                        ErrorResult& aRv) {
114   if (!CallerSubsumes(&aSubjectPrincipal)) {
115     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
116     return;
117   }
118 
119   aHash.SetLength(0);
120 
121   nsCOMPtr<nsIURI> uri;
122   aRv = GetURI(getter_AddRefs(uri));
123   if (NS_WARN_IF(aRv.Failed()) || !uri) {
124     return;
125   }
126 
127   nsAutoCString ref;
128   nsAutoString unicodeRef;
129 
130   aRv = uri->GetRef(ref);
131   if (NS_WARN_IF(aRv.Failed())) {
132     return;
133   }
134 
135   if (!ref.IsEmpty()) {
136     aHash.Assign(char16_t('#'));
137     AppendUTF8toUTF16(ref, aHash);
138   }
139 
140   if (aHash == mCachedHash) {
141     // Work around ShareThis stupidly polling location.hash every
142     // 5ms all the time by handing out the same exact string buffer
143     // we handed out last time.
144     aHash = mCachedHash;
145   } else {
146     mCachedHash = aHash;
147   }
148 }
149 
SetHash(const nsAString & aHash,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)150 void Location::SetHash(const nsAString& aHash, nsIPrincipal& aSubjectPrincipal,
151                        ErrorResult& aRv) {
152   if (!CallerSubsumes(&aSubjectPrincipal)) {
153     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
154     return;
155   }
156 
157   NS_ConvertUTF16toUTF8 hash(aHash);
158   if (hash.IsEmpty() || hash.First() != char16_t('#')) {
159     hash.Insert(char16_t('#'), 0);
160   }
161 
162   nsCOMPtr<nsIURI> uri;
163   aRv = GetURI(getter_AddRefs(uri));
164   if (NS_WARN_IF(aRv.Failed()) || !uri) {
165     return;
166   }
167 
168   aRv = NS_MutateURI(uri).SetRef(hash).Finalize(uri);
169   if (NS_WARN_IF(aRv.Failed()) || !uri) {
170     return;
171   }
172 
173   SetURI(uri, aSubjectPrincipal, aRv);
174 }
175 
GetHost(nsAString & aHost,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)176 void Location::GetHost(nsAString& aHost, nsIPrincipal& aSubjectPrincipal,
177                        ErrorResult& aRv) {
178   if (!CallerSubsumes(&aSubjectPrincipal)) {
179     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
180     return;
181   }
182 
183   aHost.Truncate();
184 
185   nsCOMPtr<nsIURI> uri;
186   nsresult result;
187 
188   result = GetURI(getter_AddRefs(uri), true);
189 
190   if (uri) {
191     nsAutoCString hostport;
192 
193     result = uri->GetHostPort(hostport);
194 
195     if (NS_SUCCEEDED(result)) {
196       AppendUTF8toUTF16(hostport, aHost);
197     }
198   }
199 }
200 
SetHost(const nsAString & aHost,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)201 void Location::SetHost(const nsAString& aHost, nsIPrincipal& aSubjectPrincipal,
202                        ErrorResult& aRv) {
203   if (!CallerSubsumes(&aSubjectPrincipal)) {
204     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
205     return;
206   }
207 
208   nsCOMPtr<nsIURI> uri;
209   aRv = GetURI(getter_AddRefs(uri));
210   if (NS_WARN_IF(aRv.Failed()) || !uri) {
211     return;
212   }
213 
214   aRv =
215       NS_MutateURI(uri).SetHostPort(NS_ConvertUTF16toUTF8(aHost)).Finalize(uri);
216   if (NS_WARN_IF(aRv.Failed())) {
217     return;
218   }
219 
220   SetURI(uri, aSubjectPrincipal, aRv);
221 }
222 
GetHostname(nsAString & aHostname,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)223 void Location::GetHostname(nsAString& aHostname,
224                            nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
225   if (!CallerSubsumes(&aSubjectPrincipal)) {
226     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
227     return;
228   }
229 
230   aHostname.Truncate();
231 
232   nsCOMPtr<nsIURI> uri;
233   GetURI(getter_AddRefs(uri), true);
234   if (uri) {
235     nsContentUtils::GetHostOrIPv6WithBrackets(uri, aHostname);
236   }
237 }
238 
SetHostname(const nsAString & aHostname,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)239 void Location::SetHostname(const nsAString& aHostname,
240                            nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
241   if (!CallerSubsumes(&aSubjectPrincipal)) {
242     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
243     return;
244   }
245 
246   nsCOMPtr<nsIURI> uri;
247   aRv = GetURI(getter_AddRefs(uri));
248   if (NS_WARN_IF(aRv.Failed()) || !uri) {
249     return;
250   }
251 
252   aRv =
253       NS_MutateURI(uri).SetHost(NS_ConvertUTF16toUTF8(aHostname)).Finalize(uri);
254   if (NS_WARN_IF(aRv.Failed())) {
255     return;
256   }
257 
258   SetURI(uri, aSubjectPrincipal, aRv);
259 }
260 
GetHref(nsAString & aHref)261 nsresult Location::GetHref(nsAString& aHref) {
262   aHref.Truncate();
263 
264   nsCOMPtr<nsIURI> uri;
265   nsresult rv = GetURI(getter_AddRefs(uri));
266   if (NS_WARN_IF(NS_FAILED(rv)) || !uri) {
267     return rv;
268   }
269 
270   nsAutoCString uriString;
271   rv = uri->GetSpec(uriString);
272   if (NS_WARN_IF(NS_FAILED(rv))) {
273     return rv;
274   }
275 
276   AppendUTF8toUTF16(uriString, aHref);
277   return NS_OK;
278 }
279 
GetOrigin(nsAString & aOrigin,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)280 void Location::GetOrigin(nsAString& aOrigin, nsIPrincipal& aSubjectPrincipal,
281                          ErrorResult& aRv) {
282   if (!CallerSubsumes(&aSubjectPrincipal)) {
283     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
284     return;
285   }
286 
287   aOrigin.Truncate();
288 
289   nsCOMPtr<nsIURI> uri;
290   aRv = GetURI(getter_AddRefs(uri), true);
291   if (NS_WARN_IF(aRv.Failed()) || !uri) {
292     return;
293   }
294 
295   nsAutoString origin;
296   aRv = nsContentUtils::GetUTFOrigin(uri, origin);
297   if (NS_WARN_IF(aRv.Failed())) {
298     return;
299   }
300 
301   aOrigin = origin;
302 }
303 
GetPathname(nsAString & aPathname,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)304 void Location::GetPathname(nsAString& aPathname,
305                            nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
306   if (!CallerSubsumes(&aSubjectPrincipal)) {
307     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
308     return;
309   }
310 
311   aPathname.Truncate();
312 
313   nsCOMPtr<nsIURI> uri;
314   aRv = GetURI(getter_AddRefs(uri));
315   if (NS_WARN_IF(aRv.Failed()) || !uri) {
316     return;
317   }
318 
319   nsAutoCString file;
320 
321   aRv = uri->GetFilePath(file);
322   if (NS_WARN_IF(aRv.Failed())) {
323     return;
324   }
325 
326   AppendUTF8toUTF16(file, aPathname);
327 }
328 
SetPathname(const nsAString & aPathname,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)329 void Location::SetPathname(const nsAString& aPathname,
330                            nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
331   if (!CallerSubsumes(&aSubjectPrincipal)) {
332     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
333     return;
334   }
335 
336   nsCOMPtr<nsIURI> uri;
337   aRv = GetURI(getter_AddRefs(uri));
338   if (NS_WARN_IF(aRv.Failed()) || !uri) {
339     return;
340   }
341 
342   nsresult rv = NS_MutateURI(uri)
343                     .SetFilePath(NS_ConvertUTF16toUTF8(aPathname))
344                     .Finalize(uri);
345   if (NS_FAILED(rv)) {
346     return;
347   }
348 
349   SetURI(uri, aSubjectPrincipal, aRv);
350 }
351 
GetPort(nsAString & aPort,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)352 void Location::GetPort(nsAString& aPort, nsIPrincipal& aSubjectPrincipal,
353                        ErrorResult& aRv) {
354   if (!CallerSubsumes(&aSubjectPrincipal)) {
355     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
356     return;
357   }
358 
359   aPort.SetLength(0);
360 
361   nsCOMPtr<nsIURI> uri;
362   aRv = GetURI(getter_AddRefs(uri), true);
363   if (NS_WARN_IF(aRv.Failed()) || !uri) {
364     return;
365   }
366 
367   int32_t port;
368   nsresult result = uri->GetPort(&port);
369 
370   // Don't propagate this exception to caller
371   if (NS_SUCCEEDED(result) && -1 != port) {
372     nsAutoString portStr;
373     portStr.AppendInt(port);
374     aPort.Append(portStr);
375   }
376 }
377 
SetPort(const nsAString & aPort,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)378 void Location::SetPort(const nsAString& aPort, nsIPrincipal& aSubjectPrincipal,
379                        ErrorResult& aRv) {
380   if (!CallerSubsumes(&aSubjectPrincipal)) {
381     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
382     return;
383   }
384 
385   nsCOMPtr<nsIURI> uri;
386   aRv = GetURI(getter_AddRefs(uri));
387   if (NS_WARN_IF(aRv.Failed() || !uri)) {
388     return;
389   }
390 
391   // perhaps use nsReadingIterators at some point?
392   NS_ConvertUTF16toUTF8 portStr(aPort);
393   const char* buf = portStr.get();
394   int32_t port = -1;
395 
396   if (!portStr.IsEmpty() && buf) {
397     if (*buf == ':') {
398       port = atol(buf + 1);
399     } else {
400       port = atol(buf);
401     }
402   }
403 
404   aRv = NS_MutateURI(uri).SetPort(port).Finalize(uri);
405   if (NS_WARN_IF(aRv.Failed())) {
406     return;
407   }
408 
409   SetURI(uri, aSubjectPrincipal, aRv);
410 }
411 
GetProtocol(nsAString & aProtocol,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)412 void Location::GetProtocol(nsAString& aProtocol,
413                            nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
414   if (!CallerSubsumes(&aSubjectPrincipal)) {
415     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
416     return;
417   }
418 
419   aProtocol.SetLength(0);
420 
421   nsCOMPtr<nsIURI> uri;
422   aRv = GetURI(getter_AddRefs(uri));
423   if (NS_WARN_IF(aRv.Failed()) || !uri) {
424     return;
425   }
426 
427   nsAutoCString protocol;
428 
429   aRv = uri->GetScheme(protocol);
430   if (NS_WARN_IF(aRv.Failed())) {
431     return;
432   }
433 
434   CopyASCIItoUTF16(protocol, aProtocol);
435   aProtocol.Append(char16_t(':'));
436 }
437 
SetProtocol(const nsAString & aProtocol,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)438 void Location::SetProtocol(const nsAString& aProtocol,
439                            nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
440   if (!CallerSubsumes(&aSubjectPrincipal)) {
441     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
442     return;
443   }
444 
445   nsCOMPtr<nsIURI> uri;
446   aRv = GetURI(getter_AddRefs(uri));
447   if (NS_WARN_IF(aRv.Failed()) || !uri) {
448     return;
449   }
450 
451   nsAString::const_iterator start, end;
452   aProtocol.BeginReading(start);
453   aProtocol.EndReading(end);
454   nsAString::const_iterator iter(start);
455   Unused << FindCharInReadable(':', iter, end);
456 
457   nsresult rv = NS_MutateURI(uri)
458                     .SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)))
459                     .Finalize(uri);
460   if (NS_WARN_IF(NS_FAILED(rv))) {
461     // Oh, I wish nsStandardURL returned NS_ERROR_MALFORMED_URI for _all_ the
462     // malformed cases, not just some of them!
463     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
464     return;
465   }
466 
467   nsAutoCString newSpec;
468   aRv = uri->GetSpec(newSpec);
469   if (NS_WARN_IF(aRv.Failed())) {
470     return;
471   }
472   // We may want a new URI class for the new URI, so recreate it:
473   rv = NS_NewURI(getter_AddRefs(uri), newSpec);
474   if (NS_FAILED(rv)) {
475     if (rv == NS_ERROR_MALFORMED_URI) {
476       rv = NS_ERROR_DOM_SYNTAX_ERR;
477     }
478 
479     aRv.Throw(rv);
480     return;
481   }
482 
483   if (!uri->SchemeIs("http") && !uri->SchemeIs("https")) {
484     // No-op, per spec.
485     return;
486   }
487 
488   SetURI(uri, aSubjectPrincipal, aRv);
489 }
490 
GetSearch(nsAString & aSearch,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)491 void Location::GetSearch(nsAString& aSearch, nsIPrincipal& aSubjectPrincipal,
492                          ErrorResult& aRv) {
493   if (!CallerSubsumes(&aSubjectPrincipal)) {
494     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
495     return;
496   }
497 
498   aSearch.SetLength(0);
499 
500   nsCOMPtr<nsIURI> uri;
501   nsresult result = NS_OK;
502 
503   result = GetURI(getter_AddRefs(uri));
504 
505   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
506 
507   if (url) {
508     nsAutoCString search;
509 
510     result = url->GetQuery(search);
511 
512     if (NS_SUCCEEDED(result) && !search.IsEmpty()) {
513       aSearch.Assign(char16_t('?'));
514       AppendUTF8toUTF16(search, aSearch);
515     }
516   }
517 }
518 
SetSearch(const nsAString & aSearch,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)519 void Location::SetSearch(const nsAString& aSearch,
520                          nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
521   if (!CallerSubsumes(&aSubjectPrincipal)) {
522     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
523     return;
524   }
525 
526   nsCOMPtr<nsIURI> uri;
527   aRv = GetURI(getter_AddRefs(uri));
528   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
529   if (NS_WARN_IF(aRv.Failed()) || !url) {
530     return;
531   }
532 
533   if (Document* doc = GetEntryDocument()) {
534     aRv = NS_MutateURI(uri)
535               .SetQueryWithEncoding(NS_ConvertUTF16toUTF8(aSearch),
536                                     doc->GetDocumentCharacterSet())
537               .Finalize(uri);
538   } else {
539     aRv = NS_MutateURI(uri)
540               .SetQuery(NS_ConvertUTF16toUTF8(aSearch))
541               .Finalize(uri);
542   }
543   if (NS_WARN_IF(aRv.Failed())) {
544     return;
545   }
546 
547   SetURI(uri, aSubjectPrincipal, aRv);
548 }
549 
Reload(bool aForceget,ErrorResult & aRv)550 void Location::Reload(bool aForceget, ErrorResult& aRv) {
551   nsCOMPtr<nsIDocShell> docShell(GetDocShell());
552   if (!docShell) {
553     return aRv.Throw(NS_ERROR_FAILURE);
554   }
555 
556   if (StaticPrefs::dom_block_reload_from_resize_event_handler()) {
557     nsCOMPtr<nsPIDOMWindowOuter> window = docShell->GetWindow();
558     if (window && window->IsHandlingResizeEvent()) {
559       // location.reload() was called on a window that is handling a
560       // resize event. Sites do this since Netscape 4.x needed it, but
561       // we don't, and it's a horrible experience for nothing. In stead
562       // of reloading the page, just clear style data and reflow the
563       // page since some sites may use this trick to work around gecko
564       // reflow bugs, and this should have the same effect.
565       RefPtr<Document> doc = window->GetExtantDoc();
566 
567       nsPresContext* pcx;
568       if (doc && (pcx = doc->GetPresContext())) {
569         pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW,
570                                  RestyleHint::RestyleSubtree());
571       }
572       return;
573     }
574   }
575 
576   uint32_t reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
577 
578   if (aForceget) {
579     reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE |
580                   nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
581   }
582 
583   nsresult rv = nsDocShell::Cast(docShell)->Reload(reloadFlags);
584   if (NS_FAILED(rv) && rv != NS_BINDING_ABORTED) {
585     // NS_BINDING_ABORTED is returned when we attempt to reload a POST result
586     // and the user says no at the "do you want to reload?" prompt.  Don't
587     // propagate this one back to callers.
588     return aRv.Throw(rv);
589   }
590 }
591 
Assign(const nsAString & aUrl,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)592 void Location::Assign(const nsAString& aUrl, nsIPrincipal& aSubjectPrincipal,
593                       ErrorResult& aRv) {
594   if (!CallerSubsumes(&aSubjectPrincipal)) {
595     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
596     return;
597   }
598 
599   DoSetHref(aUrl, aSubjectPrincipal, false, aRv);
600 }
601 
CallerSubsumes(nsIPrincipal * aSubjectPrincipal)602 bool Location::CallerSubsumes(nsIPrincipal* aSubjectPrincipal) {
603   MOZ_ASSERT(aSubjectPrincipal);
604 
605   RefPtr<BrowsingContext> bc(GetBrowsingContext());
606   if (MOZ_UNLIKELY(!bc) || MOZ_UNLIKELY(bc->IsDiscarded())) {
607     // Per spec, operations on a Location object with a discarded BC are no-ops,
608     // not security errors, so we need to return true from the access check and
609     // let the caller do its own discarded docShell check.
610     return true;
611   }
612   if (MOZ_UNLIKELY(!bc->IsInProcess())) {
613     return false;
614   }
615 
616   // Get the principal associated with the location object.  Note that this is
617   // the principal of the page which will actually be navigated, not the
618   // principal of the Location object itself.  This is why we need this check
619   // even though we only allow limited cross-origin access to Location objects
620   // in general.
621   nsCOMPtr<nsPIDOMWindowOuter> outer = bc->GetDOMWindow();
622   MOZ_DIAGNOSTIC_ASSERT(outer);
623   if (MOZ_UNLIKELY(!outer)) return false;
624 
625   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(outer);
626   bool subsumes = false;
627   nsresult rv = aSubjectPrincipal->SubsumesConsideringDomain(
628       sop->GetPrincipal(), &subsumes);
629   NS_ENSURE_SUCCESS(rv, false);
630   return subsumes;
631 }
632 
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)633 JSObject* Location::WrapObject(JSContext* aCx,
634                                JS::Handle<JSObject*> aGivenProto) {
635   return Location_Binding::Wrap(aCx, this, aGivenProto);
636 }
637 
638 }  // namespace dom
639 }  // namespace mozilla
640