jsr369-experts@servlet-spec.java.net

[jsr369-experts] Re: [servlet-spec users] Re: Trailer header implementation

From: Greg Wilkins <gregw_at_webtide.com>
Date: Fri, 5 May 2017 09:12:13 +0200

Ba, Bb, C, Ab, Aa

For requests, I prefer not mixing trailers with the header API.

cheers


On 5 May 2017 02:54, "Shing Wai Chan" <shing.wai.chan_at_oracle.com> wrote:

There are three main questions on trailer.
Let me try to summarize it from my point of view.

Section 1: is trailer supported?
RFC 7230, Section 4.3 TE
   The "TE" header field in a request indicates what transfer codings,
   besides chunked, the client is willing to accept in response, and
   whether or not the client is willing to accept trailer fields in a
   chunked transfer coding.

   The presence of the keyword "trailers" indicates that the client is
   willing to accept trailer fields in a chunked transfer coding, as
   defined in Section 4.1.2, on behalf of itself and any downstream
   clients.

MT has proposed an API to query whether trailer is supported.
And we will need to add a API in HttpServletRequest. The following are
options:
a) public boolean areTrailerFieldSupported(); // from MT
b) public false isTrailerFieldSupportSpecified(); // from MM
c) public boolean isTrailerSupported();
d) no new API users can just query TE header from the request

In (a)-(c), we will add an default method returning false.


Section 2: set trailer
RFC 7230, Section 4.4 Trailer
   When a message includes a message body encoded with the chunked
   transfer coding and the sender desires to send metadata in the form
   of trailer fields at the end of the message, the sender SHOULD
   generate a Trailer header field before the message body to indicate
   which fields will be present in the trailers. This allows the
   recipient to prepare for receipt of that metadata before it starts
   processing the body, which is useful if the message is being streamed
   and the recipient wishes to confirm an integrity check on the fly.

MT, GW and MM has a discussion on this.
The main issues are
1) generation of Http header with name "Trailer"
2) what happens when supplier generate headers with names other than those
in (1)
3) when can we call #setTrailerFields

The following are options (adapted from MT with additional comments):
Aa) Keep the existing API:
    void setTrailerFields(Supplier<Map<String, String>>)
   For (1), it is developer's responsibility to generate the http header
"Trailer".
   For (2), servlet container can
        a) only send headers specified in (1), ignore those headers not
specified in (1).
   For (3), the API can be called before response commit

Ab) Keep the existing API:
    void setTrailerFields(Supplier<Map<String, String>>)
   For (1), it is developer's responsibility to generate the http header
"Trailer".
   For (2), servlet container can
        b) send all the headers in supplier
   For (3), the API can be called before response commit

Ba) New API for each trailer field:
    void setTrailer(String name, Supplier<String>)
   For (1), it is the container's responsibility to write the http header
"Trailer".
        Servlet container will:
        a) ignore the http header "Trailer" set by developer.
   For (2), it is not an issue.
   For (3), #setTrailerFields needs to be called before the any body
message committed.

Bb) New API for each trailer field:
    void setTrailer(String name, Supplier<String>)
   For (1), it is the container's responsibility to write the http header
"Trailer".
        Servlet container will:
        b) clear the http header "Trailer" set by developer.
   For (2), it is not an issue.
   For (3), #setTrailerFields needs to be called before the any body
message committed.

C) New API for the whole trailer:
    void setTrailer(Function<String, String>)
   For (1), it is the developer's responsibility to generate the http
header "Trailer".
   For (2), this will not happen for this API as container read trailer
field
   names from "Trailer" http header.
   For (3), the API can be called before response commit

With the above setting, I believe Mark's preferences are
    (Ba), (Bb), (Ab), (Aa), (C)

In B's, we need to restrict when we can call the API.
Is it simplier to hava A's and C?
Any other opinion?


Section 3: get trailer
MM> For an inbound trailer Section 4.1.2 of RFC2370 says:
MM> <quote>
MM> When a chunked message containing a non-empty trailer is received,
MM> the recipient MAY process the fields (aside from those forbidden
MM> above) as if they were appended to the message's header section.
MM> </quote>
MM> So in addition to getTrailers() we should make the trailer headers
available
MM> through the getHeader() api's and automatically add them when they
become
MM> available (all inbound data is read).
MM> But this leads me to a concern that the RFC is a specification of how
MM> the transport layer should behave and it s not clear to me how much of
this transport
MM> function should be exposed in the Servlet Specification. In the Servlet
Spec we
MM> should not be making assumptions about how the transport layer works in
which case
MM> we should not have a getTrailers() API but instead we just expose the
headers using
MM> existing api's once all the data is read. That way we work whether or
not the transport
MM> layer exposes the trailer headers or not.

On April 6, 2017, I proposed (in (a) StandardHeader option [1])
to use the standard header APIs as one of the option to retrieve trailer
fields.
This option was rejected in [2] and [3] as follows:

GW> with regards to request trailers, the key decision is when they are
GW> available, specially with async. Does the application have to read
content
GW> to -1 or onAllDataRead before the trailers are available? I think yes.
GW> Then it does not make much sense to make them available via the normal
GW> header API and I think they need their own API.

SD> I don't think this is a good approach. The trailers will not be
SD> available immediately, so this will basically result in the headers
SD> changing after the request has been read. I think it could be very
SD> confusing to the developer.

Since the trailer fields are processed "as if they were appended to the
message's
header section."
Should trailer fields be available to get header API's, too?

Any comments?

Shing Wai Chan

ps.
[1] https://java.net/projects/servlet-spec/lists/jsr369-
experts/archive/2017-04/message/5
[2] https://java.net/projects/servlet-spec/lists/jsr369-
experts/archive/2017-04/message/6
[3] https://java.net/projects/servlet-spec/lists/jsr369-
experts/archive/2017-04/message/7



On May 4, 2017, at 8:29 AM, Martin Mulholland <mmulholl_at_us.ibm.com> wrote:

For an inbound trailer Section 4.1.2 of RFC2370 says:

<quote>
     When a chunked message containing a non-empty trailer is received,
     the recipient MAY process the fields (aside from those forbidden
     above) as if they were appended to the message's header section.
</quote>

So in addition to getTrailers() we should make the trailer headers available
through the getHeader() api's and automatically add them when they become
available (all inbound data is read).

But this leads me to a concern that the RFC is a specification of how
the transport layer should behave and it s not clear to me how much of this
transport
function should be exposed in the Servlet Specification. In the Servlet
Spec we
should not be making assumptions about how the transport layer works in
which case
we should not have a getTrailers() API but instead we just expose the
headers using
existing api's once all the data is read. That way we work whether or not
the transport
layer exposes the trailer headers or not.


Thank you,
Martin Mulholland.




From: Mark Thomas <markt_at_apache.org>
To: jsr369-experts_at_servlet-spec.java.net
Date: 05/03/2017 07:03 AM
Subject: [servlet-spec users] [jsr369-experts] Trailer header
implementation
------------------------------



Hi,

I've been working on trailer header implementation. No particular issues
with requests but the response implementation is identifying a lot of
questions.

The first one is triggered by Section 4.4 for RFC 7230:

<quote
  When a message includes a message body encoded with the chunked
  transfer coding and the sender desires to send metadata in the form
  of trailer fields at the end of the message, the sender SHOULD
  generate a Trailer header field before the message body to indicate
  which fields will be present in the trailers. This allows the
  recipient to prepare for receipt of that metadata before it starts
  processing the body, which is useful if the message is being streamed
  and the recipient wishes to confirm an integrity check on the fly.
</quote>

1. How is the container meant to construct the Trailer header field? The
point of using a supplier was so the header names and values did not
have to be known when the response was committed. However, section 4.4
requires that the names are known.

The remaining questions are a little simpler:

2. What happens if setTrailerFields() is called after the response is
committed?

3. What happens if setTrailerFields() is called and trailer fields are
not supported (HTTP 0.9, HTTP 1.0, some proxy protocols, etc.)?

4. What happens if setTrailerFields() is called multiple times?

5. What happens if setTrailerFields() is called with a null Supplier?

My current thinking:

1) Do we ignore the 'SHOULD' or do we change the API? I'm leaning
towards changing the API on the basis that if we are going to add
trailer support we should do it as correctly as possible.

2) Throw an IllegalStateException
  But. It also depends on 1). If we don't have to set the Trailers
  header it may still be possible to send the trailer fields

3) Throw an IllegalStateException

4) Use the most recent Supplier

5) Allow it and protect against any possible NPE in the container


Of these, 1) is the most serious to address. After that, 2) & 3) since
the application has no way to tell if this is going to happen. Do we
need a boolean areTrailerFieldsSupported() method?

Mark