1802Salexander.borisov@nginx.com 2802Salexander.borisov@nginx.com/* 3802Salexander.borisov@nginx.com * Copyright (C) NGINX, Inc. 4802Salexander.borisov@nginx.com */ 5802Salexander.borisov@nginx.com 6802Salexander.borisov@nginx.com'use strict'; 7802Salexander.borisov@nginx.com 8802Salexander.borisov@nginx.comconst EventEmitter = require('events'); 9802Salexander.borisov@nginx.comconst http = require('http'); 10802Salexander.borisov@nginx.comconst util = require('util'); 111132Smax.romanov@nginx.comconst unit_lib = require('./build/Release/unit-http'); 121132Smax.romanov@nginx.comconst Socket = require('./socket'); 131132Smax.romanov@nginx.comconst WebSocketFrame = require('./websocket_frame'); 141766Smax.romanov@nginx.comconst Readable = require('stream').Readable; 15802Salexander.borisov@nginx.com 16802Salexander.borisov@nginx.com 17802Salexander.borisov@nginx.comfunction ServerResponse(req) { 18802Salexander.borisov@nginx.com EventEmitter.call(this); 19802Salexander.borisov@nginx.com 20802Salexander.borisov@nginx.com this.headers = {}; 211132Smax.romanov@nginx.com 221132Smax.romanov@nginx.com this.server = req.server; 231132Smax.romanov@nginx.com this._request = req; 241132Smax.romanov@nginx.com req._response = this; 251132Smax.romanov@nginx.com this.socket = req.socket; 261132Smax.romanov@nginx.com this.connection = req.connection; 271766Smax.romanov@nginx.com this.writable = true; 28802Salexander.borisov@nginx.com} 29802Salexander.borisov@nginx.comutil.inherits(ServerResponse, EventEmitter); 30802Salexander.borisov@nginx.com 31802Salexander.borisov@nginx.comServerResponse.prototype.statusCode = 200; 32802Salexander.borisov@nginx.comServerResponse.prototype.statusMessage = undefined; 33802Salexander.borisov@nginx.comServerResponse.prototype.headers_len = 0; 34802Salexander.borisov@nginx.comServerResponse.prototype.headers_count = 0; 35802Salexander.borisov@nginx.comServerResponse.prototype.headersSent = false; 362560Szelenkov@nginx.comServerResponse.prototype.destroyed = false; 37802Salexander.borisov@nginx.comServerResponse.prototype.finished = false; 38802Salexander.borisov@nginx.com 392560Szelenkov@nginx.comServerResponse.prototype.destroy = function destroy(error) { 402560Szelenkov@nginx.com if (!this.destroyed) { 412560Szelenkov@nginx.com this.destroyed = true; 422560Szelenkov@nginx.com } 432560Szelenkov@nginx.com 442560Szelenkov@nginx.com return this; 452560Szelenkov@nginx.com}; 462560Szelenkov@nginx.com 47802Salexander.borisov@nginx.comServerResponse.prototype._finish = function _finish() { 48802Salexander.borisov@nginx.com this.headers = {}; 49802Salexander.borisov@nginx.com this.headers_len = 0; 50802Salexander.borisov@nginx.com this.headers_count = 0; 51802Salexander.borisov@nginx.com this.finished = true; 52802Salexander.borisov@nginx.com}; 53802Salexander.borisov@nginx.com 54802Salexander.borisov@nginx.comServerResponse.prototype.assignSocket = function assignSocket(socket) { 55802Salexander.borisov@nginx.com}; 56802Salexander.borisov@nginx.com 57802Salexander.borisov@nginx.comServerResponse.prototype.detachSocket = function detachSocket(socket) { 58802Salexander.borisov@nginx.com}; 59802Salexander.borisov@nginx.com 60802Salexander.borisov@nginx.comServerResponse.prototype.writeContinue = function writeContinue(cb) { 61802Salexander.borisov@nginx.com}; 62802Salexander.borisov@nginx.com 63802Salexander.borisov@nginx.comServerResponse.prototype.writeProcessing = function writeProcessing(cb) { 64802Salexander.borisov@nginx.com}; 65802Salexander.borisov@nginx.com 66875Salexander.borisov@nginx.comServerResponse.prototype.setHeader = function setHeader(name, value) { 67875Salexander.borisov@nginx.com if (typeof name !== 'string') { 68875Salexander.borisov@nginx.com throw new TypeError('Name argument must be a string'); 69802Salexander.borisov@nginx.com } 70802Salexander.borisov@nginx.com 71875Salexander.borisov@nginx.com let value_len = 0 72875Salexander.borisov@nginx.com let count = 0; 73802Salexander.borisov@nginx.com 74802Salexander.borisov@nginx.com if (Array.isArray(value)) { 75875Salexander.borisov@nginx.com count = value.length; 76802Salexander.borisov@nginx.com 77802Salexander.borisov@nginx.com value.forEach(function(val) { 78875Salexander.borisov@nginx.com value_len += Buffer.byteLength(val + "", 'latin1'); 79802Salexander.borisov@nginx.com }); 80802Salexander.borisov@nginx.com 81802Salexander.borisov@nginx.com } else { 82875Salexander.borisov@nginx.com count = 1; 83875Salexander.borisov@nginx.com value_len = Buffer.byteLength(value + "", 'latin1'); 84802Salexander.borisov@nginx.com } 85802Salexander.borisov@nginx.com 86875Salexander.borisov@nginx.com let lc_name = name.toLowerCase(); 87875Salexander.borisov@nginx.com 88875Salexander.borisov@nginx.com if (lc_name in this.headers) { 89875Salexander.borisov@nginx.com this._removeHeader(lc_name); 90875Salexander.borisov@nginx.com } 91802Salexander.borisov@nginx.com 92875Salexander.borisov@nginx.com let name_len = Buffer.byteLength(name, 'latin1'); 93875Salexander.borisov@nginx.com 94875Salexander.borisov@nginx.com this.headers[lc_name] = [name, value]; 95875Salexander.borisov@nginx.com this.headers_len += value_len + (name_len * count); 96875Salexander.borisov@nginx.com this.headers_count += count; 97802Salexander.borisov@nginx.com}; 98802Salexander.borisov@nginx.com 99802Salexander.borisov@nginx.comServerResponse.prototype.getHeader = function getHeader(name) { 100875Salexander.borisov@nginx.com const entry = this.headers[name.toLowerCase()]; 101875Salexander.borisov@nginx.com 102875Salexander.borisov@nginx.com return entry && entry[1]; 103802Salexander.borisov@nginx.com}; 104802Salexander.borisov@nginx.com 105802Salexander.borisov@nginx.comServerResponse.prototype.getHeaderNames = function getHeaderNames() { 106802Salexander.borisov@nginx.com return Object.keys(this.headers); 107802Salexander.borisov@nginx.com}; 108802Salexander.borisov@nginx.com 109802Salexander.borisov@nginx.comServerResponse.prototype.getHeaders = function getHeaders() { 110875Salexander.borisov@nginx.com const ret = Object.create(null); 111875Salexander.borisov@nginx.com 112875Salexander.borisov@nginx.com if (this.headers) { 113875Salexander.borisov@nginx.com const keys = Object.keys(this.headers); 114875Salexander.borisov@nginx.com 115875Salexander.borisov@nginx.com for (var i = 0; i < keys.length; i++) { 116875Salexander.borisov@nginx.com const key = keys[i]; 117875Salexander.borisov@nginx.com 118875Salexander.borisov@nginx.com ret[key] = this.headers[key][1]; 119875Salexander.borisov@nginx.com } 120875Salexander.borisov@nginx.com } 121875Salexander.borisov@nginx.com 122875Salexander.borisov@nginx.com return ret; 123802Salexander.borisov@nginx.com}; 124802Salexander.borisov@nginx.com 125802Salexander.borisov@nginx.comServerResponse.prototype.hasHeader = function hasHeader(name) { 126875Salexander.borisov@nginx.com return name.toLowerCase() in this.headers; 127802Salexander.borisov@nginx.com}; 128802Salexander.borisov@nginx.com 129802Salexander.borisov@nginx.comServerResponse.prototype.removeHeader = function removeHeader(name) { 130875Salexander.borisov@nginx.com if (typeof name !== 'string') { 131875Salexander.borisov@nginx.com throw new TypeError('Name argument must be a string'); 132802Salexander.borisov@nginx.com } 133802Salexander.borisov@nginx.com 134875Salexander.borisov@nginx.com let lc_name = name.toLowerCase(); 135875Salexander.borisov@nginx.com 136875Salexander.borisov@nginx.com if (lc_name in this.headers) { 137875Salexander.borisov@nginx.com this._removeHeader(lc_name); 138875Salexander.borisov@nginx.com } 139875Salexander.borisov@nginx.com}; 140802Salexander.borisov@nginx.com 1412598Szelenkov@nginx.comServerResponse.prototype.flushHeaders = function flushHeaders() { 1422598Szelenkov@nginx.com this._sendHeaders(); 1432598Szelenkov@nginx.com}; 1442598Szelenkov@nginx.com 145875Salexander.borisov@nginx.comServerResponse.prototype._removeHeader = function _removeHeader(lc_name) { 146875Salexander.borisov@nginx.com let entry = this.headers[lc_name]; 147875Salexander.borisov@nginx.com let name_len = Buffer.byteLength(entry[0] + "", 'latin1'); 148875Salexander.borisov@nginx.com let value = entry[1]; 149875Salexander.borisov@nginx.com 150875Salexander.borisov@nginx.com delete this.headers[lc_name]; 151802Salexander.borisov@nginx.com 152873Salexander.borisov@nginx.com if (Array.isArray(value)) { 153873Salexander.borisov@nginx.com this.headers_count -= value.length; 154873Salexander.borisov@nginx.com this.headers_len -= value.length * name_len; 155873Salexander.borisov@nginx.com 156873Salexander.borisov@nginx.com value.forEach(function(val) { 157802Salexander.borisov@nginx.com this.headers_len -= Buffer.byteLength(val + "", 'latin1'); 158802Salexander.borisov@nginx.com }); 159802Salexander.borisov@nginx.com 160873Salexander.borisov@nginx.com return; 161802Salexander.borisov@nginx.com } 162802Salexander.borisov@nginx.com 163873Salexander.borisov@nginx.com this.headers_count--; 164873Salexander.borisov@nginx.com this.headers_len -= name_len + Buffer.byteLength(value + "", 'latin1'); 165802Salexander.borisov@nginx.com}; 166802Salexander.borisov@nginx.com 167802Salexander.borisov@nginx.comServerResponse.prototype.sendDate = function sendDate() { 168802Salexander.borisov@nginx.com throw new Error("Not supported"); 169802Salexander.borisov@nginx.com}; 170802Salexander.borisov@nginx.com 171802Salexander.borisov@nginx.comServerResponse.prototype.setTimeout = function setTimeout(msecs, callback) { 172802Salexander.borisov@nginx.com this.timeout = msecs; 173802Salexander.borisov@nginx.com 174802Salexander.borisov@nginx.com if (callback) { 175802Salexander.borisov@nginx.com this.on('timeout', callback); 176802Salexander.borisov@nginx.com } 177802Salexander.borisov@nginx.com 178802Salexander.borisov@nginx.com return this; 179802Salexander.borisov@nginx.com}; 180802Salexander.borisov@nginx.com 181802Salexander.borisov@nginx.comServerResponse.prototype.writeHead = writeHead; 182802Salexander.borisov@nginx.comServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead; 183802Salexander.borisov@nginx.com 184802Salexander.borisov@nginx.comfunction writeHead(statusCode, reason, obj) { 185802Salexander.borisov@nginx.com var originalStatusCode = statusCode; 186802Salexander.borisov@nginx.com 187802Salexander.borisov@nginx.com statusCode |= 0; 188802Salexander.borisov@nginx.com 189802Salexander.borisov@nginx.com if (statusCode < 100 || statusCode > 999) { 190802Salexander.borisov@nginx.com throw new ERR_HTTP_INVALID_STATUS_CODE(originalStatusCode); 191802Salexander.borisov@nginx.com } 192802Salexander.borisov@nginx.com 193802Salexander.borisov@nginx.com if (typeof reason === 'string') { 194802Salexander.borisov@nginx.com this.statusMessage = reason; 195802Salexander.borisov@nginx.com 196802Salexander.borisov@nginx.com } else { 197802Salexander.borisov@nginx.com if (!this.statusMessage) { 198802Salexander.borisov@nginx.com this.statusMessage = http.STATUS_CODES[statusCode] || 'unknown'; 199802Salexander.borisov@nginx.com } 200802Salexander.borisov@nginx.com 201802Salexander.borisov@nginx.com obj = reason; 202802Salexander.borisov@nginx.com } 203802Salexander.borisov@nginx.com 204802Salexander.borisov@nginx.com this.statusCode = statusCode; 205802Salexander.borisov@nginx.com 206802Salexander.borisov@nginx.com if (obj) { 207802Salexander.borisov@nginx.com var k; 208802Salexander.borisov@nginx.com var keys = Object.keys(obj); 209802Salexander.borisov@nginx.com 210802Salexander.borisov@nginx.com for (var i = 0; i < keys.length; i++) { 211802Salexander.borisov@nginx.com k = keys[i]; 212802Salexander.borisov@nginx.com 213802Salexander.borisov@nginx.com if (k) { 214802Salexander.borisov@nginx.com this.setHeader(k, obj[k]); 215802Salexander.borisov@nginx.com } 216802Salexander.borisov@nginx.com } 217802Salexander.borisov@nginx.com } 2181114Svbart@nginx.com 2191114Svbart@nginx.com return this; 220802Salexander.borisov@nginx.com}; 221802Salexander.borisov@nginx.com 2221024Svbart@nginx.com/* 2231024Svbart@nginx.com * Some Node.js packages are known to be using this undocumented function, 2241024Svbart@nginx.com * notably "compression" middleware. 2251024Svbart@nginx.com */ 2261024Svbart@nginx.comServerResponse.prototype._implicitHeader = function _implicitHeader() { 2271024Svbart@nginx.com this.writeHead(this.statusCode); 2281024Svbart@nginx.com}; 2291024Svbart@nginx.com 2301132Smax.romanov@nginx.comServerResponse.prototype._send_headers = unit_lib.response_send_headers; 2311132Smax.romanov@nginx.com 2321132Smax.romanov@nginx.comServerResponse.prototype._sendHeaders = function _sendHeaders() { 2331132Smax.romanov@nginx.com if (!this.headersSent) { 2341132Smax.romanov@nginx.com this._send_headers(this.statusCode, this.headers, this.headers_count, 2351132Smax.romanov@nginx.com this.headers_len); 2361132Smax.romanov@nginx.com 2371132Smax.romanov@nginx.com this.headersSent = true; 2381132Smax.romanov@nginx.com } 2391132Smax.romanov@nginx.com}; 2401132Smax.romanov@nginx.com 2411132Smax.romanov@nginx.comServerResponse.prototype._write = unit_lib.response_write; 2421132Smax.romanov@nginx.com 243802Salexander.borisov@nginx.comServerResponse.prototype._writeBody = function(chunk, encoding, callback) { 244802Salexander.borisov@nginx.com var contentLength = 0; 2451322Smax.romanov@nginx.com var res, o; 246802Salexander.borisov@nginx.com 2471132Smax.romanov@nginx.com this._sendHeaders(); 248802Salexander.borisov@nginx.com 249802Salexander.borisov@nginx.com if (typeof chunk === 'function') { 250802Salexander.borisov@nginx.com callback = chunk; 251802Salexander.borisov@nginx.com chunk = null; 252802Salexander.borisov@nginx.com 253802Salexander.borisov@nginx.com } else if (typeof encoding === 'function') { 254802Salexander.borisov@nginx.com callback = encoding; 255802Salexander.borisov@nginx.com encoding = null; 256802Salexander.borisov@nginx.com } 257802Salexander.borisov@nginx.com 258802Salexander.borisov@nginx.com if (chunk) { 2592559Szelenkov@nginx.com if (typeof chunk !== 'string' && !(chunk instanceof Buffer || 2602559Szelenkov@nginx.com chunk instanceof Uint8Array)) { 2612559Szelenkov@nginx.com throw new TypeError( 2622559Szelenkov@nginx.com 'First argument must be a string, Buffer, ' + 2632559Szelenkov@nginx.com 'or Uint8Array'); 264802Salexander.borisov@nginx.com } 265802Salexander.borisov@nginx.com 266802Salexander.borisov@nginx.com if (typeof chunk === 'string') { 267802Salexander.borisov@nginx.com contentLength = Buffer.byteLength(chunk, encoding); 268802Salexander.borisov@nginx.com 2691322Smax.romanov@nginx.com if (contentLength > unit_lib.buf_min) { 2701322Smax.romanov@nginx.com chunk = Buffer.from(chunk, encoding); 2711322Smax.romanov@nginx.com 2721322Smax.romanov@nginx.com contentLength = chunk.length; 2731322Smax.romanov@nginx.com } 2741322Smax.romanov@nginx.com 275802Salexander.borisov@nginx.com } else { 276802Salexander.borisov@nginx.com contentLength = chunk.length; 277802Salexander.borisov@nginx.com } 278802Salexander.borisov@nginx.com 2791322Smax.romanov@nginx.com if (this.server._output.length > 0 || !this.socket.writable) { 2801322Smax.romanov@nginx.com o = new BufferedOutput(this, 0, chunk, encoding, callback); 2811322Smax.romanov@nginx.com this.server._output.push(o); 2821322Smax.romanov@nginx.com 2831322Smax.romanov@nginx.com return false; 2841322Smax.romanov@nginx.com } 2851322Smax.romanov@nginx.com 2861322Smax.romanov@nginx.com res = this._write(chunk, 0, contentLength); 2871322Smax.romanov@nginx.com if (res < contentLength) { 2881322Smax.romanov@nginx.com this.socket.writable = false; 2891766Smax.romanov@nginx.com this.writable = false; 2901322Smax.romanov@nginx.com 2911322Smax.romanov@nginx.com o = new BufferedOutput(this, res, chunk, encoding, callback); 2921322Smax.romanov@nginx.com this.server._output.push(o); 2931322Smax.romanov@nginx.com 2941322Smax.romanov@nginx.com return false; 2951322Smax.romanov@nginx.com } 296802Salexander.borisov@nginx.com } 297802Salexander.borisov@nginx.com 298802Salexander.borisov@nginx.com if (typeof callback === 'function') { 299874Salexander.borisov@nginx.com /* 300874Salexander.borisov@nginx.com * The callback must be called only when response.write() caller 301874Salexander.borisov@nginx.com * completes. process.nextTick() postpones the callback execution. 302874Salexander.borisov@nginx.com * 303874Salexander.borisov@nginx.com * process.nextTick() is not technically part of the event loop. 304874Salexander.borisov@nginx.com * Instead, the nextTickQueue will be processed after the current 305874Salexander.borisov@nginx.com * operation completes, regardless of the current phase of 306874Salexander.borisov@nginx.com * the event loop. All callbacks passed to process.nextTick() 307874Salexander.borisov@nginx.com * will be resolved before the event loop continues. 308874Salexander.borisov@nginx.com */ 3091322Smax.romanov@nginx.com process.nextTick(callback); 310802Salexander.borisov@nginx.com } 3111322Smax.romanov@nginx.com 3121322Smax.romanov@nginx.com return true; 313802Salexander.borisov@nginx.com}; 314802Salexander.borisov@nginx.com 315802Salexander.borisov@nginx.comServerResponse.prototype.write = function write(chunk, encoding, callback) { 316869Salexander.borisov@nginx.com if (this.finished) { 3171322Smax.romanov@nginx.com if (typeof encoding === 'function') { 3181322Smax.romanov@nginx.com callback = encoding; 3191322Smax.romanov@nginx.com encoding = null; 3201322Smax.romanov@nginx.com } 3211322Smax.romanov@nginx.com 3221322Smax.romanov@nginx.com var err = new Error("Write after end"); 3231322Smax.romanov@nginx.com process.nextTick(() => { 3241322Smax.romanov@nginx.com this.emit('error', err); 3251322Smax.romanov@nginx.com 3261322Smax.romanov@nginx.com if (typeof callback === 'function') { 3271322Smax.romanov@nginx.com callback(err); 3281322Smax.romanov@nginx.com } 3291322Smax.romanov@nginx.com }) 330869Salexander.borisov@nginx.com } 331869Salexander.borisov@nginx.com 3321322Smax.romanov@nginx.com return this._writeBody(chunk, encoding, callback); 333802Salexander.borisov@nginx.com}; 334802Salexander.borisov@nginx.com 3351132Smax.romanov@nginx.comServerResponse.prototype._end = unit_lib.response_end; 3361132Smax.romanov@nginx.com 337802Salexander.borisov@nginx.comServerResponse.prototype.end = function end(chunk, encoding, callback) { 338869Salexander.borisov@nginx.com if (!this.finished) { 3391322Smax.romanov@nginx.com if (typeof encoding === 'function') { 3401322Smax.romanov@nginx.com callback = encoding; 3411322Smax.romanov@nginx.com encoding = null; 3421322Smax.romanov@nginx.com } 343802Salexander.borisov@nginx.com 3441322Smax.romanov@nginx.com this._writeBody(chunk, encoding, () => { 3451322Smax.romanov@nginx.com this._end(); 3461322Smax.romanov@nginx.com 3471322Smax.romanov@nginx.com if (typeof callback === 'function') { 3481322Smax.romanov@nginx.com callback(); 3491322Smax.romanov@nginx.com } 3501766Smax.romanov@nginx.com 3511766Smax.romanov@nginx.com this.emit("finish"); 3521322Smax.romanov@nginx.com }); 353869Salexander.borisov@nginx.com 354869Salexander.borisov@nginx.com this.finished = true; 355869Salexander.borisov@nginx.com } 356802Salexander.borisov@nginx.com 357802Salexander.borisov@nginx.com return this; 358802Salexander.borisov@nginx.com}; 359802Salexander.borisov@nginx.com 3601132Smax.romanov@nginx.comfunction ServerRequest(server, socket) { 3611766Smax.romanov@nginx.com Readable.call(this); 362802Salexander.borisov@nginx.com 363802Salexander.borisov@nginx.com this.server = server; 3641132Smax.romanov@nginx.com this.socket = socket; 3651132Smax.romanov@nginx.com this.connection = socket; 3661766Smax.romanov@nginx.com this._pushed_eofchunk = false; 367802Salexander.borisov@nginx.com} 3681766Smax.romanov@nginx.comutil.inherits(ServerRequest, Readable); 369802Salexander.borisov@nginx.com 370802Salexander.borisov@nginx.comServerRequest.prototype.setTimeout = function setTimeout(msecs, callback) { 371802Salexander.borisov@nginx.com this.timeout = msecs; 372802Salexander.borisov@nginx.com 373802Salexander.borisov@nginx.com if (callback) { 374802Salexander.borisov@nginx.com this.on('timeout', callback); 375802Salexander.borisov@nginx.com } 376802Salexander.borisov@nginx.com 377802Salexander.borisov@nginx.com return this; 378802Salexander.borisov@nginx.com}; 379802Salexander.borisov@nginx.com 380802Salexander.borisov@nginx.comServerRequest.prototype.statusCode = function statusCode() { 381802Salexander.borisov@nginx.com /* Only valid for response obtained from http.ClientRequest. */ 382802Salexander.borisov@nginx.com}; 383802Salexander.borisov@nginx.com 384802Salexander.borisov@nginx.comServerRequest.prototype.statusMessage = function statusMessage() { 385802Salexander.borisov@nginx.com /* Only valid for response obtained from http.ClientRequest. */ 386802Salexander.borisov@nginx.com}; 387802Salexander.borisov@nginx.com 388802Salexander.borisov@nginx.comServerRequest.prototype.trailers = function trailers() { 389802Salexander.borisov@nginx.com throw new Error("Not supported"); 390802Salexander.borisov@nginx.com}; 391802Salexander.borisov@nginx.com 392802Salexander.borisov@nginx.comServerRequest.prototype.METHODS = function METHODS() { 393802Salexander.borisov@nginx.com return http.METHODS; 394802Salexander.borisov@nginx.com}; 395802Salexander.borisov@nginx.com 396802Salexander.borisov@nginx.comServerRequest.prototype.STATUS_CODES = function STATUS_CODES() { 397802Salexander.borisov@nginx.com return http.STATUS_CODES; 398802Salexander.borisov@nginx.com}; 399802Salexander.borisov@nginx.com 4001766Smax.romanov@nginx.comServerRequest.prototype._request_read = unit_lib.request_read; 401802Salexander.borisov@nginx.com 4021766Smax.romanov@nginx.comServerRequest.prototype._read = function _read(n) { 4031766Smax.romanov@nginx.com const b = this._request_read(n); 404802Salexander.borisov@nginx.com 4051766Smax.romanov@nginx.com if (b != null) { 4061766Smax.romanov@nginx.com this.push(b); 4071766Smax.romanov@nginx.com } 408870Salexander.borisov@nginx.com 4091766Smax.romanov@nginx.com if (!this._pushed_eofchunk && (b == null || b.length < n)) { 4101766Smax.romanov@nginx.com this._pushed_eofchunk = true; 4111766Smax.romanov@nginx.com this.push(null); 412870Salexander.borisov@nginx.com } 413870Salexander.borisov@nginx.com}; 414870Salexander.borisov@nginx.com 415870Salexander.borisov@nginx.com 4162642Sg.javorszky@f5.comfunction Server(options, requestListener) { 4172642Sg.javorszky@f5.com if (typeof options === 'function') { 4182642Sg.javorszky@f5.com requestListener = options; 4192642Sg.javorszky@f5.com options = {}; 4202642Sg.javorszky@f5.com } else { 421*2649Sd.callahan@f5.com console.warn("http.Server constructor was called with unsupported options, using default settings"); 4222642Sg.javorszky@f5.com } 4232642Sg.javorszky@f5.com 424802Salexander.borisov@nginx.com EventEmitter.call(this); 425802Salexander.borisov@nginx.com 426802Salexander.borisov@nginx.com this.unit = new unit_lib.Unit(); 427828Salexander.borisov@nginx.com this.unit.server = this; 428802Salexander.borisov@nginx.com 429828Salexander.borisov@nginx.com this.unit.createServer(); 430802Salexander.borisov@nginx.com 4311132Smax.romanov@nginx.com this.Socket = Socket; 4321132Smax.romanov@nginx.com this.ServerRequest = ServerRequest; 4331132Smax.romanov@nginx.com this.ServerResponse = ServerResponse; 4341132Smax.romanov@nginx.com this.WebSocketFrame = WebSocketFrame; 435802Salexander.borisov@nginx.com 436802Salexander.borisov@nginx.com if (requestListener) { 437802Salexander.borisov@nginx.com this.on('request', requestListener); 438802Salexander.borisov@nginx.com } 4391132Smax.romanov@nginx.com 4401132Smax.romanov@nginx.com this._upgradeListenerCount = 0; 4411132Smax.romanov@nginx.com this.on('newListener', function(ev) { 4421132Smax.romanov@nginx.com if (ev === 'upgrade'){ 4431132Smax.romanov@nginx.com this._upgradeListenerCount++; 4441132Smax.romanov@nginx.com } 4451132Smax.romanov@nginx.com }).on('removeListener', function(ev) { 4461132Smax.romanov@nginx.com if (ev === 'upgrade') { 4471132Smax.romanov@nginx.com this._upgradeListenerCount--; 4481132Smax.romanov@nginx.com } 4491132Smax.romanov@nginx.com }); 4501322Smax.romanov@nginx.com 4511322Smax.romanov@nginx.com this._output = []; 4521322Smax.romanov@nginx.com this._drain_resp = new Set(); 453802Salexander.borisov@nginx.com} 4541132Smax.romanov@nginx.com 455802Salexander.borisov@nginx.comutil.inherits(Server, EventEmitter); 456802Salexander.borisov@nginx.com 457802Salexander.borisov@nginx.comServer.prototype.setTimeout = function setTimeout(msecs, callback) { 458802Salexander.borisov@nginx.com this.timeout = msecs; 459802Salexander.borisov@nginx.com 460802Salexander.borisov@nginx.com if (callback) { 461802Salexander.borisov@nginx.com this.on('timeout', callback); 462802Salexander.borisov@nginx.com } 463802Salexander.borisov@nginx.com 464802Salexander.borisov@nginx.com return this; 465802Salexander.borisov@nginx.com}; 466802Salexander.borisov@nginx.com 4671447Smax.romanov@nginx.comServer.prototype.listen = function (...args) { 468802Salexander.borisov@nginx.com this.unit.listen(); 4691447Smax.romanov@nginx.com 4701865So.canty@f5.com if (typeof args[args.length - 1] === 'function') { 4711865So.canty@f5.com this.once('listening', args[args.length - 1]); 4721447Smax.romanov@nginx.com } 4731447Smax.romanov@nginx.com 4741865So.canty@f5.com /* 4751865So.canty@f5.com * Some express.js apps use the returned server object inside the listening 4761865So.canty@f5.com * callback, so we timeout the listening event to occur after this function 4771865So.canty@f5.com * returns. 4781865So.canty@f5.com */ 4791865So.canty@f5.com setImmediate(function() { 4801865So.canty@f5.com this.emit('listening') 4811865So.canty@f5.com }.bind(this)) 4821447Smax.romanov@nginx.com 4831447Smax.romanov@nginx.com return this; 484802Salexander.borisov@nginx.com}; 485802Salexander.borisov@nginx.com 4861865So.canty@f5.comServer.prototype.address = function () { 4871865So.canty@f5.com return { 4881865So.canty@f5.com family: "IPv4", 4891865So.canty@f5.com address: "127.0.0.1", 4901865So.canty@f5.com port: 80 4911865So.canty@f5.com } 4921865So.canty@f5.com} 4931865So.canty@f5.com 4941132Smax.romanov@nginx.comServer.prototype.emit_request = function (req, res) { 4951132Smax.romanov@nginx.com if (req._websocket_handshake && this._upgradeListenerCount > 0) { 4961132Smax.romanov@nginx.com this.emit('upgrade', req, req.socket); 497870Salexander.borisov@nginx.com 4981132Smax.romanov@nginx.com } else { 4991132Smax.romanov@nginx.com this.emit("request", req, res); 5001132Smax.romanov@nginx.com } 501828Salexander.borisov@nginx.com}; 502828Salexander.borisov@nginx.com 5031021Smax.romanov@nginx.comServer.prototype.emit_close = function () { 5041021Smax.romanov@nginx.com this.emit('close'); 5051021Smax.romanov@nginx.com}; 5061021Smax.romanov@nginx.com 5071322Smax.romanov@nginx.comServer.prototype.emit_drain = function () { 5081322Smax.romanov@nginx.com var res, o, l; 5091322Smax.romanov@nginx.com 5101322Smax.romanov@nginx.com if (this._output.length <= 0) { 5111322Smax.romanov@nginx.com return; 5121322Smax.romanov@nginx.com } 5131322Smax.romanov@nginx.com 5141322Smax.romanov@nginx.com while (this._output.length > 0) { 5151322Smax.romanov@nginx.com o = this._output[0]; 5161322Smax.romanov@nginx.com 5171322Smax.romanov@nginx.com if (typeof o.chunk === 'string') { 5181322Smax.romanov@nginx.com l = Buffer.byteLength(o.chunk, o.encoding); 5191322Smax.romanov@nginx.com 5201322Smax.romanov@nginx.com } else { 5211322Smax.romanov@nginx.com l = o.chunk.length; 5221322Smax.romanov@nginx.com } 5231322Smax.romanov@nginx.com 5241322Smax.romanov@nginx.com res = o.resp._write(o.chunk, o.offset, l); 5251322Smax.romanov@nginx.com 5261322Smax.romanov@nginx.com o.offset += res; 5271322Smax.romanov@nginx.com if (o.offset < l) { 5281322Smax.romanov@nginx.com return; 5291322Smax.romanov@nginx.com } 5301322Smax.romanov@nginx.com 5311322Smax.romanov@nginx.com this._drain_resp.add(o.resp); 5321322Smax.romanov@nginx.com 5331322Smax.romanov@nginx.com if (typeof o.callback === 'function') { 5341322Smax.romanov@nginx.com process.nextTick(o.callback); 5351322Smax.romanov@nginx.com } 5361322Smax.romanov@nginx.com 5371322Smax.romanov@nginx.com this._output.shift(); 5381322Smax.romanov@nginx.com } 5391322Smax.romanov@nginx.com 5401322Smax.romanov@nginx.com for (var resp of this._drain_resp) { 5411322Smax.romanov@nginx.com 5421322Smax.romanov@nginx.com if (resp.socket.writable) { 5431322Smax.romanov@nginx.com continue; 5441322Smax.romanov@nginx.com } 5451322Smax.romanov@nginx.com 5461322Smax.romanov@nginx.com resp.socket.writable = true; 5471766Smax.romanov@nginx.com resp.writable = true; 5481322Smax.romanov@nginx.com 5491322Smax.romanov@nginx.com process.nextTick(() => { 5501322Smax.romanov@nginx.com resp.emit("drain"); 5511322Smax.romanov@nginx.com }); 5521322Smax.romanov@nginx.com } 5531322Smax.romanov@nginx.com 5541322Smax.romanov@nginx.com this._drain_resp.clear(); 5551322Smax.romanov@nginx.com}; 5561322Smax.romanov@nginx.com 5571322Smax.romanov@nginx.comfunction BufferedOutput(resp, offset, chunk, encoding, callback) { 5581322Smax.romanov@nginx.com this.resp = resp; 5591322Smax.romanov@nginx.com this.offset = offset; 5601322Smax.romanov@nginx.com this.chunk = chunk; 5611322Smax.romanov@nginx.com this.encoding = encoding; 5621322Smax.romanov@nginx.com this.callback = callback; 5631322Smax.romanov@nginx.com} 5641322Smax.romanov@nginx.com 565802Salexander.borisov@nginx.comfunction connectionListener(socket) { 566802Salexander.borisov@nginx.com} 567802Salexander.borisov@nginx.com 568802Salexander.borisov@nginx.commodule.exports = { 569802Salexander.borisov@nginx.com Server, 570802Salexander.borisov@nginx.com ServerResponse, 571802Salexander.borisov@nginx.com ServerRequest, 572802Salexander.borisov@nginx.com _connectionListener: connectionListener 573802Salexander.borisov@nginx.com}; 574