1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is Google Inc.
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Darin Fisher <darin@meer.net>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsBaseChannel_h__
39 : #define nsBaseChannel_h__
40 :
41 : #include "nsString.h"
42 : #include "nsAutoPtr.h"
43 : #include "nsCOMPtr.h"
44 : #include "nsHashPropertyBag.h"
45 : #include "nsInputStreamPump.h"
46 :
47 : #include "nsIChannel.h"
48 : #include "nsIInputStream.h"
49 : #include "nsIURI.h"
50 : #include "nsILoadGroup.h"
51 : #include "nsIStreamListener.h"
52 : #include "nsIInterfaceRequestor.h"
53 : #include "nsIProgressEventSink.h"
54 : #include "nsITransport.h"
55 : #include "nsIAsyncVerifyRedirectCallback.h"
56 : #include "nsThreadUtils.h"
57 :
58 : //-----------------------------------------------------------------------------
59 : // nsBaseChannel is designed to be subclassed. The subclass is responsible for
60 : // implementing the OpenContentStream method, which will be called by the
61 : // nsIChannel::AsyncOpen and nsIChannel::Open implementations.
62 : //
63 : // nsBaseChannel implements nsIInterfaceRequestor to provide a convenient way
64 : // for subclasses to query both the nsIChannel::notificationCallbacks and
65 : // nsILoadGroup::notificationCallbacks for supported interfaces.
66 : //
67 : // nsBaseChannel implements nsITransportEventSink to support progress & status
68 : // notifications generated by the transport layer.
69 :
70 : class nsBaseChannel : public nsHashPropertyBag
71 : , public nsIChannel
72 : , public nsIInterfaceRequestor
73 : , public nsITransportEventSink
74 : , public nsIAsyncVerifyRedirectCallback
75 : , private nsIStreamListener
76 : {
77 : public:
78 : NS_DECL_ISUPPORTS_INHERITED
79 : NS_DECL_NSIREQUEST
80 : NS_DECL_NSICHANNEL
81 : NS_DECL_NSIINTERFACEREQUESTOR
82 : NS_DECL_NSITRANSPORTEVENTSINK
83 : NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
84 :
85 : nsBaseChannel();
86 :
87 : // This method must be called to initialize the basechannel instance.
88 53433 : nsresult Init() {
89 53433 : return nsHashPropertyBag::Init();
90 : }
91 :
92 : protected:
93 : // -----------------------------------------------
94 : // Methods to be implemented by the derived class:
95 :
96 106862 : virtual ~nsBaseChannel() {}
97 :
98 : private:
99 : // Implemented by subclass to supply data stream. The parameter, async, is
100 : // true when called from nsIChannel::AsyncOpen and false otherwise. When
101 : // async is true, the resulting stream will be used with a nsIInputStreamPump
102 : // instance. This means that if it is a non-blocking stream that supports
103 : // nsIAsyncInputStream that it will be read entirely on the main application
104 : // thread, and its AsyncWait method will be called whenever ReadSegments
105 : // returns NS_BASE_STREAM_WOULD_BLOCK. Otherwise, if the stream is blocking,
106 : // then it will be read on one of the background I/O threads, and it does not
107 : // need to implement ReadSegments. If async is false, this method may return
108 : // NS_ERROR_NOT_IMPLEMENTED to cause the basechannel to implement Open in
109 : // terms of AsyncOpen (see NS_ImplementChannelOpen).
110 : // A callee is allowed to return an nsIChannel instead of an nsIInputStream.
111 : // That case will be treated as a redirect to the new channel. By default
112 : // *channel will be set to null by the caller, so callees who don't want to
113 : // return one an just not touch it.
114 : virtual nsresult OpenContentStream(bool async, nsIInputStream **stream,
115 : nsIChannel** channel) = 0;
116 :
117 : // The basechannel calls this method from its OnTransportStatus method to
118 : // determine whether to call nsIProgressEventSink::OnStatus in addition to
119 : // nsIProgressEventSink::OnProgress. This method may be overriden by the
120 : // subclass to enable nsIProgressEventSink::OnStatus events. If this method
121 : // returns true, then the statusArg out param specifies the "statusArg" value
122 : // to pass to the OnStatus method. By default, OnStatus messages are
123 : // suppressed. The status parameter passed to this method is the status value
124 : // from the OnTransportStatus method.
125 0 : virtual bool GetStatusArg(nsresult status, nsString &statusArg) {
126 0 : return false;
127 : }
128 :
129 : // Called when the callbacks available to this channel may have changed.
130 329 : virtual void OnCallbacksChanged() {
131 329 : }
132 :
133 : public:
134 : // ----------------------------------------------
135 : // Methods provided for use by the derived class:
136 :
137 : // Redirect to another channel. This method takes care of notifying
138 : // observers of this redirect as well as of opening the new channel, if asked
139 : // to do so. It also cancels |this| with the status code
140 : // NS_BINDING_REDIRECTED. A failure return from this method means that the
141 : // redirect could not be performed (no channel was opened; this channel
142 : // wasn't canceled.) The redirectFlags parameter consists of the flag values
143 : // defined on nsIChannelEventSink.
144 : nsresult Redirect(nsIChannel *newChannel, PRUint32 redirectFlags,
145 : bool openNewChannel);
146 :
147 : // Tests whether a type hint was set. Subclasses can use this to decide
148 : // whether to call SetContentType.
149 : // NOTE: This is only reliable if the subclass didn't itself call
150 : // SetContentType, and should also not be called after OpenContentStream.
151 : bool HasContentTypeHint() const;
152 :
153 : // The URI member should be initialized before the channel is used, and then
154 : // it should never be changed again until the channel is destroyed.
155 8850 : nsIURI *URI() {
156 8850 : return mURI;
157 : }
158 53433 : void SetURI(nsIURI *uri) {
159 53433 : NS_ASSERTION(uri, "must specify a non-null URI");
160 53433 : NS_ASSERTION(!mURI, "must not modify URI");
161 53433 : NS_ASSERTION(!mOriginalURI, "how did that get set so early?");
162 53433 : mURI = uri;
163 53433 : mOriginalURI = uri;
164 53433 : }
165 11 : nsIURI *OriginalURI() {
166 11 : return mOriginalURI;
167 : }
168 :
169 : // The security info is a property of the transport-layer, which should be
170 : // assigned by the subclass.
171 : nsISupports *SecurityInfo() {
172 : return mSecurityInfo;
173 : }
174 : void SetSecurityInfo(nsISupports *info) {
175 : mSecurityInfo = info;
176 : }
177 :
178 : // Test the load flags
179 177 : bool HasLoadFlag(PRUint32 flag) {
180 177 : return (mLoadFlags & flag) != 0;
181 : }
182 :
183 : // This is a short-cut to calling nsIRequest::IsPending()
184 2888 : bool IsPending() const {
185 2888 : return mPump || mWaitingOnAsyncRedirect;
186 : }
187 :
188 : // Set the content length that should be reported for this channel. Pass -1
189 : // to indicate an unspecified content length.
190 : void SetContentLength64(PRInt64 len);
191 : PRInt64 ContentLength64();
192 :
193 : // Helper function for querying the channel's notification callbacks.
194 29 : template <class T> void GetCallback(nsCOMPtr<T> &result) {
195 29 : GetInterface(NS_GET_TEMPLATE_IID(T), getter_AddRefs(result));
196 29 : }
197 :
198 : // Helper function for calling QueryInterface on this.
199 0 : nsQueryInterface do_QueryInterface() {
200 0 : return nsQueryInterface(static_cast<nsIChannel *>(this));
201 : }
202 : // MSVC needs this:
203 54669 : nsQueryInterface do_QueryInterface(nsISupports *obj) {
204 54669 : return nsQueryInterface(obj);
205 : }
206 :
207 : // If a subclass does not want to feed transport-layer progress events to the
208 : // base channel via nsITransportEventSink, then it may set this flag to cause
209 : // the base channel to synthesize progress events when it receives data from
210 : // the content stream. By default, progress events are not synthesized.
211 2866 : void EnableSynthesizedProgressEvents(bool enable) {
212 2866 : mSynthProgressEvents = enable;
213 2866 : }
214 :
215 : // Some subclasses may wish to manually insert a stream listener between this
216 : // and the channel's listener. The following methods make that possible.
217 0 : void SetStreamListener(nsIStreamListener *listener) {
218 0 : mListener = listener;
219 0 : }
220 0 : nsIStreamListener *StreamListener() {
221 0 : return mListener;
222 : }
223 :
224 : // Pushes a new stream converter in front of the channel's stream listener.
225 : // The fromType and toType values are passed to nsIStreamConverterService's
226 : // AsyncConvertData method. If invalidatesContentLength is true, then the
227 : // channel's content-length property will be assigned a value of -1. This is
228 : // necessary when the converter changes the length of the resulting data
229 : // stream, which is almost always the case for a "stream converter" ;-)
230 : // This function optionally returns a reference to the new converter.
231 : nsresult PushStreamConverter(const char *fromType, const char *toType,
232 : bool invalidatesContentLength = true,
233 : nsIStreamListener **converter = nsnull);
234 :
235 : private:
236 : NS_DECL_NSISTREAMLISTENER
237 : NS_DECL_NSIREQUESTOBSERVER
238 :
239 : // Called to setup mPump and call AsyncRead on it.
240 : nsresult BeginPumpingData();
241 :
242 : // Called when the callbacks available to this channel may have changed.
243 346 : void CallbacksChanged() {
244 346 : mProgressSink = nsnull;
245 346 : mQueriedProgressSink = false;
246 346 : OnCallbacksChanged();
247 346 : }
248 :
249 : // Handle an async redirect callback. This will only be called if we
250 : // returned success from AsyncOpen while posting a redirect runnable.
251 : void HandleAsyncRedirect(nsIChannel* newChannel);
252 : void ContinueHandleAsyncRedirect(nsresult result);
253 : nsresult ContinueRedirect();
254 :
255 : // start URI classifier if requested
256 : void ClassifyURI();
257 :
258 : class RedirectRunnable : public nsRunnable
259 0 : {
260 : public:
261 0 : RedirectRunnable(nsBaseChannel* chan, nsIChannel* newChannel)
262 0 : : mChannel(chan), mNewChannel(newChannel)
263 : {
264 0 : NS_PRECONDITION(newChannel, "Must have channel to redirect to");
265 0 : }
266 :
267 0 : NS_IMETHOD Run()
268 : {
269 0 : mChannel->HandleAsyncRedirect(mNewChannel);
270 0 : return NS_OK;
271 : }
272 :
273 : private:
274 : nsRefPtr<nsBaseChannel> mChannel;
275 : nsCOMPtr<nsIChannel> mNewChannel;
276 : };
277 : friend class RedirectRunnable;
278 :
279 : nsRefPtr<nsInputStreamPump> mPump;
280 : nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
281 : nsCOMPtr<nsIProgressEventSink> mProgressSink;
282 : nsCOMPtr<nsIURI> mOriginalURI;
283 : nsCOMPtr<nsIURI> mURI;
284 : nsCOMPtr<nsISupports> mOwner;
285 : nsCOMPtr<nsISupports> mSecurityInfo;
286 : nsCOMPtr<nsIChannel> mRedirectChannel;
287 : nsCString mContentType;
288 : nsCString mContentCharset;
289 : PRUint32 mLoadFlags;
290 : bool mQueriedProgressSink;
291 : bool mSynthProgressEvents;
292 : bool mWasOpened;
293 : bool mWaitingOnAsyncRedirect;
294 : bool mOpenRedirectChannel;
295 : PRUint32 mRedirectFlags;
296 :
297 : protected:
298 : nsCOMPtr<nsILoadGroup> mLoadGroup;
299 : nsCOMPtr<nsIStreamListener> mListener;
300 : nsCOMPtr<nsISupports> mListenerContext;
301 : nsresult mStatus;
302 : };
303 :
304 : #endif // !nsBaseChannel_h__
|