aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Kandaurov <pluknet@nginx.com>2021-11-03 11:22:07 +0300
committerSergey Kandaurov <pluknet@nginx.com>2021-11-03 11:22:07 +0300
commitbbd05ae252bce1907173d13c6e48d1bed71cd9ea (patch)
tree6bca56a91f1d0a0b1c3ad4ac0d3c3ba2b4122468 /src
parent8f8cb92e9229d75ea5816f35c6b4bfdfb253a486 (diff)
parent3334585539168947650a37d74dd32973ab451d70 (diff)
downloadnginx-bbd05ae252bce1907173d13c6e48d1bed71cd9ea.tar.gz
nginx-bbd05ae252bce1907173d13c6e48d1bed71cd9ea.zip
Merged with the default branch.
Diffstat (limited to 'src')
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_buf.c8
-rw-r--r--src/core/ngx_hash.c4
-rw-r--r--src/core/ngx_output_chain.c4
-rw-r--r--src/core/ngx_times.c4
-rw-r--r--src/event/ngx_event_openssl.c244
-rw-r--r--src/event/ngx_event_openssl.h3
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c2
-rw-r--r--src/http/modules/ngx_http_mp4_module.c261
-rw-r--r--src/http/modules/ngx_http_proxy_module.c3
-rw-r--r--src/http/modules/ngx_http_scgi_module.c2
-rw-r--r--src/http/modules/ngx_http_ssl_module.c65
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c2
-rw-r--r--src/http/ngx_http.c5
-rw-r--r--src/http/ngx_http_core_module.c2
-rw-r--r--src/http/ngx_http_core_module.h4
-rw-r--r--src/http/ngx_http_request.c16
-rw-r--r--src/http/ngx_http_request_body.c2
-rw-r--r--src/http/ngx_http_upstream.c17
-rw-r--r--src/http/ngx_http_variables.c4
-rw-r--r--src/http/ngx_http_write_filter_module.c9
-rw-r--r--src/http/v2/ngx_http_v2.h3
-rw-r--r--src/mail/ngx_mail.h1
-rw-r--r--src/mail/ngx_mail_imap_module.c1
-rw-r--r--src/mail/ngx_mail_pop3_module.c1
-rw-r--r--src/mail/ngx_mail_smtp_module.c1
-rw-r--r--src/mail/ngx_mail_ssl_module.c58
-rw-r--r--src/os/unix/ngx_linux_sendfile_chain.c4
-rw-r--r--src/stream/ngx_stream_proxy_module.c36
-rw-r--r--src/stream/ngx_stream_ssl_module.c127
-rw-r--r--src/stream/ngx_stream_ssl_module.h1
-rw-r--r--src/stream/ngx_stream_upstream.h1
32 files changed, 748 insertions, 151 deletions
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 6b134945e..bc4af23af 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1021003
-#define NGINX_VERSION "1.21.3"
+#define nginx_version 1021004
+#define NGINX_VERSION "1.21.4"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c
index c3783c446..811f24d96 100644
--- a/src/core/ngx_buf.c
+++ b/src/core/ngx_buf.c
@@ -203,16 +203,16 @@ ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
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 d9c157c1d..8215c2717 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -274,6 +274,10 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
}
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 5c3dbe872..fd4603b19 100644
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -803,6 +803,10 @@ ngx_chain_writer(void *data, ngx_chain_t *in)
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 7964b008f..16788c98c 100644
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -200,10 +200,6 @@ ngx_monotonic_time(time_t sec, ngx_uint_t msec)
#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 37924685e..fef4fe50c 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -47,6 +47,8 @@ static void ngx_ssl_write_handler(ngx_event_t *wev);
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,
@@ -1764,6 +1766,16 @@ ngx_ssl_handshake(ngx_connection_t *c)
#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) {
@@ -1899,6 +1911,16 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
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) {
@@ -2502,10 +2524,11 @@ ngx_ssl_write_handler(ngx_event_t *wev)
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) {
@@ -2579,6 +2602,11 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
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) {
@@ -2610,8 +2638,35 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
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;
}
@@ -2636,7 +2691,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
buf->pos = buf->start;
buf->last = buf->start;
- if (in == NULL || send == limit) {
+ if (in == NULL || send >= limit) {
break;
}
}
@@ -2767,7 +2822,7 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
#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;
@@ -2882,6 +2937,150 @@ 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)
+{
+#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)
{
@@ -3141,6 +3340,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
#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 */
@@ -4706,6 +4908,36 @@ 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)
+{
+#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 92a5c1fed..97beae7c4 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -117,6 +117,7 @@ struct ngx_ssl_connection_s {
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;
@@ -273,6 +274,8 @@ ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool,
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 69ac0f72c..4a8dc338e 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2021,7 +2021,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
/* 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 0e93fbd09..9c3f627fe 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 {
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 @@ typedef struct {
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 @@ typedef struct {
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 @@ typedef struct {
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 @@ typedef struct {
((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 @@ static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4,
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 @@ static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4,
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 @@ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
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 @@ static ngx_command_t ngx_http_mp4_commands[] = {
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_process(ngx_http_mp4_file_t *mp4)
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 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
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 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
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 @@ 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)
+{
+ 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 @@ 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)
+{
+ 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 @@ 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)
{
- 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 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
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 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
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 @@ found:
}
+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 @@ ngx_http_mp4_create_conf(ngx_conf_t *cf)
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_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child)
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 084462746..7c4061c02 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2021,7 +2021,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
/* 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);
@@ -2337,6 +2337,7 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
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 570713df9..e5d31ae91 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -1142,7 +1142,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r)
/* 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 dbb5905df..f2a85f12e 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -17,7 +17,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c,
#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5"
#define NGX_DEFAULT_ECDH_CURVE "auto"
-#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1"
+#define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9"
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
@@ -26,11 +26,6 @@ static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
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,
@@ -363,6 +358,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
{ 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 },
@@ -449,10 +447,8 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
#if (NGX_HTTP_V2)
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
#if (NGX_HTTP_QUIC)
@@ -484,15 +480,15 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
} 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,
@@ -504,44 +500,6 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
#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)
@@ -825,11 +783,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
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 4f9c349c2..d46741a00 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1363,7 +1363,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
/* 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 c9aa3761b..908e88103 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1360,13 +1360,12 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
}
#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 c19020dfd..19bc75136 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -3720,7 +3720,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
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 ae5e518b7..148696641 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -508,8 +508,8 @@ ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r);
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 e37ef8024..88516cb4d 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -617,7 +617,7 @@ ngx_http_alloc_request(ngx_connection_t *c)
}
#if (NGX_HTTP_SSL)
- if (c->ssl) {
+ if (c->ssl && !c->ssl->sendfile) {
r->main_filter_need_in_memory = 1;
}
#endif
@@ -816,8 +816,7 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
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;
@@ -827,19 +826,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
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 e4d9ff5be..d2bec7820 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -1330,7 +1330,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
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 7ca75d3b7..d27a53ea4 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1531,8 +1531,9 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
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";
@@ -1619,10 +1620,12 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
/* 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) {
@@ -1703,9 +1706,6 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
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,
@@ -1811,6 +1811,11 @@ ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u,
}
}
+ 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 c25d80ccf..942dacd70 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -1179,6 +1179,10 @@ ngx_http_variable_content_length(ngx_http_request_t *r,
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 2a4996251..8ef19b645 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -325,18 +325,13 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
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 65fc65812..70ee287ae 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 21178c3e2..e0c62b7ab 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -324,6 +324,7 @@ typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s);
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 1f187fdee..02c684cd4 100644
--- a/src/mail/ngx_mail_imap_module.c
+++ b/src/mail/ngx_mail_imap_module.c
@@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_imap_auth_methods_names[] = {
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 a67307073..a257b5a70 100644
--- a/src/mail/ngx_mail_pop3_module.c
+++ b/src/mail/ngx_mail_pop3_module.c
@@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_pop3_auth_methods_names[] = {
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 3b5a2d8f3..0e05fdc03 100644
--- a/src/mail/ngx_mail_smtp_module.c
+++ b/src/mail/ngx_mail_smtp_module.c
@@ -39,6 +39,7 @@ static ngx_str_t ngx_mail_smtp_auth_methods_names[] = {
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 09cc425d6..2a1043e66 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 @@ ngx_module_t ngx_mail_ssl_module = {
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 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
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 5695839b0..91e7f1d93 100644
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -38,6 +38,9 @@ static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log);
* 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 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
*/
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 1275cf225..934e7d8f2 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -31,6 +31,7 @@ typedef struct {
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 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
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 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream,
}
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 @@ ngx_stream_proxy_test_finalize(ngx_stream_session_t *s,
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 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf)
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_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
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 74a727797..7fb363a5c 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -23,7 +23,13 @@ static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl,
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 @@ static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
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 @@ static ngx_command_t ngx_stream_ssl_commands[] = {
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 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = {
{ 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 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c)
#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 @@ 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)
+{
+ 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 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf)
* 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_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
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_merge_conf(ngx_conf_t *cf, void *parent, void *child)
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 @@ invalid:
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 c6e24bef3..e7c825e9b 100644
--- a/src/stream/ngx_stream_ssl_module.h
+++ b/src/stream/ngx_stream_ssl_module.h
@@ -42,6 +42,7 @@ typedef struct {
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 9857e0b75..f5617794f 100644
--- a/src/stream/ngx_stream_upstream.h
+++ b/src/stream/ngx_stream_upstream.h
@@ -142,6 +142,7 @@ typedef struct {
ngx_stream_upstream_state_t *state;
unsigned connected:1;
unsigned proxy_protocol:1;
+ unsigned half_closed:1;
} ngx_stream_upstream_t;