Back to index

lightning-sunbird  0.9+nobinonly
nsInputStreamChannel.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsInputStreamChannel.h"
00039 #include "nsIServiceManager.h"
00040 #include "nsIStreamTransportService.h"
00041 #include "nsIEventQueueService.h"
00042 #include "nsIInterfaceRequestorUtils.h"
00043 #include "nsITransport.h"
00044 #include "nsNetUtil.h"
00045 #include "nsCOMPtr.h"
00046 #include "prlog.h"
00047 
00048 
00049 #if defined(PR_LOGGING)
00050 //
00051 // NSPR_LOG_MODULES=nsStreamChannel:5
00052 //
00053 static PRLogModuleInfo *gStreamChannelLog = nsnull;
00054 #endif
00055 
00056 #define LOG(args)     PR_LOG(gStreamChannelLog, PR_LOG_DEBUG, args)
00057 #define LOG_ENABLED() PR_LOG_TEST(gStreamChannelLog, 4)
00058 
00059 //-----------------------------------------------------------------------------
00060 // nsInputStreamChannel methods
00061 //-----------------------------------------------------------------------------
00062 
00063 nsInputStreamChannel::nsInputStreamChannel()
00064     : mContentLength(-1)
00065     , mLoadFlags(LOAD_NORMAL)
00066     , mStatus(NS_OK)
00067 {
00068 #if defined(PR_LOGGING)
00069     if (!gStreamChannelLog)
00070         gStreamChannelLog = PR_NewLogModule("nsStreamChannel");
00071 #endif
00072 }
00073 
00074 nsInputStreamChannel::~nsInputStreamChannel()
00075 {
00076 }
00077 
00078 //-----------------------------------------------------------------------------
00079 // nsInputStreamChannel::nsISupports
00080 //-----------------------------------------------------------------------------
00081 
00082 NS_IMPL_ISUPPORTS5(nsInputStreamChannel,
00083                    nsIChannel,
00084                    nsIRequest,
00085                    nsIStreamListener,
00086                    nsIRequestObserver,
00087                    nsIInputStreamChannel)
00088 
00089 //-----------------------------------------------------------------------------
00090 // nsInputStreamChannel::nsIRequest
00091 //-----------------------------------------------------------------------------
00092 
00093 NS_IMETHODIMP
00094 nsInputStreamChannel::GetName(nsACString &result)
00095 {
00096     return mURI->GetSpec(result);
00097 }
00098 
00099 NS_IMETHODIMP
00100 nsInputStreamChannel::IsPending(PRBool *result)
00101 {
00102     NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
00103     return mPump->IsPending(result);
00104 }
00105 
00106 NS_IMETHODIMP
00107 nsInputStreamChannel::GetStatus(nsresult *status)
00108 {
00109     if (mPump && NS_SUCCEEDED(mStatus))
00110         mPump->GetStatus(status);
00111     else
00112         *status = mStatus;
00113     return NS_OK;
00114 }
00115 
00116 NS_IMETHODIMP
00117 nsInputStreamChannel::Cancel(nsresult status)
00118 {
00119     mStatus = status;
00120 
00121     if (mPump)
00122         mPump->Cancel(status);
00123 
00124     return NS_OK;
00125 }
00126 
00127 NS_IMETHODIMP
00128 nsInputStreamChannel::Suspend()
00129 {
00130     NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
00131     return mPump->Suspend();
00132 }
00133 
00134 NS_IMETHODIMP
00135 nsInputStreamChannel::Resume()
00136 {
00137     NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
00138     return mPump->Resume();
00139 }
00140 
00141 NS_IMETHODIMP
00142 nsInputStreamChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
00143 {
00144     *aLoadFlags = mLoadFlags;
00145     return NS_OK;
00146 }
00147 
00148 NS_IMETHODIMP
00149 nsInputStreamChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
00150 {
00151     mLoadFlags = aLoadFlags;
00152     return NS_OK;
00153 }
00154 
00155 NS_IMETHODIMP
00156 nsInputStreamChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
00157 {
00158     NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
00159     return NS_OK;
00160 }
00161 
00162 NS_IMETHODIMP
00163 nsInputStreamChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
00164 {
00165     mLoadGroup = aLoadGroup;
00166     mProgressSink = nsnull;
00167     return NS_OK;
00168 }
00169 
00170 //-----------------------------------------------------------------------------
00171 // nsInputStreamChannel::nsIChannel implementation
00172 //-----------------------------------------------------------------------------
00173 
00174 NS_IMETHODIMP
00175 nsInputStreamChannel::GetOriginalURI(nsIURI **aURI)
00176 {
00177     *aURI = mOriginalURI ? mOriginalURI : mURI;
00178     NS_IF_ADDREF(*aURI);
00179     return NS_OK;
00180 }
00181 
00182 NS_IMETHODIMP
00183 nsInputStreamChannel::SetOriginalURI(nsIURI *aURI)
00184 {
00185     mOriginalURI = aURI;
00186     return NS_OK;
00187 }
00188 
00189 NS_IMETHODIMP
00190 nsInputStreamChannel::GetURI(nsIURI **aURI)
00191 {
00192     NS_IF_ADDREF(*aURI = mURI);
00193     return NS_OK;
00194 }
00195 
00196 NS_IMETHODIMP
00197 nsInputStreamChannel::GetOwner(nsISupports **aOwner)
00198 {
00199     NS_IF_ADDREF(*aOwner = mOwner);
00200     return NS_OK;
00201 }
00202 
00203 NS_IMETHODIMP
00204 nsInputStreamChannel::SetOwner(nsISupports *aOwner)
00205 {
00206     mOwner = aOwner;
00207     return NS_OK;
00208 }
00209 
00210 NS_IMETHODIMP
00211 nsInputStreamChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
00212 {
00213     NS_IF_ADDREF(*aCallbacks = mCallbacks);
00214     return NS_OK;
00215 }
00216 
00217 NS_IMETHODIMP
00218 nsInputStreamChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
00219 {
00220     mCallbacks = aCallbacks;
00221     mProgressSink = nsnull;
00222     return NS_OK;
00223 }
00224 
00225 NS_IMETHODIMP 
00226 nsInputStreamChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
00227 {
00228     *aSecurityInfo = nsnull;
00229     return NS_OK;
00230 }
00231 
00232 NS_IMETHODIMP
00233 nsInputStreamChannel::GetContentType(nsACString &aContentType)
00234 {
00235     aContentType = mContentType;
00236     return NS_OK;
00237 }
00238 
00239 NS_IMETHODIMP
00240 nsInputStreamChannel::SetContentType(const nsACString &aContentType)
00241 {
00242     // If someone gives us a type hint we should just use that type.
00243     // So we don't care when this is being called.
00244 
00245     // mContentCharset is unchanged if not parsed
00246     NS_ParseContentType(aContentType, mContentType, mContentCharset);
00247     return NS_OK;
00248 }
00249 
00250 NS_IMETHODIMP
00251 nsInputStreamChannel::GetContentCharset(nsACString &aContentCharset)
00252 {
00253     aContentCharset = mContentCharset;
00254     return NS_OK;
00255 }
00256 
00257 NS_IMETHODIMP
00258 nsInputStreamChannel::SetContentCharset(const nsACString &aContentCharset)
00259 {
00260     // If someone gives us a charset hint we should just use that charset.
00261     // So we don't care when this is being called.
00262     mContentCharset = aContentCharset;
00263     return NS_OK;
00264 }
00265 
00266 NS_IMETHODIMP
00267 nsInputStreamChannel::GetContentLength(PRInt32 *aContentLength)
00268 {
00269     *aContentLength = mContentLength;
00270     return NS_OK;
00271 }
00272 
00273 NS_IMETHODIMP
00274 nsInputStreamChannel::SetContentLength(PRInt32 aContentLength)
00275 {
00276     // XXX does this really make any sense at all?
00277     mContentLength = aContentLength;
00278     return NS_OK;
00279 }
00280 
00281 NS_IMETHODIMP
00282 nsInputStreamChannel::Open(nsIInputStream **result)
00283 {
00284     NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED);
00285     NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
00286 
00287     // XXX this won't work if mContentStream is non-blocking.
00288 
00289     NS_ADDREF(*result = mContentStream);
00290     return NS_OK;
00291 }
00292 
00293 NS_IMETHODIMP
00294 nsInputStreamChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
00295 {
00296     NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED);
00297     NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
00298 
00299     // if content length is unknown, then we must guess... in this case, we
00300     // assume the stream can tell us.  if the stream is a pipe, then this will
00301     // not work.  in that case, we hope that the user of this interface would
00302     // have set our content length to PR_UINT32_MAX to cause us to read until
00303     // end of stream.
00304     if (mContentLength == -1)
00305         mContentStream->Available((PRUint32 *) &mContentLength);
00306 
00307     // XXX Once nsIChannel and nsIInputStream (in some future revision)
00308     // support 64-bit content lengths, mContentLength should be made 64-bit
00309     nsresult rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mContentStream,
00310                                         nsInt64(-1), nsInt64(mContentLength),
00311                                         0, 0, PR_TRUE);
00312     if (NS_FAILED(rv)) return rv;
00313 
00314     rv = mPump->AsyncRead(this, nsnull);
00315     if (NS_FAILED(rv)) return rv;
00316 
00317     if (mLoadGroup)
00318         mLoadGroup->AddRequest(this, nsnull);
00319 
00320     mListener = listener;
00321     mListenerContext = ctxt;
00322     return NS_OK;
00323 }
00324 
00325 //-----------------------------------------------------------------------------
00326 // nsInputStreamChannel::nsIInputStreamChannel implementation
00327 //-----------------------------------------------------------------------------
00328 
00329 NS_IMETHODIMP
00330 nsInputStreamChannel::SetURI(nsIURI *uri)
00331 {
00332     NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
00333     mURI = uri;
00334     return NS_OK;
00335 }
00336 
00337 NS_IMETHODIMP
00338 nsInputStreamChannel::GetContentStream(nsIInputStream **stream)
00339 {
00340     NS_IF_ADDREF(*stream = mContentStream);
00341     return NS_OK;
00342 }
00343 
00344 NS_IMETHODIMP
00345 nsInputStreamChannel::SetContentStream(nsIInputStream *stream)
00346 {
00347     NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
00348     mContentStream = stream;
00349     return NS_OK;
00350 }
00351 
00352 //-----------------------------------------------------------------------------
00353 // nsInputStreamChannel::nsIStreamListener implementation
00354 //-----------------------------------------------------------------------------
00355 
00356 NS_IMETHODIMP
00357 nsInputStreamChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
00358 {
00359     return mListener->OnStartRequest(this, mListenerContext);
00360 }
00361 
00362 NS_IMETHODIMP
00363 nsInputStreamChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
00364 {
00365     if (NS_SUCCEEDED(mStatus))
00366         mStatus = status;
00367 
00368     mListener->OnStopRequest(this, mListenerContext, mStatus);
00369     mListener = 0;
00370     mListenerContext = 0;
00371 
00372     if (mLoadGroup)
00373         mLoadGroup->RemoveRequest(this, nsnull, mStatus);
00374 
00375     mPump = 0;
00376     mContentStream = 0;
00377 
00378     // Drop notification callbacks to prevent cycles.
00379     mCallbacks = 0;
00380     mProgressSink = 0;
00381 
00382     return NS_OK;
00383 }
00384 
00385 NS_IMETHODIMP
00386 nsInputStreamChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
00387                                       nsIInputStream *stream,
00388                                       PRUint32 offset, PRUint32 count)
00389 {
00390     nsresult rv;
00391 
00392     rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
00393 
00394     if (!mProgressSink)
00395         NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
00396 
00397     // XXX need real 64-bit math here! (probably needs new streamlistener and
00398     // channel ifaces)
00399     if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
00400         mProgressSink->OnProgress(this, nsnull, nsUint64(offset + count),
00401                                   nsUint64(mContentLength));
00402 
00403     return rv; // let the pump cancel on failure
00404 }