diff --git a/netwerk/protocol/http/SpdySession31.cpp b/netwerk/protocol/http/SpdySession31.cpp index 97efc0e9c414..3f442837b71b 100644 --- a/netwerk/protocol/http/SpdySession31.cpp +++ b/netwerk/protocol/http/SpdySession31.cpp @@ -2102,6 +2102,13 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer, SpdyStream31 *stream = mInputFrameDataStream; mSegmentWriter = writer; rv = mInputFrameDataStream->WriteSegments(this, count, countWritten); + bool channelPipeFull = false; + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X " + "stream channel pipe full\n", + this, stream, stream ? stream->StreamID() : 0)); + channelPipeFull = mInputFrameDataStream->ChannelPipeFull(); + } mSegmentWriter = nullptr; mLastDataReadEpoch = mLastReadEpoch; @@ -2137,10 +2144,13 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer, } if (NS_FAILED(rv)) { - LOG3(("SpdySession31 %p data frame read failure %x\n", this, rv)); + LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X " + "data frame read failure %x pipefull=%d\n", + this, stream, stream ? stream->StreamID() : 0, rv, channelPipeFull)); // maybe just blocked reading from network - if (rv == NS_BASE_STREAM_WOULD_BLOCK) + if ((rv == NS_BASE_STREAM_WOULD_BLOCK) && !channelPipeFull) { rv = NS_OK; + } } return rv; diff --git a/netwerk/protocol/http/SpdyStream31.cpp b/netwerk/protocol/http/SpdyStream31.cpp index b3f6eaf386d7..746e5d57b854 100644 --- a/netwerk/protocol/http/SpdyStream31.cpp +++ b/netwerk/protocol/http/SpdyStream31.cpp @@ -229,6 +229,13 @@ SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer, return rv; } +bool +SpdyStream31::ChannelPipeFull() +{ + nsHttpTransaction *trans = mTransaction ? mTransaction->QueryHttpTransaction() : nullptr; + return trans ? trans->ChannelPipeFull() : false; +} + void SpdyStream31::CreatePushHashKey(const nsCString &scheme, const nsCString &hostHeader, diff --git a/netwerk/protocol/http/SpdyStream31.h b/netwerk/protocol/http/SpdyStream31.h index 6408c5cf145e..5502e9380058 100644 --- a/netwerk/protocol/http/SpdyStream31.h +++ b/netwerk/protocol/http/SpdyStream31.h @@ -88,6 +88,7 @@ public: int64_t LocalWindow() { return mLocalWindow; } bool BlockedOnRwin() { return mBlockedOnRwin; } + bool ChannelPipeFull(); // A pull stream has an implicit sink, a pushed stream has a sink // once it is matched to a pull stream. diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index 968938855c89..9ecaf866db09 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -1765,23 +1765,27 @@ nsHttpConnection::OnSocketReadable() break; } + mSocketInCondition = NS_OK; rv = mTransaction->WriteSegments(this, nsIOService::gDefaultSegmentSize, &n); + LOG(("nsHttpConnection::OnSocketReadable %p trans->ws rv=%x n=%d socketin=%x\n", + this, rv, n, mSocketInCondition)); if (NS_FAILED(rv)) { // if the transaction didn't want to take any more data, then // wait for the transaction to call ResumeRecv. - if (rv == NS_BASE_STREAM_WOULD_BLOCK) + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { rv = NS_OK; + } again = false; - } - else { + } else { mCurrentBytesRead += n; mTotalBytesRead += n; if (NS_FAILED(mSocketInCondition)) { // continue waiting for the socket if necessary... - if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) + if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) { rv = ResumeRecv(); - else + } else { rv = mSocketInCondition; + } again = false; } } diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index a1e03e287975..e25b581d0727 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -127,6 +127,7 @@ nsHttpTransaction::nsHttpTransaction() , mContentDecoding(false) , mContentDecodingCheck(false) , mDeferredSendProgress(false) + , mWaitingOnPipeOut(false) , mReportedStart(false) , mReportedResponseHeader(false) , mForTakeResponseHead(nullptr) @@ -832,9 +833,10 @@ nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer, if (rv == NS_BASE_STREAM_WOULD_BLOCK) { nsCOMPtr target; gHttpHandler->GetSocketThreadTarget(getter_AddRefs(target)); - if (target) + if (target) { mPipeOut->AsyncWait(this, 0, 0, target); - else { + mWaitingOnPipeOut = true; + } else { NS_ERROR("no socket thread event target"); rv = NS_ERROR_UNEXPECTED; } @@ -2179,6 +2181,7 @@ NS_IMPL_QUERY_INTERFACE(nsHttpTransaction, NS_IMETHODIMP nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out) { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); if (mConnection) { mConnection->TransactionHasDataToWrite(this); nsresult rv = mConnection->ResumeSend(); @@ -2196,6 +2199,8 @@ nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out) NS_IMETHODIMP nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out) { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + mWaitingOnPipeOut = false; if (mConnection) { mConnection->TransactionHasDataToRecv(this); nsresult rv = mConnection->ResumeRecv(); diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index b7021dc1311a..ce82230ba4d5 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -143,6 +143,7 @@ public: } void SetPushedStream(Http2PushedStream *push) { mPushedStream = push; } uint32_t InitialRwin() const { return mInitialRwin; }; + bool ChannelPipeFull() { return mWaitingOnPipeOut; } // Locked methods to get and set timing info const TimingStruct Timings(); @@ -306,6 +307,7 @@ private: bool mContentDecoding; bool mContentDecodingCheck; bool mDeferredSendProgress; + bool mWaitingOnPipeOut; // mClosed := transaction has been explicitly closed // mTransactionDone := transaction ran to completion or was interrupted