LCOV - app.info - netwerk/protocol/http/nsHttpPipeline.cpp

LCOV - code coverage report
| Current view: | directory - netwerk/protocol/http - nsHttpPipeline.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 327 | 0 | 0.0 %
| Date: | 2012-06-02 | Functions: | 42 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; 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.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Darin Fisher <darin@netscape.com> (original author)
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include <stdlib.h>
          40                 : #include "nsHttp.h"
          41                 : #include "nsHttpPipeline.h"
          42                 : #include "nsHttpHandler.h"
          43                 : #include "nsIOService.h"
          44                 : #include "nsIRequest.h"
          45                 : #include "nsISocketTransport.h"
          46                 : #include "nsIStringStream.h"
          47                 : #include "nsIPipe.h"
          48                 : #include "nsCOMPtr.h"
          49                 : #include "nsComponentManagerUtils.h"
          50                 :
          51                 : #ifdef DEBUG
          52                 : #include "prthread.h"
          53                 : // defined by the socket transport service while active
          54                 : extern PRThread *gSocketThread;
          55                 : #endif
          56                 :
          57                 : //-----------------------------------------------------------------------------
          58                 : // nsHttpPushBackWriter
          59                 : //-----------------------------------------------------------------------------
          60                 :
          61                 : class nsHttpPushBackWriter : public nsAHttpSegmentWriter
          62                 : {
          63                 : public:
          64               0 :     nsHttpPushBackWriter(const char *buf, PRUint32 bufLen)
          65                 :         : mBuf(buf)
          66               0 :         , mBufLen(bufLen)
          67               0 :         { }
          68               0 :     virtual ~nsHttpPushBackWriter() {}
          69                 :
          70               0 :     nsresult OnWriteSegment(char *buf, PRUint32 count, PRUint32 *countWritten)
          71                 :     {
          72               0 :         if (mBufLen == 0)
          73               0 :             return NS_BASE_STREAM_CLOSED;
          74                 :
          75               0 :         if (count > mBufLen)
          76               0 :             count = mBufLen;
          77                 :
          78               0 :         memcpy(buf, mBuf, count);
          79                 :
          80               0 :         mBuf += count;
          81               0 :         mBufLen -= count;
          82               0 :         *countWritten = count;
          83               0 :         return NS_OK;
          84                 :     }
          85                 :
          86                 : private:
          87                 :     const char *mBuf;
          88                 :     PRUint32    mBufLen;
          89                 : };
          90                 :
          91                 : //-----------------------------------------------------------------------------
          92                 : // nsHttpPipeline <public>
          93                 : //-----------------------------------------------------------------------------
          94                 :
          95               0 : nsHttpPipeline::nsHttpPipeline()
          96                 :     : mConnection(nsnull)
          97                 :     , mStatus(NS_OK)
          98                 :     , mRequestIsPartial(false)
          99                 :     , mResponseIsPartial(false)
         100                 :     , mClosed(false)
         101                 :     , mPushBackBuf(nsnull)
         102                 :     , mPushBackLen(0)
         103                 :     , mPushBackMax(0)
         104                 :     , mHttp1xTransactionCount(0)
         105                 :     , mReceivingFromProgress(0)
         106                 :     , mSendingToProgress(0)
         107               0 :     , mSuppressSendEvents(true)
         108                 : {
         109               0 : }
         110                 :
         111               0 : nsHttpPipeline::~nsHttpPipeline()
         112                 : {
         113                 :     // make sure we aren't still holding onto any transactions!
         114               0 :     Close(NS_ERROR_ABORT);
         115                 :
         116               0 :     NS_IF_RELEASE(mConnection);
         117                 :
         118               0 :     if (mPushBackBuf)
         119               0 :         free(mPushBackBuf);
         120               0 : }
         121                 :
         122                 : nsresult
         123               0 : nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
         124                 : {
         125               0 :     LOG(("nsHttpPipeline::AddTransaction [this=%x trans=%x]\n", this, trans));
         126                 :
         127               0 :     NS_ADDREF(trans);
         128               0 :     mRequestQ.AppendElement(trans);
         129                 :
         130               0 :     if (mConnection && !mClosed) {
         131               0 :         trans->SetConnection(this);
         132                 :
         133               0 :         if (mRequestQ.Length() == 1)
         134               0 :             mConnection->ResumeSend();
         135                 :     }
         136                 :
         137               0 :     return NS_OK;
         138                 : }
         139                 :
         140                 : //-----------------------------------------------------------------------------
         141                 : // nsHttpPipeline::nsISupports
         142                 : //-----------------------------------------------------------------------------
         143                 :
         144               0 : NS_IMPL_THREADSAFE_ADDREF(nsHttpPipeline)
         145               0 : NS_IMPL_THREADSAFE_RELEASE(nsHttpPipeline)
         146                 :
         147                 : // multiple inheritance fun :-)
         148               0 : NS_INTERFACE_MAP_BEGIN(nsHttpPipeline)
         149               0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsAHttpConnection)
         150               0 : NS_INTERFACE_MAP_END
         151                 :
         152                 :
         153                 : //-----------------------------------------------------------------------------
         154                 : // nsHttpPipeline::nsAHttpConnection
         155                 : //-----------------------------------------------------------------------------
         156                 :
         157                 : nsresult
         158               0 : nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans,
         159                 :                                    nsHttpRequestHead *requestHead,
         160                 :                                    nsHttpResponseHead *responseHead,
         161                 :                                    bool *reset)
         162                 : {
         163               0 :     LOG(("nsHttpPipeline::OnHeadersAvailable [this=%x]\n", this));
         164                 :
         165               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         166               0 :     NS_ASSERTION(mConnection, "no connection");
         167                 :
         168                 :     // trans has now received its response headers; forward to the real connection
         169               0 :     return mConnection->OnHeadersAvailable(trans, requestHead, responseHead, reset);
         170                 : }
         171                 :
         172                 : nsresult
         173               0 : nsHttpPipeline::ResumeSend()
         174                 : {
         175               0 :     if (mConnection)
         176               0 :         return mConnection->ResumeSend();
         177               0 :     return NS_ERROR_UNEXPECTED;
         178                 : }
         179                 :
         180                 : nsresult
         181               0 : nsHttpPipeline::ResumeRecv()
         182                 : {
         183               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         184               0 :     NS_ASSERTION(mConnection, "no connection");
         185               0 :     return mConnection->ResumeRecv();
         186                 : }
         187                 :
         188                 : void
         189               0 : nsHttpPipeline::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
         190                 : {
         191               0 :     LOG(("nsHttpPipeline::CloseTransaction [this=%x trans=%x reason=%x]\n",
         192                 :         this, trans, reason));
         193                 :
         194               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         195               0 :     NS_ASSERTION(NS_FAILED(reason), "expecting failure code");
         196                 :
         197                 :     // the specified transaction is to be closed with the given "reason"
         198                 :
         199                 :     PRInt32 index;
         200               0 :     bool killPipeline = false;
         201                 :
         202               0 :     index = mRequestQ.IndexOf(trans);
         203               0 :     if (index >= 0) {
         204               0 :         if (index == 0 && mRequestIsPartial) {
         205                 :             // the transaction is in the request queue.  check to see if any of
         206                 :             // its data has been written out yet.
         207               0 :             killPipeline = true;
         208                 :         }
         209               0 :         mRequestQ.RemoveElementAt(index);
         210                 :     }
         211                 :     else {
         212               0 :         index = mResponseQ.IndexOf(trans);
         213               0 :         if (index >= 0)
         214               0 :             mResponseQ.RemoveElementAt(index);
         215                 :         // while we could avoid killing the pipeline if this transaction is the
         216                 :         // last transaction in the pipeline, there doesn't seem to be that much
         217                 :         // value in doing so.  most likely if this transaction is going away,
         218                 :         // the others will be shortly as well.
         219               0 :         killPipeline = true;
         220                 :     }
         221                 :
         222               0 :     trans->Close(reason);
         223               0 :     NS_RELEASE(trans);
         224                 :
         225               0 :     if (killPipeline) {
         226               0 :         if (mConnection)
         227               0 :             mConnection->CloseTransaction(this, reason);
         228                 :         else
         229               0 :             Close(reason);
         230                 :     }
         231               0 : }
         232                 :
         233                 : void
         234               0 : nsHttpPipeline::GetConnectionInfo(nsHttpConnectionInfo **result)
         235                 : {
         236               0 :     NS_ASSERTION(mConnection, "no connection");
         237               0 :     mConnection->GetConnectionInfo(result);
         238               0 : }
         239                 :
         240                 : nsresult
         241               0 : nsHttpPipeline::TakeTransport(nsISocketTransport  **aTransport,
         242                 :                               nsIAsyncInputStream **aInputStream,
         243                 :                               nsIAsyncOutputStream **aOutputStream)
         244                 : {
         245               0 :     return mConnection->TakeTransport(aTransport, aInputStream, aOutputStream);
         246                 : }
         247                 :
         248                 : void
         249               0 : nsHttpPipeline::GetSecurityInfo(nsISupports **result)
         250                 : {
         251               0 :     NS_ASSERTION(mConnection, "no connection");
         252               0 :     mConnection->GetSecurityInfo(result);
         253               0 : }
         254                 :
         255                 : bool
         256               0 : nsHttpPipeline::IsPersistent()
         257                 : {
         258               0 :     return true; // pipelining requires this
         259                 : }
         260                 :
         261                 : bool
         262               0 : nsHttpPipeline::IsReused()
         263                 : {
         264               0 :     return true; // pipelining requires this
         265                 : }
         266                 :
         267                 : nsresult
         268               0 : nsHttpPipeline::PushBack(const char *data, PRUint32 length)
         269                 : {
         270               0 :     LOG(("nsHttpPipeline::PushBack [this=%x len=%u]\n", this, length));
         271                 :
         272               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         273               0 :     NS_ASSERTION(mPushBackLen == 0, "push back buffer already has data!");
         274                 :
         275                 :     // If we have no chance for a pipeline (e.g. due to an Upgrade)
         276                 :     // then push this data down to original connection
         277               0 :     if (!mConnection->IsPersistent())
         278               0 :         return mConnection->PushBack(data, length);
         279                 :
         280                 :     // PushBack is called recursively from WriteSegments
         281                 :
         282                 :     // XXX we have a design decision to make here.  either we buffer the data
         283                 :     // and process it when we return to WriteSegments, or we attempt to move
         284                 :     // onto the next transaction from here.  doing so adds complexity with the
         285                 :     // benefit of eliminating the extra buffer copy.  the buffer is at most
         286                 :     // 4096 bytes, so it is really unclear if there is any value in the added
         287                 :     // complexity.  besides simplicity, buffering this data has the advantage
         288                 :     // that we'll call close on the transaction sooner, which will wake up
         289                 :     // the HTTP channel sooner to continue with its work.
         290                 :
         291               0 :     if (!mPushBackBuf) {
         292               0 :         mPushBackMax = length;
         293               0 :         mPushBackBuf = (char *) malloc(mPushBackMax);
         294               0 :         if (!mPushBackBuf)
         295               0 :             return NS_ERROR_OUT_OF_MEMORY;
         296                 :     }
         297               0 :     else if (length > mPushBackMax) {
         298                 :         // grow push back buffer as necessary.
         299               0 :         NS_ASSERTION(length <= nsIOService::gDefaultSegmentSize, "too big");
         300               0 :         mPushBackMax = length;
         301               0 :         mPushBackBuf = (char *) realloc(mPushBackBuf, mPushBackMax);
         302               0 :         if (!mPushBackBuf)
         303               0 :             return NS_ERROR_OUT_OF_MEMORY;
         304                 :     }
         305                 :
         306               0 :     memcpy(mPushBackBuf, data, length);
         307               0 :     mPushBackLen = length;
         308                 :
         309               0 :     return NS_OK;
         310                 : }
         311                 :
         312                 : bool
         313               0 : nsHttpPipeline::LastTransactionExpectedNoContent()
         314                 : {
         315               0 :     NS_ABORT_IF_FALSE(mConnection, "no connection");
         316               0 :     return mConnection->LastTransactionExpectedNoContent();
         317                 : }
         318                 :
         319                 : void
         320               0 : nsHttpPipeline::SetLastTransactionExpectedNoContent(bool val)
         321                 : {
         322               0 :     NS_ABORT_IF_FALSE(mConnection, "no connection");
         323               0 :      mConnection->SetLastTransactionExpectedNoContent(val);
         324               0 : }
         325                 :
         326                 : nsHttpConnection *
         327               0 : nsHttpPipeline::TakeHttpConnection()
         328                 : {
         329               0 :     if (mConnection)
         330               0 :         return mConnection->TakeHttpConnection();
         331               0 :     return nsnull;
         332                 : }
         333                 :
         334                 : nsISocketTransport *
         335               0 : nsHttpPipeline::Transport()
         336                 : {
         337               0 :     if (!mConnection)
         338               0 :         return nsnull;
         339               0 :     return mConnection->Transport();
         340                 : }
         341                 :
         342                 : void
         343               0 : nsHttpPipeline::SetSSLConnectFailed()
         344                 : {
         345               0 :     nsAHttpTransaction *trans = Request(0);
         346                 :
         347               0 :     if (trans)
         348               0 :         trans->SetSSLConnectFailed();
         349               0 : }
         350                 :
         351                 : nsHttpRequestHead *
         352               0 : nsHttpPipeline::RequestHead()
         353                 : {
         354               0 :     nsAHttpTransaction *trans = Request(0);
         355                 :
         356               0 :     if (trans)
         357               0 :         return trans->RequestHead();
         358               0 :     return nsnull;
         359                 : }
         360                 :
         361                 : PRUint32
         362               0 : nsHttpPipeline::Http1xTransactionCount()
         363                 : {
         364               0 :   return mHttp1xTransactionCount;
         365                 : }
         366                 :
         367                 : nsresult
         368               0 : nsHttpPipeline::TakeSubTransactions(
         369                 :     nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
         370                 : {
         371               0 :     LOG(("nsHttpPipeline::TakeSubTransactions [this=%p]\n", this));
         372                 :
         373               0 :     if (mResponseQ.Length() || mRequestIsPartial)
         374               0 :         return NS_ERROR_ALREADY_OPENED;
         375                 :
         376                 :     // request queue could be empty if it was already canceled, in which
         377                 :     // case it is safe to treat this as a case without any
         378                 :     // sub-transactions.
         379               0 :     if (!mRequestQ.Length())
         380               0 :         return NS_ERROR_NOT_IMPLEMENTED;
         381                 :
         382               0 :     PRInt32 i, count = mRequestQ.Length();
         383               0 :     for (i = 0; i < count; ++i) {
         384               0 :         nsAHttpTransaction *trans = Request(i);
         385               0 :         outTransactions.AppendElement(trans);
         386               0 :         NS_RELEASE(trans);
         387                 :     }
         388               0 :     mRequestQ.Clear();
         389                 :
         390               0 :     LOG(("   took %d\n", count));
         391               0 :     return NS_OK;
         392                 : }
         393                 :
         394                 : //-----------------------------------------------------------------------------
         395                 : // nsHttpPipeline::nsAHttpConnection
         396                 : //-----------------------------------------------------------------------------
         397                 :
         398                 : void
         399               0 : nsHttpPipeline::SetConnection(nsAHttpConnection *conn)
         400                 : {
         401               0 :     LOG(("nsHttpPipeline::SetConnection [this=%x conn=%x]\n", this, conn));
         402                 :
         403               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         404               0 :     NS_ASSERTION(!mConnection, "already have a connection");
         405                 :
         406               0 :     NS_IF_ADDREF(mConnection = conn);
         407                 :
         408               0 :     PRInt32 i, count = mRequestQ.Length();
         409               0 :     for (i=0; i<count; ++i)
         410               0 :         Request(i)->SetConnection(this);
         411               0 : }
         412                 :
         413                 : nsAHttpConnection *
         414               0 : nsHttpPipeline::Connection()
         415                 : {
         416               0 :     LOG(("nsHttpPipeline::Connection [this=%x conn=%x]\n", this, mConnection));
         417                 :
         418               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         419               0 :     return mConnection;
         420                 : }
         421                 :
         422                 : void
         423               0 : nsHttpPipeline::GetSecurityCallbacks(nsIInterfaceRequestor **result,
         424                 :                                      nsIEventTarget        **target)
         425                 : {
         426               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         427                 :
         428                 :     // return security callbacks from first request
         429               0 :     nsAHttpTransaction *trans = Request(0);
         430               0 :     if (trans)
         431               0 :         trans->GetSecurityCallbacks(result, target);
         432                 :     else {
         433               0 :         *result = nsnull;
         434               0 :         if (target)
         435               0 :             *target = nsnull;
         436                 :     }
         437               0 : }
         438                 :
         439                 : void
         440               0 : nsHttpPipeline::OnTransportStatus(nsITransport* transport,
         441                 :                                   nsresult status, PRUint64 progress)
         442                 : {
         443               0 :     LOG(("nsHttpPipeline::OnStatus [this=%x status=%x progress=%llu]\n",
         444                 :         this, status, progress));
         445                 :
         446               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         447                 :
         448                 :     nsAHttpTransaction *trans;
         449                 :     PRInt32 i, count;
         450                 :
         451               0 :     switch (status) {
         452                 :
         453                 :     case NS_NET_STATUS_RESOLVING_HOST:
         454                 :     case NS_NET_STATUS_RESOLVED_HOST:
         455                 :     case NS_NET_STATUS_CONNECTING_TO:
         456                 :     case NS_NET_STATUS_CONNECTED_TO:
         457                 :         // These should only appear at most once per pipeline.
         458                 :         // Deliver to the first transaction.
         459                 :
         460               0 :         trans = Request(0);
         461               0 :         if (!trans)
         462               0 :             trans = Response(0);
         463               0 :         if (trans)
         464               0 :             trans->OnTransportStatus(transport, status, progress);
         465                 :
         466               0 :         break;
         467                 :
         468                 :     case NS_NET_STATUS_SENDING_TO:
         469                 :         // This is generated by the socket transport when (part) of
         470                 :         // a transaction is written out
         471                 :         //
         472                 :         // In pipelining this is generated out of FillSendBuf(), but it cannot do
         473                 :         // so until the connection is confirmed by CONNECTED_TO.
         474                 :         // See patch for bug 196827.
         475                 :         //
         476                 :
         477               0 :         if (mSuppressSendEvents) {
         478               0 :             mSuppressSendEvents = false;
         479                 :
         480                 :             // catch up by sending the event to all the transactions that have
         481                 :             // moved from request to response and any that have been partially
         482                 :             // sent. Also send WAITING_FOR to those that were completely sent
         483               0 :             count = mResponseQ.Length();
         484               0 :             for (i = 0; i < count; ++i) {
         485               0 :                 Response(i)->OnTransportStatus(transport,
         486                 :                                                NS_NET_STATUS_SENDING_TO,
         487               0 :                                                progress);
         488               0 :                 Response(i)->OnTransportStatus(transport,
         489                 :                                                NS_NET_STATUS_WAITING_FOR,
         490               0 :                                                progress);
         491                 :             }
         492               0 :             if (mRequestIsPartial && Request(0))
         493               0 :                 Request(0)->OnTransportStatus(transport,
         494                 :                                               NS_NET_STATUS_SENDING_TO,
         495               0 :                                               progress);
         496               0 :             mSendingToProgress = progress;
         497                 :         }
         498                 :         // otherwise ignore it
         499               0 :         break;
         500                 :
         501                 :     case NS_NET_STATUS_WAITING_FOR:
         502                 :         // Created by nsHttpConnection when request pipeline has been totally
         503                 :         // sent. Ignore it here because it is simulated in FillSendBuf() when
         504                 :         // a request is moved from request to response.
         505                 :
         506                 :         // ignore it
         507               0 :         break;
         508                 :
         509                 :     case NS_NET_STATUS_RECEIVING_FROM:
         510                 :         // Forward this only to the transaction currently recieving data. It is
         511                 :         // normally generated by the socket transport, but can also
         512                 :         // be repeated by the pushbackwriter if necessary.
         513               0 :         mReceivingFromProgress = progress;
         514               0 :         if (Response(0))
         515               0 :             Response(0)->OnTransportStatus(transport, status, progress);
         516               0 :         break;
         517                 :
         518                 :     default:
         519                 :         // forward other notifications to all request transactions
         520               0 :         count = mRequestQ.Length();
         521               0 :         for (i = 0; i < count; ++i)
         522               0 :             Request(i)->OnTransportStatus(transport, status, progress);
         523               0 :         break;
         524                 :     }
         525               0 : }
         526                 :
         527                 : bool
         528               0 : nsHttpPipeline::IsDone()
         529                 : {
         530               0 :     bool done = true;
         531                 :
         532               0 :     PRUint32 i, count = mRequestQ.Length();
         533               0 :     for (i = 0; done && (i < count); i++)
         534               0 :         done = Request(i)->IsDone();
         535                 :
         536               0 :     count = mResponseQ.Length();
         537               0 :     for (i = 0; done && (i < count); i++)
         538               0 :         done = Response(i)->IsDone();
         539                 :
         540               0 :     return done;
         541                 : }
         542                 :
         543                 : nsresult
         544               0 : nsHttpPipeline::Status()
         545                 : {
         546               0 :     return mStatus;
         547                 : }
         548                 :
         549                 : PRUint32
         550               0 : nsHttpPipeline::Available()
         551                 : {
         552               0 :     PRUint32 result = 0;
         553                 :
         554               0 :     PRInt32 i, count = mRequestQ.Length();
         555               0 :     for (i=0; i<count; ++i)
         556               0 :         result += Request(i)->Available();
         557               0 :     return result;
         558                 : }
         559                 :
         560                 : NS_METHOD
         561               0 : nsHttpPipeline::ReadFromPipe(nsIInputStream *stream,
         562                 :                              void *closure,
         563                 :                              const char *buf,
         564                 :                              PRUint32 offset,
         565                 :                              PRUint32 count,
         566                 :                              PRUint32 *countRead)
         567                 : {
         568               0 :     nsHttpPipeline *self = (nsHttpPipeline *) closure;
         569               0 :     return self->mReader->OnReadSegment(buf, count, countRead);
         570                 : }
         571                 :
         572                 : nsresult
         573               0 : nsHttpPipeline::ReadSegments(nsAHttpSegmentReader *reader,
         574                 :                              PRUint32 count,
         575                 :                              PRUint32 *countRead)
         576                 : {
         577               0 :     LOG(("nsHttpPipeline::ReadSegments [this=%x count=%u]\n", this, count));
         578                 :
         579               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         580                 :
         581               0 :     if (mClosed) {
         582               0 :         *countRead = 0;
         583               0 :         return mStatus;
         584                 :     }
         585                 :
         586                 :     nsresult rv;
         587               0 :     PRUint32 avail = 0;
         588               0 :     if (mSendBufIn) {
         589               0 :         rv = mSendBufIn->Available(&avail);
         590               0 :         if (NS_FAILED(rv)) return rv;
         591                 :     }
         592                 :
         593               0 :     if (avail == 0) {
         594               0 :         rv = FillSendBuf();
         595               0 :         if (NS_FAILED(rv)) return rv;
         596                 :
         597               0 :         rv = mSendBufIn->Available(&avail);
         598               0 :         if (NS_FAILED(rv)) return rv;
         599                 :
         600                 :         // return EOF if send buffer is empty
         601               0 :         if (avail == 0) {
         602               0 :             *countRead = 0;
         603               0 :             return NS_OK;
         604                 :         }
         605                 :     }
         606                 :
         607                 :     // read no more than what was requested
         608               0 :     if (avail > count)
         609               0 :         avail = count;
         610                 :
         611               0 :     mReader = reader;
         612                 :
         613               0 :     rv = mSendBufIn->ReadSegments(ReadFromPipe, this, avail, countRead);
         614                 :
         615               0 :     mReader = nsnull;
         616               0 :     return rv;
         617                 : }
         618                 :
         619                 : nsresult
         620               0 : nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
         621                 :                               PRUint32 count,
         622                 :                               PRUint32 *countWritten)
         623                 : {
         624               0 :     LOG(("nsHttpPipeline::WriteSegments [this=%x count=%u]\n", this, count));
         625                 :
         626               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
         627                 :
         628               0 :     if (mClosed)
         629               0 :         return NS_SUCCEEDED(mStatus) ? NS_BASE_STREAM_CLOSED : mStatus;
         630                 :
         631                 :     nsAHttpTransaction *trans;
         632                 :     nsresult rv;
         633                 :
         634               0 :     trans = Response(0);
         635               0 :     if (!trans) {
         636               0 :         if (mRequestQ.Length() > 0)
         637               0 :             rv = NS_BASE_STREAM_WOULD_BLOCK;
         638                 :         else
         639               0 :             rv = NS_BASE_STREAM_CLOSED;
         640                 :     }
         641                 :     else {
         642                 :         //
         643                 :         // ask the transaction to consume data from the connection.
         644                 :         // PushBack may be called recursively.
         645                 :         //
         646               0 :         rv = trans->WriteSegments(writer, count, countWritten);
         647                 :
         648               0 :         if (rv == NS_BASE_STREAM_CLOSED || trans->IsDone()) {
         649               0 :             trans->Close(NS_OK);
         650               0 :             NS_RELEASE(trans);
         651               0 :             mResponseQ.RemoveElementAt(0);
         652               0 :             mResponseIsPartial = false;
         653               0 :             ++mHttp1xTransactionCount;
         654                 :
         655                 :             // ask the connection manager to add additional transactions
         656                 :             // to our pipeline.
         657               0 :             gHttpHandler->ConnMgr()->AddTransactionToPipeline(this);
         658                 :         }
         659                 :         else
         660               0 :             mResponseIsPartial = true;
         661                 :     }
         662                 :
         663               0 :     if (mPushBackLen) {
         664               0 :         nsHttpPushBackWriter writer(mPushBackBuf, mPushBackLen);
         665               0 :         PRUint32 len = mPushBackLen, n;
         666               0 :         mPushBackLen = 0;
         667                 :
         668                 :         // This progress notification has previously been sent from
         669                 :         // the socket transport code, but it was delivered to the
         670                 :         // previous transaction on the pipeline.
         671               0 :         nsITransport *transport = Transport();
         672               0 :         if (transport)
         673                 :             OnTransportStatus(transport,
         674                 :                               nsISocketTransport::STATUS_RECEIVING_FROM,
         675               0 :                               mReceivingFromProgress);
         676                 :
         677                 :         // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE,
         678                 :         // so we are guaranteed that the next response will eat the entire
         679                 :         // push back buffer (even though it might again call PushBack).
         680               0 :         rv = WriteSegments(&writer, len, &n);
         681                 :     }
         682                 :
         683               0 :     return rv;
         684                 : }
         685                 :
         686                 : void
         687               0 : nsHttpPipeline::Close(nsresult reason)
         688                 : {
         689               0 :     LOG(("nsHttpPipeline::Close [this=%x reason=%x]\n", this, reason));
         690                 :
         691               0 :     if (mClosed) {
         692               0 :         LOG(("  already closed\n"));
         693               0 :         return;
         694                 :     }
         695                 :
         696                 :     // the connection is going away!
         697               0 :     mStatus = reason;
         698               0 :     mClosed = true;
         699                 :
         700                 :     PRUint32 i, count;
         701                 :     nsAHttpTransaction *trans;
         702                 :
         703                 :     // any pending requests can ignore this error and be restarted
         704               0 :     count = mRequestQ.Length();
         705               0 :     for (i=0; i<count; ++i) {
         706               0 :         trans = Request(i);
         707               0 :         trans->Close(NS_ERROR_NET_RESET);
         708               0 :         NS_RELEASE(trans);
         709                 :     }
         710               0 :     mRequestQ.Clear();
         711                 :
         712               0 :     trans = Response(0);
         713               0 :     if (trans) {
         714                 :         // if the current response is partially complete, then it cannot be
         715                 :         // restarted and will have to fail with the status of the connection.
         716               0 :         if (mResponseIsPartial)
         717               0 :             trans->Close(reason);
         718                 :         else
         719               0 :             trans->Close(NS_ERROR_NET_RESET);
         720               0 :         NS_RELEASE(trans);
         721                 :
         722                 :         // any remaining pending responses can be restarted
         723               0 :         count = mResponseQ.Length();
         724               0 :         for (i=1; i<count; ++i) {
         725               0 :             trans = Response(i);
         726               0 :             trans->Close(NS_ERROR_NET_RESET);
         727               0 :             NS_RELEASE(trans);
         728                 :         }
         729               0 :         mResponseQ.Clear();
         730                 :     }
         731                 :
         732                 : }
         733                 :
         734                 : nsresult
         735               0 : nsHttpPipeline::OnReadSegment(const char *segment,
         736                 :                               PRUint32 count,
         737                 :                               PRUint32 *countRead)
         738                 : {
         739               0 :     return mSendBufOut->Write(segment, count, countRead);
         740                 : }
         741                 :
         742                 : nsresult
         743               0 : nsHttpPipeline::FillSendBuf()
         744                 : {
         745                 :     // reads from request queue, moving transactions to response queue
         746                 :     // when they have been completely read.
         747                 :
         748                 :     nsresult rv;
         749                 :
         750               0 :     if (!mSendBufIn) {
         751                 :         // allocate a single-segment pipe
         752               0 :         rv = NS_NewPipe(getter_AddRefs(mSendBufIn),
         753               0 :                         getter_AddRefs(mSendBufOut),
         754                 :                         nsIOService::gDefaultSegmentSize,  /* segment size */
         755                 :                         nsIOService::gDefaultSegmentSize,  /* max size */
         756               0 :                         true, true);
         757               0 :         if (NS_FAILED(rv)) return rv;
         758                 :     }
         759                 :
         760                 :     PRUint32 n, avail;
         761                 :     nsAHttpTransaction *trans;
         762               0 :     nsITransport *transport = Transport();
         763                 :
         764               0 :     while ((trans = Request(0)) != nsnull) {
         765               0 :         avail = trans->Available();
         766               0 :         if (avail) {
         767               0 :             rv = trans->ReadSegments(this, avail, &n);
         768               0 :             if (NS_FAILED(rv)) return rv;
         769                 :
         770               0 :             if (n == 0) {
         771               0 :                 LOG(("send pipe is full"));
         772               0 :                 break;
         773                 :             }
         774                 :
         775               0 :             mSendingToProgress += n;
         776               0 :             if (!mSuppressSendEvents && transport) {
         777                 :                 // Simulate a SENDING_TO event
         778                 :                 trans->OnTransportStatus(transport,
         779                 :                                          NS_NET_STATUS_SENDING_TO,
         780               0 :                                          mSendingToProgress);
         781                 :             }
         782                 :         }
         783                 :
         784               0 :         avail = trans->Available();
         785               0 :         if (avail == 0) {
         786                 :             // move transaction from request queue to response queue
         787               0 :             mRequestQ.RemoveElementAt(0);
         788               0 :             mResponseQ.AppendElement(trans);
         789               0 :             mRequestIsPartial = false;
         790                 :
         791               0 :             if (!mSuppressSendEvents && transport) {
         792                 :                 // Simulate a WAITING_FOR event
         793                 :                 trans->OnTransportStatus(transport,
         794                 :                                          NS_NET_STATUS_WAITING_FOR,
         795               0 :                                          mSendingToProgress);
         796                 :             }
         797                 :         }
         798                 :         else
         799               0 :             mRequestIsPartial = true;
         800                 :     }
         801               0 :     return NS_OK;
         802                 : }

Generated by: LCOV version 1.7