Code change:
This reverts commit 290e381719b2fefe4e6182d3be288c48e8f5fd7e. See for most of the discussion. The key change here is to address by only requiring that the change be signaled when the table size is reduced. When I dug more into this, it's a more disruptive change, so I've made a bunch of additional changes in support of that.
I have one suggestion about a point that seems to be possible to infer from all this but is not explicitly written and may condition the sequencing of operations. Do we want to support multiple settings updates on this parameter, hence announce in the middle of a communication that we changed our local decoder size ? It seems to me that this is the case but it does not appear in the original text where it more likely sounds like the initial size. If we want to support repeated size changes from the decoder, then I agree that it's better to consider that 4096 is initial and that the setting changes it and Kazuho's wording sounds fine. But then it possibly ought to be explicitly mentioned such as: This makes sure that it's safe for an encoder to only process the settings frame once and to send a single DTSU instead of one per SETTINGS frame.
NAME I struggled a little with your text, because I think that is what this already says. However, to address your question about settings changes, I don't think that we do really want multiple settings changes, but that is the protocol we have. So multiple settings changes are possible and implied by the design of SETTINGS. Multiple changes are possible within the same SETTINGS frame, in case you were interested. The designers of this protocol seemed to love unnecessary complexity. There are some good reasons, but it's not clear that those reasons are sufficiently strong to justify the headaches they cause. I would really like it if implementations could just signal once in the preface, handle the preface from their peer and be done with settings. That's how HTTP/3 works and while we might have been forced into it there by the complexities of the QUIC integration, it turned out to be a good outcome in my view. Here, however, we need to deal with the fact that the protocol permits changes.
Hi NAME I'll have to clone your repo and run the diff here by hand then because I can't figure in this horrible interface how to view the complete set of changes at once resulting from multiple subsequent changes. And it will be easier to reread Kazuho's proposal in context. Regarding "do we want" I didn't imply that we love this situation, just "do we want in order to support this interpretation of the protocol", given that the current text never explicitly states that (as Cory mentioned a while ago, the settings change is acked by a the settings ack) and that even the protocol's original co-author back then already stated that it wasn't meant to be interpreted that way ( URL ). Sure, the result is that we have what we have and we have to deal with it in the best way possible. In that spirit I think that Kazuho's proposal tries to be as closed as possible to the current state of deployment by indicating how some implementations behave vs what others expect and suggesting not to play in the gray area there.
Hervé's post there is quite useful, yes. That supports this overall view. I've cleaned up the comments on the diff view; let me know if what you see works. The diff overall is fairly clean (it's mostly additions).
I'm just a bit confused, where am I supposed to see the unified diff ? the only way I know is by clicking on each individual commit, which is the solution I find inconvenient :-/ Do I have to add a magic ".patch" in the URL bar somewhere ?
There's a "Files changed" tab toward the top of the page: ! Adding ".patch" to the URL is a neat hack for finding something you can download, but usually I find that pulling from the branch is nicer to work with.
Thanks for pointing that one, I always thought it only contained the original PR's changes, not the latest proposed ones :-) I'm seeing this part which remains confusing: "Any change to the maximum value set by the decoder takes effect when..." which I'm reading as "the decode first sets a size, then any change to this size ...", thus reinforces what most servers currently do. I think Kazuho's proposal to move the sentence about initial values solves this: "The dynamic table has a maximum size that is set by a decoder using the SETTINGSHEADERTABLESIZE setting; see XXX. The encoder at both client and server is initialized with a dynamic table size of 4,096 bytes, the initial value of the SETTINGSHEADERTABLESIZE setting. Any change by the decoder to the maximum value takes effect...". This makes it clear that the initially advertised value is a change, which currently is the main point of disagreement. Proabably that we should wait for the end of new year holiday before merging it, so that other implementers for whom this is a change of behavior can have a look.
NAME NAME it would be nice if you, as implementers, could have a look at the proposals here, given that your implementations will need to be updated as well. In haproxy this results in a little ugly trick where the H2 layer has to inject an HPACK opcode (0x20). That's trivial but ugly enough that it warrants a second thought before jumping on any final solution.
NAME Apache is lazy and uses libnghttp2 for h2 protocol handling. It does not change the dynamic table size and all its handling and ACKs are done by nghttp2 transparently. If any changes are necessary, I'd expect them to come with an updated version of libnghttp2 and, since that is linked dynamically, no need to us to release anything new.
NAME I actually wonder if you failed to push the branch here, I saw new commits being pushed to URL instead.
Ugh, my bad. Having two remotes sometimes bites me. Sorry about that Willy. (And thanks for noticing Kazuho.)
No problem Martin, don't be sorry, you're the one doing the job :-) I'm almost fine, almost everything is OK but there remains one ambiguity in that sentence: "A decoder MUST treat a field block without a sufficiently small Dynamic Table Size Update instruction that follows an acknowledgment of a reduction of SETTINGSHEADERTABLESIZE as ...". It ought to be "a reduction of SETTINGSHEADERTABLESIZE below the current size of the header table size etc" (which is slightly different since we don't want to have to re-emit a DTSU if the previous value was already smaller). Given that this principle was explained in the previous sentence, I think we can simply address this by adding the word "such" before "a reduction": "... follows an acknowledgement of such a reduction of SETTINGSHEADERTABLE_SIZE", or probably even simpler, write "acknowledgement of such a change".
Ahh, yeah, it's hard to balance correct and clear here.
I think it's OK now. NAME NAME , care to recheck ?
Good catch indeed!
OK for me as well now. Let's hope it will not cause difficulties (e.g. for those who would pre-queue stream frames).
Enqueuing stream frames (or any frame) and then allowing a settings change to occur ahead of those frames is very risky. Anything that you do in those frames might violate a changed constraint. If you must, enqueue all frames, SETTINGS included.
I generally agree, but it's a matter of design choice (or constraints). Before this change nothing implied a possible change of headers frames representation after the requests started to flow, so that was technically possible. There are not that many H2 implementations anyway so we'll see. But I also agree that here at least we keep the option of postponing the SETTINGS ACK frame, which leaves some options open if this issue is raised. Thanks!
Hi Cory, I suspect, as you suggested in your last sentence, that writing "HPACK encoder" and "HPACK decoder" here would remove any ambiguity. Of course we know it's not the HPACK encoder in terms of code that acks for example, but it's the same endpoint and that is sufficient to declare who does what.
I've taken Mike's suggestion and mixed in a few "HPACK decoder" and "HPACK encoder" statements, using "endpoint" for protocol actions (settings, connection errors). Tell if this makes more sense to you NAME or if I've messed it up.
aside the typo above, LGTM. Thanks Martin!
NAME I guess we've left it long enough for reviews, it's probably okay to merge it by now, what do you think ? As a bonus it would close the last issue.
Opening a new issue as I notice that has been merged already. Text added by states: An encoder sends a Dynamic Table Size Update instruction after acknowledging a change of SETTINGSHEADERTABLESIZE even if it is not changing the size of the dynamic table or an increase to the maximum size is subsequently reverted before the field block is sent. I am not sure if this correct interpretation of RFC 7541, and also am concerned that this text might cause new interoperability issues. states: A change in the maximum size of the dynamic table is signaled via a dynamic table size update (see Section 6.3). This dynamic table size update MUST occur at the beginning of the first header block following the change to the dynamic table size. In HTTP/2, this follows a settings acknowledgment (see Section 6.5.3 of [HTTP2]). As can be seen, this paragraph of RFC 7541 starts "a change." When an HTTP/2 endpoint is using an HPACK encoder with a dynamic table of size 4,096 (the default) and receives SETTINGSMAXHEADERLISTSIZE of 4096, it is not changing the size of the dynamic table. My interpretation of RFC 7541 would be that it does not require Dynamic Table Update Size to be sent when the table size remains the same. Interoperability-wise, do existing servers respond with a Dynamic Table Update Size instruction when the client sends SETTINGSMAXHEADERLIST_SIZE no less than 4096? It seems to me that this newly added text suggest such behavior is required, but I'm not sure if many servers behave as such. added text indicating that endpoints MAY error-close the connection when not seeing such behavior. Even if we are to agree that Dynamic Table Size Update MUST be sent in all cases, I'm concerned that we might see more interoperability issues by suggesting that endpoints can error-close.
Yup, I think this works well. Nice work NAME

Related discussion:
text: MUST terminate the connection with a ConnectionErrorHandler of type COMPRESSION_ERROR if it does not decompress a field block. <ins> A decoding error in a field block MUST be treated as a ConnectionErrorHandler of type COMPRESSION_ERROR. 4.3.1. Field compression is stateful.  Each endpoint has an HPACK encoder context and an HPACK decoder context that are used for encoding and decoding all field blocks.  COMPRESSION defines the dynamic table, which is the primary state for each context. The dynamic table has a maximum size that is set by an HPACK decoder. An endpoint communicates the size chosen by its HPACK decoder context using the SETTINGS_HEADER_TABLE_SIZE setting; see SettingValues. When a connection is established, the dynamic table size for the HPACK decoder and encoder at both endpoints starts at 4,096 bytes, the initial value of the SETTINGS_HEADER_TABLE_SIZE setting. Any change to the maximum value set using SETTINGS_HEADER_TABLE_SIZE takes effect when the endpoint SettingsSync.  The HPACK encoder at that endpoint can set the dynamic table to any size up to the maximum value set by the decoder.  An HPACK encoder declares the size of the dynamic table with a Dynamic Table Size Update instruction (COMPRESSION). Once an endpoint acknowledges a change to SETTINGS_HEADER_TABLE_SIZE that reduces the maximum below the current size of the dynamic table, its HPACK encoder MUST start the next field block with a Dynamic Table Size Update instruction that sets the dynamic table to a size that is less than or equal to the reduced maximum; see COMPRESSION. An endpoint MUST treat a field block that follows an acknowledgment of the reduction to the maximum dynamic table size as a ConnectionErrorHandler of type COMPRESSION_ERROR if it does not start with an conformant Dynamic Table Size Update instruction. </ins> 5. A "stream" is an independent, bidirectional sequence of frames