nsresult SpdyStream::OnReadSegment(const char *buf, PRUint32 count, PRUint32 *countRead) { LOG3(("SpdyStream::OnReadSegment %p count=%d state=%x", this, count, mUpstreamState)); NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ABORT_IF_FALSE(mSegmentReader, "OnReadSegment with null mSegmentReader"); nsresult rv = NS_ERROR_UNEXPECTED; PRUint32 dataLength; switch (mUpstreamState) { case GENERATING_SYN_STREAM: // The buffer is the HTTP request stream, including at least part of the // HTTP request header. This state's job is to build a SYN_STREAM frame // from the header information. count is the number of http bytes available // (which may include more than the header), and in countRead we return // the number of those bytes that we consume (i.e. the portion that are // header bytes) rv = ParseHttpRequestHeaders(buf, count, countRead); if (NS_FAILED(rv)) return rv; LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d", this, *countRead, count, mSynFrameComplete)); if (mSynFrameComplete) { NS_ABORT_IF_FALSE(mTxInlineFrameSize, "OnReadSegment SynFrameComplete 0b"); rv = TransmitFrame(nsnull, nsnull); if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead) rv = NS_OK; if (mTxInlineFrameSize) ChangeState(SENDING_SYN_STREAM); else ChangeState(GENERATING_REQUEST_BODY); break; } NS_ABORT_IF_FALSE(*countRead == count, "Header parsing not complete but unused data"); break; case GENERATING_REQUEST_BODY: NS_ABORT_IF_FALSE(!mTxInlineFrameSent, "OnReadSegment in generating_request_body with " "frame in progress"); dataLength = NS_MIN(count, mChunkSize); LOG3(("SpdyStream %p id %x request len remaining %d, " "count avail %d, chunk used %d", this, mStreamID, mRequestBodyLen, count, dataLength)); if (dataLength > mRequestBodyLen) return NS_ERROR_UNEXPECTED; mRequestBodyLen -= dataLength; GenerateDataFrameHeader(dataLength, !mRequestBodyLen); ChangeState(SENDING_REQUEST_BODY); // NO BREAK case SENDING_REQUEST_BODY: NS_ABORT_IF_FALSE(mTxInlineFrameSize, "OnReadSegment Send Data Header 0b"); rv = TransmitFrame(buf, countRead); LOG3(("TransmitFrame() rv=%x returning %d data bytes. " "Header is %d/%d Body is %d/%d.", rv, *countRead, mTxInlineFrameSent, mTxInlineFrameSize, mTxStreamFrameSent, mTxStreamFrameSize)); if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead) rv = NS_OK; // If that frame was all sent, look for another one if (!mTxInlineFrameSize) ChangeState(GENERATING_REQUEST_BODY); break; case SENDING_SYN_STREAM: rv = NS_BASE_STREAM_WOULD_BLOCK; break; case SENDING_FIN_STREAM: NS_ABORT_IF_FALSE(false, "resuming partial fin stream out of OnReadSegment"); break; default: NS_ABORT_IF_FALSE(false, "SpdyStream::OnReadSegment non-write state"); break; } return rv; }
nsresult SpdyStream2::OnReadSegment(const char *buf, uint32_t count, uint32_t *countRead) { LOG3(("SpdyStream2::OnReadSegment %p count=%d state=%x", this, count, mUpstreamState)); NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ABORT_IF_FALSE(mSegmentReader, "OnReadSegment with null mSegmentReader"); nsresult rv = NS_ERROR_UNEXPECTED; uint32_t dataLength; switch (mUpstreamState) { case GENERATING_SYN_STREAM: // The buffer is the HTTP request stream, including at least part of the // HTTP request header. This state's job is to build a SYN_STREAM frame // from the header information. count is the number of http bytes available // (which may include more than the header), and in countRead we return // the number of those bytes that we consume (i.e. the portion that are // header bytes) rv = ParseHttpRequestHeaders(buf, count, countRead); if (NS_FAILED(rv)) return rv; LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d", this, *countRead, count, mSynFrameComplete)); if (mSynFrameComplete) { NS_ABORT_IF_FALSE(mTxInlineFrameUsed, "OnReadSegment SynFrameComplete 0b"); rv = TransmitFrame(nullptr, nullptr, true); if (rv == NS_BASE_STREAM_WOULD_BLOCK) { // this can't happen NS_ABORT_IF_FALSE(false, "Transmit Frame SYN_FRAME must at least buffer data"); rv = NS_ERROR_UNEXPECTED; } ChangeState(GENERATING_REQUEST_BODY); break; } NS_ABORT_IF_FALSE(*countRead == count, "Header parsing not complete but unused data"); break; case GENERATING_REQUEST_BODY: dataLength = std::min(count, mChunkSize); LOG3(("SpdyStream2 %p id %x request len remaining %d, " "count avail %d, chunk used %d", this, mStreamID, mRequestBodyLenRemaining, count, dataLength)); if (dataLength > mRequestBodyLenRemaining) return NS_ERROR_UNEXPECTED; mRequestBodyLenRemaining -= dataLength; GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining); ChangeState(SENDING_REQUEST_BODY); // NO BREAK case SENDING_REQUEST_BODY: NS_ABORT_IF_FALSE(mTxInlineFrameUsed, "OnReadSegment Send Data Header 0b"); rv = TransmitFrame(buf, countRead, false); NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed, "Transmit Frame should be all or nothing"); LOG3(("TransmitFrame() rv=%x returning %d data bytes. " "Header is %d Body is %d.", rv, *countRead, mTxInlineFrameUsed, mTxStreamFrameSize)); // normalize a partial write with a WOULD_BLOCK into just a partial write // as some code will take WOULD_BLOCK to mean an error with nothing // written (e.g. nsHttpTransaction::ReadRequestSegment() if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead) rv = NS_OK; // If that frame was all sent, look for another one if (!mTxInlineFrameUsed) ChangeState(GENERATING_REQUEST_BODY); break; case SENDING_FIN_STREAM: NS_ABORT_IF_FALSE(false, "resuming partial fin stream out of OnReadSegment"); break; default: NS_ABORT_IF_FALSE(false, "SpdyStream2::OnReadSegment non-write state"); break; } return rv; }