Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can PUSH_PROMISE rules be relaxed to allow sending on a control stream? #947

Closed
LPardue opened this issue Nov 20, 2017 · 5 comments
Closed

Can PUSH_PROMISE rules be relaxed to allow sending on a control stream? #947

LPardue opened this issue Nov 20, 2017 · 5 comments
Labels
-http design

Comments

@LPardue
Copy link
Member

@LPardue LPardue commented Nov 20, 2017

Reading the latest HTTP/QUIC editor's copy. Section 4.4 on server push states that:

The PUSH_PROMISE frame is sent on a response stream.

The recent changes in this area have moved away from Stream ID, PUSH_PROMISE frames now reference a Push ID. Push cancellation is achieved by the HTTP/QUIC CANCEL_PUSH frame, which is restricted to the control stream.

So I got to wondering if there may be benefits allowing/restricting HTTP/QUIC PUSH_PROMISE frames on the control stream. It seems to me that CANCEL_PUSH forces implementations to be geared up for managing server push on the control stream anyway.

Maybe I'm missing the benefit of tying pushes to requests, RFC 7540 talks about the requirements but I can't infer the benefits. Relaxing the rule and incorporating something like cache digests might give an appropriately-configured server enough information to push just the correct things with a bit more performance (it is described as unsolicited right?). Another use case is to allow server push without having to hold streams open.

@martinthomson martinthomson added -http design labels Nov 21, 2017
@martinthomson
Copy link
Member

@martinthomson martinthomson commented Nov 21, 2017

Ordering of PUSH_PROMISE relative to other activity in a response is critical. Ideally, a URL arrives after a PUSH_PROMISE, or the client might make another request that duplicates the push. It's very hard for a server to decide to cancel a request on the basis that a push is outgoing, because it can't know whether the client really wanted a second request, so we rely on ordering.

@LPardue
Copy link
Member Author

@LPardue LPardue commented Nov 21, 2017

It's very hard for a server to decide to cancel a request on the basis that a push is outgoing, because it can't know whether the client really wanted a second request, so we rely on ordering.

For clarification, are you saying it's hard for a server to cancel a second request, because the server can't know if the client really wanted the second request?

(Edited: fixed typo where I used push instead of request).

@LPardue
Copy link
Member Author

@LPardue LPardue commented Nov 21, 2017

Ordering of PUSH_PROMISE relative to other activity in a response is critical. Ideally, a URL arrives after a PUSH_PROMISE, or the client might make another request that duplicates the push.

Hmm, now I think about it, RFC 7540 Section 8.2.1 does say that "The server SHOULD send PUSH_PROMISE frames prior to sending any frames that reference the promised responses. This avoids a race where clients issue requests prior to receiving any PUSH_PROMISE frames". HTTP/2 relied on TCP to provide send-order reception guarantees. Since QUIC cannot guarantee ordering across streams (but does provide in-order delivery within a stream) sending PUSH_PROMISE on the response stream can help towards this requirement. So a simple way to address my initial comment would be to directly qualify the sentence with text, a reference to Section 8.2.1 or both.

However, I could also argue that the race condition issues could be less pronounced for HTTP/QUIC due to the CANCEL_PUSH semantic that didn't previously exist. A sensible SHOULD would place PUSH_PROMISE on the request stream but there be cases where a request-less push on the control stream could be of benefit.

I'd also like to say that I think the current design is clever. The spec already goes to some lengths to help accommodate request concurrency and out-of-order delivery. I really like the approach for allowing multiple PUSH_PROMISE frames to use the same PUSH ID.

@martinthomson
Copy link
Member

@martinthomson martinthomson commented Nov 22, 2017

An important property of pushes is their association with other requests. We discussed uncoupled pushes during the development of HTTP/2 and it made it very difficult for a stack that has multiple clients to decide which of those clients will receive the push. Though there might be cases where ordering is less critical, but I don't know how to justify adding extra complexity.

Happy to add clarification about the ordering rationale.

@LPardue
Copy link
Member Author

@LPardue LPardue commented Nov 22, 2017

Intermediaries perhaps feel particular pain. Some might say that Service Worker shines a new light on old problems.

So I think you've convinced me in the general case. In practical terms, a request object primitive is a pretty useful thing, especially for implementations that already use such a paradigm (perhaps also why H2 or HQ frames that operate at application-level have some difficulty gaining traction and header fields are preferred). Request/response is also great for implementations that like to minimise state.

The great replies from @MikeBishop on other issues I've raised have also given me greater insight to this section. Where is says:

The PUSH_PROMISE frame is sent on a response stream.

I think the term "response stream" is left over from the old @martinthomson unidirectional PR. This is the only occurrence of the term and in the current context of HTTP/QUIC doesn't make much sense.

In actuality, the PUSH_PROMISE frame is sent on the client-initiated, bidirectional stream that carried the request that generated the push. I think thats the only form allowed (i.e. you can't send PUSH_PROMISE on a server-initiated unidirectional or bidirectional stream). I might be arguing now that the current definition is not strict enough in mandating on what streams PUSH_PROMISE can be sent on.

Once that gets clarified, I think the idea of sending PUSH_PROMISE on server-initiated unidirectional streams (the control stream to name one) falls outside the general case but may help special use cases. Would there be aversion to a HTTP/QUIC extension that modifies semantics to allow such use cases?

MikeBishop pushed a commit that referenced this issue Nov 23, 2017
…why (#957)

* This clarifies where PUSH_PROMISE can be sent and gives a clue about why.

Closes #947, #950.

* Reference a Push ID
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-http design
Projects
None yet
Development

No branches or pull requests

2 participants