Skip to content

Commit b2c0ad3

Browse files
committed
Merge commit 'f71be24' into v4.4.0-proposal-port
2 parents a8755d8 + f71be24 commit b2c0ad3

25 files changed

+419
-557
lines changed

Makefile.build

Lines changed: 0 additions & 499 deletions
This file was deleted.

benchmark/net/net-c2s-cork.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// test the speed of .pipe() with sockets
2+
3+
var common = require('../common.js');
4+
var PORT = common.PORT;
5+
6+
var bench = common.createBenchmark(main, {
7+
len: [4, 8, 16, 32, 64, 128, 512, 1024],
8+
type: ['buf'],
9+
dur: [5],
10+
});
11+
12+
var dur;
13+
var len;
14+
var type;
15+
var chunk;
16+
var encoding;
17+
18+
function main(conf) {
19+
dur = +conf.dur;
20+
len = +conf.len;
21+
type = conf.type;
22+
23+
switch (type) {
24+
case 'buf':
25+
chunk = new Buffer(len);
26+
chunk.fill('x');
27+
break;
28+
case 'utf':
29+
encoding = 'utf8';
30+
chunk = new Array(len / 2 + 1).join('ü');
31+
break;
32+
case 'asc':
33+
encoding = 'ascii';
34+
chunk = new Array(len + 1).join('x');
35+
break;
36+
default:
37+
throw new Error('invalid type: ' + type);
38+
break;
39+
}
40+
41+
server();
42+
}
43+
44+
var net = require('net');
45+
46+
function Writer() {
47+
this.received = 0;
48+
this.writable = true;
49+
}
50+
51+
Writer.prototype.write = function(chunk, encoding, cb) {
52+
this.received += chunk.length;
53+
54+
if (typeof encoding === 'function')
55+
encoding();
56+
else if (typeof cb === 'function')
57+
cb();
58+
59+
return true;
60+
};
61+
62+
// doesn't matter, never emits anything.
63+
Writer.prototype.on = function() {};
64+
Writer.prototype.once = function() {};
65+
Writer.prototype.emit = function() {};
66+
67+
function server() {
68+
var writer = new Writer();
69+
70+
// the actual benchmark.
71+
var server = net.createServer(function(socket) {
72+
socket.pipe(writer);
73+
});
74+
75+
server.listen(PORT, function() {
76+
var socket = net.connect(PORT);
77+
socket.on('connect', function() {
78+
bench.start();
79+
80+
socket.on('drain', send)
81+
send()
82+
83+
setTimeout(function() {
84+
var bytes = writer.received;
85+
var gbits = (bytes * 8) / (1024 * 1024 * 1024);
86+
bench.end(gbits);
87+
}, dur * 1000);
88+
89+
function send() {
90+
socket.cork();
91+
while(socket.write(chunk, encoding)) {}
92+
socket.uncork();
93+
}
94+
});
95+
});
96+
}

configure

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,10 @@ shared_optgroup.add_option('--shared-zlib-libpath',
196196

197197
parser.add_option_group(shared_optgroup)
198198

199-
# TODO document when we've decided on what the tracing API and its options will
200-
# look like
201199
parser.add_option('--systemtap-includes',
202200
action='store',
203201
dest='systemtap_includes',
204-
help=optparse.SUPPRESS_HELP)
202+
help='directory containing systemtap header files')
205203

206204
parser.add_option('--tag',
207205
action='store',
@@ -1052,7 +1050,7 @@ def configure_intl(o):
10521050
if not icu_ver_major:
10531051
print ' Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
10541052
sys.exit(1)
1055-
icu_endianness = sys.byteorder[0]; # TODO(srl295): EBCDIC should be 'e'
1053+
icu_endianness = sys.byteorder[0];
10561054
o['variables']['icu_ver_major'] = icu_ver_major
10571055
o['variables']['icu_endianness'] = icu_endianness
10581056
icu_data_file_l = 'icudt%s%s.dat' % (icu_ver_major, 'l')
@@ -1104,7 +1102,7 @@ def configure_intl(o):
11041102
return # end of configure_intl
11051103

11061104
output = {
1107-
'variables': { 'python': sys.executable },
1105+
'variables': {},
11081106
'include_dirs': [],
11091107
'libraries': [],
11101108
'defines': [],

doc/api/documentation.markdown

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,19 @@ Every HTML file in the markdown has a corresponding JSON file with the
6666
same data.
6767

6868
This feature was added in Node.js v0.6.12. It is experimental.
69+
70+
## Syscalls and man pages
71+
72+
System calls like open(2) and read(2) define the interface between user programs
73+
and the underlying operating system. Node functions which simply wrap a syscall,
74+
like `fs.open()`, will document that. The docs link to the corresponding man
75+
pages (short for manual pages) which describe how the syscalls work.
76+
77+
**Caveat:** some syscalls, like lchown(2), are BSD-specific. That means, for
78+
example, that `fs.lchown()` only works on Mac OS X and other BSD-derived systems,
79+
and is not available on Linux.
80+
81+
Most Unix syscalls have Windows equivalents, but behavior may differ on Windows
82+
relative to Linux and OS X. For an example of the subtle ways in which it's
83+
sometimes impossible to replace Unix syscall semantics on Windows, see [Node
84+
issue 4760](https://github.com/nodejs/node/issues/4760).

lib/_debug_agent.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function Agent() {
4848

4949
this.first = true;
5050
this.binding = process._debugAPI;
51+
assert(this.binding, 'Debugger agent running without bindings!');
5152

5253
var self = this;
5354
this.binding.onmessage = function(msg) {
@@ -57,7 +58,6 @@ function Agent() {
5758
};
5859

5960
this.clients = [];
60-
assert(this.binding, 'Debugger agent running without bindings!');
6161
}
6262
util.inherits(Agent, net.Server);
6363

lib/_http_client.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ function tickOnSocket(req, socket) {
465465
parser.reinitialize(HTTPParser.RESPONSE);
466466
parser.socket = socket;
467467
parser.incoming = null;
468+
parser.outgoing = req;
468469
req.parser = parser;
469470

470471
socket.parser = parser;

lib/_http_common.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const kOnHeaders = HTTPParser.kOnHeaders | 0;
2020
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
2121
const kOnBody = HTTPParser.kOnBody | 0;
2222
const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
23+
const kOnExecute = HTTPParser.kOnExecute | 0;
2324

2425
// Only called in the slow case where slow means
2526
// that the request headers were either fragmented
@@ -77,6 +78,20 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,
7778
parser.incoming.statusMessage = statusMessage;
7879
}
7980

81+
// The client made non-upgrade request, and server is just advertising
82+
// supported protocols.
83+
//
84+
// See RFC7230 Section 6.7
85+
//
86+
// NOTE: RegExp below matches `upgrade` in `Connection: abc, upgrade, def`
87+
// header.
88+
if (upgrade &&
89+
parser.outgoing !== null &&
90+
(parser.outgoing._headers.upgrade === undefined ||
91+
!/(^|\W)upgrade(\W|$)/i.test(parser.outgoing._headers.connection))) {
92+
upgrade = false;
93+
}
94+
8095
parser.incoming.upgrade = upgrade;
8196

8297
var skipBody = false; // response to HEAD or CONNECT
@@ -142,6 +157,10 @@ var parsers = new FreeList('parsers', 1000, function() {
142157
parser._url = '';
143158
parser._consumed = false;
144159

160+
parser.socket = null;
161+
parser.incoming = null;
162+
parser.outgoing = null;
163+
145164
// Only called in the slow case where slow means
146165
// that the request headers were either fragmented
147166
// across multiple TCP packets or too large to be
@@ -151,6 +170,7 @@ var parsers = new FreeList('parsers', 1000, function() {
151170
parser[kOnHeadersComplete] = parserOnHeadersComplete;
152171
parser[kOnBody] = parserOnBody;
153172
parser[kOnMessageComplete] = parserOnMessageComplete;
173+
parser[kOnExecute] = null;
154174

155175
return parser;
156176
});
@@ -175,6 +195,8 @@ function freeParser(parser, req, socket) {
175195
parser.socket.parser = null;
176196
parser.socket = null;
177197
parser.incoming = null;
198+
parser.outgoing = null;
199+
parser[kOnExecute] = null;
178200
if (parsers.free(parser) === false)
179201
parser.close();
180202
parser = null;

lib/_stream_writable.js

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ function WritableState(options, stream) {
108108

109109
// True if the error was already emitted and should not be thrown again
110110
this.errorEmitted = false;
111+
112+
// count buffered requests
113+
this.bufferedRequestCount = 0;
114+
115+
// create the two objects needed to store the corked requests
116+
// they are not a linked list, as no new elements are inserted in there
117+
this.corkedRequestsFree = new CorkedRequest(this);
118+
this.corkedRequestsFree.next = new CorkedRequest(this);
111119
}
112120

113121
WritableState.prototype.getBuffer = function writableStateGetBuffer() {
@@ -274,6 +282,7 @@ function writeOrBuffer(stream, state, chunk, encoding, cb) {
274282
} else {
275283
state.bufferedRequest = state.lastBufferedRequest;
276284
}
285+
state.bufferedRequestCount += 1;
277286
} else {
278287
doWrite(stream, state, false, len, chunk, encoding, cb);
279288
}
@@ -357,34 +366,33 @@ function onwriteDrain(stream, state) {
357366
}
358367
}
359368

360-
361369
// if there's something in the buffer waiting, then process it
362370
function clearBuffer(stream, state) {
363371
state.bufferProcessing = true;
364372
var entry = state.bufferedRequest;
365373

366374
if (stream._writev && entry && entry.next) {
367375
// Fast case, write everything using _writev()
368-
var buffer = [];
369-
var cbs = [];
376+
var l = state.bufferedRequestCount;
377+
var buffer = new Array(l);
378+
var holder = state.corkedRequestsFree;
379+
holder.entry = entry;
380+
381+
var count = 0;
370382
while (entry) {
371-
cbs.push(entry.callback);
372-
buffer.push(entry);
383+
buffer[count] = entry;
373384
entry = entry.next;
385+
count += 1;
374386
}
375387

376-
// count the one we are adding, as well.
377-
// TODO(isaacs) clean this up
388+
doWrite(stream, state, true, state.length, buffer, '', holder.finish);
389+
390+
// doWrite is always async, defer these to save a bit of time
391+
// as the hot path ends with doWrite
378392
state.pendingcb++;
379393
state.lastBufferedRequest = null;
380-
doWrite(stream, state, true, state.length, buffer, '', function(err) {
381-
for (var i = 0; i < cbs.length; i++) {
382-
state.pendingcb--;
383-
cbs[i](err);
384-
}
385-
});
386-
387-
// Clear buffer
394+
state.corkedRequestsFree = holder.next;
395+
holder.next = null;
388396
} else {
389397
// Slow case, write chunks one-by-one
390398
while (entry) {
@@ -407,6 +415,8 @@ function clearBuffer(stream, state) {
407415
if (entry === null)
408416
state.lastBufferedRequest = null;
409417
}
418+
419+
state.bufferedRequestCount = 0;
410420
state.bufferedRequest = entry;
411421
state.bufferProcessing = false;
412422
}
@@ -484,3 +494,26 @@ function endWritable(stream, state, cb) {
484494
}
485495
state.ended = true;
486496
}
497+
498+
// It seems a linked list but it is not
499+
// there will be only 2 of these for each stream
500+
function CorkedRequest(state) {
501+
this.next = null;
502+
this.entry = null;
503+
504+
this.finish = (err) => {
505+
var entry = this.entry;
506+
this.entry = null;
507+
while (entry) {
508+
var cb = entry.callback;
509+
state.pendingcb--;
510+
cb(err);
511+
entry = entry.next;
512+
}
513+
if (state.corkedRequestsFree) {
514+
state.corkedRequestsFree.next = this;
515+
} else {
516+
state.corkedRequestsFree = this;
517+
}
518+
};
519+
}

lib/_tls_wrap.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ proxiedMethods.forEach(function(name) {
313313
});
314314

315315
tls_wrap.TLSWrap.prototype.close = function closeProxy(cb) {
316+
if (this.owner)
317+
this.owner.ssl = null;
318+
316319
if (this._parentWrap && this._parentWrap._handle === this._parent) {
317320
this._parentWrap.once('close', cb);
318321
return this._parentWrap.destroy();

lib/buffer.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,14 @@ function slowIndexOf(buffer, val, byteOffset, encoding) {
456456
}
457457

458458
Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {
459-
if (byteOffset > 0x7fffffff)
459+
if (typeof byteOffset === 'string') {
460+
encoding = byteOffset;
461+
byteOffset = 0;
462+
} else if (byteOffset > 0x7fffffff) {
460463
byteOffset = 0x7fffffff;
461-
else if (byteOffset < -0x80000000)
464+
} else if (byteOffset < -0x80000000) {
462465
byteOffset = -0x80000000;
466+
}
463467
byteOffset >>= 0;
464468

465469
if (typeof val === 'string') {

lib/internal/child_process.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ util.inherits(ChildProcess, EventEmitter);
217217
function flushStdio(subprocess) {
218218
if (subprocess.stdio == null) return;
219219
subprocess.stdio.forEach(function(stream, fd, stdio) {
220-
if (!stream || !stream.readable)
220+
if (!stream || !stream.readable || stream._readableState.readableListening)
221221
return;
222222
stream.resume();
223223
});

node.gyp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@
520520
}]
521521
],
522522
'action': [
523-
'<(python)',
523+
'python',
524524
'tools/js2c.py',
525525
'<@(_outputs)',
526526
'<@(_inputs)',

src/node_buffer.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,9 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
827827
Local<String> needle = args[1].As<String>();
828828
const char* haystack = ts_obj_data;
829829
const size_t haystack_length = ts_obj_length;
830-
const size_t needle_length = needle->Utf8Length();
830+
// Extended latin-1 characters are 2 bytes in Utf8.
831+
const size_t needle_length =
832+
enc == BINARY ? needle->Length() : needle->Utf8Length();
831833

832834

833835
if (needle_length == 0 || haystack_length == 0) {

0 commit comments

Comments
 (0)