From 53c5bf546e8e52db5b11287ab3bf1375819b369b Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 23 Aug 2017 18:29:49 +0200 Subject: [PATCH 1/5] http2: refactor error handling This changes the error handling model of ServerHttp2Stream, ServerHttp2Request and ServerHttp2Response. An 'error' emitted on ServerHttp2Stream will not go to 'uncaughtException' anymore, but to the server 'streamError'. On the stream 'error', ServerHttp2Request will emit 'abort', while ServerHttp2Response would do nothing. It also updates respondWith* to the new error handling. Fixes: https://github.com/nodejs/node/issues/14963 PR-URL: https://github.com/nodejs/node/pull/14991 Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum --- doc/api/http2.md | 39 +++++++- lib/http2.js | 4 +- lib/internal/http2/compat.js | 16 ++- lib/internal/http2/core.js | 43 ++++++-- ...p2-client-stream-destroy-before-connect.js | 17 +--- test/parallel/test-http2-compat-errors.js | 52 ++++++++++ test/parallel/test-http2-respond-file-404.js | 48 +++++++++ .../test-http2-respond-file-error-dir.js | 46 +++++++++ test/parallel/test-http2-server-errors.js | 97 +++++++++++++++++++ 9 files changed, 329 insertions(+), 33 deletions(-) create mode 100644 test/parallel/test-http2-compat-errors.js create mode 100644 test/parallel/test-http2-respond-file-404.js create mode 100644 test/parallel/test-http2-respond-file-error-dir.js create mode 100644 test/parallel/test-http2-server-errors.js diff --git a/doc/api/http2.md b/doc/api/http2.md index d9b8aa97b0e..57e1b74e7e9 100755 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -1118,6 +1118,8 @@ added: v8.4.0 * `headers` {[Headers Object][]} * `options` {Object} * `statCheck` {Function} + * `onError` {Function} Callback function invoked in the case of an + Error before send * `getTrailers` {Function} Callback function invoked to collect trailer headers. * `offset` {number} The offset position at which to begin reading @@ -1146,6 +1148,16 @@ server.on('stream', (stream) => { function statCheck(stat, headers) { headers['last-modified'] = stat.mtime.toUTCString(); } + + function onError(err) { + if (err.code === 'ENOENT') { + stream.respond({ ':status': 404 }); + } else { + stream.respond({ ':status': 500 }); + } + stream.end(); + } + stream.respondWithFile('/some/file', { 'content-type': 'text/plain' }, { statCheck }); @@ -1178,6 +1190,10 @@ The `offset` and `length` options may be used to limit the response to a specific range subset. This can be used, for instance, to support HTTP Range requests. +The `options.onError` function may also be used to handle all the errors +that could happen before the delivery of the file is initiated. The +default behavior is to destroy the stream. + When set, the `options.getTrailers()` function is called immediately after queuing the last chunk of payload data to be sent. The callback is passed a single object (with a `null` prototype) that the listener may used to specify @@ -1208,6 +1224,19 @@ added: v8.4.0 * Extends: {net.Server} +In `Http2Server`, there is no `'clientError'` event as there is in +HTTP1. However, there are `'socketError'`, `'sessionError'`, and +`'streamError'`, for error happened on the socket, session or stream +respectively. + +#### Event: 'socketError' + + +The `'socketError'` event is emitted when a `'socketError'` event is emitted by +an `Http2Session` associated with the server. + #### Event: 'sessionError' -The `'socketError'` event is emitted when a `'socketError'` event is emitted by -an `Http2Session` associated with the server. +* `socket` {http2.ServerHttp2Stream} + +If an `ServerHttp2Stream` emits an `'error'` event, it will be forwarded here. +The stream will already be destroyed when this event is triggered. #### Event: 'stream' ' + '

Look here!

' + '' + @@ -83,7 +84,7 @@ const testData = [ '' }, { - file: path.join(common.fixturesDir, 'sample_document.md'), + file: fixtures.path('sample_document.md'), html: '
  1. fish
  2. fish

  3. Redfish

  4. ' + '
  5. Bluefish
', analyticsId: 'UA-67020396-1' diff --git a/test/doctool/test-doctool-json.js b/test/doctool/test-doctool-json.js index 4a4d3a895c3..1be086c3a6a 100644 --- a/test/doctool/test-doctool-json.js +++ b/test/doctool/test-doctool-json.js @@ -10,7 +10,7 @@ try { const assert = require('assert'); const fs = require('fs'); -const path = require('path'); +const fixtures = require('../common/fixtures'); const json = require('../../tools/doc/json.js'); // Outputs valid json with the expected fields when given simple markdown @@ -19,7 +19,7 @@ const json = require('../../tools/doc/json.js'); // The json property is some json which will be generated by the doctool. const testData = [ { - file: path.join(common.fixturesDir, 'sample_document.md'), + file: fixtures.path('sample_document.md'), json: { source: 'foo', modules: [{ @@ -39,7 +39,7 @@ const testData = [ } }, { - file: path.join(common.fixturesDir, 'order_of_end_tags_5873.md'), + file: fixtures.path('order_of_end_tags_5873.md'), json: { source: 'foo', modules: [{ @@ -76,7 +76,7 @@ const testData = [ } }, { - file: path.join(common.fixturesDir, 'doc_with_yaml.md'), + file: fixtures.path('doc_with_yaml.md'), json: { source: 'foo', modules: [ diff --git a/test/fixtures/module-require-symlink/symlinked.js b/test/fixtures/module-require-symlink/symlinked.js index 657ef266264..ced901b2466 100644 --- a/test/fixtures/module-require-symlink/symlinked.js +++ b/test/fixtures/module-require-symlink/symlinked.js @@ -1,11 +1,9 @@ 'use strict'; -const common = require('../../common'); const assert = require('assert'); const foo = require('./foo'); -const path = require('path'); +const fixtures = require('../../common/fixtures'); -const linkScriptTarget = path.join(common.fixturesDir, - 'module-require-symlink', 'symlinked.js'); +const linkScriptTarget = fixtures.path('module-require-symlink', 'symlinked.js'); assert.strictEqual(foo.dep1.bar.version, 'CORRECT_VERSION'); assert.strictEqual(foo.dep2.bar.version, 'CORRECT_VERSION'); diff --git a/test/fixtures/tls-connect.js b/test/fixtures/tls-connect.js index 2ce75a53767..cff42400866 100644 --- a/test/fixtures/tls-connect.js +++ b/test/fixtures/tls-connect.js @@ -9,8 +9,7 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); -const fs = require('fs'); -const join = require('path').join; +const fixtures = require('../common/fixtures'); const tls = require('tls'); const util = require('util'); @@ -33,17 +32,13 @@ const keys = exports.keys = { function load(cert, issuer) { issuer = issuer || cert; // Assume self-signed if no issuer const id = { - key: read(cert + '-key.pem'), - cert: read(cert + '-cert.pem'), - ca: read(issuer + '-cert.pem'), + key: fixtures.readKey(cert + '-key.pem', 'binary'), + cert: fixtures.readKey(cert + '-cert.pem', 'binary'), + ca: fixtures.readKey(issuer + '-cert.pem', 'binary'), }; return id; } -function read(file) { - return fs.readFileSync(join(common.fixturesDir, 'keys', file), 'binary'); -} - exports.connect = function connect(options, callback) { callback = common.mustCall(callback); diff --git a/test/inspector/inspector-helper.js b/test/inspector/inspector-helper.js index 9c1cca3a771..81aa046bf3d 100644 --- a/test/inspector/inspector-helper.js +++ b/test/inspector/inspector-helper.js @@ -3,11 +3,11 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); const http = require('http'); -const path = require('path'); +const fixtures = require('../common/fixtures'); const { spawn } = require('child_process'); const url = require('url'); -const _MAINSCRIPT = path.join(common.fixturesDir, 'loop.js'); +const _MAINSCRIPT = fixtures.path('loop.js'); const DEBUG = false; const TIMEOUT = common.platformTimeout(15 * 1000); diff --git a/test/internet/test-tls-add-ca-cert.js b/test/internet/test-tls-add-ca-cert.js index 299e01405d7..c3780acd506 100644 --- a/test/internet/test-tls-add-ca-cert.js +++ b/test/internet/test-tls-add-ca-cert.js @@ -8,11 +8,11 @@ if (!common.hasCrypto) const assert = require('assert'); const fs = require('fs'); -const path = require('path'); +const fixtures = require('../common/fixtures'); const tls = require('tls'); function filenamePEM(n) { - return path.join(common.fixturesDir, 'keys', `${n}.pem`); + return fixtures.path('keys', `${n}.pem`); } function loadPEM(n) { diff --git a/test/known_issues/test-repl-require-context.js b/test/known_issues/test-repl-require-context.js index e7a27f2ca68..2b8737b8671 100644 --- a/test/known_issues/test-repl-require-context.js +++ b/test/known_issues/test-repl-require-context.js @@ -2,12 +2,12 @@ // Refs: https://github.com/nodejs/node/issues/7788 const common = require('../common'); const assert = require('assert'); -const path = require('path'); +const path = require('../common/fixtures').path; const repl = require('repl'); const stream = require('stream'); const inputStream = new stream.PassThrough(); const outputStream = new stream.PassThrough(); -const fixture = path.join(common.fixturesDir, 'is-object.js'); +const fixture = path('is-object.js'); const r = repl.start({ input: inputStream, output: outputStream, diff --git a/test/known_issues/test-url-parse-conformance.js b/test/known_issues/test-url-parse-conformance.js index 62c36da87e6..022a613a226 100644 --- a/test/known_issues/test-url-parse-conformance.js +++ b/test/known_issues/test-url-parse-conformance.js @@ -1,13 +1,11 @@ 'use strict'; // Refs: https://github.com/nodejs/node/issues/5832 - -const common = require('../common'); +require('../common'); const url = require('url'); const assert = require('assert'); -const path = require('path'); - -const tests = require(path.join(common.fixturesDir, 'url-tests')); +const fixtures = require('../common/fixtures'); +const tests = require(fixtures.path('url-tests')); let failed = 0; let attempted = 0; diff --git a/test/pummel/test-https-ci-reneg-attack.js b/test/pummel/test-https-ci-reneg-attack.js index fbe0e37873c..9e132b7df9a 100644 --- a/test/pummel/test-https-ci-reneg-attack.js +++ b/test/pummel/test-https-ci-reneg-attack.js @@ -31,7 +31,7 @@ const assert = require('assert'); const spawn = require('child_process').spawn; const tls = require('tls'); const https = require('https'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); // renegotiation limits to test const LIMITS = [0, 1, 2, 3, 5, 10, 16]; @@ -48,8 +48,8 @@ const LIMITS = [0, 1, 2, 3, 5, 10, 16]; function test(next) { const options = { - cert: fs.readFileSync(`${common.fixturesDir}/test_cert.pem`), - key: fs.readFileSync(`${common.fixturesDir}/test_key.pem`) + cert: fixtures.readSync('test_cert.pem'), + key: fixtures.readSync('test_key.pem') }; let seenError = false; diff --git a/test/pummel/test-https-large-response.js b/test/pummel/test-https-large-response.js index 7775ccca63e..d72fd2a65ba 100644 --- a/test/pummel/test-https-large-response.js +++ b/test/pummel/test-https-large-response.js @@ -25,12 +25,12 @@ if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); const https = require('https'); const options = { - key: fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`), - cert: fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`) + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem') }; process.stdout.write('build body...'); diff --git a/test/pummel/test-https-no-reader.js b/test/pummel/test-https-no-reader.js index b8071b9ba97..985d888e6d0 100644 --- a/test/pummel/test-https-no-reader.js +++ b/test/pummel/test-https-no-reader.js @@ -26,12 +26,11 @@ if (!common.hasCrypto) const assert = require('assert'); const https = require('https'); -const fs = require('fs'); -const path = require('path'); +const fixtures = require('../common/fixtures'); const options = { - key: fs.readFileSync(path.join(common.fixturesDir, 'test_key.pem')), - cert: fs.readFileSync(path.join(common.fixturesDir, 'test_cert.pem')) + key: fixtures.readSync('test_key.pem'), + cert: fixtures.readSync('test_cert.pem') }; const buf = Buffer.allocUnsafe(1024 * 1024); diff --git a/test/pummel/test-regress-GH-892.js b/test/pummel/test-regress-GH-892.js index 76f98b29579..05e27628b14 100644 --- a/test/pummel/test-regress-GH-892.js +++ b/test/pummel/test-regress-GH-892.js @@ -33,14 +33,13 @@ if (!common.hasCrypto) const assert = require('assert'); const spawn = require('child_process').spawn; const https = require('https'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); const bytesExpected = 1024 * 1024 * 32; let started = false; -const childScript = require('path').join(common.fixturesDir, - 'GH-892-request.js'); +const childScript = fixtures.path('GH-892-request.js'); function makeRequest() { if (started) return; @@ -78,8 +77,8 @@ function makeRequest() { const serverOptions = { - key: fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`), - cert: fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`) + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem') }; let uploadCount = 0; diff --git a/test/pummel/test-tls-ci-reneg-attack.js b/test/pummel/test-tls-ci-reneg-attack.js index 905d922db3a..dede8ec9db7 100644 --- a/test/pummel/test-tls-ci-reneg-attack.js +++ b/test/pummel/test-tls-ci-reneg-attack.js @@ -30,7 +30,7 @@ if (!common.opensslCli) const assert = require('assert'); const spawn = require('child_process').spawn; const tls = require('tls'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); // renegotiation limits to test const LIMITS = [0, 1, 2, 3, 5, 10, 16]; @@ -47,8 +47,8 @@ const LIMITS = [0, 1, 2, 3, 5, 10, 16]; function test(next) { const options = { - cert: fs.readFileSync(`${common.fixturesDir}/test_cert.pem`), - key: fs.readFileSync(`${common.fixturesDir}/test_key.pem`) + cert: fixtures.readSync('test_cert.pem'), + key: fixtures.readSync('test_key.pem') }; let seenError = false; diff --git a/test/pummel/test-tls-connect-memleak.js b/test/pummel/test-tls-connect-memleak.js index c086933a3e0..4425e8d04eb 100644 --- a/test/pummel/test-tls-connect-memleak.js +++ b/test/pummel/test-tls-connect-memleak.js @@ -28,7 +28,7 @@ if (!common.hasCrypto) const assert = require('assert'); const tls = require('tls'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); assert.strictEqual( typeof global.gc, @@ -37,8 +37,8 @@ assert.strictEqual( ); tls.createServer({ - cert: fs.readFileSync(`${common.fixturesDir}/test_cert.pem`), - key: fs.readFileSync(`${common.fixturesDir}/test_key.pem`) + cert: fixtures.readSync('test_cert.pem'), + key: fixtures.readSync('test_key.pem') }).listen(common.PORT); { diff --git a/test/pummel/test-tls-securepair-client.js b/test/pummel/test-tls-securepair-client.js index e1a489a145d..dbcd33d5346 100644 --- a/test/pummel/test-tls-securepair-client.js +++ b/test/pummel/test-tls-securepair-client.js @@ -29,10 +29,9 @@ if (!common.opensslCli) if (!common.hasCrypto) common.skip('missing crypto'); -const join = require('path').join; const net = require('net'); const assert = require('assert'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); const tls = require('tls'); const spawn = require('child_process').spawn; @@ -56,11 +55,8 @@ function test2() { } function test(keyfn, certfn, check, next) { - keyfn = join(common.fixturesDir, keyfn); - const key = fs.readFileSync(keyfn).toString(); - - certfn = join(common.fixturesDir, certfn); - const cert = fs.readFileSync(certfn).toString(); + const key = fixtures.readSync(keyfn).toString(); + const cert = fixtures.readSync(certfn).toString(); const server = spawn(common.opensslCli, ['s_server', '-accept', common.PORT, diff --git a/test/pummel/test-tls-server-large-request.js b/test/pummel/test-tls-server-large-request.js index 3255633ec7c..a99c142d53c 100644 --- a/test/pummel/test-tls-server-large-request.js +++ b/test/pummel/test-tls-server-large-request.js @@ -26,15 +26,15 @@ if (!common.hasCrypto) const assert = require('assert'); const tls = require('tls'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); const stream = require('stream'); const util = require('util'); const request = Buffer.from('ABCD'.repeat(1024 * 256 - 1)); // 1mb const options = { - key: fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`), - cert: fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`) + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem') }; function Mediator() { diff --git a/test/pummel/test-tls-session-timeout.js b/test/pummel/test-tls-session-timeout.js index 9b175da77e6..56fdfa16ea7 100644 --- a/test/pummel/test-tls-session-timeout.js +++ b/test/pummel/test-tls-session-timeout.js @@ -43,14 +43,13 @@ function doTest() { const tls = require('tls'); const fs = require('fs'); const join = require('path').join; + const fixtures = require('../common/fixtures'); const spawn = require('child_process').spawn; const SESSION_TIMEOUT = 1; - const keyFile = join(common.fixturesDir, 'agent.key'); - const certFile = join(common.fixturesDir, 'agent.crt'); - const key = fs.readFileSync(keyFile); - const cert = fs.readFileSync(certFile); + const key = fixtures.path('agent.key'); + const cert = fixtures.path('agent.crt'); const options = { key: key, cert: cert, @@ -66,9 +65,8 @@ function doTest() { const sessionFileName = (function() { const ticketFileName = 'tls-session-ticket.txt'; - const fixturesPath = join(common.fixturesDir, ticketFileName); const tmpPath = join(common.tmpDir, ticketFileName); - fs.writeFileSync(tmpPath, fs.readFileSync(fixturesPath)); + fs.writeFileSync(tmpPath, fixtures.readSync(ticketFileName)); return tmpPath; }()); diff --git a/test/pummel/test-tls-throttle.js b/test/pummel/test-tls-throttle.js index 2d0ea1c673a..3e18c4cff43 100644 --- a/test/pummel/test-tls-throttle.js +++ b/test/pummel/test-tls-throttle.js @@ -29,15 +29,15 @@ if (!common.hasCrypto) const assert = require('assert'); const tls = require('tls'); -const fs = require('fs'); +const fixtures = require('../common/fixtures'); process.stdout.write('build body...'); const body = 'hello world\n'.repeat(1024 * 1024); process.stdout.write('done\n'); const options = { - key: fs.readFileSync(`${common.fixturesDir}/keys/agent2-key.pem`), - cert: fs.readFileSync(`${common.fixturesDir}/keys/agent2-cert.pem`) + key: fixtures.readKey('agent2-key.pem'), + cert: fixtures.readKey('agent2-cert.pem') }; const server = tls.Server(options, common.mustCall(function(socket) { diff --git a/test/pummel/test-watch-file.js b/test/pummel/test-watch-file.js index 0ca8154ee2d..4a728205206 100644 --- a/test/pummel/test-watch-file.js +++ b/test/pummel/test-watch-file.js @@ -20,13 +20,13 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -const common = require('../common'); -const assert = require('assert'); +require('../common'); +const assert = require('assert'); const fs = require('fs'); -const path = require('path'); +const fixtures = require('../common/fixtures'); -const f = path.join(common.fixturesDir, 'x.txt'); +const f = fixtures.path('x.txt'); let changes = 0; function watchFile() { diff --git a/test/sequential/test-debugger-repeat-last.js b/test/sequential/test-debugger-repeat-last.js index 39572ab99b3..42638e5d2eb 100644 --- a/test/sequential/test-debugger-repeat-last.js +++ b/test/sequential/test-debugger-repeat-last.js @@ -1,13 +1,10 @@ 'use strict'; const common = require('../common'); common.skipIfInspectorDisabled(); -const path = require('path'); +const path = require('../common/fixtures').path; const spawn = require('child_process').spawn; const assert = require('assert'); -const fixture = path.join( - common.fixturesDir, - 'debugger-repeat-last.js' -); +const fixture = path('debugger-repeat-last.js'); const args = [ 'inspect', diff --git a/test/sequential/test-init.js b/test/sequential/test-init.js index 5ca0de7db36..3c3653521d6 100644 --- a/test/sequential/test-init.js +++ b/test/sequential/test-init.js @@ -23,7 +23,7 @@ const common = require('../common'); const assert = require('assert'); const child = require('child_process'); -const path = require('path'); +const fixtures = require('../common/fixtures'); if (process.env['TEST_INIT']) { return process.stdout.write('Loaded successfully!'); @@ -57,6 +57,6 @@ function test(file, expected) { // ensures that `node fs` does not mistakenly load the native 'fs' module // instead of the desired file and that the fs module loads as // expected in node - process.chdir(path.join(common.fixturesDir, 'test-init-native')); + process.chdir(fixtures.path('test-init-native')); test('fs', 'fs loaded successfully'); } From 79773f8af940912264b55e5255db9f50e25ac16a Mon Sep 17 00:00:00 2001 From: Dave Olszewski Date: Wed, 12 Jul 2017 12:35:57 -0700 Subject: [PATCH 3/5] doc: update configure to require g++ 4.9.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/14204 Reviewed-By: Anna Henningsen Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis Reviewed-By: Tobias Nießen Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 64273164bb5..a93ef8fd012 100755 --- a/configure +++ b/configure @@ -651,8 +651,8 @@ def check_compiler(o): ok, is_clang, clang_version, gcc_version = try_check_compiler(CXX, 'c++') if not ok: warn('failed to autodetect C++ compiler version (CXX=%s)' % CXX) - elif clang_version < '3.4.2' if is_clang else gcc_version < '4.8.0': - warn('C++ compiler too old, need g++ 4.8 or clang++ 3.4.2 (CXX=%s)' % CXX) + elif clang_version < '3.4.2' if is_clang else gcc_version < '4.9.4': + warn('C++ compiler too old, need g++ 4.9.4 or clang++ 3.4.2 (CXX=%s)' % CXX) ok, is_clang, clang_version, gcc_version = try_check_compiler(CC, 'c') if not ok: From cacce304cbce79ff878aaedf946f16f03ec91b8a Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sun, 22 Jan 2017 19:16:21 -0800 Subject: [PATCH 4/5] doc: add links to alternative versions of doc Each page of the API documentation should have links to other versions of the same page. This will make it easier to switch between the current "live" release at nodejs.org and LTS versions. PR-URL: https://github.com/nodejs/node/pull/10958 Fixes: https://github.com/nodejs/node/issues/10726 Reviewed-By: Refael Ackermann Reviewed-By: Evan Lucas Reviewed-By: Sakthipriyan Vairamani Reviewed-By: Ruben Bridgewater --- doc/api/addons.md | 2 ++ doc/api/assert.md | 2 ++ doc/api/buffer.md | 2 ++ doc/api/child_process.md | 2 ++ doc/api/cli.md | 1 + doc/api/cluster.md | 2 ++ doc/api/console.md | 2 ++ doc/api/crypto.md | 2 ++ doc/api/debugger.md | 2 ++ doc/api/dgram.md | 2 ++ doc/api/dns.md | 2 ++ doc/api/documentation.md | 1 + doc/api/domain.md | 2 ++ doc/api/errors.md | 1 + doc/api/events.md | 2 ++ doc/api/fs.md | 2 ++ doc/api/globals.md | 1 + doc/api/http.md | 2 ++ doc/api/https.md | 2 ++ doc/api/modules.md | 2 ++ doc/api/net.md | 2 ++ doc/api/os.md | 2 ++ doc/api/path.md | 2 ++ doc/api/process.md | 1 + doc/api/punycode.md | 2 ++ doc/api/querystring.md | 2 ++ doc/api/readline.md | 2 ++ doc/api/repl.md | 2 ++ doc/api/stream.md | 2 ++ doc/api/string_decoder.md | 2 ++ doc/api/synopsis.md | 1 + doc/api/timers.md | 2 ++ doc/api/tls.md | 2 ++ doc/api/tty.md | 2 ++ doc/api/url.md | 2 ++ doc/api/util.md | 2 ++ doc/api/v8.md | 2 ++ doc/api/vm.md | 2 ++ doc/api/zlib.md | 2 ++ doc/api_assets/style.css | 58 +++++++++++++++++++++++++++++++++++++++ doc/template.html | 20 ++++++++++---- tools/doc/html.js | 53 ++++++++++++++++++++++++++++++++++- 42 files changed, 197 insertions(+), 6 deletions(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index f09b2e7ee60..bd175103330 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -1,5 +1,7 @@ # C++ Addons + + Node.js Addons are dynamically-linked shared objects, written in C++, that can be loaded into Node.js using the [`require()`][require] function, and used just as if they were an ordinary Node.js module. They are used primarily to diff --git a/doc/api/assert.md b/doc/api/assert.md index 5126c334e16..6661459563f 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -1,5 +1,7 @@ # Assert + + > Stability: 2 - Stable The `assert` module provides a simple set of assertion tests that can be used to diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 0301eadd3be..363b10bc664 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -1,5 +1,7 @@ # Buffer + + > Stability: 2 - Stable Prior to the introduction of [`TypedArray`] in ECMAScript 2015 (ES6), the diff --git a/doc/api/child_process.md b/doc/api/child_process.md index dde0ec85749..f4a843fc096 100755 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1,5 +1,7 @@ # Child Process + + > Stability: 2 - Stable The `child_process` module provides the ability to spawn child processes in diff --git a/doc/api/cli.md b/doc/api/cli.md index beceebec779..752df72da8a 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1,5 +1,6 @@ # Command Line Options + Node.js comes with a variety of CLI options. These options expose built-in diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 95c97865016..a3146e0f608 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -1,5 +1,7 @@ # Cluster + + > Stability: 2 - Stable A single instance of Node.js runs in a single thread. To take advantage of diff --git a/doc/api/console.md b/doc/api/console.md index ee130d7b971..0bd72cd7769 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -1,5 +1,7 @@ # Console + + > Stability: 2 - Stable The `console` module provides a simple debugging console that is similar to the diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 05e02450867..bf5e7169c14 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1,5 +1,7 @@ # Crypto + + > Stability: 2 - Stable The `crypto` module provides cryptographic functionality that includes a set of diff --git a/doc/api/debugger.md b/doc/api/debugger.md index 1a2070d3f45..e16c83122e2 100644 --- a/doc/api/debugger.md +++ b/doc/api/debugger.md @@ -1,5 +1,7 @@ # Debugger + + > Stability: 2 - Stable diff --git a/doc/api/dgram.md b/doc/api/dgram.md index c3fcfb0528f..3e77827a5e4 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -1,5 +1,7 @@ # UDP / Datagram Sockets + + > Stability: 2 - Stable diff --git a/doc/api/dns.md b/doc/api/dns.md index 4248bdf43a1..5e9fc97bbc4 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -1,5 +1,7 @@ # DNS + + > Stability: 2 - Stable The `dns` module contains functions belonging to two different categories: diff --git a/doc/api/documentation.md b/doc/api/documentation.md index a12f00e1d63..802bf3613f9 100644 --- a/doc/api/documentation.md +++ b/doc/api/documentation.md @@ -1,5 +1,6 @@ # About this Documentation + The goal of this documentation is to comprehensively explain the Node.js diff --git a/doc/api/domain.md b/doc/api/domain.md index 102ac8ec7c3..a4a31d4fecd 100644 --- a/doc/api/domain.md +++ b/doc/api/domain.md @@ -7,6 +7,8 @@ changes: the first promise of a chain was created. --> + + > Stability: 0 - Deprecated **This module is pending deprecation**. Once a replacement API has been diff --git a/doc/api/errors.md b/doc/api/errors.md index 7b29ab6ddba..3d2761b54cb 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1,5 +1,6 @@ # Errors + Applications running in Node.js will generally experience four categories of diff --git a/doc/api/events.md b/doc/api/events.md index ff6fbe9bb9a..99c2e1514b4 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -1,5 +1,7 @@ # Events + + > Stability: 2 - Stable diff --git a/doc/api/fs.md b/doc/api/fs.md index 929cf6941eb..a83d0422277 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1,5 +1,7 @@ # File System + + > Stability: 2 - Stable diff --git a/doc/api/globals.md b/doc/api/globals.md index f3a2fc63779..a2e5b5fc898 100644 --- a/doc/api/globals.md +++ b/doc/api/globals.md @@ -1,5 +1,6 @@ # Global Objects + These objects are available in all modules. The following variables may appear diff --git a/doc/api/http.md b/doc/api/http.md index 8558900d881..9c1fbb3d6be 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1,5 +1,7 @@ # HTTP + + > Stability: 2 - Stable To use the HTTP server and client one must `require('http')`. diff --git a/doc/api/https.md b/doc/api/https.md index f6c56ef8ed7..3ff97bf446b 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -1,5 +1,7 @@ # HTTPS + + > Stability: 2 - Stable HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a diff --git a/doc/api/modules.md b/doc/api/modules.md index 13e3731cae7..afddbc14c4f 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -1,5 +1,7 @@ # Modules + + > Stability: 2 - Stable diff --git a/doc/api/net.md b/doc/api/net.md index 686ee300ccf..36280c06493 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -1,5 +1,7 @@ # Net + + > Stability: 2 - Stable The `net` module provides an asynchronous network API for creating stream-based diff --git a/doc/api/os.md b/doc/api/os.md index bb4ffdc3766..28eff6a13f0 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -1,5 +1,7 @@ # OS + + > Stability: 2 - Stable The `os` module provides a number of operating system-related utility methods. diff --git a/doc/api/path.md b/doc/api/path.md index f951a4ab8a5..f2015db4704 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -1,5 +1,7 @@ # Path + + > Stability: 2 - Stable The `path` module provides utilities for working with file and directory paths. diff --git a/doc/api/process.md b/doc/api/process.md index a6da470e782..e24bf19d9d2 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1,5 +1,6 @@ # Process + The `process` object is a `global` that provides information about, and control diff --git a/doc/api/punycode.md b/doc/api/punycode.md index b88a8983264..03ee3d62ebf 100644 --- a/doc/api/punycode.md +++ b/doc/api/punycode.md @@ -6,6 +6,8 @@ changes: description: Accessing this module will now emit a deprecation warning. --> + + > Stability: 0 - Deprecated **The version of the punycode module bundled in Node.js is being deprecated**. diff --git a/doc/api/querystring.md b/doc/api/querystring.md index c6b89235c14..5bd4f1cce19 100644 --- a/doc/api/querystring.md +++ b/doc/api/querystring.md @@ -1,5 +1,7 @@ # Query String + + > Stability: 2 - Stable diff --git a/doc/api/readline.md b/doc/api/readline.md index 085ac885401..603a5ec1888 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -1,5 +1,7 @@ # Readline + + > Stability: 2 - Stable The `readline` module provides an interface for reading data from a [Readable][] diff --git a/doc/api/repl.md b/doc/api/repl.md index 618744f6e2d..d61e9be57c1 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -1,5 +1,7 @@ # REPL + + > Stability: 2 - Stable The `repl` module provides a Read-Eval-Print-Loop (REPL) implementation that diff --git a/doc/api/stream.md b/doc/api/stream.md index 23b8aa55e13..efa69532ef8 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1,5 +1,7 @@ # Stream + + > Stability: 2 - Stable A stream is an abstract interface for working with streaming data in Node.js. diff --git a/doc/api/string_decoder.md b/doc/api/string_decoder.md index 5757ba6e2b3..cde81e6ae5e 100644 --- a/doc/api/string_decoder.md +++ b/doc/api/string_decoder.md @@ -1,5 +1,7 @@ # String Decoder + + > Stability: 2 - Stable The `string_decoder` module provides an API for decoding `Buffer` objects into diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index e8fa77eee47..3d680c33b55 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -1,5 +1,6 @@ # Usage + `node [options] [v8 options] [script.js | -e "script" | - ] [arguments]` diff --git a/doc/api/timers.md b/doc/api/timers.md index 8abcdcb5cb6..09502dee100 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -1,5 +1,7 @@ # Timers + + > Stability: 2 - Stable The `timer` module exposes a global API for scheduling functions to diff --git a/doc/api/tls.md b/doc/api/tls.md index 5df8c6af5e6..e18bbb62b19 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -1,5 +1,7 @@ # TLS (SSL) + + > Stability: 2 - Stable The `tls` module provides an implementation of the Transport Layer Security diff --git a/doc/api/tty.md b/doc/api/tty.md index 963de892cbc..2950eb6db1a 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -1,5 +1,7 @@ # TTY + + > Stability: 2 - Stable The `tty` module provides the `tty.ReadStream` and `tty.WriteStream` classes. diff --git a/doc/api/url.md b/doc/api/url.md index cb2a3965f5e..632eef82e44 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -1,5 +1,7 @@ # URL + + > Stability: 2 - Stable The `url` module provides utilities for URL resolution and parsing. It can be diff --git a/doc/api/util.md b/doc/api/util.md index 076fbc479dc..ce56c50104d 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1,5 +1,7 @@ # Util + + > Stability: 2 - Stable The `util` module is primarily designed to support the needs of Node.js' own diff --git a/doc/api/v8.md b/doc/api/v8.md index 3a3e5f664a1..634d3199a1a 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -1,5 +1,7 @@ # V8 + + The `v8` module exposes APIs that are specific to the version of [V8][] built into the Node.js binary. It can be accessed using: diff --git a/doc/api/vm.md b/doc/api/vm.md index 42046e01191..dff10b17cf2 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -1,5 +1,7 @@ # VM (Executing JavaScript) + + > Stability: 2 - Stable diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 0f589799491..ed94896e970 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -1,5 +1,7 @@ # Zlib + + > Stability: 2 - Stable The `zlib` module provides compression functionality implemented using Gzip and diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index 3761be4031e..6d764fd8891 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -81,6 +81,61 @@ em code { #gtoc { font-size: .8em; + margin-bottom: 1em; +} + +#gtoc ul { + list-style: none; + margin-left: 0; +} + +#gtoc li { + display: inline; +} + +li.version-picker { + position: relative; +} + +li.version-picker:hover > ol { + display: block; +} + +li.version-picker a span { + font-size: .7em; +} + +ol.version-picker { + background: #fff; + border: 1px #43853d solid; + border-radius: 2px; + display: none; + list-style: none; + position: absolute; + right: -2px; + width: 101%; +} + +#gtoc ol.version-picker li { + display: block; +} + +ol.version-picker li a { + border-radius: 0; + display: block; + margin: 0; + padding: .1em; + padding-left: 1em; +} + +ol.version-picker li:first-child a { + border-top-right-radius: 1px; + border-top-left-radius: 1px; +} + +ol.version-picker li:last-child a { + border-bottom-right-radius: 1px; + border-bottom-left-radius: 1px; } .line { @@ -507,6 +562,9 @@ th > *:last-child, td > *:last-child { #content { font-size: 3.5em; } + #gtoc { + font-size: 0.6em; + } } @media print { diff --git a/doc/template.html b/doc/template.html index 572197beff4..d65b56ca5e8 100644 --- a/doc/template.html +++ b/doc/template.html @@ -23,11 +23,21 @@

Node.js __VERSION__ Documentation

-

- Index | - View on single page | - View as JSON -

+

diff --git a/tools/doc/html.js b/tools/doc/html.js index b0a3c13c699..c55772aa053 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -31,6 +31,7 @@ const typeParser = require('./type-parser.js'); module.exports = toHTML; const STABILITY_TEXT_REG_EXP = /(.*:)\s*(\d)([\s\S]*)/; +const DOC_CREATED_REG_EXP = //; // customized heading without id attribute const renderer = new marked.Renderer(); @@ -52,13 +53,17 @@ const gtocPath = path.resolve(path.join( )); var gtocLoading = null; var gtocData = null; +var docCreated = null; +var nodeVersion = null; /** * opts: input, filename, template, nodeVersion. */ function toHTML(opts, cb) { const template = opts.template; - const nodeVersion = opts.nodeVersion || process.version; + + nodeVersion = opts.nodeVersion || process.version; + docCreated = opts.input.match(DOC_CREATED_REG_EXP); if (gtocData) { return onGtocLoaded(); @@ -157,6 +162,8 @@ function render(opts, cb) { ); } + template = template.replace(/__ALTDOCS__/, altDocs(filename)); + // content has to be the last thing we do with // the lexed tokens, because it's destructive. const content = marked.parser(lexed); @@ -188,6 +195,50 @@ function replaceInText(text) { return linkJsTypeDocs(linkManPages(text)); } +function altDocs(filename) { + let html = ''; + + if (!docCreated) { + console.error(`Failed to add alternative version links to ${filename}`); + return html; + } + + function lte(v) { + const ns = v.num.split('.'); + if (docCreated[1] > +ns[0]) + return false; + if (docCreated[1] < +ns[0]) + return true; + return docCreated[2] <= +ns[1]; + } + + const versions = [ + { num: '8.x' }, + { num: '7.x' }, + { num: '6.x', lts: true }, + { num: '5.x' }, + { num: '4.x', lts: true }, + { num: '0.12.x' }, + { num: '0.10.x' } + ]; + + const host = 'https://nodejs.org'; + const href = (v) => `${host}/docs/latest-v${v.num}/api/${filename}.html`; + + function li(v, i) { + let html = `
  • ${v.num}`; + + if (v.lts) + html += ' LTS'; + + return html + '
  • '; + } + + const lis = (vs) => vs.filter(lte).map(li).join('\n'); + + return `
      ${lis(versions)}
    `; +} + // handle general body-text replacements // for example, link man page references to the actual page function parseText(lexed) { From 7854562143ccd3add3f31cc6f4f7ab22ce6582ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Mon, 28 Aug 2017 16:57:33 +0200 Subject: [PATCH 5/5] tools: fix linter error in html.js PR-URL: https://github.com/nodejs/node/pull/15063 Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Yuta Hiroto --- tools/doc/html.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/doc/html.js b/tools/doc/html.js index c55772aa053..3373750a8d2 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -196,11 +196,9 @@ function replaceInText(text) { } function altDocs(filename) { - let html = ''; - if (!docCreated) { console.error(`Failed to add alternative version links to ${filename}`); - return html; + return ''; } function lte(v) {