Subject: Re: [quicwg/base-drafts] Unidirectional streams (#175)

From: Ryan Hamilton <[email-masked]>
Date: Tue, 07 Feb 2017 09:21:22 -0800

Adding unidirectional streams to the protocol seems like something we could consider, but removing bidirectional streams seems a bit rash. Bidirectional streams are a protocol mechanism provided by any number of different transports (TCP, SCTP, SST, etc) and have a long history of deployment success. Bidirectional streams provide an automatic mechanism for marrying a request and response together. Without this, applications (or the transport) will need some additional mechanism to associate requests with response. Since we have no experience with QUIC or HTTP/2 over QUIC using only unidirectional streams, I fear that there are unexpolored dark corners which we will only discover once we try to start using them. Open stream limits seem like one such corner. Currently with QUIC, each endpoint can specify the total number of open streams that the peer is allowed to create. If both sides set a limit of, say, 10 streams then this allows the client to issue 10 requests and for the server to provide 10 response while at the same time, it allows the server to push 10 additional responses. If all streams were unidirectional, you might imagine and a client issuing a single request and the server responding with the response + 9 pushes, hence exhausting the open stream limit. If the client opened another request, the server would not be able to open a stream to respond. Now, you could imagine that we could change the way the stream limits apply so that "response streams" don't count in some way, but that sounds treacherous.  

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278072250

---

From: Martin Thomson <[email-masked]>
Date: Tue, 07 Feb 2017 16:00:55 -0800

That's a problem that servers already have.  They can promise far in excess of the number of streams the client permits.  Thus, it is safe (though perhaps inadvisable) for the client to advertise fewer streams than it uses to initiate requests.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278185120

---

From: Ryan Hamilton <[email-masked]>
Date: Tue, 07 Feb 2017 16:05:40 -0800

I don't think servers have this problem already. Today, a server can always send a response to a request from the client, regardless of how many push streams they have opened. This is because the response streams are counted against the client's limit and the push streams are counted against the server's limit. (Or vice versa I guess, depending on how you think about it.)That would not be the case if the server's push and response streams were counted agains the same limit.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278185953

---

From: Martin Thomson <[email-masked]>
Date: Tue, 07 Feb 2017 16:14:38 -0800

A server that supports push does have the same problem.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278187708

---

From: Ryan Hamilton <[email-masked]>
Date: Tue, 07 Feb 2017 16:25:26 -0800

Hm. Can you provide an example?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278189687

---

From: Mike Bishop <[email-masked]>
Date: Tue, 07 Feb 2017 16:34:27 -0800

I think what Martin is saying is that the server is able, via PUSH_PROMISE, to queue up requests whose responses can't yet be sent.  That's not *quite* the same as saying that the client's requests also can't be sent, but from the server's perspective it's very similar -- a request is a request.  Having a reasonable initial priority on pushed streams, making them less important than client requests by default, helps to mitigate this.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278191333

---

From: Ryan Hamilton <[email-masked]>
Date: Tue, 07 Feb 2017 16:46:08 -0800

Ah. I see what you're getting at. I agree that there are some similarities here. Thanks!

On the other hand, I think there are some significant differences. While it's clear that in the promise case, the server can promise streams that it is not ready to send, the server is in a position to know the relative importance of the various resources it wishes to push and can chose to send them in the order that is most useful to the client. However, the server is not in a position to know the relative importance of the pushed stream to the not-yet-received request(s) from the client. This puts the server in the position of being unable to service a high-priority request when it arrives. In the push case, the server could chose to pause sending on the open push streams to reply to the request. It could also chose not to promise a push of an important sub-resounce of that request because it knows that it is at the push stream limit. This would allow the client to request that subresource and reply via a non-push stream.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-278193326

---

From: Mike Bishop <[email-masked]>
Date: Thu, 23 Feb 2017 15:33:44 -0800

So it seems like there are a couple stages here, and it depends how far we're willing to go.

1. A QUIC stream is bidirectional, and moves through a state machine of (idle,active,half-closed local/remote,fully-closed)
2. A QUIC stream consists of a pair of opposite-direction channels, each of which moves through the (idle,active,closed) cycle independently.
3. QUIC streams in each direction are fully independent, move through a state machine of (idle,active,closed), and any relationship between streams in opposite directions is defined by the application protocol.

Option 1 is the status quo.  I strongly support moving at least to Option 2 for the simpler state management.  Note that Option 2 still requires that we retain the concept of client-initiated and server-initiated streams.

Option 3 is a possibility, but requires much more change to the application layer from what we currently deal with.  It has some interesting possibilities, though.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-282156592

---

From: Martin Thomson <[email-masked]>
Date: Thu, 23 Feb 2017 16:30:08 -0800

I think that I agree, I'm fairly confident that we could move to option 2 (coupled pairs of streams) without a lot of pain.  The only binding we would need is that opening a stream in one direction opens a stream in the other direction.  We'd want REQUEST_RST, or DISINTEREST or something to allow an endpoint to request that an inbound channel be cancelled.  I think that we want that functionality anyway.

Option 3 would require some extra signaling in the application protocol to properly realize, but it has some properties that I think are fascinating.  The ramifications for push and stream limits and asymmetry remain interesting despite the apparent risks and uncertainty.  The worst so far doesn't relate to asymmetry as much as it does to having an unbounded number of server pushes arriving at a client with only the connection flow control window to limit them.  In some ways, that's an exciting prospect and I think that I like it, but I can also appreciate how some people might be scared by the notion.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-282166763

---

From: ianswett <[email-masked]>
Date: Thu, 23 Feb 2017 16:38:38 -0800

It'd be nice to have an implementation of option 3 before heading that direction, given it's a large departure from the status quo.  But I won't disagree with it's appeal for cases like server push.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-282168179

---

From: Mike Bishop <[email-masked]>
Date: Fri, 24 Feb 2017 10:00:07 -0800

Here's a preview of what they would look like, in my opinion:

- [Option 2](https://github.com/quicwg/base-drafts/compare/unidirectional)
- [Option 3](https://github.com/quicwg/base-drafts/compare/unidirectional2)

Both build on #171.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/175#issuecomment-282359619