зеркало из https://github.com/mozilla/gecko-dev.git
bug 790388 part 4 - upgrade testing/node-spdy to 1.8.8 r=hurley
--HG-- extra : rebase_source : b68f6dbf8faa5b97b4a97417d35c037b0557e426
This commit is contained in:
Родитель
e18fe0b0fc
Коммит
32350953ba
|
@ -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-----
|
||||
MIICXAIBAAKBgQDVufbmw+S/jrCXvQF9/Gtp2WRF3/Gnld/wcOE9J/M01y0RFiyV
|
||||
dPZ9fsOZ93nDVdNWqoaoniLOnlV7ChU4cDy5q+jei+mA1ZqyKXnMANZozVPSedXR
|
||||
GwVtlbM5OabVTcPjwrytbcXmQ5np/jJGr1BPWAX+A3vk+3j3hjJjIm79rwIDAQAB
|
||||
AoGAAv2QI9h32epQND9TxwSCKD//dC7W/cZOFNovfKCTeZjNK6EIzKqPTGA6smvR
|
||||
C1enFl5adf+IcyWqAoe4lkqTvurIj+2EhtXdQ8DBlVuXKr3xvEFdYxXPautdTCF6
|
||||
KbXEyS/s1TZCRFjYftvCrXxc3pK45AQX/wg7z1K+YB5pyIECQQD0OJvLoxLYoXAc
|
||||
FZraIOZiDsEbGuSHqoCReFXH75EC3+XGYkH2bQ/nSIZ0h1buuwQ/ylKXOlTPT3Qt
|
||||
Xm1OQEBvAkEA4AjWsIO/rRpOm/Q2aCrynWMpoUXTZSbL2yGf8pxp/+8r2br5ier0
|
||||
M1LeBb/OPY1+k39NWLXxQoo64xoSFYk2wQJAd2wDCwX4HkR7HNCXw1hZL9QFK6rv
|
||||
20NN0VSlpboJD/3KT0MW/FiCcVduoCbaJK0Au+zEjDyy4hj5N4I4Mw6KMwJAXVAx
|
||||
I+psTsxzS4/njXG+BgIEl/C+gRYsuMQDnAi8OebDq/et8l0Tg8ETSu++FnM18neG
|
||||
ntmBeMacinUUbTXuwQJBAJp/onZdsMzeVulsGrqR1uS+Lpjc5Q1gt5ttt2cxj91D
|
||||
rio48C/ZvWuKNE8EYj2ALtghcVKRvgaWfOxt2GPguGg=
|
||||
MIIEowIBAAKCAQEAthbA9VN1a77nlj1YpxkqL6IL8FWhXq56MX/u3A5BlEAwCzas
|
||||
WEKfGZ2zx3uNxfrAEc56MoVipub1Y85FySJ45WYdEdguHMJceuFgwdJhbk3HBMLF
|
||||
2Rr5ATOgUmoFLA4CQFBoX0RMD8YNrbZMY3QOpQC0foCJPcUB/iVKeDWAucxprr6N
|
||||
gOYeYYd/Z6lHD41TwpviDyI0s8/XQzfHUMiVW0HYy9eAcVjn9/PgFIPxDB6pQZqg
|
||||
i4Bwt0nqomZvO2YVYJaave40ejZXorGMcwynOIJr7bzSKbo6Cx2yAy5A73j2GT7m
|
||||
T49n9ZH4hrg3KUQUjpxVelnAAsBVbEL1U7WihwIDAQABAoIBACdvHBDFJ0vTRzI5
|
||||
TOa7Q3CXZoCA+vaXUK1BqIgNqlQh5oW3LHHc07nndlTARD7ZBBmXHs2sJ2Y/5Grd
|
||||
9C0QAyCjEa6Yo7vkt8SA5MR0/Fa4D17Pk6tl9QE2ngTbIw2cZw5om4HuN46+9J1n
|
||||
OnnbW4SOd4hh69btwHW6u7r2007pQXme0AMlAxhgfIEiD6tHjqZDCtK4G0d+GSq6
|
||||
Ks/IpXckLcrluqJ2gHVB2sbBbjh1m7dHCVzBKynCwaHrWbNla8P6j3SdabP4Umcb
|
||||
tu3hP3nLigMJmA16KdkayUg05OvUTBAkReLcVZYZQ80LmM+NioB6UvwYy677h4ma
|
||||
XFihvLkCgYEA3aLOY2rve6DxvTXDJe8D91V//+5B9XBcyLP2cMEXIP+3W9Gto9tz
|
||||
vTIOcwj8MLKh22KBBMCP7OQlXFalBoG/d5Y9YKr6X2XHBcEw96Nm1HZctUPRPQdd
|
||||
+C8S5ikwTre9QMfLmLGKzgfIpDRYyijv0ZQZw+8qlNATtVrAMQGu6D0CgYEA0lI9
|
||||
zXK+4P28+SkkCUIG/Y31wF4KeM8V5s8eUYej8LV67GQIGs9XPCEIJY2cHZpn7qD8
|
||||
H90lucr90rwAHN2rLUSdq28NVL0+RTYKNBFRRvPNloLlKOR9RvorsFz5U4z48i9x
|
||||
yZ6gk+WL0ycc2oUFfihmQpHhRUiV46IB7deEXhMCgYEA1rW+3V8eC5VaOuOXXutS
|
||||
20vwCX7GVUB6ElENICRfBK/V8NSLM98IG7QffV+p+H9E/+RIetMVWveWHgMuMcSG
|
||||
ORLJ+RkKHlrZ2IBUsMKSfqb/nvbJACdf6GuqEmC6lLe5VsV3PkBY6MlvnWu8zHOm
|
||||
CFFCOKc8iBef0CPPZmpsCD0CgYAOtS+bOWX9x+C6L9VUTGi+vHmuDSWAU0L91AgT
|
||||
vX+KaraA53HlphA8pTazoZaEP3L7LgjTlZx4xKhBX2JGon3A+aZpAagV//Hl1ySZ
|
||||
hYiAhLYgy2CJHolgOEhr2eSZoicakJTNe6lRDmFbz8Vlxp2et+aGyzrMpInO1Fp8
|
||||
LnEUPwKBgExMk6THLz8CzjJhaKDrNn1fSs6jUxgK12+1cIJxb5JEgRJs4W+yFuLw
|
||||
exCE5YKPwnZNrbji+bdkk9FwHPLuf20aH5fIB0UlMMVcvLGKyxYl7BG1pShN4k8C
|
||||
kKXaClwkngJ2eSs/AsNAe9hhbEpFjAHt+3D7Sbg8EvgeCwdjnIxw
|
||||
-----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');
|
||||
|
|
Загрузка…
Ссылка в новой задаче