With my spike on SPDY server push finally finding some measure of success, I am almost ready to move on to some real code. But first, I would like to try pushing out more than one resource.
In my spike, I have been pushing out a dummy stylesheet. The easiest way that I can think to push out two resources (and verify that it is working) is to push out the real stylesheet, which includes:
section#main {If I can push out multiple resources with the page request, then I should be able to push out everything needed to render the node-spdy sample page with only a single request from the browser.
//...
background: url(spdy.jpg) no-repeat 50% 50%;
//...
}
First up, I do a little clean-up. I will need to set multiple push streams, so I cannot hard code information in the push stream class. As noted yesterday, the only information that I believe truly changes between push streams is the URL, so I add URL to the push stream constructor:
exports.createPushStream = function(cframe, c, url) {With that, I can rewrite the named-in-a-spike
return new PushStream(cframe, c, url);
};
pushStuff()
method to:Response.prototype.pushStuff = function() {I have also commented out the dummy data for the stylesheet. Instead I am now reading the real one from the filesystem (blocking, I will worry about async another day).
if (this._pushed) return false;
if (this.streamID != 1) return false;
// TODO: Combine FIN & write? (once push stream is working)
var data = fs.readFileSync('pub/style.css', 'utf8');
var push_stream = createPushStream(this.cframe, this.c, "https://localhost:8081/style.css");
push_stream.write(
// "h1 { color: orange }"
data
);
push_stream.end();
this._pushed = true;
};
After verifying that everything still works, I factor the actual push out into a separate method:
Response.prototype.pushStuff = function() {That will allow me to add a second push, this time for the background JPG image:
if (this._pushed) return false;
if (this.streamID != 1) return false;
this._push("pub/style.css", "https://localhost:8081/style.css");
this._pushed = true;
};
Response.prototype._push = function(filename, url) {
var push_stream = createPushStream(this.cframe, this.c, url);
push_stream.write(fs.readFileSync(filename, 'utf8'));
// TODO: Combine FIN & write? (once push stream is working)
push_stream.end();
};
Response.prototype.pushStuff = function() {Now, when I load the page and check things out in Chrome's
if (this._pushed) return false;
if (this.streamID != 1) return false;
this._push("pub/style.css", "https://localhost:8081/style.css");
this._push("pub/spdy.jpg", "https://localhost:8081/spdy.jpg");
this._pushed = true;
};
about:net-internals
SPDY tab, I find (my notes inline):t=1307330730921 [st= 0] +SPDY_SESSION [dt=?]Cool! That looks to have worked.
--> host = "localhost:8081"
--> proxy = "DIRECT"
t=1307330730922 [st= 1] SPDY_SESSION_RECV_SETTINGS
--> settings = ["[0:100]"]
#####
# The HTTP Request send over SPDY
t=1307330730922 [st= 1] 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
#####
# HTTP Response headers being delivered over SPDY
t=1307330730929 [st= 8] 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
#####
# Headers for the CSS being pushed
t=1307330730954 [st= 33] SPDY_SESSION_PUSHED_SYN_STREAM
--> associated_stream = 1
--> flags = 2
--> status: 200
url: https://localhost:8081/style.css
version: http/1.1
--> id = 2
#####
# Data for the CSS
t=1307330730955 [st= 34] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 347
--> stream_id = 2
#####
# Data FIN for the CSS
t=1307330730955 [st= 34] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 0
--> stream_id = 2
#####
# Headers for the JPEG image being pushed
t=1307330730955 [st= 34] SPDY_SESSION_PUSHED_SYN_STREAM
--> associated_stream = 1
--> flags = 2
--> status: 200
url: https://localhost:8081/spdy.jpg
version: http/1.1
--> id = 4
#####
# Data for the JPEG (many other packets omitted)
t=1307330730957 [st= 36] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 8184
--> stream_id = 4
#####
# Data FIN for the JPEG
t=1307330730966 [st= 45] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 0
--> stream_id = 4
#####
# Data for the web page itself
t=1307330730966 [st= 45] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 698
--> stream_id = 1
#####
# Data FIN for the web page itself
t=1307330730966 [st= 45] SPDY_SESSION_RECV_DATA
--> flags = 0
--> size = 0
--> stream_id = 1
#####
# Successfully recognized push stream - yay!
t=1307330730975 [st= 54] SPDY_STREAM_ADOPTED_PUSH_STREAM
Unfortunately, the webpage begs to differ:
(no JPEG background)
Since the SPDY tab seems quite satisfied, I guess that I am doing something silly and (hopefully not too) subtle. I play with the order of the CSS and the JPEG image, to not avail. Next I try reading the data from the filesystem directly into a
Buffer
rather than reading it into a string. This is easily accomplished by omitting the 'utf8'
from the calls to fs.readFileSync()
:Response.prototype._push = function(filename, url) {That actually makes a certain amount of sense as an explanation for my trouble. Encoding a JPEG as a UTF-8 string may not produce the desired effects. In fact, that turns out to be the explanation:
var push_stream = createPushStream(this.cframe, this.c, url);
push_stream.write(fs.readFileSync(filename));
// TODO: Combine FIN & write? (once push stream is working)
push_stream.end();
};
Nice!
I think tomorrow I will dump my spike and begin coding this push stuff up for real.
Day #42
No comments:
Post a Comment