From 7927a9bae0158b321c8b324ccf7a57df467adc18 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Thu, 1 Dec 2011 09:19:41 -0500 Subject: [PATCH] bug 671875 pipeline transport event fixups r=honzab --- netwerk/protocol/http/nsAHttpConnection.h | 7 +- netwerk/protocol/http/nsHttpConnection.h | 1 + netwerk/protocol/http/nsHttpConnectionMgr.cpp | 8 ++ netwerk/protocol/http/nsHttpPipeline.cpp | 118 ++++++++++++++++-- netwerk/protocol/http/nsHttpPipeline.h | 5 + 5 files changed, 128 insertions(+), 11 deletions(-) diff --git a/netwerk/protocol/http/nsAHttpConnection.h b/netwerk/protocol/http/nsAHttpConnection.h index fecb9f6e548..1e0e42dfbed 100644 --- a/netwerk/protocol/http/nsAHttpConnection.h +++ b/netwerk/protocol/http/nsAHttpConnection.h @@ -124,6 +124,10 @@ public: // Transfer the base http connection object along with a // reference to it to the caller. virtual nsHttpConnection *TakeHttpConnection() = 0; + + // Get the nsISocketTransport used by the connection without changing + // references or ownership. + virtual nsISocketTransport *Transport() = 0; }; #define NS_DECL_NSAHTTPCONNECTION \ @@ -141,6 +145,7 @@ public: nsresult PushBack(const char *, PRUint32); \ bool LastTransactionExpectedNoContent(); \ void SetLastTransactionExpectedNoContent(bool); \ - nsHttpConnection *TakeHttpConnection(); + nsHttpConnection *TakeHttpConnection(); \ + nsISocketTransport *Transport(); #endif // nsAHttpConnection_h__ diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index 256548d2479..26c3696976d 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -123,6 +123,7 @@ public: mLastTransactionExpectedNoContent = val; } + nsISocketTransport *Transport() { return mSocketTransport; } nsAHttpTransaction *Transaction() { return mTransaction; } nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 23ef89334e3..5a158304b44 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -1693,3 +1693,11 @@ nsConnectionHandle::SetLastTransactionExpectedNoContent(bool val) { mConn->SetLastTransactionExpectedNoContent(val); } + +nsISocketTransport * +nsHttpConnectionMgr::nsConnectionHandle::Transport() +{ + if (!mConn) + return nsnull; + return mConn->Transport(); +} diff --git a/netwerk/protocol/http/nsHttpPipeline.cpp b/netwerk/protocol/http/nsHttpPipeline.cpp index 1ed0b907551..e8d48d95cd5 100644 --- a/netwerk/protocol/http/nsHttpPipeline.cpp +++ b/netwerk/protocol/http/nsHttpPipeline.cpp @@ -101,6 +101,9 @@ nsHttpPipeline::nsHttpPipeline() , mPushBackBuf(nsnull) , mPushBackLen(0) , mPushBackMax(0) + , mReceivingFromProgress(0) + , mSendingToProgress(0) + , mSuppressSendEvents(true) { } @@ -325,6 +328,14 @@ nsHttpPipeline::TakeHttpConnection() return nsnull; } +nsISocketTransport * +nsHttpPipeline::Transport() +{ + if (!mConnection) + return nsnull; + return mConnection->Transport(); +} + void nsHttpPipeline::SetSSLConnectFailed() { @@ -390,21 +401,80 @@ nsHttpPipeline::OnTransportStatus(nsITransport* transport, NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); nsAHttpTransaction *trans; + PRInt32 i, count; + switch (status) { - case NS_NET_STATUS_RECEIVING_FROM: - // forward this only to the transaction currently recieving data - trans = Response(0); + + case NS_NET_STATUS_RESOLVING_HOST: + case NS_NET_STATUS_RESOLVED_HOST: + case NS_NET_STATUS_CONNECTING_TO: + case NS_NET_STATUS_CONNECTED_TO: + // These should only appear at most once per pipeline. + // Deliver to the first transaction. + + trans = Request(0); + if (!trans) + trans = Response(0); if (trans) trans->OnTransportStatus(transport, status, progress); + break; - default: - // forward other notifications to all transactions - PRInt32 i, count = mRequestQ.Length(); - for (i=0; iOnTransportStatus(transport, status, progress); + + case NS_NET_STATUS_SENDING_TO: + // This is generated by the socket transport when (part) of + // a transaction is written out + // + // In pipelining this is generated out of FillSendBuf(), but it cannot do + // so until the connection is confirmed by CONNECTED_TO. + // See patch for bug 196827. + // + + if (mSuppressSendEvents) { + mSuppressSendEvents = false; + + // catch up by sending the event to all the transactions that have + // moved from request to response and any that have been partially + // sent. Also send WAITING_FOR to those that were completely sent + count = mResponseQ.Length(); + for (i = 0; i < count; ++i) { + Response(i)->OnTransportStatus(transport, + NS_NET_STATUS_SENDING_TO, + progress); + Response(i)->OnTransportStatus(transport, + NS_NET_STATUS_WAITING_FOR, + progress); + } + if (mRequestIsPartial && Request(0)) + Request(0)->OnTransportStatus(transport, + NS_NET_STATUS_SENDING_TO, + progress); + mSendingToProgress = progress; } + // otherwise ignore it + break; + + case NS_NET_STATUS_WAITING_FOR: + // Created by nsHttpConnection when request pipeline has been totally + // sent. Ignore it here because it is simulated in FillSendBuf() when + // a request is moved from request to response. + + // ignore it + break; + + case NS_NET_STATUS_RECEIVING_FROM: + // Forward this only to the transaction currently recieving data. It is + // normally generated by the socket transport, but can also + // be repeated by the pushbackwriter if necessary. + mReceivingFromProgress = progress; + if (Response(0)) + Response(0)->OnTransportStatus(transport, status, progress); + break; + + default: + // forward other notifications to all request transactions + count = mRequestQ.Length(); + for (i = 0; i < count; ++i) + Request(i)->OnTransportStatus(transport, status, progress); break; } } @@ -548,6 +618,16 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer, nsHttpPushBackWriter writer(mPushBackBuf, mPushBackLen); PRUint32 len = mPushBackLen, n; mPushBackLen = 0; + + // This progress notification has previously been sent from + // the socket transport code, but it was delivered to the + // previous transaction on the pipeline. + nsITransport *transport = Transport(); + if (transport) + OnTransportStatus(transport, + nsISocketTransport::STATUS_RECEIVING_FROM, + mReceivingFromProgress); + // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE, // so we are guaranteed that the next response will eat the entire // push back buffer (even though it might again call PushBack). @@ -638,6 +718,8 @@ nsHttpPipeline::FillSendBuf() PRUint32 n, avail; nsAHttpTransaction *trans; + nsITransport *transport = Transport(); + while ((trans = Request(0)) != nsnull) { avail = trans->Available(); if (avail) { @@ -648,13 +730,29 @@ nsHttpPipeline::FillSendBuf() LOG(("send pipe is full")); break; } + + mSendingToProgress += n; + if (!mSuppressSendEvents && transport) { + // Simulate a SENDING_TO event + trans->OnTransportStatus(transport, + NS_NET_STATUS_SENDING_TO, + mSendingToProgress); + } } + avail = trans->Available(); if (avail == 0) { // move transaction from request queue to response queue mRequestQ.RemoveElementAt(0); mResponseQ.AppendElement(trans); mRequestIsPartial = false; + + if (!mSuppressSendEvents && transport) { + // Simulate a WAITING_FOR event + trans->OnTransportStatus(transport, + NS_NET_STATUS_WAITING_FOR, + mSendingToProgress); + } } else mRequestIsPartial = true; diff --git a/netwerk/protocol/http/nsHttpPipeline.h b/netwerk/protocol/http/nsHttpPipeline.h index 6e267b58c1b..c78a72589d8 100644 --- a/netwerk/protocol/http/nsHttpPipeline.h +++ b/netwerk/protocol/http/nsHttpPipeline.h @@ -111,6 +111,11 @@ private: char *mPushBackBuf; PRUint32 mPushBackLen; PRUint32 mPushBackMax; + + // For support of OnTransportStatus() + PRUint64 mReceivingFromProgress; + PRUint64 mSendingToProgress; + bool mSuppressSendEvents; }; #endif // nsHttpPipeline_h__