Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/InterceptedHttpChannel.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 sw=2 ts=8 et 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_net_InterceptedHttpChannel_h
8
#define mozilla_net_InterceptedHttpChannel_h
9
10
#include "HttpBaseChannel.h"
11
#include "nsINetworkInterceptController.h"
12
#include "nsIInputStream.h"
13
#include "nsICacheInfoChannel.h"
14
#include "nsIChannelWithDivertableParentListener.h"
15
#include "nsIThreadRetargetableRequest.h"
16
17
namespace mozilla {
18
namespace net {
19
20
// This class represents an http channel that is being intercepted by a
21
// ServiceWorker.  This means that when the channel is opened a FetchEvent
22
// will be fired on the ServiceWorker thread.  The channel will complete
23
// depending on what the worker does.  The options are:
24
//
25
// 1. If the ServiceWorker does not handle the FetchEvent or does not call
26
//    FetchEvent.respondWith(), then the channel needs to fall back to a
27
//    normal request.  When this happens ResetInterception() is called and
28
//    the channel will perform an internal redirect back to an nsHttpChannel.
29
//
30
// 2. If the ServiceWorker provides a Response to FetchEvent.respondWith()
31
//    then the status, headers, and body must be synthesized.  When
32
//    FinishSynthesizedResponse() is called the synthesized data must be
33
//    reported back to the channel listener.  This is handled in a few
34
//    different ways:
35
//      a. If a redirect was synthesized, then we perform the redirect to
36
//         a new nsHttpChannel.  This new channel might trigger yet another
37
//         interception.
38
//      b. If a same-origin or CORS Response was synthesized, then we simply
39
//         crate an nsInputStreamPump to process it and call back to the
40
//         listener.
41
//      c. If an opaque Response was synthesized, then we perform an internal
42
//         redirect to a new InterceptedHttpChannel using the cross-origin URL.
43
//         When this new channel is opened, it then creates a pump as in case
44
//         (b).  The extra redirect here is to make sure the various listeners
45
//         treat the result as unsafe cross-origin data.
46
//
47
// 3. If an error occurs, such as the ServiceWorker passing garbage to
48
//    FetchEvent.respondWith(), then CancelInterception() is called.  This is
49
//    handled the same as a normal nsIChannel::Cancel() call.  We abort the
50
//    channel and end up calling OnStopRequest() with an error code.
51
class InterceptedHttpChannel final : public HttpBaseChannel
52
                                   , public HttpAsyncAborter<InterceptedHttpChannel>
53
                                   , public nsIInterceptedChannel
54
                                   , public nsICacheInfoChannel
55
                                   , public nsIAsyncVerifyRedirectCallback
56
                                   , public nsIStreamListener
57
                                   , public nsIChannelWithDivertableParentListener
58
                                   , public nsIThreadRetargetableRequest
59
                                   , public nsIThreadRetargetableStreamListener
60
{
61
  NS_DECL_ISUPPORTS_INHERITED
62
  NS_DECL_NSIINTERCEPTEDCHANNEL
63
  NS_DECL_NSICACHEINFOCHANNEL
64
  NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
65
  NS_DECL_NSIREQUESTOBSERVER
66
  NS_DECL_NSISTREAMLISTENER
67
  NS_DECL_NSICHANNELWITHDIVERTABLEPARENTLISTENER
68
  NS_DECL_NSITHREADRETARGETABLEREQUEST
69
  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
70
71
private:
72
  friend class HttpAsyncAborter<InterceptedHttpChannel>;
73
74
  UniquePtr<nsHttpResponseHead> mSynthesizedResponseHead;
75
  nsCOMPtr<nsIChannel> mRedirectChannel;
76
  nsCOMPtr<nsIInputStream> mBodyReader;
77
  nsCOMPtr<nsISupports> mReleaseHandle;
78
  nsCOMPtr<nsIProgressEventSink> mProgressSink;
79
  nsCOMPtr<nsIInterceptedBodyCallback> mBodyCallback;
80
  nsCOMPtr<nsICacheInfoChannel> mSynthesizedCacheInfo;
81
  RefPtr<nsInputStreamPump> mPump;
82
  RefPtr<ADivertableParentChannel> mParentChannel;
83
  TimeStamp mFinishResponseStart;
84
  TimeStamp mFinishResponseEnd;
85
  Atomic<int64_t> mProgress;
86
  int64_t mProgressReported;
87
  int64_t mSynthesizedStreamLength;
88
  uint64_t mResumeStartPos;
89
  nsCString mResumeEntityId;
90
  nsString mStatusHost;
91
  enum {
92
    Invalid = 0,
93
    Synthesized,
94
    Reset
95
  } mSynthesizedOrReset;
96
  Atomic<bool> mCallingStatusAndProgress;
97
  bool mDiverting;
98
99
  InterceptedHttpChannel(PRTime aCreationTime,
100
                         const TimeStamp& aCreationTimestamp,
101
                         const TimeStamp& aAsyncOpenTimestamp);
102
0
  ~InterceptedHttpChannel() = default;
103
104
  virtual void
105
  ReleaseListeners() override;
106
107
  virtual MOZ_MUST_USE nsresult
108
  SetupReplacementChannel(nsIURI *aURI, nsIChannel *aChannel,
109
                          bool aPreserveMethod,
110
                          uint32_t aRedirectFlags) override;
111
112
  void
113
  AsyncOpenInternal();
114
115
  bool
116
  ShouldRedirect() const;
117
118
  nsresult
119
  FollowSyntheticRedirect();
120
121
  // If the response's URL is different from the request's then do a service
122
  // worker redirect. If Response.redirected is false we do an internal
123
  // redirect. Otherwise, if Response.redirect is true do a non-internal
124
  // redirect so end consumers detect the redirected state.
125
  nsresult
126
  RedirectForResponseURL(nsIURI* aResponseURI, bool aResponseRedirected);
127
128
  nsresult
129
  StartPump();
130
131
  nsresult
132
  OpenRedirectChannel();
133
134
  void
135
  MaybeCallStatusAndProgress();
136
137
  void
138
  MaybeCallBodyCallback();
139
140
public:
141
  static already_AddRefed<InterceptedHttpChannel>
142
  CreateForInterception(PRTime aCreationTime, const TimeStamp& aCreationTimestamp,
143
                        const TimeStamp& aAsyncOpenTimestamp);
144
145
  static already_AddRefed<InterceptedHttpChannel>
146
  CreateForSynthesis(const nsHttpResponseHead* aHead, nsIInputStream* aBody,
147
                     nsIInterceptedBodyCallback* aBodyCallback,
148
                     PRTime aCreationTime,
149
                     const TimeStamp& aCreationTimestamp,
150
                     const TimeStamp& aAsyncOpenTimestamp);
151
152
  NS_IMETHOD
153
  Cancel(nsresult aStatus) override;
154
155
  NS_IMETHOD
156
  Suspend(void) override;
157
158
  NS_IMETHOD
159
  Resume(void) override;
160
161
  NS_IMETHOD
162
  GetSecurityInfo(nsISupports * *aSecurityInfo) override;
163
164
  NS_IMETHOD
165
  AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) override;
166
167
  NS_IMETHOD
168
  AsyncOpen2(nsIStreamListener *aListener) override;
169
170
  NS_IMETHOD
171
  LogBlockedCORSRequest(const nsAString & aMessage, const nsACString& aCategory) override;
172
173
  NS_IMETHOD
174
  SetupFallbackChannel(const char * aFallbackKey) override;
175
176
  NS_IMETHOD
177
  SetPriority(int32_t aPriority) override;
178
179
  NS_IMETHOD
180
  SetClassFlags(uint32_t aClassFlags) override;
181
182
  NS_IMETHOD
183
  ClearClassFlags(uint32_t flags) override;
184
185
  NS_IMETHOD
186
  AddClassFlags(uint32_t flags) override;
187
188
  NS_IMETHOD
189
  ResumeAt(uint64_t startPos, const nsACString & entityID) override;
190
191
  void
192
  DoNotifyListenerCleanup() override;
193
194
  void
195
  DoAsyncAbort(nsresult aStatus) override;
196
};
197
198
} // namespace net
199
} // namespace mozilla
200
201
#endif // mozilla_net_InterceptedHttpChannel_h