Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,65 @@ def get_gas_version(cc):
warn(f'Could not recognize `gas`: {gas_ret}')
return '0.0'

def get_openssl_version():
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a heads up to reviewers... while I'm generally not very bullish on AI generated code, I did use copilot/claude to generate this particular function for me. I went through it and the impl appeared reasonable but it's absolutely worth reviewing in detail to make sure it is correct.

Copy link
Member Author

@jasnell jasnell Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the CI run, it does look like the check here is still failing for the shared-openssl cases but the build still proceeds since the value is set to 0. This has the side effect of disabling quic in those builds so it's not fatal. Still, would be ideal to figure out a version of this that works. Going to keep iterating but if anyone in @nodejs/build has any suggestions I'd appreciate it :-) .. the key issue is that it's not able to see the include path to find the opensslv.h header in the CI builds here. It looks like our builders aren't using the --shared-openssl-includes option to set that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasnell The CI builds use pkg-config to get the include paths. I've opened #59353 to fix the OpenSSL version detection for that case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brilliant! Thank you @richardlau !

"""Parse OpenSSL version from opensslv.h header file.

Returns the version as a number matching OPENSSL_VERSION_NUMBER format:
0xMNN00PPSL where M=major, NN=minor, PP=patch, S=status(0xf=release,0x0=pre), L=0
"""

try:
# Use the C compiler to extract preprocessor macros from opensslv.h
args = ['-E', '-dM', '-include', 'openssl/opensslv.h', '-']
if not options.shared_openssl:
args = ['-I', 'deps/openssl/openssl/include'] + args
elif options.shared_openssl_includes:
args = ['-I', options.shared_openssl_includes] + args

proc = subprocess.Popen(
shlex.split(CC) + args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
with proc:
proc.stdin.write(b'\n')
out = to_utf8(proc.communicate()[0])

if proc.returncode != 0:
warn('Failed to extract OpenSSL version from opensslv.h header')
return 0

# Parse the macro definitions
macros = {}
for line in out.split('\n'):
if line.startswith('#define OPENSSL_VERSION_'):
parts = line.split()
if len(parts) >= 3:
macro_name = parts[1]
macro_value = parts[2]
macros[macro_name] = macro_value

# Extract version components
major = int(macros.get('OPENSSL_VERSION_MAJOR', '0'))
minor = int(macros.get('OPENSSL_VERSION_MINOR', '0'))
patch = int(macros.get('OPENSSL_VERSION_PATCH', '0'))

# Check if it's a pre-release (has non-empty PRE_RELEASE string)
pre_release = macros.get('OPENSSL_VERSION_PRE_RELEASE', '""').strip('"')
status = 0x0 if pre_release else 0xf
# Construct version number: 0xMNN00PPSL
version_number = ((major << 28) |
(minor << 20) |
(patch << 4) |
status)

return version_number

except (OSError, ValueError, subprocess.SubprocessError) as e:
warn(f'Failed to determine OpenSSL version from header: {e}')
return 0

# Note: Apple clang self-reports as clang 4.2.0 and gcc 4.2.1. It passes
# the version check more by accident than anything else but a more rigorous
# check involves checking the build number against an allowlist. I'm not
Expand Down Expand Up @@ -1828,6 +1887,8 @@ def without_ssl_error(option):
if options.quic:
o['defines'] += ['NODE_OPENSSL_HAS_QUIC']

o['variables']['openssl_version'] = get_openssl_version()

configure_library('openssl', o)

def configure_sqlite(o):
Expand Down
6 changes: 6 additions & 0 deletions deps/ngtcp2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ $ cp -R lib/* ../node/deps/ngtcp2/ngtcp2/lib/
$ cp -R crypto/* ../node/deps/ngtcp2/ngtcp2/crypto/
```

Be sure to also update the `ngtcp2.gyp` file to reflect any changes in
the source files or include directories.

### Updating nghttp3

To update nghttp3, replace `v0.7.0` with the desired git tag:
Expand All @@ -47,3 +50,6 @@ $ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ cp -R lib/* ../node/deps/ngtcp2/nghttp3/lib/
```

Be sure to also update the `ngtcp2.gyp` file to reflect any changes in
the source files or include directories.
117 changes: 112 additions & 5 deletions deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h
Original file line number Diff line number Diff line change
Expand Up @@ -1116,11 +1116,43 @@ typedef struct nghttp3_qpack_encoder nghttp3_qpack_encoder;
*
* :macro:`NGHTTP3_ERR_NOMEM`
* Out of memory.
*
* See also `nghttp3_qpack_encoder_new2`. This function calls
* `nghttp3_qpack_encoder_new2` with the given parameters and 0 as
* seed.
*/
NGHTTP3_EXTERN int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder,
size_t hard_max_dtable_capacity,
const nghttp3_mem *mem);

/**
* @function
*
* `nghttp3_qpack_encoder_new2` initializes QPACK encoder. |pencoder|
* must be non-NULL pointer. |hard_max_dtable_capacity| is the upper
* bound of the dynamic table capacity. |seed| must be unpredictable
* value, and is used to seed the internal data structure. |mem| is a
* memory allocator. This function allocates memory for
* :type:`nghttp3_qpack_encoder` itself, and assigns its pointer to
* |*pencoder| if it succeeds.
*
* The maximum dynamic table capacity is still 0. In order to change
* the maximum dynamic table capacity, call
* `nghttp3_qpack_encoder_set_max_dtable_capacity`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :macro:`NGHTTP3_ERR_NOMEM`
* Out of memory.
*
* This function is available since v1.11.0.
*/
NGHTTP3_EXTERN int nghttp3_qpack_encoder_new2(nghttp3_qpack_encoder **pencoder,
size_t hard_max_dtable_capacity,
uint64_t seed,
const nghttp3_mem *mem);

/**
* @function
*
Expand Down Expand Up @@ -1605,7 +1637,8 @@ NGHTTP3_EXTERN void nghttp3_set_debug_vprintf_callback(
typedef struct nghttp3_conn nghttp3_conn;

#define NGHTTP3_SETTINGS_V1 1
#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V1
#define NGHTTP3_SETTINGS_V2 2
#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V2

/**
* @struct
Expand Down Expand Up @@ -1652,6 +1685,21 @@ typedef struct nghttp3_settings {
* Datagrams (see :rfc:`9297`).
*/
uint8_t h3_datagram;
/* The following fields have been added since NGHTTP3_SETTINGS_V2. */
/**
* :member:`origin_list`, if set, must contain a serialized HTTP/3
* ORIGIN frame (see :rfc:`9412`) payload. The ORIGIN frame payload
* is a sequence of zero or more of a length prefixed byte string.
* The length is encoded in 2 bytes in network byte order. If
* :member:`origin_list->len <nghttp3_vec.len>` is zero, an empty
* ORIGIN frame is sent. An application must keep the buffer
* pointed by :member:`origin_list->base <nghttp3_vec.base>` alive
* until the :type:`nghttp3_conn` to which this field was passed is
* freed by `nghttp3_conn_del`. The object pointed to by this field
* is copied internally, and does not need to be kept alive. Only
* server uses this field. This field is available since v1.11.0.
*/
const nghttp3_vec *origin_list;
} nghttp3_settings;

/**
Expand Down Expand Up @@ -1891,8 +1939,47 @@ typedef int (*nghttp3_recv_settings)(nghttp3_conn *conn,
const nghttp3_settings *settings,
void *conn_user_data);

/**
* @functypedef
*
* :type:`nghttp3_recv_origin` is a callback function which is invoked
* when a single origin in ORIGIN frame is received. |origin| is a
* received origin of length |originlen|. |originlen| never be 0.
*
* The implementation of this callback must return 0 if it succeeds.
* Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the
* caller immediately. Any values other than 0 is treated as
* :macro:`NGHTTP3_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp3_recv_origin)(nghttp3_conn *conn, const uint8_t *origin,
size_t originlen, void *conn_user_data);

/**
* @functypedef
*
* :type:`nghttp3_end_origin` is a callback function which is invoked
* when an ORIGIN frame has been completely processed.
*
* The implementation of this callback must return 0 if it succeeds.
* Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the
* caller immediately. Any values other than 0 is treated as
* :macro:`NGHTTP3_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp3_end_origin)(nghttp3_conn *conn, void *conn_user_data);

/**
* @functypedef
*
* :type:`nghttp3_rand` is a callback function which is invoked when
* unpredictable data of |destlen| bytes are needed. The
* implementation must write unpredictable data of |destlen| bytes
* into the buffer pointed by |dest|.
*/
typedef void (*nghttp3_rand)(uint8_t *dest, size_t destlen);

#define NGHTTP3_CALLBACKS_V1 1
#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_V1
#define NGHTTP3_CALLBACKS_V2 2
#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_V2

/**
* @struct
Expand Down Expand Up @@ -1986,6 +2073,28 @@ typedef struct nghttp3_callbacks {
* when SETTINGS frame is received.
*/
nghttp3_recv_settings recv_settings;
/* The following fields have been added since NGHTTP3_CALLBACKS_V2. */
/**
* :member:`recv_origin` is a callback function which is invoked
* when a single origin in an ORIGIN frame is received. This field
* is available since v1.11.0.
*/
nghttp3_recv_origin recv_origin;
/**
* :member:`end_origin` is a callback function which is invoked when
* an ORIGIN frame has been completely processed. This field is
* available since v1.11.0.
*/
nghttp3_end_origin end_origin;
/**
* :member:`rand` is a callback function which is invoked when
* unpredictable data are needed. Although this field is optional
* due to the backward compatibility, it is recommended to specify
* this field to harden the runtime behavior against suspicious
* activities of a remote endpoint. This field is available since
* v1.11.0.
*/
nghttp3_rand rand;
} nghttp3_callbacks;

/**
Expand Down Expand Up @@ -2106,7 +2215,7 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn,
* control credit (both stream and connection) of underlying QUIC
* connection by that amount. It does not include the amount of data
* carried by DATA frame which contains application data (excluding
* any control or QPACK unidirectional streams) . See
* any control or QPACK unidirectional streams). See
* :type:`nghttp3_recv_data` to handle those bytes. If |fin| is
* nonzero, this is the last data from remote endpoint in this stream.
*
Expand Down Expand Up @@ -2480,8 +2589,6 @@ typedef struct nghttp3_data_reader {
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :macro:`NGHTTP3_ERR_INVALID_ARGUMENT`
* |stream_id| identifies unidirectional stream.
* :macro:`NGHTTP3_ERR_CONN_CLOSING`
* Connection is shutting down, and no new stream is allowed.
* :macro:`NGHTTP3_ERR_STREAM_IN_USE`
Expand Down
4 changes: 2 additions & 2 deletions deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*
* Version number of the nghttp3 library release.
*/
#define NGHTTP3_VERSION "1.6.0"
#define NGHTTP3_VERSION "1.11.0"

/**
* @macro
Expand All @@ -41,6 +41,6 @@
* number, 8 bits for minor and 8 bits for patch. Version 1.2.3
* becomes 0x010203.
*/
#define NGHTTP3_VERSION_NUM 0x010600
#define NGHTTP3_VERSION_NUM 0x010b00

#endif /* !defined(NGHTTP3_VERSION_H) */
12 changes: 12 additions & 0 deletions deps/ngtcp2/nghttp3/lib/nghttp3_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ size_t nghttp3_buf_cap(const nghttp3_buf *buf) {
return (size_t)(buf->end - buf->begin);
}

size_t nghttp3_buf_offset(const nghttp3_buf *buf) {
return (size_t)(buf->pos - buf->begin);
}

void nghttp3_buf_reset(nghttp3_buf *buf) { buf->pos = buf->last = buf->begin; }

int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem) {
Expand Down Expand Up @@ -87,4 +91,12 @@ void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf,
nghttp3_buf_type type) {
tbuf->buf = *buf;
tbuf->type = type;
tbuf->buf.begin = tbuf->buf.pos;
}

void nghttp3_typed_buf_shared_init(nghttp3_typed_buf *tbuf,
const nghttp3_buf *chunk) {
tbuf->buf = *chunk;
tbuf->type = NGHTTP3_BUF_TYPE_SHARED;
tbuf->buf.begin = tbuf->buf.pos = tbuf->buf.last;
}
19 changes: 18 additions & 1 deletion deps/ngtcp2/nghttp3/lib/nghttp3_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ void nghttp3_buf_wrap_init(nghttp3_buf *buf, uint8_t *src, size_t len);
*/
size_t nghttp3_buf_cap(const nghttp3_buf *buf);

/*
* nghttp3_buf_offset returns the distance from tbuf->begin to
* tbuf->pos. In other words, it returns buf->pos - buf->begin.
*/
size_t nghttp3_buf_offset(const nghttp3_buf *buf);

int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem);

/*
Expand All @@ -57,8 +63,12 @@ typedef enum nghttp3_buf_type {
memory. */
NGHTTP3_BUF_TYPE_SHARED,
/* NGHTTP3_BUF_TYPE_ALIEN indicates that the buffer points to a
memory which comes from outside of the library. */
memory which comes from outside of the library. When
acknowledged, acked_data callback is called. */
NGHTTP3_BUF_TYPE_ALIEN,
/* NGHTTP3_BUF_TYPE_ALIEN_NO_ACK is like NGHTTP3_BUF_TYPE_ALIEN, but
acked_data callback is not called. */
NGHTTP3_BUF_TYPE_ALIEN_NO_ACK,
} nghttp3_buf_type;

typedef struct nghttp3_typed_buf {
Expand All @@ -69,6 +79,13 @@ typedef struct nghttp3_typed_buf {
void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf,
nghttp3_buf_type type);

/*
* nghttp3_typed_buf_shared_init initializes |tbuf| of type
* NGHTTP3_BUF_TYPE_SHARED.
*/
void nghttp3_typed_buf_shared_init(nghttp3_typed_buf *tbuf,
const nghttp3_buf *chunk);

void nghttp3_typed_buf_free(nghttp3_typed_buf *tbuf);

#endif /* !defined(NGHTTP3_BUF_H) */
Loading
Loading