summaryrefslogtreecommitdiff
path: root/netwerk/base/nsBaseChannel.h
blob: 390a492f9b512beb7e2aad1fe720b0a46793943e (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 nsBaseChannel_h__
#define nsBaseChannel_h__

#include "nsString.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsHashPropertyBag.h"
#include "nsInputStreamPump.h"

#include "nsIChannel.h"
#include "nsIURI.h"
#include "nsILoadGroup.h"
#include "nsILoadInfo.h"
#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsIProgressEventSink.h"
#include "nsITransport.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "PrivateBrowsingChannel.h"
#include "nsThreadUtils.h"

class nsIInputStream;

//-----------------------------------------------------------------------------
// nsBaseChannel is designed to be subclassed.  The subclass is responsible for
// implementing the OpenContentStream method, which will be called by the
// nsIChannel::AsyncOpen and nsIChannel::Open implementations.
//
// nsBaseChannel implements nsIInterfaceRequestor to provide a convenient way
// for subclasses to query both the nsIChannel::notificationCallbacks and
// nsILoadGroup::notificationCallbacks for supported interfaces.
//
// nsBaseChannel implements nsITransportEventSink to support progress & status
// notifications generated by the transport layer.

class nsBaseChannel : public nsHashPropertyBag
                    , public nsIChannel
                    , public nsIThreadRetargetableRequest
                    , public nsIInterfaceRequestor
                    , public nsITransportEventSink
                    , public nsIAsyncVerifyRedirectCallback
                    , public mozilla::net::PrivateBrowsingChannel<nsBaseChannel>
                    , protected nsIStreamListener
                    , protected nsIThreadRetargetableStreamListener
{
public:
  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSIREQUEST
  NS_DECL_NSICHANNEL
  NS_DECL_NSIINTERFACEREQUESTOR
  NS_DECL_NSITRANSPORTEVENTSINK
  NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
  NS_DECL_NSITHREADRETARGETABLEREQUEST
  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER

  nsBaseChannel(); 

  // This method must be called to initialize the basechannel instance.
  nsresult Init() {
    return NS_OK;
  }

protected:
  // -----------------------------------------------
  // Methods to be implemented by the derived class:

  virtual ~nsBaseChannel();

private:
  // Implemented by subclass to supply data stream.  The parameter, async, is
  // true when called from nsIChannel::AsyncOpen and false otherwise.  When
  // async is true, the resulting stream will be used with a nsIInputStreamPump
  // instance.  This means that if it is a non-blocking stream that supports
  // nsIAsyncInputStream that it will be read entirely on the main application
  // thread, and its AsyncWait method will be called whenever ReadSegments
  // returns NS_BASE_STREAM_WOULD_BLOCK.  Otherwise, if the stream is blocking,
  // then it will be read on one of the background I/O threads, and it does not
  // need to implement ReadSegments.  If async is false, this method may return
  // NS_ERROR_NOT_IMPLEMENTED to cause the basechannel to implement Open in
  // terms of AsyncOpen (see NS_ImplementChannelOpen).
  // A callee is allowed to return an nsIChannel instead of an nsIInputStream.
  // That case will be treated as a redirect to the new channel.  By default
  // *channel will be set to null by the caller, so callees who don't want to
  // return one an just not touch it.
  virtual nsresult OpenContentStream(bool async, nsIInputStream **stream,
                                     nsIChannel** channel) = 0;

  // The basechannel calls this method from its OnTransportStatus method to
  // determine whether to call nsIProgressEventSink::OnStatus in addition to
  // nsIProgressEventSink::OnProgress.  This method may be overriden by the
  // subclass to enable nsIProgressEventSink::OnStatus events.  If this method
  // returns true, then the statusArg out param specifies the "statusArg" value
  // to pass to the OnStatus method.  By default, OnStatus messages are
  // suppressed.  The status parameter passed to this method is the status value
  // from the OnTransportStatus method.
  virtual bool GetStatusArg(nsresult status, nsString &statusArg) {
    return false;
  }

  // Called when the callbacks available to this channel may have changed.
  virtual void OnCallbacksChanged() {
  }

  // Called when our channel is done, to allow subclasses to drop resources.
  virtual void OnChannelDone() {
  }

public:
  // ----------------------------------------------
  // Methods provided for use by the derived class:

  // Redirect to another channel.  This method takes care of notifying
  // observers of this redirect as well as of opening the new channel, if asked
  // to do so.  It also cancels |this| with the status code
  // NS_BINDING_REDIRECTED.  A failure return from this method means that the
  // redirect could not be performed (no channel was opened; this channel
  // wasn't canceled.)  The redirectFlags parameter consists of the flag values
  // defined on nsIChannelEventSink.
  nsresult Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
                    bool openNewChannel);

  // Tests whether a type hint was set. Subclasses can use this to decide
  // whether to call SetContentType.
  // NOTE: This is only reliable if the subclass didn't itself call
  // SetContentType, and should also not be called after OpenContentStream.
  bool HasContentTypeHint() const;

  // The URI member should be initialized before the channel is used, and then
  // it should never be changed again until the channel is destroyed.
  nsIURI *URI() {
    return mURI;
  }
  void SetURI(nsIURI *uri) {
    NS_ASSERTION(uri, "must specify a non-null URI");
    NS_ASSERTION(!mURI, "must not modify URI");
    NS_ASSERTION(!mOriginalURI, "how did that get set so early?");
    mURI = uri;
    mOriginalURI = uri;
  }
  nsIURI *OriginalURI() {
    return mOriginalURI;
  }

  // The security info is a property of the transport-layer, which should be
  // assigned by the subclass.
  nsISupports *SecurityInfo() {
    return mSecurityInfo; 
  }
  void SetSecurityInfo(nsISupports *info) {
    mSecurityInfo = info;
  }

  // Test the load flags
  bool HasLoadFlag(uint32_t flag) {
    return (mLoadFlags & flag) != 0;
  }

  // This is a short-cut to calling nsIRequest::IsPending()
  virtual bool Pending() const {
    return mPump || mWaitingOnAsyncRedirect;
 }

  // Helper function for querying the channel's notification callbacks.
  template <class T> void GetCallback(nsCOMPtr<T> &result) {
    GetInterface(NS_GET_TEMPLATE_IID(T), getter_AddRefs(result));
  }

  // Helper function for calling QueryInterface on this.
  nsQueryInterface do_QueryInterface() {
    return nsQueryInterface(static_cast<nsIChannel *>(this));
  }
  // MSVC needs this:
  nsQueryInterface do_QueryInterface(nsISupports *obj) {
    return nsQueryInterface(obj);
  }

  // If a subclass does not want to feed transport-layer progress events to the
  // base channel via nsITransportEventSink, then it may set this flag to cause
  // the base channel to synthesize progress events when it receives data from
  // the content stream.  By default, progress events are not synthesized.
  void EnableSynthesizedProgressEvents(bool enable) {
    mSynthProgressEvents = enable;
  }

  // Some subclasses may wish to manually insert a stream listener between this
  // and the channel's listener.  The following methods make that possible.
  void SetStreamListener(nsIStreamListener *listener) {
    mListener = listener;
  }
  nsIStreamListener *StreamListener() {
    return mListener;
  }

  // Pushes a new stream converter in front of the channel's stream listener.
  // The fromType and toType values are passed to nsIStreamConverterService's
  // AsyncConvertData method.  If invalidatesContentLength is true, then the
  // channel's content-length property will be assigned a value of -1.  This is
  // necessary when the converter changes the length of the resulting data
  // stream, which is almost always the case for a "stream converter" ;-)
  // This function optionally returns a reference to the new converter.
  nsresult PushStreamConverter(const char *fromType, const char *toType,
                               bool invalidatesContentLength = true,
                               nsIStreamListener **converter = nullptr);

protected:
  void DisallowThreadRetargeting() {
    mAllowThreadRetargeting = false;
  }

private:
  NS_DECL_NSISTREAMLISTENER
  NS_DECL_NSIREQUESTOBSERVER

  // Called to setup mPump and call AsyncRead on it.
  nsresult BeginPumpingData();

  // Called when the callbacks available to this channel may have changed.
  void CallbacksChanged() {
    mProgressSink = nullptr;
    mQueriedProgressSink = false;
    OnCallbacksChanged();
  }

  // Called when our channel is done.  This should drop no-longer-needed pointers.
  void ChannelDone() {
      mListener = nullptr;
      mListenerContext = nullptr;
      OnChannelDone();
  }

  // Handle an async redirect callback.  This will only be called if we
  // returned success from AsyncOpen while posting a redirect runnable.
  void HandleAsyncRedirect(nsIChannel* newChannel);
  void ContinueHandleAsyncRedirect(nsresult result);
  nsresult ContinueRedirect();

  class RedirectRunnable : public mozilla::Runnable
  {
  public:
    RedirectRunnable(nsBaseChannel* chan, nsIChannel* newChannel)
      : mChannel(chan), mNewChannel(newChannel)
    {
      NS_PRECONDITION(newChannel, "Must have channel to redirect to");
    }

    NS_IMETHOD Run() override
    {
      mChannel->HandleAsyncRedirect(mNewChannel);
      return NS_OK;
    }

  private:
    RefPtr<nsBaseChannel> mChannel;
    nsCOMPtr<nsIChannel> mNewChannel;
  };
  friend class RedirectRunnable;

  RefPtr<nsInputStreamPump>         mPump;
  nsCOMPtr<nsIProgressEventSink>      mProgressSink;
  nsCOMPtr<nsIURI>                    mOriginalURI;
  nsCOMPtr<nsISupports>               mOwner;
  nsCOMPtr<nsISupports>               mSecurityInfo;
  nsCOMPtr<nsIChannel>                mRedirectChannel;
  nsCString                           mContentType;
  nsCString                           mContentCharset;
  uint32_t                            mLoadFlags;
  bool                                mQueriedProgressSink;
  bool                                mSynthProgressEvents;
  bool                                mAllowThreadRetargeting;
  bool                                mWaitingOnAsyncRedirect;
  bool                                mOpenRedirectChannel;
  uint32_t                            mRedirectFlags;

protected:
  nsCOMPtr<nsIURI>                    mURI;
  nsCOMPtr<nsILoadGroup>              mLoadGroup;
  nsCOMPtr<nsILoadInfo>               mLoadInfo;
  nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
  nsCOMPtr<nsIStreamListener>         mListener;
  nsCOMPtr<nsISupports>               mListenerContext;
  nsresult                            mStatus;
  uint32_t                            mContentDispositionHint;
  nsAutoPtr<nsString>                 mContentDispositionFilename;
  int64_t                             mContentLength;
  bool                                mWasOpened;

  friend class mozilla::net::PrivateBrowsingChannel<nsBaseChannel>;
};

#endif // !nsBaseChannel_h__