2013-10-20 07:03:07 -07:00
<!DOCTYPE html>
< html >
< head >
< title > Public API< / title >
< meta http-equiv = "content-type" content = "text/html; charset=UTF-8" >
< meta name = "viewport" content = "width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" >
< link rel = "stylesheet" media = "all" href = "docco.css" / >
< / head >
< body >
< div id = "container" >
< div id = "background" > < / div >
< ul id = "jump_to" >
< li >
< a class = "large" href = "javascript:void(0);" > Jump To … < / a >
< a class = "small" href = "javascript:void(0);" > +< / a >
< div id = "jump_wrapper" >
< div id = "jump_page" >
< a class = "source" href = "http.html" >
http.js
< / a >
< a class = "source" href = "index.html" >
index.js
< / a >
< / div >
< / li >
< / ul >
< ul class = "sections" >
< li id = "section-1" >
< div class = "annotation" >
< div class = "pilwrap for-h1" >
< a class = "pilcrow" href = "#section-1" > ¶ < / a >
< / div >
< h1 > Public API< / h1 >
< / div >
< / li >
< li id = "section-2" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-2" > ¶ < / a >
< / div >
< p > The main governing power behind the http2 API design is that it should look very similar to the
existing node.js [HTTPS API][1] (which is, in turn, almost identical to the [HTTP API][2]). The
additional features of HTTP/2 are exposed as extensions to this API. Furthermore, node-http2
should fall back to using HTTP/1.1 if needed. Compatibility with undocumented or deprecated
elements of the node.js HTTP/HTTPS API is a non-goal.< / p >
< h2 > Additional and modified API elements< / h2 >
< / div >
< / li >
< li id = "section-3" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-3" > ¶ < / a >
< / div >
< ul >
< li > < p > < strong > Class: http2.Endpoint< / strong > : an API for using the raw HTTP/2 framing layer. For documentation
see the < a href = "endpoint.html" > lib/endpoint.js< / a > file.< / p >
< / li >
< li > < p > < strong > Class: http2.Server< / strong > < / p >
< ul >
< li > < strong > Event: ' connection' (socket, [endpoint])< / strong > : there' s a second argument if the negotiation of
HTTP/2 was successful: the reference to the < a href = "endpoint.html" > Endpoint< / a > object tied to the
socket.< / li >
< / ul >
< / li >
< li > < p > < strong > http2.createServer(options, [requestListener])< / strong > : additional option:< / p >
< ul >
< li > < strong > log< / strong > : an optional < a href = "https://github.com/trentm/node-bunyan" > bunyan< / a > logger object< / li >
< li > < strong > plain< / strong > : if < code > true< / code > , the server will accept HTTP/2 connections over plain TCP instead of
TLS< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.ServerResponse< / strong > < / p >
< ul >
< li > < strong > response.push(options)< / strong > : initiates a server push. < code > options< / code > describes the ' imaginary'
request to which the push stream is a response; the possible options are identical to the
ones accepted by < code > http2.request< / code > . Returns a ServerResponse object that can be used to send
the response headers and content.< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.Agent< / strong > < / p >
< ul >
< li > < strong > new Agent(options)< / strong > : additional option:< ul >
< li > < strong > log< / strong > : an optional < a href = "https://github.com/trentm/node-bunyan" > bunyan< / a > logger object< / li >
< / ul >
< / li >
< li > < strong > agent.sockets< / strong > : only contains TCP sockets that corresponds to HTTP/1 requests.< / li >
< li > < strong > agent.endpoints< / strong > : contains < a href = "endpoint.html" > Endpoint< / a > objects for HTTP/2 connections.< / li >
< / ul >
< / li >
< li > < p > < strong > http2.request(options, [callback])< / strong > : additional option:< / p >
< ul >
< li > < strong > plain< / strong > : if < code > true< / code > , the client will not try to build a TLS tunnel, instead it will use
the raw TCP stream for HTTP/2< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.ClientRequest< / strong > < / p >
< ul >
< li > < strong > Event: ' socket' (socket)< / strong > : in case of an HTTP/2 incoming message, < code > socket< / code > is a reference
to the associated < a href = "stream.html" > HTTP/2 Stream< / a > object (and not to the TCP socket).< / li >
< li > < strong > Event: ' push' (promise)< / strong > : signals the intention of a server push associated to this
request. < code > promise< / code > is an IncomingPromise. If there' s no listener for this event, the server
push is cancelled.< / li >
< li > < strong > request.setPriority(priority)< / strong > : assign a priority to this request. < code > priority< / code > is a number
between 0 (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.IncomingMessage< / strong > < / p >
< ul >
< li > has two subclasses for easier interface description: < strong > IncomingRequest< / strong > and
< strong > IncomingResponse< / strong > < / li >
< li > < strong > message.socket< / strong > : in case of an HTTP/2 incoming message, it' s a reference to the associated
< a href = "stream.html" > HTTP/2 Stream< / a > object (and not to the TCP socket).< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.IncomingRequest (IncomingMessage)< / strong > < / p >
< ul >
< li > < strong > message.url< / strong > : in case of an HTTP/2 incoming request, the < code > url< / code > field always contains the
path, and never a full url (it contains the path in most cases in the HTTPS api as well).< / li >
< li > < strong > message.scheme< / strong > : additional field. Mandatory HTTP/2 request metadata.< / li >
< li > < strong > message.host< / strong > : additional field. Mandatory HTTP/2 request metadata. Note that this
replaces the old Host header field, but node-http2 will add Host to the < code > message.headers< / code > for
backwards compatibility.< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.IncomingPromise (IncomingRequest)< / strong > < / p >
< ul >
< li > contains the metadata of the ' imaginary' request to which the server push is an answer.< / li >
< li > < strong > Event: ' response' (response)< / strong > : signals the arrival of the actual push stream. < code > response< / code >
is an IncomingResponse.< / li >
< li > < strong > Event: ' push' (promise)< / strong > : signals the intention of a server push associated to this
request. < code > promise< / code > is an IncomingPromise. If there' s no listener for this event, the server
push is cancelled.< / li >
< li > < strong > promise.cancel()< / strong > : cancels the promised server push.< / li >
< li > < strong > promise.setPriority(priority)< / strong > : assign a priority to this push stream. < code > priority< / code > is a
number between 0 (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.< / li >
< / ul >
< / li >
< / ul >
< h2 > API elements not yet implemented< / h2 >
< / div >
< / li >
< li id = "section-4" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-4" > ¶ < / a >
< / div >
< ul >
< li > < strong > Class: http2.Server< / strong > < ul >
< li > < strong > server.maxHeadersCount< / strong > < / li >
< / ul >
< / li >
< / ul >
< h2 > API elements that are not applicable to HTTP/2< / h2 >
< / div >
< / li >
< li id = "section-5" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-5" > ¶ < / a >
< / div >
< p > The reason may be deprecation of certain HTTP/1.1 features, or that some API elements simply
don' t make sense when using HTTP/2. These will not be present when a request is done with HTTP/2,
but will function normally when falling back to using HTTP/1.1.< / p >
< ul >
< li > < p > < strong > Class: http2.Server< / strong > < / p >
< ul >
< li > < strong > Event: ' checkContinue' < / strong > : not in the spec, yet (see < a href = "https://github.com/http2/http2-spec/issues/18" > http-spec#18< / a > )< / li >
< li > < strong > Event: ' upgrade' < / strong > : upgrade is deprecated in HTTP/2< / li >
< li > < strong > Event: ' timeout' < / strong > : HTTP/2 sockets won' t timeout because of application level keepalive
(PING frames)< / li >
< li > < strong > Event: ' connect' < / strong > : not in the spec, yet (see < a href = "https://github.com/http2/http2-spec/issues/230" > http-spec#230< / a > )< / li >
< li > < strong > server.setTimeout(msecs, [callback])< / strong > < / li >
< li > < strong > server.timeout< / strong > < / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.ServerResponse< / strong > < / p >
< ul >
< li > < strong > Event: ' close' < / strong > < / li >
< li > < strong > Event: ' timeout' < / strong > < / li >
< li > < strong > response.writeContinue()< / strong > < / li >
< li > < strong > response.writeHead(statusCode, [reasonPhrase], [headers])< / strong > : reasonPhrase will always be
2014-01-13 17:16:28 -08:00
ignored since < a href = "http://tools.ietf.org/html/draft-ietf-httpbis-http2-09#section-8.1.3.2" > it' s not supported in HTTP/2< / a > < / li >
2013-10-20 07:03:07 -07:00
< li > < strong > response.setTimeout(timeout, [callback])< / strong > < / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.Agent< / strong > < / p >
< ul >
< li > < strong > agent.maxSockets< / strong > : only affects HTTP/1 connection pool. When using HTTP/2, there' s always
one connection per host.< / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.ClientRequest< / strong > < / p >
< ul >
< li > < strong > Event: ' upgrade' < / strong > < / li >
< li > < strong > Event: ' connect' < / strong > < / li >
< li > < strong > Event: ' continue' < / strong > < / li >
< li > < strong > request.setTimeout(timeout, [callback])< / strong > < / li >
< li > < strong > request.setNoDelay([noDelay])< / strong > < / li >
< li > < strong > request.setSocketKeepAlive([enable], [initialDelay])< / strong > < / li >
< / ul >
< / li >
< li > < p > < strong > Class: http2.IncomingMessage< / strong > < / p >
< ul >
< li > < strong > Event: ' close' < / strong > < / li >
< li > < strong > message.setTimeout(timeout, [callback])< / strong > < / li >
< / ul >
< / li >
< / ul >
< h1 > Common server and client side code< / h1 >
< / div >
< / li >
< li id = "section-6" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-6" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > var< / span > net = require(< span class = "string" > 'net'< / span > );
< span class = "keyword" > var< / span > url = require(< span class = "string" > 'url'< / span > );
< span class = "keyword" > var< / span > util = require(< span class = "string" > 'util'< / span > );
< span class = "keyword" > var< / span > EventEmitter = require(< span class = "string" > 'events'< / span > ).EventEmitter;
< span class = "keyword" > var< / span > PassThrough = require(< span class = "string" > 'stream'< / span > ).PassThrough;
< span class = "keyword" > var< / span > Readable = require(< span class = "string" > 'stream'< / span > ).Readable;
< span class = "keyword" > var< / span > Writable = require(< span class = "string" > 'stream'< / span > ).Writable;
< span class = "keyword" > var< / span > Endpoint = require(< span class = "string" > 'http2-protocol'< / span > ).Endpoint;
< span class = "keyword" > var< / span > http = require(< span class = "string" > 'http'< / span > );
< span class = "keyword" > var< / span > https = require(< span class = "string" > 'https'< / span > );
exports.STATUS_CODES = http.STATUS_CODES;
exports.IncomingMessage = IncomingMessage;
exports.OutgoingMessage = OutgoingMessage;
< span class = "keyword" > var< / span > deprecatedHeaders = [
< span class = "string" > 'connection'< / span > ,
< span class = "string" > 'host'< / span > ,
< span class = "string" > 'keep-alive'< / span > ,
< span class = "string" > 'proxy-connection'< / span > ,
< span class = "string" > 'te'< / span > ,
< span class = "string" > 'transfer-encoding'< / span > ,
< span class = "string" > 'upgrade'< / span >
];< / pre > < / div > < / div >
< / li >
< li id = "section-7" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-7" > ¶ < / a >
< / div >
2014-01-13 17:16:28 -08:00
< p > The implemented version of the HTTP/2 specification is < a href = "http://tools.ietf.org/html/draft-ietf-httpbis-http2-09" > draft 09< / a > .< / p >
2013-10-20 07:03:07 -07:00
< / div >
2014-01-13 17:16:28 -08:00
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > var< / span > implementedVersion = < span class = "string" > 'HTTP-draft-09/2.0'< / span > ;< / pre > < / div > < / div >
2013-10-20 07:03:07 -07:00
< / li >
< li id = "section-8" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-8" > ¶ < / a >
< / div >
< p > When doing NPN/ALPN negotiation, HTTP/1.1 is used as fallback< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > var< / span > supportedProtocols = [implementedVersion, < span class = "string" > 'http/1.1'< / span > , < span class = "string" > 'http/1.0'< / span > ];< / pre > < / div > < / div >
< / li >
< li id = "section-9" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-9" > ¶ < / a >
< / div >
< h2 > Logging< / h2 >
< / div >
< / li >
< li id = "section-10" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-10" > ¶ < / a >
< / div >
< p > Logger shim, used when no logger is provided by the user.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > noop< / span > < span class = "params" > ()< / span > {< / span > }
< span class = "keyword" > var< / span > defaultLogger = {
fatal: noop,
error: noop,
warn : noop,
info : noop,
debug: noop,
trace: noop,
child: < span class = "keyword" > function< / span > () { < span class = "keyword" > return< / span > < span class = "keyword" > this< / span > ; }
};< / pre > < / div > < / div >
< / li >
< li id = "section-11" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-11" > ¶ < / a >
< / div >
< p > Bunyan serializers exported by submodules that are worth adding when creating a logger.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > exports.serializers = require(< span class = "string" > 'http2-protocol'< / span > ).serializers;< / pre > < / div > < / div >
< / li >
< li id = "section-12" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-12" > ¶ < / a >
< / div >
< h2 > IncomingMessage class< / h2 >
< / div >
< / li >
< li id = "section-13" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-13" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > IncomingMessage< / span > < span class = "params" > (stream)< / span > {< / span > < / pre > < / div > < / div >
< / li >
< li id = "section-14" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-14" > ¶ < / a >
< / div >
< ul >
< li > This is basically a read-only wrapper for the < a href = "stream.html" > Stream< / a > class.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > PassThrough.call(< span class = "keyword" > this< / span > );
stream.pipe(< span class = "keyword" > this< / span > );
< span class = "keyword" > this< / span > .socket = < span class = "keyword" > this< / span > .stream = stream;
< span class = "keyword" > this< / span > ._log = stream._log.child({ component: < span class = "string" > 'http'< / span > });< / pre > < / div > < / div >
< / li >
< li id = "section-15" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-15" > ¶ < / a >
< / div >
< ul >
< li > HTTP/2.0 does not define a way to carry the version identifier that is included in the
HTTP/1.1 request/status line. Version is always 2.0.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > .httpVersion = < span class = "string" > '2.0'< / span > ;
< span class = "keyword" > this< / span > .httpVersionMajor = < span class = "number" > 2< / span > ;
< span class = "keyword" > this< / span > .httpVersionMinor = < span class = "number" > 0< / span > ;< / pre > < / div > < / div >
< / li >
< li id = "section-16" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-16" > ¶ < / a >
< / div >
< ul >
< li > < code > this.headers< / code > will store the regular headers (and none of the special colon headers)< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > .headers = {};
< span class = "keyword" > this< / span > .trailers = < span class = "literal" > undefined< / span > ;
< span class = "keyword" > this< / span > ._lastHeadersSeen = < span class = "literal" > undefined< / span > ;< / pre > < / div > < / div >
< / li >
< li id = "section-17" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-17" > ¶ < / a >
< / div >
< ul >
< li > Other metadata is filled in when the headers arrive.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > stream.once(< span class = "string" > 'headers'< / span > , < span class = "keyword" > this< / span > ._onHeaders.bind(< span class = "keyword" > this< / span > ));
stream.once(< span class = "string" > 'end'< / span > , < span class = "keyword" > this< / span > ._onEnd.bind(< span class = "keyword" > this< / span > ));
}
IncomingMessage.prototype = Object.create(PassThrough.prototype, { constructor: { value: IncomingMessage } });< / pre > < / div > < / div >
< / li >
< li id = "section-18" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-18" > ¶ < / a >
< / div >
2014-01-13 17:16:28 -08:00
< p > < a href = "http://tools.ietf.org/html/draft-ietf-httpbis-http2-09#section-8.1.3.1" > Request Header Fields< / a >
2013-10-20 07:03:07 -07:00
* < code > headers< / code > argument: HTTP/2.0 request and response header fields carry information as a series
of key-value pairs. This includes the target URI for the request, the status code for the
response, as well as HTTP header fields.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > IncomingMessage.prototype._onHeaders = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onHeaders< / span > < span class = "params" > (headers)< / span > {< / span > < / pre > < / div > < / div >
< / li >
< li id = "section-19" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-19" > ¶ < / a >
< / div >
< ul >
< li > An HTTP/2.0 request or response MUST NOT include any of the following header fields:
Connection, Host, Keep-Alive, Proxy-Connection, TE, Transfer-Encoding, and Upgrade. A server
MUST treat the presence of any of these header fields as a stream error of type
PROTOCOL_ERROR.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > for< / span > (< span class = "keyword" > var< / span > i = < span class = "number" > 0< / span > ; i < deprecatedHeaders.length; i++) {
< span class = "keyword" > var< / span > key = deprecatedHeaders[i];
< span class = "keyword" > if< / span > (key < span class = "keyword" > in< / span > headers) {
< span class = "keyword" > this< / span > ._log.error({ key: key, value: headers[key] }, < span class = "string" > 'Deprecated header found'< / span > );
< span class = "keyword" > this< / span > .stream.emit(< span class = "string" > 'error'< / span > , < span class = "string" > 'PROTOCOL_ERROR'< / span > );
< span class = "keyword" > return< / span > ;
}
}< / pre > < / div > < / div >
< / li >
< li id = "section-20" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-20" > ¶ < / a >
< / div >
< ul >
< li > Store the < em > regular< / em > headers in < code > this.headers< / code > < / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > for< / span > (< span class = "keyword" > var< / span > name < span class = "keyword" > in< / span > headers) {
< span class = "keyword" > if< / span > (name[< span class = "number" > 0< / span > ] !== < span class = "string" > ':'< / span > ) {
< span class = "keyword" > this< / span > .headers[name] = headers[name];
}
}< / pre > < / div > < / div >
< / li >
< li id = "section-21" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-21" > ¶ < / a >
< / div >
< ul >
< li > The last header block, if it' s not the first, will represent the trailers< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > var< / span > self = < span class = "keyword" > this< / span > ;
< span class = "keyword" > this< / span > .stream.on(< span class = "string" > 'headers'< / span > , < span class = "keyword" > function< / span > (headers) {
self._lastHeadersSeen = headers;
});
};
IncomingMessage.prototype._onEnd = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onEnd< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > this< / span > .trailers = < span class = "keyword" > this< / span > ._lastHeadersSeen;
};
IncomingMessage.prototype.setTimeout = noop;
IncomingMessage.prototype._checkSpecialHeader = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _checkSpecialHeader< / span > < span class = "params" > (key, value)< / span > {< / span >
< span class = "keyword" > if< / span > ((< span class = "keyword" > typeof< / span > value !== < span class = "string" > 'string'< / span > ) || (value.length === < span class = "number" > 0< / span > )) {
< span class = "keyword" > this< / span > ._log.error({ key: key, value: value }, < span class = "string" > 'Invalid or missing special header field'< / span > );
< span class = "keyword" > this< / span > .stream.emit(< span class = "string" > 'error'< / span > , < span class = "string" > 'PROTOCOL_ERROR'< / span > );
}
< span class = "keyword" > return< / span > value;
}
;< / pre > < / div > < / div >
< / li >
< li id = "section-22" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-22" > ¶ < / a >
< / div >
< h2 > OutgoingMessage class< / h2 >
< / div >
< / li >
< li id = "section-23" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-23" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > OutgoingMessage< / span > < span class = "params" > ()< / span > {< / span > < / pre > < / div > < / div >
< / li >
< li id = "section-24" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-24" > ¶ < / a >
< / div >
< ul >
< li > This is basically a read-only wrapper for the < a href = "stream.html" > Stream< / a > class.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > Writable.call(< span class = "keyword" > this< / span > );
< span class = "keyword" > this< / span > ._headers = {};
< span class = "keyword" > this< / span > ._trailers = < span class = "literal" > undefined< / span > ;
< span class = "keyword" > this< / span > .headersSent = < span class = "literal" > false< / span > ;
< span class = "keyword" > this< / span > .on(< span class = "string" > 'finish'< / span > , < span class = "keyword" > this< / span > ._finish);
}
OutgoingMessage.prototype = Object.create(Writable.prototype, { constructor: { value: OutgoingMessage } });
OutgoingMessage.prototype._write = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _write< / span > < span class = "params" > (chunk, encoding, callback)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > this< / span > .stream.write(chunk, encoding, callback);
} < span class = "keyword" > else< / span > {
< span class = "keyword" > this< / span > .once(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > ._write.bind(< span class = "keyword" > this< / span > , chunk, encoding, callback));
}
};
OutgoingMessage.prototype._finish = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _finish< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > ._trailers) {
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request) {
< span class = "keyword" > this< / span > .request.addTrailers(< span class = "keyword" > this< / span > ._trailers);
} < span class = "keyword" > else< / span > {
< span class = "keyword" > this< / span > .stream.headers(< span class = "keyword" > this< / span > ._trailers);
}
}
< span class = "keyword" > this< / span > .stream.end();
} < span class = "keyword" > else< / span > {
< span class = "keyword" > this< / span > .once(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > ._finish.bind(< span class = "keyword" > this< / span > ));
}
};
OutgoingMessage.prototype.setHeader = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setHeader< / span > < span class = "params" > (name, value)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .headersSent) {
< span class = "keyword" > throw< / span > < span class = "keyword" > new< / span > Error(< span class = "string" > 'Can\'t set headers after they are sent.'< / span > );
} < span class = "keyword" > else< / span > {
name = name.toLowerCase();
< span class = "keyword" > if< / span > (deprecatedHeaders.indexOf(name) !== -< span class = "number" > 1< / span > ) {
< span class = "keyword" > throw< / span > < span class = "keyword" > new< / span > Error(< span class = "string" > 'Cannot set deprecated header: '< / span > + name);
}
< span class = "keyword" > this< / span > ._headers[name] = value;
}
};
OutgoingMessage.prototype.removeHeader = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > removeHeader< / span > < span class = "params" > (name)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .headersSent) {
< span class = "keyword" > throw< / span > < span class = "keyword" > new< / span > Error(< span class = "string" > 'Can\'t remove headers after they are sent.'< / span > );
} < span class = "keyword" > else< / span > {
< span class = "keyword" > delete< / span > < span class = "keyword" > this< / span > ._headers[name.toLowerCase()];
}
};
OutgoingMessage.prototype.getHeader = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > getHeader< / span > < span class = "params" > (name)< / span > {< / span >
< span class = "keyword" > return< / span > < span class = "keyword" > this< / span > ._headers[name.toLowerCase()];
};
OutgoingMessage.prototype.addTrailers = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > addTrailers< / span > < span class = "params" > (trailers)< / span > {< / span >
< span class = "keyword" > this< / span > ._trailers = trailers;
};
OutgoingMessage.prototype.setTimeout = noop;
OutgoingMessage.prototype._checkSpecialHeader = IncomingMessage.prototype._checkSpecialHeader;< / pre > < / div > < / div >
< / li >
< li id = "section-25" >
< div class = "annotation" >
< div class = "pilwrap for-h1" >
< a class = "pilcrow" href = "#section-25" > ¶ < / a >
< / div >
< h1 > Server side< / h1 >
< / div >
< / li >
< li id = "section-26" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-26" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > exports.createServer = createServer;
exports.Server = Server;
exports.IncomingRequest = IncomingRequest;
exports.OutgoingResponse = OutgoingResponse;
exports.ServerResponse = OutgoingResponse; < span class = "comment" > // for API compatibility< / span > < / pre > < / div > < / div >
< / li >
< li id = "section-27" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-27" > ¶ < / a >
< / div >
< h2 > Server class< / h2 >
< / div >
< / li >
< li id = "section-28" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-28" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > Server< / span > < span class = "params" > (options)< / span > {< / span >
options = util._extend({}, options);
< span class = "keyword" > this< / span > ._log = (options.log || defaultLogger).child({ component: < span class = "string" > 'http'< / span > });
< span class = "keyword" > this< / span > ._settings = options.settings;
< span class = "keyword" > var< / span > start = < span class = "keyword" > this< / span > ._start.bind(< span class = "keyword" > this< / span > );
< span class = "keyword" > var< / span > fallback = < span class = "keyword" > this< / span > ._fallback.bind(< span class = "keyword" > this< / span > );< / pre > < / div > < / div >
< / li >
< li id = "section-29" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-29" > ¶ < / a >
< / div >
< p > HTTP2 over TLS (using NPN or ALPN)< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > if< / span > ((options.key & & options.cert) || options.pfx) {
< span class = "keyword" > this< / span > ._log.info(< span class = "string" > 'Creating HTTP/2 server over TLS'< / span > );
< span class = "keyword" > this< / span > ._mode = < span class = "string" > 'tls'< / span > ;
options.ALPNProtocols = supportedProtocols;
options.NPNProtocols = supportedProtocols;
< span class = "keyword" > this< / span > ._server = https.createServer(options);
< span class = "keyword" > this< / span > ._originalSocketListeners = < span class = "keyword" > this< / span > ._server.listeners(< span class = "string" > 'secureConnection'< / span > );
< span class = "keyword" > this< / span > ._server.removeAllListeners(< span class = "string" > 'secureConnection'< / span > );
< span class = "keyword" > this< / span > ._server.on(< span class = "string" > 'secureConnection'< / span > , < span class = "keyword" > function< / span > (socket) {
< span class = "keyword" > var< / span > negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
< span class = "keyword" > if< / span > ((negotiatedProtocol === implementedVersion) & & socket.servername) {
start(socket);
} < span class = "keyword" > else< / span > {
fallback(socket);
}
});
< span class = "keyword" > this< / span > ._server.on(< span class = "string" > 'request'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'request'< / span > ));
}< / pre > < / div > < / div >
< / li >
< li id = "section-30" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-30" > ¶ < / a >
< / div >
< p > HTTP2 over plain TCP< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > else< / span > < span class = "keyword" > if< / span > (options.plain) {
< span class = "keyword" > this< / span > ._log.info(< span class = "string" > 'Creating HTTP/2 server over plain TCP'< / span > );
< span class = "keyword" > this< / span > ._mode = < span class = "string" > 'plain'< / span > ;
< span class = "keyword" > this< / span > ._server = net.createServer(start);
}< / pre > < / div > < / div >
< / li >
< li id = "section-31" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-31" > ¶ < / a >
< / div >
< p > HTTP/2 with HTTP/1.1 upgrade< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > else< / span > {
< span class = "keyword" > this< / span > ._log.error(< span class = "string" > 'Trying to create HTTP/2 server with Upgrade from HTTP/1.1'< / span > );
< span class = "keyword" > throw< / span > < span class = "keyword" > new< / span > Error(< span class = "string" > 'HTTP1.1 -> HTTP2 upgrade is not yet supported. Please provide TLS keys.'< / span > );
}
< span class = "keyword" > this< / span > ._server.on(< span class = "string" > 'close'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'close'< / span > ));
}
Server.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Server } });< / pre > < / div > < / div >
< / li >
< li id = "section-32" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-32" > ¶ < / a >
< / div >
< p > Starting HTTP/2< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > Server.prototype._start = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _start< / span > < span class = "params" > (socket)< / span > {< / span >
< span class = "keyword" > var< / span > endpoint = < span class = "keyword" > new< / span > Endpoint(< span class = "keyword" > this< / span > ._log, < span class = "string" > 'SERVER'< / span > , < span class = "keyword" > this< / span > ._settings);
< span class = "keyword" > this< / span > ._log.info({ e: endpoint,
client: socket.remoteAddress + < span class = "string" > ':'< / span > + socket.remotePort,
SNI: socket.servername
}, < span class = "string" > 'New incoming HTTP/2 connection'< / span > );
endpoint.pipe(socket).pipe(endpoint);
< span class = "keyword" > var< / span > self = < span class = "keyword" > this< / span > ;
endpoint.on(< span class = "string" > 'stream'< / span > , < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onStream< / span > < span class = "params" > (stream)< / span > {< / span >
< span class = "keyword" > var< / span > response = < span class = "keyword" > new< / span > OutgoingResponse(stream);
< span class = "keyword" > var< / span > request = < span class = "keyword" > new< / span > IncomingRequest(stream);
request.once(< span class = "string" > 'ready'< / span > , self.emit.bind(self, < span class = "string" > 'request'< / span > , request, response));
});
endpoint.on(< span class = "string" > 'error'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'clientError'< / span > ));
2014-01-13 17:16:28 -08:00
socket.on(< span class = "string" > 'error'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'clientError'< / span > ));
2013-10-20 07:03:07 -07:00
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'connection'< / span > , socket, endpoint);
};
Server.prototype._fallback = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _fallback< / span > < span class = "params" > (socket)< / span > {< / span >
< span class = "keyword" > var< / span > negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
< span class = "keyword" > this< / span > ._log.info({ client: socket.remoteAddress + < span class = "string" > ':'< / span > + socket.remotePort,
protocol: negotiatedProtocol,
SNI: socket.servername
}, < span class = "string" > 'Falling back to simple HTTPS'< / span > );
< span class = "keyword" > for< / span > (< span class = "keyword" > var< / span > i = < span class = "number" > 0< / span > ; i < < span class = "keyword" > this< / span > ._originalSocketListeners.length; i++) {
< span class = "keyword" > this< / span > ._originalSocketListeners[i].call(< span class = "keyword" > this< / span > ._server, socket);
}
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'connection'< / span > , socket);
};< / pre > < / div > < / div >
< / li >
< li id = "section-33" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-33" > ¶ < / a >
< / div >
< p > There are < a href = "http://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback" > 3 possible signatures< / a > of the < code > listen< / code > function. Every arguments is forwarded to
the backing TCP or HTTPS server.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > Server.prototype.listen = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > listen< / span > < span class = "params" > (port, hostname)< / span > {< / span >
< span class = "keyword" > this< / span > ._log.info({ on: ((< span class = "keyword" > typeof< / span > hostname === < span class = "string" > 'string'< / span > ) ? (hostname + < span class = "string" > ':'< / span > + port) : port) },
< span class = "string" > 'Listening for incoming connections'< / span > );
< span class = "keyword" > this< / span > ._server.listen.apply(< span class = "keyword" > this< / span > ._server, arguments);
};
Server.prototype.close = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > close< / span > < span class = "params" > (callback)< / span > {< / span >
< span class = "keyword" > this< / span > ._log.info(< span class = "string" > 'Closing server'< / span > );
< span class = "keyword" > this< / span > ._server.close(callback);
};
Server.prototype.setTimeout = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setTimeout< / span > < span class = "params" > (timeout, callback)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > ._mode === < span class = "string" > 'tls'< / span > ) {
< span class = "keyword" > this< / span > ._server.setTimeout(timeout, callback);
}
};
Object.defineProperty(Server.prototype, < span class = "string" > 'timeout'< / span > , {
get: < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > getTimeout< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > ._mode === < span class = "string" > 'tls'< / span > ) {
< span class = "keyword" > return< / span > < span class = "keyword" > this< / span > ._server.timeout;
} < span class = "keyword" > else< / span > {
< span class = "keyword" > return< / span > < span class = "literal" > undefined< / span > ;
}
},
set: < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setTimeout< / span > < span class = "params" > (timeout)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > ._mode === < span class = "string" > 'tls'< / span > ) {
< span class = "keyword" > this< / span > ._server.timeout = timeout;
}
}
});< / pre > < / div > < / div >
< / li >
< li id = "section-34" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-34" > ¶ < / a >
< / div >
< p > Overriding < code > EventEmitter< / code > ' s < code > on(event, listener)< / code > method to forward certain subscriptions to
< code > server< / code > .There are events on the < code > http.Server< / code > class where it makes difference whether someone is
listening on the event or not. In these cases, we can not simply forward the events from the
< code > server< / code > to < code > this< / code > since that means a listener. Instead, we forward the subscriptions.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > Server.prototype.on = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > on< / span > < span class = "params" > (event, listener)< / span > {< / span >
< span class = "keyword" > if< / span > ((event === < span class = "string" > 'upgrade'< / span > ) || (event === < span class = "string" > 'timeout'< / span > )) {
< span class = "keyword" > this< / span > ._server.on(event, listener & & listener.bind(< span class = "keyword" > this< / span > ));
} < span class = "keyword" > else< / span > {
EventEmitter.prototype.on.call(< span class = "keyword" > this< / span > , event, listener);
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-35" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-35" > ¶ < / a >
< / div >
< p > < code > addContext< / code > is used to add Server Name Indication contexts< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > Server.prototype.addContext = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > addContext< / span > < span class = "params" > (hostname, credentials)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > ._mode === < span class = "string" > 'tls'< / span > ) {
< span class = "keyword" > this< / span > ._server.addContext(hostname, credentials);
}
};
< span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > createServer< / span > < span class = "params" > (options, requestListener)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > typeof< / span > options === < span class = "string" > 'function'< / span > ) {
requestListener = options;
options = < span class = "literal" > undefined< / span > ;
}
< span class = "keyword" > var< / span > server = < span class = "keyword" > new< / span > Server(options);
< span class = "keyword" > if< / span > (requestListener) {
server.on(< span class = "string" > 'request'< / span > , requestListener);
}
< span class = "keyword" > return< / span > server;
}< / pre > < / div > < / div >
< / li >
< li id = "section-36" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-36" > ¶ < / a >
< / div >
< h2 > IncomingRequest class< / h2 >
< / div >
< / li >
< li id = "section-37" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-37" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > IncomingRequest< / span > < span class = "params" > (stream)< / span > {< / span >
IncomingMessage.call(< span class = "keyword" > this< / span > , stream);
}
IncomingRequest.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingRequest } });< / pre > < / div > < / div >
< / li >
< li id = "section-38" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-38" > ¶ < / a >
< / div >
2014-01-13 17:16:28 -08:00
< p > < a href = "http://tools.ietf.org/html/draft-ietf-httpbis-http2-09#section-8.1.3.1" > Request Header Fields< / a >
2013-10-20 07:03:07 -07:00
* < code > headers< / code > argument: HTTP/2.0 request and response header fields carry information as a series
of key-value pairs. This includes the target URI for the request, the status code for the
response, as well as HTTP header fields.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > IncomingRequest.prototype._onHeaders = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onHeaders< / span > < span class = "params" > (headers)< / span > {< / span > < / pre > < / div > < / div >
< / li >
< li id = "section-39" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-39" > ¶ < / a >
< / div >
< ul >
< li > The " :method" header field includes the HTTP method< / li >
< li > The " :scheme" header field includes the scheme portion of the target URI< / li >
< li > The " :authority" header field includes the authority portion of the target URI< / li >
< li > The " :path" header field includes the path and query parts of the target URI.
This field MUST NOT be empty; URIs that do not contain a path component MUST include a value
of ' /' , unless the request is an OPTIONS request for ' < em > ' , in which case the " :path" header
field MUST include ' < / em > ' .< / li >
< li > All HTTP/2.0 requests MUST include exactly one valid value for all of these header fields. A
server MUST treat the absence of any of these header fields, presence of multiple values, or
an invalid value as a stream error of type PROTOCOL_ERROR.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > .method = < span class = "keyword" > this< / span > ._checkSpecialHeader(< span class = "string" > ':method'< / span > , headers[< span class = "string" > ':method'< / span > ]);
< span class = "keyword" > this< / span > .scheme = < span class = "keyword" > this< / span > ._checkSpecialHeader(< span class = "string" > ':scheme'< / span > , headers[< span class = "string" > ':scheme'< / span > ]);
< span class = "keyword" > this< / span > .host = < span class = "keyword" > this< / span > ._checkSpecialHeader(< span class = "string" > ':authority'< / span > , headers[< span class = "string" > ':authority'< / span > ] );
< span class = "keyword" > this< / span > .url = < span class = "keyword" > this< / span > ._checkSpecialHeader(< span class = "string" > ':path'< / span > , headers[< span class = "string" > ':path'< / span > ] );< / pre > < / div > < / div >
< / li >
< li id = "section-40" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-40" > ¶ < / a >
< / div >
< ul >
< li > Host header is included in the headers object for backwards compatibility.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > .headers.host = < span class = "keyword" > this< / span > .host;< / pre > < / div > < / div >
< / li >
< li id = "section-41" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-41" > ¶ < / a >
< / div >
< ul >
< li > Handling regular headers.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > IncomingMessage.prototype._onHeaders.call(< span class = "keyword" > this< / span > , headers);< / pre > < / div > < / div >
< / li >
< li id = "section-42" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-42" > ¶ < / a >
< / div >
< ul >
< li > Signaling that the headers arrived.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > ._log.info({ method: < span class = "keyword" > this< / span > .method, scheme: < span class = "keyword" > this< / span > .scheme, host: < span class = "keyword" > this< / span > .host,
path: < span class = "keyword" > this< / span > .url, headers: < span class = "keyword" > this< / span > .headers }, < span class = "string" > 'Incoming request'< / span > );
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'ready'< / span > );
};< / pre > < / div > < / div >
< / li >
< li id = "section-43" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-43" > ¶ < / a >
< / div >
< h2 > OutgoingResponse class< / h2 >
< / div >
< / li >
< li id = "section-44" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-44" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > OutgoingResponse< / span > < span class = "params" > (stream)< / span > {< / span >
OutgoingMessage.call(< span class = "keyword" > this< / span > );
< span class = "keyword" > this< / span > ._log = stream._log.child({ component: < span class = "string" > 'http'< / span > });
< span class = "keyword" > this< / span > .stream = stream;
< span class = "keyword" > this< / span > .statusCode = < span class = "number" > 200< / span > ;
< span class = "keyword" > this< / span > .sendDate = < span class = "literal" > true< / span > ;
< span class = "keyword" > this< / span > .stream.once(< span class = "string" > 'headers'< / span > , < span class = "keyword" > this< / span > ._onRequestHeaders.bind(< span class = "keyword" > this< / span > ));
}
OutgoingResponse.prototype = Object.create(OutgoingMessage.prototype, { constructor: { value: OutgoingResponse } });
OutgoingResponse.prototype.writeHead = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > writeHead< / span > < span class = "params" > (statusCode, reasonPhrase, headers)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > typeof< / span > reasonPhrase === < span class = "string" > 'string'< / span > ) {
< span class = "keyword" > this< / span > ._log.warn(< span class = "string" > 'Reason phrase argument was present but ignored by the writeHead method'< / span > );
} < span class = "keyword" > else< / span > {
headers = reasonPhrase;
}
< span class = "keyword" > for< / span > (< span class = "keyword" > var< / span > name < span class = "keyword" > in< / span > headers) {
< span class = "keyword" > this< / span > .setHeader(name, headers[name]);
}
headers = < span class = "keyword" > this< / span > ._headers;
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .sendDate & & !(< span class = "string" > 'date'< / span > < span class = "keyword" > in< / span > < span class = "keyword" > this< / span > ._headers)) {
headers.date = (< span class = "keyword" > new< / span > Date()).toUTCString();
}
< span class = "keyword" > this< / span > ._log.info({ status: statusCode, headers: < span class = "keyword" > this< / span > ._headers }, < span class = "string" > 'Sending server response'< / span > );
headers[< span class = "string" > ':status'< / span > ] = < span class = "keyword" > this< / span > .statusCode = statusCode;
< span class = "keyword" > this< / span > .stream.headers(headers);
< span class = "keyword" > this< / span > .headersSent = < span class = "literal" > true< / span > ;
};
OutgoingResponse.prototype._implicitHeaders = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _implicitHeaders< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > if< / span > (!< span class = "keyword" > this< / span > .headersSent) {
< span class = "keyword" > this< / span > .writeHead(< span class = "keyword" > this< / span > .statusCode);
}
};
OutgoingResponse.prototype.write = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > write< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > this< / span > ._implicitHeaders();
< span class = "keyword" > return< / span > OutgoingMessage.prototype.write.apply(< span class = "keyword" > this< / span > , arguments);
};
OutgoingResponse.prototype.end = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > end< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > this< / span > ._implicitHeaders();
< span class = "keyword" > return< / span > OutgoingMessage.prototype.end.apply(< span class = "keyword" > this< / span > , arguments);
};
OutgoingResponse.prototype._onRequestHeaders = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onRequestHeaders< / span > < span class = "params" > (headers)< / span > {< / span >
< span class = "keyword" > this< / span > ._requestHeaders = headers;
};
OutgoingResponse.prototype.push = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > push< / span > < span class = "params" > (options)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > typeof< / span > options === < span class = "string" > 'string'< / span > ) {
options = url.parse(options);
}
< span class = "keyword" > if< / span > (!options.path) {
< span class = "keyword" > throw< / span > < span class = "keyword" > new< / span > Error(< span class = "string" > '`path` option is mandatory.'< / span > );
}
< span class = "keyword" > var< / span > promise = util._extend({
< span class = "string" > ':method'< / span > : (options.method || < span class = "string" > 'GET'< / span > ).toUpperCase(),
< span class = "string" > ':scheme'< / span > : (options.protocol & & options.protocol.slice(< span class = "number" > 0< / span > , -< span class = "number" > 1< / span > )) || < span class = "keyword" > this< / span > ._requestHeaders[< span class = "string" > ':scheme'< / span > ],
< span class = "string" > ':authority'< / span > : options.hostname || options.host || < span class = "keyword" > this< / span > ._requestHeaders[< span class = "string" > ':authority'< / span > ],
< span class = "string" > ':path'< / span > : options.path
}, options.headers);
< span class = "keyword" > this< / span > ._log.info({ method: promise[< span class = "string" > ':method'< / span > ], scheme: promise[< span class = "string" > ':scheme'< / span > ],
authority: promise[< span class = "string" > ':authority'< / span > ], path: promise[< span class = "string" > ':path'< / span > ],
headers: options.headers }, < span class = "string" > 'Promising push stream'< / span > );
< span class = "keyword" > var< / span > pushStream = < span class = "keyword" > this< / span > .stream.promise(promise);
< span class = "keyword" > return< / span > < span class = "keyword" > new< / span > OutgoingResponse(pushStream);
};< / pre > < / div > < / div >
< / li >
< li id = "section-45" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-45" > ¶ < / a >
< / div >
< p > Overriding < code > EventEmitter< / code > ' s < code > on(event, listener)< / code > method to forward certain subscriptions to
< code > request< / code > . See < code > Server.prototype.on< / code > for explanation.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > OutgoingResponse.prototype.on = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > on< / span > < span class = "params" > (event, listener)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request & & (event === < span class = "string" > 'timeout'< / span > )) {
< span class = "keyword" > this< / span > .request.on(event, listener & & listener.bind(< span class = "keyword" > this< / span > ));
} < span class = "keyword" > else< / span > {
OutgoingMessage.prototype.on.call(< span class = "keyword" > this< / span > , event, listener);
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-46" >
< div class = "annotation" >
< div class = "pilwrap for-h1" >
< a class = "pilcrow" href = "#section-46" > ¶ < / a >
< / div >
< h1 > Client side< / h1 >
< / div >
< / li >
< li id = "section-47" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-47" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > exports.ClientRequest = OutgoingRequest; < span class = "comment" > // for API compatibility< / span >
exports.OutgoingRequest = OutgoingRequest;
exports.IncomingResponse = IncomingResponse;
exports.Agent = Agent;
exports.globalAgent = < span class = "literal" > undefined< / span > ;
exports.request = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > request< / span > < span class = "params" > (options, callback)< / span > {< / span >
< span class = "keyword" > return< / span > (options.agent || exports.globalAgent).request(options, callback);
};
exports.get = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > get< / span > < span class = "params" > (options, callback)< / span > {< / span >
< span class = "keyword" > return< / span > (options.agent || exports.globalAgent).get(options, callback);
};< / pre > < / div > < / div >
< / li >
< li id = "section-48" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-48" > ¶ < / a >
< / div >
< h2 > Agent class< / h2 >
< / div >
< / li >
< li id = "section-49" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-49" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > Agent< / span > < span class = "params" > (options)< / span > {< / span >
EventEmitter.call(< span class = "keyword" > this< / span > );
options = util._extend({}, options);
< span class = "keyword" > this< / span > ._settings = options.settings;
< span class = "keyword" > this< / span > ._log = (options.log || defaultLogger).child({ component: < span class = "string" > 'http'< / span > });
< span class = "keyword" > this< / span > .endpoints = {};< / pre > < / div > < / div >
< / li >
< li id = "section-50" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-50" > ¶ < / a >
< / div >
< ul >
< li > Using an own HTTPS agent, because the global agent does not look at < code > NPN/ALPNProtocols< / code > when
generating the key identifying the connection, so we may get useless non-negotiated TLS
channels even if we ask for a negotiated one. This agent will contain only negotiated
channels.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > var< / span > agentOptions = {};
agentOptions.ALPNProtocols = supportedProtocols;
agentOptions.NPNProtocols = supportedProtocols;
< span class = "keyword" > this< / span > ._httpsAgent = < span class = "keyword" > new< / span > https.Agent(agentOptions);
< span class = "keyword" > this< / span > .sockets = < span class = "keyword" > this< / span > ._httpsAgent.sockets;
< span class = "keyword" > this< / span > .requests = < span class = "keyword" > this< / span > ._httpsAgent.requests;
}
Agent.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Agent } });
Agent.prototype.request = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > request< / span > < span class = "params" > (options, callback)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > typeof< / span > options === < span class = "string" > 'string'< / span > ) {
options = url.parse(options);
} < span class = "keyword" > else< / span > {
options = util._extend({}, options);
}
options.method = (options.method || < span class = "string" > 'GET'< / span > ).toUpperCase();
options.protocol = options.protocol || < span class = "string" > 'https:'< / span > ;
options.host = options.hostname || options.host || < span class = "string" > 'localhost'< / span > ;
options.port = options.port || < span class = "number" > 443< / span > ;
options.path = options.path || < span class = "string" > '/'< / span > ;
< span class = "keyword" > if< / span > (!options.plain & & options.protocol === < span class = "string" > 'http:'< / span > ) {
< span class = "keyword" > this< / span > ._log.error(< span class = "string" > 'Trying to negotiate client request with Upgrade from HTTP/1.1'< / span > );
< span class = "keyword" > throw< / span > < span class = "keyword" > new< / span > Error(< span class = "string" > 'HTTP1.1 -> HTTP2 upgrade is not yet supported.'< / span > );
}
< span class = "keyword" > var< / span > request = < span class = "keyword" > new< / span > OutgoingRequest(< span class = "keyword" > this< / span > ._log);
< span class = "keyword" > if< / span > (callback) {
request.on(< span class = "string" > 'response'< / span > , callback);
}
< span class = "keyword" > var< / span > key = [
!!options.plain,
options.host,
options.port
].join(< span class = "string" > ':'< / span > );< / pre > < / div > < / div >
< / li >
< li id = "section-51" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-51" > ¶ < / a >
< / div >
< ul >
< li > There' s an existing HTTP/2 connection to this host< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > if< / span > (key < span class = "keyword" > in< / span > < span class = "keyword" > this< / span > .endpoints) {
< span class = "keyword" > var< / span > endpoint = < span class = "keyword" > this< / span > .endpoints[key];
request._start(endpoint.createStream(), options);
}< / pre > < / div > < / div >
< / li >
< li id = "section-52" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-52" > ¶ < / a >
< / div >
< ul >
< li > HTTP/2 over plain TCP< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > else< / span > < span class = "keyword" > if< / span > (options.plain) {
endpoint = < span class = "keyword" > new< / span > Endpoint(< span class = "keyword" > this< / span > ._log, < span class = "string" > 'CLIENT'< / span > , < span class = "keyword" > this< / span > ._settings);
endpoint.socket = net.connect({
host: options.host,
port: options.port,
localAddress: options.localAddress
});
endpoint.pipe(endpoint.socket).pipe(endpoint);
request._start(endpoint.createStream(), options);
}< / pre > < / div > < / div >
< / li >
< li id = "section-53" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-53" > ¶ < / a >
< / div >
< ul >
< li > HTTP/2 over TLS negotiated using NPN or ALPN< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > else< / span > {
< span class = "keyword" > var< / span > started = < span class = "literal" > false< / span > ;
options.ALPNProtocols = supportedProtocols;
options.NPNProtocols = supportedProtocols;
options.servername = options.host; < span class = "comment" > // Server Name Indication< / span >
options.agent = < span class = "keyword" > this< / span > ._httpsAgent;
< span class = "keyword" > var< / span > httpsRequest = https.request(options);
httpsRequest.on(< span class = "string" > 'socket'< / span > , < span class = "keyword" > function< / span > (socket) {
< span class = "keyword" > var< / span > negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
< span class = "keyword" > if< / span > (negotiatedProtocol !== < span class = "literal" > undefined< / span > ) {
negotiated();
} < span class = "keyword" > else< / span > {
socket.on(< span class = "string" > 'secureConnect'< / span > , negotiated);
}
});
< span class = "keyword" > var< / span > self = < span class = "keyword" > this< / span > ;
< span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > negotiated< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > var< / span > endpoint;
< span class = "keyword" > var< / span > negotiatedProtocol = httpsRequest.socket.alpnProtocol || httpsRequest.socket.npnProtocol;
< span class = "keyword" > if< / span > (negotiatedProtocol === implementedVersion) {
httpsRequest.socket.emit(< span class = "string" > 'agentRemove'< / span > );
unbundleSocket(httpsRequest.socket);
endpoint = < span class = "keyword" > new< / span > Endpoint(self._log, < span class = "string" > 'CLIENT'< / span > , self._settings);
endpoint.socket = httpsRequest.socket;
endpoint.pipe(endpoint.socket).pipe(endpoint);
}
< span class = "keyword" > if< / span > (started) {
< span class = "keyword" > if< / span > (endpoint) {
endpoint.close();
} < span class = "keyword" > else< / span > {
httpsRequest.abort();
}
} < span class = "keyword" > else< / span > {
< span class = "keyword" > if< / span > (endpoint) {
self._log.info({ e: endpoint, server: options.host + < span class = "string" > ':'< / span > + options.port },
< span class = "string" > 'New outgoing HTTP/2 connection'< / span > );
self.endpoints[key] = endpoint;
self.emit(key, endpoint);
} < span class = "keyword" > else< / span > {
self.emit(key, < span class = "literal" > undefined< / span > );
}
}
}
< span class = "keyword" > this< / span > .once(key, < span class = "keyword" > function< / span > (endpoint) {
started = < span class = "literal" > true< / span > ;
< span class = "keyword" > if< / span > (endpoint) {
request._start(endpoint.createStream(), options);
} < span class = "keyword" > else< / span > {
request._fallback(httpsRequest);
}
});
}
< span class = "keyword" > return< / span > request;
};
Agent.prototype.get = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > get< / span > < span class = "params" > (options, callback)< / span > {< / span >
< span class = "keyword" > var< / span > request = < span class = "keyword" > this< / span > .request(options, callback);
request.end();
< span class = "keyword" > return< / span > request;
};
< span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > unbundleSocket< / span > < span class = "params" > (socket)< / span > {< / span >
socket.removeAllListeners(< span class = "string" > 'data'< / span > );
socket.removeAllListeners(< span class = "string" > 'end'< / span > );
socket.removeAllListeners(< span class = "string" > 'readable'< / span > );
socket.removeAllListeners(< span class = "string" > 'close'< / span > );
socket.removeAllListeners(< span class = "string" > 'error'< / span > );
socket.unpipe();
< span class = "keyword" > delete< / span > socket.ondata;
< span class = "keyword" > delete< / span > socket.onend;
}
Object.defineProperty(Agent.prototype, < span class = "string" > 'maxSockets'< / span > , {
get: < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > getMaxSockets< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > return< / span > < span class = "keyword" > this< / span > ._httpsAgent.maxSockets;
},
set: < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setMaxSockets< / span > < span class = "params" > (value)< / span > {< / span >
< span class = "keyword" > this< / span > ._httpsAgent.maxSockets = value;
}
});
exports.globalAgent = < span class = "keyword" > new< / span > Agent();< / pre > < / div > < / div >
< / li >
< li id = "section-54" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-54" > ¶ < / a >
< / div >
< h2 > OutgoingRequest class< / h2 >
< / div >
< / li >
< li id = "section-55" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-55" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > OutgoingRequest< / span > < span class = "params" > ()< / span > {< / span >
OutgoingMessage.call(< span class = "keyword" > this< / span > );
< span class = "keyword" > this< / span > ._log = < span class = "literal" > undefined< / span > ;
< span class = "keyword" > this< / span > .stream = < span class = "literal" > undefined< / span > ;
}
OutgoingRequest.prototype = Object.create(OutgoingMessage.prototype, { constructor: { value: OutgoingRequest } });
OutgoingRequest.prototype._start = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _start< / span > < span class = "params" > (stream, options)< / span > {< / span >
< span class = "keyword" > this< / span > .stream = stream;
< span class = "keyword" > this< / span > ._log = stream._log.child({ component: < span class = "string" > 'http'< / span > });
< span class = "keyword" > for< / span > (< span class = "keyword" > var< / span > key < span class = "keyword" > in< / span > options.headers) {
< span class = "keyword" > this< / span > .setHeader(key, options.headers[key]);
}
< span class = "keyword" > var< / span > headers = < span class = "keyword" > this< / span > ._headers;
< span class = "keyword" > delete< / span > headers.host;
< span class = "keyword" > if< / span > (options.auth) {
headers.authorization = < span class = "string" > 'Basic '< / span > + < span class = "keyword" > new< / span > Buffer(options.auth).toString(< span class = "string" > 'base64'< / span > );
}
headers[< span class = "string" > ':scheme'< / span > ] = options.protocol.slice(< span class = "number" > 0< / span > , -< span class = "number" > 1< / span > );
headers[< span class = "string" > ':method'< / span > ] = options.method;
headers[< span class = "string" > ':authority'< / span > ] = options.host;
headers[< span class = "string" > ':path'< / span > ] = options.path;
< span class = "keyword" > this< / span > ._log.info({ scheme: headers[< span class = "string" > ':scheme'< / span > ], method: headers[< span class = "string" > ':method'< / span > ],
authority: headers[< span class = "string" > ':authority'< / span > ], path: headers[< span class = "string" > ':path'< / span > ],
headers: (options.headers || {}) }, < span class = "string" > 'Sending request'< / span > );
< span class = "keyword" > this< / span > .stream.headers(headers);
< span class = "keyword" > this< / span > .headersSent = < span class = "literal" > true< / span > ;
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .stream);
< span class = "keyword" > var< / span > response = < span class = "keyword" > new< / span > IncomingResponse(< span class = "keyword" > this< / span > .stream);
response.once(< span class = "string" > 'ready'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'response'< / span > , response));
< span class = "keyword" > this< / span > .stream.on(< span class = "string" > 'promise'< / span > , < span class = "keyword" > this< / span > ._onPromise.bind(< span class = "keyword" > this< / span > ));
};
OutgoingRequest.prototype._fallback = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _fallback< / span > < span class = "params" > (request)< / span > {< / span >
request.on(< span class = "string" > 'response'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'response'< / span > ));
< span class = "keyword" > this< / span > .stream = < span class = "keyword" > this< / span > .request = request;
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .socket);
};
OutgoingRequest.prototype.setPriority = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setPriority< / span > < span class = "params" > (priority)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > this< / span > .stream.priority(priority);
} < span class = "keyword" > else< / span > {
< span class = "keyword" > this< / span > .once(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .setPriority.bind(< span class = "keyword" > this< / span > , priority));
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-56" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-56" > ¶ < / a >
< / div >
< p > Overriding < code > EventEmitter< / code > ' s < code > on(event, listener)< / code > method to forward certain subscriptions to
< code > request< / code > . See < code > Server.prototype.on< / code > for explanation.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > OutgoingRequest.prototype.on = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > on< / span > < span class = "params" > (event, listener)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request & & (event === < span class = "string" > 'upgrade'< / span > )) {
< span class = "keyword" > this< / span > .request.on(event, listener & & listener.bind(< span class = "keyword" > this< / span > ));
} < span class = "keyword" > else< / span > {
OutgoingMessage.prototype.on.call(< span class = "keyword" > this< / span > , event, listener);
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-57" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-57" > ¶ < / a >
< / div >
< p > Methods only in fallback mode< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > OutgoingRequest.prototype.setNoDelay = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setNoDelay< / span > < span class = "params" > (noDelay)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request) {
< span class = "keyword" > this< / span > .request.setNoDelay(noDelay);
} < span class = "keyword" > else< / span > < span class = "keyword" > if< / span > (!< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > this< / span > .on(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .setNoDelay.bind(< span class = "keyword" > this< / span > , noDelay));
}
};
OutgoingRequest.prototype.setSocketKeepAlive = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setSocketKeepAlive< / span > < span class = "params" > (enable, initialDelay)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request) {
< span class = "keyword" > this< / span > .request.setSocketKeepAlive(enable, initialDelay);
} < span class = "keyword" > else< / span > < span class = "keyword" > if< / span > (!< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > this< / span > .on(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .setSocketKeepAlive.bind(< span class = "keyword" > this< / span > , enable, initialDelay));
}
};
OutgoingRequest.prototype.setTimeout = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setTimeout< / span > < span class = "params" > (timeout, callback)< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request) {
< span class = "keyword" > this< / span > .request.setTimeout(timeout, callback);
} < span class = "keyword" > else< / span > < span class = "keyword" > if< / span > (!< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > this< / span > .on(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .setTimeout.bind(< span class = "keyword" > this< / span > , timeout, callback));
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-58" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-58" > ¶ < / a >
< / div >
< p > Aborting the request< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > OutgoingRequest.prototype.abort = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > abort< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .request) {
< span class = "keyword" > this< / span > .request.abort();
} < span class = "keyword" > else< / span > < span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .stream) {
< span class = "keyword" > this< / span > .stream.reset(< span class = "string" > 'CANCEL'< / span > );
} < span class = "keyword" > else< / span > {
< span class = "keyword" > this< / span > .on(< span class = "string" > 'socket'< / span > , < span class = "keyword" > this< / span > .abort.bind(< span class = "keyword" > this< / span > ));
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-59" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-59" > ¶ < / a >
< / div >
< p > Receiving push promises< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > OutgoingRequest.prototype._onPromise = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onPromise< / span > < span class = "params" > (stream, headers)< / span > {< / span >
< span class = "keyword" > this< / span > ._log.info({ push_stream: stream.id }, < span class = "string" > 'Receiving push promise'< / span > );
< span class = "keyword" > var< / span > promise = < span class = "keyword" > new< / span > IncomingPromise(stream, headers);
< span class = "keyword" > if< / span > (< span class = "keyword" > this< / span > .listeners(< span class = "string" > 'push'< / span > ).length > < span class = "number" > 0< / span > ) {
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'push'< / span > , promise);
} < span class = "keyword" > else< / span > {
promise.cancel();
}
};< / pre > < / div > < / div >
< / li >
< li id = "section-60" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-60" > ¶ < / a >
< / div >
< h2 > IncomingResponse class< / h2 >
< / div >
< / li >
< li id = "section-61" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-61" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > IncomingResponse< / span > < span class = "params" > (stream)< / span > {< / span >
IncomingMessage.call(< span class = "keyword" > this< / span > , stream);
}
IncomingResponse.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingResponse } });< / pre > < / div > < / div >
< / li >
< li id = "section-62" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-62" > ¶ < / a >
< / div >
2014-01-13 17:16:28 -08:00
< p > < a href = "http://tools.ietf.org/html/draft-ietf-httpbis-http2-09#section-8.1.3.2" > Response Header Fields< / a >
2013-10-20 07:03:07 -07:00
* < code > headers< / code > argument: HTTP/2.0 request and response header fields carry information as a series
of key-value pairs. This includes the target URI for the request, the status code for the
response, as well as HTTP header fields.< / p >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > IncomingResponse.prototype._onHeaders = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > _onHeaders< / span > < span class = "params" > (headers)< / span > {< / span > < / pre > < / div > < / div >
< / li >
< li id = "section-63" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-63" > ¶ < / a >
< / div >
< ul >
< li > A single " :status" header field is defined that carries the HTTP status code field. This
header field MUST be included in all responses.< / li >
< li > A client MUST treat the absence of the " :status" header field, the presence of multiple
values, or an invalid value as a stream error of type PROTOCOL_ERROR.
Note: currently, we do not enforce it strictly: we accept any format, and parse it as int< / li >
< li > HTTP/2.0 does not define a way to carry the reason phrase that is included in an HTTP/1.1
status line.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > .statusCode = parseInt(< span class = "keyword" > this< / span > ._checkSpecialHeader(< span class = "string" > ':status'< / span > , headers[< span class = "string" > ':status'< / span > ]));< / pre > < / div > < / div >
< / li >
< li id = "section-64" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-64" > ¶ < / a >
< / div >
< ul >
< li > Handling regular headers.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > IncomingMessage.prototype._onHeaders.call(< span class = "keyword" > this< / span > , headers);< / pre > < / div > < / div >
< / li >
< li id = "section-65" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-65" > ¶ < / a >
< / div >
< ul >
< li > Signaling that the headers arrived.< / li >
< / ul >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "keyword" > this< / span > ._log.info({ status: < span class = "keyword" > this< / span > .statusCode, headers: < span class = "keyword" > this< / span > .headers}, < span class = "string" > 'Incoming response'< / span > );
< span class = "keyword" > this< / span > .emit(< span class = "string" > 'ready'< / span > );
};< / pre > < / div > < / div >
< / li >
< li id = "section-66" >
< div class = "annotation" >
< div class = "pilwrap for-h2" >
< a class = "pilcrow" href = "#section-66" > ¶ < / a >
< / div >
< h2 > IncomingPromise class< / h2 >
< / div >
< / li >
< li id = "section-67" >
< div class = "annotation" >
< div class = "pilwrap " >
< a class = "pilcrow" href = "#section-67" > ¶ < / a >
< / div >
< / div >
< div class = "content" > < div class = 'highlight' > < pre > < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > IncomingPromise< / span > < span class = "params" > (responseStream, promiseHeaders)< / span > {< / span >
< span class = "keyword" > var< / span > stream = < span class = "keyword" > new< / span > Readable();
stream._read = noop;
stream.push(< span class = "literal" > null< / span > );
stream._log = responseStream._log;
IncomingRequest.call(< span class = "keyword" > this< / span > , stream);
< span class = "keyword" > this< / span > ._onHeaders(promiseHeaders);
< span class = "keyword" > this< / span > ._responseStream = responseStream;
< span class = "keyword" > var< / span > response = < span class = "keyword" > new< / span > IncomingResponse(< span class = "keyword" > this< / span > ._responseStream);
response.once(< span class = "string" > 'ready'< / span > , < span class = "keyword" > this< / span > .emit.bind(< span class = "keyword" > this< / span > , < span class = "string" > 'response'< / span > , response));
< span class = "keyword" > this< / span > .stream.on(< span class = "string" > 'promise'< / span > , < span class = "keyword" > this< / span > ._onPromise.bind(< span class = "keyword" > this< / span > ));
}
IncomingPromise.prototype = Object.create(IncomingRequest.prototype, { constructor: { value: IncomingPromise } });
IncomingPromise.prototype.cancel = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > cancel< / span > < span class = "params" > ()< / span > {< / span >
< span class = "keyword" > this< / span > ._responseStream.reset(< span class = "string" > 'CANCEL'< / span > );
};
IncomingPromise.prototype.setPriority = < span class = "function" > < span class = "keyword" > function< / span > < span class = "title" > setPriority< / span > < span class = "params" > (priority)< / span > {< / span >
< span class = "keyword" > this< / span > ._responseStream.priority(priority);
};
IncomingPromise.prototype._onPromise = OutgoingRequest.prototype._onPromise;< / pre > < / div > < / div >
< / li >
< / ul >
< / div >
< / body >
< / html >