|
@@ -0,0 +1,107 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Kershaw Chang <kershaw@mozilla.com>
|
|
|
+# Date 1712320006 0
|
|
|
+# Node ID 97c5754df7dd0da57e84682d3fc788788ad4c362
|
|
|
+# Parent 327fde4c35892a8a15725bd7a5acd4ff5a7851c5
|
|
|
+Bug 1881183 - Avoid allocating too much memory when receiving CONTINUATION frame, a=RyanVM
|
|
|
+
|
|
|
+Original Revision: https://phabricator.services.mozilla.com/D205234
|
|
|
+
|
|
|
+Differential Revision: https://phabricator.services.mozilla.com/D206699
|
|
|
+
|
|
|
+diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp
|
|
|
+--- a/netwerk/protocol/http/Http2Session.cpp
|
|
|
++++ b/netwerk/protocol/http/Http2Session.cpp
|
|
|
+@@ -108,16 +108,17 @@ Http2Session::Http2Session(nsISocketTran
|
|
|
+ , mServerSessionWindow(kDefaultRwin)
|
|
|
+ , mInitialRwin(ASpdySession::kInitialRwin)
|
|
|
+ , mOutputQueueSize(kDefaultQueueSize)
|
|
|
+ , mOutputQueueUsed(0)
|
|
|
+ , mOutputQueueSent(0)
|
|
|
+ , mLastReadEpoch(PR_IntervalNow())
|
|
|
+ , mPingSentEpoch(0)
|
|
|
+ , mPreviousUsed(false)
|
|
|
++ , mAggregatedHeaderSize(0)
|
|
|
+ , mWaitingForSettingsAck(false)
|
|
|
+ , mGoAwayOnPush(false)
|
|
|
+ , mUseH2Deps(false)
|
|
|
+ , mAttemptingEarlyData(attemptingEarlyData)
|
|
|
+ , mOriginFrameActivated(false)
|
|
|
+ , mTlsHandshakeFinished(false)
|
|
|
+ , mCheckNetworkStallsWithTFO(false)
|
|
|
+ , mLastRequestBytesSentTime(0)
|
|
|
+@@ -1347,29 +1348,39 @@ Http2Session::RecvHeaders(Http2Session *
|
|
|
+ paddingLength,
|
|
|
+ self->mInputFrameFlags & kFlag_PADDED));
|
|
|
+
|
|
|
+ if ((paddingControlBytes + priorityLen + paddingLength) > self->mInputFrameDataSize) {
|
|
|
+ // This is fatal to the session
|
|
|
+ RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
|
|
|
+ }
|
|
|
+
|
|
|
++ uint32_t frameSize = self->mInputFrameDataSize - paddingControlBytes -
|
|
|
++ priorityLen - paddingLength;
|
|
|
++ if (self->mAggregatedHeaderSize + frameSize >
|
|
|
++ gHttpHandler->MaxHttpResponseHeaderSize()) {
|
|
|
++ LOG(("Http2Session %p header exceeds the limit\n", self));
|
|
|
++ RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
|
|
|
++ }
|
|
|
++
|
|
|
+ if (!self->mInputFrameDataStream) {
|
|
|
+ // Cannot find stream. We can continue the session, but we need to
|
|
|
+ // uncompress the header block to maintain the correct compression context
|
|
|
+
|
|
|
+ LOG3(("Http2Session::RecvHeaders %p lookup mInputFrameID stream "
|
|
|
+ "0x%X failed. NextStreamID = 0x%X\n",
|
|
|
+ self, self->mInputFrameID, self->mNextStreamID));
|
|
|
+
|
|
|
+ if (self->mInputFrameID >= self->mNextStreamID)
|
|
|
+ self->GenerateRstStream(PROTOCOL_ERROR, self->mInputFrameID);
|
|
|
+
|
|
|
+- self->mDecompressBuffer.Append(&self->mInputFrameBuffer[kFrameHeaderBytes + paddingControlBytes + priorityLen],
|
|
|
+- self->mInputFrameDataSize - paddingControlBytes - priorityLen - paddingLength);
|
|
|
++ self->mDecompressBuffer.Append(
|
|
|
++ &self->mInputFrameBuffer[kFrameHeaderBytes + paddingControlBytes +
|
|
|
++ priorityLen],
|
|
|
++ frameSize);
|
|
|
+
|
|
|
+ if (self->mInputFrameFlags & kFlag_END_HEADERS) {
|
|
|
+ rv = self->UncompressAndDiscard(false);
|
|
|
+ if (NS_FAILED(rv)) {
|
|
|
+ LOG3(("Http2Session::RecvHeaders uncompress failed\n"));
|
|
|
+ // this is fatal to the session
|
|
|
+ self->mGoAwayReason = COMPRESSION_ERROR;
|
|
|
+ return rv;
|
|
|
+@@ -1385,26 +1396,28 @@ Http2Session::RecvHeaders(Http2Session *
|
|
|
+ !(self->mInputFrameFlags & kFlag_END_STREAM)) {
|
|
|
+ // Any header block after the first that does *not* end the stream is
|
|
|
+ // illegal.
|
|
|
+ LOG3(("Http2Session::Illegal Extra HeaderBlock %p 0x%X\n", self, self->mInputFrameID));
|
|
|
+ RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
|
|
|
+ }
|
|
|
+
|
|
|
+ // queue up any compression bytes
|
|
|
+- self->mDecompressBuffer.Append(&self->mInputFrameBuffer[kFrameHeaderBytes + paddingControlBytes + priorityLen],
|
|
|
+- self->mInputFrameDataSize - paddingControlBytes - priorityLen - paddingLength);
|
|
|
++ self->mDecompressBuffer.Append(
|
|
|
++ &self->mInputFrameBuffer[kFrameHeaderBytes + paddingControlBytes +
|
|
|
++ priorityLen],
|
|
|
++ frameSize);
|
|
|
+
|
|
|
+ self->mInputFrameDataStream->UpdateTransportReadEvents(self->mInputFrameDataSize);
|
|
|
+ self->mLastDataReadEpoch = self->mLastReadEpoch;
|
|
|
+
|
|
|
+ if (!isContinuation) {
|
|
|
+- self->mAggregatedHeaderSize = self->mInputFrameDataSize - paddingControlBytes - priorityLen - paddingLength;
|
|
|
++ self->mAggregatedHeaderSize = frameSize;
|
|
|
+ } else {
|
|
|
+- self->mAggregatedHeaderSize += self->mInputFrameDataSize - paddingControlBytes - priorityLen - paddingLength;
|
|
|
++ self->mAggregatedHeaderSize += frameSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!endHeadersFlag) { // more are coming - don't process yet
|
|
|
+ self->ResetDownstreamState();
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ rv = self->ResponseHeadersComplete();
|