DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (d38398e5144e)

VCS Links

RedirectRunnable

nsBaseChannel

Macros

Line Code
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 298 299 300
/* -*- 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();

  // start URI classifier if requested
  void ClassifyURI();

  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__