bug 790388 part 4 - upgrade testing/node-spdy to 1.8.8 r=hurley

--HG--
extra : rebase_source : b68f6dbf8faa5b97b4a97417d35c037b0557e426
This commit is contained in:
Patrick McManus 2013-05-29 00:07:03 -04:00
Родитель e18fe0b0fc
Коммит 32350953ba
25 изменённых файлов: 1630 добавлений и 520 удалений

Просмотреть файл

@ -1,79 +1,84 @@
# SPDY Server for node.js [![Build Status](https://secure.travis-ci.org/indutny/node-spdy.png)](http://travis-ci.org/indutny/node-spdy)
<a href="http://flattr.com/thing/758213/indutnynode-spdy-on-GitHub" target="_blank">
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>
With this module you can create [SPDY](http://www.chromium.org/spdy) servers
in node.js with natural http module interface and fallback to regular https
(for browsers that doesn't support SPDY yet).
## Node+OpenSSL building
At the moment node-spdy requires zlib dictionary support, which will come to
node.js only in 0.7.x version. To build 0.7.x version follow instructions below:
```bash
git clone git://github.com/joyent/node.git
cd node
./configure --prefix=$HOME/.node/dev # <- or any other dir
make install -j4 # in -jN, N is number of CPU cores on your machine
# Add node's bin to PATH env variable
echo 'export PATH=$HOME/.node/dev/bin:$PATH' >> ~/.bashrc
#
# You have working node 0.7.x + NPN now !!!
#
```
## Usage
```javascript
var spdy = require('spdy');
var spdy = require('spdy'),
fs = require('fs');
var options = {
key: fs.readFileSync(__dirname + '/keys/spdy-key.pem'),
cert: fs.readFileSync(__dirname + '/keys/spdy-cert.pem'),
ca: fs.readFileSync(__dirname + '/keys/spdy-csr.pem')
ca: fs.readFileSync(__dirname + '/keys/spdy-csr.pem'),
// SPDY-specific options
windowSize: 1024, // Server's window size
};
spdy.createServer(options, function(req, res) {
var server = spdy.createServer(options, function(req, res) {
res.writeHead(200);
res.end('hello world!');
});
spdy.listen(443);
server.listen(443);
```
And by popular demand - usage with
[express](https://github.com/visionmedia/express):
```javascript
var spdy = require('spdy'),
express = require('express'),
fs = require('fs');
var options = { /* the same as above */ };
var app = express();
app.use(/* your favorite middleware */);
var server = spdy.createServer(options, app);
server.listen(443);
```
## API
API is compatible with `http` and `https` module, but you can use another
function as base class for SPDYServer. For example,
`require('express').HTTPSServer` given that as base class you'll get a server
compatible with [express](https://github.com/visionmedia/express) API.
function as base class for SPDYServer.
```javascript
spdy.createServer(
[base class constructor, i.e. https.Server or express.HTTPSServer],
[base class constructor, i.e. https.Server],
{ /* keys and options */ }, // <- the only one required argument
[request listener]
).listen([port], [host], [callback]);
```
Request listener will receive two arguments: `request` and `response`. They're
both instances of `http`'s `IncomingMessage` and `OutgoingMessage`. But two
custom properties are added to both of them: `streamID` and `isSpdy`. The first
one indicates on which spdy stream are sitting request and response. Latter one
is always true and can be checked to ensure that incoming request wasn't
received by HTTPS callback.
both instances of `http`'s `IncomingMessage` and `OutgoingMessage`. But three
custom properties are added to both of them: `streamID`, `isSpdy`,
`spdyVersion`. The first one indicates on which spdy stream are sitting request
and response. Second is always true and can be checked to ensure that incoming
request wasn't received by HTTPS fallback and last one is a number representing
used SPDY protocol version (2 or 3 for now).
### Push streams
It's possible to initiate 'push' stream to send content to client, before one'll
request it.
It is possible to initiate 'push' streams to send content to clients _before_
the client requests it.
```javascript
spdy.createServer(options, function(req, res) {
var headers = { 'content-type': 'application/javascript' };
res.send('/main.js', headers, function(err, stream) {
res.push('/main.js', headers, function(err, stream) {
if (err) return;
stream.end('alert("hello from push stream!");');
@ -83,7 +88,11 @@ spdy.createServer(options, function(req, res) {
}).listen(443);
```
`.push('full or relative url', { ... headers ... }, callback)`
Push is accomplished via the `push()` method invoked on the current response
object (this works for express.js response objects as well). The format of the
`push()` method is:
`.push('full or relative url', { ... headers ... }, optional priority, callback)`
You can use either full ( `http://host/path` ) or relative ( `/path` ) urls with
`.push()`. `headers` are the same as for regular response object. `callback`
@ -100,11 +109,20 @@ controlling [maximum concurrent streams][http://www.chromium.org/spdy/spdy-proto
protocol option (if client will start more streams than that limit, RST_STREAM
will be sent for each additional stream).
Additional options:
* `plain` - if defined, server will accept only plain (non-encrypted)
connections.
#### Contributors
* [Fedor Indutny](https://github.com/indutny)
* [Chris Storm](https://github.com/eee-c)
* [Chris Strom](https://github.com/eee-c)
* [François de Metz](https://github.com/francois2metz)
* [Ilya Grigorik](https://github.com/igrigorik)
* [Roberto Peon](https://github.com/grmocg)
* [Tatsuhiro Tsujikawa](https://github.com/tatsuhiro-t)
* [Jesse Cravens](https://github.com/jessecravens)
#### LICENSE

Просмотреть файл

@ -1,14 +1,19 @@
-----BEGIN CERTIFICATE-----
MIICHzCCAYgCCQCPPSUAa8QZojANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJS
VTETMBEGA1UECBMKU29tZS1TdGF0ZTENMAsGA1UEBxMET21zazEhMB8GA1UEChMY
SW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTExMDQwOTEwMDY0NVoXDTExMDUw
OTEwMDY0NVowVDELMAkGA1UEBhMCUlUxEzARBgNVBAgTClNvbWUtU3RhdGUxDTAL
BgNVBAcTBE9tc2sxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1bn25sPkv46wl70BffxradlkRd/x
p5Xf8HDhPSfzNNctERYslXT2fX7Dmfd5w1XTVqqGqJ4izp5VewoVOHA8uavo3ovp
gNWasil5zADWaM1T0nnV0RsFbZWzOTmm1U3D48K8rW3F5kOZ6f4yRq9QT1gF/gN7
5Pt494YyYyJu/a8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBuRZisIViI2G/R+w79
vk21TzC/cJ+O7tKsseDqotXYTH8SuimEH5IWcXNgnWhNzczwN8s2362NixyvCipV
yd4wzMpPbjIhnWGM0hluWZiK2RxfcqimIBjDParTv6CMUIuwGQ257THKY8hXGg7j
Uws6Lif3P9UbsuRiYPxMgg98wg==
MIIDBjCCAe4CCQCC8qgopCwXKDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTEzMDEwODEyMzYyM1oXDTIzMDEwNjEyMzYyM1owRTELMAkG
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALYWwPVTdWu+55Y9WKcZKi+iC/BVoV6uejF/7twOQZRAMAs2rFhCnxmds8d7jcX6
wBHOejKFYqbm9WPORckieOVmHRHYLhzCXHrhYMHSYW5NxwTCxdka+QEzoFJqBSwO
AkBQaF9ETA/GDa22TGN0DqUAtH6AiT3FAf4lSng1gLnMaa6+jYDmHmGHf2epRw+N
U8Kb4g8iNLPP10M3x1DIlVtB2MvXgHFY5/fz4BSD8QweqUGaoIuAcLdJ6qJmbztm
FWCWmr3uNHo2V6KxjHMMpziCa+280im6OgsdsgMuQO949hk+5k+PZ/WR+Ia4NylE
FI6cVXpZwALAVWxC9VO1oocCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAluAKUeNS
brX8+Jr7hOEftd+maTb8ERV4CU2wFSeCqupoSGh4Er37FO+eL1cAzaewpQzx8Uvp
q7oO+utrOKGA42P0bkdX6vqXZ73seorKl4Mv6Lnq1z1uTRTQyAbvJpv6mYrr+oz5
QgTGvPqUWqpv+OPf2R9J00IVLlfIjdKGLt0iZ3QEeS6SDkV/MHT4fEc9fImsg6Rq
xcb8kmcv9GAHo7YzxOw2F85h93epl6zUUlW2QCzUbvEF2S5NQowdkDQz0py6o4tv
S5Dh5XYLDm7gjcRElLNLaTmdhq9IGBEdbXy6a9kzJqZz4+AOn5+WPnA/KhVhWoTE
nJHIzjR3CQEkbA==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,11 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBkzCB/QIBADBUMQswCQYDVQQGEwJSVTETMBEGA1UECBMKU29tZS1TdGF0ZTEN
MAsGA1UEBxMET21zazEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVufbmw+S/jrCXvQF9/Gtp2WRF
3/Gnld/wcOE9J/M01y0RFiyVdPZ9fsOZ93nDVdNWqoaoniLOnlV7ChU4cDy5q+je
i+mA1ZqyKXnMANZozVPSedXRGwVtlbM5OabVTcPjwrytbcXmQ5np/jJGr1BPWAX+
A3vk+3j3hjJjIm79rwIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEAiNWhz6EppIVa
FfUaB3sLeqfamb9tg9kBHtvqj/FJni0snqms0kPWaTySEPHZF0irIb7VVdq/sVCb
3gseMVSyoDvPJ4lHC3PXqGQ7kM1mIPhDnR/4HDA3BhlGhTXSDIHgZnvI+HMBdsyC
hC3dz5odyKqe4nmoofomALkBL9t4H8s=
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx
ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALYWwPVTdWu+55Y9WKcZKi+iC/BVoV6uejF/7twO
QZRAMAs2rFhCnxmds8d7jcX6wBHOejKFYqbm9WPORckieOVmHRHYLhzCXHrhYMHS
YW5NxwTCxdka+QEzoFJqBSwOAkBQaF9ETA/GDa22TGN0DqUAtH6AiT3FAf4lSng1
gLnMaa6+jYDmHmGHf2epRw+NU8Kb4g8iNLPP10M3x1DIlVtB2MvXgHFY5/fz4BSD
8QweqUGaoIuAcLdJ6qJmbztmFWCWmr3uNHo2V6KxjHMMpziCa+280im6OgsdsgMu
QO949hk+5k+PZ/WR+Ia4NylEFI6cVXpZwALAVWxC9VO1oocCAwEAAaAAMA0GCSqG
SIb3DQEBBQUAA4IBAQCuMWhXWTpHDZTYFtkasd/b02D45RyyQTYNvw0qS67rBKnj
52YvHKXvdjXe+TFuEzq6G7QAa7cgcdv12ffzboa8l9E4hY4OTO/lysCB1gMxgpTg
ulDFRTQrIgCjrIm4rIGkFj47VL0ieSRhU4bf9npQydXdaYk0DHOxpLdGrs85LbZf
lt/5Bsls9bSsh+JYcgoOPYxcgKBzhingh/FV93HQ39JHxtcqkrpZqrfNfHSVr9gT
t+YyvUh0ctO5oGEfQj27Ewk3yt1nwgCETP55yCUhWIhJF5ATSFqm0nfeS1QYHMcU
27Hcp+20/4D4MbZ04gi4bi6Z92DawssfKfow/B4u
-----END CERTIFICATE REQUEST-----

Просмотреть файл

@ -1,15 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var spdy = exports;
// Exports utils
@ -16,8 +12,9 @@ try {
spdy.protocol.generic = require('./spdy/protocol/generic.js');
}
// Only SPDY v2 is supported now
// Supported SPDY versions
spdy.protocol[2] = require('./spdy/protocol/v2');
spdy.protocol[3] = require('./spdy/protocol/v3');
spdy.parser = require('./spdy/parser');

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var parser = exports;
var spdy = require('../spdy'),
@ -9,15 +5,21 @@ var spdy = require('../spdy'),
stream = require('stream'),
Buffer = require('buffer').Buffer;
var legacy = !stream.Duplex;
if (legacy) {
var DuplexStream = stream;
} else {
var DuplexStream = stream.Duplex;
}
//
// ### function Parser (connection, deflate, inflate)
// ### function Parser (connection)
// #### @connection {spdy.Connection} connection
// #### @deflate {zlib.Deflate} Deflate stream
// #### @inflate {zlib.Inflate} Inflate stream
// SPDY protocol frames parser's @constructor
//
function Parser(connection, deflate, inflate) {
stream.Stream.call(this);
function Parser(connection) {
DuplexStream.call(this);
this.drained = true;
this.paused = false;
@ -26,33 +28,45 @@ function Parser(connection, deflate, inflate) {
this.waiting = 8;
this.state = { type: 'frame-head' };
this.deflate = deflate;
this.inflate = inflate;
this.socket = connection.socket;
this.connection = connection;
this.framer = null;
this.connection = connection;
this.readable = this.writable = true;
if (legacy) {
this.readable = this.writable = true;
}
}
util.inherits(Parser, stream.Stream);
util.inherits(Parser, DuplexStream);
//
// ### function create (connection, deflate, inflate)
// ### function create (connection)
// #### @connection {spdy.Connection} connection
// #### @deflate {zlib.Deflate} Deflate stream
// #### @inflate {zlib.Inflate} Inflate stream
// @constructor wrapper
//
parser.create = function create(connection, deflate, inflate) {
return new Parser(connection, deflate, inflate);
parser.create = function create(connection) {
return new Parser(connection);
};
//
// ### function write (data)
// ### function destroy ()
// Just a stub.
//
Parser.prototype.destroy = function destroy() {
};
//
// ### function _write (data, encoding, cb)
// #### @data {Buffer} chunk of data
// #### @encoding {Null} encoding
// #### @cb {Function} callback
// Writes or buffers data to parser
//
Parser.prototype.write = function write(data) {
Parser.prototype._write = function write(data, encoding, cb) {
// Legacy compatibility
if (!cb) cb = function() {};
if (data !== undefined) {
// Buffer data
this.buffer.push(data);
@ -63,7 +77,7 @@ Parser.prototype.write = function write(data) {
if (this.paused) return false;
// We shall not do anything until we get all expected data
if (this.buffered < this.waiting) return;
if (this.buffered < this.waiting) return cb();
// Mark parser as not drained
if (data !== undefined) this.drained = false;
@ -106,13 +120,16 @@ Parser.prototype.write = function write(data) {
self.paused = false;
// Propagate errors
if (err) return self.emit('error', err);
if (err) {
cb();
return self.emit('error', err);
}
// Set new `waiting`
self.waiting = waiting;
if (self.waiting <= self.buffered) {
self.write();
self._write(undefined, null, cb);
} else {
process.nextTick(function() {
if (self.drained) return;
@ -121,16 +138,54 @@ Parser.prototype.write = function write(data) {
self.drained = true;
self.emit('drain');
});
cb();
}
});
};
if (legacy) {
//
// ### function write (data, encoding, cb)
// #### @data {Buffer} chunk of data
// #### @encoding {Null} encoding
// #### @cb {Function} callback
// Legacy method
//
Parser.prototype.write = Parser.prototype._write;
//
// ### function end ()
// Stream's end() implementation
//
Parser.prototype.end = function end() {
this.emit('end');
};
}
//
// ### function end ()
// Stream's end() implementation
// ### function createFramer (version)
// #### @version {Number} Protocol version, either 2 or 3
// Sets framer instance on Parser's instance
//
Parser.prototype.end = function end() {
this.emit('end');
Parser.prototype.createFramer = function createFramer(version) {
if (spdy.protocol[version]) {
this.emit('version', version);
this.framer = new spdy.protocol[version].Framer(
spdy.utils.zwrap(this.connection._deflate),
spdy.utils.zwrap(this.connection._inflate)
);
// Propagate framer to connection
this.connection._framer = this.framer;
this.emit('framer', this.framer);
} else {
this.emit(
'error',
new Error('Unknown protocol version requested: ' + version)
);
}
};
//
@ -146,16 +201,7 @@ Parser.prototype.execute = function execute(state, data, callback) {
// Lazily create framer
if (!this.framer && header.control) {
if (spdy.protocol[header.version]) {
this.framer = new spdy.protocol[header.version].Framer(
spdy.utils.zwrap(this.deflate),
spdy.utils.zwrap(this.inflate)
);
// Propagate framer to connection
this.connection.framer = this.framer;
this.emit('_framer', this.framer);
}
this.createFramer(header.version);
}
state.type = 'frame-body';

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// ### function parseHeader (data)
// ### @data {Buffer} incoming data

Просмотреть файл

@ -0,0 +1,15 @@
exports.dictionary = new Buffer([
'optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-',
'languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi',
'f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser',
'-agent10010120020120220320420520630030130230330430530630740040140240340440',
'5406407408409410411412413414415416417500501502503504505accept-rangesageeta',
'glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic',
'ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran',
'sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati',
'oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo',
'ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe',
'pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic',
'ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1',
'.1statusversionurl\x00'
].join(''));

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var framer = exports;
var spdy = require('../../../spdy'),
@ -15,6 +11,7 @@ var spdy = require('../../../spdy'),
// Framer constructor
//
function Framer(deflate, inflate) {
this.version = 2;
this.deflate = deflate;
this.inflate = inflate;
}
@ -36,6 +33,8 @@ Framer.prototype.execute = function execute(header, body, callback) {
body = body.slice(frame._offset);
this.inflate(body, function(err, chunks, length) {
if (err) return callback(err);
var pairs = new Buffer(length);
for (var i = 0, offset = 0; i < chunks.length; i++) {
chunks[i].copy(pairs, offset);
@ -43,6 +42,7 @@ Framer.prototype.execute = function execute(header, body, callback) {
}
frame.headers = protocol.parseHeaders(pairs);
frame.url = frame.headers.url || '';
callback(null, frame);
});
@ -130,7 +130,7 @@ function headersToDict(headers, preprocess) {
return result;
};
Framer.prototype._synFrame = function _synFrame(type, id, assoc, dict,
Framer.prototype._synFrame = function _synFrame(type, id, assoc, priority, dict,
callback) {
// Compress headers
this.deflate(dict, function (err, chunks, size) {
@ -150,6 +150,8 @@ Framer.prototype._synFrame = function _synFrame(type, id, assoc, dict,
frame.writeUInt32BE(assoc & 0x7fffffff, 12, true); // Stream-ID
}
frame.writeUInt8(priority & 0x3, 16, true); // Priority
for (var i = 0; i < chunks.length; i++) {
chunks[i].copy(frame, offset);
offset += chunks[i].length;
@ -171,11 +173,11 @@ Framer.prototype._synFrame = function _synFrame(type, id, assoc, dict,
Framer.prototype.replyFrame = function replyFrame(id, code, reason, headers,
callback) {
var dict = headersToDict(headers, function(headers) {
headers.status = code + ' ' + reason;
headers.version = 'HTTP/1.1';
});
headers.status = code + ' ' + reason;
headers.version = 'HTTP/1.1';
});
this._synFrame('SYN_REPLY', id, null, dict, callback);
this._synFrame('SYN_REPLY', id, null, 0, dict, callback);
};
//
@ -196,7 +198,7 @@ Framer.prototype.streamFrame = function streamFrame(id, assoc, meta, headers,
headers.url = meta.url;
});
this._synFrame('SYN_STREAM', id, assoc, dict, callback);
this._synFrame('SYN_STREAM', id, assoc, meta.priority, dict, callback);
};
//
@ -260,23 +262,23 @@ Framer.prototype.rstFrame = function rstFrame(id, code) {
Framer.rstCache = {};
//
// ### function maxStreamsFrame (count)
// #### @count {Number} Max Concurrent Streams count
// ### function settingsFrame (options)
// #### @options {Object} settings frame options
// Sends SETTINGS frame with MAX_CONCURRENT_STREAMS
//
Framer.prototype.maxStreamsFrame = function maxStreamsFrame(count) {
Framer.prototype.settingsFrame = function settingsFrame(options) {
var settings;
if (!(settings = Framer.settingsCache[count])) {
if (!(settings = Framer.settingsCache[options.maxStreams])) {
settings = new Buffer(20);
settings.writeUInt32BE(0x80020004, 0, true); // Version and type
settings.writeUInt32BE(0x0000000C, 4, true); // length
settings.writeUInt32BE(0x00000001, 8, true); // Count of entries
settings.writeUInt32LE(0x01000004, 12, true); // Entry ID and Persist flag
settings.writeUInt32BE(count, 16, true); // 100 Streams
settings.writeUInt32BE(options.maxStreams, 16, true);
Framer.settingsCache[count] = settings;
Framer.settingsCache[options.maxStreams] = settings;
}
return settings;

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var v2;
try {
@ -12,3 +8,5 @@ try {
module.exports = v2;
v2.Framer = require('./framer').Framer;
v2.dictionary = require('./dictionary').dictionary;

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var protocol = exports;
//
@ -17,6 +13,7 @@ protocol.parseSynHead = function parseSynHead(type, flags, data) {
return {
type: stream ? 'SYN_STREAM' : 'SYN_REPLY',
id: data.readUInt32BE(0, true) & 0x7fffffff,
version: 2,
associated: stream ? data.readUInt32BE(4, true) & 0x7fffffff : 0,
priority: stream ? data[8] >> 6 : 0,
fin: (flags & 0x01) === 0x01,

Просмотреть файл

@ -0,0 +1,180 @@
exports.dictionary = new Buffer([
0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,
0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,
0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,
0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,
0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,
0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,
0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,
0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,
0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,
0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,
0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,
0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,
0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,
0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,
0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,
0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,
0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,
0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,
0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,
0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,
0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,
0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,
0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,
0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,
0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,
0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,
0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,
0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,
0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,
0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,
0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,
0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,
0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,
0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,
0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,
0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,
0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,
0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,
0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,
0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,
0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,
0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,
0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,
0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,
0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,
0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,
0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,
0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,
0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,
0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,
0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,
0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,
0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,
0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,
0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,
0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,
0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,
0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,
0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,
0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,
0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,
0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,
0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,
0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,
0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,
0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,
0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,
0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,
0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,
0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,
0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,
0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,
0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,
0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,
0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,
0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,
0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,
0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,
0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,
0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,
0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,
0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,
0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,
0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,
0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,
0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,
0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,
0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,
0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,
0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,
0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,
0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,
0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,
0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,
0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,
0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,
0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,
0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,
0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,
0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,
0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,
0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,
0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,
0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,
0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,
0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,
0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,
0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,
0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,
0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,
0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,
0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,
0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,
0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,
0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,
0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,
0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,
0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e
]);

Просмотреть файл

@ -0,0 +1,335 @@
var framer = exports;
var spdy = require('../../../spdy'),
Buffer = require('buffer').Buffer,
protocol = require('./');
//
// ### function Framer (deflate, inflate)
// #### @deflate {zlib.Deflate} Deflate stream
// #### @inflate {zlib.Inflate} Inflate stream
// Framer constructor
//
function Framer(deflate, inflate) {
this.version = 3;
this.deflate = deflate;
this.inflate = inflate;
}
exports.Framer = Framer;
//
// ### function execute (header, body, callback)
// #### @header {Object} Frame headers
// #### @body {Buffer} Frame's body
// #### @callback {Function} Continuation callback
// Parse frame (decompress data and create streams)
//
Framer.prototype.execute = function execute(header, body, callback) {
// SYN_STREAM or SYN_REPLY
if (header.type === 0x01 || header.type === 0x02) {
var frame = protocol.parseSynHead(header.type, header.flags, body);
body = body.slice(frame._offset);
this.inflate(body, function(err, chunks, length) {
if (err) return callback(err);
var pairs = new Buffer(length);
for (var i = 0, offset = 0; i < chunks.length; i++) {
chunks[i].copy(pairs, offset);
offset += chunks[i].length;
}
frame.headers = protocol.parseHeaders(pairs);
frame.url = frame.headers.path || '';
callback(null, frame);
});
// RST_STREAM
} else if (header.type === 0x03) {
callback(null, protocol.parseRst(body));
// SETTINGS
} else if (header.type === 0x04) {
callback(null, protocol.parseSettings(body));
} else if (header.type === 0x05) {
callback(null, { type: 'NOOP' });
// PING
} else if (header.type === 0x06) {
callback(null, { type: 'PING', pingId: body });
// GOAWAY
} else if (header.type === 0x07) {
callback(null, protocol.parseGoaway(body));
} else if (header.type === 0x09) {
callback(null, protocol.parseWindowUpdate(body));
} else {
callback(null, { type: 'unknown: ' + header.type, body: body });
}
};
//
// internal, converts object into spdy dictionary
//
function headersToDict(headers, preprocess) {
function stringify(value) {
if (value !== undefined) {
if (Array.isArray(value)) {
return value.join('\x00');
} else if (typeof value === 'string') {
return value;
} else {
return value.toString();
}
} else {
return '';
}
}
// Lower case of all headers keys
var loweredHeaders = {};
Object.keys(headers || {}).map(function(key) {
loweredHeaders[key.toLowerCase()] = headers[key];
});
// Allow outer code to add custom headers or remove something
if (preprocess) preprocess(loweredHeaders);
// Transform object into kv pairs
var len = 4,
pairs = Object.keys(loweredHeaders).filter(function(key) {
var lkey = key.toLowerCase();
return lkey !== 'connection' && lkey !== 'keep-alive' &&
lkey !== 'proxy-connection' && lkey !== 'transfer-encoding';
}).map(function(key) {
var klen = Buffer.byteLength(key),
value = stringify(loweredHeaders[key]),
vlen = Buffer.byteLength(value);
len += 8 + klen + vlen;
return [klen, key, vlen, value];
}),
result = new Buffer(len);
result.writeUInt32BE(pairs.length, 0, true);
var offset = 4;
pairs.forEach(function(pair) {
// Write key length
result.writeUInt32BE(pair[0], offset, true);
// Write key
result.write(pair[1], offset + 4);
offset += pair[0] + 4;
// Write value length
result.writeUInt32BE(pair[2], offset, true);
// Write value
result.write(pair[3], offset + 4);
offset += pair[2] + 4;
});
return result;
};
Framer.prototype._synFrame = function _synFrame(type, id, assoc, priority, dict,
callback) {
// Compress headers
this.deflate(dict, function (err, chunks, size) {
if (err) return callback(err);
var offset = type === 'SYN_STREAM' ? 18 : 12,
total = (type === 'SYN_STREAM' ? 10 : 4) + size,
frame = new Buffer(offset + size);;
frame.writeUInt16BE(0x8003, 0, true); // Control + Version
frame.writeUInt16BE(type === 'SYN_STREAM' ? 1 : 2, 2, true); // type
frame.writeUInt32BE(total & 0x00ffffff, 4, true); // No flag support
frame.writeUInt32BE(id & 0x7fffffff, 8, true); // Stream-ID
if (type === 'SYN_STREAM') {
frame[4] = 2;
frame.writeUInt32BE(assoc & 0x7fffffff, 12, true); // Stream-ID
}
frame.writeUInt8(priority & 0x7, 16, true); // Priority
for (var i = 0; i < chunks.length; i++) {
chunks[i].copy(frame, offset);
offset += chunks[i].length;
}
callback(null, frame);
});
};
//
// ### function replyFrame (id, code, reason, headers, callback)
// #### @id {Number} Stream ID
// #### @code {Number} HTTP Status Code
// #### @reason {String} (optional)
// #### @headers {Object|Array} (optional) HTTP headers
// #### @callback {Function} Continuation function
// Sends SYN_REPLY frame
//
Framer.prototype.replyFrame = function replyFrame(id, code, reason, headers,
callback) {
var dict = headersToDict(headers, function(headers) {
headers[':status'] = code + ' ' + reason;
headers[':version'] = 'HTTP/1.1';
});
this._synFrame('SYN_REPLY', id, null, 0, dict, callback);
};
//
// ### function streamFrame (id, assoc, headers, callback)
// #### @id {Number} stream id
// #### @assoc {Number} associated stream id
// #### @meta {Object} meta headers ( method, scheme, url, version )
// #### @headers {Object} stream headers
// #### @callback {Function} continuation callback
// Create SYN_STREAM frame
// (needed for server push and testing)
//
Framer.prototype.streamFrame = function streamFrame(id, assoc, meta, headers,
callback) {
var dict = headersToDict(headers, function(headers) {
headers[':status'] = 200;
headers[':version'] = meta.version || 'HTTP/1.1';
headers[':path'] = meta.path;
headers[':scheme'] = meta.scheme || 'https';
headers[':host'] = meta.host;
});
this._synFrame('SYN_STREAM', id, assoc, meta.priority, dict, callback);
};
//
// ### function dataFrame (id, fin, data)
// #### @id {Number} Stream id
// #### @fin {Bool} Is this data frame last frame
// #### @data {Buffer} Response data
// Sends DATA frame
//
Framer.prototype.dataFrame = function dataFrame(id, fin, data) {
if (!fin && !data.length) return [];
var frame = new Buffer(8 + data.length);
frame.writeUInt32BE(id & 0x7fffffff, 0, true);
frame.writeUInt32BE(data.length & 0x00ffffff, 4, true);
frame.writeUInt8(fin ? 0x01 : 0x0, 4, true);
if (data.length) data.copy(frame, 8);
return frame;
};
//
// ### function pingFrame (id)
// #### @id {Buffer} Ping ID
// Sends PING frame
//
Framer.prototype.pingFrame = function pingFrame(id) {
var header = new Buffer(12);
header.writeUInt32BE(0x80030006, 0, true); // Version and type
header.writeUInt32BE(0x00000004, 4, true); // Length
id.copy(header, 8, 0, 4); // ID
return header;
};
//
// ### function rstFrame (id, code)
// #### @id {Number} Stream ID
// #### @code {NUmber} RST Code
// Sends PING frame
//
Framer.prototype.rstFrame = function rstFrame(id, code) {
var header;
if (!(header = Framer.rstCache[code])) {
header = new Buffer(16);
header.writeUInt32BE(0x80030003, 0, true); // Version and type
header.writeUInt32BE(0x00000008, 4, true); // Length
header.writeUInt32BE(id & 0x7fffffff, 8, true); // Stream ID
header.writeUInt32BE(code, 12, true); // Status Code
Framer.rstCache[code] = header;
}
return header;
};
Framer.rstCache = {};
//
// ### function settingsFrame (options)
// #### @options {Object} settings frame options
// Sends SETTINGS frame with MAX_CONCURRENT_STREAMS and initial window
//
Framer.prototype.settingsFrame = function settingsFrame(options) {
var settings,
key = options.maxStreams + ':' + options.windowSize;
if (!(settings = Framer.settingsCache[key])) {
settings = new Buffer(28);
settings.writeUInt32BE(0x80030004, 0, true); // Version and type
settings.writeUInt32BE((4 + 8 * 2) & 0x00FFFFFF, 4, true); // length
settings.writeUInt32BE(0x00000002, 8, true); // Count of entries
settings.writeUInt32BE(0x01000004, 12, true); // Entry ID and Persist flag
settings.writeUInt32BE(options.maxStreams & 0x7fffffff, 16, true);
settings.writeUInt32BE(0x01000007, 20, true); // Entry ID and Persist flag
settings.writeUInt32BE(options.windowSize & 0x7fffffff, 24, true);
Framer.settingsCache[key] = settings;
}
return settings;
};
Framer.settingsCache = {};
//
// ### function windowSizeFrame (size)
// #### @size {Number} data transfer window size
// Sends SETTINGS frame with window size
//
Framer.prototype.windowSizeFrame = function windowSizeFrame(size) {
var settings;
if (!(settings = Framer.windowSizeCache[size])) {
settings = new Buffer(20);
settings.writeUInt32BE(0x80030004, 0, true); // Version and type
settings.writeUInt32BE((4 + 8) & 0x00FFFFFF, 4, true); // length
settings.writeUInt32BE(0x00000001, 8, true); // Count of entries
settings.writeUInt32BE(0x01000007, 12, true); // Entry ID and Persist flag
settings.writeUInt32BE(size & 0x7fffffff, 16, true); // Window Size (KB)
Framer.windowSizeCache[size] = settings;
}
return settings;
};
Framer.windowSizeCache = {};
//
// ### function windowUpdateFrame (id)
// #### @id {Buffer} WindowUpdate ID
// Sends WINDOW_UPDATE frame
//
Framer.prototype.windowUpdateFrame = function windowUpdateFrame(id, delta) {
var header = new Buffer(16);
header.writeUInt32BE(0x80030009, 0, true); // Version and type
header.writeUInt32BE(0x00000008, 4, true); // Length
header.writeUInt32BE(id & 0x7fffffff, 8, true); // ID
header.writeUInt32BE(delta & 0x7fffffff, 12, true); // delta
return header;
};

Просмотреть файл

@ -0,0 +1,12 @@
var v3;
try {
v3 = require('./protocol.node');
} catch (e) {
v3 = require('./protocol.js');
}
module.exports = v3;
v3.Framer = require('./framer').Framer;
v3.dictionary = require('./dictionary').dictionary;

Просмотреть файл

@ -0,0 +1,109 @@
var protocol = exports;
//
// ### function parseSynHead (type, flags, data)
// #### @type {Number} Frame type
// #### @flags {Number} Frame flags
// #### @data {Buffer} input data
// Returns parsed syn_* frame's head
//
protocol.parseSynHead = function parseSynHead(type, flags, data) {
var stream = type === 0x01;
return {
type: stream ? 'SYN_STREAM' : 'SYN_REPLY',
id: data.readUInt32BE(0, true) & 0x7fffffff,
version: 3,
associated: stream ? data.readUInt32BE(4, true) & 0x7fffffff : 0,
priority: stream ? data[8] >> 5 : 0,
fin: (flags & 0x01) === 0x01,
unidir: (flags & 0x02) === 0x02,
_offset: stream ? 10 : 4
};
};
//
// ### function parseHeaders (pairs)
// #### @pairs {Buffer} header pairs
// Returns hashmap of parsed headers
//
protocol.parseHeaders = function parseHeaders(pairs) {
var count = pairs.readUInt32BE(0, true),
headers = {};
pairs = pairs.slice(4);
function readString() {
var len = pairs.readUInt32BE(0, true),
value = pairs.slice(4, 4 + len);
pairs = pairs.slice(4 + len);
return value.toString();
}
while(count > 0) {
headers[readString().replace(/^:/, '')] = readString();
count--;
}
return headers;
};
//
// ### function parsesRst frame
protocol.parseRst = function parseRst(data) {
return {
type: 'RST_STREAM',
id: data.readUInt32BE(0, true) & 0x7fffffff,
status: data.readUInt32BE(4, true)
};
};
protocol.parseSettings = function parseSettings(data) {
var settings = {},
number = data.readUInt32BE(0, true),
idMap = {
1: 'upload_bandwidth',
2: 'download_bandwidth',
3: 'round_trip_time',
4: 'max_concurrent_streams',
5: 'current_cwnd',
6: 'download_retrans_rate',
7: 'initial_window_size',
8: 'client_certificate_vector_size'
};
for (var i=0; i<number; i++) {
var id = data.readUInt32BE(4 + (i*8), true) & 0x00ffffff,
flags = data.readUInt8(4 + (i*8), true),
name = idMap[id];
settings[id] = settings[name] = {
persist: !!(flags & 0x1),
persisted: !!(flags & 0x2),
value: data.readUInt32BE(8 + (i*8), true)
};
}
return {
type: 'SETTINGS',
settings: settings
};
};
protocol.parseGoaway = function parseGoaway(data) {
return {
type: 'GOAWAY',
lastId: data.readUInt32BE(0, true) & 0x7fffffff
};
};
protocol.parseWindowUpdate = function parseWindowUpdate(data) {
var ret = {
type: 'WINDOW_UPDATE',
id: data.readUInt32BE(0, true) & 0x7fffffff,
delta: data.readUInt32BE(4, true) & 0x7fffffff
};
return ret;
};

Просмотреть файл

@ -1,9 +1,6 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var spdy = require('../spdy'),
http = require('http');
http = require('http'),
res = http.ServerResponse.prototype;
//
// ### function _renderHeaders ()
@ -15,15 +12,13 @@ exports._renderHeaders = function() {
throw new Error("Can't render headers after they are sent to the client.");
}
if (!this._headers) return {};
var headers = {};
var keys = Object.keys(this._headers);
var keys = Object.keys(this._headerNames);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
headers[(this._headerNames[key] || '').toLowerCase()] = this._headers[key];
this._headerNames[key] = this._headerNames[key].toLowerCase();
}
return headers;
return res._renderHeaders.call(this);
};
//
@ -71,12 +66,12 @@ exports.writeHead = function(statusCode) {
this._header = '';
// Do not send data to new connections after GOAWAY
if (this.socket.isGoaway()) return;
if (this.socket._isGoaway()) return;
this.socket.lock(function() {
this.socket._lock(function() {
var socket = this;
this.framer.replyFrame(
this._framer.replyFrame(
this.id,
statusCode,
reasonPhrase,
@ -84,7 +79,7 @@ exports.writeHead = function(statusCode) {
function (err, frame) {
// TODO: Handle err
socket.connection.write(frame);
socket.unlock();
socket._unlock();
}
);
});
@ -97,38 +92,45 @@ exports.writeHead = function(statusCode) {
// #### @callbacks {Function} continuation that will receive stream object
// Initiates push stream
//
exports.push = function push(url, headers, callback) {
exports.push = function push(url, headers, priority, callback) {
if (this.socket._destroyed) {
return callback(Error('Can\'t open push stream, parent socket destroyed'));
}
this.socket.lock(function() {
if (!callback && typeof priority === 'function') {
callback = priority;
priority = 0;
}
if (!callback) callback = function() {};
this.socket._lock(function() {
var socket = this,
id = socket.connection.pushId += 2,
fullUrl = /^\//.test(url) ?
this.frame.headers.scheme + '://' +
(this.frame.headers.host || 'localhost') +
url
:
url;
scheme = this._frame.headers.scheme,
host = this._frame.headers.host || 'localhost',
fullUrl = /^\//.test(url) ? scheme + '://' + host + url : url;
this.framer.streamFrame(
this._framer.streamFrame(
id,
this.id,
{
method: 'GET',
path: url,
url: fullUrl,
schema: 'https',
version: 'HTTP/1.1'
scheme: scheme,
host: host,
version: 'HTTP/1.1',
priority: priority || 0
},
headers,
function(err, frame) {
if (err) {
socket.unlock();
socket._unlock();
callback(err);
} else {
socket.connection.write(frame);
socket.unlock();
socket._unlock();
var stream = new spdy.server.Stream(socket.connection, {
type: 'SYN_STREAM',

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var scheduler = exports;
//
@ -11,7 +7,7 @@ var scheduler = exports;
//
function Scheduler(connection) {
this.connection = connection;
this.priorities = [[], [], [], []];
this.priorities = [[], [], [], [], [], [], [], []];
this._tickListener = null;
}
@ -44,10 +40,10 @@ Scheduler.prototype.tick = function tick() {
var priorities = self.priorities;
self._tickListener = null;
self.priorities = [[], [], [], []];
self.priorities = [[], [], [], [], [], [], [], []];
// Run all priorities
for (var i = 0; i < 4; i++) {
for (var i = 0; i < 8; i++) {
for (var j = 0; j < priorities[i].length; j++) {
self.connection.write(
priorities[i][j]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,35 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var utils = exports;
var spdy = require('../spdy'),
utils = exports;
var zlib = require('zlib'),
Buffer = require('buffer').Buffer;
// SPDY deflate/inflate dictionary
var dictionary = new Buffer([
'optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-',
'languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi',
'f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser',
'-agent10010120020120220320420520630030130230330430530630740040140240340440',
'5406407408409410411412413414415416417500501502503504505accept-rangesageeta',
'glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic',
'ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran',
'sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati',
'oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo',
'ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe',
'pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic',
'ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1',
'.1statusversionurl\x00'
].join(''));
//
// ### function createDeflate ()
// Creates deflate stream with SPDY dictionary
//
utils.createDeflate = function createDeflate() {
var deflate = zlib.createDeflate({ dictionary: dictionary, windowBits: 11 });
utils.createDeflate = function createDeflate(version) {
var deflate = zlib.createDeflate({
dictionary: spdy.protocol[version].dictionary,
windowBits: 11
});
// Define lock information early
deflate.locked = false;
@ -42,8 +25,11 @@ utils.createDeflate = function createDeflate() {
// ### function createInflate ()
// Creates inflate stream with SPDY dictionary
//
utils.createInflate = function createInflate() {
var inflate = zlib.createInflate({ dictionary: dictionary, windowBits: 15 });
utils.createInflate = function createInflate(version) {
var inflate = zlib.createInflate({
dictionary: spdy.protocol[version].dictionary,
windowBits: 15
});
// Define lock information early
inflate.locked = false;
@ -99,8 +85,14 @@ utils.zstream = function zstream(stream, buffer, callback) {
stream.on('data', collect);
stream.write(buffer);
stream.once('error', function(err) {
stream.removeAllListeners('data');
callback(err);
});
stream.flush(function() {
stream.removeAllListeners('data');
stream.removeAllListeners('error');
stream._flush = flush;
callback(null, chunks, total);
@ -121,4 +113,3 @@ utils.zwrap = function zwrap(stream) {
utils.zstream(stream, data, callback);
};
};

Просмотреть файл

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var zlibpool = exports,
spdy = require('../spdy');
@ -10,7 +6,10 @@ var zlibpool = exports,
// Zlib streams pool
//
function Pool() {
this.pool = [];
this.pool = {
'spdy/2': [],
'spdy/3': []
};
}
//
@ -26,13 +25,16 @@ var x = 0;
// ### function get ()
// Returns pair from pool or a new one
//
Pool.prototype.get = function get(callback) {
if (this.pool.length > 0) {
return this.pool.pop();
Pool.prototype.get = function get(version, callback) {
if (this.pool[version].length > 0) {
return this.pool[version].pop();
} else {
var id = version.split('/', 2)[1];
return {
deflate: spdy.utils.createDeflate(),
inflate: spdy.utils.createInflate()
version: version,
deflate: spdy.utils.createDeflate(id),
inflate: spdy.utils.createInflate(id)
};
}
};
@ -50,7 +52,7 @@ Pool.prototype.put = function put(pair) {
function done() {
if (--waiting === 0) {
self.pool.push(pair);
self.pool[pair.version].push(pair);
}
}
};

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "spdy",
"version": "1.2.0",
"version": "1.8.8",
"description": "Implementation of the SPDY protocol on node.js.",
"keywords": [
"spdy"
@ -17,17 +17,22 @@
"author": "Fedor Indutny <fedor.indutny@gmail.com>",
"contributors": [
"Chris Storm <github@eeecooks.com>",
"François de Metz <francois@2metz.fr>"
"François de Metz <francois@2metz.fr>",
"Ilya Grigorik <ilya@igvita.com>",
"Roberto Peon",
"Tatsuhiro Tsujikawa",
"Jesse Cravens <jesse.cravens@gmail.com>"
],
"dependencies": {},
"devDependencies": {
"mocha": "~ 0.10.1"
"mocha": "1.3.x"
},
"scripts": {
"test": "mocha --ui tdd --growl --reporter spec test/unit/*-test.js"
},
"engines": [
"node ~ 0.7.0"
"node >= 0.7.0"
],
"main": "./lib/spdy"
"main": "./lib/spdy",
"optionalDependencies": {}
}

Просмотреть файл

@ -5,7 +5,8 @@ var keysDir = require('path').resolve(__dirname, '../../keys/'),
options = {
key: fs.readFileSync(keysDir + '/spdy-key.pem'),
cert: fs.readFileSync(keysDir + '/spdy-cert.pem'),
ca: fs.readFileSync(keysDir + '/spdy-csr.pem')
ca: fs.readFileSync(keysDir + '/spdy-csr.pem'),
rejectUnauthorized: false
};
module.exports = options;

Просмотреть файл

@ -9,8 +9,8 @@ suite('A Framer of SPDY module', function() {
framer;
setup(function() {
inflate = spdy.utils.zwrap(spdy.utils.createInflate());
deflate = spdy.utils.zwrap(spdy.utils.createDeflate());
inflate = spdy.utils.zwrap(spdy.utils.createInflate(2));
deflate = spdy.utils.zwrap(spdy.utils.createDeflate(2));
framer = new spdy.protocol[2].Framer(deflate, inflate);
});
@ -177,14 +177,5 @@ suite('A Framer of SPDY module', function() {
var frame = framer.rstFrame(1, 2);
assert.ok(frame.length > 0);
});
test('.maxStreamsFrame() should generate correct frame', function() {
var frame = framer.maxStreamsFrame(13);
assert.ok(frame.length > 0);
// Verify that cache works
var frame = framer.maxStreamsFrame(13);
assert.ok(frame.length > 0);
});
});
});

Просмотреть файл

@ -5,87 +5,98 @@ var assert = require('assert'),
suite('A Parser of SPDY module', function() {
var parser;
setup(function() {
var deflate = spdy.utils.createDeflate(),
inflate = spdy.utils.createInflate();
[2,3].forEach(function(version) {
suite('version ' + version, function() {
setup(function() {
var deflate = spdy.utils.createDeflate(version),
inflate = spdy.utils.createInflate(version);
parser = new spdy.parser.create(deflate, inflate);
});
parser = new spdy.parser.create({
socket: {
setNoDelay: function() {}
},
write: function() {}
}, deflate, inflate);
test('should wait for headers initially', function() {
assert.equal(parser.waiting, 8);
});
parser.createFramer(version);
});
test('should update buffered property once given < 8 bytes', function() {
parser.write(new Buffer(5));
assert.equal(parser.buffered, 5);
});
test('should wait for headers initially', function() {
assert.equal(parser.waiting, 8);
});
test('given SYN_STREAM header should start waiting for body', function() {
parser.write(new Buffer([
0x80, 0x02, 0x00, 0x01, // Control frame, version, type (SYN_STREAM)
0x00, 0x00, 0x12, 0x34
]));
test('should update buffered property once given < 8 bytes', function() {
parser.write(new Buffer(5));
assert.equal(parser.buffered, 5);
});
assert.equal(parser.waiting, 0x1234);
assert.equal(parser.state.type, 'frame-body');
assert.ok(parser.state.header.control);
assert.equal(parser.state.header.flags, 0);
assert.equal(parser.state.header.length, 0x1234);
});
test('given SYN_STREAM header should start waiting for body', function() {
parser.write(new Buffer([
0x80, 0x02, 0x00, 0x01, // Control frame, version, type (SYN_STREAM)
0x00, 0x00, 0x12, 0x34
]));
test('given DATA header should start waiting for body', function() {
parser.write(new Buffer([
0x00, 0x00, 0x00, 0x01, // Data frame, stream ID
0x00, 0x00, 0x12, 0x34
]));
assert.equal(parser.waiting, 0x1234);
assert.equal(parser.state.type, 'frame-body');
assert.ok(parser.state.header.control);
assert.equal(parser.state.header.flags, 0);
assert.equal(parser.state.header.length, 0x1234);
});
assert.equal(parser.waiting, 0x1234);
assert.equal(parser.state.type, 'frame-body');
assert.ok(!parser.state.header.control);
assert.equal(parser.state.header.id, 1);
assert.equal(parser.state.header.flags, 0);
assert.equal(parser.state.header.length, 0x1234);
});
test('given DATA header should start waiting for body', function() {
parser.write(new Buffer([
0x00, 0x00, 0x00, 0x01, // Data frame, stream ID
0x00, 0x00, 0x12, 0x34
]));
test('given chunked header should not fail', function() {
parser.write(new Buffer([
0x80, 0x02, 0x00, 0x01 // Control frame, version, type (SYN_STREAM)
]));
assert.equal(parser.buffered, 4);
assert.equal(parser.waiting, 0x1234);
assert.equal(parser.state.type, 'frame-body');
assert.ok(!parser.state.header.control);
assert.equal(parser.state.header.id, 1);
assert.equal(parser.state.header.flags, 0);
assert.equal(parser.state.header.length, 0x1234);
});
parser.write(new Buffer([
0x00, 0x00, 0x12, 0x34
]));
assert.equal(parser.buffered, 0);
test('given chunked header should not fail', function() {
parser.write(new Buffer([
0x80, 0x02, 0x00, 0x01 // Control frame, version, type (SYN_STREAM)
]));
assert.equal(parser.buffered, 4);
assert.equal(parser.waiting, 0x1234);
assert.equal(parser.state.type, 'frame-body');
assert.ok(parser.state.header.control);
assert.equal(parser.state.header.flags, 0);
assert.equal(parser.state.header.length, 0x1234);
});
parser.write(new Buffer([
0x00, 0x00, 0x12, 0x34
]));
assert.equal(parser.buffered, 0);
test('given header and body should emit `frame`', function(done) {
parser.on('frame', function(frame) {
assert.ok(frame.type === 'DATA');
assert.equal(frame.id, 1);
assert.equal(frame.data.length, 4);
assert.equal(frame.data[0], 0x01);
assert.equal(frame.data[1], 0x02);
assert.equal(frame.data[2], 0x03);
assert.equal(frame.data[3], 0x04);
done();
assert.equal(parser.waiting, 0x1234);
assert.equal(parser.state.type, 'frame-body');
assert.ok(parser.state.header.control);
assert.equal(parser.state.header.flags, 0);
assert.equal(parser.state.header.length, 0x1234);
});
test('given header and body should emit `frame`', function(done) {
parser.on('frame', function(frame) {
assert.ok(frame.type === 'DATA');
assert.equal(frame.id, 1);
assert.equal(frame.data.length, 4);
assert.equal(frame.data[0], 0x01);
assert.equal(frame.data[1], 0x02);
assert.equal(frame.data[2], 0x03);
assert.equal(frame.data[3], 0x04);
done();
});
parser.write(new Buffer([
0x00, 0x00, 0x00, 0x01, // Data frame, stream ID
0x00, 0x00, 0x00, 0x04,
0x01, 0x02, 0x03, 0x04 // Body
]));
// Waits for next frame
assert.equal(parser.waiting, 8);
assert.equal(parser.state.type, 'frame-head');
});
});
parser.write(new Buffer([
0x00, 0x00, 0x00, 0x01, // Data frame, stream ID
0x00, 0x00, 0x00, 0x04,
0x01, 0x02, 0x03, 0x04 // Body
]));
// Waits for next frame
assert.equal(parser.waiting, 8);
assert.equal(parser.state.type, 'frame-head');
});
});

Просмотреть файл

@ -5,7 +5,6 @@ var assert = require('assert'),
tls = require('tls'),request
Buffer = require('buffer').Buffer;
suite('A SPDY Server', function() {
var server;
setup(function(done) {
@ -26,7 +25,9 @@ suite('A SPDY Server', function() {
host: 'localhost',
port: 8081,
path: '/',
method: 'GET'
method: 'GET',
agent: false,
rejectUnauthorized: false
}, function(res) {
assert.equal(res.statusCode, 200);
done();
@ -37,9 +38,9 @@ suite('A SPDY Server', function() {
var socket = tls.connect(
8081,
'localhost',
{ NPNProtocols: ['spdy/2'] },
{ NPNProtocols: ['spdy/2'], rejectUnauthorized: false },
function() {
var deflate = spdy.utils.createDeflate(),
var deflate = spdy.utils.createDeflate(2),
chunks = [],
length = 0;
@ -133,6 +134,10 @@ suite('A SPDY Server', function() {
}
);
socket.on('error', function(err) {
console.error('Socket error: ' + err);
});
server.on('request', function(req, res) {
assert.equal(req.url, '/');
assert.equal(req.method, 'GET');