Coverage Report

Created: 2018-09-25 14:53

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