Monday, May 30, 2011

Bad Combination: Relative URLs and SPDY Server Push

‹prev | My Chain | next›

Continuing my effort to get SPDY server push working, I make a couple of changes in the hopes that they will push me through.

Specifically, I switch from a fully qualified URL to a root relative URL for the stylesheet that I am trying to push:
var PushStream = exports.PushStream = function(cframe, c) {
stream.Stream.call(this);
this.streamID = 2; // TODO auto-increment even numbers per: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2#TOC-Stream-creation

this.associatedStreamId = cframe.data.streamID;
this.c = c;

this._headers = {
url: "/style.css"
};
};
Also, I prevent the response from sending out more than one server push:
Response.prototype.pushStuff = function() {
if (this._pushed) return false;
if (this.streamID != 1) return false;


// TODO: Combine FIN & write? (once push stream is working)
var push_stream = createPushStream(this.cframe, this.c);
push_stream.write(
"h1 { color: orange }"
);
push_stream.end();

this._pushed = true;
};
With that, I hope to have pushed past the never-ending server push from last night. Unfortunately, Chrome's SPDY tab in about:net-internals reports:
t=1306807793087 [st=      0] +SPDY_SESSION  [dt=4245683]
--> host = "localhost:8081"
--> proxy = "DIRECT"
t=1306807793087 [st= 0] SPDY_SESSION_SYN_STREAM
--> flags = 1
--> accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
accept-encoding: gzip,deflate,sdch
accept-language: en-US,en;q=0.8
cache-control: no-cache
host: localhost:8081
method: GET
pragma: no-cache
scheme: https
url: /
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.772.0 Safari/535.1
version: HTTP/1.1
--> id = 1
t=1306807793098 [st= 11] SPDY_SESSION_RECV_SETTINGS
--> settings = ["[0:100]"]
t=1306807793135 [st= 48] SPDY_SESSION_SYN_REPLY
--> flags = 0
--> accept-ranges: bytes
cache-control: public, max-age=0
connection: keep-alive
content-length: 698
content-type: text/html; charset=UTF-8
etag: "698-1306200491000"
last-modified: Tue, 24 May 2011 01:28:11 GMT
status: 200 OK
version: HTTP/1.1
--> id = 1
t=1306807793136 [st= 49] SPDY_SESSION_PUSHED_SYN_STREAM
--> associated_stream = 1
--> flags = 2
--> url: /style.css
--> id = 2
t=1306807793136 [st= 49] SPDY_SESSION_SEND_RST_STREAM
--> status = 1
--> stream_id = 2
Bummer.

That bit about the RST_STREAM at the end of the session would seem to indicate that I was closer to having this working last night than I am today. Even more worrisome is the status with which it is failing. A 0x01 is a generic, can't help you failure:
1 - PROTOCOL_ERROR. This is a generic error, and should only be used if a more specific error is not available.
Greeaaaaat.

To make sure that there is nothing unexpected going on in there, I inspect the packets themselves using Wireshark. First up is the initial SYN_STREAM push:

+----------------------------------+
80 02 00 01 |1| 1 | 1 |
+----------------------------------+
02 00 00 27 | Flags (8) | Length (24 bits) |
+----------------------------------+
00 00 00 02 |X| Stream-ID (31bits) |
+----------------------------------+
00 00 00 01 |X|Associated-To-Stream-ID (31bits)|
+----------------------------------+
00 00 62 60 | Pri | Unused | |
64 60 06 05 +------------------ |
01 97 7e 71 | Name/value header block |
49 65 4e aa | ... |
5e 72 71 31
00 00 00 ff
ff 02 00 00 00 ff ff
That looks OK. The stream ID is 2 (all server-side streams are even and this is the first one). The associated ID is the first client-initiated stream (the one that requested the homepage). The flag indicates that this is server push only:
0x02 = FLAG_UNIDIRECTIONAL - a stream created with this flag is already considered to be half closed to the receiver.


Next comes the actual data that I am attempting to push out and an empty DATA FIN packet:
0000  00 00 00 02 00 00 00 14  68 31 20 7b 20 63 6f 6c   ........ h1 { col
0010 6f 72 3a 20 6f 72 61 6e 67 65 20 7d or: oran ge }

0000 00 00 00 02 01 00 00 00 ........
Lastly comes the RST_STREAM from the client:
                 +-------------------------------+
80 02 00 03 |1| 1 | 3 |
+-------------------------------+
00 00 00 08 | Flags (8) | 8 |
+-------------------------------+
00 00 00 02 |X| Stream-ID (31bits) |
+-------------------------------+
00 00 00 01 | Status code |
+-------------------------------+
And yup, a generic protocol error:
1 - PROTOCOL_ERROR. This is a generic error, and should only be used if a more specific error is not available. The receiver of this error will likely abort the entire session and possibly return an error to the user.
I spend a good deal of time adding additional headers (content-length, content-type, etc). I fiddle with the DATA FIN flag a bit, but nothing I do seems to avoid the RST_STREAM.

I think tomorrow I will give the absolute URL another go. All other URLs look to be relative and it blocked the rest of the stream from completing. Still is it seemed to yield a valid server push whereas root relative URLs seem to be a dead-end.




Day #34

No comments:

Post a Comment