- From: Amos Jeffries <squid3@treenet.co.nz>
- Date: Thu, 07 Feb 2013 00:47:08 +1300
- To: ietf-http-wg@w3.org
On 6/02/2013 11:28 a.m., Roberto Peon wrote: > The proposal for framing is that there are always 8 bytes to read for > every frame, both control and data frames. (Thanks to Jeff Pinner for > modifying this for me already!) > > Generically, this is the format of a frame. > > 0 1 2 3 4 5 6 7 > +--------+--------+--------+--------+--------+--------+--------+--------+ > | Length(16) |Type(8) |Flags(8)| Num-of-Entries-or-Stream-ID-or-ID | -> > +--------+--------+--------+--------+--------+--------+--------+--------+ > 8..N > +========+ > | Data | > > +========+ > > Length: An unsigned 16-bit value representing the number of bytes of > the data field. > Type: The frame type. > Flags: Flags related to this frame. Flag definitions are dependent > upon the frame type. > Data: data associated with this control frame. The format of this > data is controlled by the frame type. > For a data frame, TYPE is set to zero, and the Num-of-Entries-or-Stream-ID-or-ID field (gotta get a better name :) ) contains a '0' followed by 31 bits of stream ID. Valid flags are: > 0x01 = FLAG_FIN - signifies that this frame represents the last > frame to be transmitted on this stream. See Stream Close > (Section 2.3.7) below. > 0x02 = MSG_DONE - signifies that this frame represents the last > frame of a message. This is relevant for layering of message- > based protocols on top of SPDY. > > For control frames, a non-zero value will exist in the TYPE field. The following flags are valid for all control frames: > > 0x01 = FLAG_FIN - signifies that this frame represents the last > > frame to be transmitted on this stream. > > 0x02 = MSG_DONE - signifies that this frame represents the last > frame of a sequence of a run of same-type control frames. > If MSG_DONE is not set for a control-frame, then the particular control message was unable to fit within a single control-frame. Implementations may process the control message up to the amount received, but MUST not treat the message as done. Implementations SHOULD finish sending the control-message as soon as possible and when finished with the particular control message, they MUST set MSG_DONE. > > What do people think about the FLAGS/TYPE arrangement? If swapped, we gain more contiguous reserved bits. > -=R The SPDY framing is a bit clumsy, in particular its way of transmitting flow state as individual frames. Below is an alternative basic frame layout I have been working on to extend the original network-friendly draft frames using the SPDY and WebSockets signal types. Using the below frame layout, in particular with two flags up front in specific positions we are able to transmit HTTP/2 and WebSockets frames on the same connection. With some small amount of magic only necessary during the transition period we are also able to identify SPDY v2, SPDY v3 and HTTP/1.x connection attempts. I am talking algorithm magic here *not* bits dedicated to a BOM. see "Relevant Magic" below. I've been holding this off while I try to figure out what bit ranges the TLS handshakes are detectible with. It seems 32-bits is required if we merge TLS port 443 traffic into this magic, but I'm not yet completely certain of that. NP: I use "flow" here to mean a series of frames which form 1..N requests and 1..N responses in a session from one client. A client may send multiple flows. For example; a proxy with many clients, browser with many tabs, spider doing parallel domain fetches, web service doing parallel fetches to a remote backend, etc. etc. The Frame format: 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +-+-+-----------+---------------+ |F|C| type | | +-+-+-----------+ + | Frame Length (24) | +-------------------------------+ | opaque ID (16) | +-------------------------------+ | Frame Data (16...N) | +-------------------------------+ flags = 2-bits : frame flags shared by all frames with the following meaning: F = final frame. There are no more frames with this request ID following. This signals termination of the flow from this sender. C = continuation. There are more frames expected to follow in this flow. * these are separate bits because F relates to the flow/session. C relates to the request, response, or entity being transferred. A flag combination of (F=0,C=0) signals the flow may continue but the object this frame relates to is now completed A flag combination of (F=0,C=1) signals the flow will continue with more frames for this particular object (request response, or entity) A flag combination of (F=1,C=0) signals the flow is terminating and the object being transferred is complete. A flag combination of (F=1,C=1) signals the flow is terminating and the object being transferred has been truncated. type = 6-bits : Frame Type code * this frame layout intentionally overlaps with WebSockets in the first octet. Frame type codes 0x0, 0x1, 0x2, 0x8, 0x9, 0xA correlate directly to the WebSockets 'opcodes' of those values. We should probably reserve those frame types for WebSockets since from this octet onwards the WS frame differs markedly in field positioning. Doing this overlap allows us to multiplex HTTP/2 frames with WebSockets frames on the one connection without having to go through the Upgrade: handshake required with HTTP/1 protocol. frame-length: 24-bit size numeric indicating how many octets the frame takes up. This size should include the headers 8 octets. opaque ID : 16-bit opaque identifier set by the sender to group a sequence of frames into a flow. The receiver must send it back on frames generated for the response or control frames related to that flow, or on frames of related responses when performing server-push. The request-ID of 0 is reserved for frames dealing with connection state, not with any particular request-response flow. ** Minimum size of Frame Data should be 16-bits, making frames 64-bit minimum with 32-bit alignment. Relevant Magic: * in HTTP/1 protocol the first 32-bits of a connection are ASCII characters. - The F flag is always 0 on the first frame of valid HTTP/1 traffic. - The C flag and type field will be random values. - the opaque ID field will never be 0x0. * in SPDY protocol the first 32-bits of the connection is a control frame. - the F flag is set to 1. - the C flag is set to 0 (since the SPDY version field is 0x3) - the type field is 0x0 (since the SPDY version is 0x3) - the first octet of the frame length will be 0x1, 0x2 or 0x3 corresponding to the SPDY version number. * in WebSockets protocol the first 32-bits of a connection is either a HTTP/1 Upgrade request (to be handled as per HTTP/1) or a frame - the F flag may be set or not. with identical meaning to HTTP/2 - the C bit is set to 0 - the type field is set to a WebSockets opcode. * I propose in HTTP/2 the first frame be a connection feature negotiation frame... - have the F flag to 0. Differentiating it from HTTP/1 and signalling any WebSockets recipient to close the connection. - have the C flag set to 1. Differentiating it from WebSockets and SPDY. Also, signalling any WebSockets recipient to close the connection. - have the type field of 0x0. Differentiating it from HTTP/1 and signalling any HTTP/1 recipient with the '@ symbol as request method. - have a frame size limit of . Causing the \0 to be delivered to HTTP/1 recipients, such that their whole method string is '@'. - have the opaque ID of 0x0. Indicating a connection-level frame. And signalling any HTTP/1 recipient to abort the transaction. - the first 16 bits of the frame data be the version BOM. This frame structure gives us several very important things: * first 32-bits up front for any frame provide the magic needed to identify how it affects the flow, how big it is, and how to process it * second 16-bits provide the opaque ID to group frames together for flow control and flow state management. * clients and servers (including intermediaries) can maintain sessions and state using TCP details plus that opaque ID (IP:port:opaque-ID) as a unique identifier for any senders session. For the vast majority of frames these fields are the only ones any intermediary software needs to actually care about for routing purposes. The flow opening frames are the exception here, where they are required processing to identify exactly what state to assign to the flow using that opaque ID. Possibly also some control frames to manage the flow control negotiation between machines - although most of these are likely to come under ID 0x0. * intermediaries should be left free to re-write (or not) the opaque ID field as necessary to prevent collisions. This means the limit SPDY places on the ID counter in section 32K sessions before a connection MUST close is removed and any one connection is free to re-use identifiers * with a 3-way separation of object termination (C flag) from flow termination (F flag) from TCP connection termination using no intermediary frames we are free to permit multiple requests and responses within one flow without additional overheads. + permitting simple server-push where one request fetch can trigger multiple responses using the same opaque ID. + permitting a whole browsing session to re-use the one opaque ID in loose equivalence to a sesison cookie. Amos
Received on Wednesday, 6 February 2013 11:47:42 UTC