Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/components/extensions/webrequest/ChannelWrapper.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "ChannelWrapper.h"
8
9
#include "jsapi.h"
10
#include "xpcpublic.h"
11
12
#include "mozilla/BasePrincipal.h"
13
#include "mozilla/SystemPrincipal.h"
14
15
#include "NSSErrorsService.h"
16
#include "nsITransportSecurityInfo.h"
17
18
#include "mozilla/AddonManagerWebAPI.h"
19
#include "mozilla/ErrorNames.h"
20
#include "mozilla/ResultExtensions.h"
21
#include "mozilla/Unused.h"
22
#include "mozilla/dom/Element.h"
23
#include "mozilla/dom/Event.h"
24
#include "mozilla/dom/TabParent.h"
25
#include "nsIContentPolicy.h"
26
#include "nsIHttpChannelInternal.h"
27
#include "nsIHttpHeaderVisitor.h"
28
#include "nsIInterfaceRequestor.h"
29
#include "nsIInterfaceRequestorUtils.h"
30
#include "nsILoadContext.h"
31
#include "nsILoadGroup.h"
32
#include "nsIProxiedChannel.h"
33
#include "nsIProxyInfo.h"
34
#include "nsITraceableChannel.h"
35
#include "nsIWritablePropertyBag2.h"
36
#include "nsNetUtil.h"
37
#include "nsProxyRelease.h"
38
#include "nsPrintfCString.h"
39
40
using namespace mozilla::dom;
41
using namespace JS;
42
43
namespace mozilla {
44
namespace extensions {
45
46
0
#define CHANNELWRAPPER_PROP_KEY NS_LITERAL_STRING("ChannelWrapper::CachedInstance")
47
48
/*****************************************************************************
49
 * Initialization
50
 *****************************************************************************/
51
52
/* static */
53
54
already_AddRefed<ChannelWrapper>
55
ChannelWrapper::Get(const GlobalObject& global, nsIChannel* channel)
56
0
{
57
0
  RefPtr<ChannelWrapper> wrapper;
58
0
59
0
  nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
60
0
  if (props) {
61
0
    Unused << props->GetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY,
62
0
                                            NS_GET_IID(ChannelWrapper),
63
0
                                            getter_AddRefs(wrapper));
64
0
65
0
    if (wrapper) {
66
0
      // Assume cached attributes may have changed at this point.
67
0
      wrapper->ClearCachedAttributes();
68
0
    }
69
0
  }
70
0
71
0
  if (!wrapper) {
72
0
    wrapper = new ChannelWrapper(global.GetAsSupports(), channel);
73
0
    if (props) {
74
0
      Unused << props->SetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY,
75
0
                                              wrapper);
76
0
    }
77
0
  }
78
0
79
0
  return wrapper.forget();
80
0
}
81
82
already_AddRefed<ChannelWrapper>
83
ChannelWrapper::GetRegisteredChannel(const GlobalObject& global, uint64_t aChannelId, const WebExtensionPolicy& aAddon, nsITabParent* aTabParent)
84
0
{
85
0
  nsIContentParent* contentParent = nullptr;
86
0
  if (TabParent* parent = static_cast<TabParent*>(aTabParent)) {
87
0
    contentParent = static_cast<nsIContentParent*>(parent->Manager());
88
0
  }
89
0
90
0
  auto& webreq = WebRequestService::GetSingleton();
91
0
92
0
  nsCOMPtr<nsITraceableChannel> channel = webreq.GetTraceableChannel(aChannelId, aAddon.Id(), contentParent);
93
0
  if (!channel) {
94
0
    return nullptr;
95
0
  }
96
0
  nsCOMPtr<nsIChannel> chan(do_QueryInterface(channel));
97
0
  return ChannelWrapper::Get(global, chan);
98
0
}
99
100
void
101
ChannelWrapper::SetChannel(nsIChannel* aChannel)
102
0
{
103
0
  detail::ChannelHolder::SetChannel(aChannel);
104
0
  ClearCachedAttributes();
105
0
  ChannelWrapper_Binding::ClearCachedFinalURIValue(this);
106
0
  ChannelWrapper_Binding::ClearCachedFinalURLValue(this);
107
0
  mFinalURLInfo.reset();
108
0
  ChannelWrapper_Binding::ClearCachedProxyInfoValue(this);
109
0
}
110
111
void
112
ChannelWrapper::ClearCachedAttributes()
113
0
{
114
0
  ChannelWrapper_Binding::ClearCachedRemoteAddressValue(this);
115
0
  ChannelWrapper_Binding::ClearCachedStatusCodeValue(this);
116
0
  ChannelWrapper_Binding::ClearCachedStatusLineValue(this);
117
0
  if (!mFiredErrorEvent) {
118
0
    ChannelWrapper_Binding::ClearCachedErrorStringValue(this);
119
0
  }
120
0
}
121
122
/*****************************************************************************
123
 * ...
124
 *****************************************************************************/
125
126
void
127
ChannelWrapper::Cancel(uint32_t aResult, ErrorResult& aRv)
128
0
{
129
0
  nsresult rv = NS_ERROR_UNEXPECTED;
130
0
  if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
131
0
    rv = chan->Cancel(nsresult(aResult));
132
0
    ErrorCheck();
133
0
  }
134
0
  if (NS_FAILED(rv)) {
135
0
    aRv.Throw(rv);
136
0
  }
137
0
}
138
139
void
140
ChannelWrapper::RedirectTo(nsIURI* aURI, ErrorResult& aRv)
141
0
{
142
0
  nsresult rv = NS_ERROR_UNEXPECTED;
143
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
144
0
    rv = chan->RedirectTo(aURI);
145
0
  }
146
0
  if (NS_FAILED(rv)) {
147
0
    aRv.Throw(rv);
148
0
  }
149
0
}
150
151
void
152
ChannelWrapper::UpgradeToSecure(ErrorResult& aRv)
153
0
{
154
0
  nsresult rv = NS_ERROR_UNEXPECTED;
155
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
156
0
    rv = chan->UpgradeToSecure();
157
0
  }
158
0
  if (NS_FAILED(rv)) {
159
0
    aRv.Throw(rv);
160
0
  }
161
0
}
162
163
void
164
ChannelWrapper::SetSuspended(bool aSuspended, ErrorResult& aRv)
165
0
{
166
0
  if (aSuspended != mSuspended) {
167
0
    nsresult rv = NS_ERROR_UNEXPECTED;
168
0
    if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
169
0
      if (aSuspended) {
170
0
        rv = chan->Suspend();
171
0
      } else {
172
0
        rv = chan->Resume();
173
0
      }
174
0
    }
175
0
    if (NS_FAILED(rv)) {
176
0
      aRv.Throw(rv);
177
0
    } else {
178
0
      mSuspended = aSuspended;
179
0
    }
180
0
  }
181
0
}
182
183
void
184
ChannelWrapper::GetContentType(nsCString& aContentType) const
185
0
{
186
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
187
0
    Unused << chan->GetContentType(aContentType);
188
0
  }
189
0
}
190
191
void
192
ChannelWrapper::SetContentType(const nsACString& aContentType)
193
0
{
194
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
195
0
    Unused << chan->SetContentType(aContentType);
196
0
  }
197
0
}
198
199
200
/*****************************************************************************
201
 * Headers
202
 *****************************************************************************/
203
204
namespace {
205
206
class MOZ_STACK_CLASS HeaderVisitor final : public nsIHttpHeaderVisitor
207
{
208
public:
209
  NS_DECL_NSIHTTPHEADERVISITOR
210
211
  explicit HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders)
212
    : mHeaders(aHeaders)
213
0
  {}
214
215
  HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders,
216
                const nsCString& aContentTypeHdr)
217
    : mHeaders(aHeaders)
218
    , mContentTypeHdr(aContentTypeHdr)
219
0
  {}
220
221
  void VisitRequestHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv)
222
0
  {
223
0
    CheckResult(aChannel->VisitRequestHeaders(this), aRv);
224
0
  }
225
226
  void VisitResponseHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv)
227
0
  {
228
0
    CheckResult(aChannel->VisitResponseHeaders(this), aRv);
229
0
  }
230
231
  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
232
233
  // Stub AddRef/Release since this is a stack class.
234
  NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override
235
0
  {
236
0
    return ++mRefCnt;
237
0
  }
238
239
  NS_IMETHOD_(MozExternalRefCountType) Release(void) override
240
0
  {
241
0
    return --mRefCnt;
242
0
  }
243
244
  virtual ~HeaderVisitor()
245
0
  {
246
0
    MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0);
247
0
  }
248
249
private:
250
  bool CheckResult(nsresult aNSRv, ErrorResult& aRv)
251
0
  {
252
0
    if (NS_FAILED(aNSRv)) {
253
0
      aRv.Throw(aNSRv);
254
0
      return false;
255
0
    }
256
0
    return true;
257
0
  }
258
259
  nsTArray<dom::MozHTTPHeader>& mHeaders;
260
  nsCString mContentTypeHdr = VoidCString();
261
262
  nsrefcnt mRefCnt = 0;
263
};
264
265
NS_IMETHODIMP
266
HeaderVisitor::VisitHeader(const nsACString& aHeader, const nsACString& aValue)
267
0
{
268
0
  auto dict = mHeaders.AppendElement(fallible);
269
0
  if (!dict) {
270
0
    return NS_ERROR_OUT_OF_MEMORY;
271
0
  }
272
0
  dict->mName = aHeader;
273
0
274
0
  if (!mContentTypeHdr.IsVoid() && aHeader.LowerCaseEqualsLiteral("content-type")) {
275
0
    dict->mValue = mContentTypeHdr;
276
0
  } else {
277
0
    dict->mValue = aValue;
278
0
  }
279
0
280
0
  return NS_OK;
281
0
}
282
283
NS_IMPL_QUERY_INTERFACE(HeaderVisitor, nsIHttpHeaderVisitor)
284
285
} // anonymous namespace
286
287
288
void
289
ChannelWrapper::GetRequestHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal, ErrorResult& aRv) const
290
0
{
291
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
292
0
    HeaderVisitor visitor(aRetVal);
293
0
    visitor.VisitRequestHeaders(chan, aRv);
294
0
  } else {
295
0
    aRv.Throw(NS_ERROR_UNEXPECTED);
296
0
  }
297
0
}
298
299
void
300
ChannelWrapper::GetResponseHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal, ErrorResult& aRv) const
301
0
{
302
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
303
0
    HeaderVisitor visitor(aRetVal, mContentTypeHdr);
304
0
    visitor.VisitResponseHeaders(chan, aRv);
305
0
  } else {
306
0
    aRv.Throw(NS_ERROR_UNEXPECTED);
307
0
  }
308
0
}
309
310
void
311
ChannelWrapper::SetRequestHeader(const nsCString& aHeader, const nsCString& aValue, bool aMerge, ErrorResult& aRv)
312
0
{
313
0
  nsresult rv = NS_ERROR_UNEXPECTED;
314
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
315
0
    rv = chan->SetRequestHeader(aHeader, aValue, aMerge);
316
0
  }
317
0
  if (NS_FAILED(rv)) {
318
0
    aRv.Throw(rv);
319
0
  }
320
0
}
321
322
void
323
ChannelWrapper::SetResponseHeader(const nsCString& aHeader, const nsCString& aValue, bool aMerge, ErrorResult& aRv)
324
0
{
325
0
  nsresult rv = NS_ERROR_UNEXPECTED;
326
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
327
0
    if (aHeader.LowerCaseEqualsLiteral("content-type")) {
328
0
      rv = chan->SetContentType(aValue);
329
0
      if (NS_SUCCEEDED(rv)) {
330
0
        mContentTypeHdr = aValue;
331
0
      }
332
0
    } else {
333
0
      rv = chan->SetResponseHeader(aHeader, aValue, aMerge);
334
0
    }
335
0
  }
336
0
  if (NS_FAILED(rv)) {
337
0
    aRv.Throw(rv);
338
0
  }
339
0
}
340
341
/*****************************************************************************
342
 * LoadInfo
343
 *****************************************************************************/
344
345
already_AddRefed<nsILoadContext>
346
ChannelWrapper::GetLoadContext() const
347
0
{
348
0
  if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
349
0
    nsCOMPtr<nsILoadContext> ctxt;
350
0
    NS_QueryNotificationCallbacks(chan, ctxt);
351
0
    return ctxt.forget();
352
0
  }
353
0
  return nullptr;
354
0
}
355
356
already_AddRefed<Element>
357
ChannelWrapper::GetBrowserElement() const
358
0
{
359
0
  if (nsCOMPtr<nsILoadContext> ctxt = GetLoadContext()) {
360
0
    RefPtr<Element> elem;
361
0
    if (NS_SUCCEEDED(ctxt->GetTopFrameElement(getter_AddRefs(elem)))) {
362
0
      return elem.forget();
363
0
    }
364
0
  }
365
0
  return nullptr;
366
0
}
367
368
static inline bool
369
IsSystemPrincipal(nsIPrincipal* aPrincipal)
370
0
{
371
0
  return BasePrincipal::Cast(aPrincipal)->Is<SystemPrincipal>();
372
0
}
373
374
bool
375
ChannelWrapper::IsSystemLoad() const
376
0
{
377
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
378
0
    if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) {
379
0
      return IsSystemPrincipal(prin);
380
0
    }
381
0
382
0
    if (loadInfo->GetOuterWindowID() == loadInfo->GetTopOuterWindowID()) {
383
0
      return false;
384
0
    }
385
0
386
0
    if (nsIPrincipal* prin = loadInfo->PrincipalToInherit()) {
387
0
      return IsSystemPrincipal(prin);
388
0
    }
389
0
    if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) {
390
0
      return IsSystemPrincipal(prin);
391
0
    }
392
0
  }
393
0
  return false;
394
0
}
395
396
bool
397
ChannelWrapper::CanModify() const
398
0
{
399
0
  if (WebExtensionPolicy::IsRestrictedURI(FinalURLInfo())) {
400
0
    return false;
401
0
  }
402
0
403
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
404
0
    if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) {
405
0
      if (IsSystemPrincipal(prin)) {
406
0
        return false;
407
0
      }
408
0
409
0
      auto* docURI = DocumentURLInfo();
410
0
      if (docURI && WebExtensionPolicy::IsRestrictedURI(*docURI)) {
411
0
        return false;
412
0
      }
413
0
    }
414
0
  }
415
0
  return true;
416
0
}
417
418
already_AddRefed<nsIURI>
419
ChannelWrapper::GetOriginURI() const
420
0
{
421
0
  nsCOMPtr<nsIURI> uri;
422
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
423
0
    if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) {
424
0
      if (prin->GetIsCodebasePrincipal()) {
425
0
        Unused << prin->GetURI(getter_AddRefs(uri));
426
0
      }
427
0
    }
428
0
  }
429
0
  return uri.forget();
430
0
}
431
432
already_AddRefed<nsIURI>
433
ChannelWrapper::GetDocumentURI() const
434
0
{
435
0
  nsCOMPtr<nsIURI> uri;
436
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
437
0
    if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) {
438
0
      if (prin->GetIsCodebasePrincipal()) {
439
0
        Unused << prin->GetURI(getter_AddRefs(uri));
440
0
      }
441
0
    }
442
0
  }
443
0
  return uri.forget();
444
0
}
445
446
447
void
448
ChannelWrapper::GetOriginURL(nsCString& aRetVal) const
449
0
{
450
0
  if (nsCOMPtr<nsIURI> uri = GetOriginURI()) {
451
0
    Unused << uri->GetSpec(aRetVal);
452
0
  }
453
0
}
454
455
void
456
ChannelWrapper::GetDocumentURL(nsCString& aRetVal) const
457
0
{
458
0
  if (nsCOMPtr<nsIURI> uri = GetDocumentURI()) {
459
0
    Unused << uri->GetSpec(aRetVal);
460
0
  }
461
0
}
462
463
464
const URLInfo&
465
ChannelWrapper::FinalURLInfo() const
466
0
{
467
0
  if (mFinalURLInfo.isNothing()) {
468
0
    ErrorResult rv;
469
0
    nsCOMPtr<nsIURI> uri = FinalURI();
470
0
    MOZ_ASSERT(uri);
471
0
    mFinalURLInfo.emplace(uri.get(), true);
472
0
473
0
    // If this is a WebSocket request, mangle the URL so that the scheme is
474
0
    // ws: or wss:, as appropriate.
475
0
    auto& url = mFinalURLInfo.ref();
476
0
    if (Type() == MozContentPolicyType::Websocket &&
477
0
        (url.Scheme() == nsGkAtoms::http ||
478
0
         url.Scheme() == nsGkAtoms::https)) {
479
0
      nsAutoCString spec(url.CSpec());
480
0
      spec.Replace(0, 4, NS_LITERAL_CSTRING("ws"));
481
0
482
0
      Unused << NS_NewURI(getter_AddRefs(uri), spec);
483
0
      MOZ_RELEASE_ASSERT(uri);
484
0
      mFinalURLInfo.reset();
485
0
      mFinalURLInfo.emplace(uri.get(), true);
486
0
    }
487
0
  }
488
0
  return mFinalURLInfo.ref();
489
0
}
490
491
const URLInfo*
492
ChannelWrapper::DocumentURLInfo() const
493
0
{
494
0
  if (mDocumentURLInfo.isNothing()) {
495
0
    nsCOMPtr<nsIURI> uri = GetDocumentURI();
496
0
    if (!uri) {
497
0
      return nullptr;
498
0
    }
499
0
    mDocumentURLInfo.emplace(uri.get(), true);
500
0
  }
501
0
  return &mDocumentURLInfo.ref();
502
0
}
503
504
505
bool
506
ChannelWrapper::Matches(const dom::MozRequestFilter& aFilter,
507
                        const WebExtensionPolicy* aExtension,
508
                        const dom::MozRequestMatchOptions& aOptions) const
509
0
{
510
0
  if (!HaveChannel()) {
511
0
    return false;
512
0
  }
513
0
514
0
  if (!aFilter.mTypes.IsNull() && !aFilter.mTypes.Value().Contains(Type())) {
515
0
    return false;
516
0
  }
517
0
518
0
  auto& urlInfo = FinalURLInfo();
519
0
  if (aFilter.mUrls && !aFilter.mUrls->Matches(urlInfo)) {
520
0
    return false;
521
0
  }
522
0
523
0
  if (aExtension) {
524
0
    bool isProxy = aOptions.mIsProxy && aExtension->HasPermission(nsGkAtoms::proxy);
525
0
    // Proxies are allowed access to all urls, including restricted urls.
526
0
    if (!aExtension->CanAccessURI(urlInfo, false, !isProxy)) {
527
0
      return false;
528
0
    }
529
0
530
0
    // If this isn't the proxy phase of the request, check that the extension
531
0
    // has origin permissions for origin that originated the request.
532
0
    if (!isProxy) {
533
0
      if (IsSystemLoad()) {
534
0
        return false;
535
0
      }
536
0
537
0
      if (auto origin = DocumentURLInfo()) {
538
0
        nsAutoCString baseURL;
539
0
        aExtension->GetBaseURL(baseURL);
540
0
541
0
        if (!StringBeginsWith(origin->CSpec(), baseURL) &&
542
0
            !aExtension->CanAccessURI(*origin)) {
543
0
          return false;
544
0
        }
545
0
      }
546
0
    }
547
0
  }
548
0
549
0
  return true;
550
0
}
551
552
553
554
int64_t
555
NormalizeWindowID(nsILoadInfo* aLoadInfo, uint64_t windowID)
556
0
{
557
0
  if (windowID == aLoadInfo->GetTopOuterWindowID()) {
558
0
    return 0;
559
0
  }
560
0
  return windowID;
561
0
}
562
563
uint64_t
564
ChannelWrapper::WindowId(nsILoadInfo* aLoadInfo) const
565
0
{
566
0
  auto frameID = aLoadInfo->GetFrameOuterWindowID();
567
0
  if (!frameID) {
568
0
    frameID = aLoadInfo->GetOuterWindowID();
569
0
  }
570
0
  return frameID;
571
0
}
572
573
int64_t
574
ChannelWrapper::WindowId() const
575
0
{
576
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
577
0
    return NormalizeWindowID(loadInfo, WindowId(loadInfo));
578
0
  }
579
0
  return 0;
580
0
}
581
582
int64_t
583
ChannelWrapper::ParentWindowId() const
584
0
{
585
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
586
0
    if (WindowId(loadInfo) == loadInfo->GetTopOuterWindowID()) {
587
0
      return -1;
588
0
    }
589
0
590
0
    uint64_t parentID;
591
0
    if (loadInfo->GetFrameOuterWindowID()) {
592
0
      parentID = loadInfo->GetOuterWindowID();
593
0
    } else {
594
0
      parentID = loadInfo->GetParentOuterWindowID();
595
0
    }
596
0
    return NormalizeWindowID(loadInfo, parentID);
597
0
  }
598
0
  return -1;
599
0
}
600
601
void
602
ChannelWrapper::GetFrameAncestors(dom::Nullable<nsTArray<dom::MozFrameAncestorInfo>>& aFrameAncestors, ErrorResult& aRv) const
603
0
{
604
0
  nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo();
605
0
  if (!loadInfo || WindowId(loadInfo) == 0) {
606
0
    aFrameAncestors.SetNull();
607
0
    return;
608
0
  }
609
0
610
0
  nsresult rv = GetFrameAncestors(loadInfo, aFrameAncestors.SetValue());
611
0
  if (NS_FAILED(rv)) {
612
0
    aRv.Throw(rv);
613
0
  }
614
0
}
615
616
nsresult
617
ChannelWrapper::GetFrameAncestors(nsILoadInfo* aLoadInfo, nsTArray<dom::MozFrameAncestorInfo>& aFrameAncestors) const
618
0
{
619
0
  const nsTArray<nsCOMPtr<nsIPrincipal>>& ancestorPrincipals = aLoadInfo->AncestorPrincipals();
620
0
  const nsTArray<uint64_t>& ancestorOuterWindowIDs = aLoadInfo->AncestorOuterWindowIDs();
621
0
  uint32_t size = ancestorPrincipals.Length();
622
0
  MOZ_DIAGNOSTIC_ASSERT(size == ancestorOuterWindowIDs.Length());
623
0
  if (size != ancestorOuterWindowIDs.Length()) {
624
0
    return NS_ERROR_UNEXPECTED;
625
0
  }
626
0
627
0
  bool subFrame = aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT;
628
0
  if (!aFrameAncestors.SetCapacity(subFrame ? size : size + 1, fallible)) {
629
0
    return NS_ERROR_OUT_OF_MEMORY;
630
0
  }
631
0
632
0
  // The immediate parent is always the first element in the ancestor arrays, however
633
0
  // SUBDOCUMENTs do not have their immediate parent included, so we inject it here.
634
0
  // This will force wrapper.parentWindowId == wrapper.frameAncestors[0].frameId to
635
0
  // always be true.  All ather requests already match this way.
636
0
  if (subFrame) {
637
0
    auto ancestor = aFrameAncestors.AppendElement();
638
0
    GetDocumentURL(ancestor->mUrl);
639
0
    ancestor->mFrameId = ParentWindowId();
640
0
  }
641
0
642
0
  for (uint32_t i = 0; i < size; ++i) {
643
0
    auto ancestor = aFrameAncestors.AppendElement();
644
0
    nsCOMPtr<nsIURI> uri;
645
0
    MOZ_TRY(ancestorPrincipals[i]->GetURI(getter_AddRefs(uri)));
646
0
    if (!uri) {
647
0
      return NS_ERROR_UNEXPECTED;
648
0
    }
649
0
    MOZ_TRY(uri->GetSpec(ancestor->mUrl));
650
0
    ancestor->mFrameId = NormalizeWindowID(aLoadInfo, ancestorOuterWindowIDs[i]);
651
0
  }
652
0
  return NS_OK;
653
0
}
654
655
/*****************************************************************************
656
 * Response filtering
657
 *****************************************************************************/
658
659
void
660
ChannelWrapper::RegisterTraceableChannel(const WebExtensionPolicy& aAddon, nsITabParent* aTabParent)
661
0
{
662
0
  // We can't attach new listeners after the response has started, so don't
663
0
  // bother registering anything.
664
0
  if (mResponseStarted || !CanModify()) {
665
0
    return;
666
0
  }
667
0
668
0
  mAddonEntries.Put(aAddon.Id(), aTabParent);
669
0
  if (!mChannelEntry) {
670
0
    mChannelEntry = WebRequestService::GetSingleton().RegisterChannel(this);
671
0
    CheckEventListeners();
672
0
  }
673
0
}
674
675
already_AddRefed<nsITraceableChannel>
676
ChannelWrapper::GetTraceableChannel(nsAtom* aAddonId, dom::nsIContentParent* aContentParent) const
677
0
{
678
0
  nsCOMPtr<nsITabParent> tabParent;
679
0
  if (mAddonEntries.Get(aAddonId, getter_AddRefs(tabParent))) {
680
0
    nsIContentParent* contentParent = nullptr;
681
0
    if (tabParent) {
682
0
      contentParent = static_cast<nsIContentParent*>(
683
0
          static_cast<TabParent*>(tabParent.get())->Manager());
684
0
    }
685
0
686
0
    if (contentParent == aContentParent) {
687
0
      nsCOMPtr<nsITraceableChannel> chan = QueryChannel();
688
0
      return chan.forget();
689
0
    }
690
0
  }
691
0
  return nullptr;
692
0
}
693
694
/*****************************************************************************
695
 * ...
696
 *****************************************************************************/
697
698
MozContentPolicyType
699
GetContentPolicyType(uint32_t aType)
700
{
701
  // Note: Please keep this function in sync with the external types in
702
  // nsIContentPolicy.idl
703
  switch (aType) {
704
  case nsIContentPolicy::TYPE_DOCUMENT:
705
    return MozContentPolicyType::Main_frame;
706
  case nsIContentPolicy::TYPE_SUBDOCUMENT:
707
    return MozContentPolicyType::Sub_frame;
708
  case nsIContentPolicy::TYPE_STYLESHEET:
709
    return MozContentPolicyType::Stylesheet;
710
  case nsIContentPolicy::TYPE_SCRIPT:
711
    return MozContentPolicyType::Script;
712
  case nsIContentPolicy::TYPE_IMAGE:
713
    return MozContentPolicyType::Image;
714
  case nsIContentPolicy::TYPE_OBJECT:
715
    return MozContentPolicyType::Object;
716
  case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST:
717
    return MozContentPolicyType::Object_subrequest;
718
  case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
719
    return MozContentPolicyType::Xmlhttprequest;
720
  // TYPE_FETCH returns xmlhttprequest for cross-browser compatibility.
721
  case nsIContentPolicy::TYPE_FETCH:
722
    return MozContentPolicyType::Xmlhttprequest;
723
  case nsIContentPolicy::TYPE_XBL:
724
    return MozContentPolicyType::Xbl;
725
  case nsIContentPolicy::TYPE_XSLT:
726
    return MozContentPolicyType::Xslt;
727
  case nsIContentPolicy::TYPE_PING:
728
    return MozContentPolicyType::Ping;
729
  case nsIContentPolicy::TYPE_BEACON:
730
    return MozContentPolicyType::Beacon;
731
  case nsIContentPolicy::TYPE_DTD:
732
    return MozContentPolicyType::Xml_dtd;
733
  case nsIContentPolicy::TYPE_FONT:
734
    return MozContentPolicyType::Font;
735
  case nsIContentPolicy::TYPE_MEDIA:
736
    return MozContentPolicyType::Media;
737
  case nsIContentPolicy::TYPE_WEBSOCKET:
738
    return MozContentPolicyType::Websocket;
739
  case nsIContentPolicy::TYPE_CSP_REPORT:
740
    return MozContentPolicyType::Csp_report;
741
  case nsIContentPolicy::TYPE_IMAGESET:
742
    return MozContentPolicyType::Imageset;
743
  case nsIContentPolicy::TYPE_WEB_MANIFEST:
744
    return MozContentPolicyType::Web_manifest;
745
  case nsIContentPolicy::TYPE_SPECULATIVE:
746
    return MozContentPolicyType::Speculative;
747
  default:
748
    return MozContentPolicyType::Other;
749
  }
750
}
751
752
MozContentPolicyType
753
ChannelWrapper::Type() const
754
0
{
755
0
  if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
756
0
    return GetContentPolicyType(loadInfo->GetExternalContentPolicyType());
757
0
  }
758
0
  return MozContentPolicyType::Other;
759
0
}
760
761
void
762
ChannelWrapper::GetMethod(nsCString& aMethod) const
763
0
{
764
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
765
0
    Unused << chan->GetRequestMethod(aMethod);
766
0
  }
767
0
}
768
769
770
/*****************************************************************************
771
 * ...
772
 *****************************************************************************/
773
774
uint32_t
775
ChannelWrapper::StatusCode() const
776
0
{
777
0
  uint32_t result = 0;
778
0
  if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
779
0
    Unused << chan->GetResponseStatus(&result);
780
0
  }
781
0
  return result;
782
0
}
783
784
void
785
ChannelWrapper::GetStatusLine(nsCString& aRetVal) const
786
0
{
787
0
  nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel();
788
0
  nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(chan);
789
0
790
0
  if (internal) {
791
0
    nsAutoCString statusText;
792
0
    uint32_t major, minor, status;
793
0
    if (NS_FAILED(chan->GetResponseStatus(&status)) ||
794
0
        NS_FAILED(chan->GetResponseStatusText(statusText)) ||
795
0
        NS_FAILED(internal->GetResponseVersion(&major, &minor))) {
796
0
      return;
797
0
    }
798
0
799
0
    aRetVal = nsPrintfCString("HTTP/%u.%u %u %s",
800
0
                              major, minor, status, statusText.get());
801
0
  }
802
0
}
803
804
/*****************************************************************************
805
 * ...
806
 *****************************************************************************/
807
808
already_AddRefed<nsIURI>
809
ChannelWrapper::FinalURI() const
810
0
{
811
0
  nsCOMPtr<nsIURI> uri;
812
0
  if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
813
0
    NS_GetFinalChannelURI(chan, getter_AddRefs(uri));
814
0
  }
815
0
  return uri.forget();
816
0
}
817
818
void
819
ChannelWrapper::GetFinalURL(nsString& aRetVal) const
820
0
{
821
0
  if (HaveChannel()) {
822
0
    aRetVal = FinalURLInfo().Spec();
823
0
  }
824
0
}
825
826
/*****************************************************************************
827
 * ...
828
 *****************************************************************************/
829
830
nsresult
831
FillProxyInfo(MozProxyInfo &aDict, nsIProxyInfo* aProxyInfo)
832
0
{
833
0
  MOZ_TRY(aProxyInfo->GetHost(aDict.mHost));
834
0
  MOZ_TRY(aProxyInfo->GetPort(&aDict.mPort));
835
0
  MOZ_TRY(aProxyInfo->GetType(aDict.mType));
836
0
  MOZ_TRY(aProxyInfo->GetUsername(aDict.mUsername));
837
0
  MOZ_TRY(aProxyInfo->GetFailoverTimeout(&aDict.mFailoverTimeout.Construct()));
838
0
839
0
  uint32_t flags;
840
0
  MOZ_TRY(aProxyInfo->GetFlags(&flags));
841
0
  aDict.mProxyDNS = flags & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
842
0
843
0
  return NS_OK;
844
0
}
845
846
void
847
ChannelWrapper::GetProxyInfo(dom::Nullable<MozProxyInfo>& aRetVal, ErrorResult& aRv) const
848
0
{
849
0
  nsCOMPtr<nsIProxyInfo> proxyInfo;
850
0
  if (nsCOMPtr<nsIProxiedChannel> proxied = QueryChannel()) {
851
0
    Unused << proxied->GetProxyInfo(getter_AddRefs(proxyInfo));
852
0
  }
853
0
  if (proxyInfo) {
854
0
    MozProxyInfo result;
855
0
856
0
    nsresult rv = FillProxyInfo(result, proxyInfo);
857
0
    if (NS_FAILED(rv)) {
858
0
      aRv.Throw(rv);
859
0
    } else {
860
0
      aRetVal.SetValue(std::move(result));
861
0
    }
862
0
  }
863
0
}
864
865
void
866
ChannelWrapper::GetRemoteAddress(nsCString& aRetVal) const
867
0
{
868
0
  aRetVal.SetIsVoid(true);
869
0
  if (nsCOMPtr<nsIHttpChannelInternal> internal = QueryChannel()) {
870
0
    Unused << internal->GetRemoteAddress(aRetVal);
871
0
  }
872
0
}
873
874
/*****************************************************************************
875
 * Error handling
876
 *****************************************************************************/
877
878
void
879
ChannelWrapper::GetErrorString(nsString& aRetVal) const
880
0
{
881
0
  if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
882
0
    nsCOMPtr<nsISupports> securityInfo;
883
0
    Unused << chan->GetSecurityInfo(getter_AddRefs(securityInfo));
884
0
    if (nsCOMPtr<nsITransportSecurityInfo> tsi = do_QueryInterface(securityInfo)) {
885
0
      int32_t errorCode = 0;
886
0
      tsi->GetErrorCode(&errorCode);
887
0
      if (psm::IsNSSErrorCode(errorCode)) {
888
0
        nsCOMPtr<nsINSSErrorsService> nsserr =
889
0
          do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
890
0
891
0
        nsresult rv = psm::GetXPCOMFromNSSError(errorCode);
892
0
        if (nsserr && NS_SUCCEEDED(nsserr->GetErrorMessage(rv, aRetVal))) {
893
0
          return;
894
0
        }
895
0
      }
896
0
    }
897
0
898
0
    nsresult status;
899
0
    if (NS_SUCCEEDED(chan->GetStatus(&status)) && NS_FAILED(status)) {
900
0
      nsAutoCString name;
901
0
      GetErrorName(status, name);
902
0
      AppendUTF8toUTF16(name, aRetVal);
903
0
    } else {
904
0
      aRetVal.SetIsVoid(true);
905
0
    }
906
0
  } else {
907
0
    aRetVal.AssignLiteral("NS_ERROR_UNEXPECTED");
908
0
  }
909
0
}
910
911
void
912
ChannelWrapper::ErrorCheck()
913
0
{
914
0
  if (!mFiredErrorEvent) {
915
0
    nsAutoString error;
916
0
    GetErrorString(error);
917
0
    if (error.Length()) {
918
0
      mChannelEntry = nullptr;
919
0
      mFiredErrorEvent = true;
920
0
      ChannelWrapper_Binding::ClearCachedErrorStringValue(this);
921
0
      FireEvent(NS_LITERAL_STRING("error"));
922
0
    }
923
0
  }
924
0
}
925
926
/*****************************************************************************
927
 * nsIWebRequestListener
928
 *****************************************************************************/
929
930
NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener,
931
                  nsIStreamListener,
932
                  nsIRequestObserver,
933
                  nsIThreadRetargetableStreamListener)
934
935
0
ChannelWrapper::RequestListener::~RequestListener() {
936
0
  NS_ReleaseOnMainThreadSystemGroup("RequestListener::mChannelWrapper",
937
0
                                    mChannelWrapper.forget());
938
0
}
939
940
nsresult
941
ChannelWrapper::RequestListener::Init()
942
0
{
943
0
  if (nsCOMPtr<nsITraceableChannel> chan = mChannelWrapper->QueryChannel()) {
944
0
    return chan->SetNewListener(this, getter_AddRefs(mOrigStreamListener));
945
0
  }
946
0
  return NS_ERROR_UNEXPECTED;
947
0
}
948
949
NS_IMETHODIMP
950
ChannelWrapper::RequestListener::OnStartRequest(nsIRequest *request, nsISupports * aCtxt)
951
0
{
952
0
  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
953
0
954
0
  mChannelWrapper->mChannelEntry = nullptr;
955
0
  mChannelWrapper->mResponseStarted = true;
956
0
  mChannelWrapper->ErrorCheck();
957
0
  mChannelWrapper->FireEvent(NS_LITERAL_STRING("start"));
958
0
959
0
  return mOrigStreamListener->OnStartRequest(request, aCtxt);
960
0
}
961
962
NS_IMETHODIMP
963
ChannelWrapper::RequestListener::OnStopRequest(nsIRequest *request, nsISupports *aCtxt,
964
                                               nsresult aStatus)
965
0
{
966
0
  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
967
0
968
0
  mChannelWrapper->mChannelEntry = nullptr;
969
0
  mChannelWrapper->ErrorCheck();
970
0
  mChannelWrapper->FireEvent(NS_LITERAL_STRING("stop"));
971
0
972
0
  return mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus);
973
0
}
974
975
NS_IMETHODIMP
976
ChannelWrapper::RequestListener::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
977
                                             nsIInputStream * inStr,
978
                                             uint64_t sourceOffset, uint32_t count)
979
0
{
980
0
  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
981
0
  return mOrigStreamListener->OnDataAvailable(request, aCtxt, inStr, sourceOffset, count);
982
0
}
983
984
NS_IMETHODIMP
985
ChannelWrapper::RequestListener::CheckListenerChain()
986
0
{
987
0
    MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!");
988
0
    nsresult rv;
989
0
    nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
990
0
        do_QueryInterface(mOrigStreamListener, &rv);
991
0
    if (retargetableListener) {
992
0
        return retargetableListener->CheckListenerChain();
993
0
    }
994
0
    return rv;
995
0
}
996
997
/*****************************************************************************
998
 * Event dispatching
999
 *****************************************************************************/
1000
1001
void
1002
ChannelWrapper::FireEvent(const nsAString& aType)
1003
0
{
1004
0
  EventInit init;
1005
0
  init.mBubbles = false;
1006
0
  init.mCancelable = false;
1007
0
1008
0
  RefPtr<Event> event = Event::Constructor(this, aType, init);
1009
0
  event->SetTrusted(true);
1010
0
1011
0
  DispatchEvent(*event);
1012
0
}
1013
1014
void
1015
ChannelWrapper::CheckEventListeners()
1016
0
{
1017
0
  if (!mAddedStreamListener && (HasListenersFor(nsGkAtoms::onerror) ||
1018
0
                                HasListenersFor(nsGkAtoms::onstart) ||
1019
0
                                HasListenersFor(nsGkAtoms::onstop) ||
1020
0
                                mChannelEntry)) {
1021
0
    auto listener = MakeRefPtr<RequestListener>(this);
1022
0
    if (!NS_WARN_IF(NS_FAILED(listener->Init()))) {
1023
0
      mAddedStreamListener = true;
1024
0
    }
1025
0
  }
1026
0
}
1027
1028
void
1029
ChannelWrapper::EventListenerAdded(nsAtom* aType)
1030
0
{
1031
0
  CheckEventListeners();
1032
0
}
1033
1034
void
1035
ChannelWrapper::EventListenerRemoved(nsAtom* aType)
1036
0
{
1037
0
  CheckEventListeners();
1038
0
}
1039
1040
/*****************************************************************************
1041
 * Glue
1042
 *****************************************************************************/
1043
1044
JSObject*
1045
ChannelWrapper::WrapObject(JSContext* aCx, HandleObject aGivenProto)
1046
0
{
1047
0
  return ChannelWrapper_Binding::Wrap(aCx, this, aGivenProto);
1048
0
}
1049
1050
NS_IMPL_CYCLE_COLLECTION_CLASS(ChannelWrapper)
1051
1052
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper)
1053
0
  NS_INTERFACE_MAP_ENTRY(ChannelWrapper)
1054
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
1055
1056
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1057
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
1058
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1059
1060
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1061
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
1062
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1063
1064
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1065
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
1066
1067
NS_IMPL_ADDREF_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1068
NS_IMPL_RELEASE_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1069
1070
} // namespace extensions
1071
} // namespace mozilla
1072