Updated the files.
This commit is contained in:
parent
1553e6b971
commit
753967d4f5
23418 changed files with 3784666 additions and 0 deletions
14
my-app/node_modules/spdy-transport/.travis.yml
generated
vendored
Executable file
14
my-app/node_modules/spdy-transport/.travis.yml
generated
vendored
Executable file
|
@ -0,0 +1,14 @@
|
|||
sudo: false
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "6"
|
||||
- "8"
|
||||
- "10"
|
||||
- "stable"
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
- npm run coverage
|
76
my-app/node_modules/spdy-transport/README.md
generated
vendored
Executable file
76
my-app/node_modules/spdy-transport/README.md
generated
vendored
Executable file
|
@ -0,0 +1,76 @@
|
|||
# spdy-transport
|
||||
|
||||
[](http://travis-ci.org/spdy-http2/spdy-transport)
|
||||
[](http://badge.fury.io/js/spdy-transport)
|
||||
[](https://david-dm.org/spdy-http2/spdy-transport)
|
||||
[](http://standardjs.com/)
|
||||
[](https://waffle.io/spdy-http2/node-spdy)
|
||||
|
||||
> SPDY/HTTP2 generic transport implementation.
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
var transport = require('spdy-transport');
|
||||
|
||||
// NOTE: socket is some stream or net.Socket instance, may be an argument
|
||||
// of `net.createServer`'s connection handler.
|
||||
|
||||
var server = transport.connection.create(socket, {
|
||||
protocol: 'http2',
|
||||
isServer: true
|
||||
});
|
||||
|
||||
server.on('stream', function(stream) {
|
||||
console.log(stream.method, stream.path, stream.headers);
|
||||
stream.respond(200, {
|
||||
header: 'value'
|
||||
});
|
||||
|
||||
stream.on('readable', function() {
|
||||
var chunk = stream.read();
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
console.log(chunk);
|
||||
});
|
||||
|
||||
stream.on('end', function() {
|
||||
console.log('end');
|
||||
});
|
||||
|
||||
// And other node.js Stream APIs
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## LICENSE
|
||||
|
||||
This software is licensed under the MIT License.
|
||||
|
||||
Copyright Fedor Indutny, 2015.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
[0]: http://json.org/
|
||||
[1]: http://github.com/indutny/bud-backend
|
||||
[2]: https://github.com/nodejs/io.js
|
||||
[3]: https://github.com/libuv/libuv
|
||||
[4]: http://openssl.org/
|
25
my-app/node_modules/spdy-transport/lib/spdy-transport.js
generated
vendored
Executable file
25
my-app/node_modules/spdy-transport/lib/spdy-transport.js
generated
vendored
Executable file
|
@ -0,0 +1,25 @@
|
|||
'use strict'
|
||||
|
||||
var transport = exports
|
||||
|
||||
// Exports utils
|
||||
transport.utils = require('./spdy-transport/utils')
|
||||
|
||||
// Export parser&framer
|
||||
transport.protocol = {}
|
||||
transport.protocol.base = require('./spdy-transport/protocol/base')
|
||||
transport.protocol.spdy = require('./spdy-transport/protocol/spdy')
|
||||
transport.protocol.http2 = require('./spdy-transport/protocol/http2')
|
||||
|
||||
// Window
|
||||
transport.Window = require('./spdy-transport/window')
|
||||
|
||||
// Priority Tree
|
||||
transport.Priority = require('./spdy-transport/priority')
|
||||
|
||||
// Export Connection and Stream
|
||||
transport.Stream = require('./spdy-transport/stream').Stream
|
||||
transport.Connection = require('./spdy-transport/connection').Connection
|
||||
|
||||
// Just for `transport.connection.create()`
|
||||
transport.connection = transport.Connection
|
845
my-app/node_modules/spdy-transport/lib/spdy-transport/connection.js
generated
vendored
Executable file
845
my-app/node_modules/spdy-transport/lib/spdy-transport/connection.js
generated
vendored
Executable file
|
@ -0,0 +1,845 @@
|
|||
'use strict'
|
||||
|
||||
var util = require('util')
|
||||
var transport = require('../spdy-transport')
|
||||
|
||||
var debug = {
|
||||
server: require('debug')('spdy:connection:server'),
|
||||
client: require('debug')('spdy:connection:client')
|
||||
}
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
|
||||
var Stream = transport.Stream
|
||||
|
||||
function Connection (socket, options) {
|
||||
EventEmitter.call(this)
|
||||
|
||||
var state = {}
|
||||
this._spdyState = state
|
||||
|
||||
// NOTE: There's a big trick here. Connection is used as a `this` argument
|
||||
// to the wrapped `connection` event listener.
|
||||
// socket end doesn't necessarly mean connection drop
|
||||
this.httpAllowHalfOpen = true
|
||||
|
||||
state.timeout = new transport.utils.Timeout(this)
|
||||
|
||||
// Protocol info
|
||||
state.protocol = transport.protocol[options.protocol]
|
||||
state.version = null
|
||||
state.constants = state.protocol.constants
|
||||
state.pair = null
|
||||
state.isServer = options.isServer
|
||||
|
||||
// Root of priority tree (i.e. stream id = 0)
|
||||
state.priorityRoot = new transport.Priority({
|
||||
defaultWeight: state.constants.DEFAULT_WEIGHT,
|
||||
maxCount: transport.protocol.base.constants.MAX_PRIORITY_STREAMS
|
||||
})
|
||||
|
||||
// Defaults
|
||||
state.maxStreams = options.maxStreams ||
|
||||
state.constants.MAX_CONCURRENT_STREAMS
|
||||
|
||||
state.autoSpdy31 = options.protocol.name !== 'h2' && options.autoSpdy31
|
||||
state.acceptPush = options.acceptPush === undefined
|
||||
? !state.isServer
|
||||
: options.acceptPush
|
||||
|
||||
if (options.maxChunk === false) { state.maxChunk = Infinity } else if (options.maxChunk === undefined) { state.maxChunk = transport.protocol.base.constants.DEFAULT_MAX_CHUNK } else {
|
||||
state.maxChunk = options.maxChunk
|
||||
}
|
||||
|
||||
// Connection-level flow control
|
||||
var windowSize = options.windowSize || 1 << 20
|
||||
state.window = new transport.Window({
|
||||
id: 0,
|
||||
isServer: state.isServer,
|
||||
recv: {
|
||||
size: state.constants.DEFAULT_WINDOW,
|
||||
max: state.constants.MAX_INITIAL_WINDOW_SIZE
|
||||
},
|
||||
send: {
|
||||
size: state.constants.DEFAULT_WINDOW,
|
||||
max: state.constants.MAX_INITIAL_WINDOW_SIZE
|
||||
}
|
||||
})
|
||||
|
||||
// It starts with DEFAULT_WINDOW, update must be sent to change it on client
|
||||
state.window.recv.setMax(windowSize)
|
||||
|
||||
// Boilerplate for Stream constructor
|
||||
state.streamWindow = new transport.Window({
|
||||
id: -1,
|
||||
isServer: state.isServer,
|
||||
recv: {
|
||||
size: windowSize,
|
||||
max: state.constants.MAX_INITIAL_WINDOW_SIZE
|
||||
},
|
||||
send: {
|
||||
size: state.constants.DEFAULT_WINDOW,
|
||||
max: state.constants.MAX_INITIAL_WINDOW_SIZE
|
||||
}
|
||||
})
|
||||
|
||||
// Various state info
|
||||
state.pool = state.protocol.compressionPool.create(options.headerCompression)
|
||||
state.counters = {
|
||||
push: 0,
|
||||
stream: 0
|
||||
}
|
||||
|
||||
// Init streams list
|
||||
state.stream = {
|
||||
map: {},
|
||||
count: 0,
|
||||
nextId: state.isServer ? 2 : 1,
|
||||
lastId: {
|
||||
both: 0,
|
||||
received: 0
|
||||
}
|
||||
}
|
||||
state.ping = {
|
||||
nextId: state.isServer ? 2 : 1,
|
||||
map: {}
|
||||
}
|
||||
state.goaway = false
|
||||
|
||||
// Debug
|
||||
state.debug = state.isServer ? debug.server : debug.client
|
||||
|
||||
// X-Forwarded feature
|
||||
state.xForward = null
|
||||
|
||||
// Create parser and hole for framer
|
||||
state.parser = state.protocol.parser.create({
|
||||
// NOTE: needed to distinguish ping from ping ACK in SPDY
|
||||
isServer: state.isServer,
|
||||
window: state.window
|
||||
})
|
||||
state.framer = state.protocol.framer.create({
|
||||
window: state.window,
|
||||
timeout: state.timeout
|
||||
})
|
||||
|
||||
// SPDY has PUSH enabled on servers
|
||||
if (state.protocol.name === 'spdy') {
|
||||
state.framer.enablePush(state.isServer)
|
||||
}
|
||||
|
||||
if (!state.isServer) { state.parser.skipPreface() }
|
||||
|
||||
this.socket = socket
|
||||
|
||||
this._init()
|
||||
}
|
||||
util.inherits(Connection, EventEmitter)
|
||||
exports.Connection = Connection
|
||||
|
||||
Connection.create = function create (socket, options) {
|
||||
return new Connection(socket, options)
|
||||
}
|
||||
|
||||
Connection.prototype._init = function init () {
|
||||
var self = this
|
||||
var state = this._spdyState
|
||||
var pool = state.pool
|
||||
|
||||
// Initialize session window
|
||||
state.window.recv.on('drain', function () {
|
||||
self._onSessionWindowDrain()
|
||||
})
|
||||
|
||||
// Initialize parser
|
||||
state.parser.on('data', function (frame) {
|
||||
self._handleFrame(frame)
|
||||
})
|
||||
state.parser.once('version', function (version) {
|
||||
self._onVersion(version)
|
||||
})
|
||||
|
||||
// Propagate parser errors
|
||||
state.parser.on('error', function (err) {
|
||||
self._onParserError(err)
|
||||
})
|
||||
|
||||
// Propagate framer errors
|
||||
state.framer.on('error', function (err) {
|
||||
self.emit('error', err)
|
||||
})
|
||||
|
||||
this.socket.pipe(state.parser)
|
||||
state.framer.pipe(this.socket)
|
||||
|
||||
// Allow high-level api to catch socket errors
|
||||
this.socket.on('error', function onSocketError (e) {
|
||||
self.emit('error', e)
|
||||
})
|
||||
|
||||
this.socket.once('close', function onclose (hadError) {
|
||||
var err
|
||||
if (hadError) {
|
||||
err = new Error('socket hang up')
|
||||
err.code = 'ECONNRESET'
|
||||
}
|
||||
|
||||
self.destroyStreams(err)
|
||||
self.emit('close')
|
||||
|
||||
if (state.pair) {
|
||||
pool.put(state.pair)
|
||||
}
|
||||
|
||||
state.framer.resume()
|
||||
})
|
||||
|
||||
// Reset timeout on close
|
||||
this.once('close', function () {
|
||||
self.setTimeout(0)
|
||||
})
|
||||
|
||||
function _onWindowOverflow () {
|
||||
self._onWindowOverflow()
|
||||
}
|
||||
|
||||
state.window.recv.on('overflow', _onWindowOverflow)
|
||||
state.window.send.on('overflow', _onWindowOverflow)
|
||||
|
||||
// Do not allow half-open connections
|
||||
this.socket.allowHalfOpen = false
|
||||
}
|
||||
|
||||
Connection.prototype._onVersion = function _onVersion (version) {
|
||||
var state = this._spdyState
|
||||
var prev = state.version
|
||||
var parser = state.parser
|
||||
var framer = state.framer
|
||||
var pool = state.pool
|
||||
|
||||
state.version = version
|
||||
state.debug('id=0 version=%d', version)
|
||||
|
||||
// Ignore transition to 3.1
|
||||
if (!prev) {
|
||||
state.pair = pool.get(version)
|
||||
parser.setCompression(state.pair)
|
||||
framer.setCompression(state.pair)
|
||||
}
|
||||
framer.setVersion(version)
|
||||
|
||||
if (!state.isServer) {
|
||||
framer.prefaceFrame()
|
||||
if (state.xForward !== null) {
|
||||
framer.xForwardedFor({ host: state.xForward })
|
||||
}
|
||||
}
|
||||
|
||||
// Send preface+settings frame (once)
|
||||
framer.settingsFrame({
|
||||
max_header_list_size: state.constants.DEFAULT_MAX_HEADER_LIST_SIZE,
|
||||
max_concurrent_streams: state.maxStreams,
|
||||
enable_push: state.acceptPush ? 1 : 0,
|
||||
initial_window_size: state.window.recv.max
|
||||
})
|
||||
|
||||
// Update session window
|
||||
if (state.version >= 3.1 || (state.isServer && state.autoSpdy31)) { this._onSessionWindowDrain() }
|
||||
|
||||
this.emit('version', version)
|
||||
}
|
||||
|
||||
Connection.prototype._onParserError = function _onParserError (err) {
|
||||
var state = this._spdyState
|
||||
|
||||
// Prevent further errors
|
||||
state.parser.kill()
|
||||
|
||||
// Send GOAWAY
|
||||
if (err instanceof transport.protocol.base.utils.ProtocolError) {
|
||||
this._goaway({
|
||||
lastId: state.stream.lastId.both,
|
||||
code: err.code,
|
||||
extra: err.message,
|
||||
send: true
|
||||
})
|
||||
}
|
||||
|
||||
this.emit('error', err)
|
||||
}
|
||||
|
||||
Connection.prototype._handleFrame = function _handleFrame (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.debug('id=0 frame', frame)
|
||||
state.timeout.reset()
|
||||
|
||||
// For testing purposes
|
||||
this.emit('frame', frame)
|
||||
|
||||
var stream
|
||||
|
||||
// Session window update
|
||||
if (frame.type === 'WINDOW_UPDATE' && frame.id === 0) {
|
||||
if (state.version < 3.1 && state.autoSpdy31) {
|
||||
state.debug('id=0 switch version to 3.1')
|
||||
state.version = 3.1
|
||||
this.emit('version', 3.1)
|
||||
}
|
||||
state.window.send.update(frame.delta)
|
||||
return
|
||||
}
|
||||
|
||||
if (state.isServer && frame.type === 'PUSH_PROMISE') {
|
||||
state.debug('id=0 server PUSH_PROMISE')
|
||||
this._goaway({
|
||||
lastId: state.stream.lastId.both,
|
||||
code: 'PROTOCOL_ERROR',
|
||||
send: true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!stream && frame.id !== undefined) {
|
||||
// Load created one
|
||||
stream = state.stream.map[frame.id]
|
||||
|
||||
// Fail if not found
|
||||
if (!stream &&
|
||||
frame.type !== 'HEADERS' &&
|
||||
frame.type !== 'PRIORITY' &&
|
||||
frame.type !== 'RST') {
|
||||
// Other side should destroy the stream upon receiving GOAWAY
|
||||
if (this._isGoaway(frame.id)) { return }
|
||||
|
||||
state.debug('id=0 stream=%d not found', frame.id)
|
||||
state.framer.rstFrame({ id: frame.id, code: 'INVALID_STREAM' })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Create new stream
|
||||
if (!stream && frame.type === 'HEADERS') {
|
||||
this._handleHeaders(frame)
|
||||
return
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
stream._handleFrame(frame)
|
||||
} else if (frame.type === 'SETTINGS') {
|
||||
this._handleSettings(frame.settings)
|
||||
} else if (frame.type === 'ACK_SETTINGS') {
|
||||
// TODO(indutny): handle it one day
|
||||
} else if (frame.type === 'PING') {
|
||||
this._handlePing(frame)
|
||||
} else if (frame.type === 'GOAWAY') {
|
||||
this._handleGoaway(frame)
|
||||
} else if (frame.type === 'X_FORWARDED_FOR') {
|
||||
// Set X-Forwarded-For only once
|
||||
if (state.xForward === null) {
|
||||
state.xForward = frame.host
|
||||
}
|
||||
} else if (frame.type === 'PRIORITY') {
|
||||
// TODO(indutny): handle this
|
||||
} else {
|
||||
state.debug('id=0 unknown frame type: %s', frame.type)
|
||||
}
|
||||
}
|
||||
|
||||
Connection.prototype._onWindowOverflow = function _onWindowOverflow () {
|
||||
var state = this._spdyState
|
||||
state.debug('id=0 window overflow')
|
||||
this._goaway({
|
||||
lastId: state.stream.lastId.both,
|
||||
code: 'FLOW_CONTROL_ERROR',
|
||||
send: true
|
||||
})
|
||||
}
|
||||
|
||||
Connection.prototype._isGoaway = function _isGoaway (id) {
|
||||
var state = this._spdyState
|
||||
if (state.goaway !== false && state.goaway < id) { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
Connection.prototype._getId = function _getId () {
|
||||
var state = this._spdyState
|
||||
|
||||
var id = state.stream.nextId
|
||||
state.stream.nextId += 2
|
||||
return id
|
||||
}
|
||||
|
||||
Connection.prototype._createStream = function _createStream (uri) {
|
||||
var state = this._spdyState
|
||||
var id = uri.id
|
||||
if (id === undefined) { id = this._getId() }
|
||||
|
||||
var isGoaway = this._isGoaway(id)
|
||||
|
||||
if (uri.push && !state.acceptPush) {
|
||||
state.debug('id=0 push disabled promisedId=%d', id)
|
||||
|
||||
// Fatal error
|
||||
this._goaway({
|
||||
lastId: state.stream.lastId.both,
|
||||
code: 'PROTOCOL_ERROR',
|
||||
send: true
|
||||
})
|
||||
isGoaway = true
|
||||
}
|
||||
|
||||
var stream = new Stream(this, {
|
||||
id: id,
|
||||
request: uri.request !== false,
|
||||
method: uri.method,
|
||||
path: uri.path,
|
||||
host: uri.host,
|
||||
priority: uri.priority,
|
||||
headers: uri.headers,
|
||||
parent: uri.parent,
|
||||
readable: !isGoaway && uri.readable,
|
||||
writable: !isGoaway && uri.writable
|
||||
})
|
||||
var self = this
|
||||
|
||||
// Just an empty stream for API consistency
|
||||
if (isGoaway) {
|
||||
return stream
|
||||
}
|
||||
|
||||
state.stream.lastId.both = Math.max(state.stream.lastId.both, id)
|
||||
|
||||
state.debug('id=0 add stream=%d', stream.id)
|
||||
state.stream.map[stream.id] = stream
|
||||
state.stream.count++
|
||||
state.counters.stream++
|
||||
if (stream.parent !== null) {
|
||||
state.counters.push++
|
||||
}
|
||||
|
||||
stream.once('close', function () {
|
||||
self._removeStream(stream)
|
||||
})
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
Connection.prototype._handleHeaders = function _handleHeaders (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
// Must be HEADERS frame after stream close
|
||||
if (frame.id <= state.stream.lastId.received) { return }
|
||||
|
||||
// Someone is using our ids!
|
||||
if ((frame.id + state.stream.nextId) % 2 === 0) {
|
||||
state.framer.rstFrame({ id: frame.id, code: 'PROTOCOL_ERROR' })
|
||||
return
|
||||
}
|
||||
|
||||
var stream = this._createStream({
|
||||
id: frame.id,
|
||||
request: false,
|
||||
method: frame.headers[':method'],
|
||||
path: frame.headers[':path'],
|
||||
host: frame.headers[':authority'],
|
||||
priority: frame.priority,
|
||||
headers: frame.headers,
|
||||
writable: frame.writable
|
||||
})
|
||||
|
||||
// GOAWAY
|
||||
if (this._isGoaway(stream.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
state.stream.lastId.received = Math.max(
|
||||
state.stream.lastId.received,
|
||||
stream.id
|
||||
)
|
||||
|
||||
// TODO(indutny) handle stream limit
|
||||
if (!this.emit('stream', stream)) {
|
||||
// No listeners was set - abort the stream
|
||||
stream.abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Create fake frame to simulate end of the data
|
||||
if (frame.fin) {
|
||||
stream._handleFrame({ type: 'FIN', fin: true })
|
||||
}
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
Connection.prototype._onSessionWindowDrain = function _onSessionWindowDrain () {
|
||||
var state = this._spdyState
|
||||
if (state.version < 3.1 && !(state.isServer && state.autoSpdy31)) {
|
||||
return
|
||||
}
|
||||
|
||||
var delta = state.window.recv.getDelta()
|
||||
if (delta === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
state.debug('id=0 session window drain, update by %d', delta)
|
||||
|
||||
state.framer.windowUpdateFrame({
|
||||
id: 0,
|
||||
delta: delta
|
||||
})
|
||||
state.window.recv.update(delta)
|
||||
}
|
||||
|
||||
Connection.prototype.start = function start (version) {
|
||||
this._spdyState.parser.setVersion(version)
|
||||
}
|
||||
|
||||
// Mostly for testing
|
||||
Connection.prototype.getVersion = function getVersion () {
|
||||
return this._spdyState.version
|
||||
}
|
||||
|
||||
Connection.prototype._handleSettings = function _handleSettings (settings) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.framer.ackSettingsFrame()
|
||||
|
||||
this._setDefaultWindow(settings)
|
||||
if (settings.max_frame_size) { state.framer.setMaxFrameSize(settings.max_frame_size) }
|
||||
|
||||
// TODO(indutny): handle max_header_list_size
|
||||
if (settings.header_table_size) {
|
||||
try {
|
||||
state.pair.compress.updateTableSize(settings.header_table_size)
|
||||
} catch (e) {
|
||||
this._goaway({
|
||||
lastId: 0,
|
||||
code: 'PROTOCOL_ERROR',
|
||||
send: true
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP2 clients needs to enable PUSH streams explicitly
|
||||
if (state.protocol.name !== 'spdy') {
|
||||
if (settings.enable_push === undefined) {
|
||||
state.framer.enablePush(state.isServer)
|
||||
} else {
|
||||
state.framer.enablePush(settings.enable_push === 1)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(indutny): handle max_concurrent_streams
|
||||
}
|
||||
|
||||
Connection.prototype._setDefaultWindow = function _setDefaultWindow (settings) {
|
||||
if (settings.initial_window_size === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var state = this._spdyState
|
||||
|
||||
// Update defaults
|
||||
var window = state.streamWindow
|
||||
window.send.setMax(settings.initial_window_size)
|
||||
|
||||
// Update existing streams
|
||||
Object.keys(state.stream.map).forEach(function (id) {
|
||||
var stream = state.stream.map[id]
|
||||
var window = stream._spdyState.window
|
||||
|
||||
window.send.updateMax(settings.initial_window_size)
|
||||
})
|
||||
}
|
||||
|
||||
Connection.prototype._handlePing = function handlePing (frame) {
|
||||
var self = this
|
||||
var state = this._spdyState
|
||||
|
||||
// Handle incoming PING
|
||||
if (!frame.ack) {
|
||||
state.framer.pingFrame({
|
||||
opaque: frame.opaque,
|
||||
ack: true
|
||||
})
|
||||
|
||||
self.emit('ping', frame.opaque)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle reply PING
|
||||
var hex = frame.opaque.toString('hex')
|
||||
if (!state.ping.map[hex]) {
|
||||
return
|
||||
}
|
||||
var ping = state.ping.map[hex]
|
||||
delete state.ping.map[hex]
|
||||
|
||||
if (ping.cb) {
|
||||
ping.cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
Connection.prototype._handleGoaway = function handleGoaway (frame) {
|
||||
this._goaway({
|
||||
lastId: frame.lastId,
|
||||
code: frame.code,
|
||||
send: false
|
||||
})
|
||||
}
|
||||
|
||||
Connection.prototype.ping = function ping (callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
// HTTP2 is using 8-byte opaque
|
||||
var opaque = Buffer.alloc(state.constants.PING_OPAQUE_SIZE)
|
||||
opaque.fill(0)
|
||||
opaque.writeUInt32BE(state.ping.nextId, opaque.length - 4)
|
||||
state.ping.nextId += 2
|
||||
|
||||
state.ping.map[opaque.toString('hex')] = { cb: callback }
|
||||
state.framer.pingFrame({
|
||||
opaque: opaque,
|
||||
ack: false
|
||||
})
|
||||
}
|
||||
|
||||
Connection.prototype.getCounter = function getCounter (name) {
|
||||
return this._spdyState.counters[name]
|
||||
}
|
||||
|
||||
Connection.prototype.reserveStream = function reserveStream (uri, callback) {
|
||||
var stream = this._createStream(uri)
|
||||
|
||||
// GOAWAY
|
||||
if (this._isGoaway(stream.id)) {
|
||||
var err = new Error('Can\'t send request after GOAWAY')
|
||||
process.nextTick(function () {
|
||||
if (callback) { callback(err) } else {
|
||||
stream.emit('error', err)
|
||||
}
|
||||
})
|
||||
return stream
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
process.nextTick(function () {
|
||||
callback(null, stream)
|
||||
})
|
||||
}
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
Connection.prototype.request = function request (uri, callback) {
|
||||
var stream = this.reserveStream(uri, function (err) {
|
||||
if (err) {
|
||||
if (callback) {
|
||||
callback(err)
|
||||
} else {
|
||||
stream.emit('error', err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (stream._wasSent()) {
|
||||
if (callback) {
|
||||
callback(null, stream)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
stream.send(function (err) {
|
||||
if (err) {
|
||||
if (callback) { return callback(err) } else { return stream.emit('error', err) }
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(null, stream)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
Connection.prototype._removeStream = function _removeStream (stream) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.debug('id=0 remove stream=%d', stream.id)
|
||||
delete state.stream.map[stream.id]
|
||||
state.stream.count--
|
||||
|
||||
if (state.stream.count === 0) {
|
||||
this.emit('_streamDrain')
|
||||
}
|
||||
}
|
||||
|
||||
Connection.prototype._goaway = function _goaway (params) {
|
||||
var state = this._spdyState
|
||||
var self = this
|
||||
|
||||
state.goaway = params.lastId
|
||||
state.debug('id=0 goaway from=%d', state.goaway)
|
||||
|
||||
Object.keys(state.stream.map).forEach(function (id) {
|
||||
var stream = state.stream.map[id]
|
||||
|
||||
// Abort every stream started after GOAWAY
|
||||
if (stream.id <= params.lastId) {
|
||||
return
|
||||
}
|
||||
|
||||
stream.abort()
|
||||
stream.emit('error', new Error('New stream after GOAWAY'))
|
||||
})
|
||||
|
||||
function finish () {
|
||||
// Destroy socket if there are no streams
|
||||
if (state.stream.count === 0 || params.code !== 'OK') {
|
||||
// No further frames should be processed
|
||||
state.parser.kill()
|
||||
|
||||
process.nextTick(function () {
|
||||
var err = new Error('Fatal error: ' + params.code)
|
||||
self._onStreamDrain(err)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
self.on('_streamDrain', self._onStreamDrain)
|
||||
}
|
||||
|
||||
if (params.send) {
|
||||
// Make sure that GOAWAY frame is sent before dumping framer
|
||||
state.framer.goawayFrame({
|
||||
lastId: params.lastId,
|
||||
code: params.code,
|
||||
extra: params.extra
|
||||
}, finish)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
Connection.prototype._onStreamDrain = function _onStreamDrain (error) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.debug('id=0 _onStreamDrain')
|
||||
|
||||
state.framer.dump()
|
||||
state.framer.unpipe(this.socket)
|
||||
state.framer.resume()
|
||||
|
||||
if (this.socket.destroySoon) {
|
||||
this.socket.destroySoon()
|
||||
}
|
||||
this.emit('close', error)
|
||||
}
|
||||
|
||||
Connection.prototype.end = function end (callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
if (callback) {
|
||||
this.once('close', callback)
|
||||
}
|
||||
this._goaway({
|
||||
lastId: state.stream.lastId.both,
|
||||
code: 'OK',
|
||||
send: true
|
||||
})
|
||||
}
|
||||
|
||||
Connection.prototype.destroyStreams = function destroyStreams (err) {
|
||||
var state = this._spdyState
|
||||
Object.keys(state.stream.map).forEach(function (id) {
|
||||
var stream = state.stream.map[id]
|
||||
|
||||
stream.destroy()
|
||||
if (err) {
|
||||
stream.emit('error', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Connection.prototype.isServer = function isServer () {
|
||||
return this._spdyState.isServer
|
||||
}
|
||||
|
||||
Connection.prototype.getXForwardedFor = function getXForwardFor () {
|
||||
return this._spdyState.xForward
|
||||
}
|
||||
|
||||
Connection.prototype.sendXForwardedFor = function sendXForwardedFor (host) {
|
||||
var state = this._spdyState
|
||||
if (state.version !== null) {
|
||||
state.framer.xForwardedFor({ host: host })
|
||||
} else {
|
||||
state.xForward = host
|
||||
}
|
||||
}
|
||||
|
||||
Connection.prototype.pushPromise = function pushPromise (parent, uri, callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
var stream = this._createStream({
|
||||
request: false,
|
||||
parent: parent,
|
||||
method: uri.method,
|
||||
path: uri.path,
|
||||
host: uri.host,
|
||||
priority: uri.priority,
|
||||
headers: uri.headers,
|
||||
readable: false
|
||||
})
|
||||
|
||||
var err
|
||||
|
||||
// TODO(indutny): deduplicate this logic somehow
|
||||
if (this._isGoaway(stream.id)) {
|
||||
err = new Error('Can\'t send PUSH_PROMISE after GOAWAY')
|
||||
|
||||
process.nextTick(function () {
|
||||
if (callback) {
|
||||
callback(err)
|
||||
} else {
|
||||
stream.emit('error', err)
|
||||
}
|
||||
})
|
||||
return stream
|
||||
}
|
||||
|
||||
if (uri.push && !state.acceptPush) {
|
||||
err = new Error(
|
||||
'Can\'t send PUSH_PROMISE, other side won\'t accept it')
|
||||
process.nextTick(function () {
|
||||
if (callback) { callback(err) } else {
|
||||
stream.emit('error', err)
|
||||
}
|
||||
})
|
||||
return stream
|
||||
}
|
||||
|
||||
stream._sendPush(uri.status, uri.response, function (err) {
|
||||
if (!callback) {
|
||||
if (err) {
|
||||
stream.emit('error', err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (err) { return callback(err) }
|
||||
callback(null, stream)
|
||||
})
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
Connection.prototype.setTimeout = function setTimeout (delay, callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.timeout.set(delay, callback)
|
||||
}
|
188
my-app/node_modules/spdy-transport/lib/spdy-transport/priority.js
generated
vendored
Executable file
188
my-app/node_modules/spdy-transport/lib/spdy-transport/priority.js
generated
vendored
Executable file
|
@ -0,0 +1,188 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../spdy-transport')
|
||||
var utils = transport.utils
|
||||
|
||||
var assert = require('assert')
|
||||
var debug = require('debug')('spdy:priority')
|
||||
|
||||
function PriorityNode (tree, options) {
|
||||
this.tree = tree
|
||||
|
||||
this.id = options.id
|
||||
this.parent = options.parent
|
||||
this.weight = options.weight
|
||||
|
||||
// To be calculated in `addChild`
|
||||
this.priorityFrom = 0
|
||||
this.priorityTo = 1
|
||||
this.priority = 1
|
||||
|
||||
this.children = {
|
||||
list: [],
|
||||
weight: 0
|
||||
}
|
||||
|
||||
if (this.parent !== null) {
|
||||
this.parent.addChild(this)
|
||||
}
|
||||
}
|
||||
|
||||
function compareChildren (a, b) {
|
||||
return a.weight === b.weight ? a.id - b.id : a.weight - b.weight
|
||||
}
|
||||
|
||||
PriorityNode.prototype.toJSON = function toJSON () {
|
||||
return {
|
||||
parent: this.parent,
|
||||
weight: this.weight,
|
||||
exclusive: this.exclusive
|
||||
}
|
||||
}
|
||||
|
||||
PriorityNode.prototype.getPriority = function getPriority () {
|
||||
return this.priority
|
||||
}
|
||||
|
||||
PriorityNode.prototype.getPriorityRange = function getPriorityRange () {
|
||||
return { from: this.priorityFrom, to: this.priorityTo }
|
||||
}
|
||||
|
||||
PriorityNode.prototype.addChild = function addChild (child) {
|
||||
child.parent = this
|
||||
utils.binaryInsert(this.children.list, child, compareChildren)
|
||||
this.children.weight += child.weight
|
||||
|
||||
this._updatePriority(this.priorityFrom, this.priorityTo)
|
||||
}
|
||||
|
||||
PriorityNode.prototype.remove = function remove () {
|
||||
assert(this.parent, 'Can\'t remove root node')
|
||||
|
||||
this.parent.removeChild(this)
|
||||
this.tree._removeNode(this)
|
||||
|
||||
// Move all children to the parent
|
||||
for (var i = 0; i < this.children.list.length; i++) {
|
||||
this.parent.addChild(this.children.list[i])
|
||||
}
|
||||
}
|
||||
|
||||
PriorityNode.prototype.removeChild = function removeChild (child) {
|
||||
this.children.weight -= child.weight
|
||||
var index = utils.binarySearch(this.children.list, child, compareChildren)
|
||||
if (index !== -1 && this.children.list.length >= index) {
|
||||
this.children.list.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
PriorityNode.prototype.removeChildren = function removeChildren () {
|
||||
var children = this.children.list
|
||||
this.children.list = []
|
||||
this.children.weight = 0
|
||||
return children
|
||||
}
|
||||
|
||||
PriorityNode.prototype._updatePriority = function _updatePriority (from, to) {
|
||||
this.priority = to - from
|
||||
this.priorityFrom = from
|
||||
this.priorityTo = to
|
||||
|
||||
var weight = 0
|
||||
for (var i = 0; i < this.children.list.length; i++) {
|
||||
var node = this.children.list[i]
|
||||
var nextWeight = weight + node.weight
|
||||
|
||||
node._updatePriority(
|
||||
from + this.priority * (weight / this.children.weight),
|
||||
from + this.priority * (nextWeight / this.children.weight)
|
||||
)
|
||||
weight = nextWeight
|
||||
}
|
||||
}
|
||||
|
||||
function PriorityTree (options) {
|
||||
this.map = {}
|
||||
this.list = []
|
||||
this.defaultWeight = options.defaultWeight || 16
|
||||
|
||||
this.count = 0
|
||||
this.maxCount = options.maxCount
|
||||
|
||||
// Root
|
||||
this.root = this.add({
|
||||
id: 0,
|
||||
parent: null,
|
||||
weight: 1
|
||||
})
|
||||
}
|
||||
module.exports = PriorityTree
|
||||
|
||||
PriorityTree.create = function create (options) {
|
||||
return new PriorityTree(options)
|
||||
}
|
||||
|
||||
PriorityTree.prototype.add = function add (options) {
|
||||
if (options.id === options.parent) {
|
||||
return this.addDefault(options.id)
|
||||
}
|
||||
|
||||
var parent = options.parent === null ? null : this.map[options.parent]
|
||||
if (parent === undefined) {
|
||||
return this.addDefault(options.id)
|
||||
}
|
||||
|
||||
debug('add node=%d parent=%d weight=%d exclusive=%d',
|
||||
options.id,
|
||||
options.parent === null ? -1 : options.parent,
|
||||
options.weight || this.defaultWeight,
|
||||
options.exclusive ? 1 : 0)
|
||||
|
||||
var children
|
||||
if (options.exclusive) {
|
||||
children = parent.removeChildren()
|
||||
}
|
||||
|
||||
var node = new PriorityNode(this, {
|
||||
id: options.id,
|
||||
parent: parent,
|
||||
weight: options.weight || this.defaultWeight
|
||||
})
|
||||
this.map[options.id] = node
|
||||
|
||||
if (options.exclusive) {
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
node.addChild(children[i])
|
||||
}
|
||||
}
|
||||
|
||||
this.count++
|
||||
if (this.count > this.maxCount) {
|
||||
debug('hit maximum remove id=%d', this.list[0].id)
|
||||
this.list.shift().remove()
|
||||
}
|
||||
|
||||
// Root node is not subject to removal
|
||||
if (node.parent !== null) {
|
||||
this.list.push(node)
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// Only for testing, should use `node`'s methods
|
||||
PriorityTree.prototype.get = function get (id) {
|
||||
return this.map[id]
|
||||
}
|
||||
|
||||
PriorityTree.prototype.addDefault = function addDefault (id) {
|
||||
debug('creating default node')
|
||||
return this.add({ id: id, parent: 0, weight: this.defaultWeight })
|
||||
}
|
||||
|
||||
PriorityTree.prototype._removeNode = function _removeNode (node) {
|
||||
delete this.map[node.id]
|
||||
var index = utils.binarySearch(this.list, node, compareChildren)
|
||||
this.list.splice(index, 1)
|
||||
this.count--
|
||||
}
|
4
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/constants.js
generated
vendored
Executable file
4
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/constants.js
generated
vendored
Executable file
|
@ -0,0 +1,4 @@
|
|||
exports.DEFAULT_METHOD = 'GET'
|
||||
exports.DEFAULT_HOST = 'localhost'
|
||||
exports.MAX_PRIORITY_STREAMS = 100
|
||||
exports.DEFAULT_MAX_CHUNK = 8 * 1024
|
58
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/framer.js
generated
vendored
Executable file
58
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/framer.js
generated
vendored
Executable file
|
@ -0,0 +1,58 @@
|
|||
'use strict'
|
||||
|
||||
var util = require('util')
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var base = require('./')
|
||||
var Scheduler = base.Scheduler
|
||||
|
||||
function Framer (options) {
|
||||
Scheduler.call(this)
|
||||
|
||||
this.version = null
|
||||
this.compress = null
|
||||
this.window = options.window
|
||||
this.timeout = options.timeout
|
||||
|
||||
// Wait for `enablePush`
|
||||
this.pushEnabled = null
|
||||
}
|
||||
util.inherits(Framer, Scheduler)
|
||||
module.exports = Framer
|
||||
|
||||
Framer.prototype.setVersion = function setVersion (version) {
|
||||
this.version = version
|
||||
this.emit('version')
|
||||
}
|
||||
|
||||
Framer.prototype.setCompression = function setCompresion (pair) {
|
||||
this.compress = new transport.utils.LockStream(pair.compress)
|
||||
}
|
||||
|
||||
Framer.prototype.enablePush = function enablePush (enable) {
|
||||
this.pushEnabled = enable
|
||||
this.emit('_pushEnabled')
|
||||
}
|
||||
|
||||
Framer.prototype._checkPush = function _checkPush (callback) {
|
||||
if (this.pushEnabled === null) {
|
||||
this.once('_pushEnabled', function () {
|
||||
this._checkPush(callback)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var err = null
|
||||
if (!this.pushEnabled) {
|
||||
err = new Error('PUSH_PROMISE disabled by other side')
|
||||
}
|
||||
process.nextTick(function () {
|
||||
return callback(err)
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype._resetTimeout = function _resetTimeout () {
|
||||
if (this.timeout) {
|
||||
this.timeout.reset()
|
||||
}
|
||||
}
|
7
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/index.js
generated
vendored
Executable file
7
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/index.js
generated
vendored
Executable file
|
@ -0,0 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
exports.utils = require('./utils')
|
||||
exports.constants = require('./constants')
|
||||
exports.Scheduler = require('./scheduler')
|
||||
exports.Parser = require('./parser')
|
||||
exports.Framer = require('./framer')
|
106
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/parser.js
generated
vendored
Executable file
106
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/parser.js
generated
vendored
Executable file
|
@ -0,0 +1,106 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
|
||||
var util = require('util')
|
||||
var utils = require('./').utils
|
||||
var OffsetBuffer = require('obuf')
|
||||
var Transform = require('readable-stream').Transform
|
||||
|
||||
function Parser (options) {
|
||||
Transform.call(this, {
|
||||
readableObjectMode: true
|
||||
})
|
||||
|
||||
this.buffer = new OffsetBuffer()
|
||||
this.partial = false
|
||||
this.waiting = 0
|
||||
|
||||
this.window = options.window
|
||||
|
||||
this.version = null
|
||||
this.decompress = null
|
||||
this.dead = false
|
||||
}
|
||||
module.exports = Parser
|
||||
util.inherits(Parser, Transform)
|
||||
|
||||
Parser.prototype.error = utils.error
|
||||
|
||||
Parser.prototype.kill = function kill () {
|
||||
this.dead = true
|
||||
}
|
||||
|
||||
Parser.prototype._transform = function transform (data, encoding, cb) {
|
||||
if (!this.dead) { this.buffer.push(data) }
|
||||
|
||||
this._consume(cb)
|
||||
}
|
||||
|
||||
Parser.prototype._consume = function _consume (cb) {
|
||||
var self = this
|
||||
|
||||
function next (err, frame) {
|
||||
if (err) {
|
||||
return cb(err)
|
||||
}
|
||||
|
||||
if (Array.isArray(frame)) {
|
||||
for (var i = 0; i < frame.length; i++) {
|
||||
self.push(frame[i])
|
||||
}
|
||||
} else if (frame) {
|
||||
self.push(frame)
|
||||
}
|
||||
|
||||
// Consume more packets
|
||||
if (!sync) {
|
||||
return self._consume(cb)
|
||||
}
|
||||
|
||||
process.nextTick(function () {
|
||||
self._consume(cb)
|
||||
})
|
||||
}
|
||||
|
||||
if (this.dead) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
if (this.buffer.size < this.waiting) {
|
||||
// No data at all
|
||||
if (this.buffer.size === 0) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
// Partial DATA frame or something that we can process partially
|
||||
if (this.partial) {
|
||||
var partial = this.buffer.clone(this.buffer.size)
|
||||
this.buffer.skip(partial.size)
|
||||
this.waiting -= partial.size
|
||||
|
||||
this.executePartial(partial, next)
|
||||
return
|
||||
}
|
||||
|
||||
// We shall not do anything until we get all expected data
|
||||
return cb()
|
||||
}
|
||||
|
||||
var sync = true
|
||||
|
||||
var content = this.buffer.clone(this.waiting)
|
||||
this.buffer.skip(this.waiting)
|
||||
|
||||
this.execute(content, next)
|
||||
sync = false
|
||||
}
|
||||
|
||||
Parser.prototype.setVersion = function setVersion (version) {
|
||||
this.version = version
|
||||
this.emit('version', version)
|
||||
}
|
||||
|
||||
Parser.prototype.setCompression = function setCompresion (pair) {
|
||||
this.decompress = new transport.utils.LockStream(pair.decompress)
|
||||
}
|
216
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/scheduler.js
generated
vendored
Executable file
216
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/scheduler.js
generated
vendored
Executable file
|
@ -0,0 +1,216 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var utils = transport.utils
|
||||
|
||||
var assert = require('assert')
|
||||
var util = require('util')
|
||||
var debug = require('debug')('spdy:scheduler')
|
||||
var Readable = require('readable-stream').Readable
|
||||
|
||||
/*
|
||||
* We create following structure in `pending`:
|
||||
* [ [ id = 0 ], [ id = 1 ], [ id = 2 ], [ id = 0 ] ]
|
||||
* chunks chunks chunks chunks
|
||||
* chunks chunks
|
||||
* chunks
|
||||
*
|
||||
* Then on the `.tick()` pass we pick one chunks from each item and remove the
|
||||
* item if it is empty:
|
||||
*
|
||||
* [ [ id = 0 ], [ id = 2 ] ]
|
||||
* chunks chunks
|
||||
* chunks
|
||||
*
|
||||
* Writing out: chunks for 0, chunks for 1, chunks for 2, chunks for 0
|
||||
*
|
||||
* This way data is interleaved between the different streams.
|
||||
*/
|
||||
|
||||
function Scheduler (options) {
|
||||
Readable.call(this)
|
||||
|
||||
// Pretty big window by default
|
||||
this.window = 0.25
|
||||
|
||||
if (options && options.window) { this.window = options.window }
|
||||
|
||||
this.sync = []
|
||||
this.list = []
|
||||
this.count = 0
|
||||
this.pendingTick = false
|
||||
}
|
||||
util.inherits(Scheduler, Readable)
|
||||
module.exports = Scheduler
|
||||
|
||||
// Just for testing, really
|
||||
Scheduler.create = function create (options) {
|
||||
return new Scheduler(options)
|
||||
}
|
||||
|
||||
function insertCompare (a, b) {
|
||||
return a.priority === b.priority
|
||||
? a.stream - b.stream
|
||||
: b.priority - a.priority
|
||||
}
|
||||
|
||||
Scheduler.prototype.schedule = function schedule (data) {
|
||||
var priority = data.priority
|
||||
var stream = data.stream
|
||||
var chunks = data.chunks
|
||||
|
||||
// Synchronous frames should not be interleaved
|
||||
if (priority === false) {
|
||||
debug('queue sync', chunks)
|
||||
this.sync.push(data)
|
||||
this.count += chunks.length
|
||||
|
||||
this._read()
|
||||
return
|
||||
}
|
||||
|
||||
debug('queue async priority=%d stream=%d', priority, stream, chunks)
|
||||
var item = new SchedulerItem(stream, priority)
|
||||
var index = utils.binaryLookup(this.list, item, insertCompare)
|
||||
|
||||
// Push new item
|
||||
if (index >= this.list.length || insertCompare(this.list[index], item) !== 0) {
|
||||
this.list.splice(index, 0, item)
|
||||
} else { // Coalesce
|
||||
item = this.list[index]
|
||||
}
|
||||
|
||||
item.push(data)
|
||||
|
||||
this.count += chunks.length
|
||||
|
||||
this._read()
|
||||
}
|
||||
|
||||
Scheduler.prototype._read = function _read () {
|
||||
if (this.count === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.pendingTick) {
|
||||
return
|
||||
}
|
||||
this.pendingTick = true
|
||||
|
||||
var self = this
|
||||
process.nextTick(function () {
|
||||
self.pendingTick = false
|
||||
self.tick()
|
||||
})
|
||||
}
|
||||
|
||||
Scheduler.prototype.tick = function tick () {
|
||||
// No luck for async frames
|
||||
if (!this.tickSync()) { return false }
|
||||
|
||||
return this.tickAsync()
|
||||
}
|
||||
|
||||
Scheduler.prototype.tickSync = function tickSync () {
|
||||
// Empty sync queue first
|
||||
var sync = this.sync
|
||||
var res = true
|
||||
this.sync = []
|
||||
for (var i = 0; i < sync.length; i++) {
|
||||
var item = sync[i]
|
||||
debug('tick sync pending=%d', this.count, item.chunks)
|
||||
for (var j = 0; j < item.chunks.length; j++) {
|
||||
this.count--
|
||||
// TODO: handle stream backoff properly
|
||||
try {
|
||||
res = this.push(item.chunks[j])
|
||||
} catch (err) {
|
||||
this.emit('error', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
debug('after tick sync pending=%d', this.count)
|
||||
|
||||
// TODO(indutny): figure out the way to invoke callback on actual write
|
||||
if (item.callback) {
|
||||
item.callback(null)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
Scheduler.prototype.tickAsync = function tickAsync () {
|
||||
var res = true
|
||||
var list = this.list
|
||||
if (list.length === 0) {
|
||||
return res
|
||||
}
|
||||
|
||||
var startPriority = list[0].priority
|
||||
for (var index = 0; list.length > 0; index++) {
|
||||
// Loop index
|
||||
index %= list.length
|
||||
if (startPriority - list[index].priority > this.window) { index = 0 }
|
||||
debug('tick async index=%d start=%d', index, startPriority)
|
||||
|
||||
var current = list[index]
|
||||
var item = current.shift()
|
||||
|
||||
if (current.isEmpty()) {
|
||||
list.splice(index, 1)
|
||||
if (index === 0 && list.length > 0) {
|
||||
startPriority = list[0].priority
|
||||
}
|
||||
index--
|
||||
}
|
||||
|
||||
debug('tick async pending=%d', this.count, item.chunks)
|
||||
for (var i = 0; i < item.chunks.length; i++) {
|
||||
this.count--
|
||||
// TODO: handle stream backoff properly
|
||||
try {
|
||||
res = this.push(item.chunks[i])
|
||||
} catch (err) {
|
||||
this.emit('error', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
debug('after tick pending=%d', this.count)
|
||||
|
||||
// TODO(indutny): figure out the way to invoke callback on actual write
|
||||
if (item.callback) {
|
||||
item.callback(null)
|
||||
}
|
||||
if (!res) { break }
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
Scheduler.prototype.dump = function dump () {
|
||||
this.tickSync()
|
||||
|
||||
// Write everything out
|
||||
while (!this.tickAsync()) {
|
||||
// Intentional no-op
|
||||
}
|
||||
assert.strictEqual(this.count, 0)
|
||||
}
|
||||
|
||||
function SchedulerItem (stream, priority) {
|
||||
this.stream = stream
|
||||
this.priority = priority
|
||||
this.queue = []
|
||||
}
|
||||
|
||||
SchedulerItem.prototype.push = function push (chunks) {
|
||||
this.queue.push(chunks)
|
||||
}
|
||||
|
||||
SchedulerItem.prototype.shift = function shift () {
|
||||
return this.queue.shift()
|
||||
}
|
||||
|
||||
SchedulerItem.prototype.isEmpty = function isEmpty () {
|
||||
return this.queue.length === 0
|
||||
}
|
94
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/utils.js
generated
vendored
Executable file
94
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/base/utils.js
generated
vendored
Executable file
|
@ -0,0 +1,94 @@
|
|||
'use strict'
|
||||
|
||||
var utils = exports
|
||||
|
||||
var util = require('util')
|
||||
|
||||
function ProtocolError (code, message) {
|
||||
this.code = code
|
||||
this.message = message
|
||||
}
|
||||
util.inherits(ProtocolError, Error)
|
||||
utils.ProtocolError = ProtocolError
|
||||
|
||||
utils.error = function error (code, message) {
|
||||
return new ProtocolError(code, message)
|
||||
}
|
||||
|
||||
utils.reverse = function reverse (object) {
|
||||
var result = []
|
||||
|
||||
Object.keys(object).forEach(function (key) {
|
||||
result[object[key] | 0] = key
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// weight [1, 36] <=> priority [0, 7]
|
||||
// This way weight=16 is preserved and has priority=3
|
||||
utils.weightToPriority = function weightToPriority (weight) {
|
||||
return ((Math.min(35, (weight - 1)) / 35) * 7) | 0
|
||||
}
|
||||
|
||||
utils.priorityToWeight = function priorityToWeight (priority) {
|
||||
return (((priority / 7) * 35) | 0) + 1
|
||||
}
|
||||
|
||||
// Copy-Paste from node
|
||||
exports.addHeaderLine = function addHeaderLine (field, value, dest) {
|
||||
field = field.toLowerCase()
|
||||
if (/^:/.test(field)) {
|
||||
dest[field] = value
|
||||
return
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
// Array headers:
|
||||
case 'set-cookie':
|
||||
if (dest[field] !== undefined) {
|
||||
dest[field].push(value)
|
||||
} else {
|
||||
dest[field] = [ value ]
|
||||
}
|
||||
break
|
||||
|
||||
/* eslint-disable max-len */
|
||||
// list is taken from:
|
||||
/* eslint-enable max-len */
|
||||
case 'content-type':
|
||||
case 'content-length':
|
||||
case 'user-agent':
|
||||
case 'referer':
|
||||
case 'host':
|
||||
case 'authorization':
|
||||
case 'proxy-authorization':
|
||||
case 'if-modified-since':
|
||||
case 'if-unmodified-since':
|
||||
case 'from':
|
||||
case 'location':
|
||||
case 'max-forwards':
|
||||
// drop duplicates
|
||||
if (dest[field] === undefined) {
|
||||
dest[field] = value
|
||||
}
|
||||
break
|
||||
|
||||
case 'cookie':
|
||||
// make semicolon-separated list
|
||||
if (dest[field] !== undefined) {
|
||||
dest[field] += '; ' + value
|
||||
} else {
|
||||
dest[field] = value
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
// make comma-separated list
|
||||
if (dest[field] !== undefined) {
|
||||
dest[field] += ', ' + value
|
||||
} else {
|
||||
dest[field] = value
|
||||
}
|
||||
}
|
||||
}
|
93
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/constants.js
generated
vendored
Executable file
93
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/constants.js
generated
vendored
Executable file
|
@ -0,0 +1,93 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var base = transport.protocol.base
|
||||
|
||||
exports.PREFACE_SIZE = 24
|
||||
exports.PREFACE = 'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'
|
||||
exports.PREFACE_BUFFER = Buffer.from(exports.PREFACE)
|
||||
|
||||
exports.PING_OPAQUE_SIZE = 8
|
||||
|
||||
exports.FRAME_HEADER_SIZE = 9
|
||||
exports.INITIAL_MAX_FRAME_SIZE = 16384
|
||||
exports.ABSOLUTE_MAX_FRAME_SIZE = 16777215
|
||||
exports.HEADER_TABLE_SIZE = 4096
|
||||
exports.DEFAULT_MAX_HEADER_LIST_SIZE = 80 * 1024 // as in http_parser
|
||||
exports.MAX_INITIAL_WINDOW_SIZE = 2147483647
|
||||
|
||||
exports.DEFAULT_WEIGHT = 16
|
||||
|
||||
exports.MAX_CONCURRENT_STREAMS = Infinity
|
||||
|
||||
exports.frameType = {
|
||||
DATA: 0,
|
||||
HEADERS: 1,
|
||||
PRIORITY: 2,
|
||||
RST_STREAM: 3,
|
||||
SETTINGS: 4,
|
||||
PUSH_PROMISE: 5,
|
||||
PING: 6,
|
||||
GOAWAY: 7,
|
||||
WINDOW_UPDATE: 8,
|
||||
CONTINUATION: 9,
|
||||
|
||||
// Custom
|
||||
X_FORWARDED_FOR: 0xde
|
||||
}
|
||||
|
||||
exports.flags = {
|
||||
ACK: 0x01, // SETTINGS-only
|
||||
END_STREAM: 0x01,
|
||||
END_HEADERS: 0x04,
|
||||
PADDED: 0x08,
|
||||
PRIORITY: 0x20
|
||||
}
|
||||
|
||||
exports.settings = {
|
||||
SETTINGS_HEADER_TABLE_SIZE: 0x01,
|
||||
SETTINGS_ENABLE_PUSH: 0x02,
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS: 0x03,
|
||||
SETTINGS_INITIAL_WINDOW_SIZE: 0x04,
|
||||
SETTINGS_MAX_FRAME_SIZE: 0x05,
|
||||
SETTINGS_MAX_HEADER_LIST_SIZE: 0x06
|
||||
}
|
||||
|
||||
exports.settingsIndex = [
|
||||
null,
|
||||
'header_table_size',
|
||||
'enable_push',
|
||||
'max_concurrent_streams',
|
||||
'initial_window_size',
|
||||
'max_frame_size',
|
||||
'max_header_list_size'
|
||||
]
|
||||
|
||||
exports.error = {
|
||||
OK: 0,
|
||||
NO_ERROR: 0,
|
||||
|
||||
PROTOCOL_ERROR: 1,
|
||||
INTERNAL_ERROR: 2,
|
||||
FLOW_CONTROL_ERROR: 3,
|
||||
SETTINGS_TIMEOUT: 4,
|
||||
|
||||
STREAM_CLOSED: 5,
|
||||
INVALID_STREAM: 5,
|
||||
|
||||
FRAME_SIZE_ERROR: 6,
|
||||
REFUSED_STREAM: 7,
|
||||
CANCEL: 8,
|
||||
COMPRESSION_ERROR: 9,
|
||||
CONNECT_ERROR: 10,
|
||||
ENHANCE_YOUR_CALM: 11,
|
||||
INADEQUATE_SECURITY: 12,
|
||||
HTTP_1_1_REQUIRED: 13
|
||||
}
|
||||
exports.errorByCode = base.utils.reverse(exports.error)
|
||||
|
||||
exports.DEFAULT_WINDOW = 64 * 1024 - 1
|
||||
|
||||
exports.goaway = exports.error
|
||||
exports.goawayByCode = Object.assign({}, exports.errorByCode)
|
||||
exports.goawayByCode[0] = 'OK'
|
542
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/framer.js
generated
vendored
Executable file
542
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/framer.js
generated
vendored
Executable file
|
@ -0,0 +1,542 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var base = transport.protocol.base
|
||||
var constants = require('./').constants
|
||||
|
||||
var assert = require('assert')
|
||||
var util = require('util')
|
||||
var WriteBuffer = require('wbuf')
|
||||
var OffsetBuffer = require('obuf')
|
||||
var debug = require('debug')('spdy:framer')
|
||||
var debugExtra = require('debug')('spdy:framer:extra')
|
||||
|
||||
function Framer (options) {
|
||||
base.Framer.call(this, options)
|
||||
|
||||
this.maxFrameSize = constants.INITIAL_MAX_FRAME_SIZE
|
||||
}
|
||||
util.inherits(Framer, base.Framer)
|
||||
module.exports = Framer
|
||||
|
||||
Framer.create = function create (options) {
|
||||
return new Framer(options)
|
||||
}
|
||||
|
||||
Framer.prototype.setMaxFrameSize = function setMaxFrameSize (size) {
|
||||
this.maxFrameSize = size
|
||||
}
|
||||
|
||||
Framer.prototype._frame = function _frame (frame, body, callback) {
|
||||
debug('id=%d type=%s', frame.id, frame.type)
|
||||
|
||||
var buffer = new WriteBuffer()
|
||||
|
||||
buffer.reserve(constants.FRAME_HEADER_SIZE)
|
||||
var len = buffer.skip(3)
|
||||
buffer.writeUInt8(constants.frameType[frame.type])
|
||||
buffer.writeUInt8(frame.flags)
|
||||
buffer.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
|
||||
body(buffer)
|
||||
|
||||
var frameSize = buffer.size - constants.FRAME_HEADER_SIZE
|
||||
len.writeUInt24BE(frameSize)
|
||||
|
||||
var chunks = buffer.render()
|
||||
var toWrite = {
|
||||
stream: frame.id,
|
||||
priority: frame.priority === undefined ? false : frame.priority,
|
||||
chunks: chunks,
|
||||
callback: callback
|
||||
}
|
||||
|
||||
if (this.window && frame.type === 'DATA') {
|
||||
var self = this
|
||||
this._resetTimeout()
|
||||
this.window.send.update(-frameSize, function () {
|
||||
self._resetTimeout()
|
||||
self.schedule(toWrite)
|
||||
})
|
||||
} else {
|
||||
this._resetTimeout()
|
||||
this.schedule(toWrite)
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
Framer.prototype._split = function _split (frame) {
|
||||
var buf = new OffsetBuffer()
|
||||
for (var i = 0; i < frame.chunks.length; i++) { buf.push(frame.chunks[i]) }
|
||||
|
||||
var frames = []
|
||||
while (!buf.isEmpty()) {
|
||||
// First frame may have reserved bytes in it
|
||||
var size = this.maxFrameSize
|
||||
if (frames.length === 0) {
|
||||
size -= frame.reserve
|
||||
}
|
||||
size = Math.min(size, buf.size)
|
||||
|
||||
var frameBuf = buf.clone(size)
|
||||
buf.skip(size)
|
||||
|
||||
frames.push({
|
||||
size: frameBuf.size,
|
||||
chunks: frameBuf.toChunks()
|
||||
})
|
||||
}
|
||||
|
||||
return frames
|
||||
}
|
||||
|
||||
Framer.prototype._continuationFrame = function _continuationFrame (frame,
|
||||
body,
|
||||
callback) {
|
||||
var frames = this._split(frame)
|
||||
|
||||
frames.forEach(function (subFrame, i) {
|
||||
var isFirst = i === 0
|
||||
var isLast = i === frames.length - 1
|
||||
|
||||
var flags = isLast ? constants.flags.END_HEADERS : 0
|
||||
|
||||
// PRIORITY and friends
|
||||
if (isFirst) {
|
||||
flags |= frame.flags
|
||||
}
|
||||
|
||||
this._frame({
|
||||
id: frame.id,
|
||||
priority: false,
|
||||
type: isFirst ? frame.type : 'CONTINUATION',
|
||||
flags: flags
|
||||
}, function (buf) {
|
||||
// Fill those reserved bytes
|
||||
if (isFirst && body) { body(buf) }
|
||||
|
||||
buf.reserve(subFrame.size)
|
||||
for (var i = 0; i < subFrame.chunks.length; i++) { buf.copyFrom(subFrame.chunks[i]) }
|
||||
}, isLast ? callback : null)
|
||||
}, this)
|
||||
|
||||
if (frames.length === 0) {
|
||||
this._frame({
|
||||
id: frame.id,
|
||||
priority: false,
|
||||
type: frame.type,
|
||||
flags: frame.flags | constants.flags.END_HEADERS
|
||||
}, function (buf) {
|
||||
if (body) { body(buf) }
|
||||
}, callback)
|
||||
}
|
||||
}
|
||||
|
||||
Framer.prototype._compressHeaders = function _compressHeaders (headers,
|
||||
pairs,
|
||||
callback) {
|
||||
Object.keys(headers || {}).forEach(function (name) {
|
||||
var lowName = name.toLowerCase()
|
||||
|
||||
// Not allowed in HTTP2
|
||||
switch (lowName) {
|
||||
case 'host':
|
||||
case 'connection':
|
||||
case 'keep-alive':
|
||||
case 'proxy-connection':
|
||||
case 'transfer-encoding':
|
||||
case 'upgrade':
|
||||
return
|
||||
}
|
||||
|
||||
// Should be in `pairs`
|
||||
if (/^:/.test(lowName)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Do not compress, or index Cookie field (for security reasons)
|
||||
var neverIndex = lowName === 'cookie' || lowName === 'set-cookie'
|
||||
|
||||
var value = headers[name]
|
||||
if (Array.isArray(value)) {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
pairs.push({
|
||||
name: lowName,
|
||||
value: value[i] + '',
|
||||
neverIndex: neverIndex,
|
||||
huffman: !neverIndex
|
||||
})
|
||||
}
|
||||
} else {
|
||||
pairs.push({
|
||||
name: lowName,
|
||||
value: value + '',
|
||||
neverIndex: neverIndex,
|
||||
huffman: !neverIndex
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
assert(this.compress !== null, 'Framer version not initialized')
|
||||
debugExtra('compressing headers=%j', pairs)
|
||||
this.compress.write([ pairs ], callback)
|
||||
}
|
||||
|
||||
Framer.prototype._isDefaultPriority = function _isDefaultPriority (priority) {
|
||||
if (!priority) { return true }
|
||||
|
||||
return !priority.parent &&
|
||||
priority.weight === constants.DEFAULT &&
|
||||
!priority.exclusive
|
||||
}
|
||||
|
||||
Framer.prototype._defaultHeaders = function _defaultHeaders (frame, pairs) {
|
||||
if (!frame.path) {
|
||||
throw new Error('`path` is required frame argument')
|
||||
}
|
||||
|
||||
pairs.push({
|
||||
name: ':method',
|
||||
value: frame.method || base.constants.DEFAULT_METHOD
|
||||
})
|
||||
pairs.push({ name: ':path', value: frame.path })
|
||||
pairs.push({ name: ':scheme', value: frame.scheme || 'https' })
|
||||
pairs.push({
|
||||
name: ':authority',
|
||||
value: frame.host ||
|
||||
(frame.headers && frame.headers.host) ||
|
||||
base.constants.DEFAULT_HOST
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype._headersFrame = function _headersFrame (kind, frame, callback) {
|
||||
var pairs = []
|
||||
|
||||
if (kind === 'request') {
|
||||
this._defaultHeaders(frame, pairs)
|
||||
} else if (kind === 'response') {
|
||||
pairs.push({ name: ':status', value: (frame.status || 200) + '' })
|
||||
}
|
||||
|
||||
var self = this
|
||||
this._compressHeaders(frame.headers, pairs, function (err, chunks) {
|
||||
if (err) {
|
||||
if (callback) {
|
||||
return callback(err)
|
||||
} else {
|
||||
return self.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
var reserve = 0
|
||||
|
||||
// If priority info is present, and the values are not default ones
|
||||
// reserve space for the priority info and add PRIORITY flag
|
||||
var priority = frame.priority
|
||||
if (!self._isDefaultPriority(priority)) { reserve = 5 }
|
||||
|
||||
var flags = reserve === 0 ? 0 : constants.flags.PRIORITY
|
||||
|
||||
// Mostly for testing
|
||||
if (frame.fin) {
|
||||
flags |= constants.flags.END_STREAM
|
||||
}
|
||||
|
||||
self._continuationFrame({
|
||||
id: frame.id,
|
||||
type: 'HEADERS',
|
||||
flags: flags,
|
||||
reserve: reserve,
|
||||
chunks: chunks
|
||||
}, function (buf) {
|
||||
if (reserve === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
buf.writeUInt32BE(((priority.exclusive ? 0x80000000 : 0) |
|
||||
priority.parent) >>> 0)
|
||||
buf.writeUInt8((priority.weight | 0) - 1)
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.requestFrame = function requestFrame (frame, callback) {
|
||||
return this._headersFrame('request', frame, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.responseFrame = function responseFrame (frame, callback) {
|
||||
return this._headersFrame('response', frame, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.headersFrame = function headersFrame (frame, callback) {
|
||||
return this._headersFrame('headers', frame, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.pushFrame = function pushFrame (frame, callback) {
|
||||
var self = this
|
||||
|
||||
function compress (headers, pairs, callback) {
|
||||
self._compressHeaders(headers, pairs, function (err, chunks) {
|
||||
if (err) {
|
||||
if (callback) {
|
||||
return callback(err)
|
||||
} else {
|
||||
return self.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
callback(chunks)
|
||||
})
|
||||
}
|
||||
|
||||
function sendPromise (chunks) {
|
||||
self._continuationFrame({
|
||||
id: frame.id,
|
||||
type: 'PUSH_PROMISE',
|
||||
reserve: 4,
|
||||
chunks: chunks
|
||||
}, function (buf) {
|
||||
buf.writeUInt32BE(frame.promisedId)
|
||||
})
|
||||
}
|
||||
|
||||
function sendResponse (chunks, callback) {
|
||||
var priority = frame.priority
|
||||
var isDefaultPriority = self._isDefaultPriority(priority)
|
||||
var flags = isDefaultPriority ? 0 : constants.flags.PRIORITY
|
||||
|
||||
// Mostly for testing
|
||||
if (frame.fin) {
|
||||
flags |= constants.flags.END_STREAM
|
||||
}
|
||||
|
||||
self._continuationFrame({
|
||||
id: frame.promisedId,
|
||||
type: 'HEADERS',
|
||||
flags: flags,
|
||||
reserve: isDefaultPriority ? 0 : 5,
|
||||
chunks: chunks
|
||||
}, function (buf) {
|
||||
if (isDefaultPriority) {
|
||||
return
|
||||
}
|
||||
|
||||
buf.writeUInt32BE((priority.exclusive ? 0x80000000 : 0) |
|
||||
priority.parent)
|
||||
buf.writeUInt8((priority.weight | 0) - 1)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
this._checkPush(function (err) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
var pairs = {
|
||||
promise: [],
|
||||
response: []
|
||||
}
|
||||
|
||||
self._defaultHeaders(frame, pairs.promise)
|
||||
pairs.response.push({ name: ':status', value: (frame.status || 200) + '' })
|
||||
|
||||
compress(frame.headers, pairs.promise, function (promiseChunks) {
|
||||
sendPromise(promiseChunks)
|
||||
if (frame.response === false) {
|
||||
return callback(null)
|
||||
}
|
||||
compress(frame.response, pairs.response, function (responseChunks) {
|
||||
sendResponse(responseChunks, callback)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.priorityFrame = function priorityFrame (frame, callback) {
|
||||
this._frame({
|
||||
id: frame.id,
|
||||
priority: false,
|
||||
type: 'PRIORITY',
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
var priority = frame.priority
|
||||
buf.writeUInt32BE((priority.exclusive ? 0x80000000 : 0) |
|
||||
priority.parent)
|
||||
buf.writeUInt8((priority.weight | 0) - 1)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.dataFrame = function dataFrame (frame, callback) {
|
||||
var frames = this._split({
|
||||
reserve: 0,
|
||||
chunks: [ frame.data ]
|
||||
})
|
||||
|
||||
var fin = frame.fin ? constants.flags.END_STREAM : 0
|
||||
|
||||
var self = this
|
||||
frames.forEach(function (subFrame, i) {
|
||||
var isLast = i === frames.length - 1
|
||||
var flags = 0
|
||||
if (isLast) {
|
||||
flags |= fin
|
||||
}
|
||||
|
||||
self._frame({
|
||||
id: frame.id,
|
||||
priority: frame.priority,
|
||||
type: 'DATA',
|
||||
flags: flags
|
||||
}, function (buf) {
|
||||
buf.reserve(subFrame.size)
|
||||
for (var i = 0; i < subFrame.chunks.length; i++) { buf.copyFrom(subFrame.chunks[i]) }
|
||||
}, isLast ? callback : null)
|
||||
})
|
||||
|
||||
// Empty DATA
|
||||
if (frames.length === 0) {
|
||||
this._frame({
|
||||
id: frame.id,
|
||||
priority: frame.priority,
|
||||
type: 'DATA',
|
||||
flags: fin
|
||||
}, function (buf) {
|
||||
// No-op
|
||||
}, callback)
|
||||
}
|
||||
}
|
||||
|
||||
Framer.prototype.pingFrame = function pingFrame (frame, callback) {
|
||||
this._frame({
|
||||
id: 0,
|
||||
type: 'PING',
|
||||
flags: frame.ack ? constants.flags.ACK : 0
|
||||
}, function (buf) {
|
||||
buf.copyFrom(frame.opaque)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.rstFrame = function rstFrame (frame, callback) {
|
||||
this._frame({
|
||||
id: frame.id,
|
||||
type: 'RST_STREAM',
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.writeUInt32BE(constants.error[frame.code])
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.prefaceFrame = function prefaceFrame (callback) {
|
||||
debug('preface')
|
||||
this._resetTimeout()
|
||||
this.schedule({
|
||||
stream: 0,
|
||||
priority: false,
|
||||
chunks: [ constants.PREFACE_BUFFER ],
|
||||
callback: callback
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.settingsFrame = function settingsFrame (options, callback) {
|
||||
var key = JSON.stringify(options)
|
||||
|
||||
var settings = Framer.settingsCache[key]
|
||||
if (settings) {
|
||||
debug('cached settings')
|
||||
this._resetTimeout()
|
||||
this.schedule({
|
||||
id: 0,
|
||||
priority: false,
|
||||
chunks: settings,
|
||||
callback: callback
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var params = []
|
||||
for (var i = 0; i < constants.settingsIndex.length; i++) {
|
||||
var name = constants.settingsIndex[i]
|
||||
if (!name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// value: Infinity
|
||||
if (!isFinite(options[name])) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (options[name] !== undefined) {
|
||||
params.push({ key: i, value: options[name] })
|
||||
}
|
||||
}
|
||||
|
||||
var bodySize = params.length * 6
|
||||
|
||||
var chunks = this._frame({
|
||||
id: 0,
|
||||
type: 'SETTINGS',
|
||||
flags: 0
|
||||
}, function (buffer) {
|
||||
buffer.reserve(bodySize)
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i]
|
||||
|
||||
buffer.writeUInt16BE(param.key)
|
||||
buffer.writeUInt32BE(param.value)
|
||||
}
|
||||
}, callback)
|
||||
|
||||
Framer.settingsCache[key] = chunks
|
||||
}
|
||||
Framer.settingsCache = {}
|
||||
|
||||
Framer.prototype.ackSettingsFrame = function ackSettingsFrame (callback) {
|
||||
/* var chunks = */ this._frame({
|
||||
id: 0,
|
||||
type: 'SETTINGS',
|
||||
flags: constants.flags.ACK
|
||||
}, function (buffer) {
|
||||
// No-op
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.windowUpdateFrame = function windowUpdateFrame (frame,
|
||||
callback) {
|
||||
this._frame({
|
||||
id: frame.id,
|
||||
type: 'WINDOW_UPDATE',
|
||||
flags: 0
|
||||
}, function (buffer) {
|
||||
buffer.reserve(4)
|
||||
buffer.writeInt32BE(frame.delta)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.goawayFrame = function goawayFrame (frame, callback) {
|
||||
this._frame({
|
||||
type: 'GOAWAY',
|
||||
id: 0,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(8)
|
||||
|
||||
// Last-good-stream-ID
|
||||
buf.writeUInt32BE(frame.lastId & 0x7fffffff)
|
||||
// Code
|
||||
buf.writeUInt32BE(constants.goaway[frame.code])
|
||||
|
||||
// Extra debugging information
|
||||
if (frame.extra) { buf.write(frame.extra) }
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.xForwardedFor = function xForwardedFor (frame, callback) {
|
||||
this._frame({
|
||||
type: 'X_FORWARDED_FOR',
|
||||
id: 0,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.write(frame.host)
|
||||
}, callback)
|
||||
}
|
34
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/hpack-pool.js
generated
vendored
Executable file
34
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/hpack-pool.js
generated
vendored
Executable file
|
@ -0,0 +1,34 @@
|
|||
'use strict'
|
||||
|
||||
var constants = require('./').constants
|
||||
|
||||
var hpack = require('hpack.js')
|
||||
|
||||
function Pool () {
|
||||
}
|
||||
module.exports = Pool
|
||||
|
||||
Pool.create = function create () {
|
||||
return new Pool()
|
||||
}
|
||||
|
||||
Pool.prototype.get = function get (version) {
|
||||
var options = {
|
||||
table: {
|
||||
maxSize: constants.HEADER_TABLE_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
var compress = hpack.compressor.create(options)
|
||||
var decompress = hpack.decompressor.create(options)
|
||||
|
||||
return {
|
||||
version: version,
|
||||
|
||||
compress: compress,
|
||||
decompress: decompress
|
||||
}
|
||||
}
|
||||
|
||||
Pool.prototype.put = function put () {
|
||||
}
|
8
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/index.js
generated
vendored
Executable file
8
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/index.js
generated
vendored
Executable file
|
@ -0,0 +1,8 @@
|
|||
'use strict'
|
||||
|
||||
exports.name = 'h2'
|
||||
|
||||
exports.constants = require('./constants')
|
||||
exports.parser = require('./parser')
|
||||
exports.framer = require('./framer')
|
||||
exports.compressionPool = require('./hpack-pool')
|
578
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/parser.js
generated
vendored
Executable file
578
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/http2/parser.js
generated
vendored
Executable file
|
@ -0,0 +1,578 @@
|
|||
'use strict'
|
||||
|
||||
var parser = exports
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var base = transport.protocol.base
|
||||
var utils = base.utils
|
||||
var constants = require('./').constants
|
||||
|
||||
var assert = require('assert')
|
||||
var util = require('util')
|
||||
|
||||
function Parser (options) {
|
||||
base.Parser.call(this, options)
|
||||
|
||||
this.isServer = options.isServer
|
||||
|
||||
this.waiting = constants.PREFACE_SIZE
|
||||
this.state = 'preface'
|
||||
this.pendingHeader = null
|
||||
|
||||
// Header Block queue
|
||||
this._lastHeaderBlock = null
|
||||
this.maxFrameSize = constants.INITIAL_MAX_FRAME_SIZE
|
||||
this.maxHeaderListSize = constants.DEFAULT_MAX_HEADER_LIST_SIZE
|
||||
}
|
||||
util.inherits(Parser, base.Parser)
|
||||
|
||||
parser.create = function create (options) {
|
||||
return new Parser(options)
|
||||
}
|
||||
|
||||
Parser.prototype.setMaxFrameSize = function setMaxFrameSize (size) {
|
||||
this.maxFrameSize = size
|
||||
}
|
||||
|
||||
Parser.prototype.setMaxHeaderListSize = function setMaxHeaderListSize (size) {
|
||||
this.maxHeaderListSize = size
|
||||
}
|
||||
|
||||
// Only for testing
|
||||
Parser.prototype.skipPreface = function skipPreface () {
|
||||
// Just some number bigger than 3.1, doesn't really matter for HTTP2
|
||||
this.setVersion(4)
|
||||
|
||||
// Parse frame header!
|
||||
this.state = 'frame-head'
|
||||
this.waiting = constants.FRAME_HEADER_SIZE
|
||||
}
|
||||
|
||||
Parser.prototype.execute = function execute (buffer, callback) {
|
||||
if (this.state === 'preface') { return this.onPreface(buffer, callback) }
|
||||
|
||||
if (this.state === 'frame-head') {
|
||||
return this.onFrameHead(buffer, callback)
|
||||
}
|
||||
|
||||
assert(this.state === 'frame-body' && this.pendingHeader !== null)
|
||||
|
||||
var self = this
|
||||
var header = this.pendingHeader
|
||||
this.pendingHeader = null
|
||||
|
||||
this.onFrameBody(header, buffer, function (err, frame) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
self.state = 'frame-head'
|
||||
self.partial = false
|
||||
self.waiting = constants.FRAME_HEADER_SIZE
|
||||
callback(null, frame)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.executePartial = function executePartial (buffer, callback) {
|
||||
var header = this.pendingHeader
|
||||
|
||||
assert.strictEqual(header.flags & constants.flags.PADDED, 0)
|
||||
|
||||
if (this.window) { this.window.recv.update(-buffer.size) }
|
||||
|
||||
callback(null, {
|
||||
type: 'DATA',
|
||||
id: header.id,
|
||||
|
||||
// Partial DATA can't be FIN
|
||||
fin: false,
|
||||
data: buffer.take(buffer.size)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onPreface = function onPreface (buffer, callback) {
|
||||
if (buffer.take(buffer.size).toString() !== constants.PREFACE) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid preface'))
|
||||
}
|
||||
|
||||
this.skipPreface()
|
||||
callback(null, null)
|
||||
}
|
||||
|
||||
Parser.prototype.onFrameHead = function onFrameHead (buffer, callback) {
|
||||
var header = {
|
||||
length: buffer.readUInt24BE(),
|
||||
control: true,
|
||||
type: buffer.readUInt8(),
|
||||
flags: buffer.readUInt8(),
|
||||
id: buffer.readUInt32BE() & 0x7fffffff
|
||||
}
|
||||
|
||||
if (header.length > this.maxFrameSize) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'Frame length OOB'))
|
||||
}
|
||||
|
||||
header.control = header.type !== constants.frameType.DATA
|
||||
|
||||
this.state = 'frame-body'
|
||||
this.pendingHeader = header
|
||||
this.waiting = header.length
|
||||
this.partial = !header.control
|
||||
|
||||
// TODO(indutny): eventually support partial padded DATA
|
||||
if (this.partial) {
|
||||
this.partial = (header.flags & constants.flags.PADDED) === 0
|
||||
}
|
||||
|
||||
callback(null, null)
|
||||
}
|
||||
|
||||
Parser.prototype.onFrameBody = function onFrameBody (header, buffer, callback) {
|
||||
var frameType = constants.frameType
|
||||
|
||||
if (header.type === frameType.DATA) {
|
||||
this.onDataFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.HEADERS) {
|
||||
this.onHeadersFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.CONTINUATION) {
|
||||
this.onContinuationFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.WINDOW_UPDATE) {
|
||||
this.onWindowUpdateFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.RST_STREAM) {
|
||||
this.onRSTFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.SETTINGS) {
|
||||
this.onSettingsFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.PUSH_PROMISE) {
|
||||
this.onPushPromiseFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.PING) {
|
||||
this.onPingFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.GOAWAY) {
|
||||
this.onGoawayFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.PRIORITY) {
|
||||
this.onPriorityFrame(header, buffer, callback)
|
||||
} else if (header.type === frameType.X_FORWARDED_FOR) {
|
||||
this.onXForwardedFrame(header, buffer, callback)
|
||||
} else {
|
||||
this.onUnknownFrame(header, buffer, callback)
|
||||
}
|
||||
}
|
||||
|
||||
Parser.prototype.onUnknownFrame = function onUnknownFrame (header, buffer, callback) {
|
||||
if (this._lastHeaderBlock !== null) {
|
||||
callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Received unknown frame in the middle of a header block'))
|
||||
return
|
||||
}
|
||||
callback(null, { type: 'unknown: ' + header.type })
|
||||
}
|
||||
|
||||
Parser.prototype.unpadData = function unpadData (header, body, callback) {
|
||||
var isPadded = (header.flags & constants.flags.PADDED) !== 0
|
||||
|
||||
if (!isPadded) { return callback(null, body) }
|
||||
|
||||
if (!body.has(1)) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'Not enough space for padding'))
|
||||
}
|
||||
|
||||
var pad = body.readUInt8()
|
||||
if (!body.has(pad)) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid padding size'))
|
||||
}
|
||||
|
||||
var contents = body.clone(body.size - pad)
|
||||
body.skip(body.size)
|
||||
callback(null, contents)
|
||||
}
|
||||
|
||||
Parser.prototype.onDataFrame = function onDataFrame (header, body, callback) {
|
||||
var isEndStream = (header.flags & constants.flags.END_STREAM) !== 0
|
||||
|
||||
if (header.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Received DATA frame with stream=0'))
|
||||
}
|
||||
|
||||
// Count received bytes
|
||||
if (this.window) {
|
||||
this.window.recv.update(-body.size)
|
||||
}
|
||||
|
||||
this.unpadData(header, body, function (err, data) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'DATA',
|
||||
id: header.id,
|
||||
fin: isEndStream,
|
||||
data: data.take(data.size)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.initHeaderBlock = function initHeaderBlock (header,
|
||||
frame,
|
||||
block,
|
||||
callback) {
|
||||
if (this._lastHeaderBlock) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Duplicate Stream ID'))
|
||||
}
|
||||
|
||||
this._lastHeaderBlock = {
|
||||
id: header.id,
|
||||
frame: frame,
|
||||
queue: [],
|
||||
size: 0
|
||||
}
|
||||
|
||||
this.queueHeaderBlock(header, block, callback)
|
||||
}
|
||||
|
||||
Parser.prototype.queueHeaderBlock = function queueHeaderBlock (header,
|
||||
block,
|
||||
callback) {
|
||||
var self = this
|
||||
var item = this._lastHeaderBlock
|
||||
if (!this._lastHeaderBlock || item.id !== header.id) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'No matching stream for continuation'))
|
||||
}
|
||||
|
||||
var fin = (header.flags & constants.flags.END_HEADERS) !== 0
|
||||
|
||||
var chunks = block.toChunks()
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
var chunk = chunks[i]
|
||||
item.queue.push(chunk)
|
||||
item.size += chunk.length
|
||||
}
|
||||
|
||||
if (item.size >= self.maxHeaderListSize) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Compressed header list is too large'))
|
||||
}
|
||||
|
||||
if (!fin) { return callback(null, null) }
|
||||
this._lastHeaderBlock = null
|
||||
|
||||
this.decompress.write(item.queue, function (err, chunks) {
|
||||
if (err) {
|
||||
return callback(self.error(constants.error.COMPRESSION_ERROR,
|
||||
err.message))
|
||||
}
|
||||
|
||||
var headers = {}
|
||||
var size = 0
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
var header = chunks[i]
|
||||
|
||||
size += header.name.length + header.value.length + 32
|
||||
if (size >= self.maxHeaderListSize) {
|
||||
return callback(self.error(constants.error.PROTOCOL_ERROR,
|
||||
'Header list is too large'))
|
||||
}
|
||||
|
||||
if (/[A-Z]/.test(header.name)) {
|
||||
return callback(self.error(constants.error.PROTOCOL_ERROR,
|
||||
'Header name must be lowercase'))
|
||||
}
|
||||
|
||||
utils.addHeaderLine(header.name, header.value, headers)
|
||||
}
|
||||
|
||||
item.frame.headers = headers
|
||||
item.frame.path = headers[':path']
|
||||
|
||||
callback(null, item.frame)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onHeadersFrame = function onHeadersFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
var self = this
|
||||
|
||||
if (header.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for HEADERS'))
|
||||
}
|
||||
|
||||
this.unpadData(header, body, function (err, data) {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
var isPriority = (header.flags & constants.flags.PRIORITY) !== 0
|
||||
if (!data.has(isPriority ? 5 : 0)) {
|
||||
return callback(self.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'Not enough data for HEADERS'))
|
||||
}
|
||||
|
||||
var exclusive = false
|
||||
var dependency = 0
|
||||
var weight = constants.DEFAULT_WEIGHT
|
||||
if (isPriority) {
|
||||
dependency = data.readUInt32BE()
|
||||
exclusive = (dependency & 0x80000000) !== 0
|
||||
dependency &= 0x7fffffff
|
||||
|
||||
// Weight's range is [1, 256]
|
||||
weight = data.readUInt8() + 1
|
||||
}
|
||||
|
||||
if (dependency === header.id) {
|
||||
return callback(self.error(constants.error.PROTOCOL_ERROR,
|
||||
'Stream can\'t dependend on itself'))
|
||||
}
|
||||
|
||||
var streamInfo = {
|
||||
type: 'HEADERS',
|
||||
id: header.id,
|
||||
priority: {
|
||||
parent: dependency,
|
||||
exclusive: exclusive,
|
||||
weight: weight
|
||||
},
|
||||
fin: (header.flags & constants.flags.END_STREAM) !== 0,
|
||||
writable: true,
|
||||
headers: null,
|
||||
path: null
|
||||
}
|
||||
|
||||
self.initHeaderBlock(header, streamInfo, data, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onContinuationFrame = function onContinuationFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
this.queueHeaderBlock(header, body, callback)
|
||||
}
|
||||
|
||||
Parser.prototype.onRSTFrame = function onRSTFrame (header, body, callback) {
|
||||
if (body.size !== 4) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'RST_STREAM length not 4'))
|
||||
}
|
||||
|
||||
if (header.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for RST_STREAM'))
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'RST',
|
||||
id: header.id,
|
||||
code: constants.errorByCode[body.readUInt32BE()]
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype._validateSettings = function _validateSettings (settings) {
|
||||
if (settings['enable_push'] !== undefined &&
|
||||
settings['enable_push'] !== 0 &&
|
||||
settings['enable_push'] !== 1) {
|
||||
return this.error(constants.error.PROTOCOL_ERROR,
|
||||
'SETTINGS_ENABLE_PUSH must be 0 or 1')
|
||||
}
|
||||
|
||||
if (settings['initial_window_size'] !== undefined &&
|
||||
(settings['initial_window_size'] > constants.MAX_INITIAL_WINDOW_SIZE ||
|
||||
settings['initial_window_size'] < 0)) {
|
||||
return this.error(constants.error.FLOW_CONTROL_ERROR,
|
||||
'SETTINGS_INITIAL_WINDOW_SIZE is OOB')
|
||||
}
|
||||
|
||||
if (settings['max_frame_size'] !== undefined &&
|
||||
(settings['max_frame_size'] > constants.ABSOLUTE_MAX_FRAME_SIZE ||
|
||||
settings['max_frame_size'] < constants.INITIAL_MAX_FRAME_SIZE)) {
|
||||
return this.error(constants.error.PROTOCOL_ERROR,
|
||||
'SETTINGS_MAX_FRAME_SIZE is OOB')
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
Parser.prototype.onSettingsFrame = function onSettingsFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
if (header.id !== 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for SETTINGS'))
|
||||
}
|
||||
|
||||
var isAck = (header.flags & constants.flags.ACK) !== 0
|
||||
if (isAck && body.size !== 0) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'SETTINGS with ACK and non-zero length'))
|
||||
}
|
||||
|
||||
if (isAck) {
|
||||
return callback(null, { type: 'ACK_SETTINGS' })
|
||||
}
|
||||
|
||||
if (body.size % 6 !== 0) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'SETTINGS length not multiple of 6'))
|
||||
}
|
||||
|
||||
var settings = {}
|
||||
while (!body.isEmpty()) {
|
||||
var id = body.readUInt16BE()
|
||||
var value = body.readUInt32BE()
|
||||
var name = constants.settingsIndex[id]
|
||||
|
||||
if (name) {
|
||||
settings[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
var err = this._validateSettings(settings)
|
||||
if (err !== undefined) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'SETTINGS',
|
||||
settings: settings
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onPushPromiseFrame = function onPushPromiseFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
if (header.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for PUSH_PROMISE'))
|
||||
}
|
||||
|
||||
var self = this
|
||||
this.unpadData(header, body, function (err, data) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
if (!data.has(4)) {
|
||||
return callback(self.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'PUSH_PROMISE length less than 4'))
|
||||
}
|
||||
|
||||
var streamInfo = {
|
||||
type: 'PUSH_PROMISE',
|
||||
id: header.id,
|
||||
fin: false,
|
||||
promisedId: data.readUInt32BE() & 0x7fffffff,
|
||||
headers: null,
|
||||
path: null
|
||||
}
|
||||
|
||||
self.initHeaderBlock(header, streamInfo, data, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onPingFrame = function onPingFrame (header, body, callback) {
|
||||
if (body.size !== 8) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'PING length != 8'))
|
||||
}
|
||||
|
||||
if (header.id !== 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for PING'))
|
||||
}
|
||||
|
||||
var ack = (header.flags & constants.flags.ACK) !== 0
|
||||
callback(null, { type: 'PING', opaque: body.take(body.size), ack: ack })
|
||||
}
|
||||
|
||||
Parser.prototype.onGoawayFrame = function onGoawayFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
if (!body.has(8)) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'GOAWAY length < 8'))
|
||||
}
|
||||
|
||||
if (header.id !== 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for GOAWAY'))
|
||||
}
|
||||
|
||||
var frame = {
|
||||
type: 'GOAWAY',
|
||||
lastId: body.readUInt32BE(),
|
||||
code: constants.goawayByCode[body.readUInt32BE()]
|
||||
}
|
||||
|
||||
if (body.size !== 0) { frame.debug = body.take(body.size) }
|
||||
|
||||
callback(null, frame)
|
||||
}
|
||||
|
||||
Parser.prototype.onPriorityFrame = function onPriorityFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
if (body.size !== 5) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'PRIORITY length != 5'))
|
||||
}
|
||||
|
||||
if (header.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for PRIORITY'))
|
||||
}
|
||||
|
||||
var dependency = body.readUInt32BE()
|
||||
|
||||
// Again the range is from 1 to 256
|
||||
var weight = body.readUInt8() + 1
|
||||
|
||||
if (dependency === header.id) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Stream can\'t dependend on itself'))
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'PRIORITY',
|
||||
id: header.id,
|
||||
priority: {
|
||||
exclusive: (dependency & 0x80000000) !== 0,
|
||||
parent: dependency & 0x7fffffff,
|
||||
weight: weight
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onWindowUpdateFrame = function onWindowUpdateFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
if (body.size !== 4) {
|
||||
return callback(this.error(constants.error.FRAME_SIZE_ERROR,
|
||||
'WINDOW_UPDATE length != 4'))
|
||||
}
|
||||
|
||||
var delta = body.readInt32BE()
|
||||
if (delta === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'WINDOW_UPDATE delta == 0'))
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'WINDOW_UPDATE',
|
||||
id: header.id,
|
||||
delta: delta
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onXForwardedFrame = function onXForwardedFrame (header,
|
||||
body,
|
||||
callback) {
|
||||
callback(null, {
|
||||
type: 'X_FORWARDED_FOR',
|
||||
host: body.take(body.size).toString()
|
||||
})
|
||||
}
|
146
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/constants.js
generated
vendored
Executable file
146
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/constants.js
generated
vendored
Executable file
|
@ -0,0 +1,146 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var base = transport.protocol.base
|
||||
|
||||
exports.FRAME_HEADER_SIZE = 8
|
||||
|
||||
exports.PING_OPAQUE_SIZE = 4
|
||||
|
||||
exports.MAX_CONCURRENT_STREAMS = Infinity
|
||||
exports.DEFAULT_MAX_HEADER_LIST_SIZE = Infinity
|
||||
|
||||
exports.DEFAULT_WEIGHT = 16
|
||||
|
||||
exports.frameType = {
|
||||
SYN_STREAM: 1,
|
||||
SYN_REPLY: 2,
|
||||
RST_STREAM: 3,
|
||||
SETTINGS: 4,
|
||||
PING: 6,
|
||||
GOAWAY: 7,
|
||||
HEADERS: 8,
|
||||
WINDOW_UPDATE: 9,
|
||||
|
||||
// Custom
|
||||
X_FORWARDED_FOR: 0xf000
|
||||
}
|
||||
|
||||
exports.flags = {
|
||||
FLAG_FIN: 0x01,
|
||||
FLAG_COMPRESSED: 0x02,
|
||||
FLAG_UNIDIRECTIONAL: 0x02
|
||||
}
|
||||
|
||||
exports.error = {
|
||||
PROTOCOL_ERROR: 1,
|
||||
INVALID_STREAM: 2,
|
||||
REFUSED_STREAM: 3,
|
||||
UNSUPPORTED_VERSION: 4,
|
||||
CANCEL: 5,
|
||||
INTERNAL_ERROR: 6,
|
||||
FLOW_CONTROL_ERROR: 7,
|
||||
STREAM_IN_USE: 8,
|
||||
// STREAM_ALREADY_CLOSED: 9
|
||||
STREAM_CLOSED: 9,
|
||||
INVALID_CREDENTIALS: 10,
|
||||
FRAME_TOO_LARGE: 11
|
||||
}
|
||||
exports.errorByCode = base.utils.reverse(exports.error)
|
||||
|
||||
exports.settings = {
|
||||
FLAG_SETTINGS_PERSIST_VALUE: 1,
|
||||
FLAG_SETTINGS_PERSISTED: 2,
|
||||
|
||||
SETTINGS_UPLOAD_BANDWIDTH: 1,
|
||||
SETTINGS_DOWNLOAD_BANDWIDTH: 2,
|
||||
SETTINGS_ROUND_TRIP_TIME: 3,
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS: 4,
|
||||
SETTINGS_CURRENT_CWND: 5,
|
||||
SETTINGS_DOWNLOAD_RETRANS_RATE: 6,
|
||||
SETTINGS_INITIAL_WINDOW_SIZE: 7,
|
||||
SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE: 8
|
||||
}
|
||||
|
||||
exports.settingsIndex = [
|
||||
null,
|
||||
|
||||
'upload_bandwidth',
|
||||
'download_bandwidth',
|
||||
'round_trip_time',
|
||||
'max_concurrent_streams',
|
||||
'current_cwnd',
|
||||
'download_retrans_rate',
|
||||
'initial_window_size',
|
||||
'client_certificate_vector_size'
|
||||
]
|
||||
|
||||
exports.DEFAULT_WINDOW = 64 * 1024
|
||||
exports.MAX_INITIAL_WINDOW_SIZE = 2147483647
|
||||
|
||||
exports.goaway = {
|
||||
OK: 0,
|
||||
PROTOCOL_ERROR: 1,
|
||||
INTERNAL_ERROR: 2
|
||||
}
|
||||
exports.goawayByCode = base.utils.reverse(exports.goaway)
|
||||
|
||||
exports.statusReason = {
|
||||
100: 'Continue',
|
||||
101: 'Switching Protocols',
|
||||
102: 'Processing', // RFC 2518, obsoleted by RFC 4918
|
||||
200: 'OK',
|
||||
201: 'Created',
|
||||
202: 'Accepted',
|
||||
203: 'Non-Authoritative Information',
|
||||
204: 'No Content',
|
||||
205: 'Reset Content',
|
||||
206: 'Partial Content',
|
||||
207: 'Multi-Status', // RFC 4918
|
||||
300: 'Multiple Choices',
|
||||
301: 'Moved Permanently',
|
||||
302: 'Moved Temporarily',
|
||||
303: 'See Other',
|
||||
304: 'Not Modified',
|
||||
305: 'Use Proxy',
|
||||
307: 'Temporary Redirect',
|
||||
308: 'Permanent Redirect', // RFC 7238
|
||||
400: 'Bad Request',
|
||||
401: 'Unauthorized',
|
||||
402: 'Payment Required',
|
||||
403: 'Forbidden',
|
||||
404: 'Not Found',
|
||||
405: 'Method Not Allowed',
|
||||
406: 'Not Acceptable',
|
||||
407: 'Proxy Authentication Required',
|
||||
408: 'Request Time-out',
|
||||
409: 'Conflict',
|
||||
410: 'Gone',
|
||||
411: 'Length Required',
|
||||
412: 'Precondition Failed',
|
||||
413: 'Request Entity Too Large',
|
||||
414: 'Request-URI Too Large',
|
||||
415: 'Unsupported Media Type',
|
||||
416: 'Requested Range Not Satisfiable',
|
||||
417: 'Expectation Failed',
|
||||
418: 'I\'m a teapot', // RFC 2324
|
||||
422: 'Unprocessable Entity', // RFC 4918
|
||||
423: 'Locked', // RFC 4918
|
||||
424: 'Failed Dependency', // RFC 4918
|
||||
425: 'Unordered Collection', // RFC 4918
|
||||
426: 'Upgrade Required', // RFC 2817
|
||||
428: 'Precondition Required', // RFC 6585
|
||||
429: 'Too Many Requests', // RFC 6585
|
||||
431: 'Request Header Fields Too Large', // RFC 6585
|
||||
500: 'Internal Server Error',
|
||||
501: 'Not Implemented',
|
||||
502: 'Bad Gateway',
|
||||
503: 'Service Unavailable',
|
||||
504: 'Gateway Time-out',
|
||||
505: 'HTTP Version Not Supported',
|
||||
506: 'Variant Also Negotiates', // RFC 2295
|
||||
507: 'Insufficient Storage', // RFC 4918
|
||||
509: 'Bandwidth Limit Exceeded',
|
||||
510: 'Not Extended', // RFC 2774
|
||||
511: 'Network Authentication Required' // RFC 6585
|
||||
}
|
203
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/dictionary.js
generated
vendored
Executable file
203
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/dictionary.js
generated
vendored
Executable file
|
@ -0,0 +1,203 @@
|
|||
'use strict'
|
||||
|
||||
var dictionary = {}
|
||||
module.exports = dictionary
|
||||
|
||||
dictionary[2] = Buffer.from([
|
||||
'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(''))
|
||||
|
||||
dictionary[3] = Buffer.from([
|
||||
0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // ....opti
|
||||
0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // ons....h
|
||||
0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // ead....p
|
||||
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // ost....p
|
||||
0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // ut....de
|
||||
0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // lete....
|
||||
0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // trace...
|
||||
0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // .accept.
|
||||
0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep
|
||||
0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t-charse
|
||||
0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t....acc
|
||||
0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ept-enco
|
||||
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // ding....
|
||||
0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // accept-l
|
||||
0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // anguage.
|
||||
0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep
|
||||
0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t-ranges
|
||||
0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // ....age.
|
||||
0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // ...allow
|
||||
0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // ....auth
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // orizatio
|
||||
0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n....cac
|
||||
0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // he-contr
|
||||
0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // ol....co
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // nnection
|
||||
0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // ....cont
|
||||
0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // ent-base
|
||||
0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // ....cont
|
||||
0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ent-enco
|
||||
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // ding....
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // content-
|
||||
0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // language
|
||||
0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // ....cont
|
||||
0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // ent-leng
|
||||
0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // th....co
|
||||
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // ntent-lo
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // cation..
|
||||
0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten
|
||||
0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t-md5...
|
||||
0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // .content
|
||||
0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // -range..
|
||||
0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten
|
||||
0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t-type..
|
||||
0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // ..date..
|
||||
0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // ..etag..
|
||||
0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // ..expect
|
||||
0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // ....expi
|
||||
0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // res....f
|
||||
0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // rom....h
|
||||
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // ost....i
|
||||
0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f-match.
|
||||
0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // ...if-mo
|
||||
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // dified-s
|
||||
0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // ince....
|
||||
0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // if-none-
|
||||
0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // match...
|
||||
0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // .if-rang
|
||||
0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e....if-
|
||||
0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // unmodifi
|
||||
0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // ed-since
|
||||
0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // ....last
|
||||
0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // -modifie
|
||||
0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d....loc
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // ation...
|
||||
0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // .max-for
|
||||
0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // wards...
|
||||
0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // .pragma.
|
||||
0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // ...proxy
|
||||
0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // -authent
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // icate...
|
||||
0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // .proxy-a
|
||||
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // uthoriza
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // tion....
|
||||
0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // range...
|
||||
0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // .referer
|
||||
0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // ....retr
|
||||
0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y-after.
|
||||
0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // ...serve
|
||||
0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r....te.
|
||||
0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // ...trail
|
||||
0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // er....tr
|
||||
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // ansfer-e
|
||||
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // ncoding.
|
||||
0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // ...upgra
|
||||
0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // de....us
|
||||
0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // er-agent
|
||||
0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // ....vary
|
||||
0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // ....via.
|
||||
0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // ...warni
|
||||
0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // ng....ww
|
||||
0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w-authen
|
||||
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // ticate..
|
||||
0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // ..method
|
||||
0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // ....get.
|
||||
0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // ...statu
|
||||
0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s....200
|
||||
0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // .OK....v
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // ersion..
|
||||
0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // ..HTTP.1
|
||||
0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // .1....ur
|
||||
0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l....pub
|
||||
0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // lic....s
|
||||
0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // et-cooki
|
||||
0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e....kee
|
||||
0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p-alive.
|
||||
0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // ...origi
|
||||
0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n1001012
|
||||
0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 01202205
|
||||
0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 20630030
|
||||
0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 23033043
|
||||
0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 05306307
|
||||
0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 40240540
|
||||
0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 64074084
|
||||
0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 09410411
|
||||
0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 41241341
|
||||
0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 44154164
|
||||
0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 17502504
|
||||
0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 505203.N
|
||||
0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // on-Autho
|
||||
0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // ritative
|
||||
0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // .Informa
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // tion204.
|
||||
0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // No.Conte
|
||||
0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // nt301.Mo
|
||||
0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // ved.Perm
|
||||
0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // anently4
|
||||
0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 00.Bad.R
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // equest40
|
||||
0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1.Unauth
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // orized40
|
||||
0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3.Forbid
|
||||
0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // den404.N
|
||||
0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // ot.Found
|
||||
0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 500.Inte
|
||||
0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // rnal.Ser
|
||||
0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // ver.Erro
|
||||
0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r501.Not
|
||||
0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // .Impleme
|
||||
0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // nted503.
|
||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // Service.
|
||||
0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // Unavaila
|
||||
0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // bleJan.F
|
||||
0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // eb.Mar.A
|
||||
0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // pr.May.J
|
||||
0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // un.Jul.A
|
||||
0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // ug.Sept.
|
||||
0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // Oct.Nov.
|
||||
0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // Dec.00.0
|
||||
0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0.00.Mon
|
||||
0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // ..Tue..W
|
||||
0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // ed..Thu.
|
||||
0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // .Fri..Sa
|
||||
0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t..Sun..
|
||||
0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // GMTchunk
|
||||
0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // ed.text.
|
||||
0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // html.ima
|
||||
0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // ge.png.i
|
||||
0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // mage.jpg
|
||||
0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // .image.g
|
||||
0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // if.appli
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x
|
||||
0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // ml.appli
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x
|
||||
0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // html.xml
|
||||
0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // .text.pl
|
||||
0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // ain.text
|
||||
0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // .javascr
|
||||
0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // ipt.publ
|
||||
0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // icprivat
|
||||
0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // emax-age
|
||||
0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // .gzip.de
|
||||
0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // flate.sd
|
||||
0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // chcharse
|
||||
0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t.utf-8c
|
||||
0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // harset.i
|
||||
0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // so-8859-
|
||||
0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1.utf-..
|
||||
0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // .enq.0.
|
||||
])
|
||||
|
||||
dictionary[3.1] = dictionary[3]
|
519
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/framer.js
generated
vendored
Executable file
519
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/framer.js
generated
vendored
Executable file
|
@ -0,0 +1,519 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var constants = require('./').constants
|
||||
var base = transport.protocol.base
|
||||
var utils = base.utils
|
||||
|
||||
var assert = require('assert')
|
||||
var util = require('util')
|
||||
var Buffer = require('buffer').Buffer
|
||||
var WriteBuffer = require('wbuf')
|
||||
|
||||
var debug = require('debug')('spdy:framer')
|
||||
|
||||
function Framer (options) {
|
||||
base.Framer.call(this, options)
|
||||
}
|
||||
util.inherits(Framer, base.Framer)
|
||||
module.exports = Framer
|
||||
|
||||
Framer.create = function create (options) {
|
||||
return new Framer(options)
|
||||
}
|
||||
|
||||
Framer.prototype.setMaxFrameSize = function setMaxFrameSize (size) {
|
||||
// http2-only
|
||||
}
|
||||
|
||||
Framer.prototype.headersToDict = function headersToDict (headers,
|
||||
preprocess,
|
||||
callback) {
|
||||
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 size = this.version === 2 ? 2 : 4
|
||||
var len = size
|
||||
var pairs = Object.keys(loweredHeaders).filter(function (key) {
|
||||
var lkey = key.toLowerCase()
|
||||
|
||||
// Will be in `:host`
|
||||
if (lkey === 'host' && this.version >= 3) {
|
||||
return false
|
||||
}
|
||||
|
||||
return lkey !== 'connection' && lkey !== 'keep-alive' &&
|
||||
lkey !== 'proxy-connection' && lkey !== 'transfer-encoding'
|
||||
}, this).map(function (key) {
|
||||
var klen = Buffer.byteLength(key)
|
||||
var value = stringify(loweredHeaders[key])
|
||||
var vlen = Buffer.byteLength(value)
|
||||
|
||||
len += size * 2 + klen + vlen
|
||||
return [klen, key, vlen, value]
|
||||
})
|
||||
|
||||
var block = new WriteBuffer()
|
||||
block.reserve(len)
|
||||
|
||||
if (this.version === 2) {
|
||||
block.writeUInt16BE(pairs.length)
|
||||
} else {
|
||||
block.writeUInt32BE(pairs.length)
|
||||
}
|
||||
|
||||
pairs.forEach(function (pair) {
|
||||
// Write key length
|
||||
if (this.version === 2) {
|
||||
block.writeUInt16BE(pair[0])
|
||||
} else {
|
||||
block.writeUInt32BE(pair[0])
|
||||
}
|
||||
|
||||
// Write key
|
||||
block.write(pair[1])
|
||||
|
||||
// Write value length
|
||||
if (this.version === 2) {
|
||||
block.writeUInt16BE(pair[2])
|
||||
} else {
|
||||
block.writeUInt32BE(pair[2])
|
||||
}
|
||||
// Write value
|
||||
block.write(pair[3])
|
||||
}, this)
|
||||
|
||||
assert(this.compress !== null, 'Framer version not initialized')
|
||||
this.compress.write(block.render(), callback)
|
||||
}
|
||||
|
||||
Framer.prototype._frame = function _frame (frame, body, callback) {
|
||||
if (!this.version) {
|
||||
this.on('version', function () {
|
||||
this._frame(frame, body, callback)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
debug('id=%d type=%s', frame.id, frame.type)
|
||||
|
||||
var buffer = new WriteBuffer()
|
||||
|
||||
buffer.writeUInt16BE(0x8000 | this.version)
|
||||
buffer.writeUInt16BE(constants.frameType[frame.type])
|
||||
buffer.writeUInt8(frame.flags)
|
||||
var len = buffer.skip(3)
|
||||
|
||||
body(buffer)
|
||||
|
||||
var frameSize = buffer.size - constants.FRAME_HEADER_SIZE
|
||||
len.writeUInt24BE(frameSize)
|
||||
|
||||
var chunks = buffer.render()
|
||||
var toWrite = {
|
||||
stream: frame.id,
|
||||
priority: false,
|
||||
chunks: chunks,
|
||||
callback: callback
|
||||
}
|
||||
|
||||
this._resetTimeout()
|
||||
this.schedule(toWrite)
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
Framer.prototype._synFrame = function _synFrame (frame, callback) {
|
||||
var self = this
|
||||
|
||||
if (!frame.path) {
|
||||
throw new Error('`path` is required frame argument')
|
||||
}
|
||||
|
||||
function preprocess (headers) {
|
||||
var method = frame.method || base.constants.DEFAULT_METHOD
|
||||
var version = frame.version || 'HTTP/1.1'
|
||||
var scheme = frame.scheme || 'https'
|
||||
var host = frame.host ||
|
||||
(frame.headers && frame.headers.host) ||
|
||||
base.constants.DEFAULT_HOST
|
||||
|
||||
if (self.version === 2) {
|
||||
headers.method = method
|
||||
headers.version = version
|
||||
headers.url = frame.path
|
||||
headers.scheme = scheme
|
||||
headers.host = host
|
||||
if (frame.status) {
|
||||
headers.status = frame.status
|
||||
}
|
||||
} else {
|
||||
headers[':method'] = method
|
||||
headers[':version'] = version
|
||||
headers[':path'] = frame.path
|
||||
headers[':scheme'] = scheme
|
||||
headers[':host'] = host
|
||||
if (frame.status) { headers[':status'] = frame.status }
|
||||
}
|
||||
}
|
||||
|
||||
this.headersToDict(frame.headers, preprocess, function (err, chunks) {
|
||||
if (err) {
|
||||
if (callback) {
|
||||
return callback(err)
|
||||
} else {
|
||||
return self.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
self._frame({
|
||||
type: 'SYN_STREAM',
|
||||
id: frame.id,
|
||||
flags: frame.fin ? constants.flags.FLAG_FIN : 0
|
||||
}, function (buf) {
|
||||
buf.reserve(10)
|
||||
|
||||
buf.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
buf.writeUInt32BE(frame.associated & 0x7fffffff)
|
||||
|
||||
var weight = (frame.priority && frame.priority.weight) ||
|
||||
constants.DEFAULT_WEIGHT
|
||||
|
||||
// We only have 3 bits for priority in SPDY, try to fit it into this
|
||||
var priority = utils.weightToPriority(weight)
|
||||
buf.writeUInt8(priority << 5)
|
||||
|
||||
// CREDENTIALS slot
|
||||
buf.writeUInt8(0)
|
||||
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
buf.copyFrom(chunks[i])
|
||||
}
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.requestFrame = function requestFrame (frame, callback) {
|
||||
this._synFrame({
|
||||
id: frame.id,
|
||||
fin: frame.fin,
|
||||
associated: 0,
|
||||
method: frame.method,
|
||||
version: frame.version,
|
||||
scheme: frame.scheme,
|
||||
host: frame.host,
|
||||
path: frame.path,
|
||||
priority: frame.priority,
|
||||
headers: frame.headers
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.responseFrame = function responseFrame (frame, callback) {
|
||||
var self = this
|
||||
|
||||
var reason = frame.reason
|
||||
if (!reason) {
|
||||
reason = constants.statusReason[frame.status]
|
||||
}
|
||||
|
||||
function preprocess (headers) {
|
||||
if (self.version === 2) {
|
||||
headers.status = frame.status + ' ' + reason
|
||||
headers.version = 'HTTP/1.1'
|
||||
} else {
|
||||
headers[':status'] = frame.status + ' ' + reason
|
||||
headers[':version'] = 'HTTP/1.1'
|
||||
}
|
||||
}
|
||||
|
||||
this.headersToDict(frame.headers, preprocess, function (err, chunks) {
|
||||
if (err) {
|
||||
if (callback) {
|
||||
return callback(err)
|
||||
} else {
|
||||
return self.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
self._frame({
|
||||
type: 'SYN_REPLY',
|
||||
id: frame.id,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(self.version === 2 ? 6 : 4)
|
||||
|
||||
buf.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
|
||||
// Unused data
|
||||
if (self.version === 2) {
|
||||
buf.writeUInt16BE(0)
|
||||
}
|
||||
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
buf.copyFrom(chunks[i])
|
||||
}
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.pushFrame = function pushFrame (frame, callback) {
|
||||
var self = this
|
||||
|
||||
this._checkPush(function (err) {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
self._synFrame({
|
||||
id: frame.promisedId,
|
||||
associated: frame.id,
|
||||
method: frame.method,
|
||||
status: frame.status || 200,
|
||||
version: frame.version,
|
||||
scheme: frame.scheme,
|
||||
host: frame.host,
|
||||
path: frame.path,
|
||||
priority: frame.priority,
|
||||
|
||||
// Merge everything together, there is no difference in SPDY protocol
|
||||
headers: Object.assign(Object.assign({}, frame.headers), frame.response)
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.headersFrame = function headersFrame (frame, callback) {
|
||||
var self = this
|
||||
|
||||
this.headersToDict(frame.headers, null, function (err, chunks) {
|
||||
if (err) {
|
||||
if (callback) { return callback(err) } else {
|
||||
return self.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
self._frame({
|
||||
type: 'HEADERS',
|
||||
id: frame.id,
|
||||
priority: false,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(4 + (self.version === 2 ? 2 : 0))
|
||||
buf.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
|
||||
// Unused data
|
||||
if (self.version === 2) { buf.writeUInt16BE(0) }
|
||||
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
buf.copyFrom(chunks[i])
|
||||
}
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Framer.prototype.dataFrame = function dataFrame (frame, callback) {
|
||||
if (!this.version) {
|
||||
return this.on('version', function () {
|
||||
this.dataFrame(frame, callback)
|
||||
})
|
||||
}
|
||||
|
||||
debug('id=%d type=DATA', frame.id)
|
||||
|
||||
var buffer = new WriteBuffer()
|
||||
buffer.reserve(8 + frame.data.length)
|
||||
|
||||
buffer.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
buffer.writeUInt8(frame.fin ? 0x01 : 0x0)
|
||||
buffer.writeUInt24BE(frame.data.length)
|
||||
buffer.copyFrom(frame.data)
|
||||
|
||||
var chunks = buffer.render()
|
||||
var toWrite = {
|
||||
stream: frame.id,
|
||||
priority: frame.priority,
|
||||
chunks: chunks,
|
||||
callback: callback
|
||||
}
|
||||
|
||||
var self = this
|
||||
this._resetTimeout()
|
||||
|
||||
var bypass = this.version < 3.1
|
||||
this.window.send.update(-frame.data.length, bypass ? undefined : function () {
|
||||
self._resetTimeout()
|
||||
self.schedule(toWrite)
|
||||
})
|
||||
|
||||
if (bypass) {
|
||||
this._resetTimeout()
|
||||
this.schedule(toWrite)
|
||||
}
|
||||
}
|
||||
|
||||
Framer.prototype.pingFrame = function pingFrame (frame, callback) {
|
||||
this._frame({
|
||||
type: 'PING',
|
||||
id: 0,
|
||||
flags: 0
|
||||
}, function (buf, callback) {
|
||||
buf.reserve(4)
|
||||
|
||||
var opaque = frame.opaque
|
||||
buf.writeUInt32BE(opaque.readUInt32BE(opaque.length - 4, true))
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.rstFrame = function rstFrame (frame, callback) {
|
||||
this._frame({
|
||||
type: 'RST_STREAM',
|
||||
id: frame.id,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(8)
|
||||
|
||||
// Stream ID
|
||||
buf.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
// Status Code
|
||||
buf.writeUInt32BE(constants.error[frame.code])
|
||||
|
||||
// Extra debugging information
|
||||
if (frame.extra) {
|
||||
buf.write(frame.extra)
|
||||
}
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.prefaceFrame = function prefaceFrame () {
|
||||
}
|
||||
|
||||
Framer.prototype.settingsFrame = function settingsFrame (options, callback) {
|
||||
var self = this
|
||||
|
||||
var key = this.version + '/' + JSON.stringify(options)
|
||||
|
||||
var settings = Framer.settingsCache[key]
|
||||
if (settings) {
|
||||
debug('cached settings')
|
||||
this._resetTimeout()
|
||||
this.schedule({
|
||||
stream: 0,
|
||||
priority: false,
|
||||
chunks: settings,
|
||||
callback: callback
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var params = []
|
||||
for (var i = 0; i < constants.settingsIndex.length; i++) {
|
||||
var name = constants.settingsIndex[i]
|
||||
if (!name) { continue }
|
||||
|
||||
// value: Infinity
|
||||
if (!isFinite(options[name])) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (options[name] !== undefined) {
|
||||
params.push({ key: i, value: options[name] })
|
||||
}
|
||||
}
|
||||
|
||||
var frame = this._frame({
|
||||
type: 'SETTINGS',
|
||||
id: 0,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(4 + 8 * params.length)
|
||||
|
||||
// Count of entries
|
||||
buf.writeUInt32BE(params.length)
|
||||
|
||||
params.forEach(function (param) {
|
||||
var flag = constants.settings.FLAG_SETTINGS_PERSIST_VALUE << 24
|
||||
|
||||
if (self.version === 2) {
|
||||
buf.writeUInt32LE(flag | param.key)
|
||||
} else { buf.writeUInt32BE(flag | param.key) }
|
||||
buf.writeUInt32BE(param.value & 0x7fffffff)
|
||||
})
|
||||
}, callback)
|
||||
|
||||
Framer.settingsCache[key] = frame
|
||||
}
|
||||
Framer.settingsCache = {}
|
||||
|
||||
Framer.prototype.ackSettingsFrame = function ackSettingsFrame (callback) {
|
||||
if (callback) {
|
||||
process.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
Framer.prototype.windowUpdateFrame = function windowUpdateFrame (frame,
|
||||
callback) {
|
||||
this._frame({
|
||||
type: 'WINDOW_UPDATE',
|
||||
id: frame.id,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(8)
|
||||
|
||||
// ID
|
||||
buf.writeUInt32BE(frame.id & 0x7fffffff)
|
||||
|
||||
// Delta
|
||||
buf.writeInt32BE(frame.delta)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.goawayFrame = function goawayFrame (frame, callback) {
|
||||
this._frame({
|
||||
type: 'GOAWAY',
|
||||
id: 0,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.reserve(8)
|
||||
|
||||
// Last-good-stream-ID
|
||||
buf.writeUInt32BE(frame.lastId & 0x7fffffff)
|
||||
// Status
|
||||
buf.writeUInt32BE(constants.goaway[frame.code])
|
||||
}, callback)
|
||||
}
|
||||
|
||||
Framer.prototype.priorityFrame = function priorityFrame (frame, callback) {
|
||||
// No such thing in SPDY
|
||||
if (callback) {
|
||||
process.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
Framer.prototype.xForwardedFor = function xForwardedFor (frame, callback) {
|
||||
this._frame({
|
||||
type: 'X_FORWARDED_FOR',
|
||||
id: 0,
|
||||
flags: 0
|
||||
}, function (buf) {
|
||||
buf.writeUInt32BE(Buffer.byteLength(frame.host))
|
||||
buf.write(frame.host)
|
||||
}, callback)
|
||||
}
|
9
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/index.js
generated
vendored
Executable file
9
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/index.js
generated
vendored
Executable file
|
@ -0,0 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
exports.name = 'spdy'
|
||||
|
||||
exports.dictionary = require('./dictionary')
|
||||
exports.constants = require('./constants')
|
||||
exports.parser = require('./parser')
|
||||
exports.framer = require('./framer')
|
||||
exports.compressionPool = require('./zlib-pool')
|
485
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/parser.js
generated
vendored
Executable file
485
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/parser.js
generated
vendored
Executable file
|
@ -0,0 +1,485 @@
|
|||
'use strict'
|
||||
|
||||
var parser = exports
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
var base = transport.protocol.base
|
||||
var utils = base.utils
|
||||
var constants = require('./constants')
|
||||
|
||||
var assert = require('assert')
|
||||
var util = require('util')
|
||||
var OffsetBuffer = require('obuf')
|
||||
|
||||
function Parser (options) {
|
||||
base.Parser.call(this, options)
|
||||
|
||||
this.isServer = options.isServer
|
||||
this.waiting = constants.FRAME_HEADER_SIZE
|
||||
this.state = 'frame-head'
|
||||
this.pendingHeader = null
|
||||
}
|
||||
util.inherits(Parser, base.Parser)
|
||||
|
||||
parser.create = function create (options) {
|
||||
return new Parser(options)
|
||||
}
|
||||
|
||||
Parser.prototype.setMaxFrameSize = function setMaxFrameSize (size) {
|
||||
// http2-only
|
||||
}
|
||||
|
||||
Parser.prototype.setMaxHeaderListSize = function setMaxHeaderListSize (size) {
|
||||
// http2-only
|
||||
}
|
||||
|
||||
// Only for testing
|
||||
Parser.prototype.skipPreface = function skipPreface () {
|
||||
}
|
||||
|
||||
Parser.prototype.execute = function execute (buffer, callback) {
|
||||
if (this.state === 'frame-head') { return this.onFrameHead(buffer, callback) }
|
||||
|
||||
assert(this.state === 'frame-body' && this.pendingHeader !== null)
|
||||
|
||||
var self = this
|
||||
var header = this.pendingHeader
|
||||
this.pendingHeader = null
|
||||
|
||||
this.onFrameBody(header, buffer, function (err, frame) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
self.state = 'frame-head'
|
||||
self.waiting = constants.FRAME_HEADER_SIZE
|
||||
self.partial = false
|
||||
callback(null, frame)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.executePartial = function executePartial (buffer, callback) {
|
||||
var header = this.pendingHeader
|
||||
|
||||
if (this.window) {
|
||||
this.window.recv.update(-buffer.size)
|
||||
}
|
||||
|
||||
// DATA frame
|
||||
callback(null, {
|
||||
type: 'DATA',
|
||||
id: header.id,
|
||||
|
||||
// Partial DATA can't be FIN
|
||||
fin: false,
|
||||
data: buffer.take(buffer.size)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onFrameHead = function onFrameHead (buffer, callback) {
|
||||
var header = {
|
||||
control: (buffer.peekUInt8() & 0x80) === 0x80,
|
||||
version: null,
|
||||
type: null,
|
||||
id: null,
|
||||
flags: null,
|
||||
length: null
|
||||
}
|
||||
|
||||
if (header.control) {
|
||||
header.version = buffer.readUInt16BE() & 0x7fff
|
||||
header.type = buffer.readUInt16BE()
|
||||
} else {
|
||||
header.id = buffer.readUInt32BE(0) & 0x7fffffff
|
||||
}
|
||||
header.flags = buffer.readUInt8()
|
||||
header.length = buffer.readUInt24BE()
|
||||
|
||||
if (this.version === null && header.control) {
|
||||
// TODO(indutny): do ProtocolError here and in the rest of errors
|
||||
if (header.version !== 2 && header.version !== 3) {
|
||||
return callback(new Error('Unsupported SPDY version: ' + header.version))
|
||||
}
|
||||
this.setVersion(header.version)
|
||||
}
|
||||
|
||||
this.state = 'frame-body'
|
||||
this.waiting = header.length
|
||||
this.pendingHeader = header
|
||||
this.partial = !header.control
|
||||
|
||||
callback(null, null)
|
||||
}
|
||||
|
||||
Parser.prototype.onFrameBody = function onFrameBody (header, buffer, callback) {
|
||||
// Data frame
|
||||
if (!header.control) {
|
||||
// Count received bytes
|
||||
if (this.window) {
|
||||
this.window.recv.update(-buffer.size)
|
||||
}
|
||||
|
||||
// No support for compressed DATA
|
||||
if ((header.flags & constants.flags.FLAG_COMPRESSED) !== 0) {
|
||||
return callback(new Error('DATA compression not supported'))
|
||||
}
|
||||
|
||||
if (header.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for DATA'))
|
||||
}
|
||||
|
||||
return callback(null, {
|
||||
type: 'DATA',
|
||||
id: header.id,
|
||||
fin: (header.flags & constants.flags.FLAG_FIN) !== 0,
|
||||
data: buffer.take(buffer.size)
|
||||
})
|
||||
}
|
||||
|
||||
if (header.type === 0x01 || header.type === 0x02) { // SYN_STREAM or SYN_REPLY
|
||||
this.onSynHeadFrame(header.type, header.flags, buffer, callback)
|
||||
} else if (header.type === 0x03) { // RST_STREAM
|
||||
this.onRSTFrame(buffer, callback)
|
||||
} else if (header.type === 0x04) { // SETTINGS
|
||||
this.onSettingsFrame(buffer, callback)
|
||||
} else if (header.type === 0x05) {
|
||||
callback(null, { type: 'NOOP' })
|
||||
} else if (header.type === 0x06) { // PING
|
||||
this.onPingFrame(buffer, callback)
|
||||
} else if (header.type === 0x07) { // GOAWAY
|
||||
this.onGoawayFrame(buffer, callback)
|
||||
} else if (header.type === 0x08) { // HEADERS
|
||||
this.onHeaderFrames(buffer, callback)
|
||||
} else if (header.type === 0x09) { // WINDOW_UPDATE
|
||||
this.onWindowUpdateFrame(buffer, callback)
|
||||
} else if (header.type === 0xf000) { // X-FORWARDED
|
||||
this.onXForwardedFrame(buffer, callback)
|
||||
} else {
|
||||
callback(null, { type: 'unknown: ' + header.type })
|
||||
}
|
||||
}
|
||||
|
||||
Parser.prototype._filterHeader = function _filterHeader (headers, name) {
|
||||
var res = {}
|
||||
var keys = Object.keys(headers)
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i]
|
||||
if (key !== name) {
|
||||
res[key] = headers[key]
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
Parser.prototype.onSynHeadFrame = function onSynHeadFrame (type,
|
||||
flags,
|
||||
body,
|
||||
callback) {
|
||||
var self = this
|
||||
var stream = type === 0x01
|
||||
var offset = stream ? 10 : this.version === 2 ? 6 : 4
|
||||
|
||||
if (!body.has(offset)) {
|
||||
return callback(new Error('SynHead OOB'))
|
||||
}
|
||||
|
||||
var head = body.clone(offset)
|
||||
body.skip(offset)
|
||||
this.parseKVs(body, function (err, headers) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
if (stream &&
|
||||
(!headers[':method'] || !headers[':path'])) {
|
||||
return callback(new Error('Missing `:method` and/or `:path` header'))
|
||||
}
|
||||
|
||||
var id = head.readUInt32BE() & 0x7fffffff
|
||||
|
||||
if (id === 0) {
|
||||
return callback(self.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for HEADERS'))
|
||||
}
|
||||
|
||||
var associated = stream ? head.readUInt32BE() & 0x7fffffff : 0
|
||||
var priority = stream
|
||||
? head.readUInt8() >> 5
|
||||
: utils.weightToPriority(constants.DEFAULT_WEIGHT)
|
||||
var fin = (flags & constants.flags.FLAG_FIN) !== 0
|
||||
var unidir = (flags & constants.flags.FLAG_UNIDIRECTIONAL) !== 0
|
||||
var path = headers[':path']
|
||||
|
||||
var isPush = stream && associated !== 0
|
||||
|
||||
var weight = utils.priorityToWeight(priority)
|
||||
var priorityInfo = {
|
||||
weight: weight,
|
||||
exclusive: false,
|
||||
parent: 0
|
||||
}
|
||||
|
||||
if (!isPush) {
|
||||
callback(null, {
|
||||
type: 'HEADERS',
|
||||
id: id,
|
||||
priority: priorityInfo,
|
||||
fin: fin,
|
||||
writable: !unidir,
|
||||
headers: headers,
|
||||
path: path
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (stream && !headers[':status']) {
|
||||
return callback(new Error('Missing `:status` header'))
|
||||
}
|
||||
|
||||
var filteredHeaders = self._filterHeader(headers, ':status')
|
||||
|
||||
callback(null, [ {
|
||||
type: 'PUSH_PROMISE',
|
||||
id: associated,
|
||||
fin: false,
|
||||
promisedId: id,
|
||||
headers: filteredHeaders,
|
||||
path: path
|
||||
}, {
|
||||
type: 'HEADERS',
|
||||
id: id,
|
||||
fin: fin,
|
||||
priority: priorityInfo,
|
||||
writable: true,
|
||||
path: undefined,
|
||||
headers: {
|
||||
':status': headers[':status']
|
||||
}
|
||||
}])
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onHeaderFrames = function onHeaderFrames (body, callback) {
|
||||
var offset = this.version === 2 ? 6 : 4
|
||||
if (!body.has(offset)) {
|
||||
return callback(new Error('HEADERS OOB'))
|
||||
}
|
||||
|
||||
var streamId = body.readUInt32BE() & 0x7fffffff
|
||||
if (this.version === 2) { body.skip(2) }
|
||||
|
||||
this.parseKVs(body, function (err, headers) {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
callback(null, {
|
||||
type: 'HEADERS',
|
||||
priority: {
|
||||
parent: 0,
|
||||
exclusive: false,
|
||||
weight: constants.DEFAULT_WEIGHT
|
||||
},
|
||||
id: streamId,
|
||||
fin: false,
|
||||
writable: true,
|
||||
path: undefined,
|
||||
headers: headers
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.parseKVs = function parseKVs (buffer, callback) {
|
||||
var self = this
|
||||
|
||||
this.decompress.write(buffer.toChunks(), function (err, chunks) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
var buffer = new OffsetBuffer()
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
buffer.push(chunks[i])
|
||||
}
|
||||
|
||||
var size = self.version === 2 ? 2 : 4
|
||||
if (!buffer.has(size)) { return callback(new Error('KV OOB')) }
|
||||
|
||||
var count = self.version === 2
|
||||
? buffer.readUInt16BE()
|
||||
: buffer.readUInt32BE()
|
||||
|
||||
var headers = {}
|
||||
|
||||
function readString () {
|
||||
if (!buffer.has(size)) { return null }
|
||||
var len = self.version === 2
|
||||
? buffer.readUInt16BE()
|
||||
: buffer.readUInt32BE()
|
||||
|
||||
if (!buffer.has(len)) { return null }
|
||||
|
||||
var value = buffer.take(len)
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
while (count > 0) {
|
||||
var key = readString()
|
||||
var value = readString()
|
||||
|
||||
if (key === null || value === null) {
|
||||
return callback(new Error('Headers OOB'))
|
||||
}
|
||||
|
||||
if (self.version < 3) {
|
||||
var isInternal = /^(method|version|url|host|scheme|status)$/.test(key)
|
||||
if (key === 'url') {
|
||||
key = 'path'
|
||||
}
|
||||
if (isInternal) {
|
||||
key = ':' + key
|
||||
}
|
||||
}
|
||||
|
||||
// Compatibility with HTTP2
|
||||
if (key === ':status') {
|
||||
value = value.split(/ /g, 2)[0]
|
||||
}
|
||||
|
||||
count--
|
||||
if (key === ':host') {
|
||||
key = ':authority'
|
||||
}
|
||||
|
||||
// Skip version, not present in HTTP2
|
||||
if (key === ':version') {
|
||||
continue
|
||||
}
|
||||
|
||||
value = value.split(/\0/g)
|
||||
for (var j = 0; j < value.length; j++) {
|
||||
utils.addHeaderLine(key, value[j], headers)
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, headers)
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onRSTFrame = function onRSTFrame (body, callback) {
|
||||
if (!body.has(8)) { return callback(new Error('RST OOB')) }
|
||||
|
||||
var frame = {
|
||||
type: 'RST',
|
||||
id: body.readUInt32BE() & 0x7fffffff,
|
||||
code: constants.errorByCode[body.readUInt32BE()]
|
||||
}
|
||||
|
||||
if (frame.id === 0) {
|
||||
return callback(this.error(constants.error.PROTOCOL_ERROR,
|
||||
'Invalid stream id for RST'))
|
||||
}
|
||||
|
||||
if (body.size !== 0) {
|
||||
frame.extra = body.take(body.size)
|
||||
}
|
||||
callback(null, frame)
|
||||
}
|
||||
|
||||
Parser.prototype.onSettingsFrame = function onSettingsFrame (body, callback) {
|
||||
if (!body.has(4)) {
|
||||
return callback(new Error('SETTINGS OOB'))
|
||||
}
|
||||
|
||||
var settings = {}
|
||||
var number = body.readUInt32BE()
|
||||
var 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'
|
||||
}
|
||||
|
||||
if (!body.has(number * 8)) {
|
||||
return callback(new Error('SETTINGS OOB#2'))
|
||||
}
|
||||
|
||||
for (var i = 0; i < number; i++) {
|
||||
var id = this.version === 2
|
||||
? body.readUInt32LE()
|
||||
: body.readUInt32BE()
|
||||
|
||||
var flags = (id >> 24) & 0xff
|
||||
id = id & 0xffffff
|
||||
|
||||
// Skip persisted settings
|
||||
if (flags & 0x2) { continue }
|
||||
|
||||
var name = idMap[id]
|
||||
|
||||
settings[name] = body.readUInt32BE()
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'SETTINGS',
|
||||
settings: settings
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onPingFrame = function onPingFrame (body, callback) {
|
||||
if (!body.has(4)) {
|
||||
return callback(new Error('PING OOB'))
|
||||
}
|
||||
|
||||
var isServer = this.isServer
|
||||
var opaque = body.clone(body.size).take(body.size)
|
||||
var id = body.readUInt32BE()
|
||||
var ack = isServer ? (id % 2 === 0) : (id % 2 === 1)
|
||||
|
||||
callback(null, { type: 'PING', opaque: opaque, ack: ack })
|
||||
}
|
||||
|
||||
Parser.prototype.onGoawayFrame = function onGoawayFrame (body, callback) {
|
||||
if (!body.has(8)) {
|
||||
return callback(new Error('GOAWAY OOB'))
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'GOAWAY',
|
||||
lastId: body.readUInt32BE() & 0x7fffffff,
|
||||
code: constants.goawayByCode[body.readUInt32BE()]
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onWindowUpdateFrame = function onWindowUpdateFrame (body,
|
||||
callback) {
|
||||
if (!body.has(8)) {
|
||||
return callback(new Error('WINDOW_UPDATE OOB'))
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
type: 'WINDOW_UPDATE',
|
||||
id: body.readUInt32BE() & 0x7fffffff,
|
||||
delta: body.readInt32BE()
|
||||
})
|
||||
}
|
||||
|
||||
Parser.prototype.onXForwardedFrame = function onXForwardedFrame (body,
|
||||
callback) {
|
||||
if (!body.has(4)) {
|
||||
return callback(new Error('X_FORWARDED OOB'))
|
||||
}
|
||||
|
||||
var len = body.readUInt32BE()
|
||||
if (!body.has(len)) { return callback(new Error('X_FORWARDED host length OOB')) }
|
||||
|
||||
callback(null, {
|
||||
type: 'X_FORWARDED_FOR',
|
||||
host: body.take(len).toString()
|
||||
})
|
||||
}
|
65
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/zlib-pool.js
generated
vendored
Executable file
65
my-app/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy/zlib-pool.js
generated
vendored
Executable file
|
@ -0,0 +1,65 @@
|
|||
'use strict'
|
||||
|
||||
var zlibpool = exports
|
||||
var zlib = require('zlib')
|
||||
|
||||
var transport = require('../../../spdy-transport')
|
||||
|
||||
// TODO(indutny): think about it, why has it always been Z_SYNC_FLUSH here.
|
||||
// It should be possible to manually flush stuff after the write instead
|
||||
function createDeflate (version, compression) {
|
||||
var deflate = zlib.createDeflate({
|
||||
dictionary: transport.protocol.spdy.dictionary[version],
|
||||
flush: zlib.Z_SYNC_FLUSH,
|
||||
windowBits: 11,
|
||||
level: compression ? zlib.Z_DEFAULT_COMPRESSION : zlib.Z_NO_COMPRESSION
|
||||
})
|
||||
|
||||
// For node.js v0.8
|
||||
deflate._flush = zlib.Z_SYNC_FLUSH
|
||||
|
||||
return deflate
|
||||
}
|
||||
|
||||
function createInflate (version) {
|
||||
var inflate = zlib.createInflate({
|
||||
dictionary: transport.protocol.spdy.dictionary[version],
|
||||
flush: zlib.Z_SYNC_FLUSH
|
||||
})
|
||||
|
||||
// For node.js v0.8
|
||||
inflate._flush = zlib.Z_SYNC_FLUSH
|
||||
|
||||
return inflate
|
||||
}
|
||||
|
||||
function Pool (compression) {
|
||||
this.compression = compression
|
||||
this.pool = {
|
||||
2: [],
|
||||
3: [],
|
||||
3.1: []
|
||||
}
|
||||
}
|
||||
|
||||
zlibpool.create = function create (compression) {
|
||||
return new Pool(compression)
|
||||
}
|
||||
|
||||
Pool.prototype.get = function get (version) {
|
||||
if (this.pool[version].length > 0) {
|
||||
return this.pool[version].pop()
|
||||
} else {
|
||||
var id = version
|
||||
|
||||
return {
|
||||
version: version,
|
||||
compress: createDeflate(id, this.compression),
|
||||
decompress: createInflate(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pool.prototype.put = function put (pair) {
|
||||
this.pool[pair.version].push(pair)
|
||||
}
|
710
my-app/node_modules/spdy-transport/lib/spdy-transport/stream.js
generated
vendored
Executable file
710
my-app/node_modules/spdy-transport/lib/spdy-transport/stream.js
generated
vendored
Executable file
|
@ -0,0 +1,710 @@
|
|||
'use strict'
|
||||
|
||||
var transport = require('../spdy-transport')
|
||||
|
||||
var assert = require('assert')
|
||||
var util = require('util')
|
||||
|
||||
var debug = {
|
||||
client: require('debug')('spdy:stream:client'),
|
||||
server: require('debug')('spdy:stream:server')
|
||||
}
|
||||
var Duplex = require('readable-stream').Duplex
|
||||
|
||||
function Stream (connection, options) {
|
||||
Duplex.call(this)
|
||||
|
||||
var connectionState = connection._spdyState
|
||||
|
||||
var state = {}
|
||||
this._spdyState = state
|
||||
|
||||
this.id = options.id
|
||||
this.method = options.method
|
||||
this.path = options.path
|
||||
this.host = options.host
|
||||
this.headers = options.headers || {}
|
||||
this.connection = connection
|
||||
this.parent = options.parent || null
|
||||
|
||||
state.socket = null
|
||||
state.protocol = connectionState.protocol
|
||||
state.constants = state.protocol.constants
|
||||
|
||||
// See _initPriority()
|
||||
state.priority = null
|
||||
|
||||
state.version = this.connection.getVersion()
|
||||
state.isServer = this.connection.isServer()
|
||||
state.debug = state.isServer ? debug.server : debug.client
|
||||
|
||||
state.framer = connectionState.framer
|
||||
state.parser = connectionState.parser
|
||||
|
||||
state.request = options.request
|
||||
state.needResponse = options.request
|
||||
state.window = connectionState.streamWindow.clone(options.id)
|
||||
state.sessionWindow = connectionState.window
|
||||
state.maxChunk = connectionState.maxChunk
|
||||
|
||||
// Can't send incoming request
|
||||
// (See `.send()` method)
|
||||
state.sent = !state.request
|
||||
|
||||
state.readable = options.readable !== false
|
||||
state.writable = options.writable !== false
|
||||
|
||||
state.aborted = false
|
||||
|
||||
state.corked = 0
|
||||
state.corkQueue = []
|
||||
|
||||
state.timeout = new transport.utils.Timeout(this)
|
||||
|
||||
this.on('finish', this._onFinish)
|
||||
this.on('end', this._onEnd)
|
||||
|
||||
var self = this
|
||||
function _onWindowOverflow () {
|
||||
self._onWindowOverflow()
|
||||
}
|
||||
|
||||
state.window.recv.on('overflow', _onWindowOverflow)
|
||||
state.window.send.on('overflow', _onWindowOverflow)
|
||||
|
||||
this._initPriority(options.priority)
|
||||
|
||||
if (!state.readable) { this.push(null) }
|
||||
if (!state.writable) {
|
||||
this._writableState.ended = true
|
||||
this._writableState.finished = true
|
||||
}
|
||||
}
|
||||
util.inherits(Stream, Duplex)
|
||||
exports.Stream = Stream
|
||||
|
||||
Stream.prototype._init = function _init (socket) {
|
||||
this.socket = socket
|
||||
}
|
||||
|
||||
Stream.prototype._initPriority = function _initPriority (priority) {
|
||||
var state = this._spdyState
|
||||
var connectionState = this.connection._spdyState
|
||||
var root = connectionState.priorityRoot
|
||||
|
||||
if (!priority) {
|
||||
state.priority = root.addDefault(this.id)
|
||||
return
|
||||
}
|
||||
|
||||
state.priority = root.add({
|
||||
id: this.id,
|
||||
parent: priority.parent,
|
||||
weight: priority.weight,
|
||||
exclusive: priority.exclusive
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype._handleFrame = function _handleFrame (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
// Ignore any kind of data after abort
|
||||
if (state.aborted) {
|
||||
state.debug('id=%d ignoring frame=%s after abort', this.id, frame.type)
|
||||
return
|
||||
}
|
||||
|
||||
// Restart the timer on incoming frames
|
||||
state.timeout.reset()
|
||||
|
||||
if (frame.type === 'DATA') {
|
||||
this._handleData(frame)
|
||||
} else if (frame.type === 'HEADERS') {
|
||||
this._handleHeaders(frame)
|
||||
} else if (frame.type === 'RST') {
|
||||
this._handleRST(frame)
|
||||
} else if (frame.type === 'WINDOW_UPDATE') { this._handleWindowUpdate(frame) } else if (frame.type === 'PRIORITY') {
|
||||
this._handlePriority(frame)
|
||||
} else if (frame.type === 'PUSH_PROMISE') { this._handlePushPromise(frame) }
|
||||
|
||||
if (frame.fin) {
|
||||
state.debug('id=%d end', this.id)
|
||||
this.push(null)
|
||||
}
|
||||
}
|
||||
|
||||
function checkAborted (stream, state, callback) {
|
||||
if (state.aborted) {
|
||||
state.debug('id=%d abort write', stream.id)
|
||||
process.nextTick(function () {
|
||||
callback(new Error('Stream write aborted'))
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function _send (stream, state, data, callback) {
|
||||
if (checkAborted(stream, state, callback)) {
|
||||
return
|
||||
}
|
||||
|
||||
state.debug('id=%d presend=%d', stream.id, data.length)
|
||||
|
||||
state.timeout.reset()
|
||||
|
||||
state.window.send.update(-data.length, function () {
|
||||
if (checkAborted(stream, state, callback)) {
|
||||
return
|
||||
}
|
||||
|
||||
state.debug('id=%d send=%d', stream.id, data.length)
|
||||
|
||||
state.timeout.reset()
|
||||
|
||||
state.framer.dataFrame({
|
||||
id: stream.id,
|
||||
priority: state.priority.getPriority(),
|
||||
fin: false,
|
||||
data: data
|
||||
}, function (err) {
|
||||
state.debug('id=%d postsend=%d', stream.id, data.length)
|
||||
callback(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype._write = function _write (data, enc, callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
// Send the request if it wasn't sent
|
||||
if (!state.sent) { this.send() }
|
||||
|
||||
// Writes should come after pending control frames (response and headers)
|
||||
if (state.corked !== 0) {
|
||||
var self = this
|
||||
state.corkQueue.push(function () {
|
||||
self._write(data, enc, callback)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Split DATA in chunks to prevent window from going negative
|
||||
this._splitStart(data, _send, callback)
|
||||
}
|
||||
|
||||
Stream.prototype._splitStart = function _splitStart (data, onChunk, callback) {
|
||||
return this._split(data, 0, onChunk, callback)
|
||||
}
|
||||
|
||||
Stream.prototype._split = function _split (data, offset, onChunk, callback) {
|
||||
if (offset === data.length) {
|
||||
return process.nextTick(callback)
|
||||
}
|
||||
|
||||
var state = this._spdyState
|
||||
var local = state.window.send
|
||||
var session = state.sessionWindow.send
|
||||
|
||||
var availSession = Math.max(0, session.getCurrent())
|
||||
if (availSession === 0) {
|
||||
availSession = session.getMax()
|
||||
}
|
||||
var availLocal = Math.max(0, local.getCurrent())
|
||||
if (availLocal === 0) {
|
||||
availLocal = local.getMax()
|
||||
}
|
||||
|
||||
var avail = Math.min(availSession, availLocal)
|
||||
avail = Math.min(avail, state.maxChunk)
|
||||
|
||||
var self = this
|
||||
|
||||
if (avail === 0) {
|
||||
state.window.send.update(0, function () {
|
||||
self._split(data, offset, onChunk, callback)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Split data in chunks in a following way:
|
||||
var limit = avail
|
||||
var size = Math.min(data.length - offset, limit)
|
||||
|
||||
var chunk = data.slice(offset, offset + size)
|
||||
|
||||
onChunk(this, state, chunk, function (err) {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
// Get the next chunk
|
||||
self._split(data, offset + size, onChunk, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype._read = function _read () {
|
||||
var state = this._spdyState
|
||||
|
||||
if (!state.window.recv.isDraining()) {
|
||||
return
|
||||
}
|
||||
|
||||
var delta = state.window.recv.getDelta()
|
||||
|
||||
state.debug('id=%d window emptying, update by %d', this.id, delta)
|
||||
|
||||
state.window.recv.update(delta)
|
||||
state.framer.windowUpdateFrame({
|
||||
id: this.id,
|
||||
delta: delta
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype._handleData = function _handleData (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
// DATA on ended or not readable stream!
|
||||
if (!state.readable || this._readableState.ended) {
|
||||
state.framer.rstFrame({ id: this.id, code: 'STREAM_CLOSED' })
|
||||
return
|
||||
}
|
||||
|
||||
state.debug('id=%d recv=%d', this.id, frame.data.length)
|
||||
state.window.recv.update(-frame.data.length)
|
||||
|
||||
this.push(frame.data)
|
||||
}
|
||||
|
||||
Stream.prototype._handleRST = function _handleRST (frame) {
|
||||
if (frame.code !== 'CANCEL') {
|
||||
this.emit('error', new Error('Got RST: ' + frame.code))
|
||||
}
|
||||
this.abort()
|
||||
}
|
||||
|
||||
Stream.prototype._handleWindowUpdate = function _handleWindowUpdate (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.window.send.update(frame.delta)
|
||||
}
|
||||
|
||||
Stream.prototype._onWindowOverflow = function _onWindowOverflow () {
|
||||
var state = this._spdyState
|
||||
|
||||
state.debug('id=%d window overflow', this.id)
|
||||
state.framer.rstFrame({ id: this.id, code: 'FLOW_CONTROL_ERROR' })
|
||||
|
||||
this.aborted = true
|
||||
this.emit('error', new Error('HTTP2 window overflow'))
|
||||
}
|
||||
|
||||
Stream.prototype._handlePriority = function _handlePriority (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.priority.remove()
|
||||
state.priority = null
|
||||
this._initPriority(frame.priority)
|
||||
|
||||
// Mostly for testing purposes
|
||||
this.emit('priority', frame.priority)
|
||||
}
|
||||
|
||||
Stream.prototype._handleHeaders = function _handleHeaders (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
if (!state.readable || this._readableState.ended) {
|
||||
state.framer.rstFrame({ id: this.id, code: 'STREAM_CLOSED' })
|
||||
return
|
||||
}
|
||||
|
||||
if (state.needResponse) {
|
||||
return this._handleResponse(frame)
|
||||
}
|
||||
|
||||
this.emit('headers', frame.headers)
|
||||
}
|
||||
|
||||
Stream.prototype._handleResponse = function _handleResponse (frame) {
|
||||
var state = this._spdyState
|
||||
|
||||
if (frame.headers[':status'] === undefined) {
|
||||
state.framer.rstFrame({ id: this.id, code: 'PROTOCOL_ERROR' })
|
||||
return
|
||||
}
|
||||
|
||||
state.needResponse = false
|
||||
this.emit('response', frame.headers[':status'] | 0, frame.headers)
|
||||
}
|
||||
|
||||
Stream.prototype._onFinish = function _onFinish () {
|
||||
var state = this._spdyState
|
||||
|
||||
// Send the request if it wasn't sent
|
||||
if (!state.sent) {
|
||||
// NOTE: will send HEADERS with FIN flag
|
||||
this.send()
|
||||
} else {
|
||||
// Just an `.end()` without any writes will trigger immediate `finish` event
|
||||
// without any calls to `_write()`.
|
||||
if (state.corked !== 0) {
|
||||
var self = this
|
||||
state.corkQueue.push(function () {
|
||||
self._onFinish()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
state.framer.dataFrame({
|
||||
id: this.id,
|
||||
priority: state.priority.getPriority(),
|
||||
fin: true,
|
||||
data: Buffer.alloc(0)
|
||||
})
|
||||
}
|
||||
|
||||
this._maybeClose()
|
||||
}
|
||||
|
||||
Stream.prototype._onEnd = function _onEnd () {
|
||||
this._maybeClose()
|
||||
}
|
||||
|
||||
Stream.prototype._checkEnded = function _checkEnded (callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
var ended = false
|
||||
if (state.aborted) { ended = true }
|
||||
|
||||
if (!state.writable || this._writableState.finished) { ended = true }
|
||||
|
||||
if (!ended) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
return false
|
||||
}
|
||||
|
||||
var err = new Error('Ended stream can\'t send frames')
|
||||
process.nextTick(function () {
|
||||
callback(err)
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Stream.prototype._maybeClose = function _maybeClose () {
|
||||
var state = this._spdyState
|
||||
|
||||
// .abort() emits `close`
|
||||
if (state.aborted) {
|
||||
return
|
||||
}
|
||||
|
||||
if ((!state.readable || this._readableState.ended) &&
|
||||
this._writableState.finished) {
|
||||
// Clear timeout
|
||||
state.timeout.set(0)
|
||||
|
||||
this.emit('close')
|
||||
}
|
||||
}
|
||||
|
||||
Stream.prototype._handlePushPromise = function _handlePushPromise (frame) {
|
||||
var push = this.connection._createStream({
|
||||
id: frame.promisedId,
|
||||
parent: this,
|
||||
push: true,
|
||||
request: true,
|
||||
method: frame.headers[':method'],
|
||||
path: frame.headers[':path'],
|
||||
host: frame.headers[':authority'],
|
||||
priority: frame.priority,
|
||||
headers: frame.headers,
|
||||
writable: false
|
||||
})
|
||||
|
||||
// GOAWAY
|
||||
if (this.connection._isGoaway(push.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.emit('pushPromise', push)) {
|
||||
push.abort()
|
||||
}
|
||||
}
|
||||
|
||||
Stream.prototype._hardCork = function _hardCork () {
|
||||
var state = this._spdyState
|
||||
|
||||
this.cork()
|
||||
state.corked++
|
||||
}
|
||||
|
||||
Stream.prototype._hardUncork = function _hardUncork () {
|
||||
var state = this._spdyState
|
||||
|
||||
this.uncork()
|
||||
state.corked--
|
||||
if (state.corked !== 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Invoke callbacks
|
||||
var queue = state.corkQueue
|
||||
state.corkQueue = []
|
||||
for (var i = 0; i < queue.length; i++) {
|
||||
queue[i]()
|
||||
}
|
||||
}
|
||||
|
||||
Stream.prototype._sendPush = function _sendPush (status, response, callback) {
|
||||
var self = this
|
||||
var state = this._spdyState
|
||||
|
||||
this._hardCork()
|
||||
state.framer.pushFrame({
|
||||
id: this.parent.id,
|
||||
promisedId: this.id,
|
||||
priority: state.priority.toJSON(),
|
||||
path: this.path,
|
||||
host: this.host,
|
||||
method: this.method,
|
||||
status: status,
|
||||
headers: this.headers,
|
||||
response: response
|
||||
}, function (err) {
|
||||
self._hardUncork()
|
||||
|
||||
callback(err)
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype._wasSent = function _wasSent () {
|
||||
var state = this._spdyState
|
||||
return state.sent
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
Stream.prototype.send = function send (callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
if (state.sent) {
|
||||
var err = new Error('Stream was already sent')
|
||||
process.nextTick(function () {
|
||||
if (callback) {
|
||||
callback(err)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
state.sent = true
|
||||
state.timeout.reset()
|
||||
|
||||
// GET requests should always be auto-finished
|
||||
if (this.method === 'GET') {
|
||||
this._writableState.ended = true
|
||||
this._writableState.finished = true
|
||||
}
|
||||
|
||||
// TODO(indunty): ideally it should just take a stream object as an input
|
||||
var self = this
|
||||
this._hardCork()
|
||||
state.framer.requestFrame({
|
||||
id: this.id,
|
||||
method: this.method,
|
||||
path: this.path,
|
||||
host: this.host,
|
||||
priority: state.priority.toJSON(),
|
||||
headers: this.headers,
|
||||
fin: this._writableState.finished
|
||||
}, function (err) {
|
||||
self._hardUncork()
|
||||
|
||||
if (!callback) {
|
||||
return
|
||||
}
|
||||
|
||||
callback(err)
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype.respond = function respond (status, headers, callback) {
|
||||
var self = this
|
||||
var state = this._spdyState
|
||||
assert(!state.request, 'Can\'t respond on request')
|
||||
|
||||
state.timeout.reset()
|
||||
|
||||
if (!this._checkEnded(callback)) { return }
|
||||
|
||||
var frame = {
|
||||
id: this.id,
|
||||
status: status,
|
||||
headers: headers
|
||||
}
|
||||
this._hardCork()
|
||||
state.framer.responseFrame(frame, function (err) {
|
||||
self._hardUncork()
|
||||
if (callback) { callback(err) }
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype.setWindow = function setWindow (size) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.timeout.reset()
|
||||
|
||||
if (!this._checkEnded()) {
|
||||
return
|
||||
}
|
||||
|
||||
state.debug('id=%d force window max=%d', this.id, size)
|
||||
state.window.recv.setMax(size)
|
||||
|
||||
var delta = state.window.recv.getDelta()
|
||||
if (delta === 0) { return }
|
||||
|
||||
state.framer.windowUpdateFrame({
|
||||
id: this.id,
|
||||
delta: delta
|
||||
})
|
||||
state.window.recv.update(delta)
|
||||
}
|
||||
|
||||
Stream.prototype.sendHeaders = function sendHeaders (headers, callback) {
|
||||
var self = this
|
||||
var state = this._spdyState
|
||||
|
||||
state.timeout.reset()
|
||||
|
||||
if (!this._checkEnded(callback)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Request wasn't yet send, coalesce headers
|
||||
if (!state.sent) {
|
||||
this.headers = Object.assign({}, this.headers)
|
||||
Object.assign(this.headers, headers)
|
||||
process.nextTick(function () {
|
||||
if (callback) {
|
||||
callback(null)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this._hardCork()
|
||||
state.framer.headersFrame({
|
||||
id: this.id,
|
||||
headers: headers
|
||||
}, function (err) {
|
||||
self._hardUncork()
|
||||
if (callback) { callback(err) }
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype._destroy = function destroy () {
|
||||
this.abort()
|
||||
}
|
||||
|
||||
Stream.prototype.abort = function abort (code, callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
// .abort(callback)
|
||||
if (typeof code === 'function') {
|
||||
callback = code
|
||||
code = null
|
||||
}
|
||||
|
||||
if (this._readableState.ended && this._writableState.finished) {
|
||||
state.debug('id=%d already closed', this.id)
|
||||
if (callback) {
|
||||
process.nextTick(callback)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (state.aborted) {
|
||||
state.debug('id=%d already aborted', this.id)
|
||||
if (callback) { process.nextTick(callback) }
|
||||
return
|
||||
}
|
||||
|
||||
state.aborted = true
|
||||
state.debug('id=%d abort', this.id)
|
||||
|
||||
this.setTimeout(0)
|
||||
|
||||
var abortCode = code || 'CANCEL'
|
||||
|
||||
state.framer.rstFrame({
|
||||
id: this.id,
|
||||
code: abortCode
|
||||
})
|
||||
|
||||
var self = this
|
||||
process.nextTick(function () {
|
||||
if (callback) {
|
||||
callback(null)
|
||||
}
|
||||
self.emit('close', new Error('Aborted, code: ' + abortCode))
|
||||
})
|
||||
}
|
||||
|
||||
Stream.prototype.setPriority = function setPriority (info) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.timeout.reset()
|
||||
|
||||
if (!this._checkEnded()) {
|
||||
return
|
||||
}
|
||||
|
||||
state.debug('id=%d priority change', this.id, info)
|
||||
|
||||
var frame = { id: this.id, priority: info }
|
||||
|
||||
// Change priority on this side
|
||||
this._handlePriority(frame)
|
||||
|
||||
// And on the other too
|
||||
state.framer.priorityFrame(frame)
|
||||
}
|
||||
|
||||
Stream.prototype.pushPromise = function pushPromise (uri, callback) {
|
||||
if (!this._checkEnded(callback)) {
|
||||
return
|
||||
}
|
||||
|
||||
var self = this
|
||||
this._hardCork()
|
||||
var push = this.connection.pushPromise(this, uri, function (err) {
|
||||
self._hardUncork()
|
||||
if (!err) {
|
||||
push._hardUncork()
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
return callback(err, push)
|
||||
}
|
||||
|
||||
if (err) { push.emit('error', err) }
|
||||
})
|
||||
push._hardCork()
|
||||
|
||||
return push
|
||||
}
|
||||
|
||||
Stream.prototype.setMaxChunk = function setMaxChunk (size) {
|
||||
var state = this._spdyState
|
||||
state.maxChunk = size
|
||||
}
|
||||
|
||||
Stream.prototype.setTimeout = function setTimeout (delay, callback) {
|
||||
var state = this._spdyState
|
||||
|
||||
state.timeout.set(delay, callback)
|
||||
}
|
196
my-app/node_modules/spdy-transport/lib/spdy-transport/utils.js
generated
vendored
Executable file
196
my-app/node_modules/spdy-transport/lib/spdy-transport/utils.js
generated
vendored
Executable file
|
@ -0,0 +1,196 @@
|
|||
'use strict'
|
||||
|
||||
var util = require('util')
|
||||
var isNode = require('detect-node')
|
||||
|
||||
// Node.js 0.8, 0.10 and 0.12 support
|
||||
Object.assign = (process.versions.modules >= 46 || !isNode)
|
||||
? Object.assign // eslint-disable-next-line
|
||||
: util._extend
|
||||
|
||||
function QueueItem () {
|
||||
this.prev = null
|
||||
this.next = null
|
||||
}
|
||||
exports.QueueItem = QueueItem
|
||||
|
||||
function Queue () {
|
||||
QueueItem.call(this)
|
||||
|
||||
this.prev = this
|
||||
this.next = this
|
||||
}
|
||||
util.inherits(Queue, QueueItem)
|
||||
exports.Queue = Queue
|
||||
|
||||
Queue.prototype.insertTail = function insertTail (item) {
|
||||
item.prev = this.prev
|
||||
item.next = this
|
||||
item.prev.next = item
|
||||
item.next.prev = item
|
||||
}
|
||||
|
||||
Queue.prototype.remove = function remove (item) {
|
||||
var next = item.next
|
||||
var prev = item.prev
|
||||
|
||||
item.next = item
|
||||
item.prev = item
|
||||
next.prev = prev
|
||||
prev.next = next
|
||||
}
|
||||
|
||||
Queue.prototype.head = function head () {
|
||||
return this.next
|
||||
}
|
||||
|
||||
Queue.prototype.tail = function tail () {
|
||||
return this.prev
|
||||
}
|
||||
|
||||
Queue.prototype.isEmpty = function isEmpty () {
|
||||
return this.next === this
|
||||
}
|
||||
|
||||
Queue.prototype.isRoot = function isRoot (item) {
|
||||
return this === item
|
||||
}
|
||||
|
||||
function LockStream (stream) {
|
||||
this.locked = false
|
||||
this.queue = []
|
||||
this.stream = stream
|
||||
}
|
||||
exports.LockStream = LockStream
|
||||
|
||||
LockStream.prototype.write = function write (chunks, callback) {
|
||||
var self = this
|
||||
|
||||
// Do not let it interleave
|
||||
if (this.locked) {
|
||||
this.queue.push(function () {
|
||||
return self.write(chunks, callback)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.locked = true
|
||||
|
||||
function done (err, chunks) {
|
||||
self.stream.removeListener('error', done)
|
||||
|
||||
self.locked = false
|
||||
if (self.queue.length > 0) { self.queue.shift()() }
|
||||
callback(err, chunks)
|
||||
}
|
||||
|
||||
this.stream.on('error', done)
|
||||
|
||||
// Accumulate all output data
|
||||
var output = []
|
||||
function onData (chunk) {
|
||||
output.push(chunk)
|
||||
}
|
||||
this.stream.on('data', onData)
|
||||
|
||||
function next (err) {
|
||||
self.stream.removeListener('data', onData)
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
|
||||
done(null, output)
|
||||
}
|
||||
|
||||
for (var i = 0; i < chunks.length - 1; i++) { this.stream.write(chunks[i]) }
|
||||
|
||||
if (chunks.length > 0) {
|
||||
this.stream.write(chunks[i], next)
|
||||
} else { process.nextTick(next) }
|
||||
|
||||
if (this.stream.execute) {
|
||||
this.stream.execute(function (err) {
|
||||
if (err) { return done(err) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Just finds the place in array to insert
|
||||
function binaryLookup (list, item, compare) {
|
||||
var start = 0
|
||||
var end = list.length
|
||||
|
||||
while (start < end) {
|
||||
var pos = (start + end) >> 1
|
||||
var cmp = compare(item, list[pos])
|
||||
|
||||
if (cmp === 0) {
|
||||
start = pos
|
||||
end = pos
|
||||
break
|
||||
} else if (cmp < 0) {
|
||||
end = pos
|
||||
} else {
|
||||
start = pos + 1
|
||||
}
|
||||
}
|
||||
|
||||
return start
|
||||
}
|
||||
exports.binaryLookup = binaryLookup
|
||||
|
||||
function binaryInsert (list, item, compare) {
|
||||
var index = binaryLookup(list, item, compare)
|
||||
|
||||
list.splice(index, 0, item)
|
||||
}
|
||||
exports.binaryInsert = binaryInsert
|
||||
|
||||
function binarySearch (list, item, compare) {
|
||||
var index = binaryLookup(list, item, compare)
|
||||
|
||||
if (index >= list.length) {
|
||||
return -1
|
||||
}
|
||||
|
||||
if (compare(item, list[index]) === 0) {
|
||||
return index
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
exports.binarySearch = binarySearch
|
||||
|
||||
function Timeout (object) {
|
||||
this.delay = 0
|
||||
this.timer = null
|
||||
this.object = object
|
||||
}
|
||||
exports.Timeout = Timeout
|
||||
|
||||
Timeout.prototype.set = function set (delay, callback) {
|
||||
this.delay = delay
|
||||
this.reset()
|
||||
if (!callback) { return }
|
||||
|
||||
if (this.delay === 0) {
|
||||
this.object.removeListener('timeout', callback)
|
||||
} else {
|
||||
this.object.once('timeout', callback)
|
||||
}
|
||||
}
|
||||
|
||||
Timeout.prototype.reset = function reset () {
|
||||
if (this.timer !== null) {
|
||||
clearTimeout(this.timer)
|
||||
this.timer = null
|
||||
}
|
||||
|
||||
if (this.delay === 0) { return }
|
||||
|
||||
var self = this
|
||||
this.timer = setTimeout(function () {
|
||||
self.timer = null
|
||||
self.object.emit('timeout')
|
||||
}, this.delay)
|
||||
}
|
174
my-app/node_modules/spdy-transport/lib/spdy-transport/window.js
generated
vendored
Executable file
174
my-app/node_modules/spdy-transport/lib/spdy-transport/window.js
generated
vendored
Executable file
|
@ -0,0 +1,174 @@
|
|||
'use strict'
|
||||
|
||||
var util = require('util')
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var debug = {
|
||||
server: require('debug')('spdy:window:server'),
|
||||
client: require('debug')('spdy:window:client')
|
||||
}
|
||||
|
||||
function Side (window, name, options) {
|
||||
EventEmitter.call(this)
|
||||
|
||||
this.name = name
|
||||
this.window = window
|
||||
this.current = options.size
|
||||
this.max = options.size
|
||||
this.limit = options.max
|
||||
this.lowWaterMark = options.lowWaterMark === undefined
|
||||
? this.max / 2
|
||||
: options.lowWaterMark
|
||||
|
||||
this._refilling = false
|
||||
this._refillQueue = []
|
||||
}
|
||||
util.inherits(Side, EventEmitter)
|
||||
|
||||
Side.prototype.setMax = function setMax (max) {
|
||||
this.window.debug('id=%d side=%s setMax=%d',
|
||||
this.window.id,
|
||||
this.name,
|
||||
max)
|
||||
this.max = max
|
||||
this.lowWaterMark = this.max / 2
|
||||
}
|
||||
|
||||
Side.prototype.updateMax = function updateMax (max) {
|
||||
var delta = max - this.max
|
||||
this.window.debug('id=%d side=%s updateMax=%d delta=%d',
|
||||
this.window.id,
|
||||
this.name,
|
||||
max,
|
||||
delta)
|
||||
|
||||
this.max = max
|
||||
this.lowWaterMark = max / 2
|
||||
|
||||
this.update(delta)
|
||||
}
|
||||
|
||||
Side.prototype.setLowWaterMark = function setLowWaterMark (lwm) {
|
||||
this.lowWaterMark = lwm
|
||||
}
|
||||
|
||||
Side.prototype.update = function update (size, callback) {
|
||||
// Not enough space for the update, wait for refill
|
||||
if (size <= 0 && callback && this.isEmpty()) {
|
||||
this.window.debug('id=%d side=%s wait for refill=%d [%d/%d]',
|
||||
this.window.id,
|
||||
this.name,
|
||||
-size,
|
||||
this.current,
|
||||
this.max)
|
||||
this._refillQueue.push({
|
||||
size: size,
|
||||
callback: callback
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.current += size
|
||||
|
||||
if (this.current > this.limit) {
|
||||
this.emit('overflow')
|
||||
return
|
||||
}
|
||||
|
||||
this.window.debug('id=%d side=%s update by=%d [%d/%d]',
|
||||
this.window.id,
|
||||
this.name,
|
||||
size,
|
||||
this.current,
|
||||
this.max)
|
||||
|
||||
// Time to send WINDOW_UPDATE
|
||||
if (size < 0 && this.isDraining()) {
|
||||
this.window.debug('id=%d side=%s drained', this.window.id, this.name)
|
||||
this.emit('drain')
|
||||
}
|
||||
|
||||
// Time to write
|
||||
if (size > 0 && this.current > 0 && this.current <= size) {
|
||||
this.window.debug('id=%d side=%s full', this.window.id, this.name)
|
||||
this.emit('full')
|
||||
}
|
||||
|
||||
this._processRefillQueue()
|
||||
|
||||
if (callback) { process.nextTick(callback) }
|
||||
}
|
||||
|
||||
Side.prototype.getCurrent = function getCurrent () {
|
||||
return this.current
|
||||
}
|
||||
|
||||
Side.prototype.getMax = function getMax () {
|
||||
return this.max
|
||||
}
|
||||
|
||||
Side.prototype.getDelta = function getDelta () {
|
||||
return this.max - this.current
|
||||
}
|
||||
|
||||
Side.prototype.isDraining = function isDraining () {
|
||||
return this.current <= this.lowWaterMark
|
||||
}
|
||||
|
||||
Side.prototype.isEmpty = function isEmpty () {
|
||||
return this.current <= 0
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
Side.prototype._processRefillQueue = function _processRefillQueue () {
|
||||
// Prevent recursion
|
||||
if (this._refilling) {
|
||||
return
|
||||
}
|
||||
this._refilling = true
|
||||
|
||||
while (this._refillQueue.length > 0) {
|
||||
var item = this._refillQueue[0]
|
||||
|
||||
if (this.isEmpty()) {
|
||||
break
|
||||
}
|
||||
|
||||
this.window.debug('id=%d side=%s refilled for size=%d',
|
||||
this.window.id,
|
||||
this.name,
|
||||
-item.size)
|
||||
|
||||
this._refillQueue.shift()
|
||||
this.update(item.size, item.callback)
|
||||
}
|
||||
|
||||
this._refilling = false
|
||||
}
|
||||
|
||||
function Window (options) {
|
||||
this.id = options.id
|
||||
this.isServer = options.isServer
|
||||
this.debug = this.isServer ? debug.server : debug.client
|
||||
|
||||
this.recv = new Side(this, 'recv', options.recv)
|
||||
this.send = new Side(this, 'send', options.send)
|
||||
}
|
||||
module.exports = Window
|
||||
|
||||
Window.prototype.clone = function clone (id) {
|
||||
return new Window({
|
||||
id: id,
|
||||
isServer: this.isServer,
|
||||
recv: {
|
||||
size: this.recv.max,
|
||||
max: this.recv.limit,
|
||||
lowWaterMark: this.recv.lowWaterMark
|
||||
},
|
||||
send: {
|
||||
size: this.send.max,
|
||||
max: this.send.limit,
|
||||
lowWaterMark: this.send.lowWaterMark
|
||||
}
|
||||
})
|
||||
}
|
43
my-app/node_modules/spdy-transport/package.json
generated
vendored
Executable file
43
my-app/node_modules/spdy-transport/package.json
generated
vendored
Executable file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "spdy-transport",
|
||||
"version": "3.0.0",
|
||||
"main": "lib/spdy-transport",
|
||||
"description": "SPDY v2, v3, v3.1 and HTTP2 transport",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"spdy",
|
||||
"http2",
|
||||
"transport"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/spdy-http2/spdy-transport.git"
|
||||
},
|
||||
"homepage": "https://github.com/spdy-http2/spdy-transport",
|
||||
"author": "Fedor Indutny <fedor@indutny.com>",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.0",
|
||||
"detect-node": "^2.0.4",
|
||||
"hpack.js": "^2.1.6",
|
||||
"obuf": "^1.1.2",
|
||||
"readable-stream": "^3.0.6",
|
||||
"wbuf": "^1.7.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^2.6.1",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "^5.2.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"standard": "^12.0.1",
|
||||
"stream-pair": "^1.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"test": "mocha --reporter=spec test/**/*-test.js test/**/**/*-test.js",
|
||||
"coverage": "istanbul cover node_modules/.bin/_mocha -- --reporter=spec test/**/*-test.js test/**/**/*-test.js"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint",
|
||||
"test"
|
||||
]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue