Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

spdy

Package Overview
Dependencies
Maintainers
1
Versions
206
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

spdy - npm Package Compare versions

Comparing version 0.1.4 to 1.0.0

.npmignore

60

lib/spdy.js

@@ -1,55 +0,15 @@

/**
* SPDY server implementation
*/
var spdy = exports;
/**
* zlib wrapper
*/
spdy.ZLib = require('./spdy/zlib').ZLib;
spdy.createZLib = require('./spdy/zlib').createZLib;
// Exports utils
spdy.utils = require('./spdy/utils');
/**
* enums
*/
spdy.enums = require('./spdy/enums').enums;
// Export parser&framer
spdy.parser = require('./spdy/parser');
spdy.framer = require('./spdy/framer');
/**
* protocol
*/
spdy.createControlFrame = require('./spdy/protocol').createControlFrame;
spdy.createRstFrame = require('./spdy/protocol').createRstFrame;
spdy.createSettingsFrame = require('./spdy/protocol').createSettingsFrame;
spdy.createDataFrame = require('./spdy/protocol').createDataFrame;
// Export ServerResponse
spdy.response = require('./spdy/response');
/**
* parser
*/
spdy.createParser = require('./spdy/parser').createParser;
spdy.Parser = require('./spdy/parser').Parser;
/**
* request
*/
spdy.Request = require('./spdy/request').Request;
spdy.createRequest = require('./spdy/request').createRequest;
/**
* push stream
*/
spdy.PushStream = require('./spdy/push_stream').PushStream;
spdy.createPushStream = require('./spdy/push_stream').createPushStream;
/**
* response
*/
spdy.Response = require('./spdy/response').Response;
spdy.createResponse = require('./spdy/response').createResponse;
/**
* core
*/
spdy.createServer = require('./spdy/core').createServer;
spdy.Server = require('./spdy/core').Server;
// Export server
spdy.server = require('./spdy/server');
spdy.createServer = spdy.server.create;

@@ -1,185 +0,152 @@

/**
* Protocol Parser
*/
var parser = exports;
var Buffer = require('buffer').Buffer,
Stream = require('stream').Stream,
util = require('util');
var spdy = require('../spdy'),
util = require('util'),
stream = require('stream'),
Buffer = require('buffer').Buffer;
var enums = require('../spdy').enums;
//
// ### function Parser (connection)
// #### @connection {Connection} SPDY connection
// SPDY protocol frames parser's @constructor
//
function Parser(connection) {
stream.Stream.call(this);
/**
* Compatibility with older versions of node
*/
if (!Buffer.prototype.readUInt32BE) {
Buffer.prototype.readUInt32BE = function(offset, noAssert) {
return this.readUInt32(offset, 'big');
};
Buffer.prototype.readUInt16BE = function(offset, noAssert) {
return this.readUInt16(offset, 'big');
};
}
this.paused = false;
this.buffer = [];
this.buffered = 0;
this.waiting = 8;
/**
* Class @constructor
*/
var Parser = exports.Parser = function(zlib) {
Stream.call(this);
this.state = { type: 'frame-head' };
this.connection = connection;
this.writable = this.readable = true;
this.readable = this.writable = true;
}
util.inherits(Parser, stream.Stream);
this.zlib = zlib;
this.buffers = [];
//
// ### function create (connection)
// #### @connection {Connection} SPDY connection
// @constructor wrapper
//
parser.create = function create(connection) {
return new Parser(connection);
};
util.inherits(Parser, Stream);
exports.createParser = function(zlib) {
return new Parser(zlib);
};
/**
* Bufferize written data
*/
Parser.prototype.write = function(chunk) {
this.buffers.push(chunk);
this.parse();
};
/**
* Concatenates first N buffers to get chunk of `len` size
*/
Parser.prototype.concat = function(len) {
var buffers = this.buffers,
total = buffers.length,
newSize = 0;
for (var i = 0; i < total && newSize < len; i++) {
newSize += buffers[i].length;
//
// ### function write (data)
// #### @data {Buffer} chunk of data
// Writes or buffers data to parser
//
Parser.prototype.write = function write(data) {
if (data !== undefined) {
// Buffer data
this.buffer.push(data);
this.buffered += data.length;
}
if (newSize < len) return new Buffer(0);
// Notify caller about state (for piping)
if (this.paused) return false;
if (i < total) i++;
// We shall not do anything until we get all expected data
if (this.buffered < this.waiting) return;
// In case that we already have a chunk of needed size
// Just return it
if (i == 1) return buffers[0];
var self = this,
buffer = new Buffer(this.waiting),
sliced = 0,
offset = 0;
var result = new Buffer(newSize);
for (var j = 0, offset = 0; offset < newSize && j < i; j++) {
buffers[j].copy(result, offset);
offset += buffers[j].length;
}
while (this.waiting > offset && this.buffered >= this.waiting &&
sliced < this.buffer.length) {
var chunk = this.buffer[sliced++],
overmatched = false;
buffers = this.buffers = buffers.slice(i - 1);
buffers[0] = result;
// Copy chunk into `buffer`
if (chunk.length > this.waiting - offset) {
chunk.copy(buffer, offset, 0, this.waiting - offset);
return result;
};
this.buffer[--sliced] = chunk.slice(this.waiting - offset);
this.buffered += this.buffer[sliced].length;
overmatched = true;
} else {
chunk.copy(buffer, offset);
}
/**
* Parse buffered data
*/
Parser.prototype.parse = function() {
var buffer = this.concat(8);
// Move offset and decrease amount of buffered data
offset += chunk.length;
this.buffered -= chunk.length;
// Headers are at least 8 bytes
if (buffer.length < 8) return;
if (overmatched) break;
}
var len = buffer.readUInt32BE(4) & 0xffffff;
// Remove used buffers
this.buffer = this.buffer.slice(sliced);
buffer = this.concat(8 + len);
// Executed parser for buffered data
this.paused = true;
this.execute(this.connection, this.state, buffer, function (err, waiting) {
// And unpause once execution finished
self.paused = false;
self.emit('drain');
// Buffered data less than packet
if (buffer.length < (8 + len)) return;
// Propagate errors
if (err) return self.emit('error', err);
var headers = {
c: ((buffer[0] & 128) >> 7) === 1,
length: len
};
// Set new `waiting`
self.waiting = waiting;
if (headers.c) {
headers.version = buffer.readUInt16BE(0) & 0x7fff;
headers.type = buffer.readUInt16BE(2);
} else {
headers.streamID = buffer.readUInt32BE(0);
}
if (self.waiting <= self.buffered) self.write();
});
};
headers.flags = buffer[4];
//
// ### function end ()
// Stream's end() implementation
//
Parser.prototype.end = function end() {
this.emit('end');
};
var data = buffer.slice(8, 8 + headers.length);
//
// ### function execute (connection, state, data, callback)
// #### @connection {Connection} SPDY connection
// #### @state {Object} Parser's state
// #### @data {Buffer} Incoming data
// #### @callback {Function} continuation callback
// Parse buffered data
//
Parser.prototype.execute = function execute(connection, state, data, callback) {
if (state.type === 'frame-head') {
var header = state.header = {
control: (data.readUInt8(0) & 0x80) === 0x80 ? true : false,
version: null,
type: null,
id: null,
flags: data.readUInt8(4),
length: data.readUInt32BE(4) & 0x00ffffff
};
this.buffers[0] = buffer.slice(8 + headers.length);
if (!this.buffers[0].length) {
this.buffers.shift();
}
if (headers.c) {
if (headers.type === enums.SYN_STREAM) {
var parsed = {
streamID: data.readUInt32BE(0) & 0x7fffffff,
assocStreamID: data.readUInt32BE(4) & 0x7fffffff,
priority: (data[8] && 192) >> 6,
nameValues: {}
};
if (header.control) {
header.version = data.readUInt16BE(0) & 0x7fff;
header.type = data.readUInt16BE(2);
} else {
header.id = data.readUInt32BE(0) & 0x7fffffff;
}
if (headers.type === enums.SYN_REPLY) {
var parsed = {
streamID: data.readUInt32BE(0) & 0x7fffffff,
nameValues: {}
};
}
if (headers.type === enums.RST_STREAM) {
var parsed = {
streamID: data.readUInt32BE(0) & 0x7fffffff,
statusCode: data.readUInt32BE(4)
};
data = parsed;
}
if (headers.type === enums.SYN_STREAM ||
headers.type === enums.SYN_REPLY) {
try {
var offset = headers.type === enums.SYN_STREAM ? 10 : 6,
nvs = this.zlib.inflate(data.slice(offset)),
nvsCount = (nvs[0] << 8) + nvs[1];
state.type = 'frame-body';
callback(null, header.length);
} else if (state.type === 'frame-body') {
var self = this;
nvs = nvs.slice(2);
while (nvsCount > 0) {
var nameLen = (nvs[0] << 8) + nvs[1],
name = nvs.slice(2, 2 + nameLen);
nvs = nvs.slice(2 + nameLen);
spdy.framer.execute(connection, state.header, data, function(err, frame) {
if (err) return callback(err);
var valueLen = nvs.readUInt16BE(0),
value = nvs.slice(2, 2 + valueLen);
nvs = nvs.slice(2 + valueLen);
self.emit('frame', frame);
parsed.nameValues[name.toString()] = value.toString();
nvsCount --;
}
data = parsed;
} catch(e) {
this.emit('error', parsed.streamID);
return;
}
}
state.type = 'frame-head';
callback(null, 8);
});
}
this.emit(headers.c ? 'cframe' : 'dframe', {
headers: headers,
data: data
});
// Probably we have more data buffered - so continue
process.nextTick(this.parse.bind(this));
};
/**
* End of stream
*/
Parser.prototype.end = function() {};
Parser.prototype.destroy = function() {};

@@ -1,245 +0,49 @@

/**
* Response class
*/
var spdy = require('../spdy'),
http = require('http');
var Buffer = require('buffer').Buffer,
util = require('util'),
stream = require('stream'),
fs = require('fs'),
enums = require('../spdy').enums,
createControlFrame = require('../spdy').createControlFrame,
createDataFrame = require('../spdy').createDataFrame,
createPushStream = require('../spdy').createPushStream,
createParser = require('../spdy').createParser,
createZLib = require('../spdy').createZLib;
//
// ### function writeHead (statusCode)
// #### @statusCode {Number} HTTP Status code
// .writeHead() wrapper
// (Sorry, copy pasted from lib/http.js)
//
exports.writeHead = function(statusCode) {
if (this._headerSent) return;
this._headerSent = true;
/**
* Class constructor
*/
var Response = exports.Response = function(cframe, c) {
stream.Stream.call(this);
this.cframe = cframe;
this.streamID = cframe.data.streamID;
this.c = c;
var reasonPhrase, headers, headerIndex;
this.statusCode = 200;
this._headers = {
'Connection': 'keep-alive'
};
this._written = false;
this._reasonPhrase = 'OK';
this._push = function() {};
// For stream.pipe and others
this.writable = true;
};
util.inherits(Response, stream.Stream);
exports.createResponse = function(cframe, c) {
return new Response(cframe, c);
};
/**
* Respond w/ SYN_REPLY
*/
Response.prototype.writeHead = function(code, reasonPhrase, headers) {
if (headers === undefined) {
headers = reasonPhrase;
reasonPhrase = '';
if (typeof arguments[1] == 'string') {
reasonPhrase = arguments[1];
headerIndex = 2;
} else {
reasonPhrase = http.STATUS_CODES[statusCode] || 'unknown';
headerIndex = 1;
}
this.statusCode = statusCode;
headers = headers || {};
for (var i in headers) {
this._headers[i] = headers[i];
}
this._reasonPhrase || (this.reasonPhrase = reasonPhrase);
this.statusCode = code;
};
var obj = arguments[headerIndex];
/**
* Flush buffered head
*/
Response.prototype._flushHead = function() {
if (this._written) {
throw Error('Headers was already written');
}
this._written = true;
if (obj && this._headers) {
// Slow-case: when progressive API and header fields are passed.
headers = this._renderHeaders();
var headers = this._headers;
headers.status = this.statusCode + ' ' + this._reasonPhrase;
headers.version = 'HTTP/1.1';
var cframe = createControlFrame(this.c.zlib, {
type: enums.SYN_REPLY,
streamID: this.streamID
}, headers);
return this.c.write(cframe);
};
Response.prototype.pushLater = function(resources) {
var that = this;
this.deferred_streams = [];
// Send headers for each post-response server push stream, but DO
// NOT sent data yet
resources.forEach(function(push_contents) {
var filename = push_contents[0]
, url = push_contents[1]
, data = fs.readFileSync(filename)
, push_stream = createPushStream(that.cframe, that.c, url);
push_stream._flushHead();
push_stream._written = true;
that.deferred_streams.push([push_stream, data]);
});
};
Response.prototype._pushLaterData = function(resources) {
if (typeof(this.deferred_streams) == 'undefined') return;
this.deferred_streams.forEach(function(stream_and_data) {
var stream = stream_and_data[0]
, data = stream_and_data[1];
stream.write(data);
stream.end();
});
};
/**
* Write any data (Internal)
*/
Response.prototype._write = function(data, encoding, fin) {
if (!this._written) {
this._flushHead();
this._push_stream();
// handle object case
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
if (k) headers[k] = obj[k];
}
} else if (this._headers) {
// only progressive api is used
headers = this._renderHeaders();
} else {
// only writeHead() called
headers = obj;
}
encoding = encoding || 'utf8';
if (data === undefined) {
data = new Buffer(0);
}
// cleanup
this._header = '';
// Write the data frame
var dframe = createDataFrame(this.getStreamCompressor(), {
streamID: this.streamID,
flags: 0
}, Buffer.isBuffer(data) ? data : new Buffer(data, encoding));
this.c.write(dframe);
// Write the data FIN if this if fin
if (fin) {
var dfin = createDataFrame(this.getStreamCompressor(), {
streamID: this.streamID,
flags: enums.DATA_FLAG_FIN
}, new Buffer(0));
this.c.write(dfin);
}
// Push any deferred data streams
this._pushLaterData();
spdy.framer.sendSynReply(this.socket, statusCode, reasonPhrase, headers);
};
Response.prototype.getStreamCompressor = function(streamID) {
if (this.stream_compressor)
return this.stream_compressor;
this.stream_compressor = createZLib({use_dictionary: false});
return this.stream_compressor;
};
/**
* Write data
*/
Response.prototype.write = function(data, encoding) {
return this._write(data, encoding, false);
};
/**
* End stream
*/
Response.prototype.end = function(data, encoding) {
this.writable = false;
return this._write(data, encoding, true);
};
/**
* Cloning node.js default API
*/
Response.prototype.setHeader = function(name, value) {
if (arguments.length < 2) {
throw new Error('`name` and `value` are required for setHeader().');
}
if (this._written) {
throw new Error('Can\'t set headers after they are sent.');
}
this._headers[name] = Array.isArray(value) ? value.join(';') : value;
};
/**
* Cloning node.js default API
*/
Response.prototype.getHeader = function(name) {
if (arguments.length < 1) {
throw new Error('`name` is required for getHeader().');
}
if (this._written) {
throw new Error('Can\'t use mutable header APIs after sent.');
}
return this._headers[name];
};
/**
* Cloning node.js default API
*/
Response.prototype.removeHeader = function(name) {
if (arguments.length < 1) {
throw new Error('`name` is required for getHeader().');
}
if (this._written) {
throw new Error('Can\'t remove headers after they are sent.');
}
delete this._headers[name];
};
/**
* Server push
*/
Response.prototype.setPush = function(fn) {
if (typeof(fn) === 'function')
this._push = fn;
};
Response.prototype._push_stream = function() {
return this._push(this);
};
Response.prototype.push_file = function(filename, url) {
console.log('[warn] Response#push_file has been deprecate. Please switch to pushFile instead.');
return this.pushFile(filename, url);
};
Response.prototype.pushFile = function(filename, url) {
this.push(fs.readFileSync(filename), url);
};
Response.prototype.push = function(data, url) {
var push_stream = createPushStream(this.cframe, this.c, url);
push_stream.write(data);
push_stream.end();
};
{
"name": "spdy",
"description": "Implementation of the SPDY protocol on node.js.",
"version": "0.1.4",
"version": "1.0.0",
"author": "Fedor Indutny <fedor.indutny@gmail.com>",
"dependencies": {
"zlibcontext": "~ 1.0.9"
},
"contributors": [
"Chris Storm <github@eeecooks.com>",
"François de Metz <francois@2metz.fr>"
],
"dependencies": {},
"engines": [
"node >= 0.6.0"
"node ~ 0.7.0"
],

@@ -12,0 +14,0 @@ "main": "./lib/spdy",

@@ -1,42 +0,49 @@

# SPDY Server on node.js (BETA)
# SPDY Server for node.js
Required node.js version - at least 0.5.0-pre.
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).
Because of libuv integration in node.js core latest version of one is not usable, try this checking out at this commit instead: https://github.com/joyent/node/commit/9812e31
It's using SSL's NPN feature that is available in node from 0.6.0 version, but
requires you to build node with latest openssl.
With that module you can create true [SPDY](http://www.chromium.org/spdy) servers with natural http module interface and fallback to HTTPS (for browsers that doesn't support SPDY).
## Node+OpenSSL building
It's using SSL's NPN feature that will be available in node.js from 0.5.0-pre version, but you'll need to compile it with latest available version of OpenSSL.
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:
Instruction for setting up development environment can be found in @eee-c article here: http://japhr.blogspot.com/2011/06/setting-up-node-spdy.html
```bash
git clone git://github.com/joyent/node.git
cd node
./configure --prefix=$HOME/.node/dev # <- or any other dir
## Alternative instructions
make install -j4 # in -jN, N is number of CPU cores on your machine
1. grab http://cvs.openssl.org
2. build it
3. build node.js with that version of openssl
# Add node's bin to PATH env variable
echo 'export PATH=$HOME/.node/dev/bin:$PATH' >> ~/.bashrc
./configure --openssl-includes=/path/to/openssl/include \
--openssl-libpath=/path/to/openssl
make install
#
# You have working node 0.7.x + NPN now !!!
#
```
4. have fun with SPDY and node.js!
## Usage
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'),
NPNProtocols: ['spdy/2']
};
```javascript
var spdy = require('spdy');
spdy.createServer(options, function(req, res) {
res.writeHead(200);
res.end('hello world!');
});
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')
};
As you can see it provides well known req/res interface for handling requests
and responding to them.
spdy.createServer(options, function(req, res) {
res.writeHead(200);
res.end('hello world!');
});
spdy.listen(443);
```
## Helping project

@@ -46,4 +53,10 @@

## LICENSE
#### Contributors
* [Fedor Indutny](https://github.com/indutny)
* [Chris Storm](https://github.com/eee-c)
* [François de Metz](https://github.com/francois2metz)
#### LICENSE
This software is licensed under the MIT License.

@@ -50,0 +63,0 @@

var fs = require('fs'),
http = require('http'),
spdy = require('../lib/spdy'),
tls = require('tls'),
buffer = require('buffer').Buffer,
NPNProtocols = new Buffer(7);
spdy = require('../lib/spdy');
if (!tls.NPN_ENABLED) throw 'You\'re using not NPN-enabled version of node.js';
// Don't crash on errors

@@ -20,3 +14,2 @@ process.on('uncaughtException', function (err) {

ca: fs.readFileSync(__dirname + '/../keys/spdy-csr.pem'),
NPNProtocols: ['spdy/2']
};

@@ -26,4 +19,2 @@

var bigBuffer = new Buffer(JSON.stringify({ok: true}));
var server = spdy.createServer(options, function(req, res) {

@@ -38,2 +29,3 @@ if (req.method == 'POST') {

}
static(req, res, function() {

@@ -40,0 +32,0 @@ res.writeHead(404);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc