Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
* License, v. 2.0. If a copy of the MPL was not distributed with this
4
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#ifndef nsBaseChannel_h__
7
#define nsBaseChannel_h__
8
9
#include "mozilla/net/NeckoTargetHolder.h"
10
#include "mozilla/Maybe.h"
11
#include "mozilla/MozPromise.h"
12
#include "nsString.h"
13
#include "nsAutoPtr.h"
14
#include "nsCOMPtr.h"
15
#include "nsHashPropertyBag.h"
16
#include "nsInputStreamPump.h"
17
18
#include "nsIChannel.h"
19
#include "nsIURI.h"
20
#include "nsILoadGroup.h"
21
#include "nsILoadInfo.h"
22
#include "nsIStreamListener.h"
23
#include "nsIInterfaceRequestor.h"
24
#include "nsIProgressEventSink.h"
25
#include "nsITransport.h"
26
#include "nsIAsyncVerifyRedirectCallback.h"
27
#include "nsIThreadRetargetableRequest.h"
28
#include "nsIThreadRetargetableStreamListener.h"
29
#include "mozilla/net/PrivateBrowsingChannel.h"
30
#include "nsThreadUtils.h"
31
32
class nsIInputStream;
33
34
//-----------------------------------------------------------------------------
35
// nsBaseChannel is designed to be subclassed. The subclass is responsible for
36
// implementing the OpenContentStream method, which will be called by the
37
// nsIChannel::AsyncOpen and nsIChannel::Open implementations.
38
//
39
// nsBaseChannel implements nsIInterfaceRequestor to provide a convenient way
40
// for subclasses to query both the nsIChannel::notificationCallbacks and
41
// nsILoadGroup::notificationCallbacks for supported interfaces.
42
//
43
// nsBaseChannel implements nsITransportEventSink to support progress & status
44
// notifications generated by the transport layer.
45
//
46
// nsBaseChannel will only implement nsIIdentChannel if mChannelId is set.
47
// It is required for devtools to capture transfer information for network
48
// connection, and not all nsBaseChannel implementation should be logged.
49
// Currently only DocumentChannelChild implements nsIIdentChannel via
50
// nsBaseChannel.
51
52
class nsBaseChannel
53
: public nsHashPropertyBag,
54
public nsIIdentChannel,
55
public nsIThreadRetargetableRequest,
56
public nsIInterfaceRequestor,
57
public nsITransportEventSink,
58
public nsIAsyncVerifyRedirectCallback,
59
public mozilla::net::PrivateBrowsingChannel<nsBaseChannel>,
60
public mozilla::net::NeckoTargetHolder,
61
protected nsIStreamListener,
62
protected nsIThreadRetargetableStreamListener {
63
public:
64
NS_DECL_ISUPPORTS_INHERITED
65
NS_DECL_NSIREQUEST
66
NS_DECL_NSICHANNEL
67
NS_DECL_NSIIDENTCHANNEL
68
NS_DECL_NSIINTERFACEREQUESTOR
69
NS_DECL_NSITRANSPORTEVENTSINK
70
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
71
NS_DECL_NSITHREADRETARGETABLEREQUEST
72
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
73
74
nsBaseChannel();
75
76
// This method must be called to initialize the basechannel instance.
77
nsresult Init() { return NS_OK; }
78
79
protected:
80
// -----------------------------------------------
81
// Methods to be implemented by the derived class:
82
83
virtual ~nsBaseChannel();
84
85
using BlockingPromise = mozilla::MozPromise<nsresult, nsresult, true>;
86
87
private:
88
// Implemented by subclass to supply data stream. The parameter, async, is
89
// true when called from nsIChannel::AsyncOpen and false otherwise. When
90
// async is true, the resulting stream will be used with a nsIInputStreamPump
91
// instance. This means that if it is a non-blocking stream that supports
92
// nsIAsyncInputStream that it will be read entirely on the main application
93
// thread, and its AsyncWait method will be called whenever ReadSegments
94
// returns NS_BASE_STREAM_WOULD_BLOCK. Otherwise, if the stream is blocking,
95
// then it will be read on one of the background I/O threads, and it does not
96
// need to implement ReadSegments. If async is false, this method may return
97
// NS_ERROR_NOT_IMPLEMENTED to cause the basechannel to implement Open in
98
// terms of AsyncOpen (see NS_ImplementChannelOpen).
99
// A callee is allowed to return an nsIChannel instead of an nsIInputStream.
100
// That case will be treated as a redirect to the new channel. By default
101
// *channel will be set to null by the caller, so callees who don't want to
102
// return one an just not touch it.
103
virtual nsresult OpenContentStream(bool async, nsIInputStream** stream,
104
nsIChannel** channel) = 0;
105
106
// Implemented by subclass to begin pumping data for an async channel, in
107
// lieu of returning a stream. If implemented, OpenContentStream will never
108
// be called for async channels. If not implemented, AsyncOpen will fall
109
// back to OpenContentStream.
110
//
111
// On success, the callee must begin pumping data to the stream listener,
112
// and at some point call OnStartRequest followed by OnStopRequest.
113
// Additionally, it may provide a request object which may be used to
114
// suspend, resume, and cancel the underlying request.
115
virtual nsresult BeginAsyncRead(nsIStreamListener* listener,
116
nsIRequest** request) {
117
return NS_ERROR_NOT_IMPLEMENTED;
118
}
119
120
// This method may return a promise that will keep the input stream pump
121
// suspended until the promise is resolved or rejected. On resolution the
122
// pump is resumed. On rejection the channel is canceled with the resulting
123
// error and then the pump is also resumed to propagate the error to the
124
// channel listener. Use it to do any asynchronous/background tasks you need
125
// to finish prior calling OnStartRequest of the listener. This method is
126
// called right after OpenContentStream() with async == true, after the input
127
// stream pump has already been called asyncRead().
128
virtual nsresult ListenerBlockingPromise(BlockingPromise** aPromise) {
129
NS_ENSURE_ARG(aPromise);
130
*aPromise = nullptr;
131
return NS_OK;
132
}
133
134
// The basechannel calls this method from its OnTransportStatus method to
135
// determine whether to call nsIProgressEventSink::OnStatus in addition to
136
// nsIProgressEventSink::OnProgress. This method may be overriden by the
137
// subclass to enable nsIProgressEventSink::OnStatus events. If this method
138
// returns true, then the statusArg out param specifies the "statusArg" value
139
// to pass to the OnStatus method. By default, OnStatus messages are
140
// suppressed. The status parameter passed to this method is the status value
141
// from the OnTransportStatus method.
142
virtual bool GetStatusArg(nsresult status, nsString& statusArg) {
143
return false;
144
}
145
146
// Called when the callbacks available to this channel may have changed.
147
virtual void OnCallbacksChanged() {}
148
149
// Called when our channel is done, to allow subclasses to drop resources.
150
virtual void OnChannelDone() {}
151
152
public:
153
// ----------------------------------------------
154
// Methods provided for use by the derived class:
155
156
// Redirect to another channel. This method takes care of notifying
157
// observers of this redirect as well as of opening the new channel, if asked
158
// to do so. It also cancels |this| with the status code
159
// NS_BINDING_REDIRECTED. A failure return from this method means that the
160
// redirect could not be performed (no channel was opened; this channel
161
// wasn't canceled.) The redirectFlags parameter consists of the flag values
162
// defined on nsIChannelEventSink.
163
nsresult Redirect(nsIChannel* newChannel, uint32_t redirectFlags,
164
bool openNewChannel);
165
166
// Tests whether a type hint was set. Subclasses can use this to decide
167
// whether to call SetContentType.
168
// NOTE: This is only reliable if the subclass didn't itself call
169
// SetContentType, and should also not be called after OpenContentStream.
170
bool HasContentTypeHint() const;
171
172
// The URI member should be initialized before the channel is used, and then
173
// it should never be changed again until the channel is destroyed.
174
nsIURI* URI() { return mURI; }
175
void SetURI(nsIURI* uri) {
176
NS_ASSERTION(uri, "must specify a non-null URI");
177
NS_ASSERTION(!mURI, "must not modify URI");
178
NS_ASSERTION(!mOriginalURI, "how did that get set so early?");
179
mURI = uri;
180
mOriginalURI = uri;
181
}
182
nsIURI* OriginalURI() { return mOriginalURI; }
183
184
// The security info is a property of the transport-layer, which should be
185
// assigned by the subclass.
186
nsISupports* SecurityInfo() { return mSecurityInfo; }
187
void SetSecurityInfo(nsISupports* info) { mSecurityInfo = info; }
188
189
// Test the load flags
190
bool HasLoadFlag(uint32_t flag) { return (mLoadFlags & flag) != 0; }
191
192
// This is a short-cut to calling nsIRequest::IsPending()
193
virtual bool Pending() const {
194
return mPumpingData || mWaitingOnAsyncRedirect;
195
}
196
197
// Helper function for querying the channel's notification callbacks.
198
template <class T>
199
void GetCallback(nsCOMPtr<T>& result) {
200
GetInterface(NS_GET_TEMPLATE_IID(T), getter_AddRefs(result));
201
}
202
203
// If a subclass does not want to feed transport-layer progress events to the
204
// base channel via nsITransportEventSink, then it may set this flag to cause
205
// the base channel to synthesize progress events when it receives data from
206
// the content stream. By default, progress events are not synthesized.
207
void EnableSynthesizedProgressEvents(bool enable) {
208
mSynthProgressEvents = enable;
209
}
210
211
// Some subclasses may wish to manually insert a stream listener between this
212
// and the channel's listener. The following methods make that possible.
213
void SetStreamListener(nsIStreamListener* listener) { mListener = listener; }
214
nsIStreamListener* StreamListener() { return mListener; }
215
216
// Pushes a new stream converter in front of the channel's stream listener.
217
// The fromType and toType values are passed to nsIStreamConverterService's
218
// AsyncConvertData method. If invalidatesContentLength is true, then the
219
// channel's content-length property will be assigned a value of -1. This is
220
// necessary when the converter changes the length of the resulting data
221
// stream, which is almost always the case for a "stream converter" ;-)
222
// This function optionally returns a reference to the new converter.
223
nsresult PushStreamConverter(const char* fromType, const char* toType,
224
bool invalidatesContentLength = true,
225
nsIStreamListener** converter = nullptr);
226
227
protected:
228
void DisallowThreadRetargeting() { mAllowThreadRetargeting = false; }
229
230
virtual void SetupNeckoTarget();
231
232
private:
233
NS_DECL_NSISTREAMLISTENER
234
NS_DECL_NSIREQUESTOBSERVER
235
236
// Called to setup mPump and call AsyncRead on it.
237
nsresult BeginPumpingData();
238
239
// Called when the callbacks available to this channel may have changed.
240
void CallbacksChanged() {
241
mProgressSink = nullptr;
242
mQueriedProgressSink = false;
243
OnCallbacksChanged();
244
}
245
246
// Called when our channel is done. This should drop no-longer-needed
247
// pointers.
248
void ChannelDone() {
249
mListener = nullptr;
250
OnChannelDone();
251
}
252
253
// Handle an async redirect callback. This will only be called if we
254
// returned success from AsyncOpen while posting a redirect runnable.
255
void HandleAsyncRedirect(nsIChannel* newChannel);
256
void ContinueHandleAsyncRedirect(nsresult result);
257
nsresult ContinueRedirect();
258
259
// start URI classifier if requested
260
void ClassifyURI();
261
262
class RedirectRunnable : public mozilla::Runnable {
263
public:
264
RedirectRunnable(nsBaseChannel* chan, nsIChannel* newChannel)
265
: mozilla::Runnable("nsBaseChannel::RedirectRunnable"),
266
mChannel(chan),
267
mNewChannel(newChannel) {
268
MOZ_ASSERT(newChannel, "Must have channel to redirect to");
269
}
270
271
NS_IMETHOD Run() override {
272
mChannel->HandleAsyncRedirect(mNewChannel);
273
return NS_OK;
274
}
275
276
private:
277
RefPtr<nsBaseChannel> mChannel;
278
nsCOMPtr<nsIChannel> mNewChannel;
279
};
280
friend class RedirectRunnable;
281
282
RefPtr<nsInputStreamPump> mPump;
283
RefPtr<nsIRequest> mRequest;
284
bool mPumpingData;
285
nsCOMPtr<nsIProgressEventSink> mProgressSink;
286
nsCOMPtr<nsIURI> mOriginalURI;
287
nsCOMPtr<nsISupports> mOwner;
288
nsCOMPtr<nsISupports> mSecurityInfo;
289
nsCOMPtr<nsIChannel> mRedirectChannel;
290
nsCString mContentType;
291
nsCString mContentCharset;
292
uint32_t mLoadFlags;
293
bool mQueriedProgressSink;
294
bool mSynthProgressEvents;
295
bool mAllowThreadRetargeting;
296
bool mWaitingOnAsyncRedirect;
297
bool mOpenRedirectChannel;
298
uint32_t mRedirectFlags;
299
300
protected:
301
nsCOMPtr<nsIURI> mURI;
302
nsCOMPtr<nsILoadGroup> mLoadGroup;
303
nsCOMPtr<nsILoadInfo> mLoadInfo;
304
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
305
nsCOMPtr<nsIStreamListener> mListener;
306
nsresult mStatus;
307
uint32_t mContentDispositionHint;
308
nsAutoPtr<nsString> mContentDispositionFilename;
309
int64_t mContentLength;
310
mozilla::Maybe<uint64_t> mChannelId;
311
bool mWasOpened;
312
313
friend class mozilla::net::PrivateBrowsingChannel<nsBaseChannel>;
314
};
315
316
#endif // !nsBaseChannel_h__