Commit 909a2d69 authored by Randell Jesup's avatar Randell Jesup Committed by Pier Angelo Vendrame
Browse files

Bug 1577576: return an error on an invalid frame ID in HTTP2 r=necko-reviewers,valentin

parent 1019abeb
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -2144,7 +2144,11 @@ nsresult Http2Session::RecvWindowUpdate(Http2Session* self) {

nsresult Http2Session::RecvContinuation(Http2Session* self) {
  MOZ_ASSERT(self->mInputFrameType == FRAME_TYPE_CONTINUATION);
  MOZ_ASSERT(self->mInputFrameID);
  if (!self->mInputFrameID) {  // must be checked before the other assertions
    LOG3(("Http2Session::RecvContinuation %p stream ID of 0 - PROTOCOL_ERROR\n",
          self));
    return self->SessionError(PROTOCOL_ERROR);
  }
  MOZ_ASSERT(self->mExpectedPushPromiseID || self->mExpectedHeaderID);
  MOZ_ASSERT(!(self->mExpectedPushPromiseID && self->mExpectedHeaderID));

+15 −0
Original line number Diff line number Diff line
@@ -948,6 +948,21 @@ async function test_http2_empty_data(serverPort) {
  });
}

async function test_http2_continuation_stream_zero(
  serverPort,
  origin = "localhost"
) {
  var chan = makeHTTPChannel(
    `https://${origin}:${serverPort}/continuation_stream_zero`
  );
  return new Promise(resolve => {
    var listener = new Http2CheckListener();
    listener.finish = resolve;
    listener.shouldSucceed = false;
    chan.asyncOpen(listener);
  });
}

async function test_http2_status_phrase(serverPort) {
  var chan = makeHTTPChannel(`https://localhost:${serverPort}/statusphrase`);
  return new Promise(resolve => {
+6 −0
Original line number Diff line number Diff line
@@ -295,6 +295,12 @@ add_task(async function do_test_http2_empty_data() {
  Assert.equal(httpProxyConnectResponseCode, -1);
});

add_task(async function do_test_http2_continuation_stream_zero() {
  const { httpProxyConnectResponseCode } =
    await test_http2_continuation_stream_zero(serverPort);
  Assert.equal(httpProxyConnectResponseCode, -1);
});

add_task(async function do_test_http2_status_phrase() {
  const { httpProxyConnectResponseCode } =
    await test_http2_status_phrase(serverPort);
+6 −0
Original line number Diff line number Diff line
@@ -236,6 +236,12 @@ add_task(async function do_test_http2_empty_data() {
  Assert.equal(httpProxyConnectResponseCode, 200);
});

add_task(async function do_test_http2_continuation_stream_zero() {
  const { httpProxyConnectResponseCode } =
    await test_http2_continuation_stream_zero(serverPort);
  Assert.equal(httpProxyConnectResponseCode, 200);
});

add_task(async function do_test_http2_status_phrase() {
  const { httpProxyConnectResponseCode } =
    await test_http2_status_phrase(serverPort);
+22 −0
Original line number Diff line number Diff line
@@ -78,6 +78,26 @@ var newTransform = function (frame) {
  originalTransform.apply(this, arguments);
};

// Injects a raw CONTINUATION frame with stream ID 0 before the first HEADERS
// frame. Since there is no pending HEADERS or PUSH_PROMISE, mExpectedHeaderID
// and mExpectedPushPromiseID are both 0, so the pre-dispatch checks are
// skipped and RecvContinuation is called with mInputFrameID = 0.
var newTransformContinuationStreamZero = function (frame) {
  if (frame.type == "HEADERS") {
    const contFrame = Buffer.alloc(9);
    contFrame[0] = 0x00; // length high
    contFrame[1] = 0x00; // length mid
    contFrame[2] = 0x00; // length low (no payload)
    contFrame[3] = 0x09; // type = CONTINUATION
    contFrame[4] = 0x04; // flags = END_HEADERS
    // stream ID bytes 5-8 remain 0x00 — stream ID = 0 (protocol error)
    this.push(contFrame);

    Serializer.prototype._transform = originalTransform;
  }
  originalTransform.apply(this, arguments);
};

function getHttpContent(pathName) {
  var content =
    "<!doctype html>" +
@@ -1549,6 +1569,8 @@ function handleRequest(req, res) {
    // empty DATA frame at the beginning of the stream response, then fall
    // through to the default response behavior.
    Serializer.prototype._transform = newTransform;
  } else if (u.pathname === "/continuation_stream_zero") {
    Serializer.prototype._transform = newTransformContinuationStreamZero;
  }

  // for use with test_immutable.js