Roman Arutyunyan [Mon, 29 Jun 2026 17:49:27 +0000 (21:49 +0400)]
Avoid duplicate subrequest finalization
Previously, if a subrequest was posted twice, it could be finalized in
both calls, excessively reducing r->main->count and potentially leading
to a use-after-free.
The fix is to avoid posting a request if it's already posted. Also,
as a hardening measure, r->write_event_handler is now reset to a no-op
handler during active subrequest finalization.
The problem manifests itself in ngx_http_ssi_filter_module during
unbuffered proxying. If a subrequest is created for an SSI include
statement while the main request has some data postponed by another
include, this subrequest becomes double-posted when the main request
data is flushed. The first post comes from ngx_http_subrequest() and
the second one comes from ngx_http_postpone_filter(). In case of a
quick subrequest finalization, the above mentioned problem happens.
Pavel Pautov [Fri, 15 May 2026 07:48:50 +0000 (00:48 -0700)]
Fixed uninitialized memory read caused by stale regex captures.
When ngx_http_regex_exec() reallocates r->captures array, it doesn't update
r->ncaptures value, if regex didn't match. So the next use of unnamed regex
capture triggers uninitialized read and potential buffer overrun.
This config demonstrates the issue:
map test $my_map {
volatile;
~mismatch(.*) 1; # reallocates r->captures in subrequests
default "";
}
server {
location ~(.*) { # sets r->ncaptures
slice 50;
# $1 will read from uninitialized memory in slice subrequests
proxy_set_header Test $my_map$1;
proxy_set_header Range $slice_range;
proxy_pass http://backend;
}
}
Script: avoid garbage at the end of the result string
If the script result turned out to be shorter than its predicted
length, the result string contained uninitialized bytes at the end.
The fix is to cut the result string by its actual size.
The following locations returned trailing garbage to the client with
URI "/1234abcd".
Maxim Dounin [Fri, 19 Jun 2026 19:54:46 +0000 (22:54 +0300)]
Script: buffer overrun protection in direct script usage.
Following the previous change, this change adds script overrun
protection to direct script evaluation in the proxy, fastcgi, scgi,
uwsgi, grpc proxy, index, and try_files modules.
This change is a modified version of a patch by Maxim Dounin. The
modifications include ngx_http_proxy_v2_module and hardened size checks.
Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/7e4d7feb4c77>
Maxim Dounin [Fri, 19 Jun 2026 19:54:27 +0000 (22:54 +0300)]
Script: buffer overrun protection.
With this change, all script copy operations now check if there is
enough room in the buffer. To do so, the script engine now provides the
e->end pointer, which specifies expected buffer end, and each copy
operation is checked against it with the ngx_http_script_check_length()
function.
The e->end pointer is optional and only checked when set, thus
introducing no incompatible API changes. All standard functions were
updated to use it, notably ngx_http_complex_value(), ngx_http_script_run(),
ngx_http_script_regex_start_code(), ngx_http_script_complex_value_code().
Direct script evaluation in the proxy, fastcgi, scgi, uwsgi, grpc proxy,
index, and try_files modules will be updated by a separate patch.
In particular, this catches issues as observed when evaluating variables
with side effects, such as in the following configuration:
map $uri $map {
~(?<capture>.*) $capture;
}
set $capture "";
set $temp "$capture $map";
As well as when evaluating non-cacheable variables, where length of a
variable might change between length and copy codes, such as in the
following configuration:
Roman Arutyunyan [Mon, 13 Jul 2026 18:16:34 +0000 (22:16 +0400)]
Disable HTTP keepalive for HTTP CONNECT requests
As per RFC 2817 Section 5.2:
Like any other pipelined HTTP/1.1 request, data to be tunneled may be
sent immediately after the blank line. The usual caveats also apply:
data may be discarded if the eventual response is negative, and the
connection may be reset with no response if more than one TCP segment
is outstanding.
A user agent SHOULD NOT send a Content-Length header field when the
request message does not contain content and the method semantics do
not anticipate such data.
Stream: proxy_socket_sndbuf and proxy_socket_rcvbuf directives
Similarly to "listen ... sndbuf/rcvbuf", proxy_socket_sndbuf and
proxy_socket_rcvbuf can be used to set the SO_SNDBUF and SO_RCVBUF
socket options, respectively, on upstream connections. By default,
the values are left unchanged.
Upstream: proxy_socket_sndbuf and proxy_socket_rcvbuf directives
Similarly to "listen ... sndbuf/rcvbuf", proxy_socket_sndbuf and
proxy_socket_rcvbuf can be used to set the SO_SNDBUF and SO_RCVBUF
socket options, respectively, for upstream connections. By default,
the values are left unchanged.
Similar changes made in fastcgi, grpc, scgi, uwsgi, tunnel.
Events: support for SO_SNDBUF on outbound peer connections
ngx_event_connect_peer() honors SO_RCVBUF via pc->rcvbuf but had
no equivalent for SO_SNDBUF. This adds pc->sndbuf and the matching
setsockopt() call, mirroring the existing SO_RCVBUF path.
Both setsockopt() calls are made non-fatal.
Existing callers leaving sndbuf at 0 retain prior behavior, since
setsockopt() is only invoked when the field is non-zero. These
fields are consumed by various proxying modules in follow-up commits.
HTTP/2: reject requests with out-of-order pseudo-headers
Handling of pseudo-headers is refactored to be more in line with
HTTP/3 implementation, that is, a request line is now constructed
as soon as pseudo-headers are followed by regular fields. Here
this plugs a missing handling for absent mandatory or out-of-order
pseudo-headers.
Such requests are now rejected immediately as malformed.
With this change, active request object is recorded in the
ngx_http_perl_call_handler() function, and checked by
ngx_http_perl_set_request() to prevent use of unexpected request
objects.
Reported by Axel Mierczuk, Keith Hoodlet, 1Password’s Off-by-1 Labs.
Maxim Dounin [Fri, 26 Jun 2026 19:23:28 +0000 (22:23 +0300)]
Perl: introduced reference counting for perl scalars
Perl scalars might have a limited lifetime, and using them without
appropriate reference counting is incorrect. In particular, heap
use-after-free was observed in the following configuration (note the
"eval", which limits lifetime of the string being printed), which
demonstrates that the previously used SvREADONLY() optimizations are
incorrect:
Similarly, errors were observed with handlers in $r->sleep() and
$r->has_request_body() when a handler comes from an eval, such as in
the following configuration:
Accordingly, the SvREADONLY() optimization was removed in
ngx_http_perl_sv2str(), since it is expected to be used for small
strings, and using proper reference counting likely will be more costly
than just copying the string. In $r->print(), $r->sleep(), and
$r->has_request_body() proper reference counting was implemented, with
decrement operations being performed by pool cleanup handlers.
As a positive side effect, $r->print() can now avoid copying any single
scalar, not just read-only scalars.
Reported by Evan Hellman,
https://github.com/freenginx/nginx/issues/26
Zhidao HONG [Tue, 19 May 2026 07:59:56 +0000 (07:59 +0000)]
Proxy: fixed HTTP/2 upstream with revalidated cache send
Previously, a revalidated cached response could fail on a cached
keepalive connection with "upstream sent frame for unknown stream"
error followed by "cache file contains invalid header".
This happened because after a 304 response, nginx parsed the cached
response while the upstream peer connection was still attached to the
request. The HTTP/2 proxy code treated cached frames as frames from
that live connection, and could assign a real stream id instead of
treating the cached response as having no real stream.
The fix is to treat cached response parsing as cache-only regardless
of the current upstream peer connection: set the stream id to 0 and
skip live upstream control-frame handling while r->cached is set.
Zhidao HONG [Mon, 8 Jun 2026 03:52:24 +0000 (03:52 +0000)]
Upstream: limit response header field sizes for HTTP/2 and gRPC
HTTP/2 and gRPC upstream response header parsing used the HPACK string
length to allocate header name and value buffers. The length was not
checked against the configured upstream buffer size before allocation.
A malicious upstream could force nginx to allocate excessive
request-pool memory before the header was rejected.
Reject oversized HTTP/2 header name and value lengths before allocation.
Also keep a per-header-block limit based on the upstream buffer size, so
a header block cannot consume unbounded memory across fields.
Zhidao HONG [Mon, 1 Jun 2026 08:41:33 +0000 (08:41 +0000)]
HTTP/2: fixed INITIAL_WINDOW_SIZE with saved state
The window size change was previously kept in a local variable while
processing SETTINGS parameters. If parsing was suspended after
SETTINGS_INITIAL_WINDOW_SIZE, the value was lost on resume and was
acknowledged without being applied.
Store the initial window size change in the HTTP/2 state until the
SETTINGS frame is fully processed.
David Carlier [Tue, 16 Jun 2026 18:58:28 +0000 (19:58 +0100)]
SSL: fixed memory leak in ngx_ssl_get_ech_outer_server_name().
SSL_ech_get1_status() allocates inner_sni and outer_sni and transfers
ownership to the caller. On the allocation-failure path the function
returned without freeing them, unlike ngx_ssl_get_ech_status() which
frees both on all paths.
Maxim Dounin [Sun, 9 Nov 2025 09:01:38 +0000 (12:01 +0300)]
Xslt: xml_external_entities directive
Loading of external entities defined in the internal DTD subset,
that is, in the XML document itself, is now disabled by default, and
can be re-enabled with "xml_external_entities on;". This makes
processing of untrusted XML responses with the xslt module slightly
safer (though still not recommended unless you thoughtfully considered
risks).
To prevent loading we intercept entities defined in the internal
subset via the entityDecl callback, and remove system identifiers from
entities. This ensures that entities cannot be loaded directly, but
still allows using of public entities with appropriate system XML
catalog.
Additionally, since libxml2 before 2.14.0 (Mar 27 2025) accepts
in-document catalogs by default, these are explicitly disabled.
Maxim Dounin [Sun, 9 Nov 2025 09:01:35 +0000 (12:01 +0300)]
Xslt: disabled loading of external entities over the network
Loading of external entities, including ones defined with the
xml_entities directive, happens while parsing the XML response, and
therefore loading over the network can block the entire worker process
for a long time. Loading of external DTD subset is disabled for the
very same reason since initial version of the module.
Further, loading over the network is anyway not available by default
since libxml2 2.13.0 (Jun 12 2024) and completely removed in libxml2
2.15.0 (Sep 15 2025).
As such, the XML_PARSE_NONET parsing option (available since libxml2
2.6.2 from 2003) is now used to prevent loading of external entities
over the network.
The fix includes the socket option level (IPPROTO_IPV6) in the feature
test and the macro (NGX_HAVE_IPV6_DONTFRAG) in the
ngx_configure_listening_sockets() function.
vinaykumar-1591 [Thu, 18 Jun 2026 06:06:33 +0000 (23:06 -0700)]
Upstream: Upgrade header processing
Pass Upgrade through for HTTP/1.x clients only: both for active
connection upgrades (101 Switching Protocols) and for advertising
available upgrades in other responses (RFC 9110 Section 7.8).
Strip it for HTTP/2+ clients where connection-specific headers
are forbidden (RFC 9113 Section 8.2.2, RFC 9114 Section 4.2).
This is actually unnecessary. Thanks to Valentin Bartenev for the
analysis
1. ngx_http_v2_handle_continuation() handles split HPACK integers at
frame boundaries
2. HPACK integers are max 4 bytes (NGX_HTTP_V2_INT_OCTETS)
3. The function is only called when length < 4 (i.e., 1-3 bytes remain)
4. The copy destination is offset by 9 bytes (frame header size)
Since 3 < 9, source and destination never overlap.
Feng Wu [Tue, 23 Jun 2026 23:22:43 +0000 (07:22 +0800)]
Add missing bounds check in ngx_{http,stream}_compile_complex_value()
Complex value compilation scans strings for $1..$9 capture references.
Check that a byte after '$' is present before testing it, matching
ngx_str_t length semantics and avoiding reliance on NUL termination.
Apply the same check to both HTTP and stream implementations.
Feng Wu [Sun, 21 Jun 2026 09:30:29 +0000 (17:30 +0800)]
HTTP/2: fixed overlapping memcpy in CONTINUATION frames
When processing CONTINUATION frames, ngx_http_v2_handle_continuation()
used ngx_memcpy() to shift header block fragment data past the frame
header. If the fragment is larger than the frame header (9 bytes),
the source and destination regions overlap, which is undefined
behavior for memcpy. The same function already uses ngx_memmove()
for another overlapping shift.
Charset: fixed another rare buffer overread in recode_from_utf8()
With prerequisites similar to 696a7f1b9, it was possible to gain 1-byte
overread on invalid UTF-8 sequences. The reason is ngx_utf8_decode()
stops advancing the pointer position on the first encountered invalid
byte. The fix is to adjust the advanced pointer up to the whole saved
sequence in this case. Note that this may result in different output
compared to complete invalid UTF-8 sequences, which we can disregard
at this point.
Reported by Han Yan of Xiaomi and p4p3r of CYBERONE.
Roman Arutyunyan [Tue, 19 May 2026 12:09:35 +0000 (16:09 +0400)]
HTTP/3: avoid recreation of standard client uni streams
Creating a control/encoder/decoder stream while another such stream
already exists, is not allowed. Also, closing such a stream results
in connection closure with NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM.
However, since stream creation and connection closure are asynchronous,
there could be a window where two control/encoder/decoder streams
could coexist within a single cycle iteration. This could result
in reusing parsing context, such as encoder insert buffer.
The change adds a mask for all standard client uni streams ever created.
This allows to check if a stream of this type was created before.
While here, mandatory stream validation now also uses this mask.
Roman Arutyunyan [Tue, 19 May 2026 11:46:31 +0000 (15:46 +0400)]
HTTP/3: allocate insert buffer from connection pool
Previously, it was allocated from the encoder stream pool. This could
lead to use-after-free if the stream was closed and another encoder
stream was opened.
Split clients: improved calculation of range boundaries
If the last variant was given an explicit percentage to reach 100%, it
did not cover hash values on the range boundary or due to accumulating
rounding error. Now this corresponds to the configuration with "*".
Vadim Zhestikov [Tue, 2 Jun 2026 15:02:17 +0000 (08:02 -0700)]
SSL: add $ssl_sigalgs variable
The new $ssl_sigalgs variable lists all signature algorithms
advertised by the client in its ClientHello message,
colon-separated, in analogy to $ssl_ciphers and $ssl_curves.
On OpenSSL 4.0+, SSL_get0_sigalg() is used, which returns proper
TLS scheme names (e.g. "rsa_pkcs1_sha256", "ecdsa_secp256r1_sha256")
and falls back to "0xHHHH" hex for unknown schemes.
On OpenSSL 1.0.2+, SSL_get_sigalgs() is used. Since OBJ_nid2sn()
on the combined psignhash NID is not injective across TLS
SignatureScheme codes (e.g. 0x0403 and 0x081a both yield
"ecdsa-with-SHA256"), raw SignatureScheme codes are reported to
avoid ambiguity and to match the hex fallback format of
SSL_get0_sigalg().
With older versions, as well as BoringSSL, LibreSSL, and AWS-LC,
the variable is empty.
Replaced RAND_bytes() and random() based $request_id
generation with SipHash-2-4. The previous implementation
used RAND_bytes() when built with OpenSSL, which is
50-100x slower than needed for a non-security identifier,
and fell back to random() which produces poor 128-bit
random numbers.
The new implementation calls SipHash twice with a secret
key and a monotonic counter, producing 128 bits with good
statistical distribution at a fraction of the cost.
Roman Arutyunyan [Thu, 14 May 2026 14:42:18 +0000 (18:42 +0400)]
Rewrite: fix buffer overflow with overlapping captures
When the rewrite replacement string had no variables, but had
overlapping captures, the length of the allocated buffer could be
smaller than the replacement string. This could happen either
when the "redirect" parameter is specified, or when arguments are
present in the replacement string.
The following configurations resulted in heap buffer overflow when
using URI "/++++++++++++++++++++++++++++++":
Roman Arutyunyan [Thu, 14 May 2026 13:47:42 +0000 (17:47 +0400)]
Rewrite: harden escape flags control
Following 2046b45aa0c6, this change introduces better control of memory
allocation flags for escaped values. Notably:
- The e->is_args flag is now explicitly reset on rewrite start.
If the flag was set prior to rewrite start, then buffer overflow
could happen before 2046b45aa0c6.
- The le->is_args flag value is now copied from e->is_args when
calculating complex value length for "if" and "set" directives.
If e->is_args was set, but le->is_args was not, then buffer overflow
could happen before 2046b45aa0c6.
Roman Arutyunyan [Sat, 25 Apr 2026 12:41:36 +0000 (16:41 +0400)]
Mail: fix session cleanup on error path
Previously, when ngx_handle_read_event() or ngx_handle_write_event()
returned an error while handling an SMTP, POP3 or IMAP session, the
released session memory could be accessed after handling the error.
Roman Arutyunyan [Sun, 26 Apr 2026 16:20:26 +0000 (20:20 +0400)]
HTTP/2: limit Content-Type and Location response header length
Previously, when these fields were larger than ~2M, the number of bytes
allocated for the field length was insufficient for such a large number.
The deficit is 1 byte up until ~4M, 2 bytes for sizes above, and grows
bigger with even larger fields.
Currently, nginx does not have modules which allow to exploit this
overflow with reasonably large Content-Type and Location. The reason is
other response fields make up for this deficit. For example, the Date
header value contains the characters compressed well by Huffman
encoding, which frees up spare bytes in the header buffer.
Proxy: fix large body with proxy_set_body and HTTP/2
Previously, if proxy_set_body was used with HTTP/2, and body size exceeded
16M, then an overflow happened in the 24-bit DATA frame size, which resulted
in sending unframed bytes, potentially allowing for an injection.
Also, DATA frame size could exceed NGX_HTTP_V2_DEFAULT_FRAME_SIZE (16K) and
available send window.
If there were arguments in a rewrite's replacement string, the is_args flag
was set and incorrectly never cleared. This resulted in escaping applied
to any captures evaluated afterwards in set or if. Additionally buffer was
allocated by ngx_http_script_complex_value_code() without escaping expected,
thus this also resulted in buffer overrun and possible segfault.
If the first response line was split across reads and it didn't appear
a status line, the portion already processed was lost. The change
introduces a new field for proper backtracking on status line fallback.
Upstream: reset parsing state after invalid status line
Previously, it was possible to start parsing headers with a wrong
parsing state after status line was not recognized, as a fallback
used in the scgi and uwsgi modules.
David Carlier [Sun, 12 Apr 2026 06:13:23 +0000 (07:13 +0100)]
Charset: fix buffer over-read in recode_from_utf8().
When a multi-byte UTF-8 character was split across 3+ single-byte
buffers, the saved bytes continuation path had two related bugs:
ngx_utf8_decode() was called with the last saved-array index instead
of the byte count, causing it to report "incomplete" even when the
sequence was already complete.
The subsequent ngx_memcpy() used that same index as the copy length,
reading past the input buffer boundary.
Roman Arutyunyan [Thu, 30 Apr 2026 13:15:53 +0000 (17:15 +0400)]
QUIC: avoid assigning unvalidated address to new streams
Previously, when a client migrated to a new address, new QUIC streams
received this address before validation. This allowed an attacker to
create QUIC streams with a spoofed address.
Roman Arutyunyan [Tue, 21 Apr 2026 10:51:41 +0000 (14:51 +0400)]
OCSP: resolve cleanup on connection close
Previously, when a client SSL connection was terminated (typically due to a
timeout) while resolving an OCSP responder, the OCSP context was freed, but
the resolve context was not. This resulted in use-after-free on resolve
completion.
Support 407 code in "satisfy any" and "auth_delay"
Notably, "auth_delay" now delays the response for both 401 and 407.
Also, in the "satisfy any" mode, the next access/auth attempt is made
for 401, 403 and 407.
Andrew Clayton [Tue, 5 May 2026 18:17:59 +0000 (19:17 +0100)]
GH: update the stale PR/issue workflow
To avoid future churn give the workflow a generic name, don't operate on
pull-requests, and extend the issues stale date to 365 days and update
its message.
Proxy: fix keepalive for HTTP/2 with explicit or no body
Previously, when an HTTP/2 request had no body or an explicit body
was set by proxy_set_body, the request consisted of only one buffer,
which had no b->last_buf flag set. This prevented ctx->output_closed
from being set after processing this buffer. Consequently,
u->keepalive might not be set to store the connection in the
keepalive cache.
Dav: improved path validation for COPY and MOVE operations
The COPY and MOVE handler did not validate whether source and
destination paths referred to the same resource or a parent-child
collection relationship, which could corrupt or destroy files.
Now 403 is returned if paths match or one is a prefix of the other.
Vladimir Homutov [Fri, 28 Oct 2016 13:01:53 +0000 (16:01 +0300)]
Upstream: least_time balancer module
The module implements load-balancing algorithm based on least average
response header/last_byte time and least number of active connections.
The optional "inflight" mode enables accounting of incomplete
requests/sessions. This allows to mitigate cases when an upstream
server hangs and does not close connections.
Example configuration:
upstream u {
least_time header | last_byte [inflight];
server a;
server b;
}
Andrew Clayton [Wed, 29 Apr 2026 18:18:03 +0000 (19:18 +0100)]
Configure: fix gcc version detection in some corner cases
If the "gcc version ... " string appeared within "Configured with:", it
was picked up rather than the real gcc version string. This might then
break the configure scripts due to a malformed NGX_COMPILER macro.
The simple fix is to look for "gcc version ... " at the start of the
line, rather than anywhere within.
Suggested-by: Aleksei Bavshin <a.bavshin@nginx.com> Closes: https://github.com/nginx/nginx/issues/1278
Sergey Kandaurov [Fri, 14 Nov 2025 12:06:56 +0000 (16:06 +0400)]
Request body: restored buffered empty body special case
This restores a long-standing optimization when the entire request
body is empty and r->request_body_in_file_only is set, used to avoid
writing an empty file as initially introduced in 4c7f51136 (0.4.4).
The previous condition never worked with chunked body filter, where
rb->bufs holds at least the final chunk; in length body filter, it is
used to indicate the last received buffer since 2a7092138 (1.21.2).
The fix is to additionally check if it is the only empty buffer.
Found with UndefinedBehaviorSanitizer (pointer-overflow)
Henry Yuan [Thu, 23 Apr 2026 21:24:24 +0000 (21:24 +0000)]
Configure: renamed the upstream sticky module option.
The module can now be disabled with the
--without-http_upstream_sticky_module option to match
the naming convention used by other upstream modules.
Deprecated the --without-http_upstream_sticky option.
Andrew Clayton [Thu, 19 Mar 2026 04:21:21 +0000 (04:21 +0000)]
Avoid undefined behaviour in ngx_pstrdup()
In the third call to ngx_pstrdup() for setting cycle->conf_param.data in
ngx_init_cycle() we would pass in a nulled ngx_str_t in the case there
was no -g command line option passed to nginx.
This would result in a
memcpy(dst, NULL, 0)
which up to and including C23 is Undefined Behaviour.
Currently Clang and GCC (in this particular case) just treat this as a
no-op, so things just happen to work.
However some undefined behaviour sanitizers will throw an error when
this is hit, e.g. Clang and the zig compiler and it's probably best not
to rely on this behaviour.
It's worth noting that the next C standard will make this (and other
NULL related operations) defined behaviour.
Vadim Zhestikov [Mon, 2 Feb 2026 22:46:00 +0000 (14:46 -0800)]
Stream: support ALPN for proxy_ssl upstream.
Added the proxy_ssl_alpn directive, which sets the list of protocols
to advertise via ALPN during upstream TLS handshakes. Each argument
is a complex value, so variables are accepted. In particular,
proxy_ssl_alpn $ssl_alpn_protocol;
inherits the protocol negotiated in the downstream TLS handshake.
When all evaluated values are empty or absent, no ALPN extension is
sent, equivalent to the directive not being set at all.
Roman Arutyunyan [Fri, 10 Apr 2026 17:42:18 +0000 (21:42 +0400)]
HTTP/3: optimize encoder stream memory usage
Previously, the encoder stream allocated each new inserted field in the
connection pool. This memory was not freed until the end of the connection.
Now a special insert buffer is used for all inserts.
SSL: logging level of "record layer failure" errors
The SSL_R_RECORD_LAYER_FAILURE ("record layer failure") errors are
reported by OpenSSL 3.2 or newer as the last record layer error for
various low level read errors. Further, a976e6b9e (1.23.4) caused
to always log them at the "crit" level. For example, the following
errors are observed on OpenSSL 3.2.0 - 4.0:
SSL_read() failed (SSL: error:0A000119:SSL routines::decryption failed
or bad record mac error:0A000139:SSL routines::record layer failure)
SSL_read() failed (SSL: error:1C800066:Provider routines::cipher operation
failed error:0A000119:SSL routines::decryption failed or bad record mac
error:0A000139:SSL routines::record layer failure)
SSL_read() failed (SSL: error:0A00010B:SSL routines::wrong version number
error:0A000139:SSL routines::record layer failure)