Re: Distinguishing 0-byte request body in HTTP/2

Kazuho Oku <> Thu, 15 September 2016 00:15 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 554E612B0F7 for <>; Wed, 14 Sep 2016 17:15:22 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -8.528
X-Spam-Status: No, score=-8.528 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.001, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_SORBS_SPAM=0.001, RP_MATCHES_RCVD=-1.508, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (2048-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id sIeLukunoQur for <>; Wed, 14 Sep 2016 17:15:20 -0700 (PDT)
Received: from ( []) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id 1729012B103 for <>; Wed, 14 Sep 2016 17:15:19 -0700 (PDT)
Received: from lists by with local (Exim 4.80) (envelope-from <>) id 1bkKG3-0005kI-IG for; Thu, 15 Sep 2016 00:10:27 +0000
Resent-Date: Thu, 15 Sep 2016 00:10:27 +0000
Resent-Message-Id: <>
Received: from ([]) by with esmtps (TLS1.2:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from <>) id 1bkKFw-0005ff-6u for; Thu, 15 Sep 2016 00:10:20 +0000
Received: from ([]) by with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from <>) id 1bkKFm-0000zG-Ce for; Thu, 15 Sep 2016 00:10:17 +0000
Received: by with SMTP id 1so61337020wmz.1 for <>; Wed, 14 Sep 2016 17:09:50 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=k0XsD0mxptJO6+KIK7+Eq5Q1LULDZSgopgOrpkZ5l3M=; b=OHBS/DU4YiIb4s/rL88Lbmq3EUr7E6lt7kFKN98/J9D36DYNixfPyXcrCCSdCXQg9l y79S9+eIgdtw4hnn3arv97qITeMRCKfLe8VwC9MeIFn5ddI3fqkNK5IR1SEKfKgAUvjA lcW74R9D86TNM6Po0WODUTEkAn9Ev5RUNyP4zPt7GqYqNZEeJjAkVIIy7UURqFQtZcMP uBC4I9bIu/phU2IEL2eAaIqXc2Nz+91szGQa7PGLaOBT4CChY6FnnRW9g0jml5j41m1r dpykAUV2liM6FSAUoVN2T1EssBXuzfoHjACsgedKma8M83HncwvnnxNDSxSVKdGSJ/Pf oZEA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=k0XsD0mxptJO6+KIK7+Eq5Q1LULDZSgopgOrpkZ5l3M=; b=bUmYuXdqX5Y5jjTtZMpDynQ1tjI+yUkCKotg/3xyTKwm6nCFNr3gyBEcRoLoXphqg7 SaXEN6ORo902ATyhh8BGa7tvp2sNfsiuXkzGO6K9LEeW+4ejIm9xhwhmyt1/gobm1q27 nSOdyU8B/Z9Vk/mkXPuz0/oa/aRtCgcOU0gxynFJt0uXvMbpmLQGK79X/LuZ2DYvMhr5 9uJn01SsQKnsvsHTYtuGf1NgNl+l5CXDrBuQKxfiJBe1Xr+tkQAHf2uarU0UWT7Noycg jW/LeVMWqY2/smnck7WIwDoA1zoWz5gjl9sg2e0d0PsV9wRhvnN3kOJtUopjCxb5fNFz r+KQ==
X-Gm-Message-State: AE9vXwPRmOuFCTEgMnuY6C76ZvMgDgt4ZZihcQyxkxxJt9xijD2sR5mZD0vrIEyv/GzmWG0LSrL9v8ApSaMGjA==
X-Received: by with SMTP id a143mr90478wme.66.1473898183890; Wed, 14 Sep 2016 17:09:43 -0700 (PDT)
MIME-Version: 1.0
Received: by with HTTP; Wed, 14 Sep 2016 17:09:42 -0700 (PDT)
In-Reply-To: <>
References: <> <>
From: Kazuho Oku <>
Date: Thu, 15 Sep 2016 09:09:42 +0900
Message-ID: <>
To: Mark Nottingham <>
Cc: HTTP Working Group <>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass client-ip=;;
X-W3C-Hub-Spam-Status: No, score=-5.2
X-W3C-Hub-Spam-Report: AWL=-0.966, BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_SORBS_SPAM=0.5, SPF_PASS=-0.001, W3C_AA=-1, W3C_WL=-1
X-W3C-Scan-Sig: 1bkKFm-0000zG-Ce b152055b13e1900bde898bcae1080e89
Subject: Re: Distinguishing 0-byte request body in HTTP/2
Archived-At: <>
X-Mailing-List: <> archive/latest/32397
Precedence: list
List-Id: <>
List-Help: <>
List-Post: <>
List-Unsubscribe: <>


Thank you very much for the clarification.

So to paraphrase, the general rule for handling request body is
defined in section 3.3.3 of RFC 7230 as:

   6.  If this is a request message and none of the above are true, then
       the message body length is zero (no message body is present).

which means that in HTTP, there is no distinction between a request
with zero-length body and a request _without_ a body.

That means it is completely up to the HTTP client to whether or not to
send `content-length: 0` for such requests, though each implementation
may decide to send or not, depending on interoperability issues that
might exist.

2016-09-15 8:21 GMT+09:00 Mark Nottingham <>et>:
> The rules in <> still apply:
>  - Any response to a HEAD has no body
>  - Any 1xx, 204 and 304 response has no body
>  - A 2xx response to a CONNECT has no body (because it's no longer HTTP after the header fields)
>  - Otherwise, the message has a body which might be 0-length.
> We intentionally made the set of messages without a body unable to be extended; see <>:
> """
> Since message parsing (Section 3.3 of [RFC7230]) needs to be independent of method semantics (aside from responses to HEAD), definitions of new methods cannot change the parsing algorithm or prohibit the presence of a message body on either the request or the response message. Definitions of new methods can specify that only a zero-length message body is allowed by requiring a Content-Length header field with a value of "0".
> """
> and <>:
> """
> To allow existing parsers to process the response message, new status codes cannot disallow a payload, although they can mandate a zero-length payload body.
> """
> Cheers,
>> On 15 Sep 2016, at 7:17 AM, Kazuho Oku <> wrote:
>> Hi,
>> Is there any way for a H2 server to distinguish between a request
>> without a body and a request with 0-byte body?
>> In HTTP/1, the distinction has been possible by looking for a
>> content-length or a transfer-encoding header. And H1 applications have
>> been actually looking for the headers to see if a request is
>> accompanied by a body by checking the existence of these headers.
>> OTOH, HTTP/2 does not seem to provide a method to distinguish between the two.
>> A HTTP/2 client is allowed to send a request accompanied by a body
>> without using the content-length header. It is also allowed to send a
>> HEADERS frame with END_STREAM flag set in case the size of the body is
>> zero-byte, omitting the DATA frame.
>> In such case, a request with zero-byte body becomes indistinguishable
>> from a request without a body.
>> The fact becomes an issue when we need to transcode a HTTP/2 request
>> to a HTTP/1 request (e.g. when a H2 proxy transmits a request to an H1
>> server running upstream), because, some applications try to see if a
>> POST request is accompanied by a body by checking the existence of
>> content-length or transfer-encoding header, or to assert that a GET
>> request is _not_ accompanied by a body by checking the non-existence
>> of the headers.
>> As a mitigation, it is certainly possible for a H2 proxy transcoding
>> to H1 to use the method of the request to see if content-length or
>> transfer-encoding header should be set in such case. But my
>> understanding is that generally speaking in HTTP whether if a request
>> is accompanied by a body is orthogonal to which method is being used.
>> Could somebody clarify what I am missing, or provide a method I should
>> use to accommodate the issue?
>> --
>> Kazuho Oku
> --
> Mark Nottingham

Kazuho Oku