http2
Advanced tools
Comparing version 3.0.0 to 3.0.1
@@ -5,2 +5,3 @@ var fs = require('fs'); | ||
// Setting the global logger (optional) | ||
http2.globalAgent = new http2.Agent({ | ||
@@ -10,10 +11,8 @@ log: require('../test/util').createLogger('client') | ||
// We use self signed certs in the example code so we ignore cert errors | ||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; | ||
// Sending the request | ||
// It would be `var request = http2.get(process.argv.pop());` if we wouldn't care about plain mode | ||
var options = require('url').parse(process.argv.pop()); | ||
options.plain = Boolean(process.env.HTTP2_PLAIN); | ||
var request = http2.request(options); | ||
request.end(); | ||
var url = process.argv.pop(); | ||
var request = process.env.HTTP2_PLAIN ? http2.raw.get(url) : http2.get(url); | ||
@@ -20,0 +19,0 @@ // Receiving the response |
@@ -5,12 +5,2 @@ var fs = require('fs'); | ||
var options = process.env.HTTP2_PLAIN ? { | ||
plain: true | ||
} : { | ||
key: fs.readFileSync(path.join(__dirname, '/localhost.key')), | ||
cert: fs.readFileSync(path.join(__dirname, '/localhost.crt')) | ||
}; | ||
// Passing bunyan logger (optional) | ||
options.log = require('../test/util').createLogger('server'); | ||
// We cache one file to be able to do simple performance tests without waiting for the disk | ||
@@ -20,4 +10,4 @@ var cachedFile = fs.readFileSync(path.join(__dirname, './server.js')); | ||
// Creating the server | ||
var server = http2.createServer(options, function(request, response) { | ||
// The callback to handle requests | ||
function onRequest(request, response) { | ||
var filename = path.join(__dirname, request.url); | ||
@@ -49,4 +39,20 @@ | ||
} | ||
}); | ||
} | ||
// Creating a bunyan logger (optional) | ||
var log = require('../test/util').createLogger('server'); | ||
// Creating the server in plain or TLS mode (TLS mode is the default) | ||
var server; | ||
if (process.env.HTTP2_PLAIN) { | ||
server = http2.raw.createServer({ | ||
log: log | ||
}, onRequest); | ||
} else { | ||
server = http2.createServer({ | ||
log: log, | ||
key: fs.readFileSync(path.join(__dirname, '/localhost.key')), | ||
cert: fs.readFileSync(path.join(__dirname, '/localhost.crt')) | ||
}, onRequest); | ||
} | ||
server.listen(process.env.HTTP2_PORT || 8080); |
Version history | ||
=============== | ||
### 3.0.0 (2014-08-XX) ### | ||
### 3.0.1 (2014-11-20) ### | ||
* Bugfix release. | ||
* Fixed #81 and #87 | ||
* Fixed a bug in flow control (without GitHub issue) | ||
### 3.0.0 (2014-08-25) ### | ||
* Re-join node-http2 and node-http2-protocol into one repository | ||
@@ -7,0 +13,0 @@ * API Changes |
@@ -756,3 +756,4 @@ // Public API | ||
} | ||
if ((options.protocol && options.protocol !== "http:") || !options.plain) { | ||
options.plain = true; | ||
if (options.protocol && options.protocol !== "http:") { | ||
throw new Error('This interface only supports http-schemed URLs'); | ||
@@ -767,3 +768,4 @@ } | ||
} | ||
if ((options.protocol && options.protocol !== "https:") || options.plain) { | ||
options.plain = false; | ||
if (options.protocol && options.protocol !== "https:") { | ||
throw new Error('This interface only supports https-schemed URLs'); | ||
@@ -778,3 +780,4 @@ } | ||
} | ||
if ((options.protocol && options.protocol !== "http:") || !options.plain) { | ||
options.plain = true; | ||
if (options.protocol && options.protocol !== "http:") { | ||
throw new Error('This interface only supports http-schemed URLs'); | ||
@@ -789,3 +792,4 @@ } | ||
} | ||
if ((options.protocol && options.protocol !== "https:") || options.plain) { | ||
options.plain = false; | ||
if (options.protocol && options.protocol !== "https:") { | ||
throw new Error('This interface only supports https-schemed URLs'); | ||
@@ -870,3 +874,3 @@ } | ||
// * HTTP/2 over TLS negotiated using NPN or ALPN | ||
// * HTTP/2 over TLS negotiated using NPN or ALPN, or fallback to HTTPS1 | ||
else { | ||
@@ -884,3 +888,3 @@ var started = false; | ||
if (negotiatedProtocol != null) { // null in >=0.11.0, undefined in <0.11.0 | ||
negotiated() | ||
negotiated(); | ||
} else { | ||
@@ -903,7 +907,8 @@ socket.on('secureConnect', negotiated); | ||
if (started) { | ||
// ** In the meantime, an other connection was made to the same host... | ||
if (endpoint) { | ||
// *** and it turned out to be HTTP2 and the request was multiplexed on that one, so we should close this one | ||
endpoint.close(); | ||
} else { | ||
httpsRequest.abort(); | ||
} | ||
// *** otherwise, the fallback to HTTPS1 is already done. | ||
} else { | ||
@@ -910,0 +915,0 @@ if (endpoint) { |
@@ -1126,6 +1126,6 @@ // The implementation of the [HTTP/2 Header Compression][http2-compression] spec is separated from | ||
if (!(value instanceof Array)) { | ||
value = [value] | ||
value = [value]; | ||
} | ||
value = Array.prototype.concat.apply([], value.map(function(cookie) { | ||
return String(cookie).split(';').map(trim) | ||
return String(cookie).split(';').map(trim); | ||
})); | ||
@@ -1260,3 +1260,3 @@ } | ||
if (('cookie' in headers) && (headers['cookie'] instanceof Array)) { | ||
headers['cookie'] = headers['cookie'].join('; ') | ||
headers['cookie'] = headers['cookie'].join('; '); | ||
} | ||
@@ -1345,3 +1345,3 @@ | ||
function trim(string) { | ||
return string.trim() | ||
return string.trim(); | ||
} |
@@ -160,3 +160,3 @@ var assert = require('assert'); | ||
// | ||
// 1. var stream = new Stream(this._log); | ||
// 1. var stream = new Stream(this._log, this); | ||
// 2. this._allocateId(stream, id); | ||
@@ -234,3 +234,3 @@ // 2. this._allocatePriority(stream); | ||
var stream = new Stream(this._log); | ||
var stream = new Stream(this._log, this); | ||
this._allocateId(stream, id); | ||
@@ -248,3 +248,3 @@ this._allocatePriority(stream); | ||
// * Receiving is enabled immediately, and an ID gets assigned to the stream | ||
var stream = new Stream(this._log); | ||
var stream = new Stream(this._log, this); | ||
this._allocatePriority(stream); | ||
@@ -251,0 +251,0 @@ |
@@ -84,3 +84,5 @@ var assert = require('assert'); | ||
Flow.prototype._write = function _write(frame, encoding, callback) { | ||
if (frame.flags.END_STREAM || (frame.type === 'RST_STREAM')) { | ||
var sentToUs = (this._flowControlId === undefined) || (frame.stream === this._flowControlId); | ||
if (sentToUs && (frame.flags.END_STREAM || (frame.type === 'RST_STREAM'))) { | ||
this._ended = true; | ||
@@ -103,4 +105,3 @@ } | ||
if ((frame.type === 'WINDOW_UPDATE') && | ||
((this._flowControlId === undefined) || (frame.stream === this._flowControlId))) { | ||
if (sentToUs && (frame.type === 'WINDOW_UPDATE')) { | ||
this._updateWindow(frame); | ||
@@ -209,12 +210,21 @@ } | ||
if (frame && (frame.type === 'DATA') && limit && (frame.data.length > limit)) { | ||
this._log.trace({ frame: frame, size: frame.data.length, forwardable: limit }, | ||
'Splitting out forwardable part of a DATA frame.'); | ||
this.unshift({ | ||
type: 'DATA', | ||
flags: {}, | ||
stream: frame.stream, | ||
data: frame.data.slice(0, limit) | ||
}); | ||
frame.data = frame.data.slice(limit); | ||
if (frame && (frame.type === 'DATA')) { | ||
// * If the frame is DATA, then there's two special cases: | ||
// * if the limit is 0, we shouldn't return anything | ||
// * if the size of the frame is larger than limit, then the frame should be split | ||
if (limit === 0) { | ||
return Duplex.prototype.read.call(this, 0); | ||
} | ||
else if (frame.data.length > limit) { | ||
this._log.trace({ frame: frame, size: frame.data.length, forwardable: limit }, | ||
'Splitting out forwardable part of a DATA frame.'); | ||
this.unshift({ | ||
type: 'DATA', | ||
flags: {}, | ||
stream: frame.stream, | ||
data: frame.data.slice(0, limit) | ||
}); | ||
frame.data = frame.data.slice(limit); | ||
} | ||
} | ||
@@ -221,0 +231,0 @@ |
@@ -913,3 +913,4 @@ // The framer consists of two [Transform Stream][1] subclasses that operate in [object mode][2]: | ||
'ENHANCE_YOUR_CALM', | ||
'INADEQUATE_SECURITY' | ||
'INADEQUATE_SECURITY', | ||
'HTTP_1_1_REQUIRED' | ||
]; | ||
@@ -916,0 +917,0 @@ |
@@ -19,3 +19,3 @@ var assert = require('assert'); | ||
// * **new Stream(log)**: create a new Stream | ||
// * **new Stream(log, connection)**: create a new Stream | ||
// | ||
@@ -50,3 +50,3 @@ // * **Event: 'headers' (headers)**: signals incoming headers | ||
// The main aspects of managing the stream are: | ||
function Stream(log) { | ||
function Stream(log, connection) { | ||
Duplex.call(this); | ||
@@ -65,2 +65,4 @@ | ||
this._initializeState(); | ||
this.connection = connection; | ||
} | ||
@@ -85,3 +87,3 @@ | ||
Stream.prototype.promise = function promise(headers) { | ||
var stream = new Stream(this._log); | ||
var stream = new Stream(this._log, this.connection); | ||
stream._priority = Math.min(this._priority + 1, MAX_PRIORITY); | ||
@@ -640,3 +642,3 @@ this._pushUpstream({ | ||
this.reset(streamError); | ||
this.emit('error', streamError) | ||
this.emit('error', streamError); | ||
} | ||
@@ -643,0 +645,0 @@ } |
{ | ||
"name": "http2", | ||
"version": "3.0.0", | ||
"version": "3.0.1", | ||
"description": "An HTTP/2 client and server implementation", | ||
@@ -17,3 +17,3 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"test": "istanbul test _mocha -- --reporter spec --slow 200", | ||
"test": "istanbul test _mocha -- --reporter spec --slow 500 --timeout 15000", | ||
"doc": "docco lib/* --output doc --layout parallel --css doc/docco.css" | ||
@@ -40,3 +40,5 @@ }, | ||
"Yoshihiro Iwanaga", | ||
"vsemogutor" | ||
"Igor Novikov", | ||
"James Willcox", | ||
"David Björklund" | ||
], | ||
@@ -43,0 +45,0 @@ "license": "MIT", |
@@ -119,8 +119,8 @@ node-http2 | ||
To generate a code coverage report, run `npm test --coverage` (which runs very slowly, be patient). | ||
Code coverage summary as of version 3.0.0: | ||
Code coverage summary as of version 3.0.1: | ||
``` | ||
Statements : 91.85% ( 1747/1902 ) | ||
Branches : 81.61% ( 688/843 ) | ||
Functions : 90.95% ( 211/232 ) | ||
Lines : 91.92% ( 1741/1894 ) | ||
Statements : 92.09% ( 1759/1910 ) | ||
Branches : 82.56% ( 696/843 ) | ||
Functions : 91.38% ( 212/232 ) | ||
Lines : 92.17% ( 1753/1902 ) | ||
``` | ||
@@ -155,8 +155,12 @@ | ||
The co-maintainer of the project is [Nick Hurley](https://github.com/todesschaf). | ||
Code contributions are always welcome! People who contributed to node-http2 so far: | ||
* Nick Hurley | ||
* Mike Belshe | ||
* Yoshihiro Iwanaga | ||
* vsemogutor | ||
* [Nick Hurley](https://github.com/todesschaf) | ||
* [Mike Belshe](https://github.com/mbelshe) | ||
* [Yoshihiro Iwanaga](https://github.com/iwanaga) | ||
* [Igor Novikov](https://github.com/vsemogutor) | ||
* [James Willcox](https://github.com/snorp) | ||
* [David Björklund](https://github.com/kesla) | ||
@@ -163,0 +167,0 @@ Special thanks to Google for financing the development of this module as part of their [Summer of |
@@ -409,3 +409,3 @@ var expect = require('chai').expect; | ||
}); | ||
}) | ||
}); | ||
describe('method decode(buffer)', function() { | ||
@@ -416,3 +416,3 @@ it('should return the Huffman decoded version of the input buffer', function() { | ||
var encoded = test_huffman_request[decoded]; | ||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded) | ||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded); | ||
} | ||
@@ -422,6 +422,6 @@ table = HuffmanTable.huffmanTable; | ||
encoded = test_huffman_response[decoded]; | ||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded) | ||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded); | ||
} | ||
}); | ||
}) | ||
}); | ||
}); | ||
@@ -575,5 +575,5 @@ | ||
} | ||
}) | ||
}) | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -134,3 +134,3 @@ var expect = require('chai').expect; | ||
done(); | ||
}) | ||
}); | ||
}); | ||
@@ -137,0 +137,0 @@ }); |
@@ -257,5 +257,5 @@ var expect = require('chai').expect; | ||
flow1.pipe(flow2).pipe(flow1); | ||
}) | ||
}); | ||
}); | ||
}); | ||
}); |
117
test/http.js
@@ -127,3 +127,3 @@ var expect = require('chai').expect; | ||
response.writeHead(200); | ||
response.writeHead(404) | ||
response.writeHead(404); | ||
}); | ||
@@ -153,2 +153,62 @@ }); | ||
}); | ||
describe('2 simple request in parallel', function() { | ||
it('should work as expected', function(originalDone) { | ||
var path = '/x'; | ||
var message = 'Hello world'; | ||
done = util.callNTimes(2, function() { | ||
server.close(); | ||
originalDone(); | ||
}); | ||
var server = http2.createServer(options, function(request, response) { | ||
expect(request.url).to.equal(path); | ||
response.end(message); | ||
}); | ||
server.listen(1234, function() { | ||
http2.get('https://localhost:1234' + path, function(response) { | ||
response.on('data', function(data) { | ||
expect(data.toString()).to.equal(message); | ||
done(); | ||
}); | ||
}); | ||
http2.get('https://localhost:1234' + path, function(response) { | ||
response.on('data', function(data) { | ||
expect(data.toString()).to.equal(message); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('100 simple request in a series', function() { | ||
it('should work as expected', function(done) { | ||
var path = '/x'; | ||
var message = 'Hello world'; | ||
var server = http2.createServer(options, function(request, response) { | ||
expect(request.url).to.equal(path); | ||
response.end(message); | ||
}); | ||
var n = 100; | ||
server.listen(1242, function() { | ||
doRequest(); | ||
function doRequest() { | ||
http2.get('https://localhost:1242' + path, function(response) { | ||
response.on('data', function(data) { | ||
expect(data.toString()).to.equal(message); | ||
if (n) { | ||
n -= 1; | ||
doRequest(); | ||
} else { | ||
server.close(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe('request with payload', function() { | ||
@@ -245,3 +305,2 @@ it('should work as expected', function(done) { | ||
var server = http2.raw.createServer({ | ||
plain: true, | ||
log: util.serverLog | ||
@@ -270,2 +329,26 @@ }, function(request, response) { | ||
}); | ||
describe('get over plain TCP', function() { | ||
it('should work as expected', function(done) { | ||
var path = '/x'; | ||
var message = 'Hello world'; | ||
var server = http2.raw.createServer({ | ||
log: util.serverLog | ||
}, function(request, response) { | ||
expect(request.url).to.equal(path); | ||
response.end(message); | ||
}); | ||
server.listen(1237, function() { | ||
var request = http2.raw.get('http://localhost:1237/x', function(response) { | ||
response.on('data', function(data) { | ||
expect(data.toString()).to.equal(message); | ||
server.close(); | ||
done(); | ||
}); | ||
}); | ||
request.end(); | ||
}); | ||
}); | ||
}); | ||
describe('request to an HTTPS/1 server', function() { | ||
@@ -291,2 +374,32 @@ it('should fall back to HTTPS/1 successfully', function(done) { | ||
}); | ||
describe('2 parallel request to an HTTPS/1 server', function() { | ||
it('should fall back to HTTPS/1 successfully', function(originalDone) { | ||
var path = '/x'; | ||
var message = 'Hello world'; | ||
done = util.callNTimes(2, function() { | ||
server.close(); | ||
originalDone(); | ||
}); | ||
var server = https.createServer(options, function(request, response) { | ||
expect(request.url).to.equal(path); | ||
response.end(message); | ||
}); | ||
server.listen(6789, function() { | ||
http2.get('https://localhost:6789' + path, function(response) { | ||
response.on('data', function(data) { | ||
expect(data.toString()).to.equal(message); | ||
done(); | ||
}); | ||
}); | ||
http2.get('https://localhost:6789' + path, function(response) { | ||
response.on('data', function(data) { | ||
expect(data.toString()).to.equal(message); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('HTTPS/1 request to a HTTP/2 server', function() { | ||
@@ -293,0 +406,0 @@ it('should fall back to HTTPS/1 successfully', function(done) { |
@@ -8,3 +8,3 @@ var expect = require('chai').expect; | ||
function createStream() { | ||
var stream = new Stream(util.log); | ||
var stream = new Stream(util.log, null); | ||
stream.upstream._window = Infinity; | ||
@@ -110,3 +110,3 @@ return stream; | ||
{ type: 'DATA', flags: {}, data: new Buffer(5) }, | ||
{ type: 'PUSH_PROMISE', flags: {}, headers: {}, promised_stream: new Stream(util.log) } | ||
{ type: 'PUSH_PROMISE', flags: {}, headers: {}, promised_stream: new Stream(util.log, null) } | ||
]; | ||
@@ -178,3 +178,3 @@ | ||
{ type: 'DATA', flags: {}, data: new Buffer(5) }, | ||
{ type: 'PUSH_PROMISE', flags: {}, headers: {}, promised_stream: new Stream(util.log) } | ||
{ type: 'PUSH_PROMISE', flags: {}, headers: {}, promised_stream: new Stream(util.log, null) } | ||
] | ||
@@ -194,3 +194,3 @@ }; | ||
stream._transition(false, invalid_frame); | ||
expect(connectionErrorHappened) | ||
expect(connectionErrorHappened); | ||
}); | ||
@@ -197,0 +197,0 @@ }); |
@@ -89,2 +89,2 @@ var path = require('path'); | ||
return output; | ||
} | ||
}; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
305039
7143
176
5