Compare commits

...

156 Commits

Author SHA1 Message Date
Sergey Kandaurov
5b8a5c08ce Core: added support for TCP keepalive parameters on macOS.
Some checks failed
buildbot / buildbot (push) Has been cancelled
The support first appeared in OS X Mavericks 10.9 and documented since
OS X Yosemite 10.10.

It has a subtle implementation difference from other operating systems
in that the TCP_KEEPALIVE socket option (used in place of TCP_KEEPIDLE)
isn't inherited from a listening socket to an accepted socket.

An apparent reason for this behaviour is that it might be preserved for
the sake of backward compatibility.  The TCP_KEEPALIVE socket option is
not inherited since appearance in OS X Panther 10.3, which long predates
two other TCP_KEEPINTVL and TCP_KEEPCNT socket options.

Thanks to Andy Pan for initial work.
2025-05-27 01:59:02 +04:00
Aleksei Bavshin
3d5889a3ee SSL: disabled UI console prompts from worker processes.
Certain providers may attempt to reload the key on the first use after a
fork.  Such attempt would require re-prompting the pin, and this time we
are not able to pass the password callback.

While it is addressable with configuration for a specific provider, it would
be prudent to ensure that no such prompts could block worker processes by
setting the default UI method.

UI_null() first appeared in 1.1.1 along with the OSSL_STORE, so it is safe
to assume the same set of guards.
2025-05-26 06:56:18 -07:00
Aleksei Bavshin
0fdbfc1ff4 SSL: support loading keys via OSSL_STORE.
A new "store:..." prefix for the "ssl_certificate_key" directive allows
loading keys via the OSSL_STORE API.

The change is required to support hardware backed keys in OpenSSL 3.x using
the new "provider(7ossl)" modules, such as "pkcs11-provider".  While the
engine API is present in 3.x, some operating systems (notably, RHEL10)
have already disabled it in their builds of OpenSSL.

Related: https://trac.nginx.org/nginx/ticket/2449
2025-05-26 06:56:18 -07:00
Sergey Kandaurov
6a134dfd48 QUIC: using QUIC API introduced in OpenSSL 3.5.
Similarly to the QUIC API originated in BoringSSL, this API allows
to register custom TLS callbacks for an external QUIC implementation.
See the SSL_set_quic_tls_cbs manual page for details.

Due to a different approach used in OpenSSL 3.5, handling of CRYPTO
frames was streamlined to always write an incoming CRYPTO buffer to
the crypto context.  Using SSL_provide_quic_data(), this results in
transient allocation of chain links and buffers for CRYPTO frames
received in order.  Testing didn't reveal performance degradation of
QUIC handshakes, https://github.com/nginx/nginx/pull/646 provides
specific results.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
1d4d2f2c96 QUIC: better approach for premature handshake completion.
Using SSL_in_init() to inspect a handshake state was replaced with
SSL_is_init_finished().  This represents a more complete fix to the
BoringSSL issue addressed in 22671b37e.

This provides awareness of the early data handshake state when using
OpenSSL 3.5 TLS callbacks in 0-RTT enabled configurations, which, in
particular, is used to avoid premature completion of the initial TLS
handshake, before required client handshake messages are received.

This is a non-functional change when using BoringSSL.  It supersedes
testing non-positive SSL_do_handshake() results in all supported SSL
libraries, hence simplified.

In preparation for using OpenSSL 3.5 TLS callbacks.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
bcb9d3fd2c QUIC: ssl_encryption_level_t abstraction layer.
Encryption level values are decoupled from ssl_encryption_level_t,
which is now limited to BoringSSL QUIC callbacks, with mappings
provided.  Although the values match, this provides a technically
safe approach, in particular, to access protection level sized arrays.

In preparation for using OpenSSL 3.5 TLS callbacks.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
9857578f15 QUIC: factored out SSL_provide_quic_data() to the helper function.
It is now called from ngx_quic_handle_crypto_frame(), prior to proceeding
with the handshake.  With this logic removed, the handshake function is
renamed to ngx_quic_handshake() to better match ngx_ssl_handshake().
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
e561f7dbcf QUIC: defined SSL API macros in a single place.
All definitions now set in ngx_event_quic.h, this includes moving
NGX_QUIC_OPENSSL_COMPAT from autotests to compile time.  Further,
to improve code readability, a new NGX_QUIC_QUICTLS_API macro is
used for QuicTLS that provides old BoringSSL QUIC API.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
54e6b7cfee QUIC: logging missing mandatory TLS extensions only once.
Previously, they might be logged on every add_handshake_data
callback invocation when using OpenSSL compat layer and processing
coalesced handshake messages.

Further, the ALPN error message is adjusted to signal the missing
extension.  Possible reasons were previously narrowed down with
ebb6f7d65 changes in the ALPN callback that is invoked earlier in
the handshake.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
5d7fd4a7e3 QUIC: reset qc->error to zero again.
Following the previous change that removed posting a close event
in OpenSSL compat layer, now ngx_quic_close_connection() is always
called on error path with either NGX_ERROR or qc->error set.

This allows to remove a special value -1 served as a missing error,
which simplifies the code.  Partially reverts d3fb12d77.

Also, this improves handling of the draining connection state, which
consists of posting a close event with NGX_OK and no qc->error set,
where it was previously converted to NGX_QUIC_ERR_INTERNAL_ERROR.
Notably, this is rather a cosmetic fix, because drained connections
do not send any packets including CONNECTION_CLOSE, and qc->error
is not otherwise used.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
7468a10b62 QUIC: adjusted handling of callback errors.
Changed handshake callbacks to always return success.  This allows to avoid
logging SSL_do_handshake() errors with empty or cryptic "internal error"
OpenSSL error messages at the inappropriate "crit" log level.

Further, connections with failed callbacks are closed now right away when
using OpenSSL compat layer.  This change supersedes and reverts c37fdcdd1,
with the conditions to check callbacks invocation kept to slightly improve
code readability of control flow; they are optimized out in the resulting
assembly code.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
47f96993f6 QUIC: logging of SSL library errors.
Logging level for such errors, which should not normally happen,
is changed to NGX_LOG_ALERT, and ngx_log_error() is replaced with
ngx_ssl_error() for consistency with the rest of the code.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
ef9cd3214f QUIC: logging level of handshake errors.
Various errors reported by SSL_do_handshake() are now logged at the
"info" or "crit" level, akin to handshakes on regular TCP connections.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
aa43385ffa QUIC: removed ALPN feature test.
ALPN support is present in all libraries that have QUIC support,
it is safe to compile it unconditionally.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
39b1e3fe9d QUIC: removed excessive casts for ngx_ssl_get_connection().
They were blindly copied from ngx_ssl_info_callback(), where
the ngx_ssl_conn_t pointer is passed with const qualifier.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
335993154c QUIC: removed level field from ngx_quic_compat_record_t.
It was made unused in d15f8f2 after introducing reusable crypto contexts.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
f3542500b6 QUIC: do not block ACKs by congestion control.
Some checks failed
buildbot / buildbot (push) Has been cancelled
Previously, it was not possible to send acknowledgments if the
congestion window was limited or temporarily exceeded, such as
after sending a large response or MTU probe.  If ACKs were not
received from the peer for some reason to update the in-flight
bytes counter below the congestion window, this might result in
a stalled connection.

The fix is to send ACKs regardless of congestion control.  This
meets RFC 9002, Section 7:
: Similar to TCP, packets containing only ACK frames do not count
: toward bytes in flight and are not congestion controlled.

This is a simplified implementation to send ACK frames from the
head of the queue.  This was made possible after 6f5f17358.

Reported in trac ticket #2621 and subsequently by Vladimir Homutov:
https://mailman.nginx.org/pipermail/nginx-devel/2025-April/ZKBAWRJVQXSZ2ISG3YJAF3EWMDRDHCMO.html
2025-04-29 19:53:41 +04:00
Sergey Kandaurov
adda704158 SSL: fixed build with OPENSSL_NO_DH. 2025-04-25 14:56:31 +04:00
Sergey Kandaurov
4f8bc0b282 SSL: fixed build with OPENSSL_NO_DEPRECATED. 2025-04-25 14:56:31 +04:00
nandsky
9785db9bd5 QUIC: fixed a typo. 2025-04-23 11:53:51 +04:00
Aleksei Bavshin
020b1db7eb Win32: added detection of ARM64 target.
This extends the target selection implemented in dad6ec3aa6 to support
Windows ARM64 platforms.  OpenSSL support for VC-WIN64-ARM target first
appeared in 1.1.1 and is present in all currently supported (3.x)
branches.

As a side effect, ARM64 Windows builds will get 16-byte alignment along
with the rest of non-x86 platforms.  This is safe, as malloc on 64-bit
Windows guarantees the fundamental alignment of allocations, 16 bytes.
2025-04-18 12:57:26 -07:00
Aleksei Bavshin
b9d0ba6677 Core: improved NGX_ALIGNMENT detection on some x86_64 platforms.
Previously, the default pool alignment used sizeof(unsigned long), with
the expectation that this would match to a platform word size.  Certain
64-bit platforms prove this assumption wrong by keeping the 32-bit long
type, which is fully compliant with the C standard.

This introduces a possibility of suboptimal misaligned access to the
data allocated with ngx_palloc() on the affected platforms, which is
addressed here by changing the default NGX_ALIGNMENT to a pointer size.

As we override the detection in auto/os/conf for all the machine types
except x86, and Unix-like 64-bit systems prefer the 64-bit long, the
impact of the change should be limited to Win64 x64.
2025-04-18 12:57:26 -07:00
Roman Arutyunyan
0f9f43b79e HTTP/3: fixed NGX_HTTP_V3_VARLEN_INT_LEN value.
After fixing ngx_http_v3_encode_varlen_int() in 400eb1b628,
NGX_HTTP_V3_VARLEN_INT_LEN retained the old value of 4, which is
insufficient for the values over 1073741823 (1G - 1).

The NGX_HTTP_V3_VARLEN_INT_LEN macro is used in ngx_http_v3_uni.c to
format stream and frame types.  Old buffer size is enough for formatting
this data.  Also, the macro is used in ngx_http_v3_filter_module.c to
format output chunks and trailers.  Considering output_buffers and
proxy_buffer_size are below 1G in all realistic scenarios, the old buffer
size is enough here as well.
2025-04-18 15:28:00 +04:00
Roman Arutyunyan
444954abac Fixed -Wunterminated-string-initialization with gcc15. 2025-04-17 19:12:59 +04:00
Roman Arutyunyan
04813dac86 QUIC: lowered log level for unsupported transport parameters. 2025-04-17 12:51:17 +04:00
Roman Arutyunyan
0626e60a75 Version bump. 2025-04-16 18:55:19 +04:00
Sergey Kandaurov
6ac8b69f06 nginx-1.27.5-RELEASE 2025-04-16 16:01:11 +04:00
Roman Arutyunyan
aa49a416b8 QUIC: dynamic packet threshold.
RFC 9002, Section 6.1.1 defines packet reordering threshold as 3.  Testing
shows that such low value leads to spurious packet losses followed by
congestion window collapse.  The change implements dynamic packet threshold
detection based on in-flight packet range.  Packet threshold is defined
as half the number of in-flight packets, with mininum value of 3.

Also, renamed ngx_quic_lost_threshold() to ngx_quic_time_threshold()
for better compliance with RFC 9002 terms.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
2fb32ff24d QUIC: optimized connection frame threshold.
Previosly the threshold was hardcoded at 10000.  This value is too low for
high BDP networks.  For example, if all frames are STREAM frames, and MTU
is 1500, the upper limit for congestion window would be roughly 15M
(10000 * 1500).  With 100ms RTT it's just a 1.2Gbps network (15M * 10 * 8).
In reality, the limit is even lower because of other frame types.  Also,
the number of frames that could be used simultaneously depends on the total
amount of data buffered in all server streams, and client flow control.

The change sets frame threshold based on max concurrent streams and stream
buffer size, the product of which is the maximum number of in-flight stream
data in all server streams at any moment.  The value is divided by 2000 to
account for a typical MTU 1500 and the fact that not all frames are STREAM
frames.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
f9a7e7cc11 QUIC: CUBIC congestion control. 2025-04-15 19:01:36 +04:00
Roman Arutyunyan
a40cc70023 QUIC: ignore congestion control when sending MTU probes.
If connection is network-limited, MTU probes have little chance of being
sent since congestion window is almost always full.  As a result, PMTUD
may not be able to reach the real MTU and the connection may operate with
a reduced MTU.  The solution is to ignore the congestion window.  This may
lead to a temporary increase in in-flight count beyond congestion window.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
6bf13e9d57 QUIC: do not shrink congestion window after losing an MTU probe.
As per RFC 9000, Section 14.4:

    Loss of a QUIC packet that is carried in a PMTU probe is therefore
    not a reliable indication of congestion and SHOULD NOT trigger a
    congestion control reaction.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
cd5e4fa144 QUIC: do not increase underutilized congestion window.
As per RFC 9002, Section 7.8, congestion window should not be increased
when it's underutilized.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
04c65ccd9a QUIC: all-levels commit and revert functions.
Previously, these functions operated on a per-level basis.  This however
resulted in excessive logging of in_flight and will also led to extra
work detecting underutilized congestion window in the followup patches.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
1e883a40db QUIC: ngx_msec_t overflow protection.
On some systems the value of ngx_current_msec is derived from monotonic
clock, for which the following is defined by POSIX:

   For this clock, the value returned by clock_gettime() represents
   the amount of time (in seconds and nanoseconds) since an unspecified
   point in the past.

As as result, overflow protection is needed when comparing two ngx_msec_t.
The change adds such protection to the ngx_quic_detect_lost() function.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
38236bf74f QUIC: prevent spurious congestion control recovery mode.
Since recovery_start field was initialized with ngx_current_msec, all
congestion events that happened within the same millisecond or cycle
iteration, were treated as in recovery mode.

Also, when handling persistent congestion, initializing recovery_start
with ngx_current_msec resulted in treating all sent packets as in recovery
mode, which violates RFC 9002, see example in Appendix B.8.

While here, also fixed recovery_start wrap protection.  Previously it used
2 * max_idle_timeout time frame for all sent frames, which is not a
reliable protection since max_idle_timeout is unrelated to congestion
control.  Now recovery_start <= now condition is enforced.  Note that
recovery_start wrap is highly unlikely and can only occur on a
32-bit system if there are no congestion events for 24 days.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
53e7e9eb54 QUIC: use path MTU in congestion window computations.
As per RFC 9002, Section B.2, max_datagram_size used in congestion window
computations should be based on path MTU.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
3a97111adf HTTP/3: graceful shutdown on keepalive timeout expiration.
Previously, the expiration caused QUIC connection finalization even if
there are application-terminated streams finishing sending data.  Such
finalization terminated these streams.

An easy way to trigger this is to request a large file from HTTP/3 over
a small MTU.  In this case keepalive timeout expiration may abruptly
terminate the request stream.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
2b8b70068a QUIC: graph-friendly congestion control logging.
Improved logging for simpler data extraction for plotting congestion
window graphs.  In particular, added current milliseconds number from
ngx_current_msec.

While here, simplified logging text and removed irrelevant data.
2025-04-15 19:01:36 +04:00
Sergey Kandaurov
b6e7eb0f57 SSL: external groups support in $ssl_curve and $ssl_curves.
Starting with OpenSSL 3.0, groups may be added externally with pluggable
KEM providers.  Using SSL_get_negotiated_group(), which makes lookup in a
static table with known groups, doesn't allow to list such groups by names
leaving them in hex.  Adding X25519MLKEM768 to the default group list in
OpenSSL 3.5 made this problem more visible.  SSL_get0_group_name() and,
apparently, SSL_group_to_name() allow to resolve such provider-implemented
groups, which is also "generally preferred" over SSL_get_negotiated_group()
as documented in OpenSSL git commit 93d4f6133f.

This change makes external groups listing by name using SSL_group_to_name()
available since OpenSSL 3.0.  To preserve "prime256v1" naming for the group
0x0017, and to avoid breaking BoringSSL and older OpenSSL versions support,
it is used supplementary for a group that appears to be unknown.

See https://github.com/openssl/openssl/issues/27137 for related discussion.
2025-04-10 18:51:10 +04:00
Sergey Kandaurov
6c3a9d5612 Upstream: fixed passwords support for dynamic certificates.
Passwords were not preserved in optimized SSL contexts, the bug had
appeared in d791b4aab (1.23.1), as in the following configuration:

    server {
        proxy_ssl_password_file password;
        proxy_ssl_certificate $ssl_server_name.crt;
        proxy_ssl_certificate_key $ssl_server_name.key;

        location /original/ {
            proxy_pass https://u1/;
        }

        location /optimized/ {
            proxy_pass https://u2/;
        }
    }

The fix is to always preserve passwords, by copying to the configuration
pool, if dynamic certificates are used.  This is done as part of merging
"ssl_passwords" configuration.

To minimize the number of copies, a preserved version is then used for
inheritance.  A notable exception is inheritance of preserved empty
passwords to the context with statically configured certificates:

    server {
        proxy_ssl_certificate $ssl_server_name.crt;
        proxy_ssl_certificate_key $ssl_server_name.key;

        location / {
            proxy_pass ...;

            proxy_ssl_certificate example.com.crt;
            proxy_ssl_certificate_key example.com.key;
        }
    }

In this case, an unmodified version (NULL) of empty passwords is set,
to allow reading them from the password prompt on nginx startup.

As an additional optimization, a preserved instance of inherited
configured passwords is set to the previous level, to inherit it
to other contexts:

    server {
        proxy_ssl_password_file password;

        location /1/ {
            proxy_pass https://u1/;
            proxy_ssl_certificate $ssl_server_name.crt;
            proxy_ssl_certificate_key $ssl_server_name.key;
        }

        location /2/ {
            proxy_pass https://u2/;
            proxy_ssl_certificate $ssl_server_name.crt;
            proxy_ssl_certificate_key $ssl_server_name.key;
        }
    }
2025-04-10 17:27:45 +04:00
Sergey Kandaurov
a813c63921 Charset filter: improved validation of charset_map with utf-8.
It was possible to write outside of the buffer used to keep UTF-8
decoded values when parsing conversion table configuration.

Since this happened before UTF-8 decoding, the fix is to check in
advance if character codes are of more than 3-byte sequence.  Note
that this is already enforced by a later check for ngx_utf8_decode()
decoded values for 0xffff, which corresponds to the maximum value
encoded as a valid 3-byte sequence, so the fix does not affect the
valid values.

Found with AddressSanitizer.
Fixes GitHub issue #529.
2025-04-09 19:37:51 +04:00
Sergey Kandaurov
d313056537 Slice filter: improved memory allocation error handling.
As uncovered by recent addition in slice.t, a partially initialized
context, coupled with HTTP 206 response from stub backend, might be
accessed in the next slice subrequest.

Found by bad memory allocator simulation.
2025-03-10 19:32:07 +03:00
Sergey Kandaurov
d16251969b SSL: removed stale comments.
It appears to be a relic from prototype locking removed in b0b7b5a35.
2025-02-26 17:40:03 +04:00
Sergey Kandaurov
311c390377 SSL: improved logging of saving sessions from upstream servers.
This makes it easier to understand why sessions may not be saved
in shared memory due to size.
2025-02-26 17:40:03 +04:00
Sergey Kandaurov
9124592202 SSL: raised limit for sessions stored in shared memory.
Upstream SSL sessions may be of a noticeably larger size with tickets
in TLSv1.2 and older versions, or with "stateless" tickets in TLSv1.3,
if a client certificate is saved into the session.  Further, certain
stateless session resumption implemetations may store additional data.

Such one is JDK, known to also include server certificates in session
ticket data, which roughly doubles a decoded session size to slightly
beyond the previous limit.  While it's believed to be an issue on the
JDK side, this change allows to save such sessions.

Another, innocent case is using RSA certificates with 8192 key size.
2025-02-26 17:40:03 +04:00
Sergey Kandaurov
3d7304b527 SSL: using static storage for NGX_SSL_MAX_SESSION_SIZE buffers.
All such transient buffers are converted to the single storage in BSS.

In preparation to raise the limit.
2025-02-26 17:40:03 +04:00
Sergey Kandaurov
b11ae4cfc9 SSL: style. 2025-02-26 17:40:03 +04:00
Sergey Kandaurov
d25139db01 Improved ngx_http_subrequest() error handling.
Some checks failed
buildbot / buildbot (push) Has been cancelled
Previously, request might be left in inconsistent state in case of error,
which manifested in "http request count is zero" alerts when used by SSI
filter.

The fix is to reshuffle initialization order to postpone committing state
changes until after any potentially failing parts.

Found by bad memory allocator simulation.
2025-02-21 00:04:12 +04:00
Orgad Shaneh
f51e2de6fe Add gitignore file.
Some checks are pending
buildbot / buildbot (push) Waiting to run
2025-02-20 14:42:53 +03:00
Thierry Bastian
3327353ec0 Configure: MSVC compatibility with PCRE2 10.45.
Some checks failed
buildbot / buildbot (push) Has been cancelled
2025-02-18 19:07:11 +04:00
Piotr Sikora
9a4090f02a Core: fix build without libcrypt.
libcrypt is no longer part of glibc, so it might not be available.

Signed-off-by: Piotr Sikora <piotr@aviatrix.com>
2025-02-18 16:18:10 +03:00
Sergey Kandaurov
f274b3f72f Version bump. 2025-02-18 15:49:18 +04:00
Sergey Kandaurov
ecb809305e nginx-1.27.4-RELEASE
Some checks failed
buildbot / buildbot (push) Has been cancelled
2025-02-05 20:13:42 +04:00
Sergey Kandaurov
46b9f5d389 SNI: added restriction for TLSv1.3 cross-SNI session resumption.
In OpenSSL, session resumption always happens in the default SSL context,
prior to invoking the SNI callback.  Further, unlike in TLSv1.2 and older
protocols, SSL_get_servername() returns values received in the resumption
handshake, which may be different from the value in the initial handshake.
Notably, this makes the restriction added in b720f650b insufficient for
sessions resumed with different SNI server name.

Considering the example from b720f650b, previously, a client was able to
request example.org by presenting a certificate for example.org, then to
resume and request example.com.

The fix is to reject handshakes resumed with a different server name, if
verification of client certificates is enabled in a corresponding server
configuration.
2025-02-05 20:11:42 +04:00
Roman Arutyunyan
22a2a225ba Added "keepalive_min_timeout" directive.
Some checks are pending
buildbot / buildbot (push) Waiting to run
The directive sets a timeout during which a keepalive connection will
not be closed by nginx for connection reuse or graceful shutdown.

The change allows clients that send multiple requests over the same
connection without delay or with a small delay between them, to avoid
receiving a TCP RST in response to one of them.  This excludes network
issues and non-graceful shutdown.  As a side-effect, it also addresses
the TCP reset problem described in RFC 9112, Section 9.6, when the last
sent HTTP response could be damaged by a followup TCP RST.  It is important
for non-idempotent requests, which cannot be retried by client.

It is not recommended to set keepalive_min_timeout to large values as
this can introduce an additional delay during graceful shutdown and may
restrict nginx from effective connection reuse.
2025-02-05 13:08:01 +03:00
Sergey Kandaurov
04914cfbcb Misc: moved documentation in generated ZIP archive.
Some checks failed
buildbot / buildbot (push) Has been cancelled
The recently added GitHub files now reside in the docs directory.
2025-01-30 18:21:43 +04:00
Sergey Kandaurov
e715202220 Configure: fixed --with-libatomic=DIR with recent libatomic_ops.
The build location of the resulting libatomic_ops.a was changed in v7.4.0
after converting libatomic_ops to use libtool.  The fix is to use library
from the install path, this allows building with both old and new versions.

Initially reported here:
https://mailman.nginx.org/pipermail/nginx/2018-April/056054.html
2025-01-30 17:16:10 +04:00
Aleksei Bavshin
64d0795ac4 QUIC: added missing casts in iov_base assignments.
Some checks failed
buildbot / buildbot (push) Has been cancelled
This is consistent with the rest of the code and fixes build on systems
with non-standard definition of struct iovec (Solaris, Illumos).
2025-01-28 08:00:42 -08:00
Pavel Pautov
5ab4f32e9d Upstream: fixed --with-compat build without SSL, broken by 454ad0e.
Some checks failed
buildbot / buildbot (push) Has been cancelled
2025-01-23 10:50:13 -08:00
Sergey Kandaurov
5d5d9adccf SSL: avoid using mismatched certificate/key cached pairs.
Some checks failed
buildbot / buildbot (push) Has been cancelled
This can happen with certificates and certificate keys specified
with variables due to partial cache update in various scenarios:
- cache expiration with only one element of pair evicted
- on-disk update with non-cacheable encrypted keys
- non-atomic on-disk update

The fix is to retry with fresh data on X509_R_KEY_VALUES_MISMATCH.
2025-01-17 04:37:46 +04:00
Sergey Kandaurov
454ad0ef33 Upstream: caching certificates and certificate keys with variables.
Caching is enabled with proxy_ssl_certificate_cache and friends.

Co-authored-by: Aleksei Bavshin <a.bavshin@nginx.com>
2025-01-17 04:37:46 +04:00
Sergey Kandaurov
4b96ad14f3 SSL: cache revalidation of file based dynamic certificates.
Revalidation is based on file modification time and uniq file index,
and happens after the cache object validity time is expired.
2025-01-17 04:37:46 +04:00
Sergey Kandaurov
0e756d67aa SSL: caching certificates and certificate keys with variables.
A new directive "ssl_certificate_cache max=N [valid=time] [inactive=time]"
enables caching of SSL certificate chain and secret key objects specified
by "ssl_certificate" and "ssl_certificate_key" directives with variables.

Co-authored-by: Aleksei Bavshin <a.bavshin@nginx.com>
2025-01-17 04:37:46 +04:00
Sergey Kandaurov
7677d5646a SSL: encrypted certificate keys are exempt from object cache.
SSL object cache, as previously introduced in 1.27.2, did not take
into account encrypted certificate keys that might be unexpectedly
fetched from the cache regardless of the matching passphrase.  To
avoid this, caching of encrypted certificate keys is now disabled
based on the passphrase callback invocation.

A notable exception is encrypted certificate keys configured without
ssl_password_file.  They are loaded once resulting in the passphrase
prompt on startup and reused in other contexts as applicable.
2025-01-17 04:37:46 +04:00
Sergey Kandaurov
8311e14ae6 SSL: object cache inheritance from the old configuration cycle.
Memory based objects are always inherited, engine based objects are
never inherited to adhere the volatile nature of engines, file based
objects are inherited subject to modification time and file index.

The previous behaviour to bypass cache from the old configuration cycle
is preserved with a new directive "ssl_object_cache_inheritable off;".
2025-01-17 04:37:46 +04:00
Daniel Vasquez Lopez
47f862ffad Slice filter: log the expected range in case of range error.
Some checks are pending
buildbot / buildbot (push) Waiting to run
2025-01-16 21:09:59 +04:00
Sergey Kandaurov
57d54fd922 Gzip: compatibility with recent zlib-ng 2.2.x versions.
Some checks failed
buildbot / buildbot (push) Has been cancelled
It now uses 5/4 times more memory for the pending buffer.

Further, a single allocation is now used, which takes additional 56 bytes
for deflate_allocs in 64-bit mode aligned to 16, to store sub-allocation
pointers, and the total allocation size now padded up to 128 bytes, which
takes theoretically 200 additional bytes in total.  This fits though into
"4 * (64 + sizeof(void*))" additional space for ZALLOC used in zlib-ng
2.1.x versions.  The comment was updated to reflect this.
2025-01-09 17:19:24 +04:00
Roman Arutyunyan
febe6e728f Year 2025. 2025-01-09 17:08:02 +04:00
Roman Arutyunyan
e3a9b6ad08 QUIC: fixed accessing a released stream.
Some checks failed
buildbot / buildbot (push) Has been cancelled
While trying to close a stream in ngx_quic_close_streams() by calling its
read event handler, the next stream saved prior to that could be destroyed
recursively.  This caused a segfault while trying to access the next stream.

The way the next stream could be destroyed in HTTP/3 is the following.
A request stream read event handler ngx_http_request_handler() could
end up calling ngx_http_v3_send_cancel_stream() to report a cancelled
request stream in the decoder stream.  If sending stream cancellation
decoder instruction fails for any reason, and the decoder stream is the
next in order after the request stream, the issue is triggered.

The fix is to postpone calling read event handlers for all streams being
closed to avoid closing a released stream.
2024-12-27 16:14:14 +04:00
Roman Arutyunyan
a52ba8ba0e QUIC: ignore version negotiation packets.
Some checks are pending
buildbot / buildbot (push) Waiting to run
Previously, such packets were treated as long header packets with unknown
version 0, and a version negotiation packet was sent in response.  This
could be used to set up an infinite traffic reflect loop with another nginx
instance.

Now version negotiation packets are ignored.  As per RFC 9000, Section 6.1:

  An endpoint MUST NOT send a Version Negotiation packet in response to
  receiving a Version Negotiation packet.
2024-12-26 18:58:05 +04:00
Jordan Zebor
c73fb273ac Updated security policy to clarify experimental features.
Some checks failed
buildbot / buildbot (push) Has been cancelled
The original security policy language did not capture the scope
as intended for experimental features and availability.
2024-12-23 20:36:15 +04:00
nandsky
930caed3bf QUIC: fixed client request timeout in 0-RTT scenarios.
Some checks failed
buildbot / buildbot (push) Has been cancelled
Since 0-RTT and 1-RTT data exist in the same packet number space,
ngx_quic_discard_ctx incorrectly discards 1-RTT packets when
0-RTT keys are discarded.

The issue was introduced by 58b92177e7.
2024-12-10 17:17:20 +04:00
Roman Arutyunyan
e28ef42b97 Version bump.
Some checks failed
buildbot / buildbot (push) Has been cancelled
2024-11-27 20:07:29 +04:00
Sergey Kandaurov
e7bd255745 nginx-1.27.3-RELEASE
Some checks are pending
buildbot / buildbot (push) Waiting to run
2024-11-26 19:55:00 +04:00
Sergey Kandaurov
ce88b17123 Mail: handling of LOGIN IMAP command untagged response.
Some checks are pending
buildbot / buildbot (push) Waiting to run
In particular, an untagged CAPABILITY response as described in the
interim RFC 3501 internet drafts was seen in various IMAP servers.
Previously resulted in a broken connection, now an untagged response
is proxied to client.
2024-11-26 19:07:17 +04:00
Roman Arutyunyan
b2a67d2614 Realip: allowed square brackets with portless IPv6 address.
When client address is received, IPv6 address could be specified without
square brackets and without port, as well as both with the brackets and
port.  The change allows IPv6 in square brackets and no port, which was
previously considered an error.  This format conforms to RFC 3986.

The change also affects proxy_bind and friends.
2024-11-26 18:27:07 +04:00
Sergey Kandaurov
3f755b5a9e QUIC: got rid of memory copy when initializing constant values. 2024-11-26 17:41:21 +04:00
Sergey Kandaurov
9a025219f6 QUIC: constified nonce parameter of crypto functions.
This follows OpenSSL and BoringSSL API, and gives a hint to compiler
that this parameter may not be modified.
2024-11-26 17:41:21 +04:00
Sergey Kandaurov
a448dd52ee Upstream: disallow empty path in proxy_store and friends.
Some checks are pending
buildbot / buildbot (push) Waiting to run
Renaming a temporary file to an empty path ("") returns NGX_ENOPATH
with a subsequent ngx_create_full_path() to create the full path.
This function skips initial bytes as part of path separator lookup,
which causes out of bounds access on short strings.

The fix is to avoid renaming a temporary file to an obviously invalid
path, as well as explicitly forbid such syntax for literal values.

Although Coverity reports about potential type underflow, it is not
actually possible because the terminating '\0' is always included.

Notably, the run-time check is sufficient enough for Win32 as well.
Other short invalid values result either in NGX_ENOENT or NGX_EEXIST
and "MoveFile() .. failed" critical log messages, which involves a
separate error handling.

Prodded by Coverity (CID 1605485).
2024-11-25 17:37:11 +04:00
Roman Arutyunyan
0864cca4d7 QUIC: prevented BIO leak in case of error. 2024-11-25 16:22:40 +04:00
Sergey Kandaurov
476d6526b2 SSL: a new macro to set default protocol versions.
Some checks failed
buildbot / buildbot (push) Has been cancelled
This simplifies merging protocol values after ea15896 and ebd18ec.

Further, as outlined in ebd18ec18, for libraries preceeding TLSv1.2+
support, only meaningful versions TLSv1 and TLSv1.1 are set by default.

While here, fixed indentation.
2024-11-22 13:47:22 +04:00
Roman Arutyunyan
569948aa12 Mp4: prevent chunk index underflow.
Some checks are pending
buildbot / buildbot (push) Waiting to run
When cropping stsc atom, it's assumed that chunk index is never 0.
Based on this assumption, start_chunk and end_chunk are calculated
by subtracting 1 from it.  If chunk index is zero, start_chunk or
end_chunk may underflow, which will later trigger
"start/end time is out mp4 stco chunks" error.  The change adds an
explicit check for zero chunk index to avoid underflow and report
a proper error.

Zero chunk index is explicitly banned in ISO/IEC 14496-12, 8.7.4
Sample To Chunk Box.  It's also implicitly banned in QuickTime File
Format specification.  Description of chunk offset table references
"Chunk 1" as the first table element.
2024-11-21 16:08:48 +04:00
Roman Arutyunyan
d1a02451c3 Mp4: unordered stsc chunks error for the final chunk.
Currently an error is triggered if any of the chunk runs in stsc are
unordered.  This however does not include the final chunk run, which
ends with trak->chunks + 1.  The previous chunk index can be larger
leading to a 32-bit overflow.  This could allow to skip the validity
check "if (start_sample > n)".  This could later lead to a large
trak->start_chunk/trak->end_chunk, which would be caught later in
ngx_http_mp4_update_stco_atom() or ngx_http_mp4_update_co64_atom().

While there are no implications of the validity check being avoided,
the change still adds a check to ensure the final chunk run is ordered,
to produce a meaningful error and avoid a potential integer overflow.
2024-11-21 16:08:48 +04:00
Roman Arutyunyan
6ec099a378 Mp4: fixed handling an empty run of chunks in stsc atom.
A specially crafted mp4 file with an empty run of chunks in the stsc atom
and a large value for samples per chunk for that run, combined with a
specially crafted request, allowed to store that large value in prev_samples
and later in trak->end_chunk_samples while in ngx_http_mp4_crop_stsc_data().
Later in ngx_http_mp4_update_stsz_atom() this could result in buffer
overread while calculating trak->end_chunk_samples_size.

Now the value of samples per chunk specified for an empty run is ignored.
2024-11-21 16:08:48 +04:00
Nathan Mentze
cb1857407b Fixed missing double quote.
Some checks failed
buildbot / buildbot (push) Has been cancelled
2024-11-20 15:30:05 +04:00
Sergey Kandaurov
0ebc3242d9 SSL: error message default in object caching API.
Some checks are pending
buildbot / buildbot (push) Waiting to run
This change initializes the "err" variable, used to produce a meaningful
diagnostics on error path, to a good safe value.
2024-11-19 21:37:03 +04:00
Andy Pan
7cd60cd475 On DragonFly BSD 5.8+, TCP_KEEPIDLE and TCP_KEEPINTVL are in secs.
Some checks are pending
buildbot / buildbot (push) Waiting to run
2024-11-19 00:30:47 +04:00
Dan Callahan
36ca44f26f Fixed link to contributing guidelines.
Some checks failed
buildbot / buildbot (push) Has been cancelled
Absolute paths in links end up being rooted at github.com.
The contributing guidelines link is broken unless we use the full URL.
Also, remove superfluous "monospace formatting" for the link.
2024-11-12 07:30:08 -08:00
Sergey Kandaurov
d10bf73eba Uwsgi: added create_loc_conf comments. 2024-11-12 17:21:22 +04:00
Sergey Kandaurov
1ac6a18585 SCGI: added create_loc_conf comments. 2024-11-12 17:21:22 +04:00
Sergey Kandaurov
a5e152b3d9 FastCGI: fixed create_loc_conf comments after 05b1a8f1e. 2024-11-12 17:21:22 +04:00
蕭澧邦
ea15896c1a SSL: fixed MSVC compilation after ebd18ec181.
Some checks are pending
buildbot / buildbot (push) Waiting to run
MSVC generates a compilation error in case #if/#endif is used in a macro
parameter.
2024-11-11 22:29:55 +04:00
Mini Hawthorne
29aec5720f Upstream: copy upstream zone DNS valid time during config reload.
Previously, all upstream DNS entries would be immediately re-resolved
on config reload.  With a large number of upstreams, this creates
a spike of DNS resolution requests.  These spikes can overwhelm the
DNS server or cause drops on the network.

This patch retains the TTL of previous resolutions across reloads
by copying each upstream's name's expiry time across configuration
cycles.  As a result, no additional resolutions are needed.
2024-11-07 07:57:42 -08:00
Vladimir Homutov
ea4654550a Upstream: per-upstream resolver.
The "resolver" and "resolver_timeout" directives can now be specified
directly in the "upstream" block.
2024-11-07 07:57:42 -08:00
Ruslan Ermilov
5ebe7a4122 Upstream: pre-resolve servers on reload.
After configuration is reloaded, it may take some time for the
re-resolvable upstream servers to resolve and become available
as peers.  During this time, client requests might get dropped.

Such servers are now pre-resolved using the "cache" of already
resolved peers from the old shared memory zone.
2024-11-07 07:57:42 -08:00
Ruslan Ermilov
1524c5e3fc Core: inheritance of non-reusable shared memory zones.
When re-creating a non-reusable zone, make the pointer to the old zone
available during the new zone initialization.
2024-11-07 07:57:42 -08:00
Dmitry Volyntsev
9fe119b431 Upstream: construct upstream peers from DNS SRV records. 2024-11-07 07:57:42 -08:00
Ruslan Ermilov
db6870e06d Upstream: re-resolvable servers.
Specifying the upstream server by a hostname together with the
"resolve" parameter will make the hostname to be periodically
resolved, and upstream servers added/removed as necessary.

This requires a "resolver" at the "http" configuration block.

The "resolver_timeout" parameter also affects when the failed
DNS requests will be attempted again.  Responses with NXDOMAIN
will be attempted again in 10 seconds.

Upstream has a configuration generation number that is incremented each
time servers are added/removed to the primary/backup list.  This number
is remembered by the peer.init method, and if peer.get detects a change
in configuration, it returns NGX_BUSY.

Each server has a reference counter.  It is incremented by peer.get and
decremented by peer.free.  When a server is removed, it is removed from
the list of servers and is marked as "zombie".  The memory allocated by
a zombie peer is freed only when its reference count becomes zero.

Co-authored-by: Roman Arutyunyan <arut@nginx.com>
Co-authored-by: Sergey Kandaurov <pluknet@nginx.com>
Co-authored-by: Vladimir Homutov <vl@nginx.com>
2024-11-07 07:57:42 -08:00
Sergey Kandaurov
ebd18ec181 SSL: disabled TLSv1 and TLSv1.1 by default.
TLSv1 and TLSv1.1 are formally deprecated and forbidden to negotiate due
to insufficient security reasons outlined in RFC 8996.

TLSv1 and TLSv1.1 are disabled in BoringSSL e95b0cad9 and LibreSSL 3.8.1
in the way they cannot be enabled in nginx configuration.  In OpenSSL 3.0,
they are only permitted at security level 0 (disabled by default).

The support is dropped in Chrome 84, Firefox 78, and deprecated in Safari.

This change disables TLSv1 and TLSv1.1 by default for OpenSSL 1.0.1 and
newer, where TLSv1.2 support is available.  For older library versions,
which do not have alternatives, these protocol versions remain enabled.
2024-10-31 19:49:00 +04:00
jzebor-at-f5
f45c2707ea Updated security policy to include disclosure details. 2024-10-21 19:43:25 +04:00
Thierry Bastian
b394d44cfa Configure: MSVC compatibility with PCRE2 10.43. 2024-10-15 18:18:33 +04:00
nandsky
3f6d94d888 QUIC: prevent deleted stream frame retransmissions.
Since a2a513b93c, stream frames no longer need to be retransmitted after it
was deleted.  The frames which were retransmitted before, could be stream data
frames sent prior to a RESET_STREAM. Such retransmissions are explicitly
prohibited by RFC 9000, Section 19.4.
2024-10-08 19:55:14 +04:00
Sergey Kandaurov
144778aee6 Version bump. 2024-10-08 18:29:01 +04:00
Sergey Kandaurov
e24f7ccc16 nginx-1.27.2-RELEASE 2024-10-02 19:13:19 +04:00
Sergey Kandaurov
0e7c9ddb27 Updated OpenSSL used for win32 builds. 2024-10-02 19:13:19 +04:00
Sergey Kandaurov
5917e9de5a SSL: caching CA certificates.
This can potentially provide a large amount of savings,
because CA certificates can be quite large.

Based on previous work by Mini Hawthorne.
2024-10-01 17:59:24 +04:00
Sergey Kandaurov
61314518de SSL: caching CRLs.
Based on previous work by Mini Hawthorne.
2024-10-01 17:59:24 +04:00
Sergey Kandaurov
7ea2fb6cb1 SSL: caching certificate keys.
EVP_KEY objects are a reference-counted container for key material, shallow
copies and OpenSSL stack management aren't needed as with certificates.

Based on previous work by Mini Hawthorne.
2024-10-01 17:59:24 +04:00
Sergey Kandaurov
78ed123e71 SSL: caching certificates.
Certificate chains are now loaded once.

The certificate cache provides each chain as a unique stack of reference
counted elements.  This shallow copy is required because OpenSSL stacks
aren't reference counted.

Based on previous work by Mini Hawthorne.
2024-10-01 17:59:24 +04:00
Sergey Kandaurov
7d7e8d2cb8 SSL: object caching.
Added ngx_openssl_cache_module, which indexes a type-aware object cache.
It maps an id to a unique instance, and provides references to it, which
are dropped when the cycle's pool is destroyed.

The cache will be used in subsequent patches.

Based on previous work by Mini Hawthorne.
2024-10-01 17:59:24 +04:00
Sergey Kandaurov
f36ff3550a SSL: moved certificate storage out of exdata.
Instead of cross-linking the objects using exdata, pointers to configured
certificates are now stored in ngx_ssl_t, and OCSP staples are now accessed
with rbtree in it.  This allows sharing these objects between SSL contexts.

Based on previous work by Mini Hawthorne.
2024-10-01 17:59:24 +04:00
tzssangglass
51857ce404 Fixed a typo of bpf makefile debug option. 2024-09-24 18:58:30 +04:00
Michael Vernik
b1e07409b1 Added new primary README.md file. 2024-09-20 09:57:11 -07:00
Sergey Kandaurov
18afcda938 SSL: optional ssl_client_certificate for ssl_verify_client.
Starting from TLSv1.1 (as seen since draft-ietf-tls-rfc2246-bis-00),
the "certificate_authorities" field grammar of the CertificateRequest
message was redone to allow no distinguished names.  In TLSv1.3, with
the restructured CertificateRequest message, this can be similarly
done by optionally including the "certificate_authorities" extension.
This allows to avoid sending DNs at all.

In practice, aside from published TLS specifications, all supported
SSL/TLS libraries allow to request client certificates with an empty
DN list for any protocol version.  For instance, when operating in
TLSv1, this results in sending the "certificate_authorities" list as
a zero-length vector, which corresponds to the TLSv1.1 specification.
Such behaviour goes back to SSLeay.

The change relaxes the requirement to specify at least one trusted CA
certificate in the ssl_client_certificate directive, which resulted in
sending DNs of these certificates (closes #142).  Instead, all trusted
CA certificates can be specified now using the ssl_trusted_certificate
directive if needed.  A notable difference that certificates specified
in ssl_trusted_certificate are always loaded remains (see 3648ba7db).

Co-authored-by: Praveen Chaudhary <praveenc@nvidia.com>
2024-09-20 14:43:00 +04:00
Sergey Kandaurov
1a64c196a7 Proxy: proxy_pass_trailers directive.
The directive allows to pass upstream response trailers to client.
2024-09-13 16:47:56 +04:00
Shaikh Yaser
00637cce36 Fixed a typo in win-utf. 2024-09-06 15:35:59 +04:00
Konstantin Pavlov
042b9cc4db Added CI based on GitHub Actions.
Pushes to master and stable branches will result in buildbot-like checks
on multiple OSes and architectures.

Pull requests will be checked on a public Ubuntu GitHub runner.
2024-09-04 20:01:47 +04:00
Maryna Herasimovich
082a3cbe3b Added GitHub templates. 2024-09-04 19:11:12 +04:00
Maryna Herasimovich
da468ec0c0 Added contributing guidelines. 2024-09-03 16:28:45 +04:00
Maryna Herasimovich
3b16b46aae Added security policy. 2024-09-02 20:10:28 +04:00
Maryna Herasimovich
e73ac62294 Added Code of Conduct. 2024-09-02 17:33:50 +04:00
Roman Arutyunyan
6bb4be1a79 Removed C-style comments from LICENSE. 2024-08-30 18:06:39 +04:00
Roman Arutyunyan
863ab647cd Moved LICENSE and README to root. 2024-08-30 18:06:39 +04:00
Roman Arutyunyan
81a933e1f6 Switched GNUmakefile from hg to git. 2024-08-30 18:06:39 +04:00
Roman Arutyunyan
900f4dc48c Removed .hgtags file. 2024-08-30 18:06:39 +04:00
Sergey Kandaurov
fb89d50eeb Stream: OCSP stapling. 2024-08-22 14:57:46 +04:00
Sergey Kandaurov
581cf22673 Stream: client certificate validation with OCSP. 2024-08-22 14:57:45 +04:00
Sergey Kandaurov
48ac1ee9c6 Version bump. 2024-08-20 21:18:30 +04:00
Sergey Kandaurov
a4100450c0 release-1.27.1 tag 2024-08-12 18:21:01 +04:00
Sergey Kandaurov
e06bdbd4a2 nginx-1.27.1-RELEASE 2024-08-12 18:20:52 +04:00
Sergey Kandaurov
c165589d09 Updated OpenSSL used for win32 builds. 2024-08-12 18:20:49 +04:00
Roman Arutyunyan
88955b1044 Mp4: rejecting unordered chunks in stsc atom.
Unordered chunks could result in trak->end_chunk smaller than trak->start_chunk
in ngx_http_mp4_crop_stsc_data().  Later in ngx_http_mp4_update_stco_atom()
this caused buffer overread while trying to calculate trak->end_offset.
2024-08-12 18:20:45 +04:00
Roman Arutyunyan
7362d01658 Mp4: fixed buffer underread while updating stsz atom.
While cropping an stsc atom in ngx_http_mp4_crop_stsc_data(), a 32-bit integer
overflow could happen, which could result in incorrect seeking and a very large
value stored in "samples".  This resulted in a large invalid value of
trak->end_chunk_samples.  This value is further used to calculate the value of
trak->end_chunk_samples_size in ngx_http_mp4_update_stsz_atom().  While doing
this, a large invalid value of trak->end_chunk_samples could result in reading
memory before stsz atom start.  This could potentially result in a segfault.
2024-08-12 18:20:43 +04:00
Sergey Kandaurov
0fa8434957 Stream ssl_preread: do not reallocate a parsed SNI host.
We own this memory from the session pool.
2024-08-09 19:12:26 +04:00
Sergey Kandaurov
504c78fc6d QUIC: zero out existing keying material only.
Previously, this used to have extra ngx_explicit_memzero() calls
from within ngx_quic_keys_cleanup(), which might be suboptimal.
2024-08-09 19:12:26 +04:00
Sergey Kandaurov
58b92177e7 QUIC: discarding 0-RTT keys.
For simplicity, this is done on successful decryption of a 1-RTT packet.
2024-08-09 19:12:25 +04:00
Sergey Kandaurov
250baed4ee Typo fixed. 2024-08-09 19:12:23 +04:00
Sergey Kandaurov
6ecc4e3807 Version bump. 2024-08-09 18:01:42 +04:00
Kasei Wang
145b228530 HTTP/2: close connections initialized during graceful shutdown.
In some rare cases, graceful shutdown may happen while initializing an HTTP/2
connection.  Previously, such a connection ignored the shutdown and remained
active.  Now it is gracefully closed prior to processing any streams to
eliminate the shutdown delay.
2024-07-18 17:43:25 +04:00
Roman Arutyunyan
788e462c5b Stream: allow servers with no handler.
Previously handlers were mandatory.  However they are not always needed.
For example, a server configured with ssl_reject_handshake does not need a
handler.  Such servers required a fake handler to pass the check.  Now handler
absence check is moved to runtime.  If handler is missing, the connection is
closed with 500 code.
2024-06-27 17:29:56 +04:00
Sergey Kandaurov
e734df6664 release-1.27.0 tag 2024-05-28 17:22:30 +04:00
Sergey Kandaurov
0ddcae05b6 nginx-1.27.0-RELEASE 2024-05-28 17:19:38 +04:00
Sergey Kandaurov
34bd899287 HTTP/3: fixed handling of zero-length literal field line.
Previously, st->value was passed with NULL data pointer to header handlers.
2024-05-28 17:20:45 +04:00
Roman Arutyunyan
9ddc6a08f4 QUIC: ngx_quic_buffer_t use-after-free protection.
Previously the last chain field of ngx_quic_buffer_t could still reference freed
chains and buffers after calling ngx_quic_free_buffer().  While normally an
ngx_quic_buffer_t object should not be used after freeing, resetting last_chain
field would prevent a potential use-after-free.
2024-05-28 17:19:21 +04:00
Roman Arutyunyan
6f8c520f49 QUIC: ignore CRYPTO frames after handshake completion.
Sending handshake-level CRYPTO frames after the client's Finished message could
lead to memory disclosure and a potential segfault, if those frames are sent in
one packet with the Finished frame.
2024-05-28 17:19:08 +04:00
Roman Arutyunyan
cca5655dd9 HTTP/3: fixed dynamic table overflow.
While inserting a new entry into the dynamic table, first the entry is added,
and then older entries are evicted until table size is within capacity.  After
the first step, the number of entries may temporarily exceed the maximum
calculated from capacity by one entry, which previously caused table overflow.

The easiest way to trigger the issue is to keep adding entries with empty names
and values until first eviction.

The issue was introduced by 987bee4363d1.
2024-05-28 17:18:50 +04:00
Roman Arutyunyan
0fd59c8b56 HTTP/3: decoder stream pre-creation.
Previously a decoder stream was created on demand for sending Section
Acknowledgement, Stream Cancellation and Insert Count Increment.  If conditions
for sending any of these instructions never happen, a decoder stream is not
created at all.  These conditions include client not using the dynamic table and
no streams abandoned by server (RFC 9204, Section 2.2.2.2).  However RFC 9204,
Section 4.2 defines only one condition for not creating a decoder stream:

   An endpoint MAY avoid creating a decoder stream if its decoder sets
   the maximum capacity of the dynamic table to zero.

The change enables pre-creation of the decoder stream at HTTP/3 session
initialization if maximum dynamic table capacity is not zero.  Note that this
value is currently hardcoded to 4096 bytes and is not configurable, so the
stream is now always created.

Also, the change fixes a potential stack overflow when creating a decoder
stream in ngx_http_v3_send_cancel_stream() while draining a request stream by
ngx_drain_connections().  Creating a decoder stream involves calling
ngx_get_connection(), which calls ngx_drain_connections(), which will drain the
same request stream again.  If client's MAX_STREAMS for uni stream is high
enough, these recursive calls will continue until we run out of stack.
Otherwise, decoder stream creation will fail at some point and the request
stream connection will be drained.  This may result in use-after-free, since
this connection could still be referenced up the stack.
2024-05-28 17:18:28 +04:00
Sergey Kandaurov
683e304e8b QUIC: client transport parameter data length checking. 2024-05-28 17:17:19 +04:00
J Carter
71ca978a35 Upstream: variables support in proxy_limit_rate and friends. 2023-11-25 21:57:09 +00:00
Roman Arutyunyan
ea8270c614 Optimized chain link usage (ticket #2614).
Previously chain links could sometimes be dropped instead of being reused,
which could result in increased memory consumption during long requests.

A similar chain link issue in ngx_http_gzip_filter_module was fixed in
da46bfc484ef (1.11.10).

Based on a patch by Sangmin Lee.
2024-05-23 19:15:38 +04:00
Edgar Bonet
efc6a217b9 Configure: fixed building libatomic test.
Using "long *" instead of "AO_t *" leads either to -Wincompatible-pointer-types
or -Wpointer-sign warnings, depending on whether long and size_t are compatible
types (e.g., ILP32 versus LP64 data models).  Notably, -Wpointer-sign warnings
are enabled by default in Clang only, and -Wincompatible-pointer-types is an
error starting from GCC 14.

Signed-off-by: Edgar Bonet <bonet@grenoble.cnrs.fr>
2024-05-16 11:15:10 +02:00
Roman Arutyunyan
489e1e6191 Stream pass: disabled passing from or to udp.
Passing from udp was not possible for the most part due to preread buffer
restriction.  Passing to udp could occasionally work, but the connection would
still be bound to the original listen rbtree, which prevented it from being
deleted on connection closure.
2024-05-03 20:26:05 +04:00
Sergey Kandaurov
6f7494081a SSL: fixed possible configuration overwrite loading "engine:" keys.
When loading certificate keys via ENGINE_load_private_key() in runtime,
it was possible to overwrite configuration on ENGINE_by_id() failure.
OpenSSL documention doesn't describe errors in details, the only reason
I found in the comment to example is when the engine is not available.
2024-05-03 20:29:01 +04:00
Sergey Kandaurov
a7e3cd52e0 HTTP/3: fixed handling of malformed request body length.
Previously, a request body larger than declared in Content-Length resulted in
a 413 status code, because Content-Length was mistakenly used as the maximum
allowed request body, similar to client_max_body_size.  Following the HTTP/3
specification, such requests are now rejected with the 400 error as malformed.
2024-05-03 20:28:32 +04:00
Sergey Kandaurov
3f0fe15a98 Version bump. 2024-05-03 20:28:22 +04:00
114 changed files with 8352 additions and 1653 deletions

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ""
labels: "bug"
---
### Environment
Include the result of the following commands:
- `nginx -V`
- `uname -a`
### Description
Describe the bug in full detail including expected and actual behavior.
Specify conditions that caused it. Provide the relevant part of nginx
configuration and debug log.
- [ ] The bug is reproducible with the latest version of nginx
- [ ] The nginx configuration is minimized to the smallest possible
to reproduce the issue and doesn't contain third-party modules
#### nginx configuration
```
# Your nginx configuration here
```
or share the configuration in [gist](https://gist.github.com/).
#### nginx debug log
It is advised to enable
[debug logging](http://nginx.org/en/docs/debugging_log.html).
```
# Your nginx debug log here
```
or share the debug log in [gist](https://gist.github.com/).

View File

@ -0,0 +1,18 @@
---
name: Feature request
about: Suggest a feature for nginx
title: ""
labels: "feature"
---
### Describe the feature you'd like to add to nginx
A clear and concise description of the feature.
### Describe the problem this feature solves
A clear and concise description of the problem.
### Additional context
Add any other context about the feature request here.

10
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,10 @@
### Proposed changes
Describe the use case and detail of the change.
If this pull request addresses an issue on GitHub, make sure to reference that
issue using one of the
[supported keywords](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue).
Before creating a pull request, make sure to comply with the
[Contributing Guidelines](https://github.com/nginx/nginx/blob/master/CONTRIBUTING.md).

11
.github/workflows/buildbot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
name: buildbot
on:
push:
branches:
- master
- 'stable-1.*'
jobs:
buildbot:
uses: nginx/ci-self-hosted/.github/workflows/nginx-buildbot.yml@main

8
.github/workflows/check-pr.yml vendored Normal file
View File

@ -0,0 +1,8 @@
name: check-pr
on:
pull_request:
jobs:
check-pr:
uses: nginx/ci-self-hosted/.github/workflows/nginx-check-pr.yml@main

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/Makefile
/objs/
/tmp/

480
.hgtags
View File

@ -1,480 +0,0 @@
551102312e19b704cd22bd7254a9444b9ea14e96 release-0.1.0
23fb87bddda14ce9faec90f774085634106aded4 release-0.1.1
295d97d70c698585705345f1a8f92b02e63d6d0d release-0.1.2
ded1284520cc939ad5ae6ddab39925375e64237d release-0.1.3
0491b909ef7612d8411f1f59054186c1f3471b52 release-0.1.4
a88a3e4e158fade0aaa6f3eb25597d5ced2c1075 release-0.1.5
1f31dc6d33a3a4e65240b08066bf186df9e33b79 release-0.1.6
5aecc125bc33d81d6214c91d73eb44230a903dde release-0.1.7
bbd6b0b4a2b15ef8c8f1aaf7b027b6da47303524 release-0.1.8
2ff194b74f1e60cd04670986973e3b1a6aa3bece release-0.1.9
31ee1b50354fb829564b81a6f34e8d6ceb2d3f48 release-0.1.10
8e8f3af115b5b903b2b8f3335de971f18891246f release-0.1.11
c3c2848fc081e19aec5ffa97e468ad20ddb81df0 release-0.1.12
ad1e9ebf93bb5ae4c748d471fad2de8a0afc4d2a release-0.1.13
c5240858380136a67bec261c59b1532560b57885 release-0.1.14
fd661d14a7fad212e326a7dad6234ea0de992fbf release-0.1.15
621229427cba1b0af417ff2a101fc4f17a7d93c8 release-0.1.16
4ebe09b07e3021f1a63b459903ec58f162183b26 release-0.1.17
31ff3e943e1675a2caf745ba7a981244445d4c98 release-0.1.18
45a460f82aec80b0f61136aa09f412436d42203a release-0.1.19
0f836f0288eee4980f57736d50a7a60fa082d8e9 release-0.1.20
975f62e77f0244f1b631f740be77c72c8f2da1de release-0.1.21
fc9909c369b2b4716304ac8e38da57b8fb781211 release-0.1.22
d7c90bb5ce83dab08715e98f9c7b81c7df4b37be release-0.1.23
64d9afb209da0cd4a917202b7b77e51cc23e2229 release-0.1.24
d4ea69372b946dc4ec37fc3f5ddd93ff7c3da675 release-0.1.25
b1648294f6935e993e436fd8a68bca75c74c826d release-0.1.26
ee66921ecd47a7fa459f70f4a9d660f91f6a1b94 release-0.1.27
cd3117ad9aab9c58c6f7e677e551e1adbdeaba54 release-0.1.28
9b8c906f6e63ec2c71cecebfff35819a7d32227d release-0.1.29
c12967aadd8726daf2d85e3f3e622d89c42db176 release-0.1.30
fbbf16224844e7d560c00043e8ade8a560415bba release-0.1.31
417a087c9c4d9abb9b0b9b3f787aff515c43c035 release-0.1.32
dadfa78d227027348d7f9d1e7b7093d06ba545a0 release-0.1.33
12234c998d83bfbbaa305273b3dd1b855ca325dc release-0.1.34
6f00349b98e5f706b82115c6e4dc84456fc0d770 release-0.1.35
2019117e6b38cc3e89fe4f56a23b271479c627a6 release-0.1.36
09b42134ac0c42625340f16628e29690a04f8db5 release-0.1.37
7fa11e5c6e9612ecff5eb58274cc846ae742d1d2 release-0.1.38
e5d7d0334fdb946133c17523c198800142ac9fe9 release-0.1.39
c3bd8cdabb8f73e5600a91f198eb7df6fac65e92 release-0.1.40
d6e48c08d718bf5a9e58c20a37e8ae172bff1139 release-0.1.41
563ad09abf5042eb41e8ecaf5b4e6c9deaa42731 release-0.1.42
c9ad0d9c7d59b2fa2a5fe669f1e88debd03e6c04 release-0.1.43
371c1cee100d7a1b0e6cad4d188e05c98a641ee7 release-0.1.44
b09ee85d0ac823e36861491eedfc4dfafe282997 release-0.1.45
511a89da35ada16ae806667d699f9610b4f8499a release-0.2.0
0148586012ab3dde69b394ec5a389d44bb11c869 release-0.2.1
818fbd4750b99d14d2736212c939855a11b1f1ef release-0.2.2
e16a8d574da511622b97d6237d005f40f2cddb30 release-0.2.3
483cca23060331f2078b1c2984870d80f288ad41 release-0.2.4
45033d85b30e3f12c407b7cfc518d76e0eda0263 release-0.2.5
7bd37aef1e7e87858c12b124e253e98558889b50 release-0.2.6
ecd9c160f25b7a7075dd93383d98a0fc8d8c0a41 release-0.3.0
c1f965ef97188fd7ef81342dcf8719da18c554d2 release-0.3.1
e48ebafc69393fc94fecfdf9997c4179fd1ce473 release-0.3.2
9c2f3ed7a24711d3b42b124d5f831155c8beff95 release-0.3.3
7c1369d37c7eb0017c28ebcaa0778046f5aafdcc release-0.3.4
1af2fcb3be8a63796b6b23a488049c92a6bc12f4 release-0.3.5
174f1e853e1e831b01000aeccfd06a9c8d4d95a2 release-0.3.6
458b6c3fea65a894c99dd429334a77bb164c7e83 release-0.3.7
58475592100cb792c125101b6d2d898f5adada30 release-0.3.8
fcd6fc7ff7f9b132c35193d834e6e7d05026c716 release-0.3.9
4d9ea73a627a914d364e83e20c58eb1283f4031d release-0.3.10
4c5c2c55975c1152b5ca5d5d55b32d4dd7945f7a release-0.3.11
326634fb9d47912ad94221dc2f8fa4bec424d40c release-0.3.12
4e296b7d25bf62390ca2afb599e395426b94f785 release-0.3.13
401de5a43ba5a8acdb9c52465193c0ea7354afe7 release-0.3.14
284cc140593bb16ac71094acd509ab415ff4837d release-0.3.15
d4e858a5751a7fd08e64586795ed7d336011fbc0 release-0.3.16
8c0cdd81580eb76d774cfc5724de68e7e5cbbdc2 release-0.3.17
425af804d968f30eeff01e33b808bc2e8c467f2c release-0.3.18
ebc68d8ca4962fe3531b7e13444f7ac4395d9c6e release-0.3.19
9262f520ce214d3d5fd7c842891519336ef85ca6 release-0.3.20
869b6444d2341a587183859d4df736c7f3381169 release-0.3.21
77f77f53214a0e3a68fef8226c15532b54f2c365 release-0.3.22
858700ae46b453ea111b966b6d03f2c21ddcb94e release-0.3.23
5dac8c7fb71b86aafed8ea352305e7f85759f72e release-0.3.24
77cdfe394a94a625955e7585e09983b3af9b889b release-0.3.25
608cf78b24ef7baaf9705e4715a361f26bb16ba9 release-0.3.26
3f8a2132b93d66ac19bec006205a304a68524a0b release-0.3.27
c73c5c58c619c22dd3a5a26c91bb0567a62c6930 release-0.3.28
5ef026a2ac7481f04154f29ab49377bf99aaf96f release-0.3.29
51b27717f140b71a2e9158807d79da17c888ce4c release-0.3.30
7a16e281c01f1c7ab3b79c64b43ddb754ea7935e release-0.3.31
93e85a79757c49d502e42a1cb8264a0f133b0b00 release-0.3.32
0216fd1471f386168545f772836156761eddec08 release-0.3.33
fbed40ce7cb4fd7203fecc22a617b9ce5b950fb3 release-0.3.34
387450de0b4d21652f0b6242a5e26a31e3be8d8c release-0.3.35
65bf042c0b4f39f18a235464c52f980e9fa24f6b release-0.3.36
5d2b8078c1c2593b95ec50acfeeafbefa65be344 release-0.3.37
f971949ffb585d400e0f15508a56232a0f897c80 release-0.3.38
18268abd340cb351e0c01b9c44e9f8cc05492364 release-0.3.39
e60fe4cf1d4ea3c34be8c49047c712c6d46c1727 release-0.3.40
715d243270806d38be776fc3ed826d97514a73d6 release-0.3.41
5e8fb59c18c19347a5607fb5af075fe1e2925b9a release-0.3.42
947c6fd27699e0199249ad592151f844c8a900b0 release-0.3.43
4946078f0a79e6cc952d3e410813aac9b8bda650 release-0.3.44
95d7da23ea5315a6e9255ce036ed2c51f091f180 release-0.3.45
1e720b0be7ecd92358da8a60944669fa493e78cd release-0.3.46
39b7d7b33c918d8f4abc86c4075052d8c19da3c7 release-0.3.47
7cbef16c71a1f43a07f8141f02e0135c775f0f5b release-0.3.48
4c8cd5ae5cc100add5c08c252d991b82b1838c6b release-0.3.49
400711951595aef7cd2ef865b84b31df52b15782 release-0.3.50
649c9063d0fda23620eaeaf0f6393be0a672ebe7 release-0.3.51
9079ee4735aefa98165bb2cb26dee4f58d58c1d7 release-0.3.52
6d5c1535bb9dcd891c5963971f767421a334a728 release-0.3.53
5fd7a5e990477189c40718c8c3e01002a2c20b81 release-0.3.54
63a820b0bc6ca629c8e45a069b52d622ddc27a2d release-0.3.55
562806624c4afb1687cba83bc1852f5d0fecbac3 release-0.3.56
cec32b3753acf610ac1a6227d14032c1a89d6319 release-0.3.57
b80f94fa2197b99db5e033fec92e0426d1fe5026 release-0.3.58
e924670896abe2769ea0fcfd2058b405bed8e8ec release-0.3.59
921a7ce4baf42fd1091b7e40f89c858c6b23053e release-0.3.60
df95dcff753a6dc5e94257302aea02c18c7a7c87 release-0.3.61
7e24168b0853ee7e46c9c7b943ef077dc64f17f5 release-0.4.0
8183d4ba50f8500465efb27e66dd23f98775dd21 release-0.4.1
610267a772c7bf911b499d37f66c21ce8f2ebaf7 release-0.4.2
39dd0b045441e21512e0a6061a03d0df63414d8b release-0.4.3
5e42c1615f4de0079bd4d8913886d588ce6a295d release-0.4.4
40266f92b829a870808b3d4ee54c8fccdecbd2d6 release-0.4.5
56e33c6efee7ff63cdc52bd1cf172bde195079df release-0.4.6
119bad43bfd493400c57a05848eada2c35a46810 release-0.4.7
0f404f82a1343cb4e4b277a44e3417385798e5e5 release-0.4.8
d24a717314365c857b9f283d6072c2a427d5e342 release-0.4.9
d6f0a00015fdef861fd67fb583b9690638650656 release-0.4.10
e372368dadd7b2ecd0182b2f1b11db86fc27b2c3 release-0.4.11
fd57967d850d2361072c72562d1ed03598473478 release-0.4.12
979045fdcbd20cf7188545c1c589ff240251f890 release-0.4.13
93c94cfa9f78f0a5740595dde4466ec4fba664f8 release-0.4.14
589ee12e8d7c2ae5e4f4676bcc7a1279a76f9e8e release-0.5.0
13416db8a807e5acb4021bc3c581203de57e2f50 release-0.5.1
06c58edc88831fb31c492a8eddcf2c6056567f18 release-0.5.2
e2ac5fa41bcba14adbbb722d45c083c30c07bb5c release-0.5.3
393dbc659df15ccd411680b5c1ce87ed86d4c144 release-0.5.4
38cc7bd8e04f2c519fd4526c12841a876be353cb release-0.5.5
6d1fcec2ea79101c756316c015f72e75f601a5ab release-0.5.6
aed8a9de62456c4b360358bc112ccca32ce02e8d release-0.5.7
7642f45af67d805452df2667486201c36efaff85 release-0.5.8
779216610662c3a459935d506f66a9b16b9c9576 release-0.5.9
9eeb585454f3daa30cf768e95c088a092fe229b9 release-0.5.10
bb491c8197e38ca10ae63b1f1ecb36bf6fdaf950 release-0.5.11
613369e08810f36bbcc9734ef1059a03ccbf5e16 release-0.5.12
bd796ef5c9c9dd34bfac20261b98685e0410122a release-0.5.13
8a730c49f906d783b47e4b44d735efd083936c64 release-0.5.14
cb447039152d85e9145139ff2575a6199b9af9d4 release-0.5.15
64854c7c95d04f838585ca08492823000503fa61 release-0.5.16
d1ffcf84ea1244f659145c36ff28de6fcdf528b2 release-0.5.17
796a6e30ca9d29504195c10210dbc8deced0ae83 release-0.5.18
1f81c711d2a039e1f93b9b515065a2235372d455 release-0.5.19
8e8f6082654aedb4438c8fca408cfc316c7c5a2a release-0.5.20
e9551132f7dd40da5719dd5bcf924c86f1436f85 release-0.5.21
533a252896c4d1cff1586ae42129d610f7497811 release-0.5.22
f461a49b6c747e0b67f721f2be172902afea5528 release-0.5.23
2d5ef73671f690b65bf6d9e22e7155f68f484d5a release-0.5.24
77bf42576050862c268e267ef3e508b145845a25 release-0.5.25
2aefee4d4ed69eb7567680bf27a2efd212232488 release-0.6.0
7ac0fe9bec9a2b5f8e191f6fdd6922bfd916a6cb release-0.6.1
4882735ebc71eeec0fbfe645bdfdb31306872d82 release-0.6.2
b94731c73d0922f472ff938b9d252ba29020f20c release-0.6.3
13e649b813d6ccba5db33a61e08ebe09d683cd5b release-0.6.4
80de622646b0059fd4c553eff47c391bf7503b89 release-0.6.5
3b05edb2619d5935023b979ee7a9611b61b6c9e5 release-0.6.6
1dcfd375100c4479611f71efb99271d0a3059215 release-0.6.7
0228185d4c5772947b842e856ad74cf7f7fd52f3 release-0.6.8
d1879c52326ecac45c713203670f54220879911e release-0.6.9
5a80c6ccbe2ad24fa3d4ff6f9fe4a2b07408d19d release-0.6.10
f88a8b0b39601b19cd740e4db614ab0b5b874686 release-0.6.11
5557460a7247a1602ae96efd1d0ccf781344cb58 release-0.6.12
451b02cc770a794cd41363461b446948ae1d8bc8 release-0.6.13
537b6ef014c4a133e0ab0b7dc817508e0647e315 release-0.6.14
5e68764f0d6e91a983170fa806e7450a9e9b33fe release-0.6.15
158aa4e8cc46fcf9504a61469d22daf3476b17bf release-0.6.16
d8fcca555542619228d9fab89e1665b993f8c3ee release-0.6.17
60707ebc037086cf004736a0d4979e2a608da033 release-0.6.18
3c2a99d3a71af846855be35e62edb9a12f363f44 release-0.6.19
3e0a27f9358ffc1b5249e0ea2311ce7da5c8967e release-0.6.20
143f4d65b1c875d6563ccb7f653d9157afc72194 release-0.6.21
95e6160d2b7d0af8ffd1b95a23cadadf8f0b3f6d release-0.6.22
69a03d5e3b6e6660079ef1ef172db7ac08d8370e release-0.6.23
3e2a58fb48f1e1a99ebf851e0d47a7034c52ae22 release-0.6.24
3b8607c05a8bebcfa59235c2126a70d737f0ccf5 release-0.6.25
07ad5b2606614c4be4ee720c46cf4af126059d31 release-0.6.26
be531addfabe5214f409d457140c1038af10d199 release-0.6.27
58f05255d3a345d04baef5cff0ca1ae0ac7ecebb release-0.6.28
eb2bd21dc8d03f6c94016f04ffb9adaf83a2b606 release-0.6.29
55408deb3cd171efa9b81d23d7a1dd1ccde0b839 release-0.6.30
d4288915bba73c4c3c9cf5d39d34e86879eb2b45 release-0.6.31
0a189588830b8629c4dfea68feb49af36b59e4a9 release-0.7.0
6ab27a06f3346cf9ec8737f5dbcc82dd4031e30f release-0.7.1
a07e258cef3b0a0b6e76a6ff4ba4651c5facc85a release-0.7.2
9992c4583513d2804fc2e7fec860fbc7ab043009 release-0.7.3
4dc24d50230fbadfc037a414a86390db2de69dd2 release-0.7.4
9527137b4354a648a229c7169850c7c65272c00d release-0.7.5
c2f0f7cf306f302254beae512bda18713922375c release-0.7.6
bbcf6d75556fdcee8bd4aba8f6c27014be9920ee release-0.7.7
43bde71f0bbe5a33b161760d7f9f980d50386597 release-0.7.8
769f0dd7081e9011394f264aa22aa66fd79730d8 release-0.7.9
511edfa732da637f5f0c9476335df7dca994706d release-0.7.10
0e7023bf6b2461309c29885935443449a41be807 release-0.7.11
9ad1bd2b21d93902863807528e426862aedee737 release-0.7.12
d90ea21e24ea35379aef50c5d70564158e110a15 release-0.7.13
c07d2d20d95c83d804079bbdcecbce4a0c8282f0 release-0.7.14
0cd7bb051f67eac2b179fb9f9cc988b9ba18ed76 release-0.7.15
eab2e87deba73ae6abd9cc740e8d4365bed96322 release-0.7.16
91d7a9eb8ade90e9421d7b1e3c2e47a6bc427876 release-0.7.17
fc10f7b5cb1305fb930f8ac40b46882d0828d61e release-0.7.18
9dba9779e37e5969a2d408c792084fd7acfec062 release-0.7.19
61838d1bcbddc7bc4dd9f30d535573a6fddca8f9 release-0.7.20
5f665d0fa6a5f6e748157f2ccbc445b2db8125d0 release-0.7.21
24763afa5efe91e54f00b2ae5b87666eb6c08c3b release-0.7.22
0562fb355a25266150cbe8c8d4e00f55e3654df3 release-0.7.23
19c452ecd083550816873a8a31eb3ed9879085e6 release-0.7.24
46b68faf271d6fdcaaf3ad2c69f6167ea9e9fa28 release-0.7.25
d04bfca0c7e3ae2e4422bc1d383553139d6f0a19 release-0.7.26
9425d9c7f8ead95b00a3929a9a5e487e0e3c8499 release-0.7.27
fbc3e7e8b3ee756568a875f87d8a954a2f9d3bf6 release-0.7.28
5176dfdf153fc785b18604197d58806f919829ad release-0.7.29
87e07ccdf0a4ec53458d9d7a4ea66e1239910968 release-0.7.30
9fddd7e1a7a27f8463867f41a461aad57df461b2 release-0.7.31
780b2ba1ec6daf6e3773774e26b05b9ff0d5483e release-0.7.32
83027471a25385b1c671968be761e9aa7a8591a7 release-0.7.33
1e9a362c3dcee221ca6e34308c483ed93867aca2 release-0.7.34
c7ee9e15717b54ead5f4a554686e74abe66c6b07 release-0.7.35
b84548abe9b9d4f4e203f848696e52c8c82c308f release-0.7.36
3286f0bab8e77dbc7ebb370b1dc379592ccff123 release-0.7.37
11a4e2ed5b166b9c9f119171aa399a9e3aa4684a release-0.7.38
f822655d4120629977794c32d3b969343b6c30db release-0.7.39
8a350e49d2b6751296db6d8e27277ccf63ed412a release-0.7.40
c4a56c197eeafd71fc1caef7a9d890a330e3c23d release-0.7.41
a9575a57a5443df39611774cf3840e9088132b0e release-0.7.42
7503d95d6eadad14c28b2db183ba09848265274b release-0.7.43
9be652e9114435fc6f1fdec84c0458d56702db91 release-0.7.44
797e070d480a34b31ddac0d364784773f1bbbcf9 release-0.7.45
9b5037e7ec7db25875c40f9d1cf20a853388b124 release-0.7.46
d1d0e6d7ff0ca3c0dd1be1ef1cfff2e3fd0b4e1c release-0.7.47
9816fb28eda599bfd53940e6d3b6617d1ecb6323 release-0.7.48
452b9d09df8e3f2fb04b2a33d04d2f3a6436eb34 release-0.7.49
e4350efa7cf7a0e868c2236a1137de8a33bd8ec6 release-0.7.50
f51f2bec766c8b6d7e1799d904f18f8ea631bd44 release-0.7.51
18e39e566781c9c187e2eb62bebd9d669d68f08c release-0.7.52
b073eaa1dcea296a3488b83d455fab6621a73932 release-0.7.53
01c6fe6c2a55998434cd3b05dd10ca487ac3fb6c release-0.7.54
3ed9377e686f2521e6ec15873084381033fb490d release-0.7.55
a1e44954549c35023b409f728c678be8bf898148 release-0.7.56
fbb1918a85e38a7becdb1a001dbaf5933f23a919 release-0.7.57
87f4a49a9cc34a5b11c8784cc5ea89e97b4b2bd8 release-0.7.58
0c22cb4862c8beb4ee1b9e4627125162a29a5304 release-0.7.59
82d56c2425ef857cd430b8530a3f9e1127145a67 release-0.8.0
f4acb784b53cd952559567971b97dde1e818a2b6 release-0.8.1
b3503597c1a0f0f378afdc5e5e5b85e2c095a4be release-0.8.2
c98da980514a02ba81c421b25bf91803ffffddf3 release-0.8.3
db34ec0c53c4b9dec12ffdf70caf89a325ab9577 release-0.8.4
0914802433b8678ba2cdf91280766f00f4b9b76e release-0.8.5
ff52ee9e6422f3759f43a442b7ba615595b3a3d4 release-0.8.6
7607237b4829fff1f60999f4663c50ed9d5182f7 release-0.8.7
1cef1807bc12cb05ac52fb0e7a0f111d3760b569 release-0.8.8
a40f8475511d74a468ade29c1505e8986600d7a3 release-0.8.9
2d9faf2260df6c3e5d4aa1781493c31f27a557d0 release-0.8.10
d0d61c32331a6505381b5218318f7b69db167ca8 release-0.8.11
ca7a1c6c798a7eb5b294d4ac3179ec87ecf297d3 release-0.8.12
81c8277cd8ed55febcb2dd9d9213076f6c0ccb09 release-0.8.13
3089486a8dc5844b5b6e9f78d536b4b26f7ffa16 release-0.8.14
d364c2c12dd9723a2dfac3f096f5e55d4cfe6838 release-0.8.15
52163a1027c3efd6b4c461b60a2ca6266c23e193 release-0.8.16
06564e9a2d9ec5852132c212e85eda0bf1300307 release-0.8.17
7aaa959da85e09e29bcac3b1cadec35b0a25b64d release-0.8.18
4bc73c644329a510da4e96b7241b80ead7772f83 release-0.8.19
ea3d168fb99c32a5c3545717ecc61e85a375e5dd release-0.8.20
27951ca037e63dae45ff5b6279124c224ae1255a release-0.8.21
d56c8b5df517c2bf6e7bc2827b8bf3e08cda90e1 release-0.8.22
3c6ac062b379b126212cbb27e98a3c8275ef381a release-0.8.23
89b9173476de14688b1418fbf7df10f91d1719ef release-0.8.24
aa550cb4159ae0d566006e091fb1c7a888771050 release-0.8.25
06ce92293f6a65651b08c466f90f55bd69984b98 release-0.8.26
ea50b0d79ef1d7d901cd0e4dcd7373447849d719 release-0.8.27
e68b1c35cad86105ff1c5b240f53442f4c36356e release-0.8.28
78d3582a30afe63fc0adb17c3ac8891a64e47146 release-0.8.29
9852c5965a3292a1b6127dbb4da9fce4912d898a release-0.8.30
4f84115914490e572bcbee5069157b7334df2744 release-0.8.31
59dee6f7f3afeb1fad6ed5983756e48c81ad2a5c release-0.8.32
a4456378d234c07038456cf32bfe3c651f1d5e82 release-0.8.33
21cb50799a20575a42f9733342d37a426f79db4d release-0.8.34
7cb3cb8d78ef7ae63561733ed91fd07933896bc8 release-0.8.35
aed68639d4eb6afe944b7fb50499c16f7f3f503c release-0.8.36
265b7fd2ae21c75bbffa5115b83a0123d6c4acb4 release-0.8.37
fa5f1ca353c0c5aa5415f51d72fd7bbcc02d1ed7 release-0.8.38
af10bf9d4c6532850aa1f70cdf7504bd109b284c release-0.8.39
4846ec9f83cb5bc4c8519d5641b35fb9b190430c release-0.8.40
718b4cb3faf7efe4e0648140f064bf7a92c3f7e8 release-0.8.41
b5a3065749093282ddd19845e0b77ffc2e54333e release-0.8.42
34df9fb22fed415cdad52def04095dc6d4b48222 release-0.8.43
00ec8cd76fb89af27363b76c40d9f88bf4679c3b release-0.8.44
e16dd52a0d226c23dcae9a11252564a04753bbed release-0.8.45
f034d9173df0a433e0bbcf5974f12ea9eb9076c0 release-0.8.46
4434dc967087315efcd0658206a67fe6c85528f3 release-0.8.47
0b65c962e0cd6783a854877b52c903cb058eec8c release-0.8.48
a2b7e94b9807e981866bf07e37b715847d1b7120 release-0.8.49
e7bdb8edc1bab2bc352a9fb6ce765c46575c35bf release-0.8.50
21dacebd12f65cb57ceb8d2688db5b07fad6e06d release-0.8.51
67dd7533b99c8945b5b8b5b393504d4e003a1c50 release-0.8.52
010468d890dbac33a4cae6dfb2017db70721b2fe release-0.8.53
62b599022a2fa625b526c2ad1711dc6db7d66786 release-0.9.0
71281dd73b17a0ead5535d531afaee098da723cb release-0.9.1
16cff36b0e49fc9fdeee13b2e92690286bcc1b3d release-0.9.2
b7b306325972661117694879d3e22faf4cf0df32 release-0.9.3
fe671505a8ea86a76f0358b3ec4de84a9037ac2b release-0.9.4
70542931bc5436d1bbd38f152245d93ac063968d release-0.9.5
27e2f3b7a3db1819c5d0ba28327ceaba84a13c4e release-0.9.6
657d05d63915ce2f6c4d763091059f5f85bb10e5 release-0.9.7
e0fd9f36005923b8f98d1ba1ea583cb7625f318f release-1.0.0
f8f89eb4e0c27e857ec517d893d4f9a454985084 release-1.0.1
c50df367648e53d55e80b60a447c9c66caa0d326 release-1.0.2
80d586db316512b5a9d39f00fe185f7f91523f52 release-1.0.3
c9c2805ac9245cc48ce6efeba2b4a444f859d6aa release-1.0.4
fa2c37b1122c2c983b6e91d1188e387d72dde4d6 release-1.0.5
f31aea5b06654c9163be5acd6d9b7aaf0fdf6b33 release-1.1.0
44bf95f670656fae01ccb266b3863843ea13d324 release-1.1.1
da1289482a143dfa016769649bdff636c26f53c8 release-1.1.2
bac8ba08a6570bac2ecd3bf2ad64b0ac3030c903 release-1.1.3
911060bc8221d4113a693ae97952a1fa88663ca8 release-1.1.4
e47531dfabbf8e5f8b8aff9ff353642ea4aa7abb release-1.1.5
f9ddecfe331462f870a95e4c1c3ba1bb8f19f2d3 release-1.1.6
378c297bb7459fb99aa9c77decac0d35391a3932 release-1.1.7
71600ce67510af093d4bc0117a78b3b4678c6b3a release-1.1.8
482d7d907f1ab92b78084d8b8631ed0eb7dd08f7 release-1.1.9
c7e65deabf0db5109e8d8f6cf64cd3fb7633a3d1 release-1.1.10
9590f0cf5aab8e6e0b0c8ae59c70187b2b97d886 release-1.1.11
ade8fc136430cfc04a8d0885c757968b0987d56c release-1.1.12
6a6836e65827fd3cb10a406e7bbbe36e0dad8736 release-1.1.13
6845f4ac909233f5a08ed8a51de137713a888328 release-1.1.14
2397e9c72f1bc5eac67006e12ad3e33e0ea9ba74 release-1.1.15
7b7c49639a7bceecabf4963c60b26b65a77d6ce0 release-1.1.16
f7e1113a9a1648cad122543e7080e895cf2d88f4 release-1.1.17
2b22743c3079b41233ded0fc35af8aa89bcfab91 release-1.1.18
0f0b425659e0b26f5bc8ea14a42dbf34de2eaba6 release-1.1.19
f582d662cc408eb7a132c21f4b298b71d0701abb release-1.2.0
9ee68d629722f583d43d92271f2eb84281afc630 release-1.3.0
61b6a3438afef630774e568eefd89c53e3b93287 release-1.3.1
7ccd50a0a455f2f2d3b241f376e1193ad956196d release-1.2.1
0000000000000000000000000000000000000000 release-1.2.1
50107e2d96bbfc2c59e46f889b1a5f68dd10cf19 release-1.3.2
2c5e1e88c8cf710caf551c5c67eba00443601efe release-1.3.3
a43447fb82aa03eabcd85352758ae14606a84d35 release-1.3.4
90f3b4ea7992a7bf9385851a3e77173363091eea release-1.3.5
3aeb14f88daeb973e4708310daa3dc68ac1200f7 release-1.3.6
dafd375f1c882b15fa4a9b7aa7c801c55082395e release-1.3.7
ab7ce0eb4cf78a656750ab1d8e55ef61f7e535ec release-1.3.8
1b1a9337a7399ad3cdc5e3a2f9fbaaec990271d5 release-1.3.9
2c053b2572694eb9cd4aed26a498b6cb1f51bbcc release-1.3.10
36409ac209872ce53019f084e4e07467c5d9d25e release-1.3.11
560dc55e90c13860a79d8f3e0d67a81c7b0257bb release-1.3.12
dc195ffe0965b2b9072f8e213fe74ecce38f6773 release-1.3.13
e04428778567dd4de329bbbe97ad653e22801612 release-1.3.14
cd84e467c72967b9f5fb4d96bfc708c93edeb634 release-1.3.15
23159600bdea695db8f9d2890aaf73424303e49c release-1.3.16
7809529022b83157067e7d1e2fb65d57db5f4d99 release-1.4.0
48a84bc3ff074a65a63e353b9796ff2b14239699 release-1.5.0
99eed1a88fc33f32d66e2ec913874dfef3e12fcc release-1.5.1
5bdca4812974011731e5719a6c398b54f14a6d61 release-1.5.2
644a079526295aca11c52c46cb81e3754e6ad4ad release-1.5.3
376a5e7694004048a9d073e4feb81bb54ee3ba91 release-1.5.4
60e0409b9ec7ee194c6d8102f0656598cc4a6cfe release-1.5.5
70c5cd3a61cb476c2afb3a61826e59c7cda0b7a7 release-1.5.6
9ba2542d75bf62a3972278c63561fc2ef5ec573a release-1.5.7
eaa76f24975948b0ce8be01838d949122d44ed67 release-1.5.8
5a1759f33b7fa6270e1617c08d7e655b7b127f26 release-1.5.9
b798fc020e3a84ef68e6c9f47865a319c826d33c release-1.5.10
f995a10d4c7e9a817157a6ce7b753297ad32897e release-1.5.11
97b47d95e4449cbde976657cf8cbbc118351ffe0 release-1.5.12
fd722b890eabc600394349730a093f50dac31639 release-1.5.13
d161d68df8be32e5cbf72b07db1a707714827803 release-1.7.0
0351a6d89c3dbcc7a76295024ba6b70e27b9a497 release-1.7.1
0bd223a546192fdf2e862f33938f4ec2a3b5b283 release-1.7.2
fe7cd01828d5ca7491059f0690bb4453645eb28b release-1.7.3
cbb146b120296852e781079d5138b04495bab6df release-1.7.4
fe129aa02db9001d220f1db7c3c056f79482c111 release-1.7.5
a8d111bb68847f61d682a3c8792fecb2e52efa2c release-1.7.6
6d2fbc30f8a7f70136cf08f32d5ff3179d524873 release-1.7.7
d5ea659b8bab2d6402a2266efa691f705e84001e release-1.7.8
34b201c1abd1e2d4faeae4650a21574771a03c0e release-1.7.9
860cfbcc4606ee36d898a9cd0c5ae8858db984d6 release-1.7.10
2b3b737b5456c05cd63d3d834f4fb4d3776953d0 release-1.7.11
3ef00a71f56420a9c3e9cec311c9a2109a015d67 release-1.7.12
53d850fe292f157d2fb999c52788ec1dc53c91ed release-1.9.0
884a967c369f73ab16ea859670d690fb094d3850 release-1.9.1
3a32d6e7404a79a0973bcd8d0b83181c5bf66074 release-1.9.2
e27a215601292872f545a733859e06d01af1017d release-1.9.3
5cb7e2eed2031e32d2e5422caf9402758c38a6ad release-1.9.4
942475e10cb47654205ede7ccbe7d568698e665b release-1.9.5
b78018cfaa2f0ec20494fccb16252daa87c48a31 release-1.9.6
54117529e40b988590ea2d38aae909b0b191663f release-1.9.7
1bdc497c81607d854e3edf8b9a3be324c3d136b6 release-1.9.8
ef107f3ddc237a3007e2769ec04adde0dcf627fa release-1.9.9
be00ca08e41a69e585b6aff70a725ed6c9e1a876 release-1.9.10
fe66cff450a95beed36a2515210eb2d7ef62c9d3 release-1.9.11
ead3907d74f90a14d1646f1b2b56ba01d3d11702 release-1.9.12
5936b7ed929237f1a73b467f662611cdc0309e51 release-1.9.13
4106db71cbcb9c8274700199ac17e520902c6c0f release-1.9.14
13070ecfda67397985f0e986eb9c42ecb46d05b5 release-1.9.15
271ee30c6791847980cd139d31807541f5e569bf release-1.11.0
cb783d9cc19761e14e1285d91c38f4b84d0b8756 release-1.11.1
4d3b3a13a8cf5fc3351a7f167d1c13325e00f21c release-1.11.2
b83a067949a3384a49fd3d943eb8d0997b31f87b release-1.11.3
953512ca02c6f63b4fcbbc3e10d0d9835896bf99 release-1.11.4
5253015a339aaca0a3111473d3e931b6d4752393 release-1.11.5
5e371426b3bcba4312ce08606194b89b758927d1 release-1.11.6
5c8f60faf33ca8926473d2da27b4c3c417bd4630 release-1.11.7
4591da489a30f790def29bc5987f43409b503cae release-1.11.8
20a45c768e5ed26b740679d0e22045c98727c3cc release-1.11.9
1ad0999a7ded3d4fb01c7acf8ff57c80b643da7e release-1.11.10
d8b321a876d6254e9e98795e3b194ef053290354 release-1.11.11
7f394e433f0003222aa6531931ecc0b24740d5e4 release-1.11.12
3d0e8655f897959e48cc74e87670bb5492a58871 release-1.11.13
3671096a45bce570a2afa20b9faf42c7fb0f7e66 release-1.13.0
539f7893ecb96bee60965528c8958d7eb2f1ce6b release-1.13.1
5be2b25bdc65775a85f18f68a4be4f58c7384415 release-1.13.2
8457ce87640f9bfe6221c4ac4466ced20e03bebe release-1.13.3
bbc642c813c829963ce8197c0ca237ab7601f3d4 release-1.13.4
0d45b4cf7c2e4e626a5a16e1fe604402ace1cea5 release-1.13.5
f87da7d9ca02b8ced4caa6c5eb9013ccd47b0117 release-1.13.6
47cca243d0ed39bf5dcb9859184affc958b79b6f release-1.13.7
20ca4bcff108d3e66977f4d97508637093492287 release-1.13.8
fb1212c7eca4c5328fe17d6cd95b010c67336aac release-1.13.9
31c929e16910c38492581ef474e72fa67c28f124 release-1.13.10
64179f242cb55fc206bca59de9bfdc4cf5ebcec7 release-1.13.11
051e5fa03b92b8a564f6b12debd483d267391e82 release-1.13.12
990b3e885636d763b97ed02d0d2cfc161a4e0c09 release-1.15.0
4189160cb946bb38d0bc0a452b5eb4cdd8979fb5 release-1.15.1
b234199c7ed8a156a6bb98f7ff58302c857c954f release-1.15.2
28b3e17ca7eba1e6a0891afde0e4bc5bcc99c861 release-1.15.3
49d49835653857daa418e68d6cbfed4958c78fca release-1.15.4
f062e43d74fc2578bb100a9e82a953efa1eb9e4e release-1.15.5
2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6
051a039ce1c7e09144de4a4846669ec7116cecea release-1.15.7
ee551e3f6dba336c0d875e266d7d55385f379b42 release-1.15.8
d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9
75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10
5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11
0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12
054c1c46395caff79bb4caf16f40b331f71bb6dd release-1.17.0
7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1
2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2
ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3
ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4
9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5
de68d0d94320cbf033599c6f3ca37e5335c67fd7 release-1.17.6
e56295fe0ea76bf53b06bffa77a2d3a9a335cb8c release-1.17.7
fdacd273711ddf20f778c1fb91529ab53979a454 release-1.17.8
5e8d52bca714d4b85284ddb649d1ba4a3ca978a8 release-1.17.9
c44970de01474f6f3e01b0adea85ec1d03e3a5f2 release-1.17.10
cbe6ba650211541310618849168631ce0b788f35 release-1.19.0
062920e2f3bf871ef7a3d8496edec1b3065faf80 release-1.19.1
a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2
3cbc2602325f0ac08917a4397d76f5155c34b7b1 release-1.19.3
dc0cc425fa63a80315f6efb68697cadb6626cdf2 release-1.19.4
8e5b068f761cd512d10c9671fbde0b568c1fd08b release-1.19.5
f618488eb769e0ed74ef0d93cd118d2ad79ef94d release-1.19.6
3fa6e2095a7a51acc630517e1c27a7b7ac41f7b3 release-1.19.7
8c65d21464aaa5923775f80c32474adc7a320068 release-1.19.8
da571b8eaf8f30f36c43b3c9b25e01e31f47149c release-1.19.9
ffcbb9980ee2bad27b4d7b1cd680b14ff47b29aa release-1.19.10
df34dcc9ac072ffd0945e5a1f3eb7987e8275375 release-1.21.0
a68ac0677f8553b1f84d357bc9da114731ab5f47 release-1.21.1
bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2
2217a9c1d0b86026f22700b3c089545db1964f55 release-1.21.3
39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4
d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5
714eb4b2c09e712fb2572a2164ce2bf67638ccac release-1.21.6
5da2c0902e8e2aa4534008a582a60c61c135960e release-1.23.0
a63d0a70afea96813ba6667997bc7d68b5863f0d release-1.23.1
aa901551a7ebad1e8b0f8c11cb44e3424ba29707 release-1.23.2
ff3afd1ce6a6b65057741df442adfaa71a0e2588 release-1.23.3
ac779115ed6ee4f3039e9aea414a54e560450ee2 release-1.23.4
12dcf92b0c2c68552398f19644ce3104459807d7 release-1.25.0
f8134640e8615448205785cf00b0bc810489b495 release-1.25.1
1d839f05409d1a50d0f15a2bf36547001f99ae40 release-1.25.2
294a3d07234f8f65d7b0e0b0e2c5b05c12c5da0a release-1.25.3
173a0a7dbce569adbb70257c6ec4f0f6bc585009 release-1.25.4
8618e4d900cc71082fbe7dc72af087937d64faf5 release-1.25.5

126
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,126 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances
of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards
of acceptable behavior and will take appropriate and fair corrective action
in response to any behavior that they deem inappropriate, threatening,
offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for
moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<nginx-oss-community@f5.com>. All complaints will be reviewed and investigated
promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external
channels like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the
[Contributor Covenant](https://www.contributor-covenant.org), version 2.1,
available at
<https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion).
For answers to common questions about this code of conduct, see the FAQ at
<https://www.contributor-covenant.org/faq>. Translations are available at
<https://www.contributor-covenant.org/translations>.

110
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,110 @@
# Contributing Guidelines
The following is a set of guidelines for contributing to nginx project.
We really appreciate that you are considering contributing!
## Table of Contents
- [Ask a Question](#ask-a-question)
- [Report a Bug](#report-a-bug)
- [Suggest a Feature or Enhancement](#suggest-a-feature-or-enhancement)
- [Open a Discussion](#open-a-discussion)
- [Submit a Pull Request](#submit-a-pull-request)
- [Issue Lifecycle](#issue-lifecycle)
## Ask a Question
To ask a question, open an issue on GitHub with the label `question`.
## Report a Bug
To report a bug, open an issue on GitHub with the label `bug` using the
available bug report issue template. Before reporting a bug, make sure the
issue has not already been reported.
## Suggest a Feature or Enhancement
To suggest a feature or enhancement, open an issue on GitHub with the label
`feature` or `enhancement` using the available feature request issue template.
Please ensure the feature or enhancement has not already been suggested.
## Open a Discussion
If you want to engage in a conversation with the community and maintainers,
we encourage you to use
[GitHub Discussions](https://github.com/nginx/nginx/discussions).
## Submit a Pull Request
Follow this plan to contribute a change to NGINX source code:
- Fork the NGINX repository
- Create a branch
- Implement your changes in this branch
- Submit a pull request (PR) when your changes are tested and ready for review
Refer to
[NGINX Development Guide](https://nginx.org/en/docs/dev/development_guide.html)
for questions about NGINX programming.
### Formatting Changes
- Changes should be formatted according to the
[code style](https://nginx.org/en/docs/dev/development_guide.html#code_style)
used by NGINX; sometimes, there is no clear rule, in which case examine how
existing NGINX sources are formatted and mimic this style; changes will more
likely be accepted if style corresponds to the surrounding code
- Keep a clean, concise and meaningful commit history on your branch, rebasing
locally and breaking changes logically into commits before submitting a PR
- Each commit message should have a single-line subject line followed by verbose
description after an empty line
- Limit the subject line to 67 characters, and the rest of the commit message
to 76 characters
- Use subject line prefixes for commits that affect a specific portion of the
code; examples include "Upstream:", "QUIC:", or "Core:"; see the commit history
to get an idea of the prefixes used
- Reference issues in the the subject line; if the commit fixes an issue,
[name it](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
accordingly
### Before Submitting
- The proposed changes should work properly on a wide range of
[supported platforms](https://nginx.org/en/index.html#tested_os_and_platforms)
- Try to make it clear why the suggested change is needed, and provide a use
case, if possible
- Passing your changes through the test suite is a good way to ensure that they
do not cause a regression; the repository with tests can be cloned with the
following command:
```bash
git clone https://github.com/nginx/nginx-tests.git
```
- Submitting a change implies granting project a permission to use it under the
[BSD-2-Clause license](https://github.com/nginx/nginx/blob/master/LICENSE)
## Issue Lifecycle
To ensure a balance between work carried out by the NGINX engineering team
while encouraging community involvement on this project, we use the following
issue lifecycle:
- A new issue is created by a community member
- An owner on the NGINX engineering team is assigned to the issue; this
owner shepherds the issue through the subsequent stages in the issue lifecycle
- The owner assigns one or more
[labels](https://github.com/nginx/nginx/issues/labels) to the issue
- The owner, in collaboration with the wider team (product management and
engineering), determines what milestone to attach to an issue;
generally, milestones correspond to product releases

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
Copyright (C) 2002-2021 Igor Sysoev
Copyright (C) 2011-2025 Nginx, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

230
README.md Normal file
View File

@ -0,0 +1,230 @@
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/9335b488-ffcc-4157-8364-2370a0b70ad0">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/3a7eeb08-1133-47f5-859c-fad4f5a6a013">
<img alt="NGINX Banner">
</picture>
NGINX (pronounced "engine x" or "en-jin-eks") is the world's most popular Web Server, high performance Load Balancer, Reverse Proxy, API Gateway and Content Cache.
NGINX is free and open source software, distributed under the terms of a simplified [2-clause BSD-like license](LICENSE).
Enterprise distributions, commercial support and training are available from [F5, Inc](https://www.f5.com/products/nginx).
> [!IMPORTANT]
> The goal of this README is to provide a basic, structured introduction to NGINX for novice users. Please refer to the [full NGINX documentation](https://nginx.org/en/docs/) for detailed information on [installing](https://nginx.org/en/docs/install.html), [building](https://nginx.org/en/docs/configure.html), [configuring](https://nginx.org/en/docs/dirindex.html), [debugging](https://nginx.org/en/docs/debugging_log.html), and more. These documentation pages also contain a more detailed [Beginners Guide](https://nginx.org/en/docs/beginners_guide.html), How-Tos, [Development guide](https://nginx.org/en/docs/dev/development_guide.html), and a complete module and [directive reference](https://nginx.org/en/docs/dirindex.html).
# Table of contents
- [How it works](#how-it-works)
- [Modules](#modules)
- [Configurations](#configurations)
- [Runtime](#runtime)
- [Downloading and installing](#downloading-and-installing)
- [Stable and Mainline binaries](#stable-and-mainline-binaries)
- [Linux binary installation process](#linux-binary-installation-process)
- [FreeBSD installation process](#freebsd-installation-process)
- [Windows executables](#windows-executables)
- [Dynamic modules](#dynamic-modules)
- [Getting started with NGINX](#getting-started-with-nginx)
- [Installing SSL certificates and enabling TLS encryption](#installing-ssl-certificates-and-enabling-tls-encryption)
- [Load Balancing](#load-balancing)
- [Rate limiting](#rate-limiting)
- [Content caching](#content-caching)
- [Building from source](#building-from-source)
- [Installing dependencies](#installing-dependencies)
- [Cloning the NGINX GitHub repository](#cloning-the-nginx-github-repository)
- [Configuring the build](#configuring-the-build)
- [Compiling](#compiling)
- [Location of binary and installation](#location-of-binary-and-installation)
- [Running and testing the installed binary](#running-and-testing-the-installed-binary)
- [Asking questions and reporting issues](#asking-questions-and-reporting-issues)
- [Contributing code](#contributing-code)
- [Additional help and resources](#additional-help-and-resources)
- [Changelog](#changelog)
- [License](#license)
# How it works
NGINX is installed software with binary packages available for all major operating systems and Linux distributions. See [Tested OS and Platforms](https://nginx.org/en/#tested_os_and_platforms) for a full list of compatible systems.
> [!IMPORTANT]
> While nearly all popular Linux-based operating systems are distributed with a community version of nginx, we highly advise installation and usage of official [packages](https://nginx.org/en/linux_packages.html) or sources from this repository. Doing so ensures that you're using the most recent release or source code, including the latest feature-set, fixes and security patches.
## Modules
NGINX is comprised of individual modules, each extending core functionality by providing additional, configurable features. See "Modules reference" at the bottom of [nginx documentation](https://nginx.org/en/docs/) for a complete list of official modules.
NGINX modules can be built and distributed as static or dynamic modules. Static modules are defined at build-time, compiled, and distributed in the resulting binaries. See [Dynamic Modules](#dynamic-modules) for more information on how they work, as well as, how to obtain, install, and configure them.
> [!TIP]
> You can issue the following command to see which static modules your NGINX binaries were built with:
```bash
nginx -V
```
> See [Configuring the build](#configuring-the-build) for information on how to include specific Static modules into your nginx build.
## Configurations
NGINX is highly flexible and configurable. Provisioning the software is achieved via text-based config file(s) accepting parameters called "[Directives](https://nginx.org/en/docs/dirindex.html)". See [Configuration File's Structure](https://nginx.org/en/docs/beginners_guide.html#conf_structure) for a comprehensive description of how NGINX configuration files work.
> [!NOTE]
> The set of directives available to your distribution of NGINX is dependent on which [modules](#modules) have been made available to it.
## Runtime
Rather than running in a single, monolithic process, NGINX is architected to scale beyond Operating System process limitations by operating as a collection of processes. They include:
- A "master" process that maintains worker processes, as well as, reads and evaluates configuration files.
- One or more "worker" processes that process data (eg. HTTP requests).
The number of [worker processes](https://nginx.org/en/docs/ngx_core_module.html#worker_processes) is defined in the configuration file and may be fixed for a given configuration or automatically adjusted to the number of available CPU cores. In most cases, the latter option optimally balances load across available system resources, as NGINX is designed to efficiently distribute work across all worker processes.
> [!TIP]
> Processes synchronize data through shared memory. For this reason, many NGINX directives require the allocation of shared memory zones. As an example, when configuring [rate limiting](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req), connecting clients may need to be tracked in a [common memory zone](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone) so all worker processes can know how many times a particular client has accessed the server in a span of time.
# Downloading and installing
Follow these steps to download and install precompiled NGINX binaries. You may also choose to [build NGINX locally from source code](#building-from-source).
## Stable and Mainline binaries
NGINX binaries are built and distributed in two versions: stable and mainline. Stable binaries are built from stable branches and only contain critical fixes backported from the mainline version. Mainline binaries are built from the [master branch](https://github.com/nginx/nginx/tree/master) and contain the latest features and bugfixes. You'll need to [decide which is appropriate for your purposes](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/#choosing-between-a-stable-or-a-mainline-version).
## Linux binary installation process
The NGINX binary installation process takes advantage of package managers native to specific Linux distributions. For this reason, first-time installations involve adding the official NGINX package repository to your system's package manager. Follow [these steps](https://nginx.org/en/linux_packages.html) to download, verify, and install NGINX binaries using the package manager appropriate for your Linux distribution.
### Upgrades
Future upgrades to the latest version can be managed using the same package manager without the need to manually download and verify binaries.
## FreeBSD installation process
For more information on installing NGINX on FreeBSD system, visit https://nginx.org/en/docs/install.html
## Windows executables
Windows executables for mainline and stable releases can be found on the main [NGINX download page](https://nginx.org/en/download.html). Note that the current implementation of NGINX for Windows is at the Proof-of-Concept stage and should only be used for development and testing purposes. For additional information, please see [nginx for Windows](https://nginx.org/en/docs/windows.html).
## Dynamic modules
NGINX version 1.9.11 added support for [Dynamic Modules](https://nginx.org/en/docs/ngx_core_module.html#load_module). Unlike Static modules, dynamically built modules can be downloaded, installed, and configured after the core NGINX binaries have been built. [Official dynamic module binaries](https://nginx.org/en/linux_packages.html#dynmodules) are available from the same package repository as the core NGINX binaries described in previous steps.
> [!TIP]
> [NGINX JavaScript (njs)](https://github.com/nginx/njs), is a popular NGINX dynamic module that enables the extension of core NGINX functionality using familiar JavaScript syntax.
> [!IMPORTANT]
> If desired, dynamic modules can also be built statically into NGINX at compile time.
# Getting started with NGINX
For a gentle introduction to NGINX basics, please see our [Beginners Guide](https://nginx.org/en/docs/beginners_guide.html).
## Installing SSL certificates and enabling TLS encryption
See [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html) for a quick guide on how to enable secure traffic to your NGINX installation.
## Load Balancing
For a quick start guide on configuring NGINX as a Load Balancer, please see [Using nginx as HTTP load balancer](https://nginx.org/en/docs/http/load_balancing.html).
## Rate limiting
See our [Rate Limiting with NGINX](https://blog.nginx.org/blog/rate-limiting-nginx) blog post for an overview of core concepts for provisioning NGINX as an API Gateway.
## Content caching
See [A Guide to Caching with NGINX and NGINX Plus](https://blog.nginx.org/blog/nginx-caching-guide) blog post for an overview of how to use NGINX as a content cache (e.g. edge server of a content delivery network).
# Building from source
The following steps can be used to build NGINX from source code available in this repository.
## Installing dependencies
Most Linux distributions will require several dependencies to be installed in order to build NGINX. The following instructions are specific to the `apt` package manager, widely available on most Ubuntu/Debian distributions and their derivatives.
> [!TIP]
> It is always a good idea to update your package repository lists prior to installing new packages.
> ```bash
> sudo apt update
> ```
### Installing compiler and make utility
Use the following command to install the GNU C compiler and Make utility.
```bash
sudo apt install gcc make
```
### Installing dependency libraries
```bash
sudo apt install libpcre3-dev zlib1g-dev
```
> [!WARNING]
> This is the minimal set of dependency libraries needed to build NGINX with rewriting and gzip capabilities. Other dependencies may be required if you choose to build NGINX with additional modules. Monitor the output of the `configure` command discussed in the following sections for information on which modules may be missing. For example, if you plan to use SSL certificates to encrypt traffic with TLS, you'll need to install the OpenSSL library. To do so, issue the following command.
>```bash
>sudo apt install libssl-dev
## Cloning the NGINX GitHub repository
Using your preferred method, clone the NGINX repository into your development directory. See [Cloning a GitHub Repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for additional help.
```bash
git clone https://github.com/nginx/nginx.git
```
## Configuring the build
Prior to building NGINX, you must run the `configure` script with [appropriate flags](https://nginx.org/en/docs/configure.html). This will generate a Makefile in your NGINX source root directory that can then be used to compile NGINX with [options specified during configuration](https://nginx.org/en/docs/configure.html).
From the NGINX source code repository's root directory:
```bash
auto/configure
```
> [!IMPORTANT]
> Configuring the build without any flags will compile NGINX with the default set of options. Please refer to https://nginx.org/en/docs/configure.html for a full list of available build configuration options.
## Compiling
The `configure` script will generate a `Makefile` in the NGINX source root directory upon successful execution. To compile NGINX into a binary, issue the following command from that same directory:
```bash
make
```
## Location of binary and installation
After successful compilation, a binary will be generated at `<NGINX_SRC_ROOT_DIR>/objs/nginx`. To install this binary, issue the following command from the source root directory:
```bash
sudo make install
```
> [!IMPORTANT]
> The binary will be installed into the `/usr/local/nginx/` directory.
## Running and testing the installed binary
To run the installed binary, issue the following command:
```bash
sudo /usr/local/nginx/sbin/nginx
```
You may test NGINX operation using `curl`.
```bash
curl localhost
```
The output of which should start with:
```html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
```
# Asking questions and reporting issues
We encourage you to engage with us.
- [NGINX GitHub Discussions](https://github.com/nginx/nginx/discussions), is the go-to place to start asking questions and sharing your thoughts.
- Our [GitHub Issues](https://github.com/nginx/nginx/issues) page offers space to submit and discuss specific issues, report bugs, and suggest enhancements.
# Contributing code
Please see the [Contributing](CONTRIBUTING.md) guide for information on how to contribute code.
# Additional help and resources
- See the [NGINX Community Blog](https://blog.nginx.org/) for more tips, tricks and HOW-TOs related to NGINX and related projects.
- Access [nginx.org](https://nginx.org/), your go-to source for all documentation, information and software related to the NGINX suite of projects.
# Changelog
See our [changelog](https://nginx.org/en/CHANGES) to keep track of updates.
# License
[2-clause BSD-like license](LICENSE)
---
Additional documentation available at: https://nginx.org/en/docs

103
SECURITY.md Normal file
View File

@ -0,0 +1,103 @@
# Security Policy
This document provides an overview of security concerns related to nginx
deployments, focusing on confidentiality, integrity, availability, and the
implications of configurations and misconfigurations.
## Reporting a Vulnerability
Please report any vulnerabilities via one of the following methods
(in order of preference):
1. [Report a vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability)
within this repository. We are using the GitHub workflow that allows us to
manage vulnerabilities in a private manner and interact with reporters
securely.
2. [Report directly to F5](https://www.f5.com/services/support/report-a-vulnerability).
3. Report via email to security-alert@nginx.org.
This method will be deprecated in the future.
### Vulnerability Disclosure and Fix Process
The nginx team expects that all suspected vulnerabilities be reported
privately via the
[Reporting a Vulnerability](SECURITY.md#reporting-a-vulnerability) guidelines.
If a publicly released vulnerability is reported, we
may request to handle it according to the private disclosure process.
If the reporter agrees, we will follow the private disclosure process.
Security fixes will be applied to all supported stable releases, as well
as the mainline version, as applicable. We recommend using the most recent
mainline or stable release of nginx. Fixes are created and tested by the core
team using a GitHub private fork for security. If necessary, the reporter
may be invited to contribute to the fork and assist with the solution.
The nginx team is committed to responsible information disclosure with
sufficient detail, such as the CVSS score and vector. Privately disclosed
vulnerabilities are embargoed by default until the fix is released.
Communications and fixes remain private until made public. As nginx is
supported by F5, we generally follow the
[F5 security vulnerability response policy](https://my.f5.com/manage/s/article/K4602).
### Vulnerability Disclosure and Fix Service Level Objectives
- We will acknowledge all vulnerability reports within 1 to 3 days.
- Fixes will be developed and released within 90 days from the date of
disclosure. If an extension is needed, we will work with the disclosing person.
- Publicly disclosed (i.e., Zero-Day vulnerabilities) will be addressed ASAP.
## Confidentiality, Integrity, and Availability
### Confidentiality and Integrity
Vulnerabilities compromising data confidentiality or integrity are considered
the highest priority. Any issue leading to unauthorized data access, leaks, or
manipulation will trigger the security release process.
### Availability
Availability issues must meet the following criteria to trigger the security
release process:
- Is present in a standard module included with nginx.
- Arises from traffic that the module is designed to handle.
- Resource exhaustion issues are not mitigated by existing timeout, rate
limiting, or buffer size configurations, or applying changes is impractical.
- Results in highly asymmetric, extreme resource consumption.
Availability issues excluded from the security release process:
- Local file content or upstream response content resulting only in worker
process termination.
- Issues with experimental features which result only in availability impact.
## Trusted Configurations and Misconfigurations
In nginx, configuration files, modules, certificate/key pairs, nginx JavaScript,
and local file content are considered trusted sources. Issues arising from
loading or execution of these trusted components are not considered
vulnerabilities. Operators are responsible for securing and maintaining the
integrity of these sources. Misconfigurations can create vulnerabilities, and
operators should implement configurations according to best practices, review
them regularly, and apply security updates.
## Data Plane vs. Control Plane
The data plane handles traffic through nginx, directly interacting with user
data. nginx inherently trusts the content and instructions from upstream
servers. The control plane governs configuration, management, and orchestration.
Misconfigurations or vulnerabilities in the control plane can cause improper
behavior in the data plane.
## Modules Under Scope
The policy applies to all nginx modules included in this repository. Security
considerations and attack vectors for each module will be identified, with
recommended configurations to mitigate risks.
## Debug Logging and Core Files
Debug logs and core files produced by nginx may contain un-sanitized data,
including sensitive information like client requests, server configurations,
and private key material. These artifacts must be handled carefully to avoid
exposing confidential data.

View File

@ -26,6 +26,10 @@ ngx_msvc_ver=`echo $NGX_MSVC_VER | sed -e 's/^\([0-9]*\).*/\1/'`
case "$NGX_MSVC_VER" in
*ARM64)
NGX_MACHINE=arm64
;;
*x64)
NGX_MACHINE=amd64
;;

View File

@ -7,8 +7,8 @@ if [ $NGX_LIBATOMIC != YES ]; then
have=NGX_HAVE_LIBATOMIC . auto/have
CORE_INCS="$CORE_INCS $NGX_LIBATOMIC/src"
LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/src/libatomic_ops.a"
CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/src/libatomic_ops.a"
LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/build/lib/libatomic_ops.a"
CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/build/lib/libatomic_ops.a"
else
@ -19,7 +19,7 @@ else
#include <atomic_ops.h>"
ngx_feature_path=
ngx_feature_libs="-latomic_ops"
ngx_feature_test="long n = 0;
ngx_feature_test="AO_t n = 0;
if (!AO_compare_and_swap(&n, 0, 1))
return 1;
if (AO_fetch_and_add(&n, 1) != 1)

View File

@ -3,14 +3,19 @@
# Copyright (C) Nginx, Inc.
case $NGX_LIBATOMIC in
/*) ngx_prefix="$NGX_LIBATOMIC/build" ;;
*) ngx_prefix="$PWD/$NGX_LIBATOMIC/build" ;;
esac
cat << END >> $NGX_MAKEFILE
$NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile
cd $NGX_LIBATOMIC && \$(MAKE)
$NGX_LIBATOMIC/build/lib/libatomic_ops.a: $NGX_LIBATOMIC/Makefile
cd $NGX_LIBATOMIC && \$(MAKE) && \$(MAKE) install
$NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE
cd $NGX_LIBATOMIC \\
&& if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
&& ./configure
&& ./configure --prefix=$ngx_prefix
END

View File

@ -12,7 +12,6 @@ if [ $OPENSSL != NONE ]; then
if [ $USE_OPENSSL_QUIC = YES ]; then
have=NGX_QUIC . auto/have
have=NGX_QUIC_OPENSSL_COMPAT . auto/have
fi
case "$CC" in
@ -148,14 +147,18 @@ else
if [ $USE_OPENSSL_QUIC = YES ]; then
ngx_feature="OpenSSL QUIC support"
ngx_feature="OpenSSL QUIC API"
ngx_feature_name="NGX_QUIC"
ngx_feature_test="SSL_set_quic_method(NULL, NULL)"
ngx_feature_test="SSL_set_quic_tls_cbs(NULL, NULL, NULL)"
. auto/feature
if [ $ngx_found = no ]; then
have=NGX_QUIC_OPENSSL_COMPAT . auto/have
ngx_feature="BoringSSL-like QUIC API"
ngx_feature_test="SSL_set_quic_method(NULL, NULL)"
. auto/feature
fi
if [ $ngx_found = no ]; then
ngx_feature="OpenSSL QUIC compatibility"
ngx_feature_test="SSL_CTX_add_custom_ext(NULL, 0, 0,
NULL, NULL, NULL, NULL, NULL)"

View File

@ -13,6 +13,10 @@ case "$CC" in
OPENSSL_TARGET=VC-WIN64A
;;
arm64)
OPENSSL_TARGET=VC-WIN64-ARM
;;
*)
OPENSSL_TARGET=VC-WIN32
;;

View File

@ -36,7 +36,9 @@ if [ $PCRE_LIBRARY = PCRE2 ]; then
pcre2_valid_utf.c \
pcre2_xclass.c"
ngx_pcre_test="pcre2_convert.c \
ngx_pcre_test="pcre2_chkdint.c \
pcre2_compile_class.c \
pcre2_convert.c \
pcre2_extuni.c \
pcre2_find_bracket.c \
pcre2_script_run.c \

View File

@ -1307,10 +1307,11 @@ fi
if [ $USE_OPENSSL = YES ]; then
ngx_module_type=CORE
ngx_module_name=ngx_openssl_module
ngx_module_name="ngx_openssl_module ngx_openssl_cache_module"
ngx_module_incs=
ngx_module_deps=src/event/ngx_event_openssl.h
ngx_module_srcs="src/event/ngx_event_openssl.c
src/event/ngx_event_openssl_cache.c
src/event/ngx_event_openssl_stapling.c"
ngx_module_libs=
ngx_module_link=YES

View File

@ -118,3 +118,19 @@ ngx_feature_libs=
ngx_feature_test="int32_t lock = 0;
if (!OSAtomicCompareAndSwap32Barrier(0, 1, &lock)) return 1"
. auto/feature
ngx_feature="TCP_KEEPALIVE"
ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
ngx_feature_run=no
ngx_feature_incs="#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>"
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_KEEPALIVE, NULL, 0);
setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0);
setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)"
. auto/feature
NGX_KEEPALIVE_CHECKED=YES

View File

@ -150,7 +150,7 @@ fi
ngx_feature="crypt()"
ngx_feature_name=
ngx_feature_name="NGX_HAVE_CRYPT"
ngx_feature_run=no
ngx_feature_incs=
ngx_feature_path=
@ -162,7 +162,7 @@ ngx_feature_test="crypt(\"test\", \"salt\");"
if [ $ngx_found = no ]; then
ngx_feature="crypt() in libcrypt"
ngx_feature_name=
ngx_feature_name="NGX_HAVE_CRYPT"
ngx_feature_run=no
ngx_feature_incs=
ngx_feature_path=
@ -508,6 +508,7 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_DEFER_ACCEPT, NULL, 0)"
. auto/feature
if test -z "$NGX_KEEPALIVE_CHECKED"; then
ngx_feature="TCP_KEEPIDLE"
ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
ngx_feature_run=no
@ -520,6 +521,7 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_KEEPIDLE, NULL, 0);
setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0);
setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)"
. auto/feature
fi
ngx_feature="TCP_FASTOPEN"

View File

@ -37,7 +37,7 @@ charset_map windows-1251 utf-8 {
AA D084 ; # capital Ukrainian YE
AB C2AB ; # left-pointing double angle quotation mark
AC C2AC ; # not sign
AD C2AD ; # soft hypen
AD C2AD ; # soft hyphen
AE C2AE ; # (R)
AF D087 ; # capital Ukrainian YI

View File

@ -1,26 +0,0 @@
/*
* Copyright (C) 2002-2021 Igor Sysoev
* Copyright (C) 2011-2024 Nginx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

View File

@ -1,3 +0,0 @@
Documentation is available at http://nginx.org

View File

@ -5,6 +5,456 @@
<change_log title="nginx">
<changes ver="1.27.5" date="2025-04-16">
<change type="feature">
<para lang="ru">
контроль перегрузки CUBIC в соединениях QUIC.
</para>
<para lang="en">
CUBIC congestion control in QUIC connections.
</para>
</change>
<change type="change">
<para lang="ru">
ограничение на максимальный размер кешируемых в разделяемой памяти
SSL-сессий поднято до 8192.
</para>
<para lang="en">
the maximum size limit for SSL sessions cached in shared memory
has been raised to 8192.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в директивах grpc_ssl_password_file, proxy_ssl_password_file и
uwsgi_ssl_password_file
при загрузке SSL-сертификатов и зашифрованных ключей из переменных;
ошибка появилась в 1.23.1.
</para>
<para lang="en">
in the "grpc_ssl_password_file", "proxy_ssl_password_file", and
"uwsgi_ssl_password_file" directives
when loading SSL certificates and encrypted keys from variables;
the bug had appeared in 1.23.1.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в переменных $ssl_curve и $ssl_curves
при использовании подключаемых кривых в OpenSSL.
</para>
<para lang="en">
in the $ssl_curve and $ssl_curves variables
when using pluggable curves in OpenSSL.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не собирался с musl libc.<br/>
Спасибо Piotr Sikora.
</para>
<para lang="en">
nginx could not be built with musl libc.<br/>
Thanks to Piotr Sikora.
</para>
</change>
<change>
<para lang="ru">
Улучшения производительности и исправления в HTTP/3.
</para>
<para lang="en">
Performance improvements and bugfixes in HTTP/3.
</para>
</change>
</changes>
<changes ver="1.27.4" date="2025-02-05">
<change type="security">
<para lang="ru">
недостаточная проверка в обработке виртуальных серверов
при использовании SNI в TLSv1.3 позволяла повторно использовать
SSL-сессию в контексте другого виртуального сервера,
чтобы обойти проверку клиентских SSL-сертификатов (CVE-2025-23419).
</para>
<para lang="en">
insufficient check in virtual servers handling with TLSv1.3 SNI
allowed to reuse SSL sessions in a different virtual server,
to bypass client SSL certificates verification (CVE-2025-23419).
</para>
</change>
<change type="feature">
<para lang="ru">
директивы ssl_object_cache_inheritable, ssl_certificate_cache,
proxy_ssl_certificate_cache, grpc_ssl_certificate_cache
и uwsgi_ssl_certificate_cache.
</para>
<para lang="en">
the "ssl_object_cache_inheritable", "ssl_certificate_cache",
"proxy_ssl_certificate_cache", "grpc_ssl_certificate_cache",
and "uwsgi_ssl_certificate_cache" directives.
</para>
</change>
<change type="feature">
<para lang="ru">
директива keepalive_min_timeout.
</para>
<para lang="en">
the "keepalive_min_timeout" directive.
</para>
</change>
<change type="workaround">
<para lang="ru">
при использовании zlib-ng
в логах появлялись сообщения "gzip filter failed to use preallocated memory".
</para>
<para lang="en">
"gzip filter failed to use preallocated memory" alerts appeared in logs
when using zlib-ng.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не мог собрать библиотеку libatomic из исходных текстов,
если использовался параметр --with-libatomic=DIR.
</para>
<para lang="en">
nginx could not build libatomic library using the library sources
if the --with-libatomic=DIR option was used.
</para>
</change>
<change type="bugfix">
<para lang="ru">
могла происходить ошибка установления соединения
при использовании 0-RTT в QUIC;
ошибка появилась в 1.27.1.
</para>
<para lang="en">
QUIC connection might not be established when using 0-RTT;
the bug had appeared in 1.27.1.
</para>
</change>
<change type="bugfix">
<para lang="ru">
теперь nginx игнорирует пакеты согласования версий QUIC от клиентов.
</para>
<para lang="en">
nginx now ignores QUIC version negotiation packets from clients.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не собирался на Solaris 10 и более ранних
с модулем ngx_http_v3_module.
</para>
<para lang="en">
nginx could not be built on Solaris 10 and earlier
with the ngx_http_v3_module.
</para>
</change>
<change>
<para lang="ru">
Исправления в HTTP/3.
</para>
<para lang="en">
Bugfixes in HTTP/3.
</para>
</change>
</changes>
<changes ver="1.27.3" date="2024-11-26">
<change type="feature">
<para lang="ru">
директива server в блоке upstream поддерживает
параметр resolve.
</para>
<para lang="en">
the "server" directive in the "upstream" block supports
the "resolve" parameter.
</para>
</change>
<change type="feature">
<para lang="ru">
директивы resolver и resolver_timeout в блоке upstream.
</para>
<para lang="en">
the "resolver" and "resolver_timeout" directives in the "upstream" block.
</para>
</change>
<change type="feature">
<para lang="ru">
поддержка SmarterMail-специфичного режима
IMAP LOGIN с нетегированным ответом CAPABILITY
в почтовом прокси-сервере.
</para>
<para lang="en">
SmarterMail specific mode support
for IMAP LOGIN with untagged CAPABILITY response
in the mail proxy module.
</para>
</change>
<change type="change">
<para lang="ru">
теперь протоколы TLSv1 и TLSv1.1 по умолчанию запрещены.
</para>
<para lang="en">
now TLSv1 and TLSv1.1 protocols are disabled by default.
</para>
</change>
<change type="change">
<para lang="ru">
IPv6-адрес в квадратных скобках без порта теперь можно указывать
в директивах proxy_bind, fastcgi_bind, grpc_bind, memcached_bind,
scgi_bind и uwsgi_bind,
а также как адрес клиента в модуле ngx_http_realip_module.
</para>
<para lang="en">
an IPv6 address in square brackets and no port can be specified
in the "proxy_bind", "fastcgi_bind", "grpc_bind", "memcached_bind",
"scgi_bind", and "uwsgi_bind" directives,
and as client address in ngx_http_realip_module.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в модуле ngx_http_mp4_module.<br/>
Спасибо Nils Bars.
</para>
<para lang="en">
in the ngx_http_mp4_module.<br/>
Thanks to Nils Bars.
</para>
</change>
<change type="bugfix">
<para lang="ru">
параметр so_keepalive директивы listen
мог работать некорректно на DragonFly BSD.
</para>
<para lang="en">
the "so_keepalive" parameter of the "listen" directive
might be handled incorrectly on DragonFly BSD.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в директиве proxy_store.
</para>
<para lang="en">
in the "proxy_store" directive.
</para>
</change>
</changes>
<changes ver="1.27.2" date="2024-10-02">
<change type="feature">
<para lang="ru">
SSL-сертификаты, секретные ключи и списки CRL теперь кешируются
на старте или во время переконфигурации.
</para>
<para lang="en">
SSL certificates, secret keys, and CRLs are now cached
on start or during reconfiguration.
</para>
</change>
<change type="feature">
<para lang="ru">
проверка клиентских сертификатов с помощью OCSP в модуле stream.
</para>
<para lang="en">
client certificate validation with OCSP in the stream module.
</para>
</change>
<change type="feature">
<para lang="ru">
поддержка OCSP stapling в модуле stream.
</para>
<para lang="en">
OCSP stapling support in the stream module.
</para>
</change>
<change type="feature">
<para lang="ru">
директива proxy_pass_trailers в модуле ngx_http_proxy_module.
</para>
<para lang="en">
the "proxy_pass_trailers" directive in the ngx_http_proxy_module.
</para>
</change>
<change type="feature">
<para lang="ru">
директива ssl_client_certificate теперь поддерживает сертификаты
с дополнительными данными.
</para>
<para lang="en">
the "ssl_client_certificate" directive now supports certificates
with auxiliary information.
</para>
</change>
<change type="change">
<para lang="ru">
теперь наличие директивы ssl_client_certificate не обязательно
для проверки клиентских SSL-сертификатов.
</para>
<para lang="en">
now the "ssl_client_certificate" directive is not required
for client SSL certificates verification.
</para>
</change>
</changes>
<changes ver="1.27.1" date="2024-08-14">
<change type="security">
<para lang="ru">
обработка специально созданного mp4-файла модулем ngx_http_mp4_module
могла приводить к падению рабочего процесса (CVE-2024-7347).<br/>
Спасибо Nils Bars.
</para>
<para lang="en">
processing of a specially crafted mp4 file by the ngx_http_mp4_module
might cause a worker process crash (CVE-2024-7347).<br/>
Thanks to Nils Bars.
</para>
</change>
<change type="change">
<para lang="ru">
теперь обработчик в модуле stream не является обязательным.
</para>
<para lang="en">
now the stream module handler is not mandatory.
</para>
</change>
<change type="bugfix">
<para lang="ru">
новые HTTP/2-соединения могли игнорировать
плавное завершение старых рабочих процессов.<br/>
Спасибо Kasei Wang.
</para>
<para lang="en">
new HTTP/2 connections might ignore
graceful shutdown of old worker processes.<br/>
Thanks to Kasei Wang.
</para>
</change>
<change>
<para lang="ru">
Исправления в HTTP/3.
</para>
<para lang="en">
Bugfixes in HTTP/3.
</para>
</change>
</changes>
<changes ver="1.27.0" date="2024-05-29">
<change type="security">
<para lang="ru">
при использовании HTTP/3 обработка специально созданной QUIC-сессии могла
приводить к падению рабочего процесса, отправке клиенту содержимого памяти
рабочего процесса на системах с MTU больше 4096 байт, а также потенциально
могла иметь другие последствия
(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).<br/>
Спасибо Nils Bars из CISPA.
</para>
<para lang="en">
when using HTTP/3, processing of a specially crafted QUIC session might
cause a worker process crash, worker process memory disclosure on systems
with MTU larger than 4096 bytes, or might have potential other impact
(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).<br/>
Thanks to Nils Bars of CISPA.
</para>
</change>
<change type="feature">
<para lang="ru">
директивы proxy_limit_rate, fastcgi_limit_rate,
scgi_limit_rate и uwsgi_limit_rate поддерживают переменные.
</para>
<para lang="en">
variables support
in the "proxy_limit_rate", "fastcgi_limit_rate", "scgi_limit_rate",
and "uwsgi_limit_rate" directives.
</para>
</change>
<change type="bugfix">
<para lang="ru">
уменьшено потребление памяти для долгоживущих запросов,
если используются директивы gzip, gunzip, ssi, sub_filter или grpc_pass.
</para>
<para lang="en">
reduced memory consumption for long-lived requests
if "gzip", "gunzip", "ssi", "sub_filter", or "grpc_pass" directives are used.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не собирался gcc 14,
если использовался параметр --with-libatomic.<br/>
Спасибо Edgar Bonet.
</para>
<para lang="en">
nginx could not be built by gcc 14
if the --with-libatomic option was used.<br/>
Thanks to Edgar Bonet.
</para>
</change>
<change>
<para lang="ru">
Исправления в HTTP/3.
</para>
<para lang="en">
Bugfixes in HTTP/3.
</para>
</change>
</changes>
<changes ver="1.25.5" date="2024-04-16">
<change type="feature">

View File

@ -6,7 +6,7 @@ TEMP = tmp
CC = cl
OBJS = objs.msvc8
OPENSSL = openssl-3.0.13
OPENSSL = openssl-3.0.15
ZLIB = zlib-1.3.1
PCRE = pcre2-10.39
@ -15,8 +15,6 @@ release: export
mv $(TEMP)/$(NGINX)/auto/configure $(TEMP)/$(NGINX)
mv $(TEMP)/$(NGINX)/docs/text/LICENSE $(TEMP)/$(NGINX)
mv $(TEMP)/$(NGINX)/docs/text/README $(TEMP)/$(NGINX)
mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX)
mv $(TEMP)/$(NGINX)/docs/man $(TEMP)/$(NGINX)
@ -30,12 +28,12 @@ release: export
export:
rm -rf $(TEMP)
hg archive -X '.hg*' $(TEMP)/$(NGINX)
git archive --prefix=$(TEMP)/$(NGINX)/ HEAD | tar -x -f - --exclude '.git*'
RELEASE:
hg ci -m nginx-$(VER)-RELEASE
hg tag -m "release-$(VER) tag" release-$(VER)
git commit -m nginx-$(VER)-RELEASE
git tag -m "release-$(VER) tag" release-$(VER)
$(MAKE) -f misc/GNUmakefile release
@ -93,8 +91,11 @@ zip: export
sed -i '' -e "s/$$/`printf '\r'`/" $(TEMP)/$(NGINX)/conf/*
mv $(TEMP)/$(NGINX)/docs/text/LICENSE $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/docs/text/README $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/LICENSE $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/README.md $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/CODE_OF_CONDUCT.md $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/CONTRIBUTING.md $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/SECURITY.md $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX)
rm -r $(TEMP)/$(NGINX)/docs

View File

@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
#define nginx_version 1025005
#define NGINX_VERSION "1.25.5"
#define nginx_version 1029000
#define NGINX_VERSION "1.29.0"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD

View File

@ -94,7 +94,7 @@ typedef intptr_t ngx_flag_t;
#ifndef NGX_ALIGNMENT
#define NGX_ALIGNMENT sizeof(unsigned long) /* platform word */
#define NGX_ALIGNMENT sizeof(uintptr_t) /* platform word */
#endif
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))

View File

@ -765,6 +765,8 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
#if !(NGX_DARWIN)
if (ls[i].keepidle) {
value = ls[i].keepidle;
@ -782,6 +784,8 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
}
}
#endif
if (ls[i].keepintvl) {
value = ls[i].keepintvl;

View File

@ -26,6 +26,7 @@ typedef struct ngx_event_aio_s ngx_event_aio_t;
typedef struct ngx_connection_s ngx_connection_t;
typedef struct ngx_thread_task_s ngx_thread_task_t;
typedef struct ngx_ssl_s ngx_ssl_t;
typedef struct ngx_ssl_cache_s ngx_ssl_cache_t;
typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
typedef struct ngx_quic_stream_s ngx_quic_stream_t;
typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;

View File

@ -38,7 +38,7 @@ static ngx_connection_t dumb;
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
void *rv;
void *rv, *data;
char **senv;
ngx_uint_t i, n;
ngx_log_t *log;
@ -438,6 +438,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
opart = &old_cycle->shared_memory.part;
oshm_zone = opart->elts;
data = NULL;
for (n = 0; /* void */ ; n++) {
if (n >= opart->nelts) {
@ -461,9 +463,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
continue;
}
if (shm_zone[i].tag == oshm_zone[n].tag && shm_zone[i].noreuse) {
data = oshm_zone[n].data;
break;
}
if (shm_zone[i].tag == oshm_zone[n].tag
&& shm_zone[i].shm.size == oshm_zone[n].shm.size
&& !shm_zone[i].noreuse)
&& shm_zone[i].shm.size == oshm_zone[n].shm.size)
{
shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
#if (NGX_WIN32)
@ -490,7 +496,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
goto failed;
}
if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
if (shm_zone[i].init(&shm_zone[i], data) != NGX_OK) {
goto failed;
}

View File

@ -639,7 +639,11 @@ ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
p = ngx_strlchr(text, last, ']');
if (p == NULL || p == last - 1 || *++p != ':') {
if (p == last - 1) {
return ngx_parse_addr(pool, addr, text + 1, len - 2);
}
if (p == NULL || *++p != ':') {
return NGX_DECLINED;
}

View File

@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
ngx_debug_point();
ctx->in = ctx->in->next;
cl = ctx->in;
ctx->in = cl->next;
ngx_free_chain(ctx->pool, cl);
continue;
}
@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
/* delete the completed buf from the ctx->in chain */
if (ngx_buf_size(ctx->in->buf) == 0) {
ctx->in = ctx->in->next;
cl = ctx->in;
ctx->in = cl->next;
ngx_free_chain(ctx->pool, cl);
}
cl = ngx_alloc_chain_link(ctx->pool);

View File

@ -203,6 +203,23 @@ ngx_event_accept(ngx_event_t *ev)
}
}
#if (NGX_HAVE_KEEPALIVE_TUNABLE && NGX_DARWIN)
/* Darwin doesn't inherit TCP_KEEPALIVE from a listening socket */
if (ls->keepidle) {
if (setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,
(const void *) &ls->keepidle, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
"setsockopt(TCP_KEEPALIVE, %d) failed, ignored",
ls->keepidle);
}
}
#endif
*log = ls->log;
c->recv = ngx_recv;

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,9 @@
#include <openssl/bn.h>
#include <openssl/conf.h>
#include <openssl/crypto.h>
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif
@ -83,6 +85,17 @@
#endif
#ifdef OPENSSL_NO_DEPRECATED_3_4
#define SSL_SESSION_get_time(s) SSL_SESSION_get_time_ex(s)
#define SSL_SESSION_set_time(s, t) SSL_SESSION_set_time_ex(s, t)
#endif
#ifdef OPENSSL_NO_DEPRECATED_3_0
#define EVP_CIPHER_CTX_cipher(c) EVP_CIPHER_CTX_get0_cipher(c)
#endif
typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t;
@ -90,6 +103,11 @@ struct ngx_ssl_s {
SSL_CTX *ctx;
ngx_log_t *log;
size_t buffer_size;
ngx_array_t certs;
ngx_rbtree_t staple_rbtree;
ngx_rbtree_node_t staple_sentinel;
};
@ -137,7 +155,7 @@ struct ngx_ssl_connection_s {
#define NGX_SSL_DFLT_BUILTIN_SCACHE -5
#define NGX_SSL_MAX_SESSION_SIZE 4096
#define NGX_SSL_MAX_SESSION_SIZE 8192
typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t;
@ -182,12 +200,27 @@ typedef struct {
#define NGX_SSL_TLSv1_3 0x0040
#if (defined SSL_OP_NO_TLSv1_2 || defined SSL_OP_NO_TLSv1_3)
#define NGX_SSL_DEFAULT_PROTOCOLS (NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)
#else
#define NGX_SSL_DEFAULT_PROTOCOLS (NGX_SSL_TLSv1|NGX_SSL_TLSv1_1)
#endif
#define NGX_SSL_BUFFER 1
#define NGX_SSL_CLIENT 2
#define NGX_SSL_BUFSIZE 16384
#define NGX_SSL_CACHE_CERT 0
#define NGX_SSL_CACHE_PKEY 1
#define NGX_SSL_CACHE_CRL 2
#define NGX_SSL_CACHE_CA 3
#define NGX_SSL_CACHE_INVALIDATE 0x80000000
ngx_int_t ngx_ssl_init(ngx_log_t *log);
ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
@ -196,7 +229,8 @@ ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
ngx_str_t *cert, ngx_str_t *key, ngx_ssl_cache_t *cache,
ngx_array_t *passwords);
ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
ngx_uint_t prefer_server_ciphers);
@ -219,6 +253,13 @@ ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s);
void ngx_ssl_ocsp_cleanup(ngx_connection_t *c);
ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data);
ngx_ssl_cache_t *ngx_ssl_cache_init(ngx_pool_t *pool, ngx_uint_t max,
time_t valid, time_t inactive);
void *ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
ngx_str_t *path, void *data);
void *ngx_ssl_cache_connection_fetch(ngx_ssl_cache_t *cache, ngx_pool_t *pool,
ngx_uint_t index, char **err, ngx_str_t *path, void *data);
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
ngx_array_t *passwords);
@ -320,6 +361,8 @@ ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
void ngx_ssl_free_buffer(ngx_connection_t *c);
ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c);
void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
char *text);
void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
char *fmt, ...);
void ngx_ssl_cleanup_ctx(void *data);
@ -330,10 +373,11 @@ extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index;
extern int ngx_ssl_ticket_keys_index;
extern int ngx_ssl_ocsp_index;
extern int ngx_ssl_certificate_index;
extern int ngx_ssl_next_certificate_index;
extern int ngx_ssl_index;
extern int ngx_ssl_certificate_name_index;
extern int ngx_ssl_stapling_index;
extern u_char ngx_ssl_session_buffer[NGX_SSL_MAX_SESSION_SIZE];
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,8 @@
typedef struct {
ngx_rbtree_node_t node;
ngx_str_t staple;
ngx_msec_t timeout;
@ -154,6 +156,7 @@ static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
void *data);
static ngx_ssl_stapling_t *ngx_ssl_stapling_lookup(ngx_ssl_t *ssl, X509 *cert);
static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
@ -196,11 +199,11 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
ngx_str_t *responder, ngx_uint_t verify)
{
X509 *cert;
ngx_uint_t k;
for (k = 0; k < ssl->certs.nelts; k++) {
cert = ((X509 **) ssl->certs.elts)[k];
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
cert;
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
{
if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify)
!= NGX_OK)
{
@ -235,10 +238,9 @@ ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert,
cln->handler = ngx_ssl_stapling_cleanup;
cln->data = staple;
if (X509_set_ex_data(cert, ngx_ssl_stapling_index, staple) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
return NGX_ERROR;
}
staple->node.key = (ngx_rbtree_key_t) cert;
ngx_rbtree_insert(&ssl->staple_rbtree, &staple->node);
#ifdef SSL_CTRL_SELECT_CURRENT_CERT
/* OpenSSL 1.0.2+ */
@ -545,14 +547,21 @@ ngx_int_t
ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
{
X509 *cert;
ngx_rbtree_t *tree;
ngx_rbtree_node_t *node;
ngx_ssl_stapling_t *staple;
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
cert;
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
tree = &ssl->staple_rbtree;
if (tree->root == tree->sentinel) {
return NGX_OK;
}
for (node = ngx_rbtree_min(tree->root, tree->sentinel);
node;
node = ngx_rbtree_next(tree, node))
{
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index);
staple = ngx_rbtree_data(node, ngx_ssl_stapling_t, node);
staple->resolver = resolver;
staple->resolver_timeout = resolver_timeout;
}
@ -567,6 +576,8 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
int rc;
X509 *cert;
u_char *p;
SSL_CTX *ssl_ctx;
ngx_ssl_t *ssl;
ngx_connection_t *c;
ngx_ssl_stapling_t *staple;
@ -583,7 +594,10 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
return rc;
}
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index);
ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
ssl = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_index);
staple = ngx_ssl_stapling_lookup(ssl, cert);
if (staple == NULL) {
return rc;
@ -613,6 +627,30 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
}
static ngx_ssl_stapling_t *
ngx_ssl_stapling_lookup(ngx_ssl_t *ssl, X509 *cert)
{
ngx_rbtree_key_t key;
ngx_rbtree_node_t *node, *sentinel;
node = ssl->staple_rbtree.root;
sentinel = ssl->staple_rbtree.sentinel;
key = (ngx_rbtree_key_t) cert;
while (node != sentinel) {
if (key != node->key) {
node = (key < node->key) ? node->left : node->right;
continue;
}
return ngx_rbtree_data(node, ngx_ssl_stapling_t, node);
}
return NULL;
}
static void
ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
{

View File

@ -25,6 +25,6 @@ clean:
@rm -f $(RESULT) *.o
debug: $(PROGNAME).o
llvm-objdump -S -no-show-raw-insn $<
llvm-objdump -S --no-show-raw-insn $<
.DELETE_ON_ERROR:

View File

@ -72,7 +72,7 @@ ngx_quic_connstate_dbg(ngx_connection_t *c)
if (qc) {
if (qc->error != (ngx_uint_t) -1) {
if (qc->error) {
p = ngx_slprintf(p, last, "%s", qc->error_app ? " app" : "");
p = ngx_slprintf(p, last, " error:%ui", qc->error);
@ -135,6 +135,9 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
if (scid.len != ctp->initial_scid.len
|| ngx_memcmp(scid.data, ctp->initial_scid.data, scid.len) != 0)
{
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR;
qc->error_reason = "invalid initial_source_connection_id";
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic client initial_source_connection_id mismatch");
return NGX_ERROR;
@ -257,9 +260,9 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf,
qc->send_ctx[i].pending_ack = NGX_QUIC_UNSET_PN;
}
qc->send_ctx[0].level = ssl_encryption_initial;
qc->send_ctx[1].level = ssl_encryption_handshake;
qc->send_ctx[2].level = ssl_encryption_application;
qc->send_ctx[0].level = NGX_QUIC_ENCRYPTION_INITIAL;
qc->send_ctx[1].level = NGX_QUIC_ENCRYPTION_HANDSHAKE;
qc->send_ctx[2].level = NGX_QUIC_ENCRYPTION_APPLICATION;
ngx_queue_init(&qc->free_frames);
@ -308,11 +311,16 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf,
qc->streams.client_max_streams_uni = qc->tp.initial_max_streams_uni;
qc->streams.client_max_streams_bidi = qc->tp.initial_max_streams_bidi;
qc->congestion.window = ngx_min(10 * qc->tp.max_udp_payload_size,
ngx_max(2 * qc->tp.max_udp_payload_size,
qc->congestion.window = ngx_min(10 * NGX_QUIC_MIN_INITIAL_SIZE,
ngx_max(2 * NGX_QUIC_MIN_INITIAL_SIZE,
14720));
qc->congestion.ssthresh = (size_t) -1;
qc->congestion.recovery_start = ngx_current_msec;
qc->congestion.mtu = NGX_QUIC_MIN_INITIAL_SIZE;
qc->congestion.recovery_start = ngx_current_msec - 1;
qc->max_frames = (conf->max_concurrent_streams_uni
+ conf->max_concurrent_streams_bidi)
* conf->stream_buffer_size / 2000;
if (pkt->validated && pkt->retried) {
qc->tp.retry_scid.len = pkt->dcid.len;
@ -512,7 +520,7 @@ ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc)
* to terminate the connection immediately.
*/
if (qc->error == (ngx_uint_t) -1) {
if (qc->error == 0 && rc == NGX_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
qc->error_app = 0;
}
@ -792,13 +800,13 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
pkt->dcid.len, &pkt->dcid);
#if (NGX_DEBUG)
if (pkt->level != ssl_encryption_application) {
if (pkt->level != NGX_QUIC_ENCRYPTION_APPLICATION) {
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic packet rx scid len:%uz %xV",
pkt->scid.len, &pkt->scid);
}
if (pkt->level == ssl_encryption_initial) {
if (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL) {
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic address validation token len:%uz %xV",
pkt->token.len, &pkt->token);
@ -815,7 +823,7 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
return NGX_DECLINED;
}
if (pkt->level != ssl_encryption_application) {
if (pkt->level != NGX_QUIC_ENCRYPTION_APPLICATION) {
if (pkt->version != qc->version) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
@ -845,7 +853,9 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
rc = ngx_quic_handle_payload(c, pkt);
if (rc == NGX_DECLINED && pkt->level == ssl_encryption_application) {
if (rc == NGX_DECLINED
&& pkt->level == NGX_QUIC_ENCRYPTION_APPLICATION)
{
if (ngx_quic_handle_stateless_reset(c, pkt) == NGX_OK) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic stateless reset packet detected");
@ -866,11 +876,11 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
return ngx_quic_negotiate_version(c, pkt);
}
if (pkt->level == ssl_encryption_application) {
if (pkt->level == NGX_QUIC_ENCRYPTION_APPLICATION) {
return ngx_quic_send_stateless_reset(c, conf, pkt);
}
if (pkt->level != ssl_encryption_initial) {
if (pkt->level != NGX_QUIC_ENCRYPTION_INITIAL) {
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic expected initial, got handshake");
return NGX_ERROR;
@ -953,7 +963,7 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
qc = ngx_quic_get_connection(c);
qc->error = (ngx_uint_t) -1;
qc->error = 0;
qc->error_reason = 0;
c->log->action = "decrypting packet";
@ -965,10 +975,10 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
return NGX_DECLINED;
}
#if !defined (OPENSSL_IS_BORINGSSL)
/* OpenSSL provides read keys for an application level before it's ready */
#if (NGX_QUIC_QUICTLS_API)
/* QuicTLS provides app read keys before completing handshake */
if (pkt->level == ssl_encryption_application && !c->ssl->handshaked) {
if (pkt->level == NGX_QUIC_ENCRYPTION_APPLICATION && !c->ssl->handshaked) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic no %s keys ready, ignoring packet",
ngx_quic_level_name(pkt->level));
@ -1006,14 +1016,14 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
}
}
if (pkt->level == ssl_encryption_handshake) {
if (pkt->level == NGX_QUIC_ENCRYPTION_HANDSHAKE) {
/*
* RFC 9001, 4.9.1. Discarding Initial Keys
*
* The successful use of Handshake packets indicates
* that no more Initial packets need to be exchanged
*/
ngx_quic_discard_ctx(c, ssl_encryption_initial);
ngx_quic_discard_ctx(c, NGX_QUIC_ENCRYPTION_INITIAL);
if (!qc->path->validated) {
qc->path->validated = 1;
@ -1022,6 +1032,16 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
}
}
if (pkt->level == NGX_QUIC_ENCRYPTION_APPLICATION) {
/*
* RFC 9001, 4.9.3. Discarding 0-RTT Keys
*
* After receiving a 1-RTT packet, servers MUST discard
* 0-RTT keys within a short time
*/
ngx_quic_keys_discard(qc->keys, NGX_QUIC_ENCRYPTION_EARLY_DATA);
}
if (qc->closing) {
/*
* RFC 9000, 10.2. Immediate Close
@ -1046,7 +1066,7 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
c->log->action = "handling payload";
if (pkt->level != ssl_encryption_application) {
if (pkt->level != NGX_QUIC_ENCRYPTION_APPLICATION) {
return ngx_quic_handle_frames(c, pkt);
}
@ -1071,7 +1091,7 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
void
ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level)
ngx_quic_discard_ctx(ngx_connection_t *c, ngx_uint_t level)
{
ngx_queue_t *q;
ngx_quic_frame_t *f;
@ -1112,7 +1132,7 @@ ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level)
ngx_quic_free_frame(c, f);
}
if (level == ssl_encryption_initial) {
if (level == NGX_QUIC_ENCRYPTION_INITIAL) {
/* close temporary listener with initial dcid */
qsock = ngx_quic_find_socket(c, NGX_QUIC_UNSET_PN);
if (qsock) {

View File

@ -12,6 +12,21 @@
#include <ngx_core.h>
#ifdef OSSL_RECORD_PROTECTION_LEVEL_NONE
#define NGX_QUIC_OPENSSL_API 1
#elif (defined SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION)
#define NGX_QUIC_QUICTLS_API 1
#elif (defined OPENSSL_IS_BORINGSSL || defined LIBRESSL_VERSION_NUMBER)
#define NGX_QUIC_BORINGSSL_API 1
#else
#define NGX_QUIC_BORINGSSL_API 1
#define NGX_QUIC_OPENSSL_COMPAT 1
#endif
#define NGX_QUIC_MAX_UDP_PAYLOAD_SIZE 65527
#define NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT 3

View File

@ -20,6 +20,10 @@
/* RFC 9002, 7.6.1. Duration: kPersistentCongestionThreshold */
#define NGX_QUIC_PERSISTENT_CONGESTION_THR 3
/* CUBIC parameters x10 */
#define NGX_QUIC_CUBIC_BETA 7
#define NGX_QUIC_CUBIC_C 4
/* send time of ACK'ed packets */
typedef struct {
@ -29,18 +33,22 @@ typedef struct {
} ngx_quic_ack_stat_t;
static ngx_inline ngx_msec_t ngx_quic_lost_threshold(ngx_quic_connection_t *qc);
static ngx_inline ngx_msec_t ngx_quic_time_threshold(ngx_quic_connection_t *qc);
static uint64_t ngx_quic_packet_threshold(ngx_quic_send_ctx_t *ctx);
static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack,
enum ssl_encryption_level_t level, ngx_msec_t send_time);
ngx_uint_t level, ngx_msec_t send_time);
static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c,
ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max,
ngx_quic_ack_stat_t *st);
static size_t ngx_quic_congestion_cubic(ngx_connection_t *c);
static void ngx_quic_drop_ack_ranges(ngx_connection_t *c,
ngx_quic_send_ctx_t *ctx, uint64_t pn);
static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c,
ngx_quic_ack_stat_t *st);
static ngx_msec_t ngx_quic_congestion_cubic_time(ngx_connection_t *c);
static ngx_msec_t ngx_quic_pcg_duration(ngx_connection_t *c);
static void ngx_quic_persistent_congestion(ngx_connection_t *c);
static ngx_msec_t ngx_quic_oldest_sent_packet(ngx_connection_t *c);
static void ngx_quic_congestion_lost(ngx_connection_t *c,
ngx_quic_frame_t *frame);
static void ngx_quic_lost_handler(ngx_event_t *ev);
@ -48,7 +56,7 @@ static void ngx_quic_lost_handler(ngx_event_t *ev);
/* RFC 9002, 6.1.2. Time Threshold: kTimeThreshold, kGranularity */
static ngx_inline ngx_msec_t
ngx_quic_lost_threshold(ngx_quic_connection_t *qc)
ngx_quic_time_threshold(ngx_quic_connection_t *qc)
{
ngx_msec_t thr;
@ -59,6 +67,29 @@ ngx_quic_lost_threshold(ngx_quic_connection_t *qc)
}
static uint64_t
ngx_quic_packet_threshold(ngx_quic_send_ctx_t *ctx)
{
uint64_t pkt_thr;
ngx_queue_t *q;
ngx_quic_frame_t *f;
if (ngx_queue_empty(&ctx->sent)) {
return NGX_QUIC_PKT_THR;
}
q = ngx_queue_head(&ctx->sent);
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
pkt_thr = (ctx->pnum - f->pnum) / 2;
if (pkt_thr <= NGX_QUIC_PKT_THR) {
return NGX_QUIC_PKT_THR;
}
return pkt_thr;
}
ngx_int_t
ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_frame_t *f)
@ -77,7 +108,7 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ctx = ngx_quic_get_send_ctx(qc, pkt->level);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_handle_ack_frame level:%d", pkt->level);
"quic ngx_quic_handle_ack_frame level:%ui", pkt->level);
ack = &f->u.ack;
@ -176,7 +207,7 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
static void
ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack,
enum ssl_encryption_level_t level, ngx_msec_t send_time)
ngx_uint_t level, ngx_msec_t send_time)
{
ngx_msec_t latest_rtt, ack_delay, adjusted_rtt, rttvar_sample;
ngx_quic_connection_t *qc;
@ -229,7 +260,7 @@ ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
qc = ngx_quic_get_connection(c);
if (ctx->level == ssl_encryption_application) {
if (ctx->level == NGX_QUIC_ENCRYPTION_APPLICATION) {
if (ngx_quic_handle_path_mtu(c, qc->path, min, max) != NGX_OK) {
return NGX_ERROR;
}
@ -313,8 +344,9 @@ ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
void
ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f)
{
size_t w_cubic;
ngx_uint_t blocked;
ngx_msec_t timer;
ngx_msec_t now, timer;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
@ -329,16 +361,34 @@ ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f)
return;
}
now = ngx_current_msec;
blocked = (cg->in_flight >= cg->window) ? 1 : 0;
cg->in_flight -= f->plen;
/* prevent recovery_start from wrapping */
timer = now - cg->recovery_start;
if ((ngx_msec_int_t) timer < 0) {
cg->recovery_start = ngx_quic_oldest_sent_packet(c) - 1;
}
timer = f->send_time - cg->recovery_start;
if ((ngx_msec_int_t) timer <= 0) {
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion ack recovery win:%uz ss:%z if:%uz",
cg->window, cg->ssthresh, cg->in_flight);
"quic congestion ack rec t:%M win:%uz if:%uz",
now, cg->window, cg->in_flight);
goto done;
}
if (cg->idle) {
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion ack idle t:%M win:%uz if:%uz",
now, cg->window, cg->in_flight);
goto done;
}
@ -346,24 +396,51 @@ ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f)
if (cg->window < cg->ssthresh) {
cg->window += f->plen;
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion slow start win:%uz ss:%z if:%uz",
cg->window, cg->ssthresh, cg->in_flight);
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion ack ss t:%M win:%uz ss:%z if:%uz",
now, cg->window, cg->ssthresh, cg->in_flight);
} else {
cg->window += qc->tp.max_udp_payload_size * f->plen / cg->window;
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion avoidance win:%uz ss:%z if:%uz",
cg->window, cg->ssthresh, cg->in_flight);
/* RFC 9438, 4.2. Window Increase Function */
w_cubic = ngx_quic_congestion_cubic(c);
if (cg->window < cg->w_prior) {
cg->w_est += (uint64_t) cg->mtu * f->plen
* 3 * (10 - NGX_QUIC_CUBIC_BETA)
/ (10 + NGX_QUIC_CUBIC_BETA) / cg->window;
} else {
cg->w_est += (uint64_t) cg->mtu * f->plen / cg->window;
}
/* prevent recovery_start from wrapping */
if (w_cubic < cg->w_est) {
cg->window = cg->w_est;
timer = cg->recovery_start - ngx_current_msec + qc->tp.max_idle_timeout * 2;
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion ack reno t:%M win:%uz c:%uz if:%uz",
now, cg->window, w_cubic, cg->in_flight);
if ((ngx_msec_int_t) timer < 0) {
cg->recovery_start = ngx_current_msec - qc->tp.max_idle_timeout * 2;
} else if (w_cubic > cg->window) {
if (w_cubic >= cg->window * 3 / 2) {
cg->window += cg->mtu / 2;
} else {
cg->window += (uint64_t) cg->mtu * (w_cubic - cg->window)
/ cg->window;
}
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion ack cubic t:%M win:%uz c:%uz if:%uz",
now, cg->window, w_cubic, cg->in_flight);
} else {
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion ack skip t:%M win:%uz c:%uz if:%uz",
now, cg->window, w_cubic, cg->in_flight);
}
}
done:
@ -374,6 +451,87 @@ done:
}
static size_t
ngx_quic_congestion_cubic(ngx_connection_t *c)
{
int64_t w, t, cc;
ngx_msec_t now;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
ngx_quic_congestion_idle(c, cg->idle);
now = ngx_current_msec;
t = (ngx_msec_int_t) (now - cg->k);
if (t > 1000000) {
w = NGX_MAX_SIZE_T_VALUE;
goto done;
}
if (t < -1000000) {
w = 0;
goto done;
}
/*
* RFC 9438, Figure 1
*
* w_cubic = C * (t_msec / 1000) ^ 3 * mtu + w_max
*/
cc = 10000000000ll / (int64_t) cg->mtu / NGX_QUIC_CUBIC_C;
w = t * t * t / cc + (int64_t) cg->w_max;
if (w > NGX_MAX_SIZE_T_VALUE) {
w = NGX_MAX_SIZE_T_VALUE;
}
if (w < 0) {
w = 0;
}
done:
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic cubic t:%L w:%L wm:%uz", t, w, cg->w_max);
return w;
}
void
ngx_quic_congestion_idle(ngx_connection_t *c, ngx_uint_t idle)
{
ngx_msec_t now;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion idle:%ui", idle);
if (cg->window >= cg->ssthresh) {
/* RFC 9438, 5.8. Behavior for Application-Limited Flows */
now = ngx_current_msec;
if (cg->idle) {
cg->k += now - cg->idle_start;
}
cg->idle_start = now;
}
cg->idle = idle;
}
static void
ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
uint64_t pn)
@ -435,6 +593,7 @@ ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
static ngx_int_t
ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st)
{
uint64_t pkt_thr;
ngx_uint_t i, nlost;
ngx_msec_t now, wait, thr, oldest, newest;
ngx_queue_t *q;
@ -444,11 +603,12 @@ ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st)
qc = ngx_quic_get_connection(c);
now = ngx_current_msec;
thr = ngx_quic_lost_threshold(qc);
thr = ngx_quic_time_threshold(qc);
/* send time of lost packets across all send contexts */
oldest = NGX_TIMER_INFINITE;
newest = NGX_TIMER_INFINITE;
#if (NGX_SUPPRESS_WARN)
oldest = now;
newest = now;
#endif
nlost = 0;
@ -460,6 +620,8 @@ ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st)
continue;
}
pkt_thr = ngx_quic_packet_threshold(ctx);
while (!ngx_queue_empty(&ctx->sent)) {
q = ngx_queue_head(&ctx->sent);
@ -471,23 +633,27 @@ ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st)
wait = start->send_time + thr - now;
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic detect_lost pnum:%uL thr:%M wait:%i level:%d",
start->pnum, thr, (ngx_int_t) wait, start->level);
ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic detect_lost pnum:%uL thr:%M pthr:%uL wait:%i level:%ui",
start->pnum, thr, pkt_thr, (ngx_int_t) wait, start->level);
if ((ngx_msec_int_t) wait > 0
&& ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR)
&& ctx->largest_ack - start->pnum < pkt_thr)
{
break;
}
if (start->send_time > qc->first_rtt) {
if ((ngx_msec_int_t) (start->send_time - qc->first_rtt) > 0) {
if (oldest == NGX_TIMER_INFINITE || start->send_time < oldest) {
if (nlost == 0
|| (ngx_msec_int_t) (start->send_time - oldest) < 0)
{
oldest = start->send_time;
}
if (newest == NGX_TIMER_INFINITE || start->send_time > newest) {
if (nlost == 0
|| (ngx_msec_int_t) (start->send_time - newest) > 0)
{
newest = start->send_time;
}
@ -508,8 +674,9 @@ ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st)
* latest ACK frame.
*/
if (st && nlost >= 2 && (st->newest < oldest || st->oldest > newest)) {
if (st && nlost >= 2 && ((ngx_msec_int_t) (st->newest - oldest) < 0
|| (ngx_msec_int_t) (st->oldest - newest) > 0))
{
if (newest - oldest > ngx_quic_pcg_duration(c)) {
ngx_quic_persistent_congestion(c);
}
@ -547,11 +714,43 @@ ngx_quic_persistent_congestion(ngx_connection_t *c)
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
cg->recovery_start = ngx_current_msec;
cg->window = qc->tp.max_udp_payload_size * 2;
cg->mtu = qc->path->mtu;
cg->recovery_start = ngx_quic_oldest_sent_packet(c) - 1;
cg->window = cg->mtu * 2;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic persistent congestion win:%uz", cg->window);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion persistent t:%M win:%uz",
ngx_current_msec, cg->window);
}
static ngx_msec_t
ngx_quic_oldest_sent_packet(ngx_connection_t *c)
{
ngx_msec_t oldest;
ngx_uint_t i;
ngx_queue_t *q;
ngx_quic_frame_t *start;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
oldest = ngx_current_msec;
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ctx = &qc->send_ctx[i];
if (!ngx_queue_empty(&ctx->sent)) {
q = ngx_queue_head(&ctx->sent);
start = ngx_queue_data(q, ngx_quic_frame_t, queue);
if ((ngx_msec_int_t) (start->send_time - oldest) < 0) {
oldest = start->send_time;
}
}
}
return oldest;
}
@ -588,7 +787,7 @@ ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
switch (f->type) {
case NGX_QUIC_FT_ACK:
case NGX_QUIC_FT_ACK_ECN:
if (ctx->level == ssl_encryption_application) {
if (ctx->level == NGX_QUIC_ENCRYPTION_APPLICATION) {
/* force generation of most recent acknowledgment */
ctx->send_ack = NGX_QUIC_MAX_ACK_GAP;
}
@ -631,14 +830,13 @@ ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
case NGX_QUIC_FT_STREAM:
qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id);
if (qs) {
if (qs->send_state == NGX_QUIC_STREAM_SEND_RESET_SENT
if (qs == NULL
|| qs->send_state == NGX_QUIC_STREAM_SEND_RESET_SENT
|| qs->send_state == NGX_QUIC_STREAM_SEND_RESET_RECVD)
{
ngx_quic_free_frame(c, f);
break;
}
}
/* fall through */
@ -660,7 +858,7 @@ static void
ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f)
{
ngx_uint_t blocked;
ngx_msec_t timer;
ngx_msec_t now, timer;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
@ -682,26 +880,41 @@ ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f)
timer = f->send_time - cg->recovery_start;
now = ngx_current_msec;
if ((ngx_msec_int_t) timer <= 0) {
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion lost recovery win:%uz ss:%z if:%uz",
cg->window, cg->ssthresh, cg->in_flight);
"quic congestion lost rec t:%M win:%uz if:%uz",
now, cg->window, cg->in_flight);
goto done;
}
cg->recovery_start = ngx_current_msec;
cg->window /= 2;
if (f->ignore_loss) {
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion lost ignore t:%M win:%uz if:%uz",
now, cg->window, cg->in_flight);
if (cg->window < qc->tp.max_udp_payload_size * 2) {
cg->window = qc->tp.max_udp_payload_size * 2;
goto done;
}
cg->ssthresh = cg->window;
/* RFC 9438, 4.6. Multiplicative Decrease */
cg->mtu = qc->path->mtu;
cg->recovery_start = now;
cg->w_prior = cg->window;
/* RFC 9438, 4.7. Fast Convergence */
cg->w_max = (cg->window < cg->w_max)
? cg->window * (10 + NGX_QUIC_CUBIC_BETA) / 20 : cg->window;
cg->ssthresh = cg->in_flight * NGX_QUIC_CUBIC_BETA / 10;
cg->window = ngx_max(cg->ssthresh, cg->mtu * 2);
cg->w_est = cg->window;
cg->k = now + ngx_quic_congestion_cubic_time(c);
cg->idle_start = now;
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion lost win:%uz ss:%z if:%uz",
cg->window, cg->ssthresh, cg->in_flight);
"quic congestion lost t:%M win:%uz if:%uz",
now, cg->window, cg->in_flight);
done:
@ -711,9 +924,62 @@ done:
}
static ngx_msec_t
ngx_quic_congestion_cubic_time(ngx_connection_t *c)
{
int64_t v, x, d, cc;
ngx_uint_t n;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
/*
* RFC 9438, Figure 2
*
* k_msec = ((w_max - cwnd_epoch) / C / mtu) ^ 1/3 * 1000
*/
if (cg->w_max <= cg->window) {
return 0;
}
cc = 10000000000ll / (int64_t) cg->mtu / NGX_QUIC_CUBIC_C;
v = (int64_t) (cg->w_max - cg->window) * cc;
/*
* Newton-Raphson method for x ^ 3 = v:
*
* x_next = (2 * x_prev + v / x_prev ^ 2) / 3
*/
x = 5000;
for (n = 1; n <= 10; n++) {
d = (v / x / x - x) / 3;
x += d;
if (ngx_abs(d) <= 100) {
break;
}
}
if (x > NGX_MAX_SIZE_T_VALUE) {
return NGX_MAX_SIZE_T_VALUE;
}
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic cubic time:%L n:%ui", x, n);
return x;
}
void
ngx_quic_set_lost_timer(ngx_connection_t *c)
{
uint64_t pkt_thr;
ngx_uint_t i;
ngx_msec_t now;
ngx_queue_t *q;
@ -739,10 +1005,12 @@ ngx_quic_set_lost_timer(ngx_connection_t *c)
q = ngx_queue_head(&ctx->sent);
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
w = (ngx_msec_int_t)
(f->send_time + ngx_quic_lost_threshold(qc) - now);
(f->send_time + ngx_quic_time_threshold(qc) - now);
if (f->pnum <= ctx->largest_ack) {
if (w < 0 || ctx->largest_ack - f->pnum >= NGX_QUIC_PKT_THR) {
pkt_thr = ngx_quic_packet_threshold(ctx);
if (w < 0 || ctx->largest_ack - f->pnum >= pkt_thr) {
w = 0;
}
@ -805,7 +1073,7 @@ ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
duration = qc->avg_rtt;
duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY);
if (ctx->level == ssl_encryption_application && c->ssl->handshaked) {
if (ctx->level == NGX_QUIC_ENCRYPTION_APPLICATION && c->ssl->handshaked) {
duration += qc->ctp.max_ack_delay;
}
@ -1160,7 +1428,7 @@ ngx_quic_generate_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
return NGX_OK;
}
if (ctx->level == ssl_encryption_application) {
if (ctx->level == NGX_QUIC_ENCRYPTION_APPLICATION) {
delay = ngx_current_msec - ctx->ack_delay_start;
qc = ngx_quic_get_connection(c);

View File

@ -17,6 +17,7 @@ ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c,
void ngx_quic_congestion_ack(ngx_connection_t *c,
ngx_quic_frame_t *frame);
void ngx_quic_congestion_idle(ngx_connection_t *c, ngx_uint_t idle);
void ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx);
void ngx_quic_set_lost_timer(ngx_connection_t *c);
void ngx_quic_pto_handler(ngx_event_t *ev);

View File

@ -17,6 +17,15 @@
/* #define NGX_QUIC_DEBUG_ALLOC */ /* log frames and bufs alloc */
/* #define NGX_QUIC_DEBUG_CRYPTO */
#define NGX_QUIC_ENCRYPTION_INITIAL 0
#define NGX_QUIC_ENCRYPTION_EARLY_DATA 1
#define NGX_QUIC_ENCRYPTION_HANDSHAKE 2
#define NGX_QUIC_ENCRYPTION_APPLICATION 3
#define NGX_QUIC_ENCRYPTION_LAST 4
#define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1)
typedef struct ngx_quic_connection_s ngx_quic_connection_t;
typedef struct ngx_quic_server_id_s ngx_quic_server_id_t;
typedef struct ngx_quic_client_id_s ngx_quic_client_id_t;
@ -46,8 +55,6 @@ typedef struct ngx_quic_keys_s ngx_quic_keys_t;
#define NGX_QUIC_UNSET_PN (uint64_t) -1
#define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1)
/* 0-RTT and 1-RTT data exist in the same packet number space,
* so we have 3 packet number spaces:
*
@ -56,8 +63,8 @@ typedef struct ngx_quic_keys_s ngx_quic_keys_t;
* 2 - 0-RTT and 1-RTT
*/
#define ngx_quic_get_send_ctx(qc, level) \
((level) == ssl_encryption_initial) ? &((qc)->send_ctx[0]) \
: (((level) == ssl_encryption_handshake) ? &((qc)->send_ctx[1]) \
((level) == NGX_QUIC_ENCRYPTION_INITIAL) ? &((qc)->send_ctx[0]) \
: (((level) == NGX_QUIC_ENCRYPTION_HANDSHAKE) ? &((qc)->send_ctx[1]) \
: &((qc)->send_ctx[2]))
#define ngx_quic_get_connection(c) \
@ -168,7 +175,14 @@ typedef struct {
size_t in_flight;
size_t window;
size_t ssthresh;
size_t w_max;
size_t w_est;
size_t w_prior;
size_t mtu;
ngx_msec_t recovery_start;
ngx_msec_t idle_start;
ngx_msec_t k;
ngx_uint_t idle; /* unsigned idle:1; */
} ngx_quic_congestion_t;
@ -181,7 +195,7 @@ typedef struct {
* are also Initial packets.
*/
struct ngx_quic_send_ctx_s {
enum ssl_encryption_level_t level;
ngx_uint_t level;
ngx_quic_buffer_t crypto;
uint64_t crypto_sent;
@ -254,6 +268,7 @@ struct ngx_quic_connection_s {
ngx_buf_t *free_shadow_bufs;
ngx_uint_t nframes;
ngx_uint_t max_frames;
#ifdef NGX_QUIC_DEBUG_ALLOC
ngx_uint_t nbufs;
ngx_uint_t nshadowbufs;
@ -271,7 +286,7 @@ struct ngx_quic_connection_s {
off_t received;
ngx_uint_t error;
enum ssl_encryption_level_t error_level;
ngx_uint_t error_level;
ngx_uint_t error_ftype;
const char *error_reason;
@ -286,13 +301,17 @@ struct ngx_quic_connection_s {
unsigned key_phase:1;
unsigned validated:1;
unsigned client_tp_done:1;
#if (NGX_QUIC_OPENSSL_API)
unsigned read_level:2;
unsigned write_level:2;
#endif
};
ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c,
ngx_quic_tp_t *ctp);
void ngx_quic_discard_ctx(ngx_connection_t *c,
enum ssl_encryption_level_t level);
void ngx_quic_discard_ctx(ngx_connection_t *c, ngx_uint_t level);
void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc);
void ngx_quic_shutdown_quic(ngx_connection_t *c);

View File

@ -99,7 +99,7 @@ ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
frame->u.retire_cid.sequence_number = f->seqnum;
@ -452,7 +452,7 @@ ngx_quic_send_server_id(ngx_connection_t *c, ngx_quic_server_id_t *sid)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID;
frame->u.ncid.seqnum = sid->seqnum;
frame->u.ncid.retire = 0;
@ -485,7 +485,7 @@ ngx_quic_free_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
frame->u.retire_cid.sequence_number = cid->seqnum;

View File

@ -214,7 +214,7 @@ ngx_quic_alloc_frame(ngx_connection_t *c)
"quic reuse frame n:%ui", qc->nframes);
#endif
} else if (qc->nframes < 10000) {
} else if (qc->nframes < qc->max_frames) {
frame = ngx_palloc(c->pool, sizeof(ngx_quic_frame_t));
if (frame == NULL) {
return NULL;
@ -648,6 +648,7 @@ ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb)
ngx_quic_free_chain(c, qb->chain);
qb->chain = NULL;
qb->last_chain = NULL;
}

View File

@ -40,7 +40,7 @@ ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
ngx_quic_frame_t *fp;
ngx_quic_connection_t *qc;
if (pkt->level != ssl_encryption_application || pkt->path_challenged) {
if (pkt->level != NGX_QUIC_ENCRYPTION_APPLICATION || pkt->path_challenged) {
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ignoring PATH_CHALLENGE");
return NGX_OK;
@ -55,7 +55,7 @@ ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
return NGX_ERROR;
}
fp->level = ssl_encryption_application;
fp->level = NGX_QUIC_ENCRYPTION_APPLICATION;
fp->type = NGX_QUIC_FT_PATH_RESPONSE;
fp->u.path_response = *f;
@ -93,7 +93,7 @@ ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
return NGX_ERROR;
}
fp->level = ssl_encryption_application;
fp->level = NGX_QUIC_ENCRYPTION_APPLICATION;
fp->type = NGX_QUIC_FT_PING;
ngx_quic_queue_frame(qc, fp);
@ -177,16 +177,17 @@ valid:
if (rst) {
/* prevent old path packets contribution to congestion control */
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
qc->rst_pnum = ctx->pnum;
ngx_memzero(&qc->congestion, sizeof(ngx_quic_congestion_t));
qc->congestion.window = ngx_min(10 * qc->tp.max_udp_payload_size,
ngx_max(2 * qc->tp.max_udp_payload_size,
qc->congestion.window = ngx_min(10 * NGX_QUIC_MIN_INITIAL_SIZE,
ngx_max(2 * NGX_QUIC_MIN_INITIAL_SIZE,
14720));
qc->congestion.ssthresh = (size_t) -1;
qc->congestion.recovery_start = ngx_current_msec;
qc->congestion.mtu = NGX_QUIC_MIN_INITIAL_SIZE;
qc->congestion.recovery_start = ngx_current_msec - 1;
ngx_quic_init_rtt(qc);
}
@ -548,7 +549,7 @@ ngx_quic_validate_path(ngx_connection_t *c, ngx_quic_path_t *path)
(void) ngx_quic_send_path_challenge(c, path);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
pto = ngx_max(ngx_quic_pto(c, ctx), 1000);
path->expires = ngx_current_msec + pto;
@ -578,7 +579,7 @@ ngx_quic_send_path_challenge(ngx_connection_t *c, ngx_quic_path_t *path)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_PATH_CHALLENGE;
ngx_memcpy(frame->u.path_challenge.data, path->challenge[n], 8);
@ -766,7 +767,7 @@ ngx_quic_expire_path_validation(ngx_connection_t *c, ngx_quic_path_t *path)
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
if (++path->tries < NGX_QUIC_PATH_RETRIES) {
pto = ngx_max(ngx_quic_pto(c, ctx), 1000) << path->tries;
@ -829,7 +830,7 @@ ngx_quic_expire_path_mtu_delay(ngx_connection_t *c, ngx_quic_path_t *path)
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
path->tries = 0;
@ -875,7 +876,7 @@ ngx_quic_expire_path_mtu_discovery(ngx_connection_t *c, ngx_quic_path_t *path)
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
if (++path->tries < NGX_QUIC_PATH_RETRIES) {
rc = ngx_quic_send_path_mtu_probe(c, path);
@ -921,11 +922,13 @@ ngx_quic_send_path_mtu_probe(ngx_connection_t *c, ngx_quic_path_t *path)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_PING;
frame->ignore_loss = 1;
frame->ignore_congestion = 1;
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
pnum = ctx->pnum;
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,

View File

@ -35,8 +35,6 @@ typedef struct {
ngx_str_t payload;
uint64_t number;
ngx_quic_compat_keys_t *keys;
enum ssl_encryption_level_t level;
} ngx_quic_compat_record_t;
@ -391,6 +389,7 @@ SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
wbio = BIO_new(BIO_s_null());
if (wbio == NULL) {
BIO_free(rbio);
return 0;
}
@ -434,11 +433,10 @@ ngx_quic_compat_message_callback(int write_p, int version, int content_type,
case SSL3_RT_HANDSHAKE:
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic compat tx %s len:%uz ",
ngx_quic_level_name(level), len);
"quic compat tx level:%d len:%uz", level, len);
if (com->method->add_handshake_data(ssl, level, buf, len) != 1) {
goto failed;
return;
}
break;
@ -448,11 +446,11 @@ ngx_quic_compat_message_callback(int write_p, int version, int content_type,
alert = ((u_char *) buf)[1];
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic compat %s alert:%ui len:%uz ",
ngx_quic_level_name(level), alert, len);
"quic compat level:%d alert:%ui len:%uz",
level, alert, len);
if (com->method->send_alert(ssl, level, alert) != 1) {
goto failed;
return;
}
}
@ -460,10 +458,6 @@ ngx_quic_compat_message_callback(int write_p, int version, int content_type,
}
return;
failed:
ngx_post_event(&qc->close, &ngx_posted_events);
}
@ -486,8 +480,8 @@ SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level,
c = ngx_ssl_get_connection(ssl);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic compat rx %s len:%uz",
ngx_quic_level_name(level), len);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic compat rx level:%d len:%uz", level, len);
qc = ngx_quic_get_connection(c);
com = qc->compat;
@ -500,7 +494,6 @@ SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level,
rec.log = c->log;
rec.number = com->read_record++;
rec.keys = &com->keys;
rec.level = level;
if (level == ssl_encryption_initial) {
n = ngx_min(len, 65535);

View File

@ -7,11 +7,6 @@
#ifndef _NGX_EVENT_QUIC_OPENSSL_COMPAT_H_INCLUDED_
#define _NGX_EVENT_QUIC_OPENSSL_COMPAT_H_INCLUDED_
#if defined SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION \
|| defined LIBRESSL_VERSION_NUMBER
#undef NGX_QUIC_OPENSSL_COMPAT
#else
#include <ngx_config.h>
#include <ngx_core.h>
@ -53,7 +48,4 @@ int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params,
void SSL_get_peer_quic_transport_params(const SSL *ssl,
const uint8_t **out_params, size_t *out_params_len);
#endif /* TLSEXT_TYPE_quic_transport_parameters */
#endif /* _NGX_EVENT_QUIC_OPENSSL_COMPAT_H_INCLUDED_ */

View File

@ -45,9 +45,9 @@
static ngx_int_t ngx_quic_create_datagrams(ngx_connection_t *c);
static void ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx);
static void ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
uint64_t pnum);
static void ngx_quic_commit_send(ngx_connection_t *c);
static void ngx_quic_revert_send(ngx_connection_t *c,
uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST]);
#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL))
static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c);
static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c);
@ -55,7 +55,8 @@ static ssize_t ngx_quic_send_segments(ngx_connection_t *c, u_char *buf,
size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment);
#endif
static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min);
ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min,
ngx_uint_t ack_only);
static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
ngx_quic_header_t *pkt, ngx_quic_path_t *path);
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
@ -127,8 +128,11 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
cg = &qc->congestion;
path = qc->path;
while (cg->in_flight < cg->window) {
#if (NGX_SUPPRESS_WARN)
ngx_memzero(preserved_pnum, sizeof(preserved_pnum));
#endif
do {
p = dst;
len = ngx_quic_path_limit(c, path, path->mtu);
@ -150,16 +154,12 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
if (min > len) {
/* padding can't be applied - avoid sending the packet */
while (i-- > 0) {
ctx = &qc->send_ctx[i];
ngx_quic_revert_send(c, ctx, preserved_pnum[i]);
}
ngx_quic_revert_send(c, preserved_pnum);
return NGX_OK;
}
n = ngx_quic_output_packet(c, ctx, p, len, min);
n = ngx_quic_output_packet(c, ctx, p, len, min,
cg->in_flight >= cg->window);
if (n == NGX_ERROR) {
return NGX_ERROR;
}
@ -180,37 +180,43 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
}
if (n == NGX_AGAIN) {
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ngx_quic_revert_send(c, &qc->send_ctx[i], preserved_pnum[i]);
}
ngx_quic_revert_send(c, preserved_pnum);
ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY);
break;
}
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ngx_quic_commit_send(c, &qc->send_ctx[i]);
}
ngx_quic_commit_send(c);
path->sent += len;
}
} while (cg->in_flight < cg->window);
return NGX_OK;
}
static void
ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
ngx_quic_commit_send(ngx_connection_t *c)
{
ngx_uint_t i, idle;
ngx_queue_t *q;
ngx_quic_frame_t *f;
ngx_quic_send_ctx_t *ctx;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
idle = 1;
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ctx = &qc->send_ctx[i];
if (!ngx_queue_empty(&ctx->frames)) {
idle = 0;
}
while (!ngx_queue_empty(&ctx->sending)) {
q = ngx_queue_head(&ctx->sending);
@ -227,26 +233,42 @@ ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
ngx_quic_free_frame(c, f);
}
}
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic congestion send if:%uz", cg->in_flight);
ngx_quic_congestion_idle(c, idle);
}
static void
ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
uint64_t pnum)
ngx_quic_revert_send(ngx_connection_t *c, uint64_t pnum[NGX_QUIC_SEND_CTX_LAST])
{
ngx_uint_t i;
ngx_queue_t *q;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
while (!ngx_queue_empty(&ctx->sending)) {
qc = ngx_quic_get_connection(c);
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ctx = &qc->send_ctx[i];
if (ngx_queue_empty(&ctx->sending)) {
continue;
}
do {
q = ngx_queue_last(&ctx->sending);
ngx_queue_remove(q);
ngx_queue_insert_head(&ctx->frames, q);
} while (!ngx_queue_empty(&ctx->sending));
ctx->pnum = pnum[i];
}
ctx->pnum = pnum;
ngx_quic_congestion_idle(c, 1);
}
@ -272,17 +294,17 @@ ngx_quic_allow_segmentation(ngx_connection_t *c)
return 0;
}
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_INITIAL);
if (!ngx_queue_empty(&ctx->frames)) {
return 0;
}
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_HANDSHAKE);
if (!ngx_queue_empty(&ctx->frames)) {
return 0;
}
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
bytes = 0;
len = ngx_min(qc->path->mtu, NGX_QUIC_MAX_UDP_SEGMENT_BUF);
@ -295,6 +317,10 @@ ngx_quic_allow_segmentation(ngx_connection_t *c)
bytes += f->len;
if (qc->congestion.in_flight + bytes >= qc->congestion.window) {
return 0;
}
if (bytes > len * 3) {
/* require at least ~3 full packets to batch */
return 1;
@ -311,19 +337,19 @@ ngx_quic_create_segments(ngx_connection_t *c)
size_t len, segsize;
ssize_t n;
u_char *p, *end;
uint64_t preserved_pnum;
ngx_uint_t nseg;
ngx_uint_t nseg, level;
ngx_quic_path_t *path;
ngx_quic_send_ctx_t *ctx;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF];
static uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST];
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
path = qc->path;
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);
if (ngx_quic_generate_ack(c, ctx) != NGX_OK) {
return NGX_ERROR;
@ -335,7 +361,8 @@ ngx_quic_create_segments(ngx_connection_t *c)
nseg = 0;
preserved_pnum = ctx->pnum;
level = ctx - qc->send_ctx;
preserved_pnum[level] = ctx->pnum;
for ( ;; ) {
@ -343,7 +370,7 @@ ngx_quic_create_segments(ngx_connection_t *c)
if (len && cg->in_flight + (p - dst) < cg->window) {
n = ngx_quic_output_packet(c, ctx, p, len, len);
n = ngx_quic_output_packet(c, ctx, p, len, len, 0);
if (n == NGX_ERROR) {
return NGX_ERROR;
}
@ -369,19 +396,18 @@ ngx_quic_create_segments(ngx_connection_t *c)
}
if (n == NGX_AGAIN) {
ngx_quic_revert_send(c, ctx, preserved_pnum);
ngx_quic_revert_send(c, preserved_pnum);
ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY);
break;
}
ngx_quic_commit_send(c, ctx);
ngx_quic_commit_send(c);
path->sent += n;
p = dst;
nseg = 0;
preserved_pnum = ctx->pnum;
preserved_pnum[level] = ctx->pnum;
}
}
@ -411,7 +437,7 @@ ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, size_t len,
ngx_memzero(msg_control, sizeof(msg_control));
iov.iov_len = len;
iov.iov_base = buf;
iov.iov_base = (void *) buf;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@ -474,7 +500,7 @@ ngx_quic_get_padding_level(ngx_connection_t *c)
*/
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_INITIAL);
for (q = ngx_queue_head(&ctx->frames);
q != ngx_queue_sentinel(&ctx->frames);
@ -501,7 +527,7 @@ ngx_quic_get_padding_level(ngx_connection_t *c)
static ssize_t
ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
u_char *data, size_t max, size_t min)
u_char *data, size_t max, size_t min, ngx_uint_t ack_only)
{
size_t len, pad, min_payload, max_payload;
u_char *p;
@ -565,6 +591,10 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
{
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
if (ack_only && f->type != NGX_QUIC_FT_ACK) {
break;
}
if (len >= max_payload) {
break;
}
@ -657,10 +687,10 @@ ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
pkt->flags = NGX_QUIC_PKT_FIXED_BIT;
if (ctx->level == ssl_encryption_initial) {
if (ctx->level == NGX_QUIC_ENCRYPTION_INITIAL) {
pkt->flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL;
} else if (ctx->level == ssl_encryption_handshake) {
} else if (ctx->level == NGX_QUIC_ENCRYPTION_HANDSHAKE) {
pkt->flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE;
} else {
@ -699,7 +729,7 @@ ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
ngx_memzero(&msg, sizeof(struct msghdr));
iov.iov_len = len;
iov.iov_base = buf;
iov.iov_base = (void *) buf;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@ -1073,7 +1103,7 @@ ngx_quic_send_new_token(ngx_connection_t *c, ngx_quic_path_t *path)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_NEW_TOKEN;
frame->data = out;
frame->u.token.length = token.len;

View File

@ -18,6 +18,9 @@
#define NGX_QUIC_INITIAL_CIPHER TLS1_3_CK_AES_128_GCM_SHA256
#define ngx_quic_md(str) { sizeof(str) - 1, str }
static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len,
const EVP_MD *digest, const u_char *prk, size_t prk_len,
const u_char *info, size_t info_len);
@ -29,10 +32,10 @@ static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask,
uint64_t *largest_pn);
static ngx_int_t ngx_quic_crypto_open(ngx_quic_secret_t *s, ngx_str_t *out,
u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log);
const u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log);
#ifndef OPENSSL_IS_BORINGSSL
static ngx_int_t ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out,
u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log);
const u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log);
#endif
static ngx_int_t ngx_quic_crypto_hp_init(const EVP_CIPHER *cipher,
@ -122,12 +125,13 @@ ngx_quic_keys_set_initial_secret(ngx_quic_keys_t *keys, ngx_str_t *secret,
ngx_quic_secret_t *client, *server;
ngx_quic_ciphers_t ciphers;
static const uint8_t salt[20] =
"\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17"
"\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb\x7f\x0a";
static const uint8_t salt[20] = {
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a
};
client = &keys->secrets[ssl_encryption_initial].client;
server = &keys->secrets[ssl_encryption_initial].server;
client = &keys->secrets[NGX_QUIC_ENCRYPTION_INITIAL].client;
server = &keys->secrets[NGX_QUIC_ENCRYPTION_INITIAL].server;
/*
* RFC 9001, section 5. Packet Protection
@ -441,7 +445,7 @@ ngx_quic_crypto_init(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s,
static ngx_int_t
ngx_quic_crypto_open(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce,
ngx_quic_crypto_open(ngx_quic_secret_t *s, ngx_str_t *out, const u_char *nonce,
ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log)
{
#ifdef OPENSSL_IS_BORINGSSL
@ -461,7 +465,7 @@ ngx_quic_crypto_open(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce,
ngx_int_t
ngx_quic_crypto_seal(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce,
ngx_quic_crypto_seal(ngx_quic_secret_t *s, ngx_str_t *out, const u_char *nonce,
ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log)
{
#ifdef OPENSSL_IS_BORINGSSL
@ -483,8 +487,8 @@ ngx_quic_crypto_seal(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce,
#ifndef OPENSSL_IS_BORINGSSL
static ngx_int_t
ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce,
ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log)
ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out,
const u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log)
{
int len, enc;
ngx_quic_crypto_ctx_t *ctx;
@ -606,7 +610,8 @@ ngx_quic_crypto_hp(ngx_quic_secret_t *s, u_char *out, u_char *in,
{
int outlen;
EVP_CIPHER_CTX *ctx;
u_char zero[NGX_QUIC_HP_LEN] = {0};
static const u_char zero[NGX_QUIC_HP_LEN];
ctx = s->hp_ctx;
@ -651,8 +656,8 @@ ngx_quic_crypto_hp_cleanup(ngx_quic_secret_t *s)
ngx_int_t
ngx_quic_keys_set_encryption_secret(ngx_log_t *log, ngx_uint_t is_write,
ngx_quic_keys_t *keys, enum ssl_encryption_level_t level,
const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len)
ngx_quic_keys_t *keys, ngx_uint_t level, const SSL_CIPHER *cipher,
const uint8_t *secret, size_t secret_len)
{
ngx_int_t key_len;
ngx_str_t secret_str;
@ -717,8 +722,8 @@ ngx_quic_keys_set_encryption_secret(ngx_log_t *log, ngx_uint_t is_write,
ngx_uint_t
ngx_quic_keys_available(ngx_quic_keys_t *keys,
enum ssl_encryption_level_t level, ngx_uint_t is_write)
ngx_quic_keys_available(ngx_quic_keys_t *keys, ngx_uint_t level,
ngx_uint_t is_write)
{
if (is_write == 0) {
return keys->secrets[level].client.ctx != NULL;
@ -729,8 +734,7 @@ ngx_quic_keys_available(ngx_quic_keys_t *keys,
void
ngx_quic_keys_discard(ngx_quic_keys_t *keys,
enum ssl_encryption_level_t level)
ngx_quic_keys_discard(ngx_quic_keys_t *keys, ngx_uint_t level)
{
ngx_quic_secret_t *client, *server;
@ -743,8 +747,15 @@ ngx_quic_keys_discard(ngx_quic_keys_t *keys,
ngx_quic_crypto_hp_cleanup(client);
ngx_quic_crypto_hp_cleanup(server);
if (client->secret.len) {
ngx_explicit_memzero(client->secret.data, client->secret.len);
client->secret.len = 0;
}
if (server->secret.len) {
ngx_explicit_memzero(server->secret.data, server->secret.len);
server->secret.len = 0;
}
}
@ -753,7 +764,7 @@ ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys)
{
ngx_quic_secrets_t *current, *next, tmp;
current = &keys->secrets[ssl_encryption_application];
current = &keys->secrets[NGX_QUIC_ENCRYPTION_APPLICATION];
next = &keys->next_key;
ngx_quic_crypto_cleanup(&current->client);
@ -782,7 +793,7 @@ ngx_quic_keys_update(ngx_event_t *ev)
qc = ngx_quic_get_connection(c);
keys = qc->keys;
current = &keys->secrets[ssl_encryption_application];
current = &keys->secrets[NGX_QUIC_ENCRYPTION_APPLICATION];
next = &keys->next_key;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic key update");
@ -844,6 +855,9 @@ ngx_quic_keys_update(ngx_event_t *ev)
ngx_explicit_memzero(current->server.secret.data,
current->server.secret.len);
current->client.secret.len = 0;
current->server.secret.len = 0;
ngx_explicit_memzero(client_key.data, client_key.len);
ngx_explicit_memzero(server_key.data, server_key.len);
@ -870,10 +884,17 @@ ngx_quic_keys_cleanup(ngx_quic_keys_t *keys)
ngx_quic_crypto_cleanup(&next->client);
ngx_quic_crypto_cleanup(&next->server);
if (next->client.secret.len) {
ngx_explicit_memzero(next->client.secret.data,
next->client.secret.len);
next->client.secret.len = 0;
}
if (next->server.secret.len) {
ngx_explicit_memzero(next->server.secret.data,
next->server.secret.len);
next->server.secret.len = 0;
}
}
@ -931,15 +952,15 @@ ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
{
u_char *start;
ngx_str_t ad, itag;
ngx_quic_md_t key;
ngx_quic_secret_t secret;
ngx_quic_ciphers_t ciphers;
/* 5.8. Retry Packet Integrity */
static u_char key_data[16] =
"\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e";
static u_char nonce[NGX_QUIC_IV_LEN] =
"\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb";
static ngx_quic_md_t key = ngx_quic_md(
"\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e");
static const u_char nonce[NGX_QUIC_IV_LEN] = {
0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb
};
static ngx_str_t in = ngx_string("");
ad.data = res->data;
@ -957,8 +978,6 @@ ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
return NGX_ERROR;
}
key.len = sizeof(key_data);
ngx_memcpy(key.data, key_data, sizeof(key_data));
secret.iv.len = NGX_QUIC_IV_LEN;
if (ngx_quic_crypto_init(ciphers.c, &secret, &key, 1, pkt->log)

View File

@ -14,8 +14,6 @@
#include <ngx_event_quic_transport.h>
#define NGX_QUIC_ENCRYPTION_LAST ((ssl_encryption_application) + 1)
/* RFC 5116, 5.1/5.3 and RFC 8439, 2.3/2.5 for all supported ciphers */
#define NGX_QUIC_IV_LEN 12
#define NGX_QUIC_TAG_LEN 16
@ -94,13 +92,11 @@ typedef struct {
ngx_int_t ngx_quic_keys_set_initial_secret(ngx_quic_keys_t *keys,
ngx_str_t *secret, ngx_log_t *log);
ngx_int_t ngx_quic_keys_set_encryption_secret(ngx_log_t *log,
ngx_uint_t is_write, ngx_quic_keys_t *keys,
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
const uint8_t *secret, size_t secret_len);
ngx_uint_t ngx_quic_keys_available(ngx_quic_keys_t *keys,
enum ssl_encryption_level_t level, ngx_uint_t is_write);
void ngx_quic_keys_discard(ngx_quic_keys_t *keys,
enum ssl_encryption_level_t level);
ngx_uint_t is_write, ngx_quic_keys_t *keys, ngx_uint_t level,
const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len);
ngx_uint_t ngx_quic_keys_available(ngx_quic_keys_t *keys, ngx_uint_t level,
ngx_uint_t is_write);
void ngx_quic_keys_discard(ngx_quic_keys_t *keys, ngx_uint_t level);
void ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys);
void ngx_quic_keys_update(ngx_event_t *ev);
void ngx_quic_keys_cleanup(ngx_quic_keys_t *keys);
@ -111,7 +107,7 @@ ngx_int_t ngx_quic_ciphers(ngx_uint_t id, ngx_quic_ciphers_t *ciphers);
ngx_int_t ngx_quic_crypto_init(const ngx_quic_cipher_t *cipher,
ngx_quic_secret_t *s, ngx_quic_md_t *key, ngx_int_t enc, ngx_log_t *log);
ngx_int_t ngx_quic_crypto_seal(ngx_quic_secret_t *s, ngx_str_t *out,
u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log);
const u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log);
void ngx_quic_crypto_cleanup(ngx_quic_secret_t *s);
ngx_int_t ngx_quic_hkdf_expand(ngx_quic_hkdf_t *hkdf, const EVP_MD *digest,
ngx_log_t *log);

View File

@ -10,13 +10,6 @@
#include <ngx_event_quic_connection.h>
#if defined OPENSSL_IS_BORINGSSL \
|| defined LIBRESSL_VERSION_NUMBER \
|| NGX_QUIC_OPENSSL_COMPAT
#define NGX_QUIC_BORINGSSL_API 1
#endif
/*
* RFC 9000, 7.5. Cryptographic Message Buffering
*
@ -25,43 +18,343 @@
#define NGX_QUIC_MAX_BUFFERED 65535
#if (NGX_QUIC_OPENSSL_API)
static int ngx_quic_cbs_send(ngx_ssl_conn_t *ssl_conn,
const unsigned char *data, size_t len, size_t *consumed, void *arg);
static int ngx_quic_cbs_recv_rcd(ngx_ssl_conn_t *ssl_conn,
const unsigned char **data, size_t *bytes_read, void *arg);
static int ngx_quic_cbs_release_rcd(ngx_ssl_conn_t *ssl_conn,
size_t bytes_read, void *arg);
static int ngx_quic_cbs_yield_secret(ngx_ssl_conn_t *ssl_conn, uint32_t level,
int direction, const unsigned char *secret, size_t secret_len, void *arg);
static int ngx_quic_cbs_got_transport_params(ngx_ssl_conn_t *ssl_conn,
const unsigned char *params, size_t params_len, void *arg);
static int ngx_quic_cbs_alert(ngx_ssl_conn_t *ssl_conn, unsigned char alert,
void *arg);
#else /* NGX_QUIC_BORINGSSL_API || NGX_QUIC_QUICTLS_API */
static ngx_inline ngx_uint_t ngx_quic_map_encryption_level(
enum ssl_encryption_level_t ssl_level);
#if (NGX_QUIC_BORINGSSL_API)
static int ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
enum ssl_encryption_level_t ssl_level, const SSL_CIPHER *cipher,
const uint8_t *secret, size_t secret_len);
static int ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
enum ssl_encryption_level_t ssl_level, const SSL_CIPHER *cipher,
const uint8_t *secret, size_t secret_len);
#else
#else /* NGX_QUIC_QUICTLS_API */
static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const uint8_t *read_secret,
enum ssl_encryption_level_t ssl_level, const uint8_t *read_secret,
const uint8_t *write_secret, size_t secret_len);
#endif
static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const uint8_t *data, size_t len);
enum ssl_encryption_level_t ssl_level, const uint8_t *data, size_t len);
static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn);
static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, uint8_t alert);
static ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
enum ssl_encryption_level_t level);
enum ssl_encryption_level_t ssl_level, uint8_t alert);
#endif
static ngx_int_t ngx_quic_handshake(ngx_connection_t *c);
static ngx_int_t ngx_quic_crypto_provide(ngx_connection_t *c, ngx_uint_t level);
#if (NGX_QUIC_OPENSSL_API)
static int
ngx_quic_cbs_send(ngx_ssl_conn_t *ssl_conn,
const unsigned char *data, size_t len, size_t *consumed, void *arg)
{
ngx_connection_t *c = arg;
ngx_chain_t *out;
unsigned int alpn_len;
ngx_quic_frame_t *frame;
const unsigned char *alpn_data;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_cbs_send len:%uz", len);
qc = ngx_quic_get_connection(c);
*consumed = 0;
SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len);
if (alpn_len == 0) {
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL);
qc->error_reason = "missing ALPN extension";
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic missing ALPN extension");
return 1;
}
if (!qc->client_tp_done) {
/* RFC 9001, 8.2. QUIC Transport Parameters Extension */
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION);
qc->error_reason = "missing transport parameters";
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"missing transport parameters");
return 1;
}
ctx = ngx_quic_get_send_ctx(qc, qc->write_level);
out = ngx_quic_copy_buffer(c, (u_char *) data, len);
if (out == NGX_CHAIN_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
frame->data = out;
frame->level = qc->write_level;
frame->type = NGX_QUIC_FT_CRYPTO;
frame->u.crypto.offset = ctx->crypto_sent;
frame->u.crypto.length = len;
ctx->crypto_sent += len;
*consumed = len;
ngx_quic_queue_frame(qc, frame);
return 1;
}
static int
ngx_quic_cbs_recv_rcd(ngx_ssl_conn_t *ssl_conn,
const unsigned char **data, size_t *bytes_read, void *arg)
{
ngx_connection_t *c = arg;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_cbs_recv_rcd");
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, qc->read_level);
for (cl = ctx->crypto.chain; cl; cl = cl->next) {
b = cl->buf;
if (b->sync) {
/* hole */
*bytes_read = 0;
break;
}
*data = b->pos;
*bytes_read = b->last - b->pos;
break;
}
return 1;
}
static int
ngx_quic_cbs_release_rcd(ngx_ssl_conn_t *ssl_conn, size_t bytes_read, void *arg)
{
ngx_connection_t *c = arg;
ngx_chain_t *cl;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_cbs_release_rcd len:%uz", bytes_read);
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, qc->read_level);
cl = ngx_quic_read_buffer(c, &ctx->crypto, bytes_read);
if (cl == NGX_CHAIN_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
ngx_quic_free_chain(c, cl);
return 1;
}
static int
ngx_quic_cbs_yield_secret(ngx_ssl_conn_t *ssl_conn, uint32_t ssl_level,
int direction, const unsigned char *secret, size_t secret_len, void *arg)
{
ngx_connection_t *c = arg;
ngx_uint_t level;
const SSL_CIPHER *cipher;
ngx_quic_connection_t *qc;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_cbs_yield_secret() level:%uD", ssl_level);
#ifdef NGX_QUIC_DEBUG_CRYPTO
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic %s secret len:%uz %*xs",
direction ? "write" : "read", secret_len,
secret_len, secret);
#endif
qc = ngx_quic_get_connection(c);
cipher = SSL_get_current_cipher(ssl_conn);
switch (ssl_level) {
case OSSL_RECORD_PROTECTION_LEVEL_NONE:
level = NGX_QUIC_ENCRYPTION_INITIAL;
break;
case OSSL_RECORD_PROTECTION_LEVEL_EARLY:
level = NGX_QUIC_ENCRYPTION_EARLY_DATA;
break;
case OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE:
level = NGX_QUIC_ENCRYPTION_HANDSHAKE;
break;
default: /* OSSL_RECORD_PROTECTION_LEVEL_APPLICATION */
level = NGX_QUIC_ENCRYPTION_APPLICATION;
break;
}
if (ngx_quic_keys_set_encryption_secret(c->log, direction, qc->keys, level,
cipher, secret, secret_len)
!= NGX_OK)
{
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
if (direction) {
qc->write_level = level;
} else {
qc->read_level = level;
}
return 1;
}
static int
ngx_quic_cbs_got_transport_params(ngx_ssl_conn_t *ssl_conn,
const unsigned char *params, size_t params_len, void *arg)
{
ngx_connection_t *c = arg;
u_char *p, *end;
ngx_quic_tp_t ctp;
ngx_quic_connection_t *qc;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_cbs_got_transport_params() len:%uz",
params_len);
qc = ngx_quic_get_connection(c);
/* defaults for parameters not sent by client */
ngx_memcpy(&ctp, &qc->ctp, sizeof(ngx_quic_tp_t));
p = (u_char *) params;
end = p + params_len;
if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) != NGX_OK) {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR;
qc->error_reason = "failed to process transport parameters";
return 1;
}
if (ngx_quic_apply_transport_params(c, &ctp) != NGX_OK) {
return 1;
}
qc->client_tp_done = 1;
return 1;
}
static int
ngx_quic_cbs_alert(ngx_ssl_conn_t *ssl_conn, unsigned char alert, void *arg)
{
ngx_connection_t *c = arg;
ngx_quic_connection_t *qc;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_cbs_alert() alert:%d", (int) alert);
/* already closed on regular shutdown */
qc = ngx_quic_get_connection(c);
if (qc == NULL) {
return 1;
}
qc->error = NGX_QUIC_ERR_CRYPTO(alert);
qc->error_reason = "handshake failed";
return 1;
}
#else /* NGX_QUIC_BORINGSSL_API || NGX_QUIC_QUICTLS_API */
static ngx_inline ngx_uint_t
ngx_quic_map_encryption_level(enum ssl_encryption_level_t ssl_level)
{
switch (ssl_level) {
case ssl_encryption_initial:
return NGX_QUIC_ENCRYPTION_INITIAL;
case ssl_encryption_early_data:
return NGX_QUIC_ENCRYPTION_EARLY_DATA;
case ssl_encryption_handshake:
return NGX_QUIC_ENCRYPTION_HANDSHAKE;
default: /* ssl_encryption_application */
return NGX_QUIC_ENCRYPTION_APPLICATION;
}
}
#if (NGX_QUIC_BORINGSSL_API)
static int
ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
enum ssl_encryption_level_t ssl_level, const SSL_CIPHER *cipher,
const uint8_t *rsecret, size_t secret_len)
{
ngx_uint_t level;
ngx_connection_t *c;
ngx_quic_connection_t *qc;
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
qc = ngx_quic_get_connection(c);
level = ngx_quic_map_encryption_level(ssl_level);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_set_read_secret() level:%d", level);
"quic ngx_quic_set_read_secret() level:%d", ssl_level);
#ifdef NGX_QUIC_DEBUG_CRYPTO
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic read secret len:%uz %*xs", secret_len,
@ -72,7 +365,7 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
cipher, rsecret, secret_len)
!= NGX_OK)
{
return 0;
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
}
return 1;
@ -81,17 +374,19 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
static int
ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
enum ssl_encryption_level_t ssl_level, const SSL_CIPHER *cipher,
const uint8_t *wsecret, size_t secret_len)
{
ngx_uint_t level;
ngx_connection_t *c;
ngx_quic_connection_t *qc;
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
qc = ngx_quic_get_connection(c);
level = ngx_quic_map_encryption_level(ssl_level);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_set_write_secret() level:%d", level);
"quic ngx_quic_set_write_secret() level:%d", ssl_level);
#ifdef NGX_QUIC_DEBUG_CRYPTO
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic write secret len:%uz %*xs", secret_len,
@ -102,28 +397,31 @@ ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn,
cipher, wsecret, secret_len)
!= NGX_OK)
{
return 0;
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
}
return 1;
}
#else
#else /* NGX_QUIC_QUICTLS_API */
static int
ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const uint8_t *rsecret,
enum ssl_encryption_level_t ssl_level, const uint8_t *rsecret,
const uint8_t *wsecret, size_t secret_len)
{
ngx_uint_t level;
ngx_connection_t *c;
const SSL_CIPHER *cipher;
ngx_quic_connection_t *qc;
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
qc = ngx_quic_get_connection(c);
level = ngx_quic_map_encryption_level(ssl_level);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_set_encryption_secrets() level:%d", level);
"quic ngx_quic_set_encryption_secrets() level:%d",
ssl_level);
#ifdef NGX_QUIC_DEBUG_CRYPTO
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic read secret len:%uz %*xs", secret_len,
@ -136,10 +434,11 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
cipher, rsecret, secret_len)
!= NGX_OK)
{
return 0;
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
if (level == ssl_encryption_early_data) {
if (level == NGX_QUIC_ENCRYPTION_EARLY_DATA) {
return 1;
}
@ -153,7 +452,7 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
cipher, wsecret, secret_len)
!= NGX_OK)
{
return 0;
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
}
return 1;
@ -164,24 +463,24 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
static int
ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const uint8_t *data, size_t len)
enum ssl_encryption_level_t ssl_level, const uint8_t *data, size_t len)
{
u_char *p, *end;
size_t client_params_len;
ngx_uint_t level;
ngx_chain_t *out;
unsigned int alpn_len;
const uint8_t *client_params;
ngx_quic_tp_t ctp;
ngx_quic_frame_t *frame;
ngx_connection_t *c;
const unsigned char *alpn_data;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
unsigned int alpn_len;
const unsigned char *alpn_data;
#endif
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
qc = ngx_quic_get_connection(c);
level = ngx_quic_map_encryption_level(ssl_level);
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_add_handshake_data");
@ -193,20 +492,19 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
* here;
*/
#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len);
if (alpn_len == 0) {
if (qc->error == 0) {
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL);
qc->error_reason = "unsupported protocol in ALPN extension";
qc->error_reason = "missing ALPN extension";
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic unsupported protocol in ALPN extension");
return 0;
"quic missing ALPN extension");
}
#endif
return 1;
}
SSL_get_peer_quic_transport_params(ssl_conn, &client_params,
&client_params_len);
@ -217,12 +515,16 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
if (client_params_len == 0) {
/* RFC 9001, 8.2. QUIC Transport Parameters Extension */
if (qc->error == 0) {
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION);
qc->error_reason = "missing transport parameters";
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"missing transport parameters");
return 0;
}
return 1;
}
p = (u_char *) client_params;
@ -237,11 +539,11 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR;
qc->error_reason = "failed to process transport parameters";
return 0;
return 1;
}
if (ngx_quic_apply_transport_params(c, &ctp) != NGX_OK) {
return 0;
return 1;
}
qc->client_tp_done = 1;
@ -251,12 +553,14 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
out = ngx_quic_copy_buffer(c, (u_char *) data, len);
if (out == NGX_CHAIN_ERROR) {
return 0;
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return 0;
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
return 1;
}
frame->data = out;
@ -279,7 +583,7 @@ ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn)
#if (NGX_DEBUG)
ngx_connection_t *c;
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_flush_flight()");
@ -289,17 +593,17 @@ ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn)
static int
ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level,
uint8_t alert)
ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t ssl_level, uint8_t alert)
{
ngx_connection_t *c;
ngx_quic_connection_t *qc;
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_send_alert() level:%s alert:%d",
ngx_quic_level_name(level), (int) alert);
"quic ngx_quic_send_alert() level:%d alert:%d",
ssl_level, (int) alert);
/* already closed on regular shutdown */
@ -314,18 +618,24 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level,
return 1;
}
#endif
ngx_int_t
ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_frame_t *frame)
{
uint64_t last;
ngx_chain_t *cl;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
ngx_quic_crypto_frame_t *f;
qc = ngx_quic_get_connection(c);
if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) {
return NGX_OK;
}
ctx = ngx_quic_get_send_ctx(qc, pkt->level);
f = &frame->u.crypto;
@ -338,13 +648,13 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
}
if (last <= ctx->crypto.offset) {
if (pkt->level == ssl_encryption_initial) {
if (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL) {
/* speeding up handshake completion */
if (!ngx_queue_empty(&ctx->sent)) {
ngx_quic_resend_frames(c, ctx);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake);
ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_HANDSHAKE);
while (!ngx_queue_empty(&ctx->sent)) {
ngx_quic_resend_frames(c, ctx);
}
@ -354,43 +664,25 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
return NGX_OK;
}
if (f->offset == ctx->crypto.offset) {
if (ngx_quic_crypto_input(c, frame->data, pkt->level) != NGX_OK) {
return NGX_ERROR;
}
ngx_quic_skip_buffer(c, &ctx->crypto, last);
} else {
if (ngx_quic_write_buffer(c, &ctx->crypto, frame->data, f->length,
f->offset)
== NGX_CHAIN_ERROR)
{
return NGX_ERROR;
}
}
cl = ngx_quic_read_buffer(c, &ctx->crypto, (uint64_t) -1);
if (cl) {
if (ngx_quic_crypto_input(c, cl, pkt->level) != NGX_OK) {
if (ngx_quic_crypto_provide(c, pkt->level) != NGX_OK) {
return NGX_ERROR;
}
ngx_quic_free_chain(c, cl);
}
return NGX_OK;
return ngx_quic_handshake(c);
}
static ngx_int_t
ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
enum ssl_encryption_level_t level)
ngx_quic_handshake(ngx_connection_t *c)
{
int n, sslerr;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_ssl_conn_t *ssl_conn;
ngx_quic_frame_t *frame;
ngx_quic_connection_t *qc;
@ -399,20 +691,14 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
ssl_conn = c->ssl->connection;
for (cl = data; cl; cl = cl->next) {
b = cl->buf;
if (!SSL_provide_quic_data(ssl_conn, level, b->pos, b->last - b->pos)) {
ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
"SSL_provide_quic_data() failed");
return NGX_ERROR;
}
}
n = SSL_do_handshake(ssl_conn);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
if (qc->error) {
return NGX_ERROR;
}
if (n <= 0) {
sslerr = SSL_get_error(ssl_conn, n);
@ -428,13 +714,13 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
return NGX_ERROR;
}
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed");
ngx_ssl_connection_error(c, sslerr, 0, "SSL_do_handshake() failed");
return NGX_ERROR;
}
}
if (n <= 0 || SSL_in_init(ssl_conn)) {
if (ngx_quic_keys_available(qc->keys, ssl_encryption_early_data, 0)
if (!SSL_is_init_finished(ssl_conn)) {
if (ngx_quic_keys_available(qc->keys, NGX_QUIC_ENCRYPTION_EARLY_DATA, 0)
&& qc->client_tp_done)
{
if (ngx_quic_init_streams(c) != NGX_OK) {
@ -456,7 +742,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_HANDSHAKE_DONE;
ngx_quic_queue_frame(qc, frame);
@ -480,7 +766,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
* An endpoint MUST discard its Handshake keys
* when the TLS handshake is confirmed.
*/
ngx_quic_discard_ctx(c, ssl_encryption_handshake);
ngx_quic_discard_ctx(c, NGX_QUIC_ENCRYPTION_HANDSHAKE);
ngx_quic_discover_path_mtu(c, qc->path);
@ -497,6 +783,60 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data,
}
static ngx_int_t
ngx_quic_crypto_provide(ngx_connection_t *c, ngx_uint_t level)
{
#if (NGX_QUIC_BORINGSSL_API || NGX_QUIC_QUICTLS_API)
ngx_buf_t *b;
ngx_chain_t *out, *cl;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
enum ssl_encryption_level_t ssl_level;
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, level);
out = ngx_quic_read_buffer(c, &ctx->crypto, (uint64_t) -1);
if (out == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
switch (level) {
case NGX_QUIC_ENCRYPTION_INITIAL:
ssl_level = ssl_encryption_initial;
break;
case NGX_QUIC_ENCRYPTION_EARLY_DATA:
ssl_level = ssl_encryption_early_data;
break;
case NGX_QUIC_ENCRYPTION_HANDSHAKE:
ssl_level = ssl_encryption_handshake;
break;
default: /* NGX_QUIC_ENCRYPTION_APPLICATION */
ssl_level = ssl_encryption_application;
break;
}
for (cl = out; cl; cl = cl->next) {
b = cl->buf;
if (!SSL_provide_quic_data(c->ssl->connection, ssl_level, b->pos,
b->last - b->pos))
{
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
"SSL_provide_quic_data() failed");
return NGX_ERROR;
}
}
ngx_quic_free_chain(c, out);
#endif
return NGX_OK;
}
ngx_int_t
ngx_quic_init_connection(ngx_connection_t *c)
{
@ -507,7 +847,33 @@ ngx_quic_init_connection(ngx_connection_t *c)
ngx_ssl_conn_t *ssl_conn;
ngx_quic_socket_t *qsock;
ngx_quic_connection_t *qc;
#if (NGX_QUIC_OPENSSL_API)
static const OSSL_DISPATCH qtdis[] = {
{ OSSL_FUNC_SSL_QUIC_TLS_CRYPTO_SEND,
(void (*)(void)) ngx_quic_cbs_send },
{ OSSL_FUNC_SSL_QUIC_TLS_CRYPTO_RECV_RCD,
(void (*)(void)) ngx_quic_cbs_recv_rcd },
{ OSSL_FUNC_SSL_QUIC_TLS_CRYPTO_RELEASE_RCD,
(void (*)(void)) ngx_quic_cbs_release_rcd },
{ OSSL_FUNC_SSL_QUIC_TLS_YIELD_SECRET,
(void (*)(void)) ngx_quic_cbs_yield_secret },
{ OSSL_FUNC_SSL_QUIC_TLS_GOT_TRANSPORT_PARAMS,
(void (*)(void)) ngx_quic_cbs_got_transport_params },
{ OSSL_FUNC_SSL_QUIC_TLS_ALERT,
(void (*)(void)) ngx_quic_cbs_alert },
{ 0, NULL }
};
#else /* NGX_QUIC_BORINGSSL_API || NGX_QUIC_QUICTLS_API */
static SSL_QUIC_METHOD quic_method;
#endif
qc = ngx_quic_get_connection(c);
@ -519,6 +885,20 @@ ngx_quic_init_connection(ngx_connection_t *c)
ssl_conn = c->ssl->connection;
#if (NGX_QUIC_OPENSSL_API)
if (SSL_set_quic_tls_cbs(ssl_conn, qtdis, c) == 0) {
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
"quic SSL_set_quic_tls_cbs() failed");
return NGX_ERROR;
}
if (SSL_CTX_get_max_early_data(qc->conf->ssl->ctx)) {
SSL_set_quic_tls_early_data_enabled(ssl_conn, 1);
}
#else /* NGX_QUIC_BORINGSSL_API || NGX_QUIC_QUICTLS_API */
if (!quic_method.send_alert) {
#if (NGX_QUIC_BORINGSSL_API)
quic_method.set_read_secret = ngx_quic_set_read_secret;
@ -532,15 +912,17 @@ ngx_quic_init_connection(ngx_connection_t *c)
}
if (SSL_set_quic_method(ssl_conn, &quic_method) == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
"quic SSL_set_quic_method() failed");
return NGX_ERROR;
}
#ifdef OPENSSL_INFO_QUIC
#if (NGX_QUIC_QUICTLS_API)
if (SSL_CTX_get_max_early_data(qc->conf->ssl->ctx)) {
SSL_set_quic_early_data_enabled(ssl_conn, 1);
}
#endif
#endif
qsock = ngx_quic_get_socket(c);
@ -572,15 +954,23 @@ ngx_quic_init_connection(ngx_connection_t *c)
"quic transport parameters len:%uz %*xs", len, len, p);
#endif
#if (NGX_QUIC_OPENSSL_API)
if (SSL_set_quic_tls_transport_params(ssl_conn, p, len) == 0) {
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
"quic SSL_set_quic_tls_transport_params() failed");
return NGX_ERROR;
}
#else
if (SSL_set_quic_transport_params(ssl_conn, p, len) == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
"quic SSL_set_quic_transport_params() failed");
return NGX_ERROR;
}
#endif
#ifdef OPENSSL_IS_BORINGSSL
if (SSL_set_quic_early_data_context(ssl_conn, p, clen) == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
"quic SSL_set_quic_early_data_context() failed");
return NGX_ERROR;
}

View File

@ -174,7 +174,7 @@ ngx_int_t
ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc)
{
ngx_pool_t *pool;
ngx_queue_t *q;
ngx_queue_t *q, posted_events;
ngx_rbtree_t *tree;
ngx_connection_t *sc;
ngx_rbtree_node_t *node;
@ -197,6 +197,8 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc)
return NGX_OK;
}
ngx_queue_init(&posted_events);
node = ngx_rbtree_min(tree->root, tree->sentinel);
while (node) {
@ -213,15 +215,21 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc)
}
sc->read->error = 1;
sc->read->ready = 1;
sc->write->error = 1;
ngx_quic_set_event(sc->read);
ngx_quic_set_event(sc->write);
sc->write->ready = 1;
sc->close = 1;
sc->read->handler(sc->read);
if (sc->read->posted) {
ngx_delete_posted_event(sc->read);
}
ngx_post_event(sc->read, &posted_events);
}
ngx_event_process_posted((ngx_cycle_t *) ngx_cycle, &posted_events);
if (tree->root == tree->sentinel) {
return NGX_OK;
}
@ -272,7 +280,7 @@ ngx_quic_do_reset_stream(ngx_quic_stream_t *qs, ngx_uint_t err)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_RESET_STREAM;
frame->u.reset_stream.id = qs->id;
frame->u.reset_stream.error_code = err;
@ -359,7 +367,7 @@ ngx_quic_shutdown_stream_recv(ngx_connection_t *c)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0,
"quic stream id:0x%xL recv shutdown", qs->id);
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_STOP_SENDING;
frame->u.stop_sending.id = qs->id;
frame->u.stop_sending.error_code = qc->conf->stream_close_code;
@ -519,7 +527,7 @@ ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_RESET_STREAM;
frame->u.reset_stream.id = id;
frame->u.reset_stream.error_code = code;
@ -532,7 +540,7 @@ ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_STOP_SENDING;
frame->u.stop_sending.id = id;
frame->u.stop_sending.error_code = code;
@ -1054,7 +1062,7 @@ ngx_quic_stream_flush(ngx_quic_stream_t *qs)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_STREAM;
frame->data = out;
@ -1172,7 +1180,7 @@ ngx_quic_close_stream(ngx_quic_stream_t *qs)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_MAX_STREAMS;
if (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
@ -1763,7 +1771,7 @@ ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_MAX_STREAM_DATA;
frame->u.max_stream_data.id = qs->id;
frame->u.max_stream_data.limit = qs->recv_max_data;
@ -1799,7 +1807,7 @@ ngx_quic_update_max_data(ngx_connection_t *c)
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
frame->type = NGX_QUIC_FT_MAX_DATA;
frame->u.max_data.max_data = qc->streams.recv_max_data;

View File

@ -281,7 +281,7 @@ ngx_int_t
ngx_quic_parse_packet(ngx_quic_header_t *pkt)
{
if (!ngx_quic_long_pkt(pkt->flags)) {
pkt->level = ssl_encryption_application;
pkt->level = NGX_QUIC_ENCRYPTION_APPLICATION;
if (ngx_quic_parse_short_header(pkt, NGX_QUIC_SERVER_CID_LEN) != NGX_OK)
{
@ -295,6 +295,11 @@ ngx_quic_parse_packet(ngx_quic_header_t *pkt)
return NGX_ERROR;
}
if (pkt->version == 0) {
/* version negotiation */
return NGX_ERROR;
}
if (!ngx_quic_supported_version(pkt->version)) {
return NGX_ABORT;
}
@ -463,13 +468,13 @@ ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt)
return NGX_ERROR;
}
pkt->level = ssl_encryption_initial;
pkt->level = NGX_QUIC_ENCRYPTION_INITIAL;
} else if (ngx_quic_pkt_zrtt(pkt->flags)) {
pkt->level = ssl_encryption_early_data;
pkt->level = NGX_QUIC_ENCRYPTION_EARLY_DATA;
} else if (ngx_quic_pkt_hs(pkt->flags)) {
pkt->level = ssl_encryption_handshake;
pkt->level = NGX_QUIC_ENCRYPTION_HANDSHAKE;
} else {
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
@ -588,7 +593,7 @@ ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len)
/* flags, version, dcid and scid with lengths and zero-length token */
len = 5 + 2 + pkt->dcid.len + pkt->scid.len
+ (pkt->level == ssl_encryption_initial ? 1 : 0);
+ (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL ? 1 : 0);
if (len > pkt_len) {
return 0;
@ -627,7 +632,7 @@ ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
if (out == NULL) {
return 5 + 2 + pkt->dcid.len + pkt->scid.len
+ ngx_quic_varint_len(rem_len) + pkt->num_len
+ (pkt->level == ssl_encryption_initial ? 1 : 0);
+ (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL ? 1 : 0);
}
p = start = out;
@ -642,7 +647,7 @@ ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
*p++ = pkt->scid.len;
p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);
if (pkt->level == ssl_encryption_initial) {
if (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL) {
ngx_quic_build_int(&p, 0);
}
@ -1750,6 +1755,14 @@ ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp,
return NGX_ERROR;
}
if ((size_t) (end - p) < len) {
ngx_log_error(NGX_LOG_INFO, log, 0,
"quic failed to parse"
" transport param id:0x%xL, data length %uL too long",
id, len);
return NGX_ERROR;
}
rc = ngx_quic_parse_transport_param(p, p + len, id, tp);
if (rc == NGX_ERROR) {
@ -1760,7 +1773,7 @@ ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp,
}
if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_INFO, log, 0,
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
"quic %s transport param id:0x%xL, skipped",
(id % 31 == 27) ? "reserved" : "unknown", id);
}

View File

@ -47,9 +47,9 @@
(ngx_quic_long_pkt(flags) ? 0x0F : 0x1F)
#define ngx_quic_level_name(lvl) \
(lvl == ssl_encryption_application) ? "app" \
: (lvl == ssl_encryption_initial) ? "init" \
: (lvl == ssl_encryption_handshake) ? "hs" : "early"
(lvl == NGX_QUIC_ENCRYPTION_APPLICATION) ? "app" \
: (lvl == NGX_QUIC_ENCRYPTION_INITIAL) ? "init" \
: (lvl == NGX_QUIC_ENCRYPTION_HANDSHAKE) ? "hs" : "early"
#define NGX_QUIC_MAX_CID_LEN 20
#define NGX_QUIC_SERVER_CID_LEN NGX_QUIC_MAX_CID_LEN
@ -262,7 +262,7 @@ typedef struct ngx_quic_frame_s ngx_quic_frame_t;
struct ngx_quic_frame_s {
ngx_uint_t type;
enum ssl_encryption_level_t level;
ngx_uint_t level;
ngx_queue_t queue;
uint64_t pnum;
size_t plen;
@ -271,6 +271,7 @@ struct ngx_quic_frame_s {
unsigned need_ack:1;
unsigned pkt_need_ack:1;
unsigned ignore_congestion:1;
unsigned ignore_loss:1;
ngx_chain_t *data;
union {
@ -309,7 +310,7 @@ typedef struct {
uint8_t flags;
uint32_t version;
ngx_str_t token;
enum ssl_encryption_level_t level;
ngx_uint_t level;
ngx_uint_t error;
/* filled in by parser */

View File

@ -1332,6 +1332,12 @@ ngx_http_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
table = ctx->table;
if (ctx->charset->utf8) {
if (value[1].len / 2 > NGX_UTF_LEN - 1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
p = &table->src2dst[src * NGX_UTF_LEN];
*p++ = (u_char) (value[1].len / 2);

View File

@ -375,7 +375,7 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
{ ngx_string("fastcgi_limit_rate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
ngx_http_set_complex_value_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate),
NULL },
@ -2877,7 +2877,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.store_lengths = NULL;
* conf->upstream.store_values = NULL;
*
* conf->index.len = { 0, NULL };
* conf->index = { 0, NULL };
*/
conf->upstream.store = NGX_CONF_UNSET;
@ -2898,7 +2898,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
@ -3015,8 +3015,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_size_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, 0);
ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, NULL);
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
@ -3781,6 +3781,11 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
if (value[1].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
return NGX_CONF_ERROR;
}
#if (NGX_HTTP_CACHE)
if (flcf->upstream.cache > 0) {
return "is incompatible with \"fastcgi_cache\"";

View File

@ -205,6 +205,8 @@ static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#if (NGX_HTTP_SSL)
static char *ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post,
@ -437,6 +439,13 @@ static ngx_command_t ngx_http_grpc_commands[] = {
offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate_key),
NULL },
{ ngx_string("grpc_ssl_certificate_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
ngx_http_grpc_ssl_certificate_cache,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("grpc_ssl_password_file"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_grpc_ssl_password_file,
@ -1231,7 +1240,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
ngx_buf_t *b;
ngx_int_t rc;
ngx_uint_t next, last;
ngx_chain_t *cl, *out, **ll;
ngx_chain_t *cl, *out, *ln, **ll;
ngx_http_upstream_t *u;
ngx_http_grpc_ctx_t *ctx;
ngx_http_grpc_frame_t *f;
@ -1459,7 +1468,10 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
last = 1;
}
ln = in;
in = in->next;
ngx_free_chain(r->pool, ln);
}
ctx->in = in;
@ -4383,6 +4395,7 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR;
conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
#endif
@ -4473,9 +4486,7 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.ssl_session_reuse, 1);
ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
(NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));
ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
"DEFAULT");
@ -4496,8 +4507,15 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.ssl_certificate, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
prev->upstream.ssl_certificate_key, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords,
prev->upstream.ssl_passwords, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache,
prev->upstream.ssl_certificate_cache, NULL);
if (ngx_http_upstream_merge_ssl_passwords(cf, &conf->upstream,
&prev->upstream)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
prev->ssl_conf_commands, NULL);
@ -4846,6 +4864,100 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_HTTP_SSL)
static char *
ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_grpc_loc_conf_t *plcf = conf;
time_t inactive, valid;
ngx_str_t *value, s;
ngx_int_t max;
ngx_uint_t i;
if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
max = 0;
inactive = 10;
valid = 60;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
max = ngx_atoi(value[i].data + 4, value[i].len - 4);
if (max <= 0) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
s.len = value[i].len - 6;
s.data = value[i].data + 6;
valid = ngx_parse_time(&s, 1);
if (valid == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strcmp(value[i].data, "off") == 0) {
plcf->upstream.ssl_certificate_cache = NULL;
continue;
}
failed:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (plcf->upstream.ssl_certificate_cache == NULL) {
return NGX_CONF_OK;
}
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"grpc_ssl_certificate_cache\" must have "
"the \"max\" parameter");
return NGX_CONF_ERROR;
}
plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max,
valid, inactive);
if (plcf->upstream.ssl_certificate_cache == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@ -4970,16 +5082,9 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf)
return NGX_ERROR;
}
if (glcf->upstream.ssl_certificate->lengths
|| glcf->upstream.ssl_certificate_key->lengths)
if (glcf->upstream.ssl_certificate->lengths == NULL
&& glcf->upstream.ssl_certificate_key->lengths == NULL)
{
glcf->upstream.ssl_passwords =
ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords);
if (glcf->upstream.ssl_passwords == NULL) {
return NGX_ERROR;
}
} else {
if (ngx_ssl_certificate(cf, glcf->upstream.ssl,
&glcf->upstream.ssl_certificate->value,
&glcf->upstream.ssl_certificate_key->value,

View File

@ -333,6 +333,8 @@ static ngx_int_t
ngx_http_gunzip_filter_add_data(ngx_http_request_t *r,
ngx_http_gunzip_ctx_t *ctx)
{
ngx_chain_t *cl;
if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) {
return NGX_OK;
}
@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http_request_t *r,
return NGX_DECLINED;
}
ctx->in_buf = ctx->in->buf;
ctx->in = ctx->in->next;
cl = ctx->in;
ctx->in_buf = cl->buf;
ctx->in = cl->next;
ngx_free_chain(r->pool, cl);
ctx->zstream.next_in = ctx->in_buf->pos;
ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos;
@ -374,6 +379,7 @@ static ngx_int_t
ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r,
ngx_http_gunzip_ctx_t *ctx)
{
ngx_chain_t *cl;
ngx_http_gunzip_conf_t *conf;
if (ctx->zstream.avail_out) {
@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r,
conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module);
if (ctx->free) {
ctx->out_buf = ctx->free->buf;
ctx->free = ctx->free->next;
cl = ctx->free;
ctx->out_buf = cl->buf;
ctx->free = cl->next;
ngx_free_chain(r->pool, cl);
ctx->out_buf->flush = 0;

View File

@ -516,8 +516,10 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
/*
* Another zlib variant, https://github.com/zlib-ng/zlib-ng.
* It used to force window bits to 13 for fast compression level,
* uses (64 + sizeof(void*)) additional space on all allocations
* for alignment, 16-byte padding in one of window-sized buffers,
* used (64 + sizeof(void*)) additional space on all allocations
* for alignment and 16-byte padding in one of window-sized buffers,
* uses a single allocation with up to 200 bytes for alignment and
* internal pointers, 5/4 times more memory for the pending buffer,
* and 128K hash.
*/
@ -526,7 +528,7 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
}
ctx->allocated = 8192 + 16 + (1 << (wbits + 2))
+ 131072 + (1 << (memlevel + 8))
+ 131072 + (5 << (memlevel + 6))
+ 4 * (64 + sizeof(void*));
ctx->zlib_ng = 1;
}
@ -985,10 +987,14 @@ static void
ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx)
{
ngx_chain_t *cl;
ngx_chain_t *cl, *ln;
for (cl = ctx->copied; cl; cl = cl->next) {
ngx_pfree(r->pool, cl->buf->start);
for (cl = ctx->copied; cl; /* void */) {
ln = cl;
cl = cl->next;
ngx_pfree(r->pool, ln->buf->start);
ngx_free_chain(r->pool, ln);
}
ctx->copied = NULL;

View File

@ -3099,7 +3099,8 @@ static ngx_int_t
ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak, ngx_uint_t start)
{
uint32_t start_sample, chunk, samples, id, next_chunk, n,
uint64_t n;
uint32_t start_sample, chunk, samples, id, next_chunk,
prev_samples;
ngx_buf_t *data, *buf;
ngx_uint_t entries, target_chunk, chunk_samples;
@ -3155,12 +3156,19 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
next_chunk = ngx_mp4_get_32value(entry->chunk);
if (next_chunk < chunk) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"unordered mp4 stsc chunks in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"sample:%uD, chunk:%uD, chunks:%uD, "
"samples:%uD, id:%uD",
start_sample, chunk, next_chunk - chunk, samples, id);
n = (next_chunk - chunk) * samples;
n = (uint64_t) (next_chunk - chunk) * samples;
if (start_sample < n) {
goto found;
@ -3168,7 +3176,10 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
start_sample -= n;
if (next_chunk > chunk) {
prev_samples = samples;
}
chunk = next_chunk;
samples = ngx_mp4_get_32value(entry->samples);
id = ngx_mp4_get_32value(entry->id);
@ -3178,11 +3189,18 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
next_chunk = trak->chunks + 1;
if (next_chunk < chunk) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"unordered mp4 stsc chunks in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"sample:%uD, chunk:%uD, chunks:%uD, samples:%uD",
start_sample, chunk, next_chunk - chunk, samples);
n = (next_chunk - chunk) * samples;
n = (uint64_t) (next_chunk - chunk) * samples;
if (start_sample > n) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
@ -3203,6 +3221,12 @@ found:
return NGX_ERROR;
}
if (chunk == 0) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"zero chunk in \"%s\"", mp4->file.name.data);
return NGX_ERROR;
}
target_chunk = chunk - 1;
target_chunk += start_sample / samples;
chunk_samples = start_sample % samples;

View File

@ -138,6 +138,8 @@ typedef struct {
ngx_chain_t *free;
ngx_chain_t *busy;
ngx_buf_t *trailers;
unsigned head:1;
unsigned internal_chunked:1;
unsigned header_sent:1;
@ -163,6 +165,8 @@ static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
ssize_t bytes);
static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
ssize_t bytes);
static ngx_int_t ngx_http_proxy_process_trailer(ngx_http_request_t *r,
ngx_buf_t *buf);
static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
@ -222,6 +226,8 @@ static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif
#if (NGX_HTTP_SSL)
static char *ngx_http_proxy_ssl_certificate_cache(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
#endif
@ -457,6 +463,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
NULL },
{ ngx_string("proxy_pass_trailers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_trailers),
NULL },
{ ngx_string("proxy_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
@ -494,7 +507,7 @@ static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_limit_rate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
ngx_http_set_complex_value_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate),
NULL },
@ -764,6 +777,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key),
NULL },
{ ngx_string("proxy_ssl_certificate_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
ngx_http_proxy_ssl_certificate_cache,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("proxy_ssl_password_file"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_proxy_ssl_password_file,
@ -2186,6 +2206,7 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
ngx_chain_t *cl;
ngx_http_request_t *r;
ngx_http_proxy_ctx_t *ctx;
ngx_http_proxy_loc_conf_t *plcf;
if (buf->pos == buf->last) {
return NGX_OK;
@ -2216,11 +2237,39 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
}
b = NULL;
if (ctx->trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_OK) {
/* a whole response has been parsed successfully */
p->length = 0;
r->upstream->keepalive = !r->upstream->headers_in.connection_close;
if (buf->pos != buf->last) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent data after trailers");
r->upstream->keepalive = 0;
}
}
goto free_buf;
}
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
prev = &buf->shadow;
for ( ;; ) {
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked,
plcf->upstream.pass_trailers);
if (rc == NGX_OK) {
@ -2275,6 +2324,19 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
if (rc == NGX_DONE) {
if (plcf->upstream.pass_trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_AGAIN) {
p->length = 1;
break;
}
}
/* a whole response has been parsed successfully */
p->length = 0;
@ -2306,6 +2368,8 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_ERROR;
}
free_buf:
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http proxy chunked state %ui, length %O",
ctx->chunked.state, p->length);
@ -2406,6 +2470,9 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
ngx_chain_t *cl, **ll;
ngx_http_upstream_t *u;
ngx_http_proxy_ctx_t *ctx;
ngx_http_proxy_loc_conf_t *plcf;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
@ -2419,13 +2486,38 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
buf->pos = buf->last;
buf->last += bytes;
if (ctx->trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_OK) {
/* a whole response has been parsed successfully */
r->upstream->keepalive = !u->headers_in.connection_close;
u->length = 0;
if (buf->pos != buf->last) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent data after trailers");
u->keepalive = 0;
}
}
return NGX_OK;
}
for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
ll = &cl->next;
}
for ( ;; ) {
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked,
plcf->upstream.pass_trailers);
if (rc == NGX_OK) {
@ -2467,6 +2559,19 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
if (rc == NGX_DONE) {
if (plcf->upstream.pass_trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_AGAIN) {
u->length = 1;
break;
}
}
/* a whole response has been parsed successfully */
u->keepalive = !u->headers_in.connection_close;
@ -2497,6 +2602,115 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
}
static ngx_int_t
ngx_http_proxy_process_trailer(ngx_http_request_t *r, ngx_buf_t *buf)
{
size_t len;
ngx_int_t rc;
ngx_buf_t *b;
ngx_table_elt_t *h;
ngx_http_proxy_ctx_t *ctx;
ngx_http_proxy_loc_conf_t *plcf;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
if (ctx->trailers == NULL) {
ctx->trailers = ngx_create_temp_buf(r->pool,
plcf->upstream.buffer_size);
if (ctx->trailers == NULL) {
return NGX_ERROR;
}
}
b = ctx->trailers;
len = ngx_min(buf->last - buf->pos, b->end - b->last);
b->last = ngx_cpymem(b->last, buf->pos, len);
for ( ;; ) {
rc = ngx_http_parse_header_line(r, b, 1);
if (rc == NGX_OK) {
/* a header line has been parsed successfully */
h = ngx_list_push(&r->upstream->headers_in.trailers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = r->header_hash;
h->key.len = r->header_name_end - r->header_name_start;
h->value.len = r->header_end - r->header_start;
h->key.data = ngx_pnalloc(r->pool,
h->key.len + 1 + h->value.len + 1 + h->key.len);
if (h->key.data == NULL) {
h->hash = 0;
return NGX_ERROR;
}
h->value.data = h->key.data + h->key.len + 1;
h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
h->key.data[h->key.len] = '\0';
ngx_memcpy(h->value.data, r->header_start, h->value.len);
h->value.data[h->value.len] = '\0';
if (h->key.len == r->lowcase_index) {
ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
} else {
ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy trailer: \"%V: %V\"",
&h->key, &h->value);
continue;
}
if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
/* a whole header has been parsed successfully */
buf->pos += len - (b->last - b->pos);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy trailer done");
return NGX_OK;
}
if (rc == NGX_AGAIN) {
buf->pos += len;
if (b->last == b->end) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too big trailers");
return NGX_ERROR;
}
return NGX_AGAIN;
}
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid trailer: \"%*s\\x%02xd...\"",
r->header_end - r->header_name_start,
r->header_name_start, *r->header_end);
return NGX_ERROR;
}
}
static void
ngx_http_proxy_abort_request(ngx_http_request_t *r)
{
@ -3371,7 +3585,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
@ -3379,6 +3593,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
conf->upstream.pass_trailers = NGX_CONF_UNSET;
#if (NGX_HTTP_CACHE)
conf->upstream.cache = NGX_CONF_UNSET;
@ -3407,6 +3622,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.ssl_verify = NGX_CONF_UNSET;
conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR;
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
@ -3515,8 +3731,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_size_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, 0);
ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, NULL);
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
@ -3721,6 +3937,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.pass_request_body,
prev->upstream.pass_request_body, 1);
ngx_conf_merge_value(conf->upstream.pass_trailers,
prev->upstream.pass_trailers, 0);
ngx_conf_merge_value(conf->upstream.intercept_errors,
prev->upstream.intercept_errors, 0);
@ -3734,9 +3953,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.ssl_session_reuse, 1);
ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
(NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));
ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
"DEFAULT");
@ -3757,8 +3974,15 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.ssl_certificate, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
prev->upstream.ssl_certificate_key, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords,
prev->upstream.ssl_passwords, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache,
prev->upstream.ssl_certificate_cache, NULL);
if (ngx_http_upstream_merge_ssl_passwords(cf, &conf->upstream,
&prev->upstream)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
prev->ssl_conf_commands, NULL);
@ -4736,6 +4960,11 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
if (value[1].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
return NGX_CONF_ERROR;
}
#if (NGX_HTTP_CACHE)
if (plcf->upstream.cache > 0) {
return "is incompatible with \"proxy_cache\"";
@ -4862,6 +5091,100 @@ ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_HTTP_SSL)
static char *
ngx_http_proxy_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_proxy_loc_conf_t *plcf = conf;
time_t inactive, valid;
ngx_str_t *value, s;
ngx_int_t max;
ngx_uint_t i;
if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
max = 0;
inactive = 10;
valid = 60;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
max = ngx_atoi(value[i].data + 4, value[i].len - 4);
if (max <= 0) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
s.len = value[i].len - 6;
s.data = value[i].data + 6;
valid = ngx_parse_time(&s, 1);
if (valid == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strcmp(value[i].data, "off") == 0) {
plcf->upstream.ssl_certificate_cache = NULL;
continue;
}
failed:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (plcf->upstream.ssl_certificate_cache == NULL) {
return NGX_CONF_OK;
}
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"proxy_ssl_certificate_cache\" must have "
"the \"max\" parameter");
return NGX_CONF_ERROR;
}
plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max,
valid, inactive);
if (plcf->upstream.ssl_certificate_cache == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@ -5019,16 +5342,9 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
return NGX_ERROR;
}
if (plcf->upstream.ssl_certificate->lengths
|| plcf->upstream.ssl_certificate_key->lengths)
if (plcf->upstream.ssl_certificate->lengths == NULL
&& plcf->upstream.ssl_certificate_key->lengths == NULL)
{
plcf->upstream.ssl_passwords =
ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords);
if (plcf->upstream.ssl_passwords == NULL) {
return NGX_ERROR;
}
} else {
if (ngx_ssl_certificate(cf, plcf->upstream.ssl,
&plcf->upstream.ssl_certificate->value,
&plcf->upstream.ssl_certificate_key->value,

View File

@ -223,7 +223,7 @@ static ngx_command_t ngx_http_scgi_commands[] = {
{ ngx_string("scgi_limit_rate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
ngx_http_set_complex_value_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate),
NULL },
@ -1283,6 +1283,21 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->upstream.bufs.num = 0;
* conf->upstream.ignore_headers = 0;
* conf->upstream.next_upstream = 0;
* conf->upstream.cache_zone = NULL;
* conf->upstream.cache_use_stale = 0;
* conf->upstream.cache_methods = 0;
* conf->upstream.temp_path = NULL;
* conf->upstream.hide_headers_hash = { NULL, 0 };
* conf->upstream.store_lengths = NULL;
* conf->upstream.store_values = NULL;
*/
conf->upstream.store = NGX_CONF_UNSET;
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
@ -1301,7 +1316,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
@ -1413,8 +1428,8 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_size_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, 0);
ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, NULL);
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
@ -1980,6 +1995,11 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
if (value[1].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
return NGX_CONF_ERROR;
}
#if (NGX_HTTP_CACHE)
if (scf->upstream.cache > 0) {
return "is incompatible with \"scgi_cache\"";

View File

@ -165,8 +165,8 @@ ngx_http_slice_header_filter(ngx_http_request_t *r)
if (cr.start != ctx->start || cr.end != end) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"unexpected range in slice response: %O-%O",
cr.start, cr.end);
"unexpected range in slice response: %O-%O, "
"expected: %O-%O", cr.start, cr.end, ctx->start, end);
return NGX_ERROR;
}
@ -419,13 +419,13 @@ ngx_http_slice_range_variable(ngx_http_request_t *r,
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module);
p = ngx_pnalloc(r->pool, sizeof("bytes=-") - 1 + 2 * NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module);
ctx->start = slcf->size * (ngx_http_slice_get_start(r) / slcf->size);
ctx->range.data = p;

View File

@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
while (ctx->in || ctx->buf) {
if (ctx->buf == NULL) {
ctx->buf = ctx->in->buf;
ctx->in = ctx->in->next;
cl = ctx->in;
ctx->buf = cl->buf;
ctx->in = cl->next;
ctx->pos = ctx->buf->pos;
ngx_free_chain(r->pool, cl);
}
if (ctx->state == ssi_start_state) {

View File

@ -43,6 +43,8 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
ngx_http_ssl_srv_conf_t *conf);
static char *ngx_http_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
@ -108,6 +110,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
offsetof(ngx_http_ssl_srv_conf_t, certificate_keys),
NULL },
{ ngx_string("ssl_certificate_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE123,
ngx_http_ssl_certificate_cache,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("ssl_password_file"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_ssl_password_file,
@ -619,6 +628,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
sscf->verify_depth = NGX_CONF_UNSET_UINT;
sscf->certificates = NGX_CONF_UNSET_PTR;
sscf->certificate_keys = NGX_CONF_UNSET_PTR;
sscf->certificate_cache = NGX_CONF_UNSET_PTR;
sscf->passwords = NGX_CONF_UNSET_PTR;
sscf->conf_commands = NGX_CONF_UNSET_PTR;
sscf->builtin_session_cache = NGX_CONF_UNSET;
@ -652,9 +662,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0);
ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
(NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));
ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
NGX_SSL_BUFSIZE);
@ -666,6 +674,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
NULL);
ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache,
NULL);
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
@ -787,9 +798,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->verify) {
if (conf->client_certificate.len == 0 && conf->verify != 3) {
if (conf->verify != 3
&& conf->client_certificate.len == 0
&& conf->trusted_certificate.len == 0)
{
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no ssl_client_certificate for ssl_verify_client");
"no ssl_client_certificate or "
"ssl_trusted_certificate for ssl_verify_client");
return NGX_CONF_ERROR;
}
@ -982,6 +997,99 @@ found:
}
static char *
ngx_http_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_ssl_srv_conf_t *sscf = conf;
time_t inactive, valid;
ngx_str_t *value, s;
ngx_int_t max;
ngx_uint_t i;
if (sscf->certificate_cache != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
max = 0;
inactive = 10;
valid = 60;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
max = ngx_atoi(value[i].data + 4, value[i].len - 4);
if (max <= 0) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
s.len = value[i].len - 6;
s.data = value[i].data + 6;
valid = ngx_parse_time(&s, 1);
if (valid == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strcmp(value[i].data, "off") == 0) {
sscf->certificate_cache = NULL;
continue;
}
failed:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (sscf->certificate_cache == NULL) {
return NGX_CONF_OK;
}
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"ssl_certificate_cache\" must have "
"the \"max\" parameter");
return NGX_CONF_ERROR;
}
sscf->certificate_cache = ngx_ssl_cache_init(cf->pool, max, valid,
inactive);
if (sscf->certificate_cache == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{

View File

@ -38,6 +38,8 @@ typedef struct {
ngx_array_t *certificate_values;
ngx_array_t *certificate_key_values;
ngx_ssl_cache_t *certificate_cache;
ngx_str_t dhparam;
ngx_str_t ecdh_curve;
ngx_str_t client_certificate;

View File

@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
while (ctx->in || ctx->buf) {
if (ctx->buf == NULL) {
ctx->buf = ctx->in->buf;
ctx->in = ctx->in->next;
cl = ctx->in;
ctx->buf = cl->buf;
ctx->in = cl->next;
ctx->pos = ctx->buf->pos;
ngx_free_chain(r->pool, cl);
}
if (ctx->buf->flush || ctx->buf->recycled) {

View File

@ -24,6 +24,9 @@ typedef struct {
typedef struct {
ngx_http_complex_value_t key;
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_uint_t config;
#endif
ngx_http_upstream_chash_points_t *points;
} ngx_http_upstream_hash_srv_conf_t;
@ -49,6 +52,8 @@ static ngx_int_t ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc,
static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us);
static ngx_int_t ngx_http_upstream_update_chash(ngx_pool_t *pool,
ngx_http_upstream_srv_conf_t *us);
static int ngx_libc_cdecl
ngx_http_upstream_chash_cmp_points(const void *one, const void *two);
static ngx_uint_t ngx_http_upstream_find_chash_point(
@ -178,11 +183,18 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_rlock(hp->rrp.peers);
if (hp->tries > 20 || hp->rrp.peers->single || hp->key.len == 0) {
if (hp->tries > 20 || hp->rrp.peers->number < 2 || hp->key.len == 0) {
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return hp->get_rr_peer(pc, &hp->rrp);
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (hp->rrp.peers->config && hp->rrp.config != *hp->rrp.peers->config) {
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return hp->get_rr_peer(pc, &hp->rrp);
}
#endif
now = ngx_time();
pc->cached = 0;
@ -262,6 +274,7 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
}
hp->rrp.current = peer;
ngx_http_upstream_rr_peer_ref(hp->rrp.peers, peer);
pc->sockaddr = peer->sockaddr;
pc->socklen = peer->socklen;
@ -284,6 +297,26 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
static ngx_int_t
ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
{
if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
return NGX_ERROR;
}
us->peer.init = ngx_http_upstream_init_chash_peer;
#if (NGX_HTTP_UPSTREAM_ZONE)
if (us->shm_zone) {
return NGX_OK;
}
#endif
return ngx_http_upstream_update_chash(cf->pool, us);
}
static ngx_int_t
ngx_http_upstream_update_chash(ngx_pool_t *pool,
ngx_http_upstream_srv_conf_t *us)
{
u_char *host, *port, c;
size_t host_len, port_len, size;
@ -299,25 +332,32 @@ ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
u_char byte[4];
} prev_hash;
if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
return NGX_ERROR;
}
hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module);
us->peer.init = ngx_http_upstream_init_chash_peer;
if (hcf->points) {
ngx_free(hcf->points);
hcf->points = NULL;
}
peers = us->peer.data;
npoints = peers->total_weight * 160;
size = sizeof(ngx_http_upstream_chash_points_t)
+ sizeof(ngx_http_upstream_chash_point_t) * (npoints - 1);
- sizeof(ngx_http_upstream_chash_point_t)
+ sizeof(ngx_http_upstream_chash_point_t) * npoints;
points = ngx_palloc(cf->pool, size);
points = pool ? ngx_palloc(pool, size) : ngx_alloc(size, ngx_cycle->log);
if (points == NULL) {
return NGX_ERROR;
}
points->number = 0;
if (npoints == 0) {
hcf->points = points;
return NGX_OK;
}
for (peer = peers->peer; peer; peer = peer->next) {
server = &peer->server;
@ -401,7 +441,6 @@ ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
points->number = i + 1;
hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module);
hcf->points = points;
return NGX_OK;
@ -481,7 +520,22 @@ ngx_http_upstream_init_chash_peer(ngx_http_request_t *r,
ngx_http_upstream_rr_peers_rlock(hp->rrp.peers);
#if (NGX_HTTP_UPSTREAM_ZONE)
if (hp->rrp.peers->config
&& (hcf->points == NULL || hcf->config != *hp->rrp.peers->config))
{
if (ngx_http_upstream_update_chash(NULL, us) != NGX_OK) {
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return NGX_ERROR;
}
hcf->config = *hp->rrp.peers->config;
}
#endif
if (hcf->points->number) {
hp->hash = ngx_http_upstream_find_chash_point(hcf->points, hash);
}
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
@ -517,6 +571,20 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
pc->cached = 0;
pc->connection = NULL;
if (hp->rrp.peers->number == 0) {
pc->name = hp->rrp.peers->name;
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return NGX_BUSY;
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (hp->rrp.peers->config && hp->rrp.config != *hp->rrp.peers->config) {
pc->name = hp->rrp.peers->name;
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return NGX_BUSY;
}
#endif
now = ngx_time();
hcf = hp->conf;
@ -597,6 +665,7 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
found:
hp->rrp.current = best;
ngx_http_upstream_rr_peer_ref(hp->rrp.peers, best);
pc->sockaddr = best->sockaddr;
pc->socklen = best->socklen;
@ -664,6 +733,7 @@ ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
uscf->flags = NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_MODIFY
|NGX_HTTP_UPSTREAM_WEIGHT
|NGX_HTTP_UPSTREAM_MAX_CONNS
|NGX_HTTP_UPSTREAM_MAX_FAILS

View File

@ -163,11 +163,19 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_rlock(iphp->rrp.peers);
if (iphp->tries > 20 || iphp->rrp.peers->single) {
if (iphp->tries > 20 || iphp->rrp.peers->number < 2) {
ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
return iphp->get_rr_peer(pc, &iphp->rrp);
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (iphp->rrp.peers->config && iphp->rrp.config != *iphp->rrp.peers->config)
{
ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
return iphp->get_rr_peer(pc, &iphp->rrp);
}
#endif
now = ngx_time();
pc->cached = 0;
@ -232,6 +240,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
}
iphp->rrp.current = peer;
ngx_http_upstream_rr_peer_ref(iphp->rrp.peers, peer);
pc->sockaddr = peer->sockaddr;
pc->socklen = peer->socklen;
@ -268,6 +277,7 @@ ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
uscf->flags = NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_MODIFY
|NGX_HTTP_UPSTREAM_WEIGHT
|NGX_HTTP_UPSTREAM_MAX_CONNS
|NGX_HTTP_UPSTREAM_MAX_FAILS

View File

@ -124,6 +124,12 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_wlock(peers);
#if (NGX_HTTP_UPSTREAM_ZONE)
if (peers->config && rrp->config != *peers->config) {
goto busy;
}
#endif
best = NULL;
total = 0;
@ -244,6 +250,7 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
best->conns++;
rrp->current = best;
ngx_http_upstream_rr_peer_ref(peers, best);
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
@ -280,6 +287,10 @@ failed:
ngx_http_upstream_rr_peers_wlock(peers);
}
#if (NGX_HTTP_UPSTREAM_ZONE)
busy:
#endif
ngx_http_upstream_rr_peers_unlock(peers);
pc->name = peers->name;
@ -303,6 +314,7 @@ ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
uscf->peer.init_upstream = ngx_http_upstream_init_least_conn;
uscf->flags = NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_MODIFY
|NGX_HTTP_UPSTREAM_WEIGHT
|NGX_HTTP_UPSTREAM_MAX_CONNS
|NGX_HTTP_UPSTREAM_MAX_FAILS

View File

@ -17,6 +17,9 @@ typedef struct {
typedef struct {
ngx_uint_t two;
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_uint_t config;
#endif
ngx_http_upstream_random_range_t *ranges;
} ngx_http_upstream_random_srv_conf_t;
@ -127,6 +130,11 @@ ngx_http_upstream_update_random(ngx_pool_t *pool,
rcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_random_module);
if (rcf->ranges) {
ngx_free(rcf->ranges);
rcf->ranges = NULL;
}
peers = us->peer.data;
size = peers->number * sizeof(ngx_http_upstream_random_range_t);
@ -186,11 +194,15 @@ ngx_http_upstream_init_random_peer(ngx_http_request_t *r,
ngx_http_upstream_rr_peers_rlock(rp->rrp.peers);
#if (NGX_HTTP_UPSTREAM_ZONE)
if (rp->rrp.peers->shpool && rcf->ranges == NULL) {
if (rp->rrp.peers->config
&& (rcf->ranges == NULL || rcf->config != *rp->rrp.peers->config))
{
if (ngx_http_upstream_update_random(NULL, us) != NGX_OK) {
ngx_http_upstream_rr_peers_unlock(rp->rrp.peers);
return NGX_ERROR;
}
rcf->config = *rp->rrp.peers->config;
}
#endif
@ -220,11 +232,18 @@ ngx_http_upstream_get_random_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_rlock(peers);
if (rp->tries > 20 || peers->single) {
if (rp->tries > 20 || peers->number < 2) {
ngx_http_upstream_rr_peers_unlock(peers);
return ngx_http_upstream_get_round_robin_peer(pc, rrp);
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (peers->config && rrp->config != *peers->config) {
ngx_http_upstream_rr_peers_unlock(peers);
return ngx_http_upstream_get_round_robin_peer(pc, rrp);
}
#endif
pc->cached = 0;
pc->connection = NULL;
@ -274,6 +293,7 @@ ngx_http_upstream_get_random_peer(ngx_peer_connection_t *pc, void *data)
}
rrp->current = peer;
ngx_http_upstream_rr_peer_ref(peers, peer);
if (now - peer->checked > peer->fail_timeout) {
peer->checked = now;
@ -314,11 +334,18 @@ ngx_http_upstream_get_random2_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_wlock(peers);
if (rp->tries > 20 || peers->single) {
if (rp->tries > 20 || peers->number < 2) {
ngx_http_upstream_rr_peers_unlock(peers);
return ngx_http_upstream_get_round_robin_peer(pc, rrp);
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (peers->config && rrp->config != *peers->config) {
ngx_http_upstream_rr_peers_unlock(peers);
return ngx_http_upstream_get_round_robin_peer(pc, rrp);
}
#endif
pc->cached = 0;
pc->connection = NULL;
@ -384,6 +411,7 @@ ngx_http_upstream_get_random2_peer(ngx_peer_connection_t *pc, void *data)
}
rrp->current = peer;
ngx_http_upstream_rr_peer_ref(peers, peer);
if (now - peer->checked > peer->fail_timeout) {
peer->checked = now;
@ -467,6 +495,7 @@ ngx_http_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
uscf->peer.init_upstream = ngx_http_upstream_init_random;
uscf->flags = NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_MODIFY
|NGX_HTTP_UPSTREAM_WEIGHT
|NGX_HTTP_UPSTREAM_MAX_CONNS
|NGX_HTTP_UPSTREAM_MAX_FAILS

View File

@ -15,9 +15,22 @@ static char *ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd,
static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone,
void *data);
static ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers(
ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf);
ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf,
ngx_http_upstream_srv_conf_t *ouscf);
static ngx_http_upstream_rr_peer_t *ngx_http_upstream_zone_copy_peer(
ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *src);
static ngx_int_t ngx_http_upstream_zone_preresolve(
ngx_http_upstream_rr_peer_t *resolve,
ngx_http_upstream_rr_peers_t *peers,
ngx_http_upstream_rr_peer_t *oresolve,
ngx_http_upstream_rr_peers_t *opeers);
static void ngx_http_upstream_zone_set_single(
ngx_http_upstream_srv_conf_t *uscf);
static void ngx_http_upstream_zone_remove_peer_locked(
ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *peer);
static ngx_int_t ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle);
static void ngx_http_upstream_zone_resolve_timer(ngx_event_t *event);
static void ngx_http_upstream_zone_resolve_handler(ngx_resolver_ctx_t *ctx);
static ngx_command_t ngx_http_upstream_zone_commands[] = {
@ -55,7 +68,7 @@ ngx_module_t ngx_http_upstream_zone_module = {
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
ngx_http_upstream_zone_init_worker, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
@ -121,11 +134,11 @@ static ngx_int_t
ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data)
{
size_t len;
ngx_uint_t i;
ngx_uint_t i, j;
ngx_slab_pool_t *shpool;
ngx_http_upstream_rr_peers_t *peers, **peersp;
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
ngx_http_upstream_main_conf_t *umcf;
ngx_http_upstream_srv_conf_t *uscf, *ouscf, **uscfp, **ouscfp;
ngx_http_upstream_main_conf_t *umcf, *oumcf;
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
umcf = shm_zone->data;
@ -162,6 +175,7 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data)
/* copy peers to shared memory */
peersp = (ngx_http_upstream_rr_peers_t **) (void *) &shpool->data;
oumcf = data;
for (i = 0; i < umcf->upstreams.nelts; i++) {
uscf = uscfp[i];
@ -170,7 +184,38 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data)
continue;
}
peers = ngx_http_upstream_zone_copy_peers(shpool, uscf);
ouscf = NULL;
if (oumcf) {
ouscfp = oumcf->upstreams.elts;
for (j = 0; j < oumcf->upstreams.nelts; j++) {
if (ouscfp[j]->shm_zone == NULL) {
continue;
}
if (ouscfp[j]->shm_zone->shm.name.len != shm_zone->shm.name.len
|| ngx_memcmp(ouscfp[j]->shm_zone->shm.name.data,
shm_zone->shm.name.data,
shm_zone->shm.name.len)
!= 0)
{
continue;
}
if (ouscfp[j]->host.len == uscf->host.len
&& ngx_memcmp(ouscfp[j]->host.data, uscf->host.data,
uscf->host.len)
== 0)
{
ouscf = ouscfp[j];
break;
}
}
}
peers = ngx_http_upstream_zone_copy_peers(shpool, uscf, ouscf);
if (peers == NULL) {
return NGX_ERROR;
}
@ -185,11 +230,19 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data)
static ngx_http_upstream_rr_peers_t *
ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
ngx_http_upstream_srv_conf_t *uscf)
ngx_http_upstream_srv_conf_t *uscf, ngx_http_upstream_srv_conf_t *ouscf)
{
ngx_str_t *name;
ngx_uint_t *config;
ngx_http_upstream_rr_peer_t *peer, **peerp;
ngx_http_upstream_rr_peers_t *peers, *backup;
ngx_http_upstream_rr_peers_t *peers, *opeers, *backup;
opeers = (ouscf ? ouscf->peer.data : NULL);
config = ngx_slab_calloc(shpool, sizeof(ngx_uint_t));
if (config == NULL) {
return NULL;
}
peers = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t));
if (peers == NULL) {
@ -214,6 +267,7 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
peers->name = name;
peers->shpool = shpool;
peers->config = config;
for (peerp = &peers->peer; *peerp; peerp = &peer->next) {
/* pool is unlocked */
@ -223,6 +277,27 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
}
*peerp = peer;
(*peers->config)++;
}
for (peerp = &peers->resolve; *peerp; peerp = &peer->next) {
peer = ngx_http_upstream_zone_copy_peer(peers, *peerp);
if (peer == NULL) {
return NULL;
}
*peerp = peer;
(*peers->config)++;
}
if (opeers) {
if (ngx_http_upstream_zone_preresolve(peers->resolve, peers,
opeers->resolve, opeers)
!= NGX_OK)
{
return NULL;
}
}
if (peers->next == NULL) {
@ -239,6 +314,7 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
backup->name = name;
backup->shpool = shpool;
backup->config = config;
for (peerp = &backup->peer; *peerp; peerp = &peer->next) {
/* pool is unlocked */
@ -248,14 +324,45 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
}
*peerp = peer;
(*backup->config)++;
}
for (peerp = &backup->resolve; *peerp; peerp = &peer->next) {
peer = ngx_http_upstream_zone_copy_peer(backup, *peerp);
if (peer == NULL) {
return NULL;
}
*peerp = peer;
(*backup->config)++;
}
peers->next = backup;
if (opeers && opeers->next) {
if (ngx_http_upstream_zone_preresolve(peers->resolve, backup,
opeers->resolve, opeers->next)
!= NGX_OK)
{
return NULL;
}
if (ngx_http_upstream_zone_preresolve(backup->resolve, backup,
opeers->next->resolve,
opeers->next)
!= NGX_OK)
{
return NULL;
}
}
done:
uscf->peer.data = peers;
ngx_http_upstream_zone_set_single(uscf);
return peers;
}
@ -279,6 +386,7 @@ ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers,
dst->sockaddr = NULL;
dst->name.data = NULL;
dst->server.data = NULL;
dst->host = NULL;
}
dst->sockaddr = ngx_slab_calloc_locked(pool, sizeof(ngx_sockaddr_t));
@ -301,12 +409,53 @@ ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers,
}
ngx_memcpy(dst->server.data, src->server.data, src->server.len);
if (src->host) {
dst->host = ngx_slab_calloc_locked(pool,
sizeof(ngx_http_upstream_host_t));
if (dst->host == NULL) {
goto failed;
}
dst->host->name.data = ngx_slab_alloc_locked(pool,
src->host->name.len);
if (dst->host->name.data == NULL) {
goto failed;
}
dst->host->peers = peers;
dst->host->peer = dst;
dst->host->name.len = src->host->name.len;
ngx_memcpy(dst->host->name.data, src->host->name.data,
src->host->name.len);
if (src->host->service.len) {
dst->host->service.data = ngx_slab_alloc_locked(pool,
src->host->service.len);
if (dst->host->service.data == NULL) {
goto failed;
}
dst->host->service.len = src->host->service.len;
ngx_memcpy(dst->host->service.data, src->host->service.data,
src->host->service.len);
}
}
}
return dst;
failed:
if (dst->host) {
if (dst->host->name.data) {
ngx_slab_free_locked(pool, dst->host->name.data);
}
ngx_slab_free_locked(pool, dst->host);
}
if (dst->server.data) {
ngx_slab_free_locked(pool, dst->server.data);
}
@ -323,3 +472,536 @@ failed:
return NULL;
}
static ngx_int_t
ngx_http_upstream_zone_preresolve(ngx_http_upstream_rr_peer_t *resolve,
ngx_http_upstream_rr_peers_t *peers,
ngx_http_upstream_rr_peer_t *oresolve,
ngx_http_upstream_rr_peers_t *opeers)
{
in_port_t port;
ngx_str_t *server;
ngx_http_upstream_host_t *host;
ngx_http_upstream_rr_peer_t *peer, *template, *opeer, **peerp;
if (resolve == NULL || oresolve == NULL) {
return NGX_OK;
}
for (peerp = &peers->peer; *peerp; peerp = &(*peerp)->next) {
/* void */
}
ngx_http_upstream_rr_peers_rlock(opeers);
for (template = resolve; template; template = template->next) {
for (opeer = oresolve; opeer; opeer = opeer->next) {
if (opeer->host->name.len != template->host->name.len
|| ngx_memcmp(opeer->host->name.data,
template->host->name.data,
template->host->name.len)
!= 0)
{
continue;
}
if (opeer->host->service.len != template->host->service.len
|| ngx_memcmp(opeer->host->service.data,
template->host->service.data,
template->host->service.len)
!= 0)
{
continue;
}
host = opeer->host;
for (opeer = opeers->peer; opeer; opeer = opeer->next) {
if (opeer->host != host) {
continue;
}
peer = ngx_http_upstream_zone_copy_peer(peers, NULL);
if (peer == NULL) {
ngx_http_upstream_rr_peers_unlock(opeers);
return NGX_ERROR;
}
ngx_memcpy(peer->sockaddr, opeer->sockaddr, opeer->socklen);
if (template->host->service.len == 0) {
port = ngx_inet_get_port(template->sockaddr);
ngx_inet_set_port(peer->sockaddr, port);
}
peer->socklen = opeer->socklen;
peer->name.len = ngx_sock_ntop(peer->sockaddr, peer->socklen,
peer->name.data,
NGX_SOCKADDR_STRLEN, 1);
peer->host = template->host;
template->host->valid = host->valid;
server = template->host->service.len ? &opeer->server
: &template->server;
peer->server.data = ngx_slab_alloc(peers->shpool, server->len);
if (peer->server.data == NULL) {
ngx_http_upstream_rr_peers_unlock(opeers);
return NGX_ERROR;
}
ngx_memcpy(peer->server.data, server->data, server->len);
peer->server.len = server->len;
if (host->service.len == 0) {
peer->weight = template->weight;
} else {
peer->weight = (template->weight != 1 ? template->weight
: opeer->weight);
}
peer->effective_weight = peer->weight;
peer->max_conns = template->max_conns;
peer->max_fails = template->max_fails;
peer->fail_timeout = template->fail_timeout;
peer->down = template->down;
(*peers->config)++;
*peerp = peer;
peerp = &peer->next;
peers->number++;
peers->tries += (peer->down == 0);
peers->total_weight += peer->weight;
peers->weighted = (peers->total_weight != peers->number);
}
break;
}
}
ngx_http_upstream_rr_peers_unlock(opeers);
return NGX_OK;
}
static void
ngx_http_upstream_zone_set_single(ngx_http_upstream_srv_conf_t *uscf)
{
ngx_http_upstream_rr_peers_t *peers;
peers = uscf->peer.data;
if (peers->number == 1
&& (peers->next == NULL || peers->next->number == 0))
{
peers->single = 1;
} else {
peers->single = 0;
}
}
static void
ngx_http_upstream_zone_remove_peer_locked(ngx_http_upstream_rr_peers_t *peers,
ngx_http_upstream_rr_peer_t *peer)
{
peers->total_weight -= peer->weight;
peers->number--;
peers->tries -= (peer->down == 0);
(*peers->config)++;
peers->weighted = (peers->total_weight != peers->number);
ngx_http_upstream_rr_peer_free(peers, peer);
}
static ngx_int_t
ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
{
time_t now;
ngx_msec_t timer;
ngx_uint_t i;
ngx_event_t *event;
ngx_http_upstream_rr_peer_t *peer;
ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
ngx_http_upstream_main_conf_t *umcf;
if (ngx_process != NGX_PROCESS_WORKER
&& ngx_process != NGX_PROCESS_SINGLE)
{
return NGX_OK;
}
now = ngx_time();
umcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_module);
if (umcf == NULL) {
return NGX_OK;
}
uscfp = umcf->upstreams.elts;
for (i = 0; i < umcf->upstreams.nelts; i++) {
uscf = uscfp[i];
if (uscf->shm_zone == NULL) {
continue;
}
peers = uscf->peer.data;
do {
ngx_http_upstream_rr_peers_wlock(peers);
for (peer = peers->resolve; peer; peer = peer->next) {
if (peer->host->worker != ngx_worker) {
continue;
}
event = &peer->host->event;
ngx_memzero(event, sizeof(ngx_event_t));
event->data = uscf;
event->handler = ngx_http_upstream_zone_resolve_timer;
event->log = cycle->log;
event->cancelable = 1;
timer = (peer->host->valid > now)
? (ngx_msec_t) 1000 * (peer->host->valid - now) : 1;
ngx_add_timer(event, timer);
}
ngx_http_upstream_rr_peers_unlock(peers);
peers = peers->next;
} while (peers);
}
return NGX_OK;
}
static void
ngx_http_upstream_zone_resolve_timer(ngx_event_t *event)
{
ngx_resolver_ctx_t *ctx;
ngx_http_upstream_host_t *host;
ngx_http_upstream_srv_conf_t *uscf;
host = (ngx_http_upstream_host_t *) event;
uscf = event->data;
ctx = ngx_resolve_start(uscf->resolver, NULL);
if (ctx == NULL) {
goto retry;
}
if (ctx == NGX_NO_RESOLVER) {
ngx_log_error(NGX_LOG_ERR, event->log, 0,
"no resolver defined to resolve %V", &host->name);
return;
}
ctx->name = host->name;
ctx->handler = ngx_http_upstream_zone_resolve_handler;
ctx->data = host;
ctx->timeout = uscf->resolver_timeout;
ctx->service = host->service;
ctx->cancelable = 1;
if (ngx_resolve_name(ctx) == NGX_OK) {
return;
}
retry:
ngx_add_timer(event, ngx_max(uscf->resolver_timeout, 1000));
}
#define ngx_http_upstream_zone_addr_marked(addr) \
((uintptr_t) (addr)->sockaddr & 1)
#define ngx_http_upstream_zone_mark_addr(addr) \
(addr)->sockaddr = (struct sockaddr *) ((uintptr_t) (addr)->sockaddr | 1)
#define ngx_http_upstream_zone_unmark_addr(addr) \
(addr)->sockaddr = \
(struct sockaddr *) ((uintptr_t) (addr)->sockaddr & ~((uintptr_t) 1))
static void
ngx_http_upstream_zone_resolve_handler(ngx_resolver_ctx_t *ctx)
{
time_t now;
u_short min_priority;
in_port_t port;
ngx_str_t *server;
ngx_msec_t timer;
ngx_uint_t i, j, backup, addr_backup;
ngx_event_t *event;
ngx_resolver_addr_t *addr;
ngx_resolver_srv_name_t *srv;
ngx_http_upstream_host_t *host;
ngx_http_upstream_rr_peer_t *peer, *template, **peerp;
ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_srv_conf_t *uscf;
host = ctx->data;
event = &host->event;
uscf = event->data;
peers = host->peers;
template = host->peer;
ngx_http_upstream_rr_peers_wlock(peers);
now = ngx_time();
for (i = 0; i < ctx->nsrvs; i++) {
srv = &ctx->srvs[i];
if (srv->state) {
ngx_log_error(NGX_LOG_ERR, event->log, 0,
"%V could not be resolved (%i: %s) "
"while resolving service %V of %V",
&srv->name, srv->state,
ngx_resolver_strerror(srv->state), &ctx->service,
&ctx->name);
}
}
if (ctx->state) {
if (ctx->service.len) {
ngx_log_error(NGX_LOG_ERR, event->log, 0,
"service %V of %V could not be resolved (%i: %s)",
&ctx->service, &ctx->name, ctx->state,
ngx_resolver_strerror(ctx->state));
} else {
ngx_log_error(NGX_LOG_ERR, event->log, 0,
"%V could not be resolved (%i: %s)",
&ctx->name, ctx->state,
ngx_resolver_strerror(ctx->state));
}
if (ctx->state != NGX_RESOLVE_NXDOMAIN) {
ngx_http_upstream_rr_peers_unlock(peers);
ngx_resolve_name_done(ctx);
ngx_add_timer(event, ngx_max(uscf->resolver_timeout, 1000));
return;
}
/* NGX_RESOLVE_NXDOMAIN */
ctx->naddrs = 0;
}
backup = 0;
min_priority = 65535;
for (i = 0; i < ctx->naddrs; i++) {
min_priority = ngx_min(ctx->addrs[i].priority, min_priority);
}
#if (NGX_DEBUG)
{
u_char text[NGX_SOCKADDR_STRLEN];
size_t len;
for (i = 0; i < ctx->naddrs; i++) {
len = ngx_sock_ntop(ctx->addrs[i].sockaddr, ctx->addrs[i].socklen,
text, NGX_SOCKADDR_STRLEN, 1);
ngx_log_debug7(NGX_LOG_DEBUG_HTTP, event->log, 0,
"name %V was resolved to %*s "
"s:\"%V\" n:\"%V\" w:%d %s",
&host->name, len, text, &host->service,
&ctx->addrs[i].name, ctx->addrs[i].weight,
ctx->addrs[i].priority != min_priority ? "backup" : "");
}
}
#endif
again:
for (peerp = &peers->peer; *peerp; /* void */ ) {
peer = *peerp;
if (peer->host != host) {
goto next;
}
for (j = 0; j < ctx->naddrs; j++) {
addr = &ctx->addrs[j];
addr_backup = (addr->priority != min_priority);
if (addr_backup != backup) {
continue;
}
if (ngx_http_upstream_zone_addr_marked(addr)) {
continue;
}
if (ngx_cmp_sockaddr(peer->sockaddr, peer->socklen,
addr->sockaddr, addr->socklen,
host->service.len != 0)
!= NGX_OK)
{
continue;
}
if (host->service.len) {
if (addr->name.len != peer->server.len
|| ngx_strncmp(addr->name.data, peer->server.data,
addr->name.len))
{
continue;
}
if (template->weight == 1 && addr->weight != peer->weight) {
continue;
}
}
ngx_http_upstream_zone_mark_addr(addr);
goto next;
}
*peerp = peer->next;
ngx_http_upstream_zone_remove_peer_locked(peers, peer);
ngx_http_upstream_zone_set_single(uscf);
continue;
next:
peerp = &peer->next;
}
for (i = 0; i < ctx->naddrs; i++) {
addr = &ctx->addrs[i];
addr_backup = (addr->priority != min_priority);
if (addr_backup != backup) {
continue;
}
if (ngx_http_upstream_zone_addr_marked(addr)) {
ngx_http_upstream_zone_unmark_addr(addr);
continue;
}
ngx_shmtx_lock(&peers->shpool->mutex);
peer = ngx_http_upstream_zone_copy_peer(peers, NULL);
ngx_shmtx_unlock(&peers->shpool->mutex);
if (peer == NULL) {
ngx_log_error(NGX_LOG_ERR, event->log, 0,
"cannot add new server to upstream \"%V\", "
"memory exhausted", peers->name);
goto done;
}
ngx_memcpy(peer->sockaddr, addr->sockaddr, addr->socklen);
if (host->service.len == 0) {
port = ngx_inet_get_port(template->sockaddr);
ngx_inet_set_port(peer->sockaddr, port);
}
peer->socklen = addr->socklen;
peer->name.len = ngx_sock_ntop(peer->sockaddr, peer->socklen,
peer->name.data, NGX_SOCKADDR_STRLEN, 1);
peer->host = template->host;
server = host->service.len ? &addr->name : &template->server;
peer->server.data = ngx_slab_alloc(peers->shpool, server->len);
if (peer->server.data == NULL) {
ngx_http_upstream_rr_peer_free(peers, peer);
ngx_log_error(NGX_LOG_ERR, event->log, 0,
"cannot add new server to upstream \"%V\", "
"memory exhausted", peers->name);
goto done;
}
peer->server.len = server->len;
ngx_memcpy(peer->server.data, server->data, server->len);
if (host->service.len == 0) {
peer->weight = template->weight;
} else {
peer->weight = (template->weight != 1 ? template->weight
: addr->weight);
}
peer->effective_weight = peer->weight;
peer->max_conns = template->max_conns;
peer->max_fails = template->max_fails;
peer->fail_timeout = template->fail_timeout;
peer->down = template->down;
*peerp = peer;
peerp = &peer->next;
peers->number++;
peers->tries += (peer->down == 0);
peers->total_weight += peer->weight;
peers->weighted = (peers->total_weight != peers->number);
(*peers->config)++;
ngx_http_upstream_zone_set_single(uscf);
}
if (host->service.len && peers->next) {
ngx_http_upstream_rr_peers_unlock(peers);
peers = peers->next;
backup = 1;
ngx_http_upstream_rr_peers_wlock(peers);
goto again;
}
done:
host->valid = ctx->valid;
ngx_http_upstream_rr_peers_unlock(peers);
while (++i < ctx->naddrs) {
ngx_http_upstream_zone_unmark_addr(&ctx->addrs[i]);
}
timer = (ngx_msec_t) 1000 * (ctx->valid > now ? ctx->valid - now + 1 : 1);
ngx_resolve_name_done(ctx);
ngx_add_timer(event, timer);
}

View File

@ -92,6 +92,8 @@ static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
#endif
#if (NGX_HTTP_SSL)
static char *ngx_http_uwsgi_ssl_certificate_cache(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post,
@ -289,7 +291,7 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
{ ngx_string("uwsgi_limit_rate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
ngx_http_set_complex_value_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.limit_rate),
NULL },
@ -559,6 +561,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate_key),
NULL },
{ ngx_string("uwsgi_ssl_certificate_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
ngx_http_uwsgi_ssl_certificate_cache,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("uwsgi_ssl_password_file"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_uwsgi_ssl_password_file,
@ -1511,6 +1520,28 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->upstream.bufs.num = 0;
* conf->upstream.ignore_headers = 0;
* conf->upstream.next_upstream = 0;
* conf->upstream.cache_zone = NULL;
* conf->upstream.cache_use_stale = 0;
* conf->upstream.cache_methods = 0;
* conf->upstream.temp_path = NULL;
* conf->upstream.hide_headers_hash = { NULL, 0 };
* conf->upstream.store_lengths = NULL;
* conf->upstream.store_values = NULL;
*
* conf->uwsgi_string = { 0, NULL };
* conf->ssl = 0;
* conf->ssl_protocols = 0;
* conf->ssl_ciphers = { 0, NULL };
* conf->ssl_trusted_certificate = { 0, NULL };
* conf->ssl_crl = { 0, NULL };
*/
conf->modifier1 = NGX_CONF_UNSET_UINT;
conf->modifier2 = NGX_CONF_UNSET_UINT;
@ -1532,7 +1563,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
@ -1568,6 +1599,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR;
conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR;
conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
#endif
@ -1656,8 +1688,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_size_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, 0);
ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
prev->upstream.limit_rate, NULL);
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
@ -1878,9 +1910,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.ssl_session_reuse, 1);
ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
(NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));
ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
"DEFAULT");
@ -1901,8 +1931,15 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.ssl_certificate, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
prev->upstream.ssl_certificate_key, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords,
prev->upstream.ssl_passwords, NULL);
ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache,
prev->upstream.ssl_certificate_cache, NULL);
if (ngx_http_upstream_merge_ssl_passwords(cf, &conf->upstream,
&prev->upstream)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
prev->ssl_conf_commands, NULL);
@ -2302,6 +2339,11 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
if (value[1].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
return NGX_CONF_ERROR;
}
#if (NGX_HTTP_CACHE)
if (uwcf->upstream.cache > 0) {
@ -2430,6 +2472,100 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_HTTP_SSL)
static char *
ngx_http_uwsgi_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_uwsgi_loc_conf_t *plcf = conf;
time_t inactive, valid;
ngx_str_t *value, s;
ngx_int_t max;
ngx_uint_t i;
if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
max = 0;
inactive = 10;
valid = 60;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
max = ngx_atoi(value[i].data + 4, value[i].len - 4);
if (max <= 0) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
s.len = value[i].len - 6;
s.data = value[i].data + 6;
valid = ngx_parse_time(&s, 1);
if (valid == (time_t) NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strcmp(value[i].data, "off") == 0) {
plcf->upstream.ssl_certificate_cache = NULL;
continue;
}
failed:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (plcf->upstream.ssl_certificate_cache == NULL) {
return NGX_CONF_OK;
}
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"uwsgi_ssl_certificate_cache\" must have "
"the \"max\" parameter");
return NGX_CONF_ERROR;
}
plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max,
valid, inactive);
if (plcf->upstream.ssl_certificate_cache == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@ -2554,16 +2690,9 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
return NGX_ERROR;
}
if (uwcf->upstream.ssl_certificate->lengths
|| uwcf->upstream.ssl_certificate_key->lengths)
if (uwcf->upstream.ssl_certificate->lengths == NULL
&& uwcf->upstream.ssl_certificate_key->lengths == NULL)
{
uwcf->upstream.ssl_passwords =
ngx_ssl_preserve_passwords(cf, uwcf->upstream.ssl_passwords);
if (uwcf->upstream.ssl_passwords == NULL) {
return NGX_ERROR;
}
} else {
if (ngx_ssl_certificate(cf, uwcf->upstream.ssl,
&uwcf->upstream.ssl_certificate->value,
&uwcf->upstream.ssl_certificate_key->value,

View File

@ -117,7 +117,7 @@ ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len,
void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,
ngx_str_t *args);
ngx_int_t ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
ngx_http_chunked_t *ctx);
ngx_http_chunked_t *ctx, ngx_uint_t keep_trailers);
ngx_http_request_t *ngx_http_create_request(ngx_connection_t *c);

View File

@ -509,6 +509,13 @@ static ngx_command_t ngx_http_core_commands[] = {
0,
NULL },
{ ngx_string("keepalive_min_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, keepalive_min_timeout),
NULL },
{ ngx_string("keepalive_requests"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
@ -2320,6 +2327,7 @@ ngx_http_subrequest(ngx_http_request_t *r,
ngx_connection_t *c;
ngx_http_request_t *sr;
ngx_http_core_srv_conf_t *cscf;
ngx_http_posted_request_t *posted;
ngx_http_postponed_request_t *pr, *p;
if (r->subrequests == 0) {
@ -2373,6 +2381,11 @@ ngx_http_subrequest(ngx_http_request_t *r,
return NGX_ERROR;
}
posted = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
if (posted == NULL) {
return NGX_ERROR;
}
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
sr->main_conf = cscf->ctx->main_conf;
sr->srv_conf = cscf->ctx->srv_conf;
@ -2431,10 +2444,6 @@ ngx_http_subrequest(ngx_http_request_t *r,
}
if (!sr->background) {
if (c->data == r && r->postponed == NULL) {
c->data = sr;
}
pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
if (pr == NULL) {
return NGX_ERROR;
@ -2444,6 +2453,10 @@ ngx_http_subrequest(ngx_http_request_t *r,
pr->out = NULL;
pr->next = NULL;
if (c->data == r && r->postponed == NULL) {
c->data = sr;
}
if (r->postponed) {
for (p = r->postponed; p->next; p = p->next) { /* void */ }
p->next = pr;
@ -2491,7 +2504,7 @@ ngx_http_subrequest(ngx_http_request_t *r,
ngx_http_update_location_config(sr);
}
return ngx_http_post_request(sr, NULL);
return ngx_http_post_request(sr, posted);
}
@ -3606,6 +3619,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
clcf->keepalive_time = NGX_CONF_UNSET_MSEC;
clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
clcf->keepalive_header = NGX_CONF_UNSET;
clcf->keepalive_min_timeout = NGX_CONF_UNSET_MSEC;
clcf->keepalive_requests = NGX_CONF_UNSET_UINT;
clcf->lingering_close = NGX_CONF_UNSET_UINT;
clcf->lingering_time = NGX_CONF_UNSET_MSEC;
@ -3844,6 +3858,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->keepalive_timeout, 75000);
ngx_conf_merge_sec_value(conf->keepalive_header,
prev->keepalive_header, 0);
ngx_conf_merge_msec_value(conf->keepalive_min_timeout,
prev->keepalive_min_timeout, 0);
ngx_conf_merge_uint_value(conf->keepalive_requests,
prev->keepalive_requests, 1000);
ngx_conf_merge_uint_value(conf->lingering_close,

View File

@ -370,6 +370,7 @@ struct ngx_http_core_loc_conf_s {
ngx_msec_t send_timeout; /* send_timeout */
ngx_msec_t keepalive_time; /* keepalive_time */
ngx_msec_t keepalive_timeout; /* keepalive_timeout */
ngx_msec_t keepalive_min_timeout; /* keepalive_min_timeout */
ngx_msec_t lingering_time; /* lingering_time */
ngx_msec_t lingering_timeout; /* lingering_timeout */
ngx_msec_t resolver_timeout; /* resolver_timeout */

View File

@ -2140,7 +2140,7 @@ ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
ngx_int_t
ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
ngx_http_chunked_t *ctx)
ngx_http_chunked_t *ctx, ngx_uint_t keep_trailers)
{
u_char *pos, ch, c;
ngx_int_t rc;
@ -2218,6 +2218,9 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
state = sw_last_chunk_extension_almost_done;
break;
case LF:
if (keep_trailers) {
goto done;
}
state = sw_trailer;
break;
case ';':
@ -2297,12 +2300,18 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
state = sw_last_chunk_extension_almost_done;
break;
case LF:
if (keep_trailers) {
goto done;
}
state = sw_trailer;
}
break;
case sw_last_chunk_extension_almost_done:
if (ch == LF) {
if (keep_trailers) {
goto done;
}
state = sw_trailer;
break;
}

View File

@ -932,6 +932,31 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
goto done;
}
sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module);
#if (defined TLS1_3_VERSION \
&& !defined LIBRESSL_VERSION_NUMBER && !defined OPENSSL_IS_BORINGSSL)
/*
* SSL_SESSION_get0_hostname() is only available in OpenSSL 1.1.1+,
* but servername being negotiated in every TLSv1.3 handshake
* is only returned in OpenSSL 1.1.1+ as well
*/
if (sscf->verify) {
const char *hostname;
hostname = SSL_SESSION_get0_hostname(SSL_get0_session(ssl_conn));
if (hostname != NULL && ngx_strcmp(hostname, servername) != 0) {
c->ssl->handshake_rejected = 1;
*ad = SSL_AD_ACCESS_DENIED;
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
}
#endif
hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t));
if (hc->ssl_servername == NULL) {
goto error;
@ -945,8 +970,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
ngx_set_connection_log(c, clcf->error_log);
sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
c->ssl->buffer_size = sscf->buffer_size;
if (sscf->ssl.ctx) {
@ -1054,6 +1077,7 @@ ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
"ssl key: \"%s\"", key.data);
if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key,
sscf->certificate_cache,
sscf->passwords)
!= NGX_OK)
{
@ -2798,6 +2822,13 @@ ngx_http_finalize_connection(ngx_http_request_t *r)
r->lingering_close = 1;
}
if (r->keepalive
&& clcf->keepalive_min_timeout > 0)
{
ngx_http_set_keepalive(r);
return;
}
if (!ngx_terminate
&& !ngx_exiting
&& r->keepalive
@ -3300,10 +3331,22 @@ ngx_http_set_keepalive(ngx_http_request_t *r)
r->http_state = NGX_HTTP_KEEPALIVE_STATE;
#endif
if (clcf->keepalive_min_timeout == 0) {
c->idle = 1;
ngx_reusable_connection(c, 1);
}
ngx_add_timer(rev, clcf->keepalive_timeout);
if (clcf->keepalive_min_timeout > 0
&& clcf->keepalive_timeout > clcf->keepalive_min_timeout)
{
hc->keepalive_timeout = clcf->keepalive_timeout
- clcf->keepalive_min_timeout;
} else {
hc->keepalive_timeout = 0;
}
ngx_add_timer(rev, clcf->keepalive_timeout - hc->keepalive_timeout);
if (rev->ready) {
ngx_post_event(rev, &ngx_posted_events);
@ -3318,11 +3361,28 @@ ngx_http_keepalive_handler(ngx_event_t *rev)
ssize_t n;
ngx_buf_t *b;
ngx_connection_t *c;
ngx_http_connection_t *hc;
c = rev->data;
hc = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http keepalive handler");
if (!ngx_terminate
&& !ngx_exiting
&& rev->timedout
&& hc->keepalive_timeout > 0)
{
c->idle = 1;
ngx_reusable_connection(c, 1);
ngx_add_timer(rev, hc->keepalive_timeout);
hc->keepalive_timeout = 0;
rev->timedout = 0;
return;
}
if (rev->timedout || c->close) {
ngx_http_close_connection(c);
return;

View File

@ -329,6 +329,8 @@ typedef struct {
ngx_chain_t *free;
ngx_msec_t keepalive_timeout;
unsigned ssl:1;
unsigned proxy_protocol:1;
} ngx_http_connection_t;

View File

@ -870,7 +870,7 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
for ( ;; ) {
rc = ngx_http_parse_chunked(r, b, rb->chunked);
rc = ngx_http_parse_chunked(r, b, rb->chunked, 0);
if (rc == NGX_OK) {
@ -1131,7 +1131,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
cl->buf->file_pos,
cl->buf->file_last - cl->buf->file_pos);
rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked, 0);
if (rc == NGX_OK) {

View File

@ -169,6 +169,10 @@ static ngx_int_t ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#if (NGX_HTTP_UPSTREAM_ZONE)
static char *ngx_http_upstream_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif
static ngx_int_t ngx_http_upstream_set_local(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_http_upstream_local_t *local);
@ -339,6 +343,24 @@ static ngx_command_t ngx_http_upstream_commands[] = {
0,
NULL },
#if (NGX_HTTP_UPSTREAM_ZONE)
{ ngx_string("resolver"),
NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
ngx_http_upstream_resolver,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("resolver_timeout"),
NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_upstream_srv_conf_t, resolver_timeout),
NULL },
#endif
ngx_null_command
};
@ -1565,6 +1587,26 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->state->peer = u->peer.name;
#if (NGX_HTTP_UPSTREAM_ZONE)
if (u->upstream && u->upstream->shm_zone
&& (u->upstream->flags & NGX_HTTP_UPSTREAM_MODIFY))
{
u->state->peer = ngx_palloc(r->pool,
sizeof(ngx_str_t) + u->peer.name->len);
if (u->state->peer == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
u->state->peer->len = u->peer.name->len;
u->state->peer->data = (u_char *) (u->state->peer + 1);
ngx_memcpy(u->state->peer->data, u->peer.name->data, u->peer.name->len);
u->peer.name = u->state->peer;
}
#endif
if (rc == NGX_BUSY) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
@ -1977,6 +2019,7 @@ ngx_http_upstream_ssl_certificate(ngx_http_request_t *r,
"http upstream ssl key: \"%s\"", key.data);
if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key,
u->conf->ssl_certificate_cache,
u->conf->ssl_passwords)
!= NGX_OK)
{
@ -3236,7 +3279,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->downstream = c;
p->pool = r->pool;
p->log = c->log;
p->limit_rate = u->conf->limit_rate;
p->limit_rate = ngx_http_complex_value_size(r, u->conf->limit_rate, 0);
p->start_sec = ngx_time();
p->cacheable = u->cacheable || u->store;
@ -4315,6 +4358,10 @@ ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
"upstream stores \"%s\" to \"%s\"",
tf->file.name.data, path.data);
if (path.len == 0) {
return;
}
(void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
u->store = 0;
@ -6066,6 +6113,7 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
u.no_port = 1;
uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_MODIFY
|NGX_HTTP_UPSTREAM_WEIGHT
|NGX_HTTP_UPSTREAM_MAX_CONNS
|NGX_HTTP_UPSTREAM_MAX_FAILS
@ -6171,6 +6219,9 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_url_t u;
ngx_int_t weight, max_conns, max_fails;
ngx_uint_t i;
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_uint_t resolve;
#endif
ngx_http_upstream_server_t *us;
us = ngx_array_push(uscf->servers);
@ -6186,6 +6237,9 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
max_conns = 0;
max_fails = 1;
fail_timeout = 10;
#if (NGX_HTTP_UPSTREAM_ZONE)
resolve = 0;
#endif
for (i = 2; i < cf->args->nelts; i++) {
@ -6274,6 +6328,26 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (ngx_strcmp(value[i].data, "resolve") == 0) {
resolve = 1;
continue;
}
if (ngx_strncmp(value[i].data, "service=", 8) == 0) {
us->service.len = value[i].len - 8;
us->service.data = &value[i].data[8];
if (us->service.len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "service is empty");
return NGX_CONF_ERROR;
}
continue;
}
#endif
goto invalid;
}
@ -6282,6 +6356,22 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
u.url = value[1];
u.default_port = 80;
#if (NGX_HTTP_UPSTREAM_ZONE)
if (resolve) {
/* resolve at run time */
u.no_resolve = 1;
}
if (us->service.len && !resolve) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"service upstream \"%V\" requires "
"\"resolve\" parameter",
&u.url);
return NGX_CONF_ERROR;
}
#endif
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@ -6292,8 +6382,61 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
us->name = u.url;
#if (NGX_HTTP_UPSTREAM_ZONE)
if (us->service.len && !u.no_port) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"service upstream \"%V\" may not have port",
&us->name);
return NGX_CONF_ERROR;
}
if (us->service.len && u.naddrs) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"service upstream \"%V\" requires domain name",
&us->name);
return NGX_CONF_ERROR;
}
if (resolve && u.naddrs == 0) {
ngx_addr_t *addr;
/* save port */
addr = ngx_pcalloc(cf->pool, sizeof(ngx_addr_t));
if (addr == NULL) {
return NGX_CONF_ERROR;
}
addr->sockaddr = ngx_palloc(cf->pool, u.socklen);
if (addr->sockaddr == NULL) {
return NGX_CONF_ERROR;
}
ngx_memcpy(addr->sockaddr, &u.sockaddr, u.socklen);
addr->socklen = u.socklen;
us->addrs = addr;
us->naddrs = 1;
us->host = u.host;
} else {
us->addrs = u.addrs;
us->naddrs = u.naddrs;
}
#else
us->addrs = u.addrs;
us->naddrs = u.naddrs;
#endif
us->weight = weight;
us->max_conns = max_conns;
us->max_fails = max_fails;
@ -6318,6 +6461,32 @@ not_supported:
}
#if (NGX_HTTP_UPSTREAM_ZONE)
static char *
ngx_http_upstream_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_upstream_srv_conf_t *uscf = conf;
ngx_str_t *value;
if (uscf->resolver) {
return "is duplicate";
}
value = cf->args->elts;
uscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
if (uscf->resolver == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
#endif
ngx_http_upstream_srv_conf_t *
ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
{
@ -6399,6 +6568,9 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
uscf->line = cf->conf_file->line;
uscf->port = u->port;
uscf->no_port = u->no_port;
#if (NGX_HTTP_UPSTREAM_ZONE)
uscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
#endif
if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) {
uscf->servers = ngx_array_create(cf->pool, 1,
@ -6749,6 +6921,61 @@ ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
}
#if (NGX_HTTP_SSL)
ngx_int_t
ngx_http_upstream_merge_ssl_passwords(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev)
{
ngx_uint_t preserve;
ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
if (conf->ssl_certificate == NULL
|| conf->ssl_certificate->value.len == 0
|| conf->ssl_certificate_key == NULL)
{
return NGX_OK;
}
if (conf->ssl_certificate->lengths == NULL
&& conf->ssl_certificate_key->lengths == NULL)
{
if (conf->ssl_passwords && conf->ssl_passwords->pool == NULL) {
/* un-preserve empty password list */
conf->ssl_passwords = NULL;
}
return NGX_OK;
}
if (conf->ssl_passwords && conf->ssl_passwords->pool != cf->temp_pool) {
/* already preserved */
return NGX_OK;
}
preserve = (conf->ssl_passwords == prev->ssl_passwords) ? 1 : 0;
conf->ssl_passwords = ngx_ssl_preserve_passwords(cf, conf->ssl_passwords);
if (conf->ssl_passwords == NULL) {
return NGX_ERROR;
}
/*
* special handling to keep a preserved ssl_passwords copy
* in the previous configuration to inherit it to all children
*/
if (preserve) {
prev->ssl_passwords = conf->ssl_passwords;
}
return NGX_OK;
}
#endif
static void *
ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
{

View File

@ -104,7 +104,12 @@ typedef struct {
unsigned backup:1;
NGX_COMPAT_BEGIN(6)
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_str_t host;
ngx_str_t service;
#endif
NGX_COMPAT_BEGIN(2)
NGX_COMPAT_END
} ngx_http_upstream_server_t;
@ -115,6 +120,7 @@ typedef struct {
#define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008
#define NGX_HTTP_UPSTREAM_DOWN 0x0010
#define NGX_HTTP_UPSTREAM_BACKUP 0x0020
#define NGX_HTTP_UPSTREAM_MODIFY 0x0040
#define NGX_HTTP_UPSTREAM_MAX_CONNS 0x0100
@ -133,6 +139,8 @@ struct ngx_http_upstream_srv_conf_s {
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_shm_zone_t *shm_zone;
ngx_resolver_t *resolver;
ngx_msec_t resolver_timeout;
#endif
};
@ -156,7 +164,7 @@ typedef struct {
size_t send_lowat;
size_t buffer_size;
size_t limit_rate;
ngx_http_complex_value_t *limit_rate;
size_t busy_buffers_size;
size_t max_temp_file_size;
@ -176,6 +184,7 @@ typedef struct {
ngx_flag_t request_buffering;
ngx_flag_t pass_request_headers;
ngx_flag_t pass_request_body;
ngx_flag_t pass_trailers;
ngx_flag_t ignore_client_abort;
ngx_flag_t intercept_errors;
@ -224,7 +233,6 @@ typedef struct {
signed store:2;
unsigned intercept_404:1;
unsigned change_buffering:1;
unsigned pass_trailers:1;
unsigned preserve_output:1;
#if (NGX_HTTP_SSL || NGX_COMPAT)
@ -237,6 +245,7 @@ typedef struct {
ngx_http_complex_value_t *ssl_certificate;
ngx_http_complex_value_t *ssl_certificate_key;
ngx_ssl_cache_t *ssl_certificate_cache;
ngx_array_t *ssl_passwords;
#endif
@ -428,6 +437,10 @@ char *ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
ngx_str_t *default_hide_headers, ngx_hash_init_t *hash);
#if (NGX_HTTP_SSL)
ngx_int_t ngx_http_upstream_merge_ssl_passwords(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev);
#endif
#define ngx_http_conf_upstream_srv_conf(uscf, module) \

View File

@ -32,10 +32,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us)
{
ngx_url_t u;
ngx_uint_t i, j, n, w, t;
ngx_uint_t i, j, n, r, w, t;
ngx_http_upstream_server_t *server;
ngx_http_upstream_rr_peer_t *peer, **peerp;
ngx_http_upstream_rr_peers_t *peers, *backup;
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_uint_t resolve;
ngx_http_core_loc_conf_t *clcf;
ngx_http_upstream_rr_peer_t **rpeerp;
#endif
us->peer.init = ngx_http_upstream_init_round_robin_peer;
@ -43,14 +48,33 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
server = us->servers->elts;
n = 0;
r = 0;
w = 0;
t = 0;
#if (NGX_HTTP_UPSTREAM_ZONE)
resolve = 0;
#endif
for (i = 0; i < us->servers->nelts; i++) {
#if (NGX_HTTP_UPSTREAM_ZONE)
if (server[i].host.len) {
resolve = 1;
}
#endif
if (server[i].backup) {
continue;
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (server[i].host.len) {
r++;
continue;
}
#endif
n += server[i].naddrs;
w += server[i].naddrs * server[i].weight;
@ -59,7 +83,53 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
}
}
if (n == 0) {
#if (NGX_HTTP_UPSTREAM_ZONE)
if (us->shm_zone) {
if (resolve && !(us->flags & NGX_HTTP_UPSTREAM_MODIFY)) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"load balancing method does not support"
" resolving names at run time in"
" upstream \"%V\" in %s:%ui",
&us->host, us->file_name, us->line);
return NGX_ERROR;
}
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
if (us->resolver == NULL) {
us->resolver = clcf->resolver;
}
/*
* Without "resolver_timeout" in http{} the merged value is unset.
*/
ngx_conf_merge_msec_value(us->resolver_timeout,
clcf->resolver_timeout, 30000);
if (resolve
&& (us->resolver == NULL
|| us->resolver->connections.nelts == 0))
{
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no resolver defined to resolve names"
" at run time in upstream \"%V\" in %s:%ui",
&us->host, us->file_name, us->line);
return NGX_ERROR;
}
} else if (resolve) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"resolving names at run time requires"
" upstream \"%V\" in %s:%ui"
" to be in shared memory",
&us->host, us->file_name, us->line);
return NGX_ERROR;
}
#endif
if (n + r == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no servers in upstream \"%V\" in %s:%ui",
&us->host, us->file_name, us->line);
@ -71,7 +141,8 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
return NGX_ERROR;
}
peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
* (n + r));
if (peer == NULL) {
return NGX_ERROR;
}
@ -86,11 +157,47 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
peerp = &peers->peer;
#if (NGX_HTTP_UPSTREAM_ZONE)
rpeerp = &peers->resolve;
#endif
for (i = 0; i < us->servers->nelts; i++) {
if (server[i].backup) {
continue;
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (server[i].host.len) {
peer[n].host = ngx_pcalloc(cf->pool,
sizeof(ngx_http_upstream_host_t));
if (peer[n].host == NULL) {
return NGX_ERROR;
}
peer[n].host->name = server[i].host;
peer[n].host->service = server[i].service;
peer[n].sockaddr = server[i].addrs[0].sockaddr;
peer[n].socklen = server[i].addrs[0].socklen;
peer[n].name = server[i].addrs[0].name;
peer[n].weight = server[i].weight;
peer[n].effective_weight = server[i].weight;
peer[n].current_weight = 0;
peer[n].max_conns = server[i].max_conns;
peer[n].max_fails = server[i].max_fails;
peer[n].fail_timeout = server[i].fail_timeout;
peer[n].down = server[i].down;
peer[n].server = server[i].name;
*rpeerp = &peer[n];
rpeerp = &peer[n].next;
n++;
continue;
}
#endif
for (j = 0; j < server[i].naddrs; j++) {
peer[n].sockaddr = server[i].addrs[j].sockaddr;
peer[n].socklen = server[i].addrs[j].socklen;
@ -115,6 +222,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
/* backup servers */
n = 0;
r = 0;
w = 0;
t = 0;
@ -123,6 +231,13 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
continue;
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (server[i].host.len) {
r++;
continue;
}
#endif
n += server[i].naddrs;
w += server[i].naddrs * server[i].weight;
@ -131,7 +246,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
}
}
if (n == 0) {
if (n == 0
#if (NGX_HTTP_UPSTREAM_ZONE)
&& !resolve
#endif
) {
return NGX_OK;
}
if (n + r == 0 && !(us->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
return NGX_OK;
}
@ -140,12 +263,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
return NGX_ERROR;
}
peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
* (n + r));
if (peer == NULL) {
return NGX_ERROR;
}
if (n > 0) {
peers->single = 0;
}
backup->single = 0;
backup->number = n;
backup->weighted = (w != n);
@ -156,11 +283,47 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
peerp = &backup->peer;
#if (NGX_HTTP_UPSTREAM_ZONE)
rpeerp = &backup->resolve;
#endif
for (i = 0; i < us->servers->nelts; i++) {
if (!server[i].backup) {
continue;
}
#if (NGX_HTTP_UPSTREAM_ZONE)
if (server[i].host.len) {
peer[n].host = ngx_pcalloc(cf->pool,
sizeof(ngx_http_upstream_host_t));
if (peer[n].host == NULL) {
return NGX_ERROR;
}
peer[n].host->name = server[i].host;
peer[n].host->service = server[i].service;
peer[n].sockaddr = server[i].addrs[0].sockaddr;
peer[n].socklen = server[i].addrs[0].socklen;
peer[n].name = server[i].addrs[0].name;
peer[n].weight = server[i].weight;
peer[n].effective_weight = server[i].weight;
peer[n].current_weight = 0;
peer[n].max_conns = server[i].max_conns;
peer[n].max_fails = server[i].max_fails;
peer[n].fail_timeout = server[i].fail_timeout;
peer[n].down = server[i].down;
peer[n].server = server[i].name;
*rpeerp = &peer[n];
rpeerp = &peer[n].next;
n++;
continue;
}
#endif
for (j = 0; j < server[i].naddrs; j++) {
peer[n].sockaddr = server[i].addrs[j].sockaddr;
peer[n].socklen = server[i].addrs[j].socklen;
@ -273,7 +436,12 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
rrp->peers = us->peer.data;
rrp->current = NULL;
rrp->config = 0;
ngx_http_upstream_rr_peers_rlock(rrp->peers);
#if (NGX_HTTP_UPSTREAM_ZONE)
rrp->config = rrp->peers->config ? *rrp->peers->config : 0;
#endif
n = rrp->peers->number;
@ -281,6 +449,10 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
n = rrp->peers->next->number;
}
r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
ngx_http_upstream_rr_peers_unlock(rrp->peers);
if (n <= 8 * sizeof(uintptr_t)) {
rrp->tried = &rrp->data;
rrp->data = 0;
@ -296,7 +468,6 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
#if (NGX_HTTP_SSL)
r->upstream->peer.set_session =
ngx_http_upstream_set_round_robin_peer_session;
@ -446,6 +617,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
peers = rrp->peers;
ngx_http_upstream_rr_peers_wlock(peers);
#if (NGX_HTTP_UPSTREAM_ZONE)
if (peers->config && rrp->config != *peers->config) {
goto busy;
}
#endif
if (peers->single) {
peer = peers->peer;
@ -458,6 +635,7 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
}
rrp->current = peer;
ngx_http_upstream_rr_peer_ref(peers, peer);
} else {
@ -510,6 +688,10 @@ failed:
ngx_http_upstream_rr_peers_wlock(peers);
}
#if (NGX_HTTP_UPSTREAM_ZONE)
busy:
#endif
ngx_http_upstream_rr_peers_unlock(peers);
pc->name = peers->name;
@ -580,6 +762,7 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
}
rrp->current = best;
ngx_http_upstream_rr_peer_ref(rrp->peers, best);
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
@ -617,9 +800,16 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
if (rrp->peers->single) {
if (peer->fails) {
peer->fails = 0;
}
peer->conns--;
if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
}
ngx_http_upstream_rr_peers_unlock(rrp->peers);
pc->tries = 0;
@ -661,7 +851,10 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
peer->conns--;
if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
}
ngx_http_upstream_rr_peers_unlock(rrp->peers);
if (pc->tries) {
@ -685,7 +878,6 @@ ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
int len;
const u_char *p;
ngx_http_upstream_rr_peers_t *peers;
u_char buf[NGX_SSL_MAX_SESSION_SIZE];
#endif
peer = rrp->current;
@ -705,12 +897,12 @@ ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
len = peer->ssl_session_len;
ngx_memcpy(buf, peer->ssl_session, len);
ngx_memcpy(ngx_ssl_session_buffer, peer->ssl_session, len);
ngx_http_upstream_rr_peer_unlock(peers, peer);
ngx_http_upstream_rr_peers_unlock(peers);
p = buf;
p = ngx_ssl_session_buffer;
ssl_session = d2i_SSL_SESSION(NULL, &p, len);
rc = ngx_ssl_set_session(pc->connection, ssl_session);
@ -747,7 +939,6 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
int len;
u_char *p;
ngx_http_upstream_rr_peers_t *peers;
u_char buf[NGX_SSL_MAX_SESSION_SIZE];
#endif
#if (NGX_HTTP_UPSTREAM_ZONE)
@ -761,18 +952,18 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
return;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"save session: %p", ssl_session);
len = i2d_SSL_SESSION(ssl_session, NULL);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"save session: %p:%d", ssl_session, len);
/* do not cache too big session */
if (len > NGX_SSL_MAX_SESSION_SIZE) {
return;
}
p = buf;
p = ngx_ssl_session_buffer;
(void) i2d_SSL_SESSION(ssl_session, &p);
peer = rrp->current;
@ -802,7 +993,7 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
peer->ssl_session_len = len;
}
ngx_memcpy(peer->ssl_session, buf, len);
ngx_memcpy(peer->ssl_session, ngx_ssl_session_buffer, len);
ngx_http_upstream_rr_peer_unlock(peers, peer);
ngx_http_upstream_rr_peers_unlock(peers);
@ -830,8 +1021,6 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"old session: %p", old_ssl_session);
/* TODO: may block */
ngx_ssl_free_session(old_ssl_session);
}
}

View File

@ -14,8 +14,25 @@
#include <ngx_http.h>
typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t;
typedef struct ngx_http_upstream_rr_peer_s ngx_http_upstream_rr_peer_t;
#if (NGX_HTTP_UPSTREAM_ZONE)
typedef struct {
ngx_event_t event; /* must be first */
ngx_uint_t worker;
ngx_str_t name;
ngx_str_t service;
time_t valid;
ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_rr_peer_t *peer;
} ngx_http_upstream_host_t;
#endif
struct ngx_http_upstream_rr_peer_s {
struct sockaddr *sockaddr;
socklen_t socklen;
@ -46,24 +63,28 @@ struct ngx_http_upstream_rr_peer_s {
#endif
#if (NGX_HTTP_UPSTREAM_ZONE)
unsigned zombie:1;
ngx_atomic_t lock;
ngx_uint_t refs;
ngx_http_upstream_host_t *host;
#endif
ngx_http_upstream_rr_peer_t *next;
NGX_COMPAT_BEGIN(32)
NGX_COMPAT_BEGIN(15)
NGX_COMPAT_END
};
typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t;
struct ngx_http_upstream_rr_peers_s {
ngx_uint_t number;
#if (NGX_HTTP_UPSTREAM_ZONE)
ngx_slab_pool_t *shpool;
ngx_atomic_t rwlock;
ngx_uint_t *config;
ngx_http_upstream_rr_peer_t *resolve;
ngx_http_upstream_rr_peers_t *zone_next;
#endif
@ -114,6 +135,65 @@ struct ngx_http_upstream_rr_peers_s {
ngx_rwlock_unlock(&peer->lock); \
}
#define ngx_http_upstream_rr_peer_ref(peers, peer) \
(peer)->refs++;
static ngx_inline void
ngx_http_upstream_rr_peer_free_locked(ngx_http_upstream_rr_peers_t *peers,
ngx_http_upstream_rr_peer_t *peer)
{
if (peer->refs) {
peer->zombie = 1;
return;
}
ngx_slab_free_locked(peers->shpool, peer->sockaddr);
ngx_slab_free_locked(peers->shpool, peer->name.data);
if (peer->server.data) {
ngx_slab_free_locked(peers->shpool, peer->server.data);
}
#if (NGX_HTTP_SSL)
if (peer->ssl_session) {
ngx_slab_free_locked(peers->shpool, peer->ssl_session);
}
#endif
ngx_slab_free_locked(peers->shpool, peer);
}
static ngx_inline void
ngx_http_upstream_rr_peer_free(ngx_http_upstream_rr_peers_t *peers,
ngx_http_upstream_rr_peer_t *peer)
{
ngx_shmtx_lock(&peers->shpool->mutex);
ngx_http_upstream_rr_peer_free_locked(peers, peer);
ngx_shmtx_unlock(&peers->shpool->mutex);
}
static ngx_inline ngx_int_t
ngx_http_upstream_rr_peer_unref(ngx_http_upstream_rr_peers_t *peers,
ngx_http_upstream_rr_peer_t *peer)
{
peer->refs--;
if (peers->shpool == NULL) {
return NGX_OK;
}
if (peer->refs == 0 && peer->zombie) {
ngx_http_upstream_rr_peer_free(peers, peer);
return NGX_DONE;
}
return NGX_OK;
}
#else
#define ngx_http_upstream_rr_peers_rlock(peers)
@ -121,6 +201,8 @@ struct ngx_http_upstream_rr_peers_s {
#define ngx_http_upstream_rr_peers_unlock(peers)
#define ngx_http_upstream_rr_peer_lock(peers, peer)
#define ngx_http_upstream_rr_peer_unlock(peers, peer)
#define ngx_http_upstream_rr_peer_ref(peers, peer)
#define ngx_http_upstream_rr_peer_unref(peers, peer) NGX_OK
#endif

View File

@ -292,6 +292,11 @@ ngx_http_v2_init(ngx_event_t *rev)
c->data = h2c;
if (ngx_exiting) {
ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
return;
}
rev->handler = ngx_http_v2_read_handler;
c->write->handler = ngx_http_v2_write_handler;

View File

@ -115,10 +115,11 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
ngx_http_core_srv_conf_t *cscf;
u_char addr[NGX_SOCKADDR_STRLEN];
static const u_char nginx[5] = "\x84\xaa\x63\x55\xe7";
static const u_char nginx[5] = { 0x84, 0xaa, 0x63, 0x55, 0xe7 };
#if (NGX_HTTP_GZIP)
static const u_char accept_encoding[12] =
"\x8b\x84\x84\x2d\x69\x5b\x05\x44\x3c\x86\xaa\x6f";
static const u_char accept_encoding[12] = {
0x8b, 0x84, 0x84, 0x2d, 0x69, 0x5b, 0x05, 0x44, 0x3c, 0x86, 0xaa, 0x6f
};
#endif
static size_t nginx_ver_len = ngx_http_v2_literal_size(NGINX_VER);

View File

@ -70,7 +70,7 @@ ngx_http_v3_keepalive_handler(ngx_event_t *ev)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 keepalive handler");
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR,
ngx_http_v3_shutdown_connection(c, NGX_HTTP_V3_ERR_NO_ERROR,
"keepalive timeout");
}

View File

@ -23,7 +23,7 @@
#define NGX_HTTP_V3_HQ_ALPN_PROTO "\x0Ahq-interop"
#define NGX_HTTP_V3_HQ_PROTO "hq-interop"
#define NGX_HTTP_V3_VARLEN_INT_LEN 4
#define NGX_HTTP_V3_VARLEN_INT_LEN 8
#define NGX_HTTP_V3_PREFIX_INT_LEN 11
#define NGX_HTTP_V3_STREAM_CONTROL 0x00

View File

@ -810,6 +810,7 @@ ngx_http_v3_parse_field_lri(ngx_connection_t *c,
st->literal.length = st->pint.value;
if (st->literal.length == 0) {
st->value.data = (u_char *) "";
goto done;
}
@ -932,6 +933,7 @@ ngx_http_v3_parse_field_l(ngx_connection_t *c,
st->literal.length = st->pint.value;
if (st->literal.length == 0) {
st->value.data = (u_char *) "";
goto done;
}
@ -1072,6 +1074,7 @@ ngx_http_v3_parse_field_lpbi(ngx_connection_t *c,
st->literal.length = st->pint.value;
if (st->literal.length == 0) {
st->value.data = (u_char *) "";
goto done;
}

View File

@ -134,7 +134,17 @@ ngx_http_v3_init(ngx_connection_t *c)
}
}
return ngx_http_v3_send_settings(c);
if (ngx_http_v3_send_settings(c) != NGX_OK) {
return NGX_ERROR;
}
if (h3scf->max_table_capacity > 0) {
if (ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER) == NULL) {
return NGX_ERROR;
}
}
return NGX_OK;
}
@ -399,13 +409,11 @@ void
ngx_http_v3_reset_stream(ngx_connection_t *c)
{
ngx_http_v3_session_t *h3c;
ngx_http_v3_srv_conf_t *h3scf;
h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module);
h3c = ngx_http_v3_get_session(c);
if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq
if (!c->read->eof && !h3c->hq
&& h3c->known_streams[NGX_HTTP_V3_STREAM_SERVER_DECODER]
&& (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0)
{
(void) ngx_http_v3_send_cancel_stream(c, c->quic->id);
@ -1575,6 +1583,15 @@ ngx_http_v3_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
/* rc == NGX_OK */
if (max != -1 && (uint64_t) (max - rb->received) < st->length) {
if (r->headers_in.content_length_n != -1) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client intended to send body data "
"larger than declared");
return NGX_HTTP_BAD_REQUEST;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client intended to send too large "
"body: %O+%ui bytes",

View File

@ -308,7 +308,7 @@ ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity)
prev_max = dt->capacity / 32;
if (max > prev_max) {
elts = ngx_alloc(max * sizeof(void *), c->log);
elts = ngx_alloc((max + 1) * sizeof(void *), c->log);
if (elts == NULL) {
return NGX_ERROR;
}

View File

@ -20,8 +20,6 @@ static void ngx_http_v3_close_uni_stream(ngx_connection_t *c);
static void ngx_http_v3_uni_read_handler(ngx_event_t *rev);
static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev);
static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev);
static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c,
ngx_uint_t type);
void
@ -307,7 +305,7 @@ ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev)
}
static ngx_connection_t *
ngx_connection_t *
ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type)
{
u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN];

View File

@ -19,6 +19,8 @@ ngx_int_t ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type);
ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id);
ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c,
ngx_uint_t type);
ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c);
ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id);
ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c,

View File

@ -1019,12 +1019,36 @@ ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state)
break;
case ngx_imap_passwd:
/*
* untagged CAPABILITY response (draft-crispin-imapv-16),
* known to be sent by SmarterMail and Gmail
*/
if (p[0] == '*' && p[1] == ' ') {
p += 2;
while (p < b->last - 1) {
if (p[0] == CR && p[1] == LF) {
p += 2;
break;
}
p++;
}
if (b->last - p < 4) {
return NGX_AGAIN;
}
}
if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0) {
p += s->tag.len;
if (p[0] == 'O' && p[1] == 'K') {
return NGX_OK;
}
}
break;
}

View File

@ -344,9 +344,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
prev->prefer_server_ciphers, 0);
ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
(NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));
ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
@ -450,9 +448,13 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->verify) {
if (conf->client_certificate.len == 0 && conf->verify != 3) {
if (conf->verify != 3
&& conf->client_certificate.len == 0
&& conf->trusted_certificate.len == 0)
{
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no ssl_client_certificate for ssl_verify_client");
"no ssl_client_certificate or "
"ssl_trusted_certificate for ssl_verify_client");
return NGX_CONF_ERROR;
}

View File

@ -103,7 +103,7 @@ typedef struct aiocb ngx_aiocb_t;
#define NGX_LISTEN_BACKLOG -1
#ifdef __DragonFly__
#if (defined __DragonFly__ && __DragonFly_version < 500702)
#define NGX_KEEPALIVE_FACTOR 1000
#endif

View File

@ -52,7 +52,6 @@
#include <malloc.h> /* memalign() */
#include <limits.h> /* IOV_MAX */
#include <sys/ioctl.h>
#include <crypt.h>
#include <sys/utsname.h> /* uname() */
#include <dlfcn.h>
@ -61,6 +60,11 @@
#include <ngx_auto_config.h>
#if (NGX_HAVE_CRYPT_H)
#include <crypt.h>
#endif
#if (NGX_HAVE_POSIX_SEM)
#include <semaphore.h>
#endif

View File

@ -41,7 +41,7 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
return NGX_ERROR;
}
#else
#elif (NGX_HAVE_CRYPT)
ngx_int_t
ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
@ -71,6 +71,14 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
return NGX_ERROR;
}
#else
ngx_int_t
ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
{
return NGX_ERROR;
}
#endif
#endif /* NGX_CRYPT */

Some files were not shown because too many files have changed in this diff Show More