diff --git a/BUILDING.md b/BUILDING.md index 118dacd7352..e1ade4f4d21 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -197,9 +197,11 @@ Prerequisites: * [Visual Studio 2015 Update 3](https://www.visualstudio.com/), all editions including the Community edition (remember to select "Common Tools for Visual C++ 2015" feature during installation). - * [Visual Studio 2017](https://www.visualstudio.com/downloads/), any edition (including the Build Tools SKU). - **Required Components:** "MSbuild", "VC++ 2017 v141 toolset" and at least one of the Windows SDKs. - *Note*: For "Windows 10 SDK (10.0.15063.0)" only the "Desktop C++ x86 and x64" flavor is required. + * The "Desktop development with C++" workload from + [Visual Studio 2017](https://www.visualstudio.com/downloads/) or the + "Visual C++ build tools" workload from the + [Build Tools](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017), + with the default optional components. * Basic Unix tools required for some tests, [Git for Windows](http://git-scm.com/download/win) includes Git Bash and tools which can be included in the global `PATH`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 99278a843af..b234f935488 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -334,6 +334,14 @@ use `Refs:`. - `Refs: http://eslint.org/docs/rules/space-in-parens.html` - `Refs: https://github.com/nodejs/node/pull/3615` +5. If your commit introduces a breaking change (`semver-major`), it should +contain an explanation about the reason of the breaking change, which +situation would trigger the breaking change and what is the exact change. + +Breaking changes will be listed in the wiki with the aim to make upgrading +easier. Please have a look at [Breaking Changes](https://github.com/nodejs/node/wiki/Breaking-changes-between-v4-LTS-and-v6-LTS) +for the level of detail that's suitable. + Sample complete commit message: ```txt @@ -625,6 +633,7 @@ Focus first on the most significant aspects of the change: 1. Does this change make sense for Node.js? 2. Does this change make Node.js better, even if only incrementally? 3. Are there clear bugs or larger scale issues that need attending to? +4. Is the commit message readable and correct? If it contains a breaking change is it clear enough? When changes are necessary, *request* them, do not *demand* them, and do not assume that the submitter already knows how to add a test or run a benchmark. diff --git a/Makefile b/Makefile index 64dc22867fc..763e944e9b0 100644 --- a/Makefile +++ b/Makefile @@ -984,6 +984,7 @@ lint-md-build: echo "Markdown linter: installing remark-preset-lint-node into tools/"; \ cd tools/remark-preset-lint-node && ../../$(NODE) ../../$(NPM) install; fi +ifneq ("","$(wildcard tools/remark-cli/node_modules/)") LINT_MD_TARGETS = src lib benchmark tools/doc tools/icu LINT_MD_ROOT_DOCS := $(wildcard *.md) LINT_MD_FILES := $(shell find $(LINT_MD_TARGETS) -type f \ @@ -1002,7 +1003,12 @@ tools/.miscmdlintstamp: $(LINT_MD_FILES) tools/.mdlintstamp: tools/.miscmdlintstamp tools/.docmdlintstamp -lint-md: | lint-md-build tools/.mdlintstamp +lint-md: | tools/.mdlintstamp +else +lint-md: + @echo "The markdown linter is not installed." + @echo "To install (requires internet access) run: $ make lint-md-build" +endif LINT_JS_TARGETS = benchmark doc lib test tools LINT_JS_CMD = tools/eslint/bin/eslint.js --cache \ diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 500c2b5185c..da4214365c4 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -26,6 +26,7 @@ Marc Schlaich Michael Michael Neumann Nicholas Vavilov +Nick Logan Rasmus Christian Pedersen Rasmus Christian Pedersen Robert Mustacchi diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 4747c06b306..03255534fa1 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -315,3 +315,6 @@ darobs Zheng, Lei Carlo Marcelo Arenas Belón Scott Parker +Wade Brainerd +rayrase +Pekka Nikander diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 64b18695e16..595b3871278 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,55 @@ +2017.11.11, Version 1.16.1 (Stable), 4056fbe46493ef87237e307e0025e551db875e13 + +Changes since version 1.16.0: + +* unix: move net/if.h include (cjihrig) + +* win: fix undeclared NDIS_IF_MAX_STRING_SIZE (Nick Logan) + + +2017.11.07, Version 1.16.0 (Stable), d68779f0ea742918f653b9c20237460271c39aeb + +Changes since version 1.15.0: + +* win: change st_blksize from `2048` to `4096` (Joran Dirk Greef) + +* unix,win: add fs open flags, map O_DIRECT|O_DSYNC (Joran Dirk Greef) + +* win, fs: fix non-symlink reparse points (Wade Brainerd) + +* test: fix -Wstrict-prototypes warnings (Ben Noordhuis) + +* unix, windows: map ENOTTY errno (Ben Noordhuis) + +* unix: fall back to fsync() if F_FULLFSYNC fails (Joran Dirk Greef) + +* unix: do not close invalid kqueue fd after fork (jBarz) + +* zos: reset epoll data after fork (jBarz) + +* zos: skip fork_threadpool_queue_work_simple (jBarz) + +* test: keep platform_output as first test (Bartosz Sosnowski) + +* win: fix non-English dlopen error message (Bartosz Sosnowski) + +* unix,win: add uv_os_getppid() (cjihrig) + +* test: fix const qualification compiler warning (Ben Noordhuis) + +* doc: mark uv_default_loop() as not thread safe (rayrase) + +* win, pipe: null-initialize stream->shutdown_req (Jameson Nash) + +* tty, win: get SetWinEventHook pointer at startup (Bartosz Sosnowski) + +* test: no extra new line in skipped test output (Bartosz Sosnowski) + +* pipe: allow access from other users (Bartosz Sosnowski) + +* unix,win: add uv_if_{indextoname,indextoiid} (Pekka Nikander) + + 2017.10.03, Version 1.15.0 (Stable), 8b69ce1419d2958011d415a636810705c36c2cc2 Changes since version 1.14.1: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index b94fdd63b58..6e548a69c37 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -212,6 +212,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-pipe-server-close.c \ test/test-pipe-close-stdout-read-stdin.c \ test/test-pipe-set-non-blocking.c \ + test/test-pipe-set-fchmod.c \ test/test-platform-output.c \ test/test-poll.c \ test/test-poll-close.c \ diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml index f519bc099b6..8ad69718b6e 100644 --- a/deps/uv/appveyor.yml +++ b/deps/uv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.15.0.build{build} +version: v1.16.1.build{build} init: - git config --global core.autocrlf true diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index ebf5bc3d8ef..5fc0f72434d 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.15.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.16.1], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 2db915bc9e6..f46c4e761a5 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -353,3 +353,154 @@ Helper functions any attempts to close it or to use it after closing the fd may lead to malfunction. .. versionadded:: 1.12.0 + +File open constants +------------------- + +.. c:macro:: UV_FS_O_APPEND + + The file is opened in append mode. Before each write, the file offset is + positioned at the end of the file. + +.. c:macro:: UV_FS_O_CREAT + + The file is created if it does not already exist. + +.. c:macro:: UV_FS_O_DIRECT + + File I/O is done directly to and from user-space buffers, which must be + aligned. Buffer size and address should be a multiple of the physical sector + size of the block device. + + .. note:: + `UV_FS_O_DIRECT` is supported on Linux, and on Windows via + `FILE_FLAG_NO_BUFFERING `_. + `UV_FS_O_DIRECT` is not supported on macOS. + +.. c:macro:: UV_FS_O_DIRECTORY + + If the path is not a directory, fail the open. + + .. note:: + `UV_FS_O_DIRECTORY` is not supported on Windows. + +.. c:macro:: UV_FS_O_DSYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and a minimum of metadata are flushed to disk. + + .. note:: + `UV_FS_O_DSYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_EXCL + + If the `O_CREAT` flag is set and the file already exists, fail the open. + + .. note:: + In general, the behavior of `O_EXCL` is undefined if it is used without + `O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can + be used without `O_CREAT` if pathname refers to a block device. If the + block device is in use by the system (e.g., mounted), the open will fail + with the error `EBUSY`. + +.. c:macro:: UV_FS_O_EXLOCK + + Atomically obtain an exclusive lock. + + .. note:: + `UV_FS_O_EXLOCK` is only supported on macOS. + +.. c:macro:: UV_FS_O_NOATIME + + Do not update the file access time when the file is read. + + .. note:: + `UV_FS_O_NOATIME` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOCTTY + + If the path identifies a terminal device, opening the path will not cause + that terminal to become the controlling terminal for the process (if the + process does not already have one). + + .. note:: + `UV_FS_O_NOCTTY` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOFOLLOW + + If the path is a symbolic link, fail the open. + + .. note:: + `UV_FS_O_NOFOLLOW` is not supported on Windows. + +.. c:macro:: UV_FS_O_NONBLOCK + + Open the file in nonblocking mode if possible. + + .. note:: + `UV_FS_O_NONBLOCK` is not supported on Windows. + +.. c:macro:: UV_FS_O_RANDOM + + Access is intended to be random. The system can use this as a hint to + optimize file caching. + + .. note:: + `UV_FS_O_RANDOM` is only supported on Windows via + `FILE_FLAG_RANDOM_ACCESS `_. + +.. c:macro:: UV_FS_O_RDONLY + + Open the file for read-only access. + +.. c:macro:: UV_FS_O_RDWR + + Open the file for read-write access. + +.. c:macro:: UV_FS_O_SEQUENTIAL + + Access is intended to be sequential from beginning to end. The system can + use this as a hint to optimize file caching. + + .. note:: + `UV_FS_O_SEQUENTIAL` is only supported on Windows via + `FILE_FLAG_SEQUENTIAL_SCAN `_. + +.. c:macro:: UV_FS_O_SHORT_LIVED + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_SHORT_LIVED` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_SYMLINK + + Open the symbolic link itself rather than the resource it points to. + +.. c:macro:: UV_FS_O_SYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and all metadata are flushed to disk. + + .. note:: + `UV_FS_O_SYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_TEMPORARY + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_TEMPORARY` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_TRUNC + + If the file exists and is a regular file, and the file is opened + successfully for write access, its length shall be truncated to zero. + +.. c:macro:: UV_FS_O_WRONLY + + Open the file for write-only access. diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index 02543171de4..c63f813993f 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -86,6 +86,9 @@ API should) be closed with :c:func:`uv_loop_close` so the resources associated with it are freed. + .. warning:: + This function is not thread safe. + .. c:function:: int uv_run(uv_loop_t* loop, uv_run_mode mode) This function runs the event loop. It will act differently depending on the diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 3fea708a8d3..2968d1cea1c 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -59,6 +59,12 @@ Data types Abstract representation of a file descriptor. On Unix systems this is a `typedef` of `int` and on Windows a `HANDLE`. +.. c:type:: uv_pid_t + + Cross platform representation of a `pid_t`. + + .. versionadded:: 1.16.0 + .. c:type:: uv_rusage_t Data type for resource usage results. @@ -221,6 +227,12 @@ API On Windows not all fields are set, the unsupported fields are filled with zeroes. See :c:type:`uv_rusage_t` for more details. +.. c:function:: uv_pid_t uv_os_getppid(void) + + Returns the parent process ID. + + .. versionadded:: 1.16.0 + .. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) Gets information about the CPUs on the system. The `cpu_infos` array will @@ -271,6 +283,60 @@ API and :man:`inet_pton(3)`. On success they return 0. In case of error the target `dst` pointer is unmodified. +.. c:macro:: UV_IF_NAMESIZE + + Maximum IPv6 interface identifier name length. Defined as + `IFNAMSIZ` on Unix and `IF_NAMESIZE` on Linux and Windows. + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) + + IPv6-capable implementation of :man:`if_indextoname(3)`. When called, + `*size` indicates the length of the `buffer`, which is used to store the + result. + On success, zero is returned, `buffer` contains the interface name, and + `*size` represents the string length of the `buffer`, excluding the NUL + terminator byte from `*size`. On error, a negative result is + returned. If `buffer` is not large enough to hold the result, + `UV_ENOBUFS` is returned, and `*size` represents the necessary size in + bytes, including the NUL terminator byte into the `*size`. + + On Unix, the returned interface name can be used directly as an + interface identifier in scoped IPv6 addresses, e.g. + `fe80::abc:def1:2345%en0`. + + On Windows, the returned interface cannot be used as an interface + identifier, as Windows uses numerical interface identifiers, e.g. + `fe80::abc:def1:2345%5`. + + To get an interface identifier in a cross-platform compatible way, + use `uv_if_indextoiid()`. + + Example: + + :: + + char ifname[UV_IF_NAMESIZE]; + size_t size = sizeof(ifname); + uv_if_indextoname(sin6->sin6_scope_id, ifname, &size); + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) + + Retrieves a network interface identifier suitable for use in an IPv6 scoped + address. On Windows, returns the numeric `ifindex` as a string. On all other + platforms, `uv_if_indextoname()` is called. The result is written to + `buffer`, with `*size` indicating the length of `buffer`. If `buffer` is not + large enough to hold the result, then `UV_ENOBUFS` is returned, and `*size` + represents the size, including the NUL byte, required to hold the + result. + + See `uv_if_indextoname` for further details. + + .. versionadded:: 1.16.0 + .. c:function:: int uv_exepath(char* buffer, size_t* size) Gets the executable path. diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst index d33b0f2b977..bdaeeba9d43 100644 --- a/deps/uv/docs/src/pipe.rst +++ b/deps/uv/docs/src/pipe.rst @@ -102,3 +102,12 @@ API and call ``uv_accept(pipe, handle)``. .. seealso:: The :c:type:`uv_stream_t` API functions also apply. + +.. c:function:: int uv_pipe_chmod(uv_pipe_t* handle, int flags) + + Alters pipe permissions, allowing it to be accessed from processes run by + different users. Makes the pipe writable or readable by all users. Mode can + be ``UV_WRITABLE``, ``UV_READABLE`` or ``UV_WRITABLE | UV_READABLE``. This + function is blocking. + + .. versionadded:: 1.16.0 diff --git a/deps/uv/include/uv-errno.h b/deps/uv/include/uv-errno.h index 32bbc5177e4..8a415331479 100644 --- a/deps/uv/include/uv-errno.h +++ b/deps/uv/include/uv-errno.h @@ -422,4 +422,10 @@ # define UV__EREMOTEIO (-4030) #endif +#if defined(ENOTTY) && !defined(_WIN32) +# define UV__ENOTTY (-ENOTTY) +#else +# define UV__ENOTTY (-4029) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index d7754509b1e..6565ff441ef 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -123,6 +123,7 @@ typedef struct uv_buf_t { typedef int uv_file; typedef int uv_os_sock_t; typedef int uv_os_fd_t; +typedef pid_t uv_pid_t; #define UV_ONCE_INIT PTHREAD_ONCE_INIT @@ -365,4 +366,97 @@ typedef struct { uv_fs_event_cb cb; \ UV_PLATFORM_FS_EVENT_FIELDS \ +/* fs open() flags supported on this platform: */ +#if defined(O_APPEND) +# define UV_FS_O_APPEND O_APPEND +#else +# define UV_FS_O_APPEND 0 +#endif +#if defined(O_CREAT) +# define UV_FS_O_CREAT O_CREAT +#else +# define UV_FS_O_CREAT 0 +#endif +#if defined(O_DIRECT) +# define UV_FS_O_DIRECT O_DIRECT +#else +# define UV_FS_O_DIRECT 0 +#endif +#if defined(O_DIRECTORY) +# define UV_FS_O_DIRECTORY O_DIRECTORY +#else +# define UV_FS_O_DIRECTORY 0 +#endif +#if defined(O_DSYNC) +# define UV_FS_O_DSYNC O_DSYNC +#else +# define UV_FS_O_DSYNC 0 +#endif +#if defined(O_EXCL) +# define UV_FS_O_EXCL O_EXCL +#else +# define UV_FS_O_EXCL 0 +#endif +#if defined(O_EXLOCK) +# define UV_FS_O_EXLOCK O_EXLOCK +#else +# define UV_FS_O_EXLOCK 0 +#endif +#if defined(O_NOATIME) +# define UV_FS_O_NOATIME O_NOATIME +#else +# define UV_FS_O_NOATIME 0 +#endif +#if defined(O_NOCTTY) +# define UV_FS_O_NOCTTY O_NOCTTY +#else +# define UV_FS_O_NOCTTY 0 +#endif +#if defined(O_NOFOLLOW) +# define UV_FS_O_NOFOLLOW O_NOFOLLOW +#else +# define UV_FS_O_NOFOLLOW 0 +#endif +#if defined(O_NONBLOCK) +# define UV_FS_O_NONBLOCK O_NONBLOCK +#else +# define UV_FS_O_NONBLOCK 0 +#endif +#if defined(O_RDONLY) +# define UV_FS_O_RDONLY O_RDONLY +#else +# define UV_FS_O_RDONLY 0 +#endif +#if defined(O_RDWR) +# define UV_FS_O_RDWR O_RDWR +#else +# define UV_FS_O_RDWR 0 +#endif +#if defined(O_SYMLINK) +# define UV_FS_O_SYMLINK O_SYMLINK +#else +# define UV_FS_O_SYMLINK 0 +#endif +#if defined(O_SYNC) +# define UV_FS_O_SYNC O_SYNC +#else +# define UV_FS_O_SYNC 0 +#endif +#if defined(O_TRUNC) +# define UV_FS_O_TRUNC O_TRUNC +#else +# define UV_FS_O_TRUNC 0 +#endif +#if defined(O_WRONLY) +# define UV_FS_O_WRONLY O_WRONLY +#else +# define UV_FS_O_WRONLY 0 +#endif + +/* fs open() flags supported on other platforms: */ +#define UV_FS_O_RANDOM 0 +#define UV_FS_O_SHORT_LIVED 0 +#define UV_FS_O_SEQUENTIAL 0 +#define UV_FS_O_TEMPORARY 0 + #endif /* UV_UNIX_H */ diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 55d7c91055c..1c9113cdc9f 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 15 -#define UV_VERSION_PATCH 0 +#define UV_VERSION_MINOR 16 +#define UV_VERSION_PATCH 1 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 9677ff164b7..be150fc482f 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -222,6 +222,7 @@ typedef struct uv_buf_t { typedef int uv_file; typedef SOCKET uv_os_sock_t; typedef HANDLE uv_os_fd_t; +typedef int uv_pid_t; typedef HANDLE uv_thread_t; @@ -648,3 +649,28 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #ifndef X_OK #define X_OK 1 #endif + +/* fs open() flags supported on this platform: */ +#define UV_FS_O_APPEND _O_APPEND +#define UV_FS_O_CREAT _O_CREAT +#define UV_FS_O_EXCL _O_EXCL +#define UV_FS_O_RANDOM _O_RANDOM +#define UV_FS_O_RDONLY _O_RDONLY +#define UV_FS_O_RDWR _O_RDWR +#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL +#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED +#define UV_FS_O_TEMPORARY _O_TEMPORARY +#define UV_FS_O_TRUNC _O_TRUNC +#define UV_FS_O_WRONLY _O_WRONLY + +/* fs open() flags supported on other platforms (or mapped on this platform): */ +#define UV_FS_O_DIRECT 0x2000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECTORY 0 +#define UV_FS_O_DSYNC 0x4000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0 +#define UV_FS_O_NOATIME 0 +#define UV_FS_O_NOCTTY 0 +#define UV_FS_O_NOFOLLOW 0 +#define UV_FS_O_NONBLOCK 0 +#define UV_FS_O_SYMLINK 0 +#define UV_FS_O_SYNC 0x8000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 0e4151d1389..3f61812081d 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -141,6 +141,7 @@ extern "C" { XX(EMLINK, "too many links") \ XX(EHOSTDOWN, "host is down") \ XX(EREMOTEIO, "remote I/O error") \ + XX(ENOTTY, "inappropriate ioctl for device") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ @@ -709,6 +710,7 @@ UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle, UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); +UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags); struct uv_poll_s { @@ -1068,6 +1070,7 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); +UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); @@ -1405,6 +1408,21 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); +#if defined(IF_NAMESIZE) +# define UV_IF_NAMESIZE (IF_NAMESIZE + 1) +#elif defined(IFNAMSIZ) +# define UV_IF_NAMESIZE (IFNAMSIZ + 1) +#else +# define UV_IF_NAMESIZE (16 + 1) +#endif + +UV_EXTERN int uv_if_indextoname(unsigned int ifindex, + char* buffer, + size_t* size); +UV_EXTERN int uv_if_indextoiid(unsigned int ifindex, + char* buffer, + size_t* size); + UV_EXTERN int uv_exepath(char* buffer, size_t* size); UV_EXTERN int uv_cwd(char* buffer, size_t* size); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index ef82ee27b85..d64593a3134 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -1343,3 +1343,8 @@ int uv_os_gethostname(char* buffer, size_t* size) { uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } + + +uv_pid_t uv_os_getppid(void) { + return getppid(); +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 2684c814a2b..e0969a4c2f3 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -132,26 +132,33 @@ while (0) -static ssize_t uv__fs_fdatasync(uv_fs_t* req) { -#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) - return fdatasync(req->file); -#elif defined(__APPLE__) +static ssize_t uv__fs_fsync(uv_fs_t* req) { +#if defined(__APPLE__) /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache * to the drive platters. This is in contrast to Linux's fdatasync and fsync * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent - * for flushing buffered data to permanent storage. + * for flushing buffered data to permanent storage. If F_FULLFSYNC is not + * supported by the file system we should fall back to fsync(). This is the + * same approach taken by sqlite. */ - return fcntl(req->file, F_FULLFSYNC); + int r; + + r = fcntl(req->file, F_FULLFSYNC); + if (r != 0 && errno == ENOTTY) + r = fsync(req->file); + return r; #else return fsync(req->file); #endif } -static ssize_t uv__fs_fsync(uv_fs_t* req) { -#if defined(__APPLE__) - /* See the comment in uv__fs_fdatasync. */ - return fcntl(req->file, F_FULLFSYNC); +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) + /* See the comment in uv__fs_fsync. */ + return uv__fs_fsync(req); #else return fsync(req->file); #endif diff --git a/deps/uv/src/unix/getaddrinfo.c b/deps/uv/src/unix/getaddrinfo.c index 2049aea2f38..0185971697a 100644 --- a/deps/uv/src/unix/getaddrinfo.c +++ b/deps/uv/src/unix/getaddrinfo.c @@ -32,6 +32,7 @@ #include /* NULL */ #include #include +#include /* if_indextoname() */ /* EAI_* constants. */ #include @@ -200,3 +201,32 @@ void uv_freeaddrinfo(struct addrinfo* ai) { if (ai) freeaddrinfo(ai); } + + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + char ifname_buf[UV_IF_NAMESIZE]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (if_indextoname(ifindex, ifname_buf) == NULL) + return -errno; + + len = strnlen(ifname_buf, sizeof(ifname_buf)); + + if (*size <= len) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ifname_buf, len); + buffer[len] = '\0'; + *size = len; + + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + return uv_if_indextoname(ifindex, buffer, size); +} diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index c9adddbdb87..5e89bdced4e 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -65,7 +65,6 @@ static int uv__has_forked_with_cfrunloop; int uv__io_fork(uv_loop_t* loop) { int err; - uv__close(loop->backend_fd); loop->backend_fd = -1; err = uv__kqueue_init(loop); if (err) diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index bcd49242cea..5b5b0e095bb 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -31,7 +31,6 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - uv__signal_global_once_init(); saved_data = loop->data; memset(loop, 0, sizeof(*loop)); @@ -68,6 +67,7 @@ int uv_loop_init(uv_loop_t* loop) { if (err) return err; + uv__signal_global_once_init(); err = uv_signal_init(loop, &loop->child_watcher); if (err) goto fail_signal_init; diff --git a/deps/uv/src/unix/os390-syscalls.c b/deps/uv/src/unix/os390-syscalls.c index ca539c26f7b..86c6852b4b6 100644 --- a/deps/uv/src/unix/os390-syscalls.c +++ b/deps/uv/src/unix/os390-syscalls.c @@ -120,10 +120,41 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { } +static void before_fork(void) { + uv_mutex_lock(&global_epoll_lock); +} + + +static void after_fork(void) { + uv_mutex_unlock(&global_epoll_lock); +} + + +static void child_fork(void) { + QUEUE* q; + uv_once_t child_once = UV_ONCE_INIT; + + /* reset once */ + memcpy(&once, &child_once, sizeof(child_once)); + + /* reset epoll list */ + while (!QUEUE_EMPTY(&global_epoll_queue)) { + q = QUEUE_HEAD(&global_epoll_queue); + QUEUE_REMOVE(q); + } + + uv_mutex_unlock(&global_epoll_lock); + uv_mutex_destroy(&global_epoll_lock); +} + + static void epoll_init(void) { QUEUE_INIT(&global_epoll_queue); if (uv_mutex_init(&global_epoll_lock)) abort(); + + if (pthread_atfork(&before_fork, &after_fork, &child_fork)) + abort(); } diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 4a812955b0d..ac7cfb46a92 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -302,3 +302,56 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { else return uv__handle_type(handle->accepted_fd); } + + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + unsigned desired_mode; + struct stat pipe_stat; + char* name_buffer; + size_t name_len; + int r; + + if (handle == NULL || uv__stream_fd(handle) == -1) + return -EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return -EINVAL; + + if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) + return -errno; + + desired_mode = 0; + if (mode & UV_READABLE) + desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (mode & UV_WRITABLE) + desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + /* Exit early if pipe already has desired mode. */ + if ((pipe_stat.st_mode & desired_mode) == desired_mode) + return 0; + + pipe_stat.st_mode |= desired_mode; + + /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ + name_len = 0; + r = uv_pipe_getsockname(handle, NULL, &name_len); + if (r != UV_ENOBUFS) + return r; + + name_buffer = uv__malloc(name_len); + if (name_buffer == NULL) + return UV_ENOMEM; + + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) { + uv__free(name_buffer); + return r; + } + + r = chmod(name_buffer, pipe_stat.st_mode); + uv__free(name_buffer); + + return r != -1 ? 0 : -errno; +} diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index d454014d8ad..97ac1c1ad10 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -89,9 +89,9 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { - static const char not_win32_app_msg[] = "%1 is not a valid Win32 application"; DWORD_PTR arg; DWORD res; + char* msg; if (lib->errmsg) { LocalFree(lib->errmsg); @@ -114,16 +114,16 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { 0, (LPSTR) &lib->errmsg, 0, NULL); } - /* Inexpert hack to get the filename into the error message. */ - if (res && strstr(lib->errmsg, not_win32_app_msg)) { - LocalFree(lib->errmsg); + if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) { + msg = lib->errmsg; lib->errmsg = NULL; arg = (DWORD_PTR) filename; res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, - not_win32_app_msg, + msg, 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); + LocalFree(msg); } if (!res) diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index c374a82ca01..b90eaa75489 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -415,21 +415,21 @@ void fs__open(uv_fs_t* req) { umask(current_umask); /* convert flags and mode to CreateFile parameters */ - switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { - case _O_RDONLY: + switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { + case UV_FS_O_RDONLY: access = FILE_GENERIC_READ; break; - case _O_WRONLY: + case UV_FS_O_WRONLY: access = FILE_GENERIC_WRITE; break; - case _O_RDWR: + case UV_FS_O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; break; default: goto einval; } - if (flags & _O_APPEND) { + if (flags & UV_FS_O_APPEND) { access &= ~FILE_WRITE_DATA; access |= FILE_APPEND_DATA; } @@ -442,23 +442,23 @@ void fs__open(uv_fs_t* req) { */ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { case 0: - case _O_EXCL: + case UV_FS_O_EXCL: disposition = OPEN_EXISTING; break; - case _O_CREAT: + case UV_FS_O_CREAT: disposition = OPEN_ALWAYS; break; - case _O_CREAT | _O_EXCL: - case _O_CREAT | _O_TRUNC | _O_EXCL: + case UV_FS_O_CREAT | UV_FS_O_EXCL: + case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL: disposition = CREATE_NEW; break; - case _O_TRUNC: - case _O_TRUNC | _O_EXCL: + case UV_FS_O_TRUNC: + case UV_FS_O_TRUNC | UV_FS_O_EXCL: disposition = TRUNCATE_EXISTING; break; - case _O_CREAT | _O_TRUNC: + case UV_FS_O_CREAT | UV_FS_O_TRUNC: disposition = CREATE_ALWAYS; break; default: @@ -466,34 +466,49 @@ void fs__open(uv_fs_t* req) { } attributes |= FILE_ATTRIBUTE_NORMAL; - if (flags & _O_CREAT) { + if (flags & UV_FS_O_CREAT) { if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { attributes |= FILE_ATTRIBUTE_READONLY; } } - if (flags & _O_TEMPORARY ) { + if (flags & UV_FS_O_TEMPORARY ) { attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; access |= DELETE; } - if (flags & _O_SHORT_LIVED) { + if (flags & UV_FS_O_SHORT_LIVED) { attributes |= FILE_ATTRIBUTE_TEMPORARY; } - switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) { case 0: break; - case _O_SEQUENTIAL: + case UV_FS_O_SEQUENTIAL: attributes |= FILE_FLAG_SEQUENTIAL_SCAN; break; - case _O_RANDOM: + case UV_FS_O_RANDOM: attributes |= FILE_FLAG_RANDOM_ACCESS; break; default: goto einval; } + if (flags & UV_FS_O_DIRECT) { + attributes |= FILE_FLAG_NO_BUFFERING; + } + + switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) { + case 0: + break; + case UV_FS_O_DSYNC: + case UV_FS_O_SYNC: + attributes |= FILE_FLAG_WRITE_THROUGH; + break; + default: + goto einval; + } + /* Setting this flag makes it possible to open a directory. */ attributes |= FILE_FLAG_BACKUP_SEMANTICS; @@ -506,9 +521,9 @@ void fs__open(uv_fs_t* req) { NULL); if (file == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); - if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) && - !(flags & _O_EXCL)) { - /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */ + if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) && + !(flags & UV_FS_O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */ /* specified, it means the path referred to a directory. */ SET_REQ_UV_ERROR(req, UV_EISDIR, error); } else { @@ -1070,7 +1085,8 @@ void fs__scandir(uv_fs_t* req) { } -INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { +INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, + int do_lstat) { FILE_ALL_INFORMATION file_info; FILE_FS_VOLUME_INFORMATION volume_info; NTSTATUS nt_status; @@ -1125,17 +1141,25 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { */ statbuf->st_mode = 0; - if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* + * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism + * by which filesystem drivers can intercept and alter file system requests. + * + * The only reparse points we care about are symlinks and mount points, both + * of which are treated as POSIX symlinks. Further, we only care when + * invoked via lstat, which seeks information about the link instead of its + * target. Otherwise, reparse points must be treated as regular files. + */ + if (do_lstat && + (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { /* - * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have - * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets - * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode - * calculated below will indicate a normal directory or file, as if - * FILE_ATTRIBUTE_REPARSE_POINT was not present. + * If reading the link fails, the reparse point is not a symlink and needs + * to be treated as a regular file. The higher level lstat function will + * detect this failure and retry without do_lstat if appropriate. */ - if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { - statbuf->st_mode |= S_IFLNK; - } + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + return -1; + statbuf->st_mode |= S_IFLNK; } if (statbuf->st_mode == 0) { @@ -1178,8 +1202,12 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { * * Therefore we'll just report a sensible value that's quite commonly okay * on modern hardware. + * + * 4096 is the minimum required to be compatible with newer Advanced Format + * drives (which have 4096 bytes per physical sector), and to be backwards + * compatible with older drives (which have 512 bytes per physical sector). */ - statbuf->st_blksize = 2048; + statbuf->st_blksize = 4096; /* Todo: set st_flags to something meaningful. Also provide a wrapper for * chattr(2). @@ -1230,9 +1258,11 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { return; } - if (fs__stat_handle(handle, &req->statbuf) != 0) { + if (fs__stat_handle(handle, &req->statbuf, do_lstat) != 0) { DWORD error = GetLastError(); - if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) { + if (do_lstat && + (error == ERROR_SYMLINK_NOT_SUPPORTED || + error == ERROR_NOT_A_REPARSE_POINT)) { /* We opened a reparse point but it was not a symlink. Try again. */ fs__stat_impl(req, 0); @@ -1276,7 +1306,7 @@ static void fs__fstat(uv_fs_t* req) { return; } - if (fs__stat_handle(handle, &req->statbuf) != 0) { + if (fs__stat_handle(handle, &req->statbuf, 0) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); return; } diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index baab838898a..282d919cf75 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -28,6 +28,8 @@ /* EAI_* constants. */ #include +/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */ +#include int uv__getaddrinfo_translate_error(int sys_err) { switch (sys_err) { @@ -73,6 +75,9 @@ int uv__getaddrinfo_translate_error(int sys_err) { /* Do we need different versions of this for different architectures? */ #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) +#ifndef NDIS_IF_MAX_STRING_SIZE +#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE +#endif static void uv__getaddrinfo_work(struct uv__work* w) { uv_getaddrinfo_t* req; @@ -380,3 +385,69 @@ int uv_getaddrinfo(uv_loop_t* loop, } return uv_translate_sys_error(err); } + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + NET_LUID luid; + wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ + DWORD bufsize; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = ConvertInterfaceIndexToLuid(ifindex, &luid); + + if (r != 0) + return uv_translate_sys_error(r); + + r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); + + if (r != 0) + return uv_translate_sys_error(r); + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + wname, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = snprintf(buffer, *size, "%d", ifindex); + + if (r < 0) + return uv_translate_sys_error(r); + + if (r >= (int) *size) { + *size = r + 1; + return UV_ENOBUFS; + } + + *size = r; + return 0; +} diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 444327d647f..217fcdb5d76 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -326,7 +326,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); void uv__util_init(void); uint64_t uv__hrtime(double scale); -int uv_parent_pid(void); int uv_current_pid(void); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 5c666788fd6..642213bc888 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -31,6 +31,9 @@ #include "stream-inl.h" #include "req-inl.h" +#include +#include + typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; struct uv__ipc_queue_item_s { @@ -202,7 +205,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, uv_unique_pipe_name(ptr, name, nameSize); pipeHandle = CreateNamedPipeA(name, - access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, NULL); @@ -534,7 +537,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { */ handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | - FILE_FLAG_FIRST_PIPE_INSTANCE, + FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); @@ -803,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, assert(req->pipeHandle == INVALID_HANDLE_VALUE); req->pipeHandle = CreateNamedPipeW(handle->name, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); @@ -1969,7 +1972,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); - pipe->pipe.conn.ipc_pid = uv_parent_pid(); + pipe->pipe.conn.ipc_pid = uv_os_getppid(); assert(pipe->pipe.conn.ipc_pid != -1); } return 0; @@ -2132,3 +2135,80 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { else return UV_TCP; } + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY; + PACL old_dacl, new_dacl; + PSECURITY_DESCRIPTOR sd; + EXPLICIT_ACCESS ea; + PSID everyone; + int error; + + if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + if (!AllocateAndInitializeSid(&sid_world, + 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &everyone)) { + error = GetLastError(); + goto done; + } + + if (GetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &old_dacl, + NULL, + &sd)) { + error = GetLastError(); + goto clean_sid; + } + + memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); + if (mode & UV_READABLE) + ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + if (mode & UV_WRITABLE) + ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + ea.grfAccessPermissions |= SYNCHRONIZE; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea.Trustee.ptstrName = (LPTSTR)everyone; + + if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) { + error = GetLastError(); + goto clean_sd; + } + + if (SetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + new_dacl, + NULL)) { + error = GetLastError(); + goto clean_dacl; + } + + error = 0; + +clean_dacl: + LocalFree((HLOCAL) new_dacl); +clean_sd: + LocalFree((HLOCAL) sd); +clean_sid: + FreeSid(everyone); +done: + return uv_translate_sys_error(error); +} diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h index bf12148afe1..dba03747043 100644 --- a/deps/uv/src/win/stream-inl.h +++ b/deps/uv/src/win/stream-inl.h @@ -36,6 +36,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop, uv__handle_init(loop, (uv_handle_t*) handle, type); handle->write_queue_size = 0; handle->activecnt = 0; + handle->stream.conn.shutdown_req = NULL; } @@ -47,8 +48,6 @@ INLINE static void uv_connection_init(uv_stream_t* handle) { handle->read_req.event_handle = NULL; handle->read_req.wait_handle = INVALID_HANDLE_VALUE; handle->read_req.data = handle; - - handle->stream.conn.shutdown_req = NULL; } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index a2acda1152f..2aec9f8dfe3 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -331,7 +331,7 @@ uint64_t uv_get_total_memory(void) { } -int uv_parent_pid(void) { +uv_pid_t uv_os_getppid(void) { int parent_pid = -1; HANDLE handle; PROCESSENTRY32 pe; diff --git a/deps/uv/test/benchmark-pump.c b/deps/uv/test/benchmark-pump.c index 88f2dc5c658..8685258e052 100644 --- a/deps/uv/test/benchmark-pump.c +++ b/deps/uv/test/benchmark-pump.c @@ -36,9 +36,9 @@ static int TARGET_CONNECTIONS; static void do_write(uv_stream_t*); -static void maybe_connect_some(); +static void maybe_connect_some(void); -static uv_req_t* req_alloc(); +static uv_req_t* req_alloc(void); static void req_free(uv_req_t* uv_req); static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf); diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index 5e44118775e..f017902a04f 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -81,6 +81,7 @@ int run_tests(int benchmark_output) { int skipped; int current; int test_result; + int skip; task_entry_t* task; /* Count the number of tests. */ @@ -92,7 +93,9 @@ int run_tests(int benchmark_output) { } } - qsort(TASKS, actual, sizeof(TASKS[0]), compare_task); + /* Keep platform_output first. */ + skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output")); + qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task); fprintf(stderr, "1..%d\n", total); fflush(stderr); @@ -127,6 +130,7 @@ void log_tap_result(int test_count, const char* result; const char* directive; char reason[1024]; + int reason_length; switch (status) { case TEST_OK: @@ -144,6 +148,9 @@ void log_tap_result(int test_count, if (status == TEST_SKIP && process_output_size(process) > 0) { process_read_last_line(process, reason, sizeof reason); + reason_length = strlen(reason); + if (reason_length > 0 && reason[reason_length - 1] == '\n') + reason[reason_length - 1] = '\0'; } else { reason[0] = '\0'; } diff --git a/deps/uv/test/test-fork.c b/deps/uv/test/test-fork.c index 3716a3ad975..ba85b531064 100644 --- a/deps/uv/test/test-fork.c +++ b/deps/uv/test/test-fork.c @@ -636,6 +636,7 @@ static void assert_run_work(uv_loop_t* const loop) { } +#ifndef __MVS__ TEST_IMPL(fork_threadpool_queue_work_simple) { /* The threadpool works in a child process. */ @@ -672,6 +673,7 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { MAKE_VALGRIND_HAPPY(); return 0; } +#endif /* !__MVS__ */ #endif /* !_WIN32 */ diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 0000e563a73..6afa650793e 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -115,6 +115,17 @@ static char test_buf[] = "test-buffer\n"; static char test_buf2[] = "second-buffer\n"; static uv_buf_t iov; +#ifdef _WIN32 +/* + * This tag and guid have no special meaning, and don't conflict with + * reserved ids. +*/ +static unsigned REPARSE_TAG = 0x9913; +static GUID REPARSE_GUID = { + 0x1bf6205f, 0x46ae, 0x4527, + 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }; +#endif + static void check_permission(const char* filename, unsigned int mode) { int r; uv_fs_t req; @@ -1991,6 +2002,109 @@ TEST_IMPL(fs_symlink_dir) { } +#ifdef _WIN32 +TEST_IMPL(fs_non_symlink_reparse_point) { + uv_fs_t req; + int r; + HANDLE file_handle; + REPARSE_GUID_DATA_BUFFER reparse_buffer; + DWORD bytes_returned; + uv_dirent_t dent; + + /* set-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + + file_handle = CreateFile("test_dir/test_file", + GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + ASSERT(file_handle != INVALID_HANDLE_VALUE); + + memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); + reparse_buffer.ReparseTag = REPARSE_TAG; + reparse_buffer.ReparseDataLength = 0; + reparse_buffer.ReparseGuid = REPARSE_GUID; + + r = DeviceIoControl(file_handle, + FSCTL_SET_REPARSE_POINT, + &reparse_buffer, + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, + NULL, + 0, + &bytes_returned, + NULL); + ASSERT(r != 0); + + CloseHandle(file_handle); + + r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED); + uv_fs_req_cleanup(&req); + +/* + Placeholder tests for exercising the behavior fixed in issue #995. + To run, update the path with the IP address of a Mac with the hard drive + shared via SMB as "Macintosh HD". + + r = uv_fs_stat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + +/* + uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse + points when a minifilter driver is registered which intercepts + associated filesystem requests. Installing a driver is beyond + the scope of this test. + + r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + + r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); + ASSERT(r == 1); + ASSERT(scandir_req.result == 1); + ASSERT(scandir_req.ptr); + while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { + ASSERT(strcmp(dent.name, "test_file") == 0); + /* uv_fs_scandir incorrectly identifies non-symlink reparse points + as links because it doesn't open the file and verify the reparse + point tag. The PowerShell Get-ChildItem command shares this + behavior, so it's reasonable to leave it as is. */ + ASSERT(dent.type == UV_DIRENT_LINK); + } + uv_fs_req_cleanup(&scandir_req); + ASSERT(!scandir_req.ptr); + + /* clean-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(fs_utime) { utime_check_t checkme; const char* path = "test_file"; diff --git a/deps/uv/test/test-ip6-addr.c b/deps/uv/test/test-ip6-addr.c index 156fccde39d..25570dcacde 100644 --- a/deps/uv/test/test-ip6-addr.c +++ b/deps/uv/test/test-ip6-addr.c @@ -44,8 +44,12 @@ TEST_IMPL(ip6_addr_link_local) { const char* device_name; /* 40 bytes address, 16 bytes device name, plus reserve. */ char scoped_addr[128]; + size_t scoped_addr_len; + char interface_id[UV_IF_NAMESIZE]; + size_t interface_id_len; int count; int ix; + int r; ASSERT(0 == uv_interface_addresses(&addresses, &count)); @@ -67,19 +71,29 @@ TEST_IMPL(ip6_addr_link_local) { iface_index = address->address.address6.sin6_scope_id; device_name = address->name; + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 == uv_if_indextoname(iface_index, scoped_addr, &scoped_addr_len)); +#ifndef _WIN32 + /* This assert fails on Windows, as Windows semantics are different. */ + ASSERT(0 == strcmp(device_name, scoped_addr)); +#endif + + interface_id_len = sizeof(interface_id); + r = uv_if_indextoiid(iface_index, interface_id, &interface_id_len); + ASSERT(0 == r); #ifdef _WIN32 - snprintf(scoped_addr, - sizeof(scoped_addr), - "%s%%%d", - string_address, - iface_index); + /* On Windows, the interface identifier is the numeric string of the index. */ + ASSERT(strtol(interface_id, NULL, 10) == iface_index); #else + /* On Unix/Linux, the interface identifier is the interface device name. */ + ASSERT(0 == strcmp(device_name, interface_id)); +#endif + snprintf(scoped_addr, sizeof(scoped_addr), "%s%%%s", string_address, - device_name); -#endif + interface_id); fprintf(stderr, "Testing link-local address %s " "(iface_index: 0x%02x, device_name: %s)\n", @@ -96,6 +110,9 @@ TEST_IMPL(ip6_addr_link_local) { uv_free_interface_addresses(addresses, count); + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr, &scoped_addr_len)); + MAKE_VALGRIND_HAPPY(); return 0; } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 0dde57c2ed2..3e88e6c928d 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -204,6 +204,7 @@ TEST_DECLARE (pipe_ref4) TEST_DECLARE (pipe_close_stdout_read_stdin) #endif TEST_DECLARE (pipe_set_non_blocking) +TEST_DECLARE (pipe_set_chmod) TEST_DECLARE (process_ref) TEST_DECLARE (has_ref) TEST_DECLARE (active) @@ -282,6 +283,9 @@ TEST_DECLARE (fs_readlink) TEST_DECLARE (fs_realpath) TEST_DECLARE (fs_symlink) TEST_DECLARE (fs_symlink_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_non_symlink_reparse_point) +#endif TEST_DECLARE (fs_utime) TEST_DECLARE (fs_futime) TEST_DECLARE (fs_file_open_append) @@ -398,8 +402,10 @@ TEST_DECLARE (fork_signal_to_child_closed) TEST_DECLARE (fork_fs_events_child) TEST_DECLARE (fork_fs_events_child_dir) TEST_DECLARE (fork_fs_events_file_parent_child) +#ifndef __MVS__ TEST_DECLARE (fork_threadpool_queue_work_simple) #endif +#endif TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) @@ -438,6 +444,7 @@ TASK_LIST_START TEST_ENTRY (pipe_close_stdout_read_stdin) #endif TEST_ENTRY (pipe_set_non_blocking) + TEST_ENTRY (pipe_set_chmod) TEST_ENTRY (tty) #ifdef _WIN32 TEST_ENTRY (tty_raw) @@ -790,6 +797,9 @@ TASK_LIST_START TEST_ENTRY (fs_realpath) TEST_ENTRY (fs_symlink) TEST_ENTRY (fs_symlink_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_non_symlink_reparse_point) +#endif TEST_ENTRY (fs_stat_missing_path) TEST_ENTRY (fs_read_file_eof) TEST_ENTRY (fs_file_open_append) @@ -861,8 +871,10 @@ TASK_LIST_START TEST_ENTRY (fork_fs_events_child) TEST_ENTRY (fork_fs_events_child_dir) TEST_ENTRY (fork_fs_events_file_parent_child) +#ifndef __MVS__ TEST_ENTRY (fork_threadpool_queue_work_simple) #endif +#endif #if 0 /* These are for testing the test runner. */ diff --git a/deps/uv/test/test-pipe-set-fchmod.c b/deps/uv/test/test-pipe-set-fchmod.c new file mode 100644 index 00000000000..59f0e6f5454 --- /dev/null +++ b/deps/uv/test/test-pipe-set-fchmod.c @@ -0,0 +1,66 @@ +/* Copyright libuv project contributors. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to +* deal in the Software without restriction, including without limitation the +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +* IN THE SOFTWARE. +*/ + + +#include "uv.h" +#include "task.h" + +TEST_IMPL(pipe_set_chmod) { + uv_pipe_t pipe_handle; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_pipe_init(loop, &pipe_handle, 0); + ASSERT(r == 0); + + r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); + ASSERT(r == 0); + + /* No easy way to test if this works, we will only make sure that */ + /* the call is successful. */ + r = uv_pipe_chmod(&pipe_handle, UV_READABLE); + if (r == UV_EPERM) { + MAKE_VALGRIND_HAPPY(); + RETURN_SKIP("Insufficient privileges to alter pipe fmode"); + } + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + r = uv_pipe_chmod(&pipe_handle, 12345678); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&pipe_handle, NULL); + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 72c176edc45..50ed59a6d23 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -29,6 +29,7 @@ TEST_IMPL(platform_output) { size_t rss; size_t size; double uptime; + uv_pid_t ppid; uv_rusage_t rusage; uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; @@ -144,5 +145,9 @@ TEST_IMPL(platform_output) { printf(" shell: %s\n", pwd.shell); printf(" home directory: %s\n", pwd.homedir); + ppid = uv_os_getppid(); + ASSERT(ppid > 0); + printf("uv_os_getppid: %d\n", (int) ppid); + return 0; } diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 91d831e19b9..d3958fe216f 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1721,9 +1721,9 @@ TEST_IMPL(spawn_quoted_path) { RETURN_SKIP("Test for Windows"); #else char* quoted_path_env[2]; - options.file = "not_existing"; - args[0] = options.file; + args[0] = "not_existing"; args[1] = NULL; + options.file = args[0]; options.args = args; options.exit_cb = exit_cb; options.flags = 0; diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 38765eefd12..9d9bb4b735a 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -393,6 +393,7 @@ 'test/test-pipe-server-close.c', 'test/test-pipe-close-stdout-read-stdin.c', 'test/test-pipe-set-non-blocking.c', + 'test/test-pipe-set-fchmod.c', 'test/test-platform-output.c', 'test/test-poll.c', 'test/test-poll-close.c', diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index adfb3305268..b8170f1e440 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -737,6 +737,16 @@ Type: Runtime internal mechanics of the `REPLServer` itself, and is therefore not necessary in user space. + +### DEP0083: Disabling ECDH by setting ecdhCurve to false + +Type: Runtime + +The `ecdhCurve` option to `tls.createSecureContext()` and `tls.TLSSocket` could +be set to `false` to disable ECDH entirely on the server only. This mode is +deprecated in preparation for migrating to OpenSSL 1.1.0 and consistency with +the client. Use the `ciphers` parameter instead. + [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size [`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 910289b37f9..4e57142888b 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -455,7 +455,7 @@ On IPv4, if `multicastInterface` is a valid address but does not match any interface, or if the address does not match the family then a [`System Error`][] such as `EADDRNOTAVAIL` or `EPROTONOSUP` is thrown. -On IPv6, most errors with specifying or omiting scope will result in the socket +On IPv6, most errors with specifying or omitting scope will result in the socket continuing to use (or returning to) the system's default interface selection. A socket's address family's ANY address (IPv4 `'0.0.0.0'` or IPv6 `'::'`) can be diff --git a/doc/api/http2.md b/doc/api/http2.md index 33f7caa97b2..1efbad29bec 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -1808,7 +1808,7 @@ All additional properties on the settings object are ignored. ### Using `options.selectPadding` When `options.paddingStrategy` is equal to -`http2.constants.PADDING_STRATEGY_CALLBACK`, the the HTTP/2 implementation will +`http2.constants.PADDING_STRATEGY_CALLBACK`, the HTTP/2 implementation will consult the `options.selectPadding` callback function, if provided, to determine the specific amount of padding to use per HEADERS and DATA frame. diff --git a/doc/api/n-api.md b/doc/api/n-api.md index d4452377c35..f877b6e6d63 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -1788,7 +1788,7 @@ This API returns the C int32 primitive equivalent of the given JavaScript Number. If the number exceeds the range of the 32 bit integer, then the result is truncated to the equivalent of the bottom 32 bits. This can result in a large positive number becoming -a negative number if the the value is > 2^31 -1. +a negative number if the value is > 2^31 -1. #### *napi_get_value_int64* + +* {integer} + +The `process.ppid` property returns the PID of the current parent process. + +```js +console.log(`The parent process is pid ${process.ppid}`); +``` + ## process.release -Returns an object representing the cipher name and the SSL/TLS protocol version -that first defined the cipher. +Returns an object representing the cipher name. The `version` key is a legacy +field which always contains the value `'TLSv1/SSLv3'`. For example: `{ name: 'AES256-SHA', version: 'TLSv1/SSLv3' }` -See `SSL_CIPHER_get_name()` and `SSL_CIPHER_get_version()` in +See `SSL_CIPHER_get_name()` in https://www.openssl.org/docs/man1.0.2/ssl/SSL_CIPHER_get_name.html for more information. diff --git a/lib/_http_agent.js b/lib/_http_agent.js index b0e011d40c4..5f1e56caeab 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -127,10 +127,10 @@ Agent.prototype.getName = function getName(options) { // Pacify parallel/test-http-agent-getname by only appending // the ':' when options.family is set. if (options.family === 4 || options.family === 6) - name += ':' + options.family; + name += `:${options.family}`; if (options.socketPath) - name += ':' + options.socketPath; + name += `:${options.socketPath}`; return name; }; diff --git a/lib/_http_common.js b/lib/_http_common.js index a1fe29217f5..4c8d3c3850b 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -78,7 +78,7 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, parser.incoming = new IncomingMessage(parser.socket); parser.incoming.httpVersionMajor = versionMajor; parser.incoming.httpVersionMinor = versionMinor; - parser.incoming.httpVersion = versionMajor + '.' + versionMinor; + parser.incoming.httpVersion = `${versionMajor}.${versionMinor}`; parser.incoming.url = url; var n = headers.length; diff --git a/lib/_http_server.js b/lib/_http_server.js index 04161ac024b..8fe9e58dff5 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -176,7 +176,7 @@ ServerResponse.prototype.detachSocket = function detachSocket(socket) { }; ServerResponse.prototype.writeContinue = function writeContinue(cb) { - this._writeRaw('HTTP/1.1 100 Continue' + CRLF + CRLF, 'ascii', cb); + this._writeRaw(`HTTP/1.1 100 Continue${CRLF}${CRLF}`, 'ascii', cb); this._sent100 = true; }; @@ -230,7 +230,7 @@ function writeHead(statusCode, reason, obj) { if (checkInvalidHeaderChar(this.statusMessage)) throw new errors.Error('ERR_INVALID_CHAR', 'statusMessage'); - var statusLine = 'HTTP/1.1 ' + statusCode + ' ' + this.statusMessage + CRLF; + var statusLine = `HTTP/1.1 ${statusCode} ${this.statusMessage}${CRLF}`; if (statusCode === 204 || statusCode === 304 || (statusCode >= 100 && statusCode <= 199)) { @@ -456,7 +456,7 @@ function onParserExecute(server, socket, parser, state, ret, d) { } const badRequestResponse = Buffer.from( - 'HTTP/1.1 400 ' + STATUS_CODES[400] + CRLF + CRLF, 'ascii' + `HTTP/1.1 400 ${STATUS_CODES[400]}${CRLF}${CRLF}`, 'ascii' ); function socketOnError(e) { // Ignore further errors diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 4196cc084c8..75eb6a2ec53 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -65,6 +65,16 @@ function validateKeyCert(value, type) { exports.SecureContext = SecureContext; +function ecdhCurveWarning() { + if (ecdhCurveWarning.emitted) return; + process.emitWarning('{ ecdhCurve: false } is deprecated.', + 'DeprecationWarning', + 'DEP0083'); + ecdhCurveWarning.emitted = true; +} +ecdhCurveWarning.emitted = false; + + exports.createSecureContext = function createSecureContext(options, context) { if (!options) options = {}; @@ -140,6 +150,8 @@ exports.createSecureContext = function createSecureContext(options, context) { c.context.setECDHCurve(tls.DEFAULT_ECDH_CURVE); else if (options.ecdhCurve) c.context.setECDHCurve(options.ecdhCurve); + else + ecdhCurveWarning(); if (options.dhparam) { const warning = c.context.setDHParam(options.dhparam); diff --git a/lib/child_process.js b/lib/child_process.js index a0bd01b16bd..b951caee10c 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -266,7 +266,7 @@ exports.execFile = function(file /*, args, options, callback*/) { } if (args.length !== 0) - cmd += ' ' + args.join(' '); + cmd += ` ${args.join(' ')}`; if (!ex) { ex = new Error('Command failed: ' + cmd + '\n' + stderr); @@ -475,7 +475,7 @@ function normalizeSpawnArguments(file, args, options) { var envPairs = []; for (var key in env) { - envPairs.push(key + '=' + env[key]); + envPairs.push(`${key}=${env[key]}`); } _convertCustomFds(options); @@ -570,7 +570,7 @@ function checkExecSyncError(ret, args, cmd) { var msg = 'Command failed: '; msg += cmd || args.join(' '); if (ret.stderr && ret.stderr.length > 0) - msg += '\n' + ret.stderr.toString(); + msg += `\n${ret.stderr.toString()}`; err = new Error(msg); } if (err) { diff --git a/lib/dns.js b/lib/dns.js index 4a2672c2544..ca4a02d2ef0 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -51,7 +51,7 @@ function errnoException(err, syscall, hostname) { } var ex = null; if (typeof err === 'string') { // c-ares error code. - const errHost = hostname ? ' ' + hostname : ''; + const errHost = hostname ? ` ${hostname}` : ''; ex = new Error(`${syscall} ${err}${errHost}`); ex.code = err; ex.errno = err; diff --git a/lib/internal/v8_prof_polyfill.js b/lib/internal/v8_prof_polyfill.js index 1bfa111d8d8..5c6b1407120 100644 --- a/lib/internal/v8_prof_polyfill.js +++ b/lib/internal/v8_prof_polyfill.js @@ -79,7 +79,7 @@ var line = ''; function peekline() { const s = readline(); - line = s + '\n' + line; + line = `${s}\n${line}`; return s; } diff --git a/node.gyp b/node.gyp index 5b5d9283646..59cff560d5f 100644 --- a/node.gyp +++ b/node.gyp @@ -335,6 +335,11 @@ 'NODE_OPENSSL_SYSTEM_CERT_PATH="<(openssl_system_ca_path)"', ], }, + 'conditions': [ + [ 'node_shared=="true" and node_module_version!="" and OS!="win"', { + 'product_extension': '<(shlib_suffix)', + }] + ], }, { 'target_name': 'mkssldef', diff --git a/node.gypi b/node.gypi index 24dbadad7b7..12321f1626b 100644 --- a/node.gypi +++ b/node.gypi @@ -11,11 +11,6 @@ 'defines': [ 'NODE_SHARED_MODE', ], - 'conditions': [ - [ 'node_module_version!="" and OS!="win"', { - 'product_extension': '<(shlib_suffix)', - }] - ], }], [ 'node_enable_d8=="true"', { 'dependencies': [ 'deps/v8/src/d8.gyp:d8' ], diff --git a/src/node.cc b/src/node.cc index 8788996762d..a325570971c 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2939,6 +2939,12 @@ static void EnvEnumerator(const PropertyCallbackInfo& info) { } +static void GetParentProcessId(Local property, + const PropertyCallbackInfo& info) { + info.GetReturnValue().Set(Integer::New(info.GetIsolate(), uv_os_getppid())); +} + + static Local GetFeatures(Environment* env) { EscapableHandleScope scope(env->isolate()); @@ -3276,6 +3282,9 @@ void SetupProcessObject(Environment* env, READONLY_PROPERTY(process, "pid", Integer::New(env->isolate(), getpid())); READONLY_PROPERTY(process, "features", GetFeatures(env)); + process->SetAccessor(FIXED_ONE_BYTE_STRING(env->isolate(), "ppid"), + GetParentProcessId); + auto need_immediate_callback_string = FIXED_ONE_BYTE_STRING(env->isolate(), "_needImmediateCallback"); CHECK(process->SetAccessor(env->context(), need_immediate_callback_string, diff --git a/src/node_constants.cc b/src/node_constants.cc index ba33d65d1dc..d478d434000 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -759,6 +759,10 @@ void DefineSignalConstants(Local target) { } void DefineOpenSSLConstants(Local target) { +#ifdef OPENSSL_VERSION_NUMBER + NODE_DEFINE_CONSTANT(target, OPENSSL_VERSION_NUMBER); +#endif + #ifdef SSL_OP_ALL NODE_DEFINE_CONSTANT(target, SSL_OP_ALL); #endif diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 0332daf68e6..afdd69bd6a3 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -106,6 +106,118 @@ using v8::String; using v8::Value; +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, + const BIGNUM** d) { + if (n != nullptr) { + *n = r->n; + } + if (e != nullptr) { + *e = r->e; + } + if (d != nullptr) { + *d = r->d; + } +} + +static void DH_get0_pqg(const DH* dh, const BIGNUM** p, const BIGNUM** q, + const BIGNUM** g) { + if (p != nullptr) { + *p = dh->p; + } + if (q != nullptr) { + *q = dh->q; + } + if (g != nullptr) { + *g = dh->g; + } +} + +static int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) { + if ((dh->p == nullptr && p == nullptr) || + (dh->g == nullptr && g == nullptr)) { + return 0; + } + + if (p != nullptr) { + BN_free(dh->p); + dh->p = p; + } + if (q != nullptr) { + BN_free(dh->q); + dh->q = q; + } + if (g != nullptr) { + BN_free(dh->g); + dh->g = g; + } + + return 1; +} + +static void DH_get0_key(const DH* dh, const BIGNUM** pub_key, + const BIGNUM** priv_key) { + if (pub_key != nullptr) { + *pub_key = dh->pub_key; + } + if (priv_key != nullptr) { + *priv_key = dh->priv_key; + } +} + +static int DH_set0_key(DH* dh, BIGNUM* pub_key, BIGNUM* priv_key) { + if (pub_key != nullptr) { + BN_free(dh->pub_key); + dh->pub_key = pub_key; + } + if (priv_key != nullptr) { + BN_free(dh->priv_key); + dh->priv_key = priv_key; + } + + return 1; +} + +static const SSL_METHOD* TLS_method() { return SSLv23_method(); } + +static void SSL_SESSION_get0_ticket(const SSL_SESSION* s, + const unsigned char** tick, size_t* len) { + *len = s->tlsext_ticklen; + if (tick != nullptr) { + *tick = s->tlsext_tick; + } +} + +#define SSL_get_tlsext_status_type(ssl) (ssl->tlsext_status_type) + +static int X509_STORE_up_ref(X509_STORE* store) { + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); + return 1; +} + +static int X509_up_ref(X509* cert) { + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); + return 1; +} + +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy + +HMAC_CTX* HMAC_CTX_new() { + HMAC_CTX* ctx = Malloc(1); + HMAC_CTX_init(ctx); + return ctx; +} + +void HMAC_CTX_free(HMAC_CTX* ctx) { + if (ctx == nullptr) { + return; + } + HMAC_CTX_cleanup(ctx); + free(ctx); +} +#endif // OPENSSL_VERSION_NUMBER < 0x10100000L + // Subject DER of CNNIC ROOT CA and CNNIC EV ROOT CA are taken from // https://hg.mozilla.org/mozilla-central/file/98820360ab66/security/ // certverifier/NSSCertDBTrustDomain.cpp#l672 @@ -134,8 +246,6 @@ static X509_NAME *cnnic_ev_name = d2i_X509_NAME(nullptr, &cnnic_ev_p, sizeof(CNNIC_EV_ROOT_CA_SUBJECT_DATA)-1); -static Mutex* mutexes; - static const char* const root_certs[] = { #include "node_root_certs.h" // NOLINT(build/include_order) }; @@ -152,11 +262,19 @@ template void SSLWrap::AddMethods(Environment* env, template void SSLWrap::InitNPN(SecureContext* sc); template void SSLWrap::SetSNIContext(SecureContext* sc); template int SSLWrap::SetCACerts(SecureContext* sc); +#if OPENSSL_VERSION_NUMBER < 0x10100000L template SSL_SESSION* SSLWrap::GetSessionCallback( SSL* s, unsigned char* key, int len, int* copy); +#else +template SSL_SESSION* SSLWrap::GetSessionCallback( + SSL* s, + const unsigned char* key, + int len, + int* copy); +#endif template int SSLWrap::NewSessionCallback(SSL* s, SSL_SESSION* sess); template void SSLWrap::OnClientHello( @@ -196,6 +314,9 @@ template int SSLWrap::SelectALPNCallback( void* arg); #endif // TLSEXT_TYPE_application_layer_protocol_negotiation +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static Mutex* mutexes; + static void crypto_threadid_cb(CRYPTO_THREADID* tid) { static_assert(sizeof(uv_thread_t) <= sizeof(void*), "uv_thread_t does not fit in a pointer"); @@ -218,6 +339,7 @@ static void crypto_lock_cb(int mode, int n, const char* file, int line) { else mutex->Unlock(); } +#endif static int PasswordCallback(char *buf, int size, int rwflag, void *u) { @@ -421,12 +543,12 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); Environment* env = sc->env(); - const SSL_METHOD* method = SSLv23_method(); + const SSL_METHOD* method = TLS_method(); if (args.Length() == 1 && args[0]->IsString()) { const node::Utf8Value sslmethod(env->isolate(), args[0]); - // Note that SSLv2 and SSLv3 are disallowed but SSLv2_method and friends + // Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends // are still accepted. They are OpenSSL's way of saying that all known // protocols are supported unless explicitly disabled (which we do below // for SSLv2 and SSLv3.) @@ -474,7 +596,7 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { sc->ctx_ = SSL_CTX_new(method); SSL_CTX_set_app_data(sc->ctx_, sc); - // Disable SSLv2 in the case when method == SSLv23_method() and the + // Disable SSLv2 in the case when method == TLS_method() and the // cipher list contains SSLv2 ciphers (not the default, should be rare.) // The bundled OpenSSL doesn't have SSLv2 support but the system OpenSSL may. // SSLv3 is disabled because it's susceptible to downgrade attacks (POODLE.) @@ -488,6 +610,19 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { SSL_SESS_CACHE_NO_AUTO_CLEAR); SSL_CTX_sess_set_get_cb(sc->ctx_, SSLWrap::GetSessionCallback); SSL_CTX_sess_set_new_cb(sc->ctx_, SSLWrap::NewSessionCallback); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + // OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was + // exposed in the public API. To retain compatibility, install a callback + // which restores the old algorithm. + if (RAND_bytes(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) <= 0 || + RAND_bytes(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) <= 0 || + RAND_bytes(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)) <= 0) { + return env->ThrowError("Error generating ticket keys"); + } + SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_, + SecureContext::TicketCompatibilityCallback); +#endif } @@ -565,19 +700,12 @@ void SecureContext::SetKey(const FunctionCallbackInfo& args) { int SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) { - int ret; - X509_STORE* store = SSL_CTX_get_cert_store(ctx); - X509_STORE_CTX store_ctx; - - ret = X509_STORE_CTX_init(&store_ctx, store, nullptr, nullptr); - if (!ret) - goto end; - - ret = X509_STORE_CTX_get1_issuer(issuer, &store_ctx, cert); - X509_STORE_CTX_cleanup(&store_ctx); - - end: + X509_STORE_CTX* store_ctx = X509_STORE_CTX_new(); + int ret = store_ctx != nullptr && + X509_STORE_CTX_init(store_ctx, store, nullptr, nullptr) == 1 && + X509_STORE_CTX_get1_issuer(issuer, store_ctx, cert) == 1; + X509_STORE_CTX_free(store_ctx); return ret; } @@ -668,7 +796,6 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, x = PEM_read_bio_X509_AUX(in, nullptr, NoPasswordCallback, nullptr); if (x == nullptr) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); return 0; } @@ -679,7 +806,6 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, // Read extra certs STACK_OF(X509)* extra_certs = sk_X509_new_null(); if (extra_certs == nullptr) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_MALLOC_FAILURE); goto done; } @@ -762,22 +888,6 @@ void SecureContext::SetCert(const FunctionCallbackInfo& args) { } -#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) -// This section contains OpenSSL 1.1.0 functions reimplemented for OpenSSL -// 1.0.2 so that the following code can be written without lots of #if lines. - -static int X509_STORE_up_ref(X509_STORE* store) { - CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); - return 1; -} - -static int X509_up_ref(X509* cert) { - CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); - return 1; -} -#endif // OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL - - static X509_STORE* NewRootCertStore() { static std::vector root_certs_vector; if (root_certs_vector.empty()) { @@ -970,8 +1080,10 @@ void SecureContext::SetECDHCurve(const FunctionCallbackInfo& args) { node::Utf8Value curve(env->isolate(), args[0]); +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_ecdh_auto(sc->ctx_, 1); +#endif if (strcmp(*curve, "auto") == 0) return; @@ -1003,7 +1115,9 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo& args) { if (dh == nullptr) return; - const int size = BN_num_bits(dh->p); + const BIGNUM* p; + DH_get0_pqg(dh, &p, nullptr, nullptr); + const int size = BN_num_bits(p); if (size < 1024) { return env->ThrowError("DH parameter is less than 1024 bits"); } else if (size < 2048) { @@ -1188,11 +1302,17 @@ void SecureContext::GetTicketKeys(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); Local buff = Buffer::New(wrap->env(), 48).ToLocalChecked(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + memcpy(Buffer::Data(buff), wrap->ticket_key_name_, 16); + memcpy(Buffer::Data(buff) + 16, wrap->ticket_key_hmac_, 16); + memcpy(Buffer::Data(buff) + 32, wrap->ticket_key_aes_, 16); +#else if (SSL_CTX_get_tlsext_ticket_keys(wrap->ctx_, Buffer::Data(buff), Buffer::Length(buff)) != 1) { return wrap->env()->ThrowError("Failed to fetch tls ticket keys"); } +#endif args.GetReturnValue().Set(buff); #endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) @@ -1215,11 +1335,17 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo& args) { return env->ThrowTypeError("Ticket keys length must be 48 bytes"); } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + memcpy(wrap->ticket_key_name_, Buffer::Data(args[0]), 16); + memcpy(wrap->ticket_key_hmac_, Buffer::Data(args[0]) + 16, 16); + memcpy(wrap->ticket_key_aes_, Buffer::Data(args[0]) + 32, 16); +#else if (SSL_CTX_set_tlsext_ticket_keys(wrap->ctx_, Buffer::Data(args[0]), Buffer::Length(args[0])) != 1) { return env->ThrowError("Failed to fetch tls ticket keys"); } +#endif args.GetReturnValue().Set(true); #endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) @@ -1227,7 +1353,7 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo& args) { void SecureContext::SetFreeListLength(const FunctionCallbackInfo& args) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) +#if OPENSSL_VERSION_NUMBER < 0x10100000L // |freelist_max_len| was removed in OpenSSL 1.1.0. In that version OpenSSL // mallocs and frees buffers directly, without the use of a freelist. SecureContext* wrap; @@ -1330,6 +1456,42 @@ int SecureContext::TicketKeyCallback(SSL* ssl, } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +int SecureContext::TicketCompatibilityCallback(SSL* ssl, + unsigned char* name, + unsigned char* iv, + EVP_CIPHER_CTX* ectx, + HMAC_CTX* hctx, + int enc) { + SecureContext* sc = static_cast( + SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); + + if (enc) { + memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)); + if (RAND_bytes(iv, 16) <= 0 || + EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, + sc->ticket_key_aes_, iv) <= 0 || + HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), + EVP_sha256(), nullptr) <= 0) { + return -1; + } + return 1; + } + + if (memcmp(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) != 0) { + // The ticket key name does not match. Discard the ticket. + return 0; + } + + if (EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_, + iv) <= 0 || + HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), + EVP_sha256(), nullptr) <= 0) { + return -1; + } + return 1; +} +#endif void SecureContext::CtxGetter(Local property, @@ -1434,11 +1596,19 @@ void SSLWrap::InitNPN(SecureContext* sc) { } +#if OPENSSL_VERSION_NUMBER < 0x10100000L template SSL_SESSION* SSLWrap::GetSessionCallback(SSL* s, unsigned char* key, int len, int* copy) { +#else +template +SSL_SESSION* SSLWrap::GetSessionCallback(SSL* s, + const unsigned char* key, + int len, + int* copy) { +#endif Base* w = static_cast(SSL_get_app_data(s)); *copy = 0; @@ -1615,14 +1785,17 @@ static Local X509ToObject(Environment* env, X509* cert) { rsa = EVP_PKEY_get1_RSA(pkey); if (rsa != nullptr) { - BN_print(bio, rsa->n); + const BIGNUM* n; + const BIGNUM* e; + RSA_get0_key(rsa, &n, &e, nullptr); + BN_print(bio, n); BIO_get_mem_ptr(bio, &mem); info->Set(env->modulus_string(), String::NewFromUtf8(env->isolate(), mem->data, String::kNormalString, mem->length)); (void) BIO_reset(bio); - uint64_t exponent_word = static_cast(BN_get_word(rsa->e)); + uint64_t exponent_word = static_cast(BN_get_word(e)); uint32_t lo = static_cast(exponent_word); uint32_t hi = static_cast(exponent_word >> 32); if (hi == 0) { @@ -1948,13 +2121,18 @@ void SSLWrap::GetTLSTicket(const FunctionCallbackInfo& args) { Environment* env = w->ssl_env(); SSL_SESSION* sess = SSL_get_session(w->ssl_); - if (sess == nullptr || sess->tlsext_tick == nullptr) + if (sess == nullptr) + return; + + const unsigned char *ticket; + size_t length; + SSL_SESSION_get0_ticket(sess, &ticket, &length); + + if (ticket == nullptr) return; Local buff = Buffer::Copy( - env, - reinterpret_cast(sess->tlsext_tick), - sess->tlsext_ticklen).ToLocalChecked(); + env, reinterpret_cast(ticket), length).ToLocalChecked(); args.GetReturnValue().Set(buff); } @@ -2145,9 +2323,8 @@ void SSLWrap::GetCurrentCipher(const FunctionCallbackInfo& args) { Local info = Object::New(env->isolate()); const char* cipher_name = SSL_CIPHER_get_name(c); info->Set(env->name_string(), OneByteString(args.GetIsolate(), cipher_name)); - const char* cipher_version = SSL_CIPHER_get_version(c); info->Set(env->version_string(), - OneByteString(args.GetIsolate(), cipher_version)); + OneByteString(args.GetIsolate(), "TLSv1/SSLv3")); args.GetReturnValue().Set(info); } @@ -2327,20 +2504,12 @@ int SSLWrap::SelectALPNCallback(SSL* s, unsigned alpn_protos_len = Buffer::Length(alpn_buffer); int status = SSL_select_next_proto(const_cast(out), outlen, alpn_protos, alpn_protos_len, in, inlen); - - switch (status) { - case OPENSSL_NPN_NO_OVERLAP: - // According to 3.2. Protocol Selection of RFC7301, - // fatal no_application_protocol alert shall be sent - // but current openssl does not support it yet. See - // https://rt.openssl.org/Ticket/Display.html?id=3463&user=guest&pass=guest - // Instead, we send a warning alert for now. - return SSL_TLSEXT_ERR_ALERT_WARNING; - case OPENSSL_NPN_NEGOTIATED: - return SSL_TLSEXT_ERR_OK; - default: - return SSL_TLSEXT_ERR_ALERT_FATAL; - } + // According to 3.2. Protocol Selection of RFC7301, fatal + // no_application_protocol alert shall be sent but OpenSSL 1.0.2 does not + // support it yet. See + // https://rt.openssl.org/Ticket/Display.html?id=3463&user=guest&pass=guest + return status == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK + : SSL_TLSEXT_ERR_NOACK; } #endif // TLSEXT_TYPE_application_layer_protocol_negotiation @@ -2481,7 +2650,7 @@ int SSLWrap::SSLCertCallback(SSL* s, void* arg) { bool ocsp = false; #ifdef NODE__HAVE_TLSEXT_STATUS_CB - ocsp = s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp; + ocsp = SSL_get_tlsext_status_type(s) == TLSEXT_STATUSTYPE_ocsp; #endif info->Set(env->ocsp_request_string(), Boolean::New(env->isolate(), ocsp)); @@ -3358,7 +3527,7 @@ void CipherBase::Init(const char* cipher_type, } #endif // NODE_FIPS_MODE - CHECK_EQ(initialised_, false); + CHECK_EQ(ctx_, nullptr); const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type); if (cipher == nullptr) { return env()->ThrowError("Unknown cipher"); @@ -3376,11 +3545,11 @@ void CipherBase::Init(const char* cipher_type, key, iv); - EVP_CIPHER_CTX_init(&ctx_); + ctx_ = EVP_CIPHER_CTX_new(); const bool encrypt = (kind_ == kCipher); - EVP_CipherInit_ex(&ctx_, cipher, nullptr, nullptr, nullptr, encrypt); + EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt); - int mode = EVP_CIPHER_CTX_mode(&ctx_); + int mode = EVP_CIPHER_CTX_mode(ctx_); if (encrypt && (mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_GCM_MODE || mode == EVP_CIPH_CCM_MODE)) { ProcessEmitWarning(env(), "Use Cipheriv for counter mode of %s", @@ -3388,17 +3557,16 @@ void CipherBase::Init(const char* cipher_type, } if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + EVP_CIPHER_CTX_set_flags(ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); - CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)); + CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(ctx_, key_len)); - EVP_CipherInit_ex(&ctx_, + EVP_CipherInit_ex(ctx_, nullptr, nullptr, reinterpret_cast(key), reinterpret_cast(iv), kind_ == kCipher); - initialised_ = true; } @@ -3435,32 +3603,33 @@ void CipherBase::InitIv(const char* cipher_type, return env()->ThrowError("Invalid IV length"); } - EVP_CIPHER_CTX_init(&ctx_); + ctx_ = EVP_CIPHER_CTX_new(); if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + EVP_CIPHER_CTX_set_flags(ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); const bool encrypt = (kind_ == kCipher); - EVP_CipherInit_ex(&ctx_, cipher, nullptr, nullptr, nullptr, encrypt); + EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt); if (is_gcm_mode && - !EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) { - EVP_CIPHER_CTX_cleanup(&ctx_); + !EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; return env()->ThrowError("Invalid IV length"); } - if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) { - EVP_CIPHER_CTX_cleanup(&ctx_); + if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; return env()->ThrowError("Invalid key length"); } - EVP_CipherInit_ex(&ctx_, + EVP_CipherInit_ex(ctx_, nullptr, nullptr, reinterpret_cast(key), reinterpret_cast(iv), kind_ == kCipher); - initialised_ = true; } @@ -3482,8 +3651,8 @@ void CipherBase::InitIv(const FunctionCallbackInfo& args) { bool CipherBase::IsAuthenticatedMode() const { // Check if this cipher operates in an AEAD mode that we support. - CHECK_EQ(initialised_, true); - const EVP_CIPHER* const cipher = EVP_CIPHER_CTX_cipher(&ctx_); + CHECK_NE(ctx_, nullptr); + const EVP_CIPHER* const cipher = EVP_CIPHER_CTX_cipher(ctx_); int mode = EVP_CIPHER_mode(cipher); return mode == EVP_CIPH_GCM_MODE; } @@ -3495,7 +3664,7 @@ void CipherBase::GetAuthTag(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder()); // Only callable after Final and if encrypting. - if (cipher->initialised_ || + if (cipher->ctx_ != nullptr || cipher->kind_ != kCipher || cipher->auth_tag_len_ == 0) { return args.GetReturnValue().SetUndefined(); @@ -3512,7 +3681,7 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { CipherBase* cipher; ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder()); - if (!cipher->initialised_ || + if (cipher->ctx_ == nullptr || !cipher->IsAuthenticatedMode() || cipher->kind_ != kDecipher) { return args.GetReturnValue().Set(false); @@ -3530,10 +3699,10 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { bool CipherBase::SetAAD(const char* data, unsigned int len) { - if (!initialised_ || !IsAuthenticatedMode()) + if (ctx_ == nullptr || !IsAuthenticatedMode()) return false; int outlen; - if (!EVP_CipherUpdate(&ctx_, + if (!EVP_CipherUpdate(ctx_, nullptr, &outlen, reinterpret_cast(data), @@ -3557,21 +3726,21 @@ bool CipherBase::Update(const char* data, int len, unsigned char** out, int* out_len) { - if (!initialised_) + if (ctx_ == nullptr) return 0; // on first update: if (kind_ == kDecipher && IsAuthenticatedMode() && auth_tag_len_ > 0) { - EVP_CIPHER_CTX_ctrl(&ctx_, + EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_TAG, auth_tag_len_, reinterpret_cast(auth_tag_)); auth_tag_len_ = 0; } - *out_len = len + EVP_CIPHER_CTX_block_size(&ctx_); + *out_len = len + EVP_CIPHER_CTX_block_size(ctx_); *out = Malloc(static_cast(*out_len)); - return EVP_CipherUpdate(&ctx_, + return EVP_CipherUpdate(ctx_, *out, out_len, reinterpret_cast(data), @@ -3617,9 +3786,9 @@ void CipherBase::Update(const FunctionCallbackInfo& args) { bool CipherBase::SetAutoPadding(bool auto_padding) { - if (!initialised_) + if (ctx_ == nullptr) return false; - return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding); + return EVP_CIPHER_CTX_set_padding(ctx_, auto_padding); } @@ -3633,22 +3802,22 @@ void CipherBase::SetAutoPadding(const FunctionCallbackInfo& args) { bool CipherBase::Final(unsigned char** out, int *out_len) { - if (!initialised_) + if (ctx_ == nullptr) return false; *out = Malloc( - static_cast(EVP_CIPHER_CTX_block_size(&ctx_))); - int r = EVP_CipherFinal_ex(&ctx_, *out, out_len); + static_cast(EVP_CIPHER_CTX_block_size(ctx_))); + int r = EVP_CipherFinal_ex(ctx_, *out, out_len); if (r == 1 && kind_ == kCipher && IsAuthenticatedMode()) { auth_tag_len_ = sizeof(auth_tag_); - r = EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_, + r = EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_, reinterpret_cast(auth_tag_)); CHECK_EQ(r, 1); } - EVP_CIPHER_CTX_cleanup(&ctx_); - initialised_ = false; + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; return r == 1; } @@ -3659,7 +3828,7 @@ void CipherBase::Final(const FunctionCallbackInfo& args) { CipherBase* cipher; ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder()); - if (!cipher->initialised_) return env->ThrowError("Unsupported state"); + if (cipher->ctx_ == nullptr) return env->ThrowError("Unsupported state"); unsigned char* out_value = nullptr; int out_len = -1; @@ -3691,6 +3860,11 @@ void CipherBase::Final(const FunctionCallbackInfo& args) { } +Hmac::~Hmac() { + HMAC_CTX_free(ctx_); +} + + void Hmac::Initialize(Environment* env, v8::Local target) { Local t = env->NewFunctionTemplate(New); @@ -3717,14 +3891,16 @@ void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) { if (md == nullptr) { return env()->ThrowError("Unknown message digest"); } - HMAC_CTX_init(&ctx_); if (key_len == 0) { key = ""; } - if (!HMAC_Init_ex(&ctx_, key, key_len, md, nullptr)) { + ctx_ = HMAC_CTX_new(); + if (ctx_ == nullptr || + !HMAC_Init_ex(ctx_, key, key_len, md, nullptr)) { + HMAC_CTX_free(ctx_); + ctx_ = nullptr; return ThrowCryptoError(env(), ERR_get_error()); } - initialised_ = true; } @@ -3741,9 +3917,9 @@ void Hmac::HmacInit(const FunctionCallbackInfo& args) { bool Hmac::HmacUpdate(const char* data, int len) { - if (!initialised_) + if (ctx_ == nullptr) return false; - int r = HMAC_Update(&ctx_, reinterpret_cast(data), len); + int r = HMAC_Update(ctx_, reinterpret_cast(data), len); return r == 1; } @@ -3788,10 +3964,10 @@ void Hmac::HmacDigest(const FunctionCallbackInfo& args) { unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len = 0; - if (hmac->initialised_) { - HMAC_Final(&hmac->ctx_, md_value, &md_len); - HMAC_CTX_cleanup(&hmac->ctx_); - hmac->initialised_ = false; + if (hmac->ctx_ != nullptr) { + HMAC_Final(hmac->ctx_, md_value, &md_len); + HMAC_CTX_free(hmac->ctx_); + hmac->ctx_ = nullptr; } Local error; @@ -3810,6 +3986,11 @@ void Hmac::HmacDigest(const FunctionCallbackInfo& args) { } +Hash::~Hash() { + EVP_MD_CTX_free(mdctx_); +} + + void Hash::Initialize(Environment* env, v8::Local target) { Local t = env->NewFunctionTemplate(New); @@ -3839,20 +4020,22 @@ bool Hash::HashInit(const char* hash_type) { const EVP_MD* md = EVP_get_digestbyname(hash_type); if (md == nullptr) return false; - EVP_MD_CTX_init(&mdctx_); - if (EVP_DigestInit_ex(&mdctx_, md, nullptr) <= 0) { + mdctx_ = EVP_MD_CTX_new(); + if (mdctx_ == nullptr || + EVP_DigestInit_ex(mdctx_, md, nullptr) <= 0) { + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; return false; } - initialised_ = true; finalized_ = false; return true; } bool Hash::HashUpdate(const char* data, int len) { - if (!initialised_) + if (mdctx_ == nullptr) return false; - EVP_DigestUpdate(&mdctx_, data, len); + EVP_DigestUpdate(mdctx_, data, len); return true; } @@ -3896,8 +4079,7 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len; - EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len); - EVP_MD_CTX_cleanup(&hash->mdctx_); + EVP_DigestFinal_ex(hash->mdctx_, md_value, &md_len); hash->finalized_ = true; Local error; @@ -3916,6 +4098,46 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { } +SignBase::~SignBase() { + EVP_MD_CTX_free(mdctx_); +} + + +SignBase::Error SignBase::Init(const char* sign_type) { + CHECK_EQ(mdctx_, nullptr); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + // Historically, "dss1" and "DSS1" were DSA aliases for SHA-1 + // exposed through the public API. + if (strcmp(sign_type, "dss1") == 0 || + strcmp(sign_type, "DSS1") == 0) { + sign_type = "SHA1"; + } +#endif + const EVP_MD* md = EVP_get_digestbyname(sign_type); + if (md == nullptr) + return kSignUnknownDigest; + + mdctx_ = EVP_MD_CTX_new(); + if (mdctx_ == nullptr || + !EVP_DigestInit_ex(mdctx_, md, nullptr)) { + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; + return kSignInit; + } + + return kSignOk; +} + + +SignBase::Error SignBase::Update(const char* data, int len) { + if (mdctx_ == nullptr) + return kSignNotInitialised; + if (!EVP_DigestUpdate(mdctx_, data, len)) + return kSignUpdate; + return kSignOk; +} + + void SignBase::CheckThrow(SignBase::Error error) { HandleScope scope(env()->isolate()); @@ -3989,36 +4211,12 @@ void Sign::New(const FunctionCallbackInfo& args) { } -SignBase::Error Sign::SignInit(const char* sign_type) { - CHECK_EQ(initialised_, false); - const EVP_MD* md = EVP_get_digestbyname(sign_type); - if (md == nullptr) - return kSignUnknownDigest; - - EVP_MD_CTX_init(&mdctx_); - if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) - return kSignInit; - initialised_ = true; - - return kSignOk; -} - - void Sign::SignInit(const FunctionCallbackInfo& args) { Sign* sign; ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder()); const node::Utf8Value sign_type(args.GetIsolate(), args[0]); - sign->CheckThrow(sign->SignInit(*sign_type)); -} - - -SignBase::Error Sign::SignUpdate(const char* data, int len) { - if (!initialised_) - return kSignNotInitialised; - if (!EVP_DigestUpdate(&mdctx_, data, len)) - return kSignUpdate; - return kSignOk; + sign->CheckThrow(sign->Init(*sign_type)); } @@ -4029,7 +4227,7 @@ void Sign::SignUpdate(const FunctionCallbackInfo& args) { Error err; char* buf = Buffer::Data(args[0]); size_t buflen = Buffer::Length(args[0]); - err = sign->SignUpdate(buf, buflen); + err = sign->Update(buf, buflen); sign->CheckThrow(err); } @@ -4072,7 +4270,7 @@ SignBase::Error Sign::SignFinal(const char* key_pem, unsigned int* sig_len, int padding, int salt_len) { - if (!initialised_) + if (!mdctx_) return kSignNotInitialised; BIO* bp = nullptr; @@ -4117,18 +4315,17 @@ SignBase::Error Sign::SignFinal(const char* key_pem, } #endif // NODE_FIPS_MODE - if (Node_SignFinal(&mdctx_, sig, sig_len, pkey, padding, salt_len)) + if (Node_SignFinal(mdctx_, sig, sig_len, pkey, padding, salt_len)) fatal = false; - initialised_ = false; - exit: if (pkey != nullptr) EVP_PKEY_free(pkey); if (bp != nullptr) BIO_free_all(bp); - EVP_MD_CTX_cleanup(&mdctx_); + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; if (fatal) return kSignPrivateKey; @@ -4202,38 +4399,12 @@ void Verify::New(const FunctionCallbackInfo& args) { } -SignBase::Error Verify::VerifyInit(const char* verify_type) { - CHECK_EQ(initialised_, false); - const EVP_MD* md = EVP_get_digestbyname(verify_type); - if (md == nullptr) - return kSignUnknownDigest; - - EVP_MD_CTX_init(&mdctx_); - if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) - return kSignInit; - initialised_ = true; - - return kSignOk; -} - - void Verify::VerifyInit(const FunctionCallbackInfo& args) { Verify* verify; ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder()); const node::Utf8Value verify_type(args.GetIsolate(), args[0]); - verify->CheckThrow(verify->VerifyInit(*verify_type)); -} - - -SignBase::Error Verify::VerifyUpdate(const char* data, int len) { - if (!initialised_) - return kSignNotInitialised; - - if (!EVP_DigestUpdate(&mdctx_, data, len)) - return kSignUpdate; - - return kSignOk; + verify->CheckThrow(verify->Init(*verify_type)); } @@ -4244,7 +4415,7 @@ void Verify::VerifyUpdate(const FunctionCallbackInfo& args) { Error err; char* buf = Buffer::Data(args[0]); size_t buflen = Buffer::Length(args[0]); - err = verify->VerifyUpdate(buf, buflen); + err = verify->Update(buf, buflen); verify->CheckThrow(err); } @@ -4257,7 +4428,7 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, int padding, int saltlen, bool* verify_result) { - if (!initialised_) + if (!mdctx_) return kSignNotInitialised; EVP_PKEY* pkey = nullptr; @@ -4302,7 +4473,7 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, goto exit; } - if (!EVP_DigestFinal_ex(&mdctx_, m, &m_len)) { + if (!EVP_DigestFinal_ex(mdctx_, m, &m_len)) { goto exit; } @@ -4315,7 +4486,7 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, goto err; if (!ApplyRSAOptions(pkey, pkctx, padding, saltlen)) goto err; - if (EVP_PKEY_CTX_set_signature_md(pkctx, mdctx_.digest) <= 0) + if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_md(mdctx_)) <= 0) goto err; r = EVP_PKEY_verify(pkctx, reinterpret_cast(sig), @@ -4334,8 +4505,8 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, if (x509 != nullptr) X509_free(x509); - EVP_MD_CTX_cleanup(&mdctx_); - initialised_ = false; + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; if (fatal) return kSignPublicKey; @@ -4584,10 +4755,15 @@ bool DiffieHellman::Init(int primeLength, int g) { bool DiffieHellman::Init(const char* p, int p_len, int g) { dh = DH_new(); - dh->p = BN_bin2bn(reinterpret_cast(p), p_len, 0); - dh->g = BN_new(); - if (!BN_set_word(dh->g, g)) + BIGNUM* bn_p = + BN_bin2bn(reinterpret_cast(p), p_len, nullptr); + BIGNUM* bn_g = BN_new(); + if (!BN_set_word(bn_g, g) || + !DH_set0_pqg(dh, bn_p, nullptr, bn_g)) { + BN_free(bn_p); + BN_free(bn_g); return false; + } bool result = VerifyContext(); if (!result) return false; @@ -4598,8 +4774,13 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) { bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) { dh = DH_new(); - dh->p = BN_bin2bn(reinterpret_cast(p), p_len, 0); - dh->g = BN_bin2bn(reinterpret_cast(g), g_len, 0); + BIGNUM *bn_p = BN_bin2bn(reinterpret_cast(p), p_len, 0); + BIGNUM *bn_g = BN_bin2bn(reinterpret_cast(g), g_len, 0); + if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) { + BN_free(bn_p); + BN_free(bn_g); + return false; + } bool result = VerifyContext(); if (!result) return false; @@ -4687,22 +4868,25 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo& args) { return ThrowCryptoError(env, ERR_get_error(), "Key generation failed"); } - size_t size = BN_num_bytes(diffieHellman->dh->pub_key); + const BIGNUM* pub_key; + DH_get0_key(diffieHellman->dh, &pub_key, nullptr); + size_t size = BN_num_bytes(pub_key); char* data = Malloc(size); - BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast(data)); + BN_bn2bin(pub_key, reinterpret_cast(data)); args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked()); } void DiffieHellman::GetField(const FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* err_if_null) { + const BIGNUM* (*get_field)(const DH*), + const char* err_if_null) { Environment* env = Environment::GetCurrent(args); DiffieHellman* dh; ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder()); if (!dh->initialised_) return env->ThrowError("Not initialized"); - const BIGNUM* num = (dh->dh)->*field; + const BIGNUM* num = get_field(dh->dh); if (num == nullptr) return env->ThrowError(err_if_null); size_t size = BN_num_bytes(num); @@ -4712,24 +4896,38 @@ void DiffieHellman::GetField(const FunctionCallbackInfo& args, } void DiffieHellman::GetPrime(const FunctionCallbackInfo& args) { - GetField(args, &DH::p, "p is null"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* p; + DH_get0_pqg(dh, &p, nullptr, nullptr); + return p; + }, "p is null"); } void DiffieHellman::GetGenerator(const FunctionCallbackInfo& args) { - GetField(args, &DH::g, "g is null"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* g; + DH_get0_pqg(dh, nullptr, nullptr, &g); + return g; + }, "g is null"); } void DiffieHellman::GetPublicKey(const FunctionCallbackInfo& args) { - GetField(args, &DH::pub_key, - "No public key - did you forget to generate one?"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* pub_key; + DH_get0_key(dh, &pub_key, nullptr); + return pub_key; + }, "No public key - did you forget to generate one?"); } void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo& args) { - GetField(args, &DH::priv_key, - "No private key - did you forget to generate one?"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* priv_key; + DH_get0_key(dh, nullptr, &priv_key); + return priv_key; + }, "No private key - did you forget to generate one?"); } @@ -4805,16 +5003,14 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(rc); } - void DiffieHellman::SetKey(const v8::FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* what) { + void (*set_field)(DH*, BIGNUM*), const char* what) { Environment* env = Environment::GetCurrent(args); DiffieHellman* dh; ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder()); if (!dh->initialised_) return env->ThrowError("Not initialized"); - BIGNUM** num = &((dh->dh)->*field); char errmsg[64]; if (args.Length() == 0) { @@ -4827,19 +5023,28 @@ void DiffieHellman::SetKey(const v8::FunctionCallbackInfo& args, return env->ThrowTypeError(errmsg); } - *num = BN_bin2bn(reinterpret_cast(Buffer::Data(args[0])), - Buffer::Length(args[0]), *num); - CHECK_NE(*num, nullptr); + BIGNUM* num = + BN_bin2bn(reinterpret_cast(Buffer::Data(args[0])), + Buffer::Length(args[0]), nullptr); + CHECK_NE(num, nullptr); + set_field(dh->dh, num); } void DiffieHellman::SetPublicKey(const FunctionCallbackInfo& args) { - SetKey(args, &DH::pub_key, "Public key"); + SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); }, + "Public key"); } - void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo& args) { - SetKey(args, &DH::priv_key, "Private key"); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + OPENSSL_VERSION_NUMBER < 0x10100070L +// Older versions of OpenSSL 1.1.0 have a DH_set0_key which does not work for +// Node. See https://github.com/openssl/openssl/pull/4384. +#error "OpenSSL 1.1.0 revisions before 1.1.0g are not supported" +#endif + SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, nullptr, num); }, + "Private key"); } @@ -5583,7 +5788,7 @@ void RandomBytesBuffer(const FunctionCallbackInfo& args) { void GetSSLCiphers(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - SSL_CTX* ctx = SSL_CTX_new(TLSv1_server_method()); + SSL_CTX* ctx = SSL_CTX_new(TLS_method()); CHECK_NE(ctx, nullptr); SSL* ssl = SSL_new(ctx); @@ -5848,9 +6053,11 @@ void InitCryptoOnce() { SSL_library_init(); OpenSSL_add_all_algorithms(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L crypto_lock_init(); CRYPTO_set_locking_callback(crypto_lock_cb); CRYPTO_THREADID_set_callback(crypto_threadid_cb); +#endif #ifdef NODE_FIPS_MODE /* Override FIPS settings in cnf file, if needed. */ diff --git a/src/node_crypto.h b/src/node_crypto.h index a155411aa81..c3bc5d24c36 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -51,8 +51,6 @@ #include #include -#define EVP_F_EVP_DECRYPTFINAL 101 - #if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) # define NODE__HAVE_TLSEXT_STATUS_CB #endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) @@ -105,8 +103,20 @@ class SecureContext : public BaseObject { static const int kTicketKeyNameIndex = 3; static const int kTicketKeyIVIndex = 4; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + unsigned char ticket_key_name_[16]; + unsigned char ticket_key_aes_[16]; + unsigned char ticket_key_hmac_[16]; +#endif + protected: +#if OPENSSL_VERSION_NUMBER < 0x10100000L static const int64_t kExternalSize = sizeof(SSL_CTX); +#else + // OpenSSL 1.1.0 has opaque structures. This is an estimate based on the size + // as of OpenSSL 1.1.0f. + static const int64_t kExternalSize = 872; +#endif static void New(const v8::FunctionCallbackInfo& args); static void Init(const v8::FunctionCallbackInfo& args); @@ -144,6 +154,15 @@ class SecureContext : public BaseObject { HMAC_CTX* hctx, int enc); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + static int TicketCompatibilityCallback(SSL* ssl, + unsigned char* name, + unsigned char* iv, + EVP_CIPHER_CTX* ectx, + HMAC_CTX* hctx, + int enc); +#endif + SecureContext(Environment* env, v8::Local wrap) : BaseObject(env, wrap), ctx_(nullptr), @@ -220,19 +239,32 @@ class SSLWrap { protected: typedef void (*CertCb)(void* arg); +#if OPENSSL_VERSION_NUMBER < 0x10100000L // Size allocated by OpenSSL: one for SSL structure, one for SSL3_STATE and // some for buffers. // NOTE: Actually it is much more than this static const int64_t kExternalSize = sizeof(SSL) + sizeof(SSL3_STATE) + 42 * 1024; +#else + // OpenSSL 1.1.0 has opaque structures. This is an estimate based on the size + // as of OpenSSL 1.1.0f. + static const int64_t kExternalSize = 4448 + 1024 + 42 * 1024; +#endif static void InitNPN(SecureContext* sc); static void AddMethods(Environment* env, v8::Local t); +#if OPENSSL_VERSION_NUMBER < 0x10100000L static SSL_SESSION* GetSessionCallback(SSL* s, unsigned char* key, int len, int* copy); +#else + static SSL_SESSION* GetSessionCallback(SSL* s, + const unsigned char* key, + int len, + int* copy); +#endif static int NewSessionCallback(SSL* s, SSL_SESSION* sess); static void OnClientHello(void* arg, const ClientHelloParser::ClientHello& hello); @@ -423,9 +455,7 @@ class Connection : public AsyncWrap, public SSLWrap { class CipherBase : public BaseObject { public: ~CipherBase() override { - if (!initialised_) - return; - EVP_CIPHER_CTX_cleanup(&ctx_); + EVP_CIPHER_CTX_free(ctx_); } static void Initialize(Environment* env, v8::Local target); @@ -464,15 +494,14 @@ class CipherBase : public BaseObject { v8::Local wrap, CipherKind kind) : BaseObject(env, wrap), - initialised_(false), + ctx_(nullptr), kind_(kind), auth_tag_len_(0) { MakeWeak(this); } private: - EVP_CIPHER_CTX ctx_; /* coverity[member_decl] */ - bool initialised_; + EVP_CIPHER_CTX* ctx_; const CipherKind kind_; unsigned int auth_tag_len_; char auth_tag_[EVP_GCM_TLS_TAG_LEN]; @@ -480,11 +509,7 @@ class CipherBase : public BaseObject { class Hmac : public BaseObject { public: - ~Hmac() override { - if (!initialised_) - return; - HMAC_CTX_cleanup(&ctx_); - } + ~Hmac() override; static void Initialize(Environment* env, v8::Local target); @@ -499,22 +524,17 @@ class Hmac : public BaseObject { Hmac(Environment* env, v8::Local wrap) : BaseObject(env, wrap), - initialised_(false) { + ctx_(nullptr) { MakeWeak(this); } private: - HMAC_CTX ctx_; /* coverity[member_decl] */ - bool initialised_; + HMAC_CTX* ctx_; }; class Hash : public BaseObject { public: - ~Hash() override { - if (!initialised_) - return; - EVP_MD_CTX_cleanup(&mdctx_); - } + ~Hash() override; static void Initialize(Environment* env, v8::Local target); @@ -528,13 +548,13 @@ class Hash : public BaseObject { Hash(Environment* env, v8::Local wrap) : BaseObject(env, wrap), - initialised_(false) { + mdctx_(nullptr), + finalized_(false) { MakeWeak(this); } private: - EVP_MD_CTX mdctx_; /* coverity[member_decl] */ - bool initialised_; + EVP_MD_CTX* mdctx_; bool finalized_; }; @@ -552,28 +572,24 @@ class SignBase : public BaseObject { SignBase(Environment* env, v8::Local wrap) : BaseObject(env, wrap), - initialised_(false) { + mdctx_(nullptr) { } - ~SignBase() override { - if (!initialised_) - return; - EVP_MD_CTX_cleanup(&mdctx_); - } + ~SignBase() override; + + Error Init(const char* sign_type); + Error Update(const char* data, int len); protected: void CheckThrow(Error error); - EVP_MD_CTX mdctx_; /* coverity[member_decl] */ - bool initialised_; + EVP_MD_CTX* mdctx_; }; class Sign : public SignBase { public: static void Initialize(Environment* env, v8::Local target); - Error SignInit(const char* sign_type); - Error SignUpdate(const char* data, int len); Error SignFinal(const char* key_pem, int key_pem_len, const char* passphrase, @@ -597,8 +613,6 @@ class Verify : public SignBase { public: static void Initialize(Environment* env, v8::Local target); - Error VerifyInit(const char* verify_type); - Error VerifyUpdate(const char* data, int len); Error VerifyFinal(const char* key_pem, int key_pem_len, const char* sig, @@ -688,9 +702,10 @@ class DiffieHellman : public BaseObject { private: static void GetField(const v8::FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* err_if_null); + const BIGNUM* (*get_field)(const DH*), + const char* err_if_null); static void SetKey(const v8::FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* what); + void (*set_field)(DH*, BIGNUM*), const char* what); bool VerifyContext(); bool initialised_; diff --git a/src/node_crypto_bio.cc b/src/node_crypto_bio.cc index eb1399f0bff..eb0500952b1 100644 --- a/src/node_crypto_bio.cc +++ b/src/node_crypto_bio.cc @@ -28,24 +28,20 @@ namespace node { namespace crypto { -const BIO_METHOD NodeBIO::method = { - BIO_TYPE_MEM, - "node.js SSL buffer", - NodeBIO::Write, - NodeBIO::Read, - NodeBIO::Puts, - NodeBIO::Gets, - NodeBIO::Ctrl, - NodeBIO::New, - NodeBIO::Free, - nullptr -}; +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define BIO_set_data(bio, data) bio->ptr = data +#define BIO_get_data(bio) bio->ptr +#define BIO_set_shutdown(bio, shutdown_) bio->shutdown = shutdown_ +#define BIO_get_shutdown(bio) bio->shutdown +#define BIO_set_init(bio, init_) bio->init = init_ +#define BIO_get_init(bio) bio->init +#endif BIO* NodeBIO::New() { // The const_cast doesn't violate const correctness. OpenSSL's usage of // BIO_METHOD is effectively const but BIO_new() takes a non-const argument. - return BIO_new(const_cast(&method)); + return BIO_new(const_cast(GetMethod())); } @@ -70,12 +66,11 @@ void NodeBIO::AssignEnvironment(Environment* env) { int NodeBIO::New(BIO* bio) { - bio->ptr = new NodeBIO(); + BIO_set_data(bio, new NodeBIO()); // XXX Why am I doing it?! - bio->shutdown = 1; - bio->init = 1; - bio->num = -1; + BIO_set_shutdown(bio, 1); + BIO_set_init(bio, 1); return 1; } @@ -85,10 +80,10 @@ int NodeBIO::Free(BIO* bio) { if (bio == nullptr) return 0; - if (bio->shutdown) { - if (bio->init && bio->ptr != nullptr) { + if (BIO_get_shutdown(bio)) { + if (BIO_get_init(bio) && BIO_get_data(bio) != nullptr) { delete FromBIO(bio); - bio->ptr = nullptr; + BIO_set_data(bio, nullptr); } } @@ -97,13 +92,13 @@ int NodeBIO::Free(BIO* bio) { int NodeBIO::Read(BIO* bio, char* out, int len) { - int bytes; BIO_clear_retry_flags(bio); - bytes = FromBIO(bio)->Read(out, len); + NodeBIO* nbio = FromBIO(bio); + int bytes = nbio->Read(out, len); if (bytes == 0) { - bytes = bio->num; + bytes = nbio->eof_return(); if (bytes != 0) { BIO_set_retry_read(bio); } @@ -161,7 +156,7 @@ int NodeBIO::Puts(BIO* bio, const char* str) { int NodeBIO::Gets(BIO* bio, char* out, int size) { - NodeBIO* nbio = FromBIO(bio); + NodeBIO* nbio = FromBIO(bio); if (nbio->Length() == 0) return 0; @@ -201,7 +196,7 @@ long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) ret = nbio->Length() == 0; break; case BIO_C_SET_BUF_MEM_EOF_RETURN: - bio->num = num; + nbio->set_eof_return(num); break; case BIO_CTRL_INFO: ret = nbio->Length(); @@ -216,10 +211,10 @@ long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) ret = 0; break; case BIO_CTRL_GET_CLOSE: - ret = bio->shutdown; + ret = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: - bio->shutdown = num; + BIO_set_shutdown(bio, num); break; case BIO_CTRL_WPENDING: ret = 0; @@ -241,6 +236,41 @@ long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) } +const BIO_METHOD* NodeBIO::GetMethod() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + static const BIO_METHOD method = { + BIO_TYPE_MEM, + "node.js SSL buffer", + Write, + Read, + Puts, + Gets, + Ctrl, + New, + Free, + nullptr + }; + + return &method; +#else + static BIO_METHOD* method = nullptr; + + if (method == nullptr) { + method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer"); + BIO_meth_set_write(method, Write); + BIO_meth_set_read(method, Read); + BIO_meth_set_puts(method, Puts); + BIO_meth_set_gets(method, Gets); + BIO_meth_set_ctrl(method, Ctrl); + BIO_meth_set_create(method, New); + BIO_meth_set_destroy(method, Free); + } + + return method; +#endif +} + + void NodeBIO::TryMoveReadHead() { // `read_pos_` and `write_pos_` means the position of the reader and writer // inside the buffer, respectively. When they're equal - its safe to reset @@ -488,5 +518,12 @@ NodeBIO::~NodeBIO() { write_head_ = nullptr; } + +NodeBIO* NodeBIO::FromBIO(BIO* bio) { + CHECK_NE(BIO_get_data(bio), nullptr); + return static_cast(BIO_get_data(bio)); +} + + } // namespace crypto } // namespace node diff --git a/src/node_crypto_bio.h b/src/node_crypto_bio.h index 6ec256d0081..380a3a6b4c6 100644 --- a/src/node_crypto_bio.h +++ b/src/node_crypto_bio.h @@ -37,6 +37,7 @@ class NodeBIO { NodeBIO() : env_(nullptr), initial_(kInitialBufferLength), length_(0), + eof_return_(-1), read_head_(nullptr), write_head_(nullptr) { } @@ -95,14 +96,19 @@ class NodeBIO { return length_; } + inline void set_eof_return(int num) { + eof_return_ = num; + } + + inline int eof_return() { + return eof_return_; + } + inline void set_initial(size_t initial) { initial_ = initial; } - static inline NodeBIO* FromBIO(BIO* bio) { - CHECK_NE(bio->ptr, nullptr); - return static_cast(bio->ptr); - } + static NodeBIO* FromBIO(BIO* bio); private: static int New(BIO* bio); @@ -114,12 +120,12 @@ class NodeBIO { static long Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) void* ptr); + static const BIO_METHOD* GetMethod(); + // Enough to handle the most of the client hellos static const size_t kInitialBufferLength = 1024; static const size_t kThroughputBufferLength = 16384; - static const BIO_METHOD method; - class Buffer { public: Buffer(Environment* env, size_t len) : env_(env), @@ -151,6 +157,7 @@ class NodeBIO { Environment* env_; size_t initial_; size_t length_; + int eof_return_; Buffer* read_head_; Buffer* write_head_; }; diff --git a/src/node_perf.cc b/src/node_perf.cc index f5aafbab63a..155f1e66e46 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -215,6 +215,7 @@ void MarkGarbageCollectionEnd(Isolate* isolate, uv_async_t* async = new uv_async_t(); // coverity[leaked_storage] if (uv_async_init(env->event_loop(), async, PerformanceGCCallback)) return delete async; + uv_unref(reinterpret_cast(async)); async->data = new PerformanceEntry::Data(env, "gc", "gc", performance_last_gc_start_mark_, diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h index e1e50802f2a..807e138ef7b 100644 --- a/src/stream_base-inl.h +++ b/src/stream_base-inl.h @@ -11,6 +11,7 @@ namespace node { +using v8::AccessorSignature; using v8::External; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -31,27 +32,33 @@ void StreamBase::AddMethods(Environment* env, HandleScope scope(env->isolate()); enum PropertyAttribute attributes = - static_cast(v8::ReadOnly | v8::DontDelete); + static_cast( + v8::ReadOnly | v8::DontDelete | v8::DontEnum); + Local signature = + AccessorSignature::New(env->isolate(), t); t->PrototypeTemplate()->SetAccessor(env->fd_string(), GetFD, nullptr, env->as_external(), v8::DEFAULT, - attributes); + attributes, + signature); t->PrototypeTemplate()->SetAccessor(env->external_stream_string(), GetExternal, nullptr, env->as_external(), v8::DEFAULT, - attributes); + attributes, + signature); t->PrototypeTemplate()->SetAccessor(env->bytes_read_string(), GetBytesRead, nullptr, env->as_external(), v8::DEFAULT, - attributes); + attributes, + signature); env->SetProtoMethod(t, "readStart", JSMethod); env->SetProtoMethod(t, "readStop", JSMethod); diff --git a/test/fixtures/cluster-preload-test.js b/test/fixtures/cluster-preload-test.js index 0094fe6657f..570cb83bdc4 100644 --- a/test/fixtures/cluster-preload-test.js +++ b/test/fixtures/cluster-preload-test.js @@ -2,6 +2,6 @@ const cluster = require('cluster'); if (cluster.isMaster) { cluster.fork(); // one child cluster.on('exit', function(worker, code, signal) { - console.log('worker terminated with code ' + code); + console.log(`worker terminated with code ${code}`); }); } diff --git a/test/fixtures/guess-hash-seed.js b/test/fixtures/guess-hash-seed.js index c0d072b23d2..18a6f5124dc 100644 --- a/test/fixtures/guess-hash-seed.js +++ b/test/fixtures/guess-hash-seed.js @@ -134,7 +134,7 @@ const slow_str_gen = (function*() { let strgen_i = 0; outer: while (1) { - const str = '#' + (strgen_i++); + const str = `#${strgen_i++}`; for (let i = 0; i < 1000; i++) { if (time_set_lookup(tester_set, str) < tester_set_treshold) continue outer; diff --git a/test/fixtures/loop.js b/test/fixtures/loop.js index e91b831d01b..461fb393583 100644 --- a/test/fixtures/loop.js +++ b/test/fixtures/loop.js @@ -4,7 +4,7 @@ console.log('A message', 5); while (t > 0) { if (t++ === 1000) { t = 0; - console.log('Outputed message #' + k++); + console.log(`Outputed message #${k++}`); } } process.exit(55); diff --git a/test/fixtures/net-fd-passing-receiver.js b/test/fixtures/net-fd-passing-receiver.js index 4279a49beca..8559f116c54 100644 --- a/test/fixtures/net-fd-passing-receiver.js +++ b/test/fixtures/net-fd-passing-receiver.js @@ -36,12 +36,12 @@ receiver = net.createServer(function(socket) { }); passedSocket.on('data', function(data) { - passedSocket.send('[echo] ' + data); + passedSocket.send(`[echo] ${data}`); }); passedSocket.on('close', function() { receiver.close(); }); - passedSocket.send('[greeting] ' + greeting); + passedSocket.send(`[greeting] ${greeting}`); }); }); diff --git a/test/fixtures/print-10-lines.js b/test/fixtures/print-10-lines.js index d483fe6bff3..e672ef80cf4 100644 --- a/test/fixtures/print-10-lines.js +++ b/test/fixtures/print-10-lines.js @@ -20,5 +20,5 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. for (var i = 0; i < 10; i++) { - console.log('count ' + i); + console.log(`count ${i}`); } diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index 30d7be58667..c75aa575c46 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -5,8 +5,6 @@ prefix parallel # sample-test : PASS,FLAKY [true] # This section applies to all platforms -# https://github.com/nodejs/node/issues/16210 -test-async-wrap-uncaughtexception: PASS,FLAKY [$system==win32] diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 955b775b70f..bd33737fb4c 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -693,7 +693,7 @@ try { code: 'ERR_INVALID_ARG_TYPE', type: TypeError, message: 'The "block" argument must be of type function. Received ' + - 'type ' + typeName(block) + `type ${typeName(block)}` })(e); } diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index 62d0f7d6b06..c162d660bd4 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -56,6 +56,19 @@ const secret3 = dh3.computeSecret(key2, 'hex', 'base64'); assert.strictEqual(secret1, secret3); +// computeSecret works without a public key set at all. +const dh4 = crypto.createDiffieHellman(p1, 'buffer'); +dh4.setPrivateKey(privkey1); + +assert.deepStrictEqual(dh1.getPrime(), dh4.getPrime()); +assert.deepStrictEqual(dh1.getGenerator(), dh4.getGenerator()); +assert.deepStrictEqual(dh1.getPrivateKey(), dh4.getPrivateKey()); +assert.strictEqual(dh4.verifyError, 0); + +const secret4 = dh4.computeSecret(key2, 'hex', 'base64'); + +assert.strictEqual(secret1, secret4); + const wrongBlockLength = /^Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length$/; diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 76164c683f9..69f3a7f4198 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -132,12 +132,12 @@ const noCapitals = /^[^A-Z]+$/; assert(tlsCiphers.every((value) => noCapitals.test(value))); validateList(tlsCiphers); -// Assert that we have sha and sha1 but not SHA and SHA1. +// Assert that we have sha1 and sha256 but not SHA1 and SHA256. assert.notStrictEqual(0, crypto.getHashes().length); assert(crypto.getHashes().includes('sha1')); -assert(crypto.getHashes().includes('sha')); +assert(crypto.getHashes().includes('sha256')); assert(!crypto.getHashes().includes('SHA1')); -assert(!crypto.getHashes().includes('SHA')); +assert(!crypto.getHashes().includes('SHA256')); assert(crypto.getHashes().includes('RSA-SHA1')); assert(!crypto.getHashes().includes('rsa-sha1')); validateList(crypto.getHashes()); @@ -238,7 +238,7 @@ assert.throws(function() { // Throws crypto error, so there is an opensslErrorStack property. // The openSSL stack should have content. if ((err instanceof Error) && - /asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag/.test(err) && + /asn1 encoding routines:[^:]*:wrong tag/.test(err) && err.opensslErrorStack !== undefined && Array.isArray(err.opensslErrorStack) && err.opensslErrorStack.length > 0) { diff --git a/test/parallel/test-http2-create-client-connect.js b/test/parallel/test-http2-create-client-connect.js index 7fdea9aef41..cd7d8b4fc8c 100644 --- a/test/parallel/test-http2-create-client-connect.js +++ b/test/parallel/test-http2-create-client-connect.js @@ -3,6 +3,7 @@ // Tests http2.connect() const common = require('../common'); +const Countdown = require('../common/countdown'); if (!common.hasCrypto) common.skip('missing crypto'); const fixtures = require('../common/fixtures'); @@ -25,13 +26,12 @@ const URL = url.URL; [{ port: port, hostname: '127.0.0.1' }, { protocol: 'http:' }] ]; - let count = items.length; + const serverClose = new Countdown(items.length + 1, + () => setImmediate(() => server.close())); const maybeClose = common.mustCall((client) => { client.destroy(); - if (--count === 0) { - setImmediate(() => server.close()); - } + serverClose.dec(); }, items.length); items.forEach((i) => { @@ -42,7 +42,7 @@ const URL = url.URL; // Will fail because protocol does not match the server. h2.connect({ port: port, protocol: 'https:' }) - .on('socketError', common.mustCall()); + .on('socketError', common.mustCall(() => serverClose.dec())); })); } @@ -70,13 +70,12 @@ const URL = url.URL; [{ port: port, hostname: '127.0.0.1', protocol: 'https:' }, opts] ]; - let count = items.length; + const serverClose = new Countdown(items.length, + () => setImmediate(() => server.close())); const maybeClose = common.mustCall((client) => { client.destroy(); - if (--count === 0) { - setImmediate(() => server.close()); - } + serverClose.dec(); }, items.length); items.forEach((i) => { diff --git a/test/parallel/test-https-agent-session-eviction.js b/test/parallel/test-https-agent-session-eviction.js index 616604124ac..cf6a1341c1e 100644 --- a/test/parallel/test-https-agent-session-eviction.js +++ b/test/parallel/test-https-agent-session-eviction.js @@ -8,7 +8,8 @@ if (!common.hasCrypto) const assert = require('assert'); const https = require('https'); -const SSL_OP_NO_TICKET = require('crypto').constants.SSL_OP_NO_TICKET; +const { OPENSSL_VERSION_NUMBER, SSL_OP_NO_TICKET } = + require('crypto').constants; const options = { key: readKey('agent1-key.pem'), @@ -58,14 +59,25 @@ function second(server, session) { res.resume(); }); - // Let it fail - req.on('error', common.mustCall(function(err) { - assert(/wrong version number/.test(err.message)); + if (OPENSSL_VERSION_NUMBER >= 0x10100000) { + // Although we have a TLS 1.2 session to offer to the TLS 1.0 server, + // connection to the TLS 1.0 server should work. + req.on('response', common.mustCall(function(res) { + // The test is now complete for OpenSSL 1.1.0. + server.close(); + })); + } else { + // OpenSSL 1.0.x mistakenly locked versions based on the session it was + // offering. This causes this sequent request to fail. Let it fail, but + // test that this is mitigated on the next try by invalidating the session. + req.on('error', common.mustCall(function(err) { + assert(/wrong version number/.test(err.message)); - req.on('close', function() { - third(server); - }); - })); + req.on('close', function() { + third(server); + }); + })); + } req.end(); } diff --git a/test/parallel/test-https-connect-address-family.js b/test/parallel/test-https-connect-address-family.js index a345a70a570..28d47b3a967 100644 --- a/test/parallel/test-https-connect-address-family.js +++ b/test/parallel/test-https-connect-address-family.js @@ -7,12 +7,15 @@ if (!common.hasIPv6) common.skip('no IPv6 support'); const assert = require('assert'); +const fixtures = require('../common/fixtures'); const https = require('https'); const dns = require('dns'); function runTest() { - const ciphers = 'AECDH-NULL-SHA'; - https.createServer({ ciphers }, common.mustCall(function(req, res) { + https.createServer({ + cert: fixtures.readKey('agent1-cert.pem'), + key: fixtures.readKey('agent1-key.pem'), + }, common.mustCall(function(req, res) { this.close(); res.end(); })).listen(0, '::1', common.mustCall(function() { @@ -20,7 +23,6 @@ function runTest() { host: 'localhost', port: this.address().port, family: 6, - ciphers: ciphers, rejectUnauthorized: false, }; // Will fail with ECONNREFUSED if the address family is not honored. diff --git a/test/parallel/test-performance-gc.js b/test/parallel/test-performance-gc.js index 1ff4c9ae629..89a9041c1c1 100644 --- a/test/parallel/test-performance-gc.js +++ b/test/parallel/test-performance-gc.js @@ -48,4 +48,6 @@ const kinds = [ })); obs.observe({ entryTypes: ['gc'] }); global.gc(); + // Keep the event loop alive to witness the GC async callback happen. + setImmediate(() => setImmediate(() => 0)); } diff --git a/test/parallel/test-process-ppid.js b/test/parallel/test-process-ppid.js new file mode 100644 index 00000000000..d78ef3a2dd9 --- /dev/null +++ b/test/parallel/test-process-ppid.js @@ -0,0 +1,16 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const cp = require('child_process'); + +if (process.argv[2] === 'child') { + // The following console.log() call is part of the test's functionality. + console.log(process.ppid); +} else { + const child = cp.spawnSync(process.execPath, [__filename, 'child']); + + assert.strictEqual(child.status, 0); + assert.strictEqual(child.signal, null); + assert.strictEqual(+child.stdout.toString().trim(), process.pid); + assert.strictEqual(child.stderr.toString().trim(), ''); +} diff --git a/test/parallel/test-process-raw-debug.js b/test/parallel/test-process-raw-debug.js index 7b89a8ad18e..6f989e123e8 100644 --- a/test/parallel/test-process-raw-debug.js +++ b/test/parallel/test-process-raw-debug.js @@ -50,10 +50,10 @@ function parent() { console.log('ok - got expected message'); }); - child.on('exit', function(c) { + child.on('exit', common.mustCall(function(c) { assert(!c); console.log('ok - child exited nicely'); - }); + })); } function child() { diff --git a/test/parallel/test-stream-base-prototype-accessors-enumerability.js b/test/parallel/test-stream-base-prototype-accessors-enumerability.js new file mode 100644 index 00000000000..f59aced197c --- /dev/null +++ b/test/parallel/test-stream-base-prototype-accessors-enumerability.js @@ -0,0 +1,19 @@ +'use strict'; + +require('../common'); + +// This tests that the prototype accessors added by StreamBase::AddMethods +// are not enumerable. They could be enumerated when inspecting the prototype +// with util.inspect or the inspector protocol. + +const assert = require('assert'); + +// Or anything that calls StreamBase::AddMethods when setting up its prototype +const TTY = process.binding('tty_wrap').TTY; + +{ + assert.strictEqual(TTY.prototype.propertyIsEnumerable('bytesRead'), false); + assert.strictEqual(TTY.prototype.propertyIsEnumerable('fd'), false); + assert.strictEqual( + TTY.prototype.propertyIsEnumerable('_externalStream'), false); +} diff --git a/test/parallel/test-stream-base-prototype-accessors.js b/test/parallel/test-stream-base-prototype-accessors.js new file mode 100644 index 00000000000..f9e12582a09 --- /dev/null +++ b/test/parallel/test-stream-base-prototype-accessors.js @@ -0,0 +1,27 @@ +'use strict'; + +require('../common'); + +// This tests that the prototype accessors added by StreamBase::AddMethods +// do not raise assersions when called with incompatible receivers. + +const assert = require('assert'); + +// Or anything that calls StreamBase::AddMethods when setting up its prototype +const TTY = process.binding('tty_wrap').TTY; + +// Should throw instead of raise assertions +{ + const msg = /TypeError: Method \w+ called on incompatible receiver/; + assert.throws(() => { + TTY.prototype.bytesRead; + }, msg); + + assert.throws(() => { + TTY.prototype.fd; + }, msg); + + assert.throws(() => { + TTY.prototype._externalStream; + }, msg); +} diff --git a/test/parallel/test-tls-cert-regression.js b/test/parallel/test-tls-cert-regression.js index ab967bb2c6e..9329dea9fb1 100644 --- a/test/parallel/test-tls-cert-regression.js +++ b/test/parallel/test-tls-cert-regression.js @@ -27,29 +27,43 @@ if (!common.hasCrypto) const tls = require('tls'); - const cert = `-----BEGIN CERTIFICATE----- -MIIBfjCCASgCCQDmmNjAojbDQjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMCAXDTE0MDExNjE3NTMxM1oYDzIyODcxMDMxMTc1MzEzWjBFMQsw -CQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu -ZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKwlfMX -6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+wsU1O9FzRIVmpeIjDXhbp -Mjsa1HtzSiccPXsCAwEAATANBgkqhkiG9w0BAQUFAANBAHOoKy0NkyfiYH7Ne5ka -uvCyndyeB4d24FlfqEUlkfaWCZlNKRaV9YhLDiEg3BcIreFo4brtKQfZzTRs0GVm -KHg= +MIIDNDCCAp2gAwIBAgIJAJvXLQpGPpm7MA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV +BAYTAkdCMRAwDgYDVQQIEwdHd3luZWRkMREwDwYDVQQHEwhXYXVuZmF3cjEUMBIG +A1UEChMLQWNrbmFjayBMdGQxEjAQBgNVBAsTCVRlc3QgQ2VydDESMBAGA1UEAxMJ +bG9jYWxob3N0MB4XDTA5MTEwMjE5MzMwNVoXDTEwMTEwMjE5MzMwNVowcDELMAkG +A1UEBhMCR0IxEDAOBgNVBAgTB0d3eW5lZGQxETAPBgNVBAcTCFdhdW5mYXdyMRQw +EgYDVQQKEwtBY2tuYWNrIEx0ZDESMBAGA1UECxMJVGVzdCBDZXJ0MRIwEAYDVQQD +Ewlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdym7nGe2yw +6LlJfJrQtC5TmKOGrSXiyolYCbGOy4xZI4KD31d3097jhlQFJyF+10gwkE62DuJe +fLvBZDUsvLe1R8bzlVhZnBVn+3QJyUIWQAL+DsRj8P3KoD7k363QN5dIaA1GOAg2 +vZcPy1HCUsvOgvDXGRUCZqNLAyt+h/cpAgMBAAGjgdUwgdIwHQYDVR0OBBYEFK4s +VBV4shKUj3UX/fvSJnFaaPBjMIGiBgNVHSMEgZowgZeAFK4sVBV4shKUj3UX/fvS +JnFaaPBjoXSkcjBwMQswCQYDVQQGEwJHQjEQMA4GA1UECBMHR3d5bmVkZDERMA8G +A1UEBxMIV2F1bmZhd3IxFDASBgNVBAoTC0Fja25hY2sgTHRkMRIwEAYDVQQLEwlU +ZXN0IENlcnQxEjAQBgNVBAMTCWxvY2FsaG9zdIIJAJvXLQpGPpm7MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAFxR7BA1mUlsYqPiogtxSIfLzHWh+s0bJ +SBuhNrHes4U8QxS8+x/KWjd/81gzsf9J1C2VzTlFaydAgigz3SkQYgs+TMnFkT2o +9jqoJrcdf4WpZ2DQXUALaZgwNzPumMUSx8Ac5gO+BY/RHyP6fCodYvdNwyKslnI3 +US7eCSHZsVo= -----END CERTIFICATE-----`; const key = `-----BEGIN RSA PRIVATE KEY----- -MIIBPQIBAAJBAPKwlfMX6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+w -sU1O9FzRIVmpeIjDXhbpMjsa1HtzSiccPXsCAwEAAQJBAM4uU9aJE0OfdE1p/X+K -LrCT3XMdFCJ24GgmHyOURtwDy18upQJecDVdcZp16fjtOPmaW95GoYRyifB3R4I5 -RxECIQD7jRM9slCSVV8xp9kOJQNpHjhRQYVGBn+pyllS2sb+RQIhAPb7Y+BIccri -NWnuhwCW8hA7Fkj/kaBdAwyW7L3Tvui/AiEAiqLCovMecre4Yi6GcsQ1b/6mvSmm -IOS+AT6zIfXPTB0CIQCJKGR3ymN/Qw5crL1GQ41cHCQtF9ickOq/lBUW+j976wIh -AOaJnkQrmurlRdePX6LvN/LgGAQoxwovfjcOYNnZsIVY +MIICXgIBAAKBgQDXcpu5xntssOi5SXya0LQuU5ijhq0l4sqJWAmxjsuMWSOCg99X +d9Pe44ZUBSchftdIMJBOtg7iXny7wWQ1LLy3tUfG85VYWZwVZ/t0CclCFkAC/g7E +Y/D9yqA+5N+t0DeXSGgNRjgINr2XD8tRwlLLzoLw1xkVAmajSwMrfof3KQIDAQAB +AoGBAIBHR/tT93ce2mJAJAXV0AJpWc+7x2pwX2FpXtQujnlxNZhnRlrBCRCD7h4m +t0bVS/86kyGaesBDvAbavfx/N5keYzzmmSp5Ht8IPqKPydGWdigk4x90yWvktai7 +dWuRKF94FXr0GUuBONb/dfHdp4KBtzN7oIF9WydYGGXA9ZmBAkEA8/k01bfwQZIu +AgcdNEM94Zcug1gSspXtUu8exNQX4+PNVbadghZb1+OnUO4d3gvWfqvAnaXD3KV6 +N4OtUhQQ0QJBAOIRbKMfaymQ9yE3CQQxYfKmEhHXWARXVwuYqIFqjmhSjSXx0l/P +7mSHz1I9uDvxkJev8sQgu1TKIyTOdqPH1tkCQQDPa6H1yYoj1Un0Q2Qa2Mg1kTjk +Re6vkjPQ/KcmJEOjZjtekgFbZfLzmwLXFXqjG2FjFFaQMSxR3QYJSJQEYjbhAkEA +sy7OZcjcXnjZeEkv61Pc57/7qIp/6Aj2JGnefZ1gvI1Z9Q5kCa88rA/9Iplq8pA4 +ZBKAoDW1ZbJGAsFmxc/6mQJAdPilhci0qFN86IGmf+ZBnwsDflIwHKDaVofti4wQ +sPWhSOb9VQjMXekI4Y2l8fqAVTS2Fn6+8jkVKxXBywSVCw== -----END RSA PRIVATE KEY-----`; function test(cert, key, cb) { diff --git a/test/parallel/test-tls-connect-address-family.js b/test/parallel/test-tls-connect-address-family.js index b0623c6cf60..75416c397d7 100644 --- a/test/parallel/test-tls-connect-address-family.js +++ b/test/parallel/test-tls-connect-address-family.js @@ -7,19 +7,21 @@ if (!common.hasIPv6) common.skip('no IPv6 support'); const assert = require('assert'); +const fixtures = require('../common/fixtures'); const tls = require('tls'); const dns = require('dns'); function runTest() { - const ciphers = 'AECDH-NULL-SHA'; - tls.createServer({ ciphers }, common.mustCall(function() { + tls.createServer({ + cert: fixtures.readKey('agent1-cert.pem'), + key: fixtures.readKey('agent1-key.pem'), + }, common.mustCall(function() { this.close(); })).listen(0, '::1', common.mustCall(function() { const options = { host: 'localhost', port: this.address().port, family: 6, - ciphers: ciphers, rejectUnauthorized: false, }; // Will fail with ECONNREFUSED if the address family is not honored. diff --git a/test/parallel/test-tls-ecdh-disable.js b/test/parallel/test-tls-ecdh-disable.js index 72b51771c87..af97fbfcdd0 100644 --- a/test/parallel/test-tls-ecdh-disable.js +++ b/test/parallel/test-tls-ecdh-disable.js @@ -31,6 +31,11 @@ if (!common.hasCrypto) if (!common.opensslCli) common.skip('missing openssl-cli'); +const OPENSSL_VERSION_NUMBER = + require('crypto').constants.OPENSSL_VERSION_NUMBER; +if (OPENSSL_VERSION_NUMBER >= 0x10100000) + common.skip('false ecdhCurve not supported in OpenSSL 1.1.0'); + const assert = require('assert'); const tls = require('tls'); const exec = require('child_process').exec; @@ -42,6 +47,9 @@ const options = { ecdhCurve: false }; +common.expectWarning('DeprecationWarning', + '{ ecdhCurve: false } is deprecated.'); + const server = tls.createServer(options, common.mustNotCall()); server.listen(0, '127.0.0.1', common.mustCall(function() { diff --git a/test/parallel/test-tls-econnreset.js b/test/parallel/test-tls-econnreset.js index 8a6536890e8..1ffd7b1e975 100644 --- a/test/parallel/test-tls-econnreset.js +++ b/test/parallel/test-tls-econnreset.js @@ -25,72 +25,28 @@ if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const net = require('net'); const tls = require('tls'); -const cacert = -`-----BEGIN CERTIFICATE----- -MIIBxTCCAX8CAnXnMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD -VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n -TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv -bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMH0xCzAJ -BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZ -MBcGA1UEChMQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRow -GAYDVQQDExFjYS5zdHJvbmdsb29wLmNvbTBMMA0GCSqGSIb3DQEBAQUAAzsAMDgC -MQDKbQ6rIR5t1q1v4Ha36jrq0IkyUohy9EYNvLnXUly1PGqxby0ILlAVJ8JawpY9 -AVkCAwEAATANBgkqhkiG9w0BAQUFAAMxALA1uS4CqQXRSAyYTfio5oyLGz71a+NM -+0AFLBwh5AQjhGd0FcenU4OfHxyDEOJT/Q== ------END CERTIFICATE-----`; - -const cert = -`-----BEGIN CERTIFICATE----- -MIIBfDCCATYCAgQaMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD -VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n -TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv -bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMBkxFzAV -BgNVBAMTDnN0cm9uZ2xvb3AuY29tMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxAMfk -I0LWU15pPUwIQNMnRVhhOibi0TQmAau8FBtgwEfGK01WpfGUaJr1a41K8Uq7xwID -AQABoxkwFzAVBgNVHREEDjAMhwQAAAAAhwR/AAABMA0GCSqGSIb3DQEBBQUAAzEA -cGpYrhkrb7mIh9DNhV0qp7pGjqBzlHqB7KQXw2luLDp//6dyHBMexDCQznkhZKRU ------END CERTIFICATE-----`; - -const key = -`-----BEGIN RSA PRIVATE KEY----- -MIH0AgEAAjEAx+QjQtZTXmk9TAhA0ydFWGE6JuLRNCYBq7wUG2DAR8YrTVal8ZRo -mvVrjUrxSrvHAgMBAAECMBCGccvSwC2r8Z9Zh1JtirQVxaL1WWpAQfmVwLe0bAgg -/JWMU/6hS36TsYyZMxwswQIZAPTAfht/zDLb7Hwgu2twsS1Ra9w/yyvtlwIZANET -26votwJAHK1yUrZGA5nnp5qcmQ/JUQIZAII5YV/UUZvF9D/fUplJ7puENPWNY9bN -pQIZAMMwxuS3XiO7two2sQF6W+JTYyX1DPCwAQIZAOYg1TvEGT38k8e8jygv8E8w -YqrWTeQFNQ== ------END RSA PRIVATE KEY-----`; - -const ca = [ cert, cacert ]; - let clientError = null; -let connectError = null; -const server = tls.createServer({ ca: ca, cert: cert, key: key }, () => { - assert.fail('should be unreachable'); -}).on('tlsClientError', function(err, conn) { +const server = tls.createServer({ + cert: fixtures.readKey('agent1-cert.pem'), + key: fixtures.readKey('agent1-key.pem'), +}, common.mustNotCall()).on('tlsClientError', function(err, conn) { assert(!clientError && conn); clientError = err; + server.close(); }).listen(0, function() { - const options = { - ciphers: 'AES128-GCM-SHA256', - port: this.address().port, - ca: ca - }; - tls.connect(options).on('error', function(err) { - assert(!connectError); - - connectError = err; + net.connect(this.address().port, function() { + // Destroy the socket once it is connected, so the server sees ECONNRESET. this.destroy(); - server.close(); - }).write('123'); + }).on('error', common.mustNotCall()); }); process.on('exit', function() { assert(clientError); - assert(connectError); assert(/socket hang up/.test(clientError.message)); assert(/ECONNRESET/.test(clientError.code)); }); diff --git a/test/parallel/test-tls-junk-server.js b/test/parallel/test-tls-junk-server.js index 3270dec745c..27c273857b5 100644 --- a/test/parallel/test-tls-junk-server.js +++ b/test/parallel/test-tls-junk-server.js @@ -21,7 +21,9 @@ server.listen(0, function() { req.end(); req.once('error', common.mustCall(function(err) { - assert(/unknown protocol/.test(err.message)); + // OpenSSL 1.0.x and 1.1.x use different error messages for junk inputs. + assert(/unknown protocol/.test(err.message) || + /wrong version number/.test(err.message)); server.close(); })); }); diff --git a/test/parallel/test-tls-no-sslv3.js b/test/parallel/test-tls-no-sslv3.js index 9622262f38c..aa37fc2e3b6 100644 --- a/test/parallel/test-tls-no-sslv3.js +++ b/test/parallel/test-tls-no-sslv3.js @@ -46,6 +46,8 @@ process.on('exit', function() { common.printSkipMessage('`openssl s_client -ssl3` not supported.'); } else { assert.strictEqual(errors.length, 1); - assert(/:wrong version number/.test(errors[0].message)); + // OpenSSL 1.0.x and 1.1.x report invalid client versions differently. + assert(/:wrong version number/.test(errors[0].message) || + /:version too low/.test(errors[0].message)); } }); diff --git a/test/parallel/test-tls-server-failed-handshake-emits-clienterror.js b/test/parallel/test-tls-server-failed-handshake-emits-clienterror.js index 8efb4ec5386..c4351008c14 100644 --- a/test/parallel/test-tls-server-failed-handshake-emits-clienterror.js +++ b/test/parallel/test-tls-server-failed-handshake-emits-clienterror.js @@ -20,8 +20,10 @@ const server = tls.createServer({}) }).on('tlsClientError', common.mustCall(function(e) { assert.ok(e instanceof Error, 'Instance of Error should be passed to error handler'); + // OpenSSL 1.0.x and 1.1.x use different error codes for junk inputs. assert.ok( - /SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol/.test(e.message), + /SSL routines:[^:]*:(unknown protocol|wrong version number)/.test( + e.message), 'Expecting SSL unknown protocol'); server.close(); diff --git a/test/parallel/test-tls-socket-failed-handshake-emits-error.js b/test/parallel/test-tls-socket-failed-handshake-emits-error.js index a54b7170f08..d67a5498d65 100644 --- a/test/parallel/test-tls-socket-failed-handshake-emits-error.js +++ b/test/parallel/test-tls-socket-failed-handshake-emits-error.js @@ -20,8 +20,10 @@ const server = net.createServer(function(c) { s.on('error', common.mustCall(function(e) { assert.ok(e instanceof Error, 'Instance of Error should be passed to error handler'); + // OpenSSL 1.0.x and 1.1.x use different error codes for junk inputs. assert.ok( - /SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol/.test(e.message), + /SSL routines:[^:]*:(unknown protocol|wrong version number)/.test( + e.message), 'Expecting SSL unknown protocol'); })); diff --git a/test/parallel/test-whatwg-url-setters.js b/test/parallel/test-whatwg-url-setters.js index e612eec9c70..0354edf2061 100644 --- a/test/parallel/test-whatwg-url-setters.js +++ b/test/parallel/test-whatwg-url-setters.js @@ -46,10 +46,10 @@ function runURLSettersTests(all_test_cases) { var test_cases = all_test_cases[attribute_to_be_set]; for(var i = 0, l = test_cases.length; i < l; i++) { var test_case = test_cases[i]; - var name = "Setting <" + test_case.href + ">." + attribute_to_be_set + - " = '" + test_case.new_value + "'"; + var name = `Setting <${test_case.href}>.${attribute_to_be_set}` + + ` = '${test_case.new_value}'`; if ("comment" in test_case) { - name += " " + test_case.comment; + name += ` ${test_case.comment}`; } test(function() { var url = new URL(test_case.href); @@ -57,7 +57,7 @@ function runURLSettersTests(all_test_cases) { for (var attribute in test_case.expected) { assert_equals(url[attribute], test_case.expected[attribute]) } - }, "URL: " + name) + }, `URL: ${name}`); // test(function() { // var url = document.createElement("a"); // url.href = test_case.href; @@ -93,7 +93,7 @@ startURLSettersTests() let name = `Setting <${testCase.href}>.${attributeToBeSet}` + ` = "${testCase.new_value}"`; if ('comment' in testCase) { - name += ' ' + testCase.comment; + name += ` ${testCase.comment}`; } test(function() { const url = new URL(testCase.href); @@ -101,7 +101,7 @@ startURLSettersTests() for (const attribute in testCase.expected) { assert_equals(url[attribute], testCase.expected[attribute]); } - }, 'URL: ' + name); + }, `URL: ${name}`); } } } diff --git a/test/sequential/sequential.status b/test/sequential/sequential.status index 2226edb3f77..22fb7c1a500 100644 --- a/test/sequential/sequential.status +++ b/test/sequential/sequential.status @@ -10,6 +10,7 @@ prefix sequential test-inspector-async-call-stack : PASS, FLAKY test-inspector-bindings : PASS, FLAKY test-inspector-debug-end : PASS, FLAKY +test-inspector-async-hook-setup-at-signal: PASS, FLAKY [$system==linux]