Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/fetch/InternalRequest.h
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
#ifndef mozilla_dom_InternalRequest_h
8
#define mozilla_dom_InternalRequest_h
9
10
#include "mozilla/dom/HeadersBinding.h"
11
#include "mozilla/dom/InternalHeaders.h"
12
#include "mozilla/dom/RequestBinding.h"
13
#include "mozilla/LoadTainting.h"
14
#include "mozilla/net/ReferrerPolicy.h"
15
16
#include "nsIContentPolicy.h"
17
#include "nsIInputStream.h"
18
#include "nsISupportsImpl.h"
19
#ifdef DEBUG
20
#include "nsIURLParser.h"
21
#include "nsNetCID.h"
22
#include "nsServiceManagerUtils.h"
23
#endif
24
25
namespace mozilla {
26
27
namespace ipc {
28
class PrincipalInfo;
29
} // namespace ipc
30
31
namespace dom {
32
33
/*
34
 * The mapping of RequestDestination and nsContentPolicyType is currently as the
35
 * following.  Note that this mapping is not perfect yet (see the TODO comments
36
 * below for examples).
37
 *
38
 * RequestDestination| nsContentPolicyType
39
 * ------------------+--------------------
40
 * audio             | TYPE_INTERNAL_AUDIO
41
 * audioworklet      | TODO
42
 * document          | TYPE_DOCUMENT, TYPE_INTERNAL_IFRAME, TYPE_SUBDOCUMENT
43
 * embed             | TYPE_INTERNAL_EMBED
44
 * font              | TYPE_FONT
45
 * image             | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD,
46
 *                   | TYPE_IMAGE, TYPE_INTERNAL_IMAGE_FAVICON, TYPE_IMAGESET
47
 * manifest          | TYPE_WEB_MANIFEST
48
 * object            | TYPE_INTERNAL_OBJECT, TYPE_OBJECT
49
 * "paintworklet"    | TODO
50
 * report"           | TODO
51
 * script            | TYPE_INTERNAL_SCRIPT, TYPE_INTERNAL_SCRIPT_PRELOAD, TYPE_SCRIPT
52
 *                   | TYPE_INTERNAL_SERVICE_WORKER, TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS
53
 * sharedworker      | TYPE_INTERNAL_SHARED_WORKER
54
 * serviceworker     | The spec lists this as a valid value for the enum,however it
55
 *                   | is impossible to observe a request with this destination value.
56
 * style             | TYPE_INTERNAL_STYLESHEET, TYPE_INTERNAL_STYLESHEET_PRELOAD,
57
 *                   | TYPE_STYLESHEET
58
 * track             | TYPE_INTERNAL_TRACK
59
 * video             | TYPE_INTERNAL_VIDEO
60
 * worker            | TYPE_INTERNAL_WORKER
61
 * xslt              | TYPE_XSLT
62
 * _empty            | Default for everything else.
63
 *
64
 */
65
66
class Request;
67
class IPCInternalRequest;
68
69
0
#define kFETCH_CLIENT_REFERRER_STR "about:client"
70
class InternalRequest final
71
{
72
  friend class Request;
73
public:
74
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
75
  InternalRequest(const nsACString& aURL, const nsACString& aFragment);
76
  InternalRequest(const nsACString& aURL,
77
                  const nsACString& aFragment,
78
                  const nsACString& aMethod,
79
                  already_AddRefed<InternalHeaders> aHeaders,
80
                  RequestCache aCacheMode,
81
                  RequestMode aMode,
82
                  RequestRedirect aRequestRedirect,
83
                  RequestCredentials aRequestCredentials,
84
                  const nsAString& aReferrer,
85
                  ReferrerPolicy aReferrerPolicy,
86
                  nsContentPolicyType aContentPolicyType,
87
                  const nsAString& aIntegrity);
88
89
  explicit InternalRequest(const IPCInternalRequest& aIPCRequest);
90
91
  void ToIPC(IPCInternalRequest* aIPCRequest);
92
93
  already_AddRefed<InternalRequest> Clone();
94
95
  void
96
  GetMethod(nsCString& aMethod) const
97
  {
98
    aMethod.Assign(mMethod);
99
  }
100
101
  void
102
  SetMethod(const nsACString& aMethod)
103
  {
104
    mMethod.Assign(aMethod);
105
  }
106
107
  bool
108
  HasSimpleMethod() const
109
0
  {
110
0
    return mMethod.LowerCaseEqualsASCII("get") ||
111
0
           mMethod.LowerCaseEqualsASCII("post") ||
112
0
           mMethod.LowerCaseEqualsASCII("head");
113
0
  }
114
  // GetURL should get the request's current url with fragment. A request has
115
  // an associated current url. It is a pointer to the last fetch URL in
116
  // request's url list.
117
  void
118
  GetURL(nsACString& aURL) const
119
  {
120
    aURL.Assign(GetURLWithoutFragment());
121
    if (GetFragment().IsEmpty()) {
122
      return;
123
    }
124
    aURL.AppendLiteral("#");
125
    aURL.Append(GetFragment());
126
  }
127
128
  const nsCString&
129
  GetURLWithoutFragment() const
130
  {
131
    MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
132
                       "Internal Request's urlList should not be empty.");
133
134
    return mURLList.LastElement();
135
  }
136
137
  // A safe guard for ensuring that request's URL is only allowed to be set in a
138
  // sw internal redirect.
139
  void
140
  SetURLForInternalRedirect(const uint32_t aFlag,
141
                            const nsACString& aURL,
142
                            const nsACString& aFragment)
143
0
  {
144
0
    // Only check in debug build to prevent it from being used unexpectedly.
145
0
    MOZ_ASSERT(aFlag & nsIChannelEventSink::REDIRECT_INTERNAL);
146
0
147
0
    return SetURL(aURL, aFragment);
148
0
  }
149
150
  // AddURL should append the url into url list.
151
  // Normally we strip the fragment from the URL in Request::Constructor and
152
  // pass the fragment as the second argument into it.
153
  // If a fragment is present in the URL it must be stripped and passed in
154
  // separately.
155
  void
156
  AddURL(const nsACString& aURL, const nsACString& aFragment)
157
0
  {
158
0
    MOZ_ASSERT(!aURL.IsEmpty());
159
0
    MOZ_ASSERT(!aURL.Contains('#'));
160
0
161
0
    mURLList.AppendElement(aURL);
162
0
163
0
    mFragment.Assign(aFragment);
164
0
  }
165
  // Get the URL list without their fragments.
166
  void
167
  GetURLListWithoutFragment(nsTArray<nsCString>& aURLList)
168
0
  {
169
0
    aURLList.Assign(mURLList);
170
0
  }
171
  void
172
  GetReferrer(nsAString& aReferrer) const
173
  {
174
    aReferrer.Assign(mReferrer);
175
  }
176
177
  void
178
  SetReferrer(const nsAString& aReferrer)
179
  {
180
#ifdef DEBUG
181
    bool validReferrer = false;
182
    if (aReferrer.IsEmpty() ||
183
        aReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
184
      validReferrer = true;
185
    } else {
186
      nsCOMPtr<nsIURLParser> parser = do_GetService(NS_STDURLPARSER_CONTRACTID);
187
      if (!parser) {
188
        NS_WARNING("Could not get parser to validate URL!");
189
      } else {
190
        uint32_t schemePos;
191
        int32_t schemeLen;
192
        uint32_t authorityPos;
193
        int32_t authorityLen;
194
        uint32_t pathPos;
195
        int32_t pathLen;
196
197
        NS_ConvertUTF16toUTF8 ref(aReferrer);
198
        nsresult rv = parser->ParseURL(ref.get(), ref.Length(),
199
                                       &schemePos, &schemeLen,
200
                                       &authorityPos, &authorityLen,
201
                                       &pathPos, &pathLen);
202
        if (NS_FAILED(rv)) {
203
          NS_WARNING("Invalid referrer URL!");
204
        } else if (schemeLen < 0 || authorityLen < 0) {
205
          NS_WARNING("Invalid referrer URL!");
206
        } else {
207
          validReferrer = true;
208
        }
209
      }
210
    }
211
212
    MOZ_ASSERT(validReferrer);
213
#endif
214
215
    mReferrer.Assign(aReferrer);
216
  }
217
218
  ReferrerPolicy
219
  ReferrerPolicy_() const
220
  {
221
    return mReferrerPolicy;
222
  }
223
224
  void
225
  SetReferrerPolicy(ReferrerPolicy aReferrerPolicy)
226
  {
227
    mReferrerPolicy = aReferrerPolicy;
228
  }
229
230
  void
231
  SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
232
0
  {
233
0
    switch (aReferrerPolicy) {
234
0
      case net::RP_Unset:
235
0
        mReferrerPolicy = ReferrerPolicy::_empty;
236
0
        break;
237
0
      case net::RP_No_Referrer:
238
0
        mReferrerPolicy = ReferrerPolicy::No_referrer;
239
0
        break;
240
0
      case net::RP_No_Referrer_When_Downgrade:
241
0
        mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
242
0
        break;
243
0
      case net::RP_Origin:
244
0
        mReferrerPolicy = ReferrerPolicy::Origin;
245
0
        break;
246
0
      case net::RP_Origin_When_Crossorigin:
247
0
        mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
248
0
        break;
249
0
      case net::RP_Unsafe_URL:
250
0
        mReferrerPolicy = ReferrerPolicy::Unsafe_url;
251
0
        break;
252
0
      case net::RP_Same_Origin:
253
0
        mReferrerPolicy = ReferrerPolicy::Same_origin;
254
0
        break;
255
0
      case net::RP_Strict_Origin:
256
0
        mReferrerPolicy = ReferrerPolicy::Strict_origin;
257
0
        break;
258
0
      case net::RP_Strict_Origin_When_Cross_Origin:
259
0
        mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin;
260
0
        break;
261
0
      default:
262
0
        MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
263
0
        break;
264
0
    }
265
0
  }
266
267
  net::ReferrerPolicy
268
  GetReferrerPolicy()
269
0
  {
270
0
    switch (mReferrerPolicy) {
271
0
      case ReferrerPolicy::_empty:
272
0
        return net::RP_Unset;
273
0
      case ReferrerPolicy::No_referrer:
274
0
        return net::RP_No_Referrer;
275
0
      case ReferrerPolicy::No_referrer_when_downgrade:
276
0
        return net::RP_No_Referrer_When_Downgrade;
277
0
      case ReferrerPolicy::Origin:
278
0
        return net::RP_Origin;
279
0
      case ReferrerPolicy::Origin_when_cross_origin:
280
0
        return net::RP_Origin_When_Crossorigin;
281
0
      case ReferrerPolicy::Unsafe_url:
282
0
        return net::RP_Unsafe_URL;
283
0
      case ReferrerPolicy::Strict_origin:
284
0
        return net::RP_Strict_Origin;
285
0
      case ReferrerPolicy::Same_origin:
286
0
        return net::RP_Same_Origin;
287
0
      case ReferrerPolicy::Strict_origin_when_cross_origin:
288
0
        return net::RP_Strict_Origin_When_Cross_Origin;
289
0
      default:
290
0
        MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
291
0
        break;
292
0
    }
293
0
    return net::RP_Unset;
294
0
  }
295
296
  net::ReferrerPolicy
297
  GetEnvironmentReferrerPolicy() const
298
0
  {
299
0
    return mEnvironmentReferrerPolicy;
300
0
  }
301
302
  void
303
  SetEnvironmentReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
304
0
  {
305
0
    mEnvironmentReferrerPolicy = aReferrerPolicy;
306
0
  }
307
308
  bool
309
  SkipServiceWorker() const
310
0
  {
311
0
    return mSkipServiceWorker;
312
0
  }
313
314
  void
315
  SetSkipServiceWorker()
316
0
  {
317
0
    mSkipServiceWorker = true;
318
0
  }
319
320
  bool
321
  IsSynchronous() const
322
0
  {
323
0
    return mSynchronous;
324
0
  }
325
326
  RequestMode
327
  Mode() const
328
  {
329
    return mMode;
330
  }
331
332
  void
333
  SetMode(RequestMode aMode)
334
  {
335
    mMode = aMode;
336
  }
337
338
  RequestCredentials
339
  GetCredentialsMode() const
340
  {
341
    return mCredentialsMode;
342
  }
343
344
  void
345
  SetCredentialsMode(RequestCredentials aCredentialsMode)
346
  {
347
    mCredentialsMode = aCredentialsMode;
348
  }
349
350
  LoadTainting
351
  GetResponseTainting() const
352
0
  {
353
0
    return mResponseTainting;
354
0
  }
355
356
  void
357
  MaybeIncreaseResponseTainting(LoadTainting aTainting)
358
0
  {
359
0
    if (aTainting > mResponseTainting) {
360
0
      mResponseTainting = aTainting;
361
0
    }
362
0
  }
363
364
  RequestCache
365
  GetCacheMode() const
366
  {
367
    return mCacheMode;
368
  }
369
370
  void
371
  SetCacheMode(RequestCache aCacheMode)
372
  {
373
    mCacheMode = aCacheMode;
374
  }
375
376
  RequestRedirect
377
  GetRedirectMode() const
378
  {
379
    return mRedirectMode;
380
  }
381
382
  void
383
  SetRedirectMode(RequestRedirect aRedirectMode)
384
  {
385
    mRedirectMode = aRedirectMode;
386
  }
387
388
  const nsString&
389
  GetIntegrity() const
390
  {
391
    return mIntegrity;
392
  }
393
  void
394
  SetIntegrity(const nsAString& aIntegrity)
395
  {
396
    MOZ_ASSERT(mIntegrity.IsEmpty());
397
    mIntegrity.Assign(aIntegrity);
398
  }
399
400
  bool
401
  MozErrors() const
402
  {
403
    return mMozErrors;
404
  }
405
406
  void
407
  SetMozErrors()
408
0
  {
409
0
    mMozErrors = true;
410
0
  }
411
412
  const nsCString&
413
  GetFragment() const
414
  {
415
    return mFragment;
416
  }
417
418
  nsContentPolicyType
419
  ContentPolicyType() const
420
  {
421
    return mContentPolicyType;
422
  }
423
  void
424
  SetContentPolicyType(nsContentPolicyType aContentPolicyType);
425
426
  void
427
  OverrideContentPolicyType(nsContentPolicyType aContentPolicyType);
428
429
  RequestDestination
430
  Destination() const
431
  {
432
    return MapContentPolicyTypeToRequestDestination(mContentPolicyType);
433
  }
434
435
  bool
436
  UnsafeRequest() const
437
0
  {
438
0
    return mUnsafeRequest;
439
0
  }
440
441
  void
442
  SetUnsafeRequest()
443
0
  {
444
0
    mUnsafeRequest = true;
445
0
  }
446
447
  InternalHeaders*
448
  Headers()
449
  {
450
    return mHeaders;
451
  }
452
453
  bool
454
  ForceOriginHeader()
455
0
  {
456
0
    return mForceOriginHeader;
457
0
  }
458
459
  bool
460
  SameOriginDataURL() const
461
  {
462
    return mSameOriginDataURL;
463
  }
464
465
  void
466
  UnsetSameOriginDataURL()
467
  {
468
    mSameOriginDataURL = false;
469
  }
470
471
  void
472
  SetBody(nsIInputStream* aStream, int64_t aBodyLength)
473
  {
474
    // A request's body may not be reset once set.
475
    MOZ_ASSERT_IF(aStream, !mBodyStream);
476
    mBodyStream = aStream;
477
    mBodyLength = aBodyLength;
478
  }
479
480
  // Will return the original stream!
481
  // Use a tee or copy if you don't want to erase the original.
482
  void
483
  GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr)
484
  {
485
    nsCOMPtr<nsIInputStream> s = mBodyStream;
486
    s.forget(aStream);
487
488
    if (aBodyLength) {
489
      *aBodyLength = mBodyLength;
490
    }
491
  }
492
493
  void
494
  SetBodyLocalPath(nsAString& aLocalPath)
495
  {
496
    mBodyLocalPath = aLocalPath;
497
  }
498
499
  const nsAString&
500
  BodyLocalPath() const
501
0
  {
502
0
    return mBodyLocalPath;
503
0
  }
504
505
  // The global is used as the client for the new object.
506
  already_AddRefed<InternalRequest>
507
  GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
508
509
  bool
510
  WasCreatedByFetchEvent() const
511
0
  {
512
0
    return mCreatedByFetchEvent;
513
0
  }
514
515
  void
516
  SetCreatedByFetchEvent()
517
  {
518
    mCreatedByFetchEvent = true;
519
  }
520
521
  void
522
  ClearCreatedByFetchEvent()
523
0
  {
524
0
    mCreatedByFetchEvent = false;
525
0
  }
526
527
  bool
528
  IsNavigationRequest() const;
529
530
  bool
531
  IsWorkerRequest() const;
532
533
  bool
534
  IsClientRequest() const;
535
536
  void
537
  MaybeSkipCacheIfPerformingRevalidation();
538
539
  bool
540
  IsContentPolicyTypeOverridden() const
541
  {
542
    return mContentPolicyTypeOverridden;
543
  }
544
545
  static RequestMode
546
  MapChannelToRequestMode(nsIChannel* aChannel);
547
548
  static RequestCredentials
549
  MapChannelToRequestCredentials(nsIChannel* aChannel);
550
551
  // Takes ownership of the principal info.
552
  void
553
  SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
554
555
  const UniquePtr<mozilla::ipc::PrincipalInfo>&
556
  GetPrincipalInfo() const
557
0
  {
558
0
    return mPrincipalInfo;
559
0
  }
560
561
  const nsCString&
562
  GetPreferredAlternativeDataType() const
563
0
  {
564
0
    return mPreferredAlternativeDataType;
565
0
  }
566
567
  void
568
  SetPreferredAlternativeDataType(const nsACString& aDataType)
569
  {
570
    mPreferredAlternativeDataType = aDataType;
571
  }
572
573
private:
574
  // Does not copy mBodyStream.  Use fallible Clone() for complete copy.
575
  explicit InternalRequest(const InternalRequest& aOther);
576
577
  ~InternalRequest();
578
579
  // Map the content policy type to the associated fetch destination, as defined
580
  // by the spec at https://fetch.spec.whatwg.org/#concept-request-destination.
581
  // Note that while the HTML spec for the "Link" element and its "as" attribute
582
  // (https://html.spec.whatwg.org/#attr-link-as) reuse fetch's definition of
583
  // destination, and the Link class has an internal Link::AsDestination enum type,
584
  // the latter is only a support type to map the string values via
585
  // Link::ParseAsValue and Link::AsValueToContentPolicy to our canonical nsContentPolicyType.
586
  static RequestDestination
587
  MapContentPolicyTypeToRequestDestination(nsContentPolicyType aContentPolicyType);
588
589
  static bool
590
  IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType);
591
592
  static bool
593
  IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType);
594
595
  // It should only be called while there is a service-worker-internal-redirect.
596
  void
597
  SetURL(const nsACString& aURL, const nsACString& aFragment)
598
0
  {
599
0
    MOZ_ASSERT(!aURL.IsEmpty());
600
0
    MOZ_ASSERT(!aURL.Contains('#'));
601
0
    MOZ_ASSERT(mURLList.Length() > 0);
602
0
603
0
    mURLList.LastElement() = aURL;
604
0
    mFragment.Assign(aFragment);
605
0
  }
606
607
  nsCString mMethod;
608
  // mURLList: a list of one or more fetch URLs
609
  nsTArray<nsCString> mURLList;
610
  RefPtr<InternalHeaders> mHeaders;
611
  nsString mBodyLocalPath;
612
  nsCOMPtr<nsIInputStream> mBodyStream;
613
  int64_t mBodyLength;
614
615
  nsCString mPreferredAlternativeDataType;
616
617
  nsContentPolicyType mContentPolicyType;
618
619
  // Empty string: no-referrer
620
  // "about:client": client (default)
621
  // URL: an URL
622
  nsString mReferrer;
623
  ReferrerPolicy mReferrerPolicy;
624
625
  // This will be used for request created from Window or Worker contexts
626
  // In case there's no Referrer Policy in Request, this will be passed to
627
  // channel.
628
  // The Environment Referrer Policy should be net::ReferrerPolicy so that it
629
  // could be associated with nsIHttpChannel.
630
  net::ReferrerPolicy mEnvironmentReferrerPolicy;
631
  RequestMode mMode;
632
  RequestCredentials mCredentialsMode;
633
  MOZ_INIT_OUTSIDE_CTOR LoadTainting mResponseTainting;
634
  RequestCache mCacheMode;
635
  RequestRedirect mRedirectMode;
636
  nsString mIntegrity;
637
  bool mMozErrors;
638
  nsCString mFragment;
639
  MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
640
  MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
641
  MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;
642
  MOZ_INIT_OUTSIDE_CTOR bool mSameOriginDataURL;
643
  MOZ_INIT_OUTSIDE_CTOR bool mSkipServiceWorker;
644
  MOZ_INIT_OUTSIDE_CTOR bool mSynchronous;
645
  MOZ_INIT_OUTSIDE_CTOR bool mUnsafeRequest;
646
  MOZ_INIT_OUTSIDE_CTOR bool mUseURLCredentials;
647
  // This is only set when a Request object is created by a fetch event.  We
648
  // use it to check if Service Workers are simply fetching intercepted Request
649
  // objects without modifying them.
650
  bool mCreatedByFetchEvent = false;
651
  // This is only set when Request.overrideContentPolicyType() has been set.
652
  // It is illegal to pass such a Request object to a fetch() method unless
653
  // if the caller has chrome privileges.
654
  bool mContentPolicyTypeOverridden = false;
655
656
  UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
657
};
658
659
} // namespace dom
660
} // namespace mozilla
661
662
#endif // mozilla_dom_InternalRequest_h