Thanks to an assist from Mike Belshe (OK not so much an assist, more he solved it completely), I now have server push working in node-spdy.
This is just a spike at this point and not yet general purpose. When the client connects to the node-spdy server, I am trying to server push a dumb version of the CSS stylesheet. As Mike pointed out, I was missing
version
and status
in the push stream's headers. I had experimented with a number of headers. Per the spec:
The pushed stream inherits all of the headers from the associated-stream-id with the exception of ":host", ":scheme", and ":path", which are provided as part of the pushed response stream headers.I completely overlooked the part of the spec describing responses (push or otherwise):
The response status line is unfolded into name/value pairs like other HTTP headers and must be present:So I go ahead and add this to my dumb, push version of the":status" - The HTTP response status code (e.g. "200" or "200 OK")
":version" - The HTTP response version (e.g. "HTTP/1.1")
/style.css
stylesheet in the node-spdy sample app:var PushStream = exports.PushStream = function(cframe, c) {Now, when I load up the sample node-spdy app, I see:
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 = {
"cache-control": "public, max-age=0",
url: "https://localhost:8081/style.css",
"status": 200,
"version": "http/1.1",
"content-length": 20,
"content-type": "text/css; charset=UTF-8",
etag: "347-1306200491000",
"last-modified": "Tue, 24 May 2011 01:28:11 GMT"
};
};
That is definitely the dumb version of the
/style.css
stylesheet in effect:push_stream.write(Taking a look at this in the SPDY tab of
"h1 { color: orange }"
);
about:net-internals
, I see that my push stream is adopted by Chrome:t=1307160566672 [st= 0] +SPDY_SESSION [dt=?]The new
--> host = "localhost:8081"
--> proxy = "DIRECT"
t=1307160566672 [st= 0] SPDY_SESSION_RECV_SETTINGS
--> settings = ["[0:100]"]
t=1307160566672 [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
host: localhost:8081
method: GET
scheme: https
url: /
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.1 Safari/535.1
version: HTTP/1.1
--> id = 1
t=1307160566677 [st= 5] 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=1307160566711 [st=39] SPDY_SESSION_PUSHED_SYN_STREAM
--> associated_stream = 1
--> flags = 2
--> cache-control: public, max-age=0
content-length: 20
content-type: text/css; charset=UTF-8
etag: 347-1306200491000
last-modified: Tue, 24 May 2011 01:28:11 GMT
status: 200
url: https://localhost:8081/style.css
version: http/1.1
--> id = 2
t=1307160566711 [st=39] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 20
--> stream_id = 2
...
status
and version
are in place and seem to be making the difference. After receiving the pushed CSS as well as the HTML for the page itself, Chrome notes that yes, it really is a legit push stream:
t=1307160566714 [st=42] SPDY_STREAM_ADOPTED_PUSH_STREAMThat is not new. I had node-spdy that far days ago. What is new is that, since I have all of the necessary headers in place, Chrome does not block waiting on a HEADERS SPDY frame. Instead, it makes the next request (an AJAX POST):
t=1307160566721 [st=49] SPDY_SESSION_SYN_STREAMAfter sending the headers for that request, Chrome sends the POST data itself:
--> flags = 0
--> accept: */*
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
content-length: 18
content-type: application/xml
host: localhost:8081
method: POST
origin: https://localhost:8081
referer: https://localhost:8081/
scheme: https
url: /
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.1 Safari/535.1
version: HTTP/1.1
--> id = 3
t=1307160566723 [st=51] SPDY_SESSION_SEND_DATAThe server replies with header and data:
--> flags = 1
--> size = 18
--> stream_id = 3
t=1307160566725 [st=53] SPDY_SESSION_SYN_REPLYAnd that is it.
--> flags = 0
--> connection: keep-alive
status: 200 OK
version: HTTP/1.1
--> id = 3
t=1307160566761 [st=89] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 18
--> stream_id = 3
t=1307160566761 [st=89] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 0
--> stream_id = 3
The most important aspect of this SPDY session is that the browser never requests the CSS stylesheet. The page itself definitely includes the CSS:
<!DOCTYPE html>But since the server performed a SPDY server push, the client recognizes that the resource in question has already been pushed into cache, making a request unnecessary.
<html>
<head>
<link rel=icon type=image/png href="favicon.png" />
<link rel=stylesheet type=text/css href="style.css" />
<title>SPDY Server</title>
...
And, if I shift-reload the page, I by-pass cache and download the real stylesheet for the node-spdy sample app:
Yay! SPDY server push is finally mine!
Day #39
No comments:
Post a Comment