summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/nsCORSListenerProxy.h
blob: 3f8c13ea641a816ef0224191e86d723ce216f929 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsCORSListenerProxy_h__
#define nsCORSListenerProxy_h__

#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIURI.h"
#include "nsTArray.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "mozilla/Attributes.h"
#include "mozilla/Atomics.h"
#include "mozilla/Mutex.h"

class nsIHttpChannel;
class nsIURI;
class nsIPrincipal;
class nsINetworkInterceptController;
class nsICorsPreflightCallback;

namespace mozilla {
namespace net {
class HttpChannelParent;
class nsHttpChannel;
}  // namespace net
}  // namespace mozilla

enum class DataURIHandling { Allow, Disallow };

enum class UpdateType {
  Default,
  StripRequestBodyHeader,
  InternalOrHSTSRedirect
};

class nsCORSListenerProxy final : public nsIStreamListener,
                                  public nsIInterfaceRequestor,
                                  public nsIChannelEventSink,
                                  public nsIThreadRetargetableStreamListener {
 public:
  nsCORSListenerProxy(nsIStreamListener* aOuter,
                      nsIPrincipal* aRequestingPrincipal,
                      bool aWithCredentials);

  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIREQUESTOBSERVER
  NS_DECL_NSISTREAMLISTENER
  NS_DECL_NSIINTERFACEREQUESTOR
  NS_DECL_NSICHANNELEVENTSINK
  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER

  static void Shutdown();
  static void ClearCache();
  static void ClearPrivateBrowsingCache();

  [[nodiscard]] nsresult Init(nsIChannel* aChannel,
                              DataURIHandling aAllowDataURI);

  void SetInterceptController(
      nsINetworkInterceptController* aInterceptController);

  // When CORS blocks a request, log the message to the web console, or the
  // browser console if no valid inner window ID is found.
  static void LogBlockedCORSRequest(uint64_t aInnerWindowID,
                                    bool aPrivateBrowsing,
                                    bool aFromChromeContext,
                                    const nsAString& aMessage,
                                    const nsACString& aCategory,
                                    bool aIsWarning = false);

 private:
  // Only HttpChannelParent can call RemoveFromCorsPreflightCache
  friend class mozilla::net::HttpChannelParent;
  // Only nsHttpChannel can invoke CORS preflights
  friend class mozilla::net::nsHttpChannel;

  static void RemoveFromCorsPreflightCache(
      nsIURI* aURI, nsIPrincipal* aRequestingPrincipal,
      const mozilla::OriginAttributes& aOriginAttributes);
  [[nodiscard]] static nsresult StartCORSPreflight(
      nsIChannel* aRequestChannel, nsICorsPreflightCallback* aCallback,
      nsTArray<nsCString>& aUnsafeHeaders, nsIChannel** aPreflightChannel);

  ~nsCORSListenerProxy() = default;

  [[nodiscard]] nsresult UpdateChannel(nsIChannel* aChannel,
                                       DataURIHandling aAllowDataURI,
                                       UpdateType aUpdateType);
  [[nodiscard]] nsresult CheckRequestApproved(nsIRequest* aRequest);
  [[nodiscard]] nsresult CheckPreflightNeeded(nsIChannel* aChannel,
                                              UpdateType aUpdateType);

  nsCOMPtr<nsIStreamListener> mOuterListener;
  // The principal that originally kicked off the request
  nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
  // The principal to use for our Origin header ("source origin" in spec terms).
  // This can get changed during redirects, unlike mRequestingPrincipal.
  nsCOMPtr<nsIPrincipal> mOriginHeaderPrincipal;
  nsCOMPtr<nsIInterfaceRequestor> mOuterNotificationCallbacks;
  nsCOMPtr<nsINetworkInterceptController> mInterceptController;
  bool mWithCredentials;
  mozilla::Atomic<bool, mozilla::Relaxed> mRequestApproved;
  // Please note that the member variable mHasBeenCrossSite may rely on the
  // promise that the CSP directive 'upgrade-insecure-requests' upgrades
  // an http: request to https: in nsHttpChannel::Connect() and hence
  // a request might not be marked as cross site request based on that promise.
  bool mHasBeenCrossSite;
  bool mIsRedirect = false;
  // Under e10s, logging happens in the child process. Keep a reference to the
  // creator nsIHttpChannel in order to find the way back to the child. Released
  // in OnStopRequest().
  nsCOMPtr<nsIHttpChannel> mHttpChannel;
#ifdef DEBUG
  bool mInited;
#endif

  // only locking mOuterListener, because it can be used on different threads.
  // We guarantee that OnStartRequest, OnDataAvailable and OnStopReques will be
  // called in order, but to make tsan happy we will lock mOuterListener.
  mutable mozilla::Mutex mMutex MOZ_UNANNOTATED;
};

#endif