Merge branch 'nginx' (nginx-1.21.4).
Change-Id: I536c3df3620b3fc2f904d920d07bea71cd5d70e4
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 34b2f18..ef68adc 100644
--- a/.hgtags
+++ b/.hgtags
@@ -464,3 +464,4 @@
a68ac0677f8553b1f84d357bc9da114731ab5f47 release-1.21.1
bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2
2217a9c1d0b86026f22700b3c089545db1964f55 release-1.21.3
+39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4
diff --git a/BUILD b/BUILD
index 807986d..1a9004d 100644
--- a/BUILD
+++ b/BUILD
@@ -1538,5 +1538,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.21.3",
+ version = "1.21.4",
)
diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl
index 06bb4c9..36defe2 100644
--- a/bazel/repositories.bzl
+++ b/bazel/repositories.bzl
@@ -34,9 +34,9 @@
new_git_repository(
name = "nginx_pkgoss",
build_file = "@nginx//bazel/external:nginx_pkgoss.BUILD",
- commit = "48ec648c7fd9157a68f209b60e7abb25350d1ce5", # nginx-1.21.3
+ commit = "bf9b800b2fc3a037afeb64034e9bf942d1773109", # nginx-1.21.4
remote = "https://nginx.googlesource.com/nginx-pkgoss",
- shallow_since = "1631031305 +0300",
+ shallow_since = "1635865333 +0300",
)
http_archive(
diff --git a/conf/mime.types b/conf/mime.types
index b53f7f7..1c00d70 100644
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -15,6 +15,7 @@
text/vnd.wap.wml wml;
text/x-component htc;
+ image/avif avif;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 65772d0..0808b5c 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,137 @@
<change_log title="nginx">
+<changes ver="1.21.4" date="2021-11-02">
+
+<change type="change">
+<para lang="ru">
+поддержка NPN вместо ALPN для установления HTTP/2-соединений
+упразднена.
+</para>
+<para lang="en">
+support for NPN instead of ALPN to establish HTTP/2 connections
+has been removed.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx закрывает SSL соединение, если клиент использует ALPN,
+но nginx не поддерживает ни один из присланных клиентом протоколов.
+</para>
+<para lang="en">
+now nginx rejects SSL connections if ALPN is used by the client,
+but no supported protocols can be negotiated.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+в директиве sendfile_max_chunk значение по умолчанию
+изменено на 2 мегабайта.
+</para>
+<para lang="en">
+the default value of the "sendfile_max_chunk" directive
+was changed to 2 megabytes.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива proxy_half_close в модуле stream.
+</para>
+<para lang="en">
+the "proxy_half_close" directive in the stream module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива ssl_alpn в модуле stream.
+</para>
+<para lang="en">
+the "ssl_alpn" directive in the stream module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+переменная $ssl_alpn_protocol.
+</para>
+<para lang="en">
+the $ssl_alpn_protocol variable.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+поддержка SSL_sendfile() при использовании OpenSSL 3.0.
+</para>
+<para lang="en">
+support for SSL_sendfile() when using OpenSSL 3.0.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива mp4_start_key_frame в модуле ngx_http_mp4_module.<br/>
+Спасибо Tracey Jaquith.
+</para>
+<para lang="en">
+the "mp4_start_key_frame" directive in the ngx_http_mp4_module.<br/>
+Thanks to Tracey Jaquith.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в переменной $content_length при использовании chunked transfer encoding.
+</para>
+<para lang="en">
+in the $content_length variable when using chunked transfer encoding.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при получении ответа некорректной длины от проксируемого бэкенда
+nginx мог тем не менее закэшировать соединение.<br/>
+Спасибо Awdhesh Mathpal.
+</para>
+<para lang="en">
+after receiving a response with incorrect length from a proxied backend
+nginx might nevertheless cache the connection.<br/>
+Thanks to Awdhesh Mathpal.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+некорректные заголовки от бэкендов
+логгировались на уровне info вместо error;
+ошибка появилась в 1.21.1.
+</para>
+<para lang="en">
+invalid headers from backends
+were logged at the "info" level instead of "error";
+the bug had appeared in 1.21.1.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании HTTP/2 и директивы aio_write
+запросы могли зависать.
+</para>
+<para lang="en">
+requests might hang
+when using HTTP/2 and the "aio_write" directive.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.21.3" date="2021-09-07">
<change type="change">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index f60ced9..4e58152 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1021003
-#define NGINX_VERSION "1.21.3"
+#define nginx_version 1021004
+#define NGINX_VERSION "1.21.4"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c
index c3783c4..811f24d 100644
--- a/src/core/ngx_buf.c
+++ b/src/core/ngx_buf.c
@@ -203,16 +203,16 @@
while (*busy) {
cl = *busy;
- if (ngx_buf_size(cl->buf) != 0) {
- break;
- }
-
if (cl->buf->tag != tag) {
*busy = cl->next;
ngx_free_chain(p, cl);
continue;
}
+ if (ngx_buf_size(cl->buf) != 0) {
+ break;
+ }
+
cl->buf->pos = cl->buf->start;
cl->buf->last = cl->buf->start;
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index d9c157c..8215c27 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -274,6 +274,10 @@
}
for (n = 0; n < nelts; n++) {
+ if (names[n].key.data == NULL) {
+ continue;
+ }
+
if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
{
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c
index 5c3dbe8..fd4603b 100644
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -803,6 +803,10 @@
return NGX_ERROR;
}
+ if (chain && c->write->ready) {
+ ngx_post_event(c->write, &ngx_posted_next_events);
+ }
+
for (cl = ctx->out; cl && cl != chain; /* void */) {
ln = cl;
cl = cl->next;
diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c
index ff81b09..414d2d5 100644
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -200,10 +200,6 @@
#if defined(CLOCK_MONOTONIC_FAST)
clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
-
-#elif defined(CLOCK_MONOTONIC_COARSE)
- clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
-
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 602e003..282e855 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -47,6 +47,8 @@
static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data,
size_t size);
#endif
+static ssize_t ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file,
+ size_t size);
static void ngx_ssl_read_handler(ngx_event_t *rev);
static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
@@ -1787,6 +1789,16 @@
#endif
#endif
+#ifdef BIO_get_ktls_send
+
+ if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "BIO_get_ktls_send(): 1");
+ c->ssl->sendfile = 1;
+ }
+
+#endif
+
rc = ngx_ssl_ocsp_validate(c);
if (rc == NGX_ERROR) {
@@ -1922,6 +1934,16 @@
c->read->ready = 1;
c->write->ready = 1;
+#ifdef BIO_get_ktls_send
+
+ if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "BIO_get_ktls_send(): 1");
+ c->ssl->sendfile = 1;
+ }
+
+#endif
+
rc = ngx_ssl_ocsp_validate(c);
if (rc == NGX_ERROR) {
@@ -2525,10 +2547,11 @@
ngx_chain_t *
ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
{
- int n;
- ngx_uint_t flush;
- ssize_t send, size;
- ngx_buf_t *buf;
+ int n;
+ ngx_uint_t flush;
+ ssize_t send, size, file_size;
+ ngx_buf_t *buf;
+ ngx_chain_t *cl;
if (!c->ssl->buffer) {
@@ -2602,6 +2625,11 @@
continue;
}
+ if (in->buf->in_file && c->ssl->sendfile) {
+ flush = 1;
+ break;
+ }
+
size = in->buf->last - in->buf->pos;
if (size > buf->end - buf->last) {
@@ -2633,8 +2661,35 @@
size = buf->last - buf->pos;
if (size == 0) {
+
+ if (in && in->buf->in_file && send < limit) {
+
+ /* coalesce the neighbouring file bufs */
+
+ cl = in;
+ file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send);
+
+ n = ngx_ssl_sendfile(c, in->buf, file_size);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (n == NGX_AGAIN) {
+ break;
+ }
+
+ in = ngx_chain_update_sent(in, n);
+
+ send += n;
+ flush = 0;
+
+ continue;
+ }
+
buf->flush = 0;
c->buffered &= ~NGX_SSL_BUFFERED;
+
return in;
}
@@ -2659,7 +2714,7 @@
buf->pos = buf->start;
buf->last = buf->start;
- if (in == NULL || send == limit) {
+ if (in == NULL || send >= limit) {
break;
}
}
@@ -2790,7 +2845,7 @@
#ifdef SSL_READ_EARLY_DATA_SUCCESS
-ssize_t
+static ssize_t
ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size)
{
int n, sslerr;
@@ -2905,6 +2960,150 @@
#endif
+static ssize_t
+ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size)
+{
+#ifdef BIO_get_ktls_send
+
+ int sslerr;
+ ssize_t n;
+ ngx_err_t err;
+
+ ngx_ssl_clear_error(c->log);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL to sendfile: @%O %uz",
+ file->file_pos, size);
+
+ ngx_set_errno(0);
+
+ n = SSL_sendfile(c->ssl->connection, file->file->fd, file->file_pos,
+ size, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %d", n);
+
+ if (n > 0) {
+
+ if (c->ssl->saved_read_handler) {
+
+ c->read->handler = c->ssl->saved_read_handler;
+ c->ssl->saved_read_handler = NULL;
+ c->read->ready = 1;
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_post_event(c->read, &ngx_posted_events);
+ }
+
+ c->sent += n;
+
+ return n;
+ }
+
+ if (n == 0) {
+
+ /*
+ * if sendfile returns zero, then someone has truncated the file,
+ * so the offset became beyond the end of the file
+ */
+
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "SSL_sendfile() reported that \"%s\" was truncated at %O",
+ file->file->name.data, file->file_pos);
+
+ return NGX_ERROR;
+ }
+
+ sslerr = SSL_get_error(c->ssl->connection, n);
+
+ if (sslerr == SSL_ERROR_ZERO_RETURN) {
+
+ /*
+ * OpenSSL fails to return SSL_ERROR_SYSCALL if an error
+ * happens during writing after close_notify alert from the
+ * peer, and returns SSL_ERROR_ZERO_RETURN instead
+ */
+
+ sslerr = SSL_ERROR_SYSCALL;
+ }
+
+ if (sslerr == SSL_ERROR_SSL
+ && ERR_GET_REASON(ERR_peek_error()) == SSL_R_UNINITIALIZED
+ && ngx_errno != 0)
+ {
+ /*
+ * OpenSSL fails to return SSL_ERROR_SYSCALL if an error
+ * happens in sendfile(), and returns SSL_ERROR_SSL with
+ * SSL_R_UNINITIALIZED reason instead
+ */
+
+ sslerr = SSL_ERROR_SYSCALL;
+ }
+
+ err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
+
+ if (sslerr == SSL_ERROR_WANT_WRITE) {
+
+ if (c->ssl->saved_read_handler) {
+
+ c->read->handler = c->ssl->saved_read_handler;
+ c->ssl->saved_read_handler = NULL;
+ c->read->ready = 1;
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_post_event(c->read, &ngx_posted_events);
+ }
+
+ c->write->ready = 0;
+ return NGX_AGAIN;
+ }
+
+ if (sslerr == SSL_ERROR_WANT_READ) {
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL_sendfile: want read");
+
+ c->read->ready = 0;
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ /*
+ * we do not set the timer because there is already
+ * the write event timer
+ */
+
+ if (c->ssl->saved_read_handler == NULL) {
+ c->ssl->saved_read_handler = c->read->handler;
+ c->read->handler = ngx_ssl_read_handler;
+ }
+
+ return NGX_AGAIN;
+ }
+
+ c->ssl->no_wait_shutdown = 1;
+ c->ssl->no_send_shutdown = 1;
+ c->write->error = 1;
+
+ ngx_ssl_connection_error(c, sslerr, err, "SSL_sendfile() failed");
+
+#else
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "SSL_sendfile() not available");
+#endif
+
+ return NGX_ERROR;
+}
+
+
static void
ngx_ssl_read_handler(ngx_event_t *rev)
{
@@ -3157,6 +3356,9 @@
#ifdef SSL_R_CALLBACK_FAILED
|| n == SSL_R_CALLBACK_FAILED /* 234 */
#endif
+#ifdef SSL_R_NO_APPLICATION_PROTOCOL
+ || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */
+#endif
|| n == SSL_R_UNEXPECTED_MESSAGE /* 244 */
|| n == SSL_R_UNEXPECTED_RECORD /* 245 */
|| n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */
@@ -4725,6 +4927,36 @@
ngx_int_t
+ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+
+ unsigned int len;
+ const unsigned char *data;
+
+ SSL_get0_alpn_selected(c->ssl->connection, &data, &len);
+
+ if (len > 0) {
+
+ s->data = ngx_pnalloc(pool, len);
+ if (s->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(s->data, data, len);
+ s->len = len;
+
+ return NGX_OK;
+ }
+
+#endif
+
+ s->len = 0;
+ return NGX_OK;
+}
+
+
+ngx_int_t
ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
{
size_t len;
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 8ad5361..df05a6f 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -109,6 +109,7 @@
unsigned handshake_rejected:1;
unsigned renegotiation:1;
unsigned buffer:1;
+ unsigned sendfile:1;
unsigned no_wait_shutdown:1;
unsigned no_send_shutdown:1;
unsigned shutdown_without_free:1;
@@ -267,6 +268,8 @@
ngx_str_t *s);
ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
+ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool,
+ ngx_str_t *s);
ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool,
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 69ac0f7..4a8dc33 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2021,7 +2021,7 @@
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid header: \"%*s\\x%02xd...\"",
r->header_end - r->header_name_start,
r->header_name_start, *r->header_end);
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 0e93fbd..9c3f627 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -11,31 +11,33 @@
#define NGX_HTTP_MP4_TRAK_ATOM 0
#define NGX_HTTP_MP4_TKHD_ATOM 1
-#define NGX_HTTP_MP4_MDIA_ATOM 2
-#define NGX_HTTP_MP4_MDHD_ATOM 3
-#define NGX_HTTP_MP4_HDLR_ATOM 4
-#define NGX_HTTP_MP4_MINF_ATOM 5
-#define NGX_HTTP_MP4_VMHD_ATOM 6
-#define NGX_HTTP_MP4_SMHD_ATOM 7
-#define NGX_HTTP_MP4_DINF_ATOM 8
-#define NGX_HTTP_MP4_STBL_ATOM 9
-#define NGX_HTTP_MP4_STSD_ATOM 10
-#define NGX_HTTP_MP4_STTS_ATOM 11
-#define NGX_HTTP_MP4_STTS_DATA 12
-#define NGX_HTTP_MP4_STSS_ATOM 13
-#define NGX_HTTP_MP4_STSS_DATA 14
-#define NGX_HTTP_MP4_CTTS_ATOM 15
-#define NGX_HTTP_MP4_CTTS_DATA 16
-#define NGX_HTTP_MP4_STSC_ATOM 17
-#define NGX_HTTP_MP4_STSC_START 18
-#define NGX_HTTP_MP4_STSC_DATA 19
-#define NGX_HTTP_MP4_STSC_END 20
-#define NGX_HTTP_MP4_STSZ_ATOM 21
-#define NGX_HTTP_MP4_STSZ_DATA 22
-#define NGX_HTTP_MP4_STCO_ATOM 23
-#define NGX_HTTP_MP4_STCO_DATA 24
-#define NGX_HTTP_MP4_CO64_ATOM 25
-#define NGX_HTTP_MP4_CO64_DATA 26
+#define NGX_HTTP_MP4_EDTS_ATOM 2
+#define NGX_HTTP_MP4_ELST_ATOM 3
+#define NGX_HTTP_MP4_MDIA_ATOM 4
+#define NGX_HTTP_MP4_MDHD_ATOM 5
+#define NGX_HTTP_MP4_HDLR_ATOM 6
+#define NGX_HTTP_MP4_MINF_ATOM 7
+#define NGX_HTTP_MP4_VMHD_ATOM 8
+#define NGX_HTTP_MP4_SMHD_ATOM 9
+#define NGX_HTTP_MP4_DINF_ATOM 10
+#define NGX_HTTP_MP4_STBL_ATOM 11
+#define NGX_HTTP_MP4_STSD_ATOM 12
+#define NGX_HTTP_MP4_STTS_ATOM 13
+#define NGX_HTTP_MP4_STTS_DATA 14
+#define NGX_HTTP_MP4_STSS_ATOM 15
+#define NGX_HTTP_MP4_STSS_DATA 16
+#define NGX_HTTP_MP4_CTTS_ATOM 17
+#define NGX_HTTP_MP4_CTTS_DATA 18
+#define NGX_HTTP_MP4_STSC_ATOM 19
+#define NGX_HTTP_MP4_STSC_START 20
+#define NGX_HTTP_MP4_STSC_DATA 21
+#define NGX_HTTP_MP4_STSC_END 22
+#define NGX_HTTP_MP4_STSZ_ATOM 23
+#define NGX_HTTP_MP4_STSZ_DATA 24
+#define NGX_HTTP_MP4_STCO_ATOM 25
+#define NGX_HTTP_MP4_STCO_DATA 26
+#define NGX_HTTP_MP4_CO64_ATOM 27
+#define NGX_HTTP_MP4_CO64_DATA 28
#define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA
@@ -43,6 +45,7 @@
typedef struct {
size_t buffer_size;
size_t max_buffer_size;
+ ngx_flag_t start_key_frame;
} ngx_http_mp4_conf_t;
@@ -54,6 +57,25 @@
typedef struct {
+ u_char size[4];
+ u_char name[4];
+} ngx_mp4_edts_atom_t;
+
+
+typedef struct {
+ u_char size[4];
+ u_char name[4];
+ u_char version[1];
+ u_char flags[3];
+ u_char entries[4];
+ u_char duration[8];
+ u_char media_time[8];
+ u_char media_rate[2];
+ u_char reserved[2];
+} ngx_mp4_elst_atom_t;
+
+
+typedef struct {
uint32_t timescale;
uint32_t time_to_sample_entries;
uint32_t sample_to_chunk_entries;
@@ -70,6 +92,9 @@
ngx_uint_t end_chunk_samples;
uint64_t start_chunk_samples_size;
uint64_t end_chunk_samples_size;
+ uint64_t duration;
+ uint64_t prefix;
+ uint64_t movie_duration;
off_t start_offset;
off_t end_offset;
@@ -85,6 +110,8 @@
ngx_buf_t trak_atom_buf;
ngx_buf_t tkhd_atom_buf;
+ ngx_buf_t edts_atom_buf;
+ ngx_buf_t elst_atom_buf;
ngx_buf_t mdia_atom_buf;
ngx_buf_t mdhd_atom_buf;
ngx_buf_t hdlr_atom_buf;
@@ -111,6 +138,8 @@
ngx_buf_t co64_atom_buf;
ngx_buf_t co64_data_buf;
+ ngx_mp4_edts_atom_t edts_atom;
+ ngx_mp4_elst_atom_t elst_atom;
ngx_mp4_stsc_entry_t stsc_start_chunk_entry;
ngx_mp4_stsc_entry_t stsc_end_chunk_entry;
} ngx_http_mp4_trak_t;
@@ -186,6 +215,14 @@
((u_char *) (p))[6] = n3; \
((u_char *) (p))[7] = n4
+#define ngx_mp4_get_16value(p) \
+ ( ((uint16_t) ((u_char *) (p))[0] << 8) \
+ + ( ((u_char *) (p))[1]) )
+
+#define ngx_mp4_set_16value(p, n) \
+ ((u_char *) (p))[0] = (u_char) ((n) >> 8); \
+ ((u_char *) (p))[1] = (u_char) (n)
+
#define ngx_mp4_get_32value(p) \
( ((uint32_t) ((u_char *) (p))[0] << 24) \
+ ( ((u_char *) (p))[1] << 16) \
@@ -253,6 +290,8 @@
ngx_http_mp4_trak_t *trak);
static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
+static void ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak);
static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4,
@@ -267,6 +306,8 @@
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
+static void ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak);
static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4,
@@ -277,6 +318,8 @@
ngx_http_mp4_trak_t *trak);
static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak, ngx_uint_t start);
+static uint32_t ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, uint32_t start_sample);
static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
@@ -340,6 +383,13 @@
offsetof(ngx_http_mp4_conf_t, max_buffer_size),
NULL },
+ { ngx_string("mp4_start_key_frame"),
+ 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_mp4_conf_t, start_key_frame),
+ NULL },
+
ngx_null_command
};
@@ -822,10 +872,11 @@
ngx_http_mp4_update_stbl_atom(mp4, &trak[i]);
ngx_http_mp4_update_minf_atom(mp4, &trak[i]);
- trak[i].size += trak[i].mdhd_size;
+ ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]);
trak[i].size += trak[i].hdlr_size;
ngx_http_mp4_update_mdia_atom(mp4, &trak[i]);
trak[i].size += trak[i].tkhd_size;
+ ngx_http_mp4_update_edts_atom(mp4, &trak[i]);
ngx_http_mp4_update_trak_atom(mp4, &trak[i]);
mp4->moov_size += trak[i].size;
@@ -1587,6 +1638,7 @@
trak = ngx_mp4_last_trak(mp4);
trak->tkhd_size = atom_size;
+ trak->movie_duration = duration;
ngx_mp4_set_32value(tkhd_atom->size, atom_size);
@@ -1749,16 +1801,10 @@
trak = ngx_mp4_last_trak(mp4);
trak->mdhd_size = atom_size;
trak->timescale = timescale;
+ trak->duration = duration;
ngx_mp4_set_32value(mdhd_atom->size, atom_size);
- if (mdhd_atom->version[0] == 0) {
- ngx_mp4_set_32value(mdhd_atom->duration, duration);
-
- } else {
- ngx_mp4_set_64value(mdhd64_atom->duration, duration);
- }
-
atom = &trak->mdhd_atom_buf;
atom->temporary = 1;
atom->pos = atom_header;
@@ -1772,6 +1818,33 @@
}
+static void
+ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak)
+{
+ ngx_buf_t *atom;
+ ngx_mp4_mdhd_atom_t *mdhd_atom;
+ ngx_mp4_mdhd64_atom_t *mdhd64_atom;
+
+ atom = trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf;
+ if (atom == NULL) {
+ return;
+ }
+
+ mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom->pos;
+ mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom->pos;
+
+ if (mdhd_atom->version[0] == 0) {
+ ngx_mp4_set_32value(mdhd_atom->duration, trak->duration);
+
+ } else {
+ ngx_mp4_set_64value(mdhd64_atom->duration, trak->duration);
+ }
+
+ trak->size += trak->mdhd_size;
+}
+
+
static ngx_int_t
ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
{
@@ -1962,6 +2035,59 @@
static void
+ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak)
+{
+ ngx_buf_t *atom;
+ ngx_mp4_elst_atom_t *elst_atom;
+ ngx_mp4_edts_atom_t *edts_atom;
+
+ if (trak->prefix == 0) {
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 edts atom update prefix:%uL", trak->prefix);
+
+ edts_atom = &trak->edts_atom;
+ ngx_mp4_set_32value(edts_atom->size, sizeof(ngx_mp4_edts_atom_t)
+ + sizeof(ngx_mp4_elst_atom_t));
+ ngx_mp4_set_atom_name(edts_atom, 'e', 'd', 't', 's');
+
+ atom = &trak->edts_atom_buf;
+ atom->temporary = 1;
+ atom->pos = (u_char *) edts_atom;
+ atom->last = (u_char *) edts_atom + sizeof(ngx_mp4_edts_atom_t);
+
+ trak->out[NGX_HTTP_MP4_EDTS_ATOM].buf = atom;
+
+ elst_atom = &trak->elst_atom;
+ ngx_mp4_set_32value(elst_atom->size, sizeof(ngx_mp4_elst_atom_t));
+ ngx_mp4_set_atom_name(elst_atom, 'e', 'l', 's', 't');
+
+ elst_atom->version[0] = 1;
+ elst_atom->flags[0] = 0;
+ elst_atom->flags[1] = 0;
+ elst_atom->flags[2] = 0;
+
+ ngx_mp4_set_32value(elst_atom->entries, 1);
+ ngx_mp4_set_64value(elst_atom->duration, trak->movie_duration);
+ ngx_mp4_set_64value(elst_atom->media_time, trak->prefix);
+ ngx_mp4_set_16value(elst_atom->media_rate, 1);
+ ngx_mp4_set_16value(elst_atom->reserved, 0);
+
+ atom = &trak->elst_atom_buf;
+ atom->temporary = 1;
+ atom->pos = (u_char *) elst_atom;
+ atom->last = (u_char *) elst_atom + sizeof(ngx_mp4_elst_atom_t);
+
+ trak->out[NGX_HTTP_MP4_ELST_ATOM].buf = atom;
+
+ trak->size += sizeof(ngx_mp4_edts_atom_t) + sizeof(ngx_mp4_elst_atom_t);
+}
+
+
+static void
ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
@@ -2159,7 +2285,7 @@
ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak, ngx_uint_t start)
{
- uint32_t count, duration, rest;
+ uint32_t count, duration, rest, key_prefix;
uint64_t start_time;
ngx_buf_t *data;
ngx_uint_t start_sample, entries, start_sec;
@@ -2183,7 +2309,7 @@
data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
- start_time = (uint64_t) start_sec * trak->timescale / 1000;
+ start_time = (uint64_t) start_sec * trak->timescale / 1000 + trak->prefix;
entries = trak->time_to_sample_entries;
start_sample = 0;
@@ -2229,6 +2355,26 @@
found:
if (start) {
+ key_prefix = ngx_http_mp4_seek_key_frame(mp4, trak, start_sample);
+
+ start_sample -= key_prefix;
+
+ while (rest < key_prefix) {
+ trak->prefix += rest * duration;
+ key_prefix -= rest;
+
+ entry--;
+ entries++;
+
+ count = ngx_mp4_get_32value(entry->count);
+ duration = ngx_mp4_get_32value(entry->duration);
+ rest = count;
+ }
+
+ trak->prefix += key_prefix * duration;
+ trak->duration += trak->prefix;
+ rest -= key_prefix;
+
ngx_mp4_set_32value(entry->count, count - rest);
data->pos = (u_char *) entry;
trak->time_to_sample_entries = entries;
@@ -2253,6 +2399,49 @@
}
+static uint32_t
+ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak,
+ uint32_t start_sample)
+{
+ uint32_t key_prefix, sample, *entry, *end;
+ ngx_buf_t *data;
+ ngx_http_mp4_conf_t *conf;
+
+ conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
+ if (!conf->start_key_frame) {
+ return 0;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf;
+ if (data == NULL) {
+ return 0;
+ }
+
+ entry = (uint32_t *) data->pos;
+ end = (uint32_t *) data->last;
+
+ /* sync samples starts from 1 */
+ start_sample++;
+
+ key_prefix = 0;
+
+ while (entry < end) {
+ sample = ngx_mp4_get_32value(entry);
+ if (sample > start_sample) {
+ break;
+ }
+
+ key_prefix = start_sample - sample;
+ entry++;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 key frame prefix:%uD", key_prefix);
+
+ return key_prefix;
+}
+
+
typedef struct {
u_char size[4];
u_char name[4];
@@ -3590,6 +3779,7 @@
conf->buffer_size = NGX_CONF_UNSET_SIZE;
conf->max_buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->start_key_frame = NGX_CONF_UNSET;
return conf;
}
@@ -3604,6 +3794,7 @@
ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024);
ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size,
10 * 1024 * 1024);
+ ngx_conf_merge_value(conf->start_key_frame, prev->start_key_frame, 0);
return NGX_CONF_OK;
}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index a8554a4..cf91525 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2028,7 +2028,7 @@
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid header: \"%*s\\x%02xd...\"",
r->header_end - r->header_name_start,
r->header_name_start, *r->header_end);
@@ -2344,6 +2344,7 @@
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
+ u->keepalive = 0;
return NGX_OK;
}
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 570713d..e5d31ae 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -1142,7 +1142,7 @@
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid header: \"%*s\\x%02xd...\"",
r->header_end - r->header_name_start,
r->header_name_start, *r->header_end);
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index e67dcde..4bfcbd8 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -17,6 +17,8 @@
#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5"
#define NGX_DEFAULT_ECDH_CURVE "auto"
+#define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9"
+
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
@@ -24,11 +26,6 @@
const unsigned char *in, unsigned int inlen, void *arg);
#endif
-#ifdef TLSEXT_TYPE_next_proto_neg
-static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn,
- const unsigned char **out, unsigned int *outlen, void *arg);
-#endif
-
static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r,
@@ -361,6 +358,9 @@
{ ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 },
+ { ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable,
+ (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
{ ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
@@ -442,22 +442,20 @@
hc = c->data;
if (hc->addr_conf->http2) {
- srv =
- (unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
- srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
-
+ srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS;
+ srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1;
} else
#endif
{
- srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE;
- srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1;
+ srv = (unsigned char *) NGX_HTTP_ALPN_PROTOS;
+ srvlen = sizeof(NGX_HTTP_ALPN_PROTOS) - 1;
}
if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen,
in, inlen)
!= OPENSSL_NPN_NEGOTIATED)
{
- return SSL_TLSEXT_ERR_NOACK;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
@@ -469,44 +467,6 @@
#endif
-#ifdef TLSEXT_TYPE_next_proto_neg
-
-static int
-ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn,
- const unsigned char **out, unsigned int *outlen, void *arg)
-{
-#if (NGX_HTTP_V2 || NGX_DEBUG)
- ngx_connection_t *c;
-
- c = ngx_ssl_get_connection(ssl_conn);
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised");
-#endif
-
-#if (NGX_HTTP_V2)
- {
- ngx_http_connection_t *hc;
-
- hc = c->data;
-
- if (hc->addr_conf->http2) {
- *out =
- (unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
- *outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
-
- return SSL_TLSEXT_ERR_OK;
- }
- }
-#endif
-
- *out = (unsigned char *) NGX_HTTP_NPN_ADVERTISE;
- *outlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1;
-
- return SSL_TLSEXT_ERR_OK;
-}
-
-#endif
-
-
static ngx_int_t
ngx_http_ssl_static_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
@@ -805,11 +765,6 @@
SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL);
#endif
-#ifdef TLSEXT_TYPE_next_proto_neg
- SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx,
- ngx_http_ssl_npn_advertised, NULL);
-#endif
-
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 4f9c349..d46741a 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1363,7 +1363,7 @@
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid header: \"%*s\\x%02xd...\"",
r->header_end - r->header_name_start,
r->header_name_start, *r->header_end);
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index 3d5c4ac..73c08d5 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1338,13 +1338,12 @@
}
#if (NGX_HTTP_V2 && NGX_HTTP_SSL \
- && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \
- && !defined TLSEXT_TYPE_next_proto_neg)
+ && !defined TLSEXT_TYPE_application_layer_protocol_negotiation)
if (lsopt->http2 && lsopt->ssl) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"nginx was built with OpenSSL that lacks ALPN "
- "and NPN support, HTTP/2 is not enabled for %V",
+ "support, HTTP/2 is not enabled for %V",
&lsopt->addr_text);
}
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 127a35c..2e9954e 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -3720,7 +3720,7 @@
ngx_conf_merge_value(conf->internal, prev->internal, 0);
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
ngx_conf_merge_size_value(conf->sendfile_max_chunk,
- prev->sendfile_max_chunk, 0);
+ prev->sendfile_max_chunk, 2 * 1024 * 1024);
ngx_conf_merge_size_value(conf->subrequest_output_buffer_size,
prev->subrequest_output_buffer_size,
(size_t) ngx_pagesize);
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index c9a6109..74098c2 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -502,8 +502,8 @@
ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,
- ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr,
- ngx_http_post_subrequest_t *psr, ngx_uint_t flags);
+ ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
+ ngx_http_post_subrequest_t *ps, ngx_uint_t flags);
ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
ngx_str_t *uri, ngx_str_t *args);
ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 9cf371d..4c5bfbf 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -607,7 +607,7 @@
}
#if (NGX_HTTP_SSL)
- if (c->ssl) {
+ if (c->ssl && !c->ssl->sendfile) {
r->main_filter_need_in_memory = 1;
}
#endif
@@ -806,8 +806,7 @@
c->ssl->no_wait_shutdown = 1;
#if (NGX_HTTP_V2 \
- && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \
- || defined TLSEXT_TYPE_next_proto_neg))
+ && defined TLSEXT_TYPE_application_layer_protocol_negotiation)
{
unsigned int len;
const unsigned char *data;
@@ -817,19 +816,8 @@
if (hc->addr_conf->http2) {
-#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
SSL_get0_alpn_selected(c->ssl->connection, &data, &len);
-#ifdef TLSEXT_TYPE_next_proto_neg
- if (len == 0) {
- SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
- }
-#endif
-
-#else /* TLSEXT_TYPE_next_proto_neg */
- SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
-#endif
-
if (len == 2 && data[0] == 'h' && data[1] == '2') {
ngx_http_v2_init(c->read);
return;
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 89a4c74..ad3549f 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -1309,7 +1309,7 @@
if (rb->rest > 0) {
- if (rb->buf && rb->buf->last == rb->buf->end
+ if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end
&& ngx_http_write_request_body(r) != NGX_OK)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 2e6a3b1..dd3685d 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1511,8 +1511,9 @@
static void
ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
- ngx_int_t rc;
- ngx_connection_t *c;
+ ngx_int_t rc;
+ ngx_connection_t *c;
+ ngx_http_core_loc_conf_t *clcf;
r->connection->log->action = "connecting to upstream";
@@ -1599,10 +1600,12 @@
/* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
u->writer.out = NULL;
u->writer.last = &u->writer.out;
u->writer.connection = c;
- u->writer.limit = 0;
+ u->writer.limit = clcf->sendfile_max_chunk;
if (u->request_sent) {
if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
@@ -1683,9 +1686,6 @@
return;
}
- c->sendfile = 0;
- u->output.sendfile = 0;
-
if (u->conf->ssl_server_name || u->conf->ssl_verify) {
if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
@@ -1791,6 +1791,11 @@
}
}
+ if (!c->ssl->sendfile) {
+ c->sendfile = 0;
+ u->output.sendfile = 0;
+ }
+
c->write->handler = ngx_http_upstream_handler;
c->read->handler = ngx_http_upstream_handler;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 7a0a99a..410e2bd 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -1179,6 +1179,10 @@
v->no_cacheable = 0;
v->not_found = 0;
+ } else if (r->headers_in.chunked) {
+ v->not_found = 1;
+ v->no_cacheable = 1;
+
} else {
v->not_found = 1;
}
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index 6a5d957..932f26d 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -321,18 +321,13 @@
delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate);
if (delay > 0) {
- limit = 0;
c->write->delayed = 1;
ngx_add_timer(c->write, delay);
}
}
- if (limit
- && c->write->ready
- && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))
- {
- c->write->delayed = 1;
- ngx_add_timer(c->write, 1);
+ if (chain && c->write->ready && !c->write->delayed) {
+ ngx_post_event(c->write, &ngx_posted_next_events);
}
for (cl = r->out; cl && cl != chain; /* void */) {
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index 3492297..0eceae3 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -13,8 +13,7 @@
#include <ngx_http.h>
-#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2"
-#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE
+#define NGX_HTTP_V2_ALPN_PROTO "\x02h2"
#define NGX_HTTP_V2_STATE_BUFFER_SIZE 16
diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h
index 21178c3..e0c62b7 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -324,6 +324,7 @@
struct ngx_mail_protocol_s {
ngx_str_t name;
+ ngx_str_t alpn;
in_port_t port[4];
ngx_uint_t type;
diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c
index 1f187fd..02c684c 100644
--- a/src/mail/ngx_mail_imap_module.c
+++ b/src/mail/ngx_mail_imap_module.c
@@ -46,6 +46,7 @@
static ngx_mail_protocol_t ngx_mail_imap_protocol = {
ngx_string("imap"),
+ ngx_string("\x04imap"),
{ 143, 993, 0, 0 },
NGX_MAIL_IMAP_PROTOCOL,
diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c
index a673070..a257b5a 100644
--- a/src/mail/ngx_mail_pop3_module.c
+++ b/src/mail/ngx_mail_pop3_module.c
@@ -46,6 +46,7 @@
static ngx_mail_protocol_t ngx_mail_pop3_protocol = {
ngx_string("pop3"),
+ ngx_string("\x04pop3"),
{ 110, 995, 0, 0 },
NGX_MAIL_POP3_PROTOCOL,
diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c
index 3b5a2d8..0e05fdc 100644
--- a/src/mail/ngx_mail_smtp_module.c
+++ b/src/mail/ngx_mail_smtp_module.c
@@ -39,6 +39,7 @@
static ngx_mail_protocol_t ngx_mail_smtp_protocol = {
ngx_string("smtp"),
+ ngx_string("\x04smtp"),
{ 25, 465, 587, 0 },
NGX_MAIL_SMTP_PROTOCOL,
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index 09cc425..2a1043e 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -14,6 +14,12 @@
#define NGX_DEFAULT_ECDH_CURVE "auto"
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
+ const unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg);
+#endif
+
static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf);
static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
@@ -244,6 +250,54 @@
static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL");
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+
+static int
+ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in, unsigned int inlen,
+ void *arg)
+{
+ unsigned int srvlen;
+ unsigned char *srv;
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
+ ngx_mail_core_srv_conf_t *cscf;
+#if (NGX_DEBUG)
+ unsigned int i;
+#endif
+
+ c = ngx_ssl_get_connection(ssl_conn);
+ s = c->data;
+
+#if (NGX_DEBUG)
+ for (i = 0; i < inlen; i += in[i] + 1) {
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "SSL ALPN supported by client: %*s",
+ (size_t) in[i], &in[i + 1]);
+ }
+#endif
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+ srv = cscf->protocol->alpn.data;
+ srvlen = cscf->protocol->alpn.len;
+
+ if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen,
+ in, inlen)
+ != OPENSSL_NPN_NEGOTIATED)
+ {
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "SSL ALPN selected: %*s", (size_t) *outlen, *out);
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+#endif
+
+
static void *
ngx_mail_ssl_create_conf(ngx_conf_t *cf)
{
@@ -394,6 +448,10 @@
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = &conf->ssl;
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+ SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL);
+#endif
+
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c
index 5695839..91e7f1d 100644
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -38,6 +38,9 @@
* On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter
* more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL,
* so we limit it to 2G-1 bytes.
+ *
+ * On Linux 2.6.16 and later, sendfile() silently limits the count parameter
+ * to 2G minus the page size, even on 64-bit platforms.
*/
#define NGX_SENDFILE_MAXSIZE 2147483647L
@@ -216,7 +219,6 @@
*/
send = prev_send + sent;
- continue;
}
if (send >= limit || in == NULL) {
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 1275cf2..934e7d8 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -31,6 +31,7 @@
ngx_uint_t next_upstream_tries;
ngx_flag_t next_upstream;
ngx_flag_t proxy_protocol;
+ ngx_flag_t half_close;
ngx_stream_upstream_local_t *local;
ngx_flag_t socket_keepalive;
@@ -245,6 +246,13 @@
offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol),
NULL },
+ { ngx_string("proxy_half_close"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_proxy_srv_conf_t, half_close),
+ NULL },
+
#if (NGX_STREAM_SSL)
{ ngx_string("proxy_ssl"),
@@ -1755,6 +1763,24 @@
}
if (dst) {
+
+ if (dst->type == SOCK_STREAM && pscf->half_close
+ && src->read->eof && !u->half_closed && !dst->buffered)
+ {
+ if (ngx_shutdown_socket(dst->fd, NGX_WRITE_SHUTDOWN) == -1) {
+ ngx_connection_error(c, ngx_socket_errno,
+ ngx_shutdown_socket_n " failed");
+
+ ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ u->half_closed = 1;
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+ "stream proxy %s socket shutdown",
+ from_upstream ? "client" : "upstream");
+ }
+
if (ngx_handle_write_event(dst->write, 0) != NGX_OK) {
ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
return;
@@ -1833,6 +1859,13 @@
return NGX_DECLINED;
}
+ if (pscf->half_close) {
+ /* avoid closing live connections until both read ends get EOF */
+ if (!(c->read->eof && pc->read->eof && !c->buffered && !pc->buffered)) {
+ return NGX_DECLINED;
+ }
+ }
+
handler = c->log->handler;
c->log->handler = NULL;
@@ -2052,6 +2085,7 @@
conf->proxy_protocol = NGX_CONF_UNSET;
conf->local = NGX_CONF_UNSET_PTR;
conf->socket_keepalive = NGX_CONF_UNSET;
+ conf->half_close = NGX_CONF_UNSET;
#if (NGX_STREAM_SSL)
conf->ssl_enable = NGX_CONF_UNSET;
@@ -2110,6 +2144,8 @@
ngx_conf_merge_value(conf->socket_keepalive,
prev->socket_keepalive, 0);
+ ngx_conf_merge_value(conf->half_close, prev->half_close, 0);
+
#if (NGX_STREAM_SSL)
ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0);
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index b735000..530fe8b 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -23,7 +23,13 @@
ngx_connection_t *c);
static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c);
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
+static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad,
+ void *arg);
+#endif
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+static int ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
+ const unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg);
#endif
#ifdef SSL_R_CERT_CB_ERROR
static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
@@ -45,6 +51,8 @@
void *conf);
static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post,
void *data);
@@ -211,6 +219,13 @@
offsetof(ngx_stream_ssl_conf_t, conf_commands),
&ngx_stream_ssl_conf_command_post },
+ { ngx_string("ssl_alpn"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
+ ngx_stream_ssl_alpn,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
ngx_null_command
};
@@ -266,6 +281,9 @@
{ ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable,
(uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 },
+ { ngx_string("ssl_alpn_protocol"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
{ ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable,
(uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 },
@@ -434,7 +452,7 @@
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-int
+static int
ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
{
return SSL_TLSEXT_ERR_OK;
@@ -443,9 +461,49 @@
#endif
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+
+static int
+ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in, unsigned int inlen,
+ void *arg)
+{
+ ngx_str_t *alpn;
+#if (NGX_DEBUG)
+ unsigned int i;
+ ngx_connection_t *c;
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ for (i = 0; i < inlen; i += in[i] + 1) {
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL ALPN supported by client: %*s",
+ (size_t) in[i], &in[i + 1]);
+ }
+
+#endif
+
+ alpn = arg;
+
+ if (SSL_select_next_proto((unsigned char **) out, outlen, alpn->data,
+ alpn->len, in, inlen)
+ != OPENSSL_NPN_NEGOTIATED)
+ {
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL ALPN selected: %*s", (size_t) *outlen, *out);
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+#endif
+
+
#ifdef SSL_R_CERT_CB_ERROR
-int
+static int
ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
{
ngx_str_t cert, key;
@@ -602,6 +660,7 @@
* scf->client_certificate = { 0, NULL };
* scf->trusted_certificate = { 0, NULL };
* scf->crl = { 0, NULL };
+ * scf->alpn = { 0, NULL };
* scf->ciphers = { 0, NULL };
* scf->shm_zone = NULL;
*/
@@ -660,6 +719,7 @@
ngx_conf_merge_str_value(conf->trusted_certificate,
prev->trusted_certificate, "");
ngx_conf_merge_str_value(conf->crl, prev->crl, "");
+ ngx_conf_merge_str_value(conf->alpn, prev->alpn, "");
ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
NGX_DEFAULT_ECDH_CURVE);
@@ -720,6 +780,13 @@
ngx_stream_ssl_servername);
#endif
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+ if (conf->alpn.len) {
+ SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_stream_ssl_alpn_select,
+ &conf->alpn);
+ }
+#endif
+
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
@@ -1057,6 +1124,60 @@
static char *
+ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+
+ ngx_stream_ssl_conf_t *scf = conf;
+
+ u_char *p;
+ size_t len;
+ ngx_str_t *value;
+ ngx_uint_t i;
+
+ if (scf->alpn.len) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ len = 0;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (value[i].len > 255) {
+ return "protocol too long";
+ }
+
+ len += value[i].len + 1;
+ }
+
+ scf->alpn.data = ngx_pnalloc(cf->pool, len);
+ if (scf->alpn.data == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ p = scf->alpn.data;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+ *p++ = value[i].len;
+ p = ngx_cpymem(p, value[i].data, value[i].len);
+ }
+
+ scf->alpn.len = len;
+
+ return NGX_CONF_OK;
+
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the \"ssl_alpn\" directive requires OpenSSL "
+ "with ALPN support");
+ return NGX_CONF_ERROR;
+#endif
+}
+
+
+static char *
ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)
{
#ifndef SSL_CONF_FLAG_FILE
diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h
index c6e24be..e7c825e 100644
--- a/src/stream/ngx_stream_ssl_module.h
+++ b/src/stream/ngx_stream_ssl_module.h
@@ -42,6 +42,7 @@
ngx_str_t client_certificate;
ngx_str_t trusted_certificate;
ngx_str_t crl;
+ ngx_str_t alpn;
ngx_str_t ciphers;
diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h
index 7aaf628..dfaf0f6 100644
--- a/src/stream/ngx_stream_upstream.h
+++ b/src/stream/ngx_stream_upstream.h
@@ -142,6 +142,7 @@
ngx_stream_upstream_state_t *state;
unsigned connected:1;
unsigned proxy_protocol:1;
+ unsigned half_closed:1;
} ngx_stream_upstream_t;