Back to index

lightning-sunbird  0.9+nobinonly
nsDateTimeChannel.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Brian Ryner.
00020  * Portions created by the Initial Developer are Copyright (C) 2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Brian Ryner <bryner@brianryner.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 // DateTime implementation
00041 
00042 #include "nsDateTimeChannel.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsILoadGroup.h"
00045 #include "nsIInterfaceRequestor.h"
00046 #include "nsIInterfaceRequestorUtils.h"
00047 #include "nsXPIDLString.h"
00048 #include "nsISocketTransportService.h"
00049 #include "nsIStringStream.h"
00050 #include "nsMimeTypes.h"
00051 #include "nsIStreamConverterService.h"
00052 #include "nsITXTToHTMLConv.h"
00053 #include "nsIProgressEventSink.h"
00054 #include "nsEventQueueUtils.h"
00055 #include "nsNetUtil.h"
00056 #include "nsCRT.h"
00057 
00058 static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
00059 static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
00060 
00061 // nsDateTimeChannel methods
00062 nsDateTimeChannel::nsDateTimeChannel()
00063     : mLoadFlags(LOAD_NORMAL)
00064     , mStatus(NS_OK)
00065     , mPort(-1)
00066 {
00067 }
00068 
00069 nsDateTimeChannel::~nsDateTimeChannel()
00070 {
00071 }
00072 
00073 NS_IMPL_ISUPPORTS4(nsDateTimeChannel, 
00074                    nsIChannel, 
00075                    nsIRequest,
00076                    nsIStreamListener, 
00077                    nsIRequestObserver)
00078 
00079 nsresult
00080 nsDateTimeChannel::Init(nsIURI *uri, nsIProxyInfo *proxyInfo)
00081 {
00082     nsresult rv;
00083 
00084     NS_ASSERTION(uri, "no uri");
00085 
00086     mURI = uri;
00087     mProxyInfo = proxyInfo;
00088 
00089     rv = mURI->GetPort(&mPort);
00090     if (NS_FAILED(rv) || mPort < 1)
00091         mPort = DATETIME_PORT;
00092 
00093     rv = mURI->GetPath(mHost);
00094     if (NS_FAILED(rv)) return rv;
00095 
00096     if (mHost.IsEmpty())
00097         return NS_ERROR_MALFORMED_URI;
00098 
00099     mContentType.AssignLiteral(TEXT_HTML); // expected content-type
00100     return NS_OK;
00101 }
00102 
00104 // nsIRequest methods:
00105 
00106 NS_IMETHODIMP
00107 nsDateTimeChannel::GetName(nsACString &result)
00108 {
00109     return mURI->GetSpec(result);
00110 }
00111 
00112 NS_IMETHODIMP
00113 nsDateTimeChannel::IsPending(PRBool *result)
00114 {
00115     *result = (mPump != nsnull);
00116     return NS_OK;
00117 }
00118 
00119 NS_IMETHODIMP
00120 nsDateTimeChannel::GetStatus(nsresult *status)
00121 {
00122     if (NS_SUCCEEDED(mStatus) && mPump)
00123         mPump->GetStatus(status);
00124     else
00125         *status = mStatus;
00126     return NS_OK;
00127 }
00128 
00129 NS_IMETHODIMP
00130 nsDateTimeChannel::Cancel(nsresult status)
00131 {
00132     NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
00133 
00134     mStatus = status;
00135     if (mPump)
00136         mPump->Cancel(status);
00137 
00138     return NS_ERROR_UNEXPECTED;
00139 }
00140 
00141 NS_IMETHODIMP
00142 nsDateTimeChannel::Suspend()
00143 {
00144     if (mPump)
00145         return mPump->Suspend();
00146     return NS_ERROR_UNEXPECTED;
00147 }
00148 
00149 NS_IMETHODIMP
00150 nsDateTimeChannel::Resume()
00151 {
00152     if (mPump)
00153         return mPump->Resume();
00154     return NS_ERROR_UNEXPECTED;
00155 }
00156 
00158 // nsIChannel methods:
00159 
00160 NS_IMETHODIMP
00161 nsDateTimeChannel::GetOriginalURI(nsIURI* *aURI)
00162 {
00163     *aURI = mOriginalURI ? mOriginalURI : mURI;
00164     NS_ADDREF(*aURI);
00165     return NS_OK;
00166 }
00167 
00168 NS_IMETHODIMP
00169 nsDateTimeChannel::SetOriginalURI(nsIURI* aURI)
00170 {
00171     mOriginalURI = aURI;
00172     return NS_OK;
00173 }
00174 
00175 NS_IMETHODIMP
00176 nsDateTimeChannel::GetURI(nsIURI* *aURI)
00177 {
00178     *aURI = mURI;
00179     NS_IF_ADDREF(*aURI);
00180     return NS_OK;
00181 }
00182 
00183 NS_IMETHODIMP
00184 nsDateTimeChannel::Open(nsIInputStream **_retval)
00185 {
00186     return NS_ImplementChannelOpen(this, _retval);
00187 }
00188 
00189 NS_IMETHODIMP
00190 nsDateTimeChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
00191 {
00192     nsresult rv = NS_CheckPortSafety(mPort, "datetime");
00193     if (NS_FAILED(rv)) return rv;
00194 
00195     nsCOMPtr<nsIEventQueue> eventQ;
00196     rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ));
00197     if (NS_FAILED(rv)) return rv;
00198 
00199     //
00200     // create transport
00201     //
00202     nsCOMPtr<nsISocketTransportService> sts = 
00203              do_GetService(kSocketTransportServiceCID, &rv);
00204     if (NS_FAILED(rv)) return rv;
00205 
00206     rv = sts->CreateTransport(nsnull, 0, mHost, mPort, mProxyInfo,
00207                               getter_AddRefs(mTransport));
00208     if (NS_FAILED(rv)) return rv;
00209 
00210     // not fatal if this fails
00211     mTransport->SetEventSink(this, eventQ);
00212 
00213     //
00214     // create TXT to HTML stream converter
00215     //
00216     nsCOMPtr<nsIStreamConverterService> scs = 
00217              do_GetService(kStreamConverterServiceCID, &rv);
00218     if (NS_FAILED(rv)) return rv;
00219 
00220     nsCOMPtr<nsIStreamListener> convListener;
00221     rv = scs->AsyncConvertData("text/plain", "text/html", this, nsnull,
00222                                getter_AddRefs(convListener));
00223     if (NS_FAILED(rv)) return rv;
00224 
00225     nsCOMPtr<nsITXTToHTMLConv> conv = do_QueryInterface(convListener);
00226     if (conv) {
00227         nsCAutoString userHost;
00228         rv = mURI->GetPath(userHost);
00229 
00230         nsAutoString title;
00231         title.AppendLiteral("DateTime according to ");
00232         AppendUTF8toUTF16(mHost, title);
00233 
00234         conv->SetTitle(title.get());
00235         conv->PreFormatHTML(PR_TRUE);
00236     }
00237 
00238     //
00239     // open input stream, and create input stream pump...
00240     //
00241     nsCOMPtr<nsIInputStream> sockIn;
00242     rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(sockIn));
00243     if (NS_FAILED(rv)) return rv;
00244 
00245     rv = NS_NewInputStreamPump(getter_AddRefs(mPump), sockIn);
00246     if (NS_FAILED(rv)) return rv;
00247 
00248     rv = mPump->AsyncRead(convListener, nsnull);
00249     if (NS_FAILED(rv)) return rv;
00250 
00251     if (mLoadGroup)
00252         mLoadGroup->AddRequest(this, nsnull);
00253 
00254     mListener = aListener;
00255     mListenerContext = ctxt;
00256     return NS_OK;
00257 }
00258 
00259 NS_IMETHODIMP
00260 nsDateTimeChannel::GetLoadFlags(PRUint32 *aLoadFlags)
00261 {
00262     *aLoadFlags = mLoadFlags;
00263     return NS_OK;
00264 }
00265 
00266 NS_IMETHODIMP
00267 nsDateTimeChannel::SetLoadFlags(PRUint32 aLoadFlags)
00268 {
00269     mLoadFlags = aLoadFlags;
00270     return NS_OK;
00271 }
00272 
00273 NS_IMETHODIMP
00274 nsDateTimeChannel::GetContentType(nsACString &aContentType)
00275 {
00276     aContentType = mContentType;
00277     return NS_OK;
00278 }
00279 
00280 NS_IMETHODIMP
00281 nsDateTimeChannel::SetContentType(const nsACString &aContentType)
00282 {
00283     mContentType = aContentType;
00284     return NS_OK;
00285 }
00286 
00287 NS_IMETHODIMP
00288 nsDateTimeChannel::GetContentCharset(nsACString &aContentCharset)
00289 {
00290     aContentCharset = mContentCharset;
00291     return NS_OK;
00292 }
00293 
00294 NS_IMETHODIMP
00295 nsDateTimeChannel::SetContentCharset(const nsACString &aContentCharset)
00296 {
00297     mContentCharset = aContentCharset;
00298     return NS_OK;
00299 }
00300 
00301 NS_IMETHODIMP
00302 nsDateTimeChannel::GetContentLength(PRInt32 *aContentLength)
00303 {
00304     *aContentLength = -1;
00305     return NS_OK;
00306 }
00307 
00308 NS_IMETHODIMP
00309 nsDateTimeChannel::SetContentLength(PRInt32 aContentLength)
00310 {
00311     // silently ignore this...
00312     return NS_OK;
00313 }
00314 
00315 NS_IMETHODIMP
00316 nsDateTimeChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
00317 {
00318     *aLoadGroup = mLoadGroup;
00319     NS_IF_ADDREF(*aLoadGroup);
00320     return NS_OK;
00321 }
00322 
00323 NS_IMETHODIMP
00324 nsDateTimeChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
00325 {
00326     mLoadGroup = aLoadGroup;
00327     mProgressSink = nsnull;
00328     return NS_OK;
00329 }
00330 
00331 NS_IMETHODIMP
00332 nsDateTimeChannel::GetOwner(nsISupports* *aOwner)
00333 {
00334     *aOwner = mOwner.get();
00335     NS_IF_ADDREF(*aOwner);
00336     return NS_OK;
00337 }
00338 
00339 NS_IMETHODIMP
00340 nsDateTimeChannel::SetOwner(nsISupports* aOwner)
00341 {
00342     mOwner = aOwner;
00343     return NS_OK;
00344 }
00345 
00346 NS_IMETHODIMP
00347 nsDateTimeChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
00348 {
00349     *aNotificationCallbacks = mCallbacks.get();
00350     NS_IF_ADDREF(*aNotificationCallbacks);
00351     return NS_OK;
00352 }
00353 
00354 NS_IMETHODIMP
00355 nsDateTimeChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
00356 {
00357     mCallbacks = aNotificationCallbacks;
00358     mProgressSink = nsnull;
00359     return NS_OK;
00360 }
00361 
00362 NS_IMETHODIMP 
00363 nsDateTimeChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
00364 {
00365     if (mTransport)
00366         return mTransport->GetSecurityInfo(aSecurityInfo);
00367 
00368     *aSecurityInfo = nsnull;
00369     return NS_OK;
00370 }
00371 
00372 //-----------------------------------------------------------------------------
00373 // nsIRequestObserver methods
00374 //-----------------------------------------------------------------------------
00375 
00376 NS_IMETHODIMP
00377 nsDateTimeChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
00378 {
00379     return mListener->OnStartRequest(this, mListenerContext);
00380 }
00381 
00382 NS_IMETHODIMP
00383 nsDateTimeChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
00384 {
00385     if (NS_SUCCEEDED(mStatus))
00386         mStatus = status;
00387 
00388     mListener->OnStopRequest(this, mListenerContext, mStatus);
00389     mListener = 0;
00390     mListenerContext = 0;
00391 
00392     if (mLoadGroup)
00393         mLoadGroup->RemoveRequest(this, nsnull, mStatus);
00394 
00395     mPump = 0;
00396     mTransport = 0;
00397 
00398     // Drop notification callbacks to prevent cycles.
00399     mCallbacks = 0;
00400     mProgressSink = 0;
00401 
00402     return NS_OK;
00403 }
00404 
00405 NS_IMETHODIMP
00406 nsDateTimeChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
00407                                  nsIInputStream *stream, PRUint32 offset,
00408                                  PRUint32 count)
00409 {
00410     return mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
00411 }
00412 
00413 //-----------------------------------------------------------------------------
00414 // nsITransportEventSink methods
00415 //-----------------------------------------------------------------------------
00416 
00417 NS_IMETHODIMP
00418 nsDateTimeChannel::OnTransportStatus(nsITransport *trans, nsresult status,
00419                                      PRUint64 progress, PRUint64 progressMax)
00420 {
00421     if (!mProgressSink)
00422         NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
00423 
00424     // suppress status notification if channel is no longer pending!
00425     if (mProgressSink && NS_SUCCEEDED(mStatus) && mPump && !(mLoadFlags & LOAD_BACKGROUND)) {
00426         NS_ConvertUTF8toUTF16 host(mHost);
00427         mProgressSink->OnStatus(this, nsnull, status, host.get());
00428 
00429         if (status == nsISocketTransport::STATUS_RECEIVING_FROM ||
00430             status == nsISocketTransport::STATUS_SENDING_TO) {
00431             mProgressSink->OnProgress(this, nsnull, progress, progressMax);
00432         }
00433     }
00434     return NS_OK;
00435 }