Skip to content

Commit 1bc4468

Browse files
indutnyrvagg
authored andcommitted
http_parser: consume StreamBase instance
Consume StreamBase instance and operate on incoming data directly without allocating Buffer instances. Improves performance. PR-URL: #2355 Reviewed-By: Trevor Norris <trev.norris@gmail.com>
1 parent b36debd commit 1bc4468

File tree

5 files changed

+266
-37
lines changed

5 files changed

+266
-37
lines changed

lib/_http_server.js

+52-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ const STATUS_CODES = exports.STATUS_CODES = {
7979
511 : 'Network Authentication Required' // RFC 6585
8080
};
8181

82+
const kOnExecute = HTTPParser.kOnExecute | 0;
83+
8284

8385
function ServerResponse(req) {
8486
OutgoingMessage.call(this);
@@ -317,6 +319,21 @@ function connectionListener(socket) {
317319
socket.on('end', socketOnEnd);
318320
socket.on('data', socketOnData);
319321

322+
// We are consuming socket, so it won't get any actual data
323+
socket.on('resume', onSocketResume);
324+
socket.on('pause', onSocketPause);
325+
326+
socket.on('drain', socketOnDrain);
327+
328+
// Override on to unconsume on `data`, `readable` listeners
329+
socket.on = socketOnWrap;
330+
331+
var external = socket._handle._externalStream;
332+
if (external)
333+
parser.consume(external);
334+
external = null;
335+
parser[kOnExecute] = onParserExecute;
336+
320337
// TODO(isaacs): Move all these functions out of here
321338
function socketOnError(e) {
322339
self.emit('clientError', e, this);
@@ -326,6 +343,16 @@ function connectionListener(socket) {
326343
assert(!socket._paused);
327344
debug('SERVER socketOnData %d', d.length);
328345
var ret = parser.execute(d);
346+
347+
onParserExecuteCommon(ret, d);
348+
}
349+
350+
function onParserExecute(ret, d) {
351+
debug('SERVER socketOnParserExecute %d', ret);
352+
onParserExecuteCommon(ret, undefined);
353+
}
354+
355+
function onParserExecuteCommon(ret, d) {
329356
if (ret instanceof Error) {
330357
debug('parse error');
331358
socket.destroy(ret);
@@ -335,9 +362,13 @@ function connectionListener(socket) {
335362
var req = parser.incoming;
336363
debug('SERVER upgrade or connect', req.method);
337364

365+
if (!d)
366+
d = parser.getCurrentBuffer();
367+
338368
socket.removeListener('data', socketOnData);
339369
socket.removeListener('end', socketOnEnd);
340370
socket.removeListener('close', serverSocketCloseListener);
371+
parser.unconsume(socket._handle._externalStream);
341372
parser.finish();
342373
freeParser(parser, req, null);
343374
parser = null;
@@ -400,7 +431,6 @@ function connectionListener(socket) {
400431
socket.resume();
401432
}
402433
}
403-
socket.on('drain', socketOnDrain);
404434

405435
function parserOnIncoming(req, shouldKeepAlive) {
406436
incoming.push(req);
@@ -480,3 +510,24 @@ function connectionListener(socket) {
480510
}
481511
}
482512
exports._connectionListener = connectionListener;
513+
514+
function onSocketResume() {
515+
this._handle.readStart();
516+
}
517+
518+
function onSocketPause() {
519+
this._handle.readStop();
520+
}
521+
522+
function socketOnWrap(ev, fn) {
523+
var res = net.Socket.prototype.on.call(this, ev, fn);
524+
if (!this.parser) {
525+
this.on = net.Socket.prototype.on;
526+
return res;
527+
}
528+
529+
if (ev === 'data' || ev === 'readable')
530+
this.parser.unconsume(this._handle._externalStream);
531+
532+
return res;
533+
}

src/env-inl.h

+11
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ inline Environment::Environment(v8::Local<v8::Context> context,
178178
printed_error_(false),
179179
trace_sync_io_(false),
180180
debugger_agent_(this),
181+
http_parser_buffer_(nullptr),
181182
context_(context->GetIsolate(), context) {
182183
// We'll be creating new objects so make sure we've entered the context.
183184
v8::HandleScope handle_scope(isolate());
@@ -200,6 +201,7 @@ inline Environment::~Environment() {
200201
isolate_data()->Put();
201202

202203
delete[] heap_statistics_buffer_;
204+
delete[] http_parser_buffer_;
203205
}
204206

205207
inline void Environment::CleanupHandles() {
@@ -338,6 +340,15 @@ inline void Environment::set_heap_statistics_buffer(uint32_t* pointer) {
338340
heap_statistics_buffer_ = pointer;
339341
}
340342

343+
inline char* Environment::http_parser_buffer() const {
344+
return http_parser_buffer_;
345+
}
346+
347+
inline void Environment::set_http_parser_buffer(char* buffer) {
348+
CHECK_EQ(http_parser_buffer_, nullptr); // Should be set only once.
349+
http_parser_buffer_ = buffer;
350+
}
351+
341352
inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
342353
return ContainerOf(&Environment::cares_timer_handle_, handle);
343354
}

src/env.h

+5
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ class Environment {
429429
inline uint32_t* heap_statistics_buffer() const;
430430
inline void set_heap_statistics_buffer(uint32_t* pointer);
431431

432+
inline char* http_parser_buffer() const;
433+
inline void set_http_parser_buffer(char* buffer);
434+
432435
inline void ThrowError(const char* errmsg);
433436
inline void ThrowTypeError(const char* errmsg);
434437
inline void ThrowRangeError(const char* errmsg);
@@ -526,6 +529,8 @@ class Environment {
526529

527530
uint32_t* heap_statistics_buffer_ = nullptr;
528531

532+
char* http_parser_buffer_;
533+
529534
#define V(PropertyName, TypeName) \
530535
v8::Persistent<TypeName> PropertyName ## _;
531536
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)

0 commit comments

Comments
 (0)