summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornginx <nginx@nginx.org>2014-04-08 14:31:42 +0000
committerJon Kolb <kolbyjack@gmail.com>2014-04-08 14:31:42 +0000
commitd2ce3a1fcb5e0f7f27d22293832ced78b2cc744d (patch)
tree7bf028a91c7a083809ac298947ce157e02e884a4
parentc6e7bb24dc541324343df6e734a44aa8e75b446f (diff)
downloadnginx-1.5.tar.gz
Changes with nginx 1.5.13 08 Apr 2014v1.5.13nginx-1.5
*) Change: improved hash table handling; the default values of the "variables_hash_max_size" and "types_hash_bucket_size" were changed to 1024 and 64 respectively. *) Feature: the ngx_http_mp4_module now supports the "end" argument. *) Feature: byte ranges support in the ngx_http_mp4_module and while saving responses to cache. *) Bugfix: alerts "ngx_slab_alloc() failed: no memory" no longer logged when using shared memory in the "ssl_session_cache" directive and in the ngx_http_limit_req_module. *) Bugfix: the "underscores_in_headers" directive did not allow underscore as a first character of a header. Thanks to Piotr Sikora. *) Bugfix: cache manager might hog CPU on exit in nginx/Windows. *) Bugfix: nginx/Windows terminated abnormally if the "ssl_session_cache" directive was used with the "shared" parameter. *) Bugfix: in the ngx_http_spdy_module.
-rw-r--r--CHANGES27
-rw-r--r--CHANGES.ru28
-rw-r--r--auto/cc/msvc2
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_hash.c15
-rw-r--r--src/core/ngx_slab.c6
-rw-r--r--src/core/ngx_slab.h2
-rw-r--r--src/event/ngx_event_openssl.c10
-rw-r--r--src/http/modules/ngx_http_limit_req_module.c4
-rw-r--r--src/http/modules/ngx_http_mp4_module.c754
-rw-r--r--src/http/modules/ngx_http_range_filter_module.c5
-rw-r--r--src/http/ngx_http_core_module.c22
-rw-r--r--src/http/ngx_http_parse.c13
-rw-r--r--src/http/ngx_http_request.h1
-rw-r--r--src/http/ngx_http_spdy.c83
-rw-r--r--src/http/ngx_http_spdy_filter_module.c75
-rw-r--r--src/http/ngx_http_spdy_module.c4
-rw-r--r--src/http/ngx_http_upstream.c5
-rw-r--r--src/mail/ngx_mail_handler.c7
-rw-r--r--src/os/unix/ngx_files.h2
20 files changed, 815 insertions, 254 deletions
diff --git a/CHANGES b/CHANGES
index a38f93754..215cb5501 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,31 @@
+Changes with nginx 1.5.13 08 Apr 2014
+
+ *) Change: improved hash table handling; the default values of the
+ "variables_hash_max_size" and "types_hash_bucket_size" were changed
+ to 1024 and 64 respectively.
+
+ *) Feature: the ngx_http_mp4_module now supports the "end" argument.
+
+ *) Feature: byte ranges support in the ngx_http_mp4_module and while
+ saving responses to cache.
+
+ *) Bugfix: alerts "ngx_slab_alloc() failed: no memory" no longer logged
+ when using shared memory in the "ssl_session_cache" directive and in
+ the ngx_http_limit_req_module.
+
+ *) Bugfix: the "underscores_in_headers" directive did not allow
+ underscore as a first character of a header.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: cache manager might hog CPU on exit in nginx/Windows.
+
+ *) Bugfix: nginx/Windows terminated abnormally if the
+ "ssl_session_cache" directive was used with the "shared" parameter.
+
+ *) Bugfix: in the ngx_http_spdy_module.
+
+
Changes with nginx 1.5.12 18 Mar 2014
*) Security: a heap memory buffer overflow might occur in a worker
diff --git a/CHANGES.ru b/CHANGES.ru
index 139934be0..6b6f14e08 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,32 @@
+Изменения в nginx 1.5.13 08.04.2014
+
+ *) Изменение: улучшена обработка хэш-таблиц; в директивах
+ variables_hash_max_size и types_hash_bucket_size значения по
+ умолчанию изменены на 1024 и 64 соответственно.
+
+ *) Добавление: модуль ngx_http_mp4_module теперь понимает аргумент end.
+
+ *) Добавление: поддержка byte ranges модулем ngx_http_mp4_module и при
+ сохранении ответов в кэш.
+
+ *) Исправление: теперь nginx не пишет в лог сообщения "ngx_slab_alloc()
+ failed: no memory" при использовании разделяемой памяти в
+ ssl_session_cache и в модуле ngx_http_limit_req_module.
+
+ *) Исправление: директива underscores_in_headers не разрешала
+ подчёркивание в первом символе заголовка.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: cache manager мог нагружать процессор при выходе в
+ nginx/Windows.
+
+ *) Исправление: при использовании ssl_session_cache с параметром shared
+ рабочий процесс nginx/Windows завершался аварийно.
+
+ *) Исправление: в модуле ngx_http_spdy_module.
+
+
Изменения в nginx 1.5.12 18.03.2014
*) Безопасность: при обработке специально созданного запроса модулем
diff --git a/auto/cc/msvc b/auto/cc/msvc
index 6cb8b3d58..393ba3214 100644
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -106,7 +106,7 @@ fi
# precompiled headers
CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
-CORE_LINK="$NGX_OBJS/ngx_pch.obj"
+CORE_LINK="$CORE_LINK $NGX_OBJS/ngx_pch.obj"
NGX_PCH="$NGX_OBJS/ngx_config.pch"
NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch"
NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch"
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 17dda595e..dc88100b9 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1005012
-#define NGINX_VERSION "1.5.12"
+#define nginx_version 1005013
+#define NGINX_VERSION "1.5.13"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index b53294502..c7bfed709 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -282,7 +282,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
start = hinit->max_size - 1000;
}
- for (size = start; size < hinit->max_size; size++) {
+ for (size = start; size <= hinit->max_size; size++) {
ngx_memzero(test, size * sizeof(u_short));
@@ -312,15 +312,12 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
continue;
}
- ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
- "could not build the %s, you should increase "
- "either %s_max_size: %i or %s_bucket_size: %i",
+ ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
+ "could not build optimal %s, you should increase "
+ "either %s_max_size: %i or %s_bucket_size: %i; "
+ "ignoring %s_bucket_size",
hinit->name, hinit->name, hinit->max_size,
- hinit->name, hinit->bucket_size);
-
- ngx_free(test);
-
- return NGX_ERROR;
+ hinit->name, hinit->bucket_size, hinit->name);
found:
diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c
index 6d18abb72..be7927ce0 100644
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -129,6 +129,7 @@ ngx_slab_init(ngx_slab_pool_t *pool)
pool->pages->slab = pages;
}
+ pool->log_nomem = 1;
pool->log_ctx = &pool->zero;
pool->zero = '\0';
}
@@ -658,7 +659,10 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
}
}
- ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory");
+ if (pool->log_nomem) {
+ ngx_slab_error(pool, NGX_LOG_CRIT,
+ "ngx_slab_alloc() failed: no memory");
+ }
return NULL;
}
diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h
index c5e420bfa..5735e3bb3 100644
--- a/src/core/ngx_slab.h
+++ b/src/core/ngx_slab.h
@@ -39,6 +39,8 @@ typedef struct {
u_char *log_ctx;
u_char zero;
+ unsigned log_nomem:1;
+
void *data;
void *addr;
} ngx_slab_pool_t;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 28e7aa509..d8dd3d358 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1804,13 +1804,13 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
return NGX_OK;
}
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
if (shm_zone->shm.exists) {
- shm_zone->data = data;
+ shm_zone->data = shpool->data;
return NGX_OK;
}
- shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
-
cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
if (cache == NULL) {
return NGX_ERROR;
@@ -1834,6 +1834,8 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
&shm_zone->shm.name);
+ shpool->log_nomem = 0;
+
return NGX_OK;
}
@@ -1986,7 +1988,7 @@ failed:
ngx_shmtx_unlock(&shpool->mutex);
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "could not add new SSL session to the session cache");
+ "could not allocate new session%s", shpool->log_ctx);
return 0;
}
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index d4c1ff6c3..74f7fdaa7 100644
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -451,6 +451,8 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash,
node = ngx_slab_alloc_locked(ctx->shpool, size);
if (node == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "could not allocate node%s", ctx->shpool->log_ctx);
return NGX_ERROR;
}
}
@@ -674,6 +676,8 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)
ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z",
&shm_zone->shm.name);
+ ctx->shpool->log_nomem = 0;
+
return NGX_OK;
}
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 426a0b97f..8f439ba92 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -27,14 +27,15 @@
#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_CHUNK 18
+#define NGX_HTTP_MP4_STSC_START 18
#define NGX_HTTP_MP4_STSC_DATA 19
-#define NGX_HTTP_MP4_STSZ_ATOM 20
-#define NGX_HTTP_MP4_STSZ_DATA 21
-#define NGX_HTTP_MP4_STCO_ATOM 22
-#define NGX_HTTP_MP4_STCO_DATA 23
-#define NGX_HTTP_MP4_CO64_ATOM 24
-#define NGX_HTTP_MP4_CO64_DATA 25
+#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_LAST_ATOM NGX_HTTP_MP4_CO64_DATA
@@ -62,10 +63,15 @@ typedef struct {
uint32_t chunks;
ngx_uint_t start_sample;
+ ngx_uint_t end_sample;
ngx_uint_t start_chunk;
- ngx_uint_t chunk_samples;
- uint64_t chunk_samples_size;
+ ngx_uint_t end_chunk;
+ ngx_uint_t start_chunk_samples;
+ ngx_uint_t end_chunk_samples;
+ uint64_t start_chunk_samples_size;
+ uint64_t end_chunk_samples_size;
off_t start_offset;
+ off_t end_offset;
size_t tkhd_size;
size_t mdhd_size;
@@ -95,7 +101,8 @@ typedef struct {
ngx_buf_t ctts_atom_buf;
ngx_buf_t ctts_data_buf;
ngx_buf_t stsc_atom_buf;
- ngx_buf_t stsc_chunk_buf;
+ ngx_buf_t stsc_start_chunk_buf;
+ ngx_buf_t stsc_end_chunk_buf;
ngx_buf_t stsc_data_buf;
ngx_buf_t stsz_atom_buf;
ngx_buf_t stsz_data_buf;
@@ -104,7 +111,8 @@ typedef struct {
ngx_buf_t co64_atom_buf;
ngx_buf_t co64_data_buf;
- ngx_mp4_stsc_entry_t stsc_chunk_entry;
+ ngx_mp4_stsc_entry_t stsc_start_chunk_entry;
+ ngx_mp4_stsc_entry_t stsc_end_chunk_entry;
} ngx_http_mp4_trak_t;
@@ -121,6 +129,7 @@ typedef struct {
off_t end;
off_t content_length;
ngx_uint_t start;
+ ngx_uint_t length;
uint32_t timescale;
ngx_http_request_t *request;
ngx_array_t trak;
@@ -219,7 +228,7 @@ static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4,
static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4,
- off_t start_offset);
+ off_t start_offset, off_t end_offset);
static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4,
@@ -258,18 +267,26 @@ static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
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 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,
ngx_http_mp4_trak_t *trak);
+static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
+static void ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
+static ngx_int_t ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
@@ -403,8 +420,8 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
{
u_char *last;
size_t root;
- ngx_int_t rc, start;
- ngx_uint_t level;
+ ngx_int_t rc, start, end;
+ ngx_uint_t level, length;
ngx_str_t path, value;
ngx_log_t *log;
ngx_buf_t *b;
@@ -509,6 +526,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
r->allow_ranges = 1;
start = -1;
+ length = 0;
r->headers_out.content_length_n = of.size;
mp4 = NULL;
b = NULL;
@@ -530,10 +548,30 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
start = -1;
}
}
+
+ if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) {
+
+ ngx_set_errno(0);
+ end = (int) (strtod((char *) value.data, NULL) * 1000);
+
+ if (ngx_errno != 0) {
+ end = -1;
+ }
+
+ if (end > 0) {
+ if (start < 0) {
+ start = 0;
+ }
+
+ if (end > start) {
+ length = end - start;
+ }
+ }
+ }
}
if (start >= 0) {
- r->allow_ranges = 0;
+ r->single_range = 1;
mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t));
if (mp4 == NULL) {
@@ -545,6 +583,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
mp4->file.log = r->connection->log;
mp4->end = of.size;
mp4->start = (ngx_uint_t) start;
+ mp4->length = length;
mp4->request = r;
switch (ngx_http_mp4_process(mp4)) {
@@ -650,15 +689,15 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
static ngx_int_t
ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
{
- off_t start_offset, adjustment;
+ off_t start_offset, end_offset, adjustment;
ngx_int_t rc;
ngx_uint_t i, j;
ngx_chain_t **prev;
ngx_http_mp4_trak_t *trak;
ngx_http_mp4_conf_t *conf;
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "mp4 start:%ui", mp4->start);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 start:%ui, length:%ui", mp4->start, mp4->length);
conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
@@ -700,6 +739,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
}
start_offset = mp4->end;
+ end_offset = 0;
trak = mp4->trak.elts;
for (i = 0; i < mp4->trak.nelts; i++) {
@@ -747,6 +787,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
start_offset = trak[i].start_offset;
}
+ if (end_offset < trak[i].end_offset) {
+ end_offset = trak[i].end_offset;
+ }
+
*prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM];
prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next;
@@ -758,6 +802,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
}
}
+ if (end_offset < start_offset) {
+ end_offset = start_offset;
+ }
+
mp4->moov_size += 8;
ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size);
@@ -774,7 +822,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
}
adjustment = mp4->ftyp_size + mp4->moov_size
- + ngx_http_mp4_update_mdat_atom(mp4, start_offset)
+ + ngx_http_mp4_update_mdat_atom(mp4, start_offset, end_offset)
- start_offset;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -1018,7 +1066,7 @@ ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
no_mdat = (mp4->mdat_atom.buf == NULL);
- if (no_mdat && mp4->start == 0) {
+ if (no_mdat && mp4->start == 0 && mp4->length == 0) {
/*
* send original file if moov atom resides before
* mdat atom and client requests integral file
@@ -1117,7 +1165,8 @@ ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
static size_t
-ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset)
+ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset,
+ off_t end_offset)
{
off_t atom_data_size;
u_char *atom_header;
@@ -1125,8 +1174,9 @@ ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset)
uint64_t atom_size;
ngx_buf_t *atom;
- atom_data_size = mp4->mdat_data.buf->file_last - start_offset;
+ atom_data_size = end_offset - start_offset;
mp4->mdat_data.buf->file_pos = start_offset;
+ mp4->mdat_data.buf->file_last = end_offset;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mdat new offset @%O:%O", start_offset, atom_data_size);
@@ -1208,7 +1258,7 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
u_char *atom_header;
size_t atom_size;
uint32_t timescale;
- uint64_t duration, start_time;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_mp4_mvhd_atom_t *mvhd_atom;
ngx_mp4_mvhd64_atom_t *mvhd64_atom;
@@ -1262,6 +1312,14 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
duration -= start_time;
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mvhd new duration:%uL, time:%.3fs",
duration, (double) duration / timescale);
@@ -1407,7 +1465,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
{
u_char *atom_header;
size_t atom_size;
- uint64_t duration, start_time;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_http_mp4_trak_t *trak;
ngx_mp4_tkhd_atom_t *tkhd_atom;
@@ -1449,7 +1507,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
start_time = (uint64_t) mp4->start * mp4->timescale / 1000;
- if (duration < start_time) {
+ if (duration <= start_time) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"tkhd duration is less than start time");
return NGX_DECLINED;
@@ -1457,6 +1515,14 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
duration -= start_time;
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * mp4->timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"tkhd new duration:%uL, time:%.3fs",
duration, (double) duration / mp4->timescale);
@@ -1558,7 +1624,7 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
u_char *atom_header;
size_t atom_size;
uint32_t timescale;
- uint64_t duration, start_time;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_http_mp4_trak_t *trak;
ngx_mp4_mdhd_atom_t *mdhd_atom;
@@ -1602,7 +1668,7 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
start_time = (uint64_t) mp4->start * timescale / 1000;
- if (duration < start_time) {
+ if (duration <= start_time) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mdhd duration is less than start time");
return NGX_DECLINED;
@@ -1610,6 +1676,14 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
duration -= start_time;
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mdhd new duration:%uL, time:%.3fs",
duration, (double) duration / timescale);
@@ -1981,13 +2055,9 @@ static ngx_int_t
ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
- size_t atom_size;
- uint32_t entries, count, duration;
- uint64_t start_time;
- ngx_buf_t *atom, *data;
- ngx_uint_t start_sample;
- ngx_mp4_stts_atom_t *stts_atom;
- ngx_mp4_stts_entry_t *entry, *end;
+ size_t atom_size;
+ ngx_buf_t *atom, *data;
+ ngx_mp4_stts_atom_t *stts_atom;
/*
* mdia.minf.stbl.stts updating requires trak->timescale
@@ -2006,12 +2076,60 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
return NGX_ERROR;
}
- entries = trak->time_to_sample_entries;
- start_time = (uint64_t) mp4->start * trak->timescale / 1000;
+ if (ngx_http_mp4_crop_stts_data(mp4, trak, 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_http_mp4_crop_stts_data(mp4, trak, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "time-to-sample start_time:%uL", start_time);
+ "time-to-sample entries:%uD", trak->time_to_sample_entries);
+
+ atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
+ stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
+ ngx_mp4_set_32value(stts_atom->size, atom_size);
+ ngx_mp4_set_32value(stts_atom->entries, trak->time_to_sample_entries);
+
+ return NGX_OK;
+}
+
+
+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;
+ uint64_t start_time;
+ ngx_buf_t *data;
+ ngx_uint_t start_sample, entries, start_sec;
+ ngx_mp4_stts_entry_t *entry, *end;
+
+ if (start) {
+ start_sec = mp4->start;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stts crop start_time:%ui", start_sec);
+
+ } else if (mp4->length) {
+ start_sec = mp4->length;
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stts crop end_time:%ui", start_sec);
+
+ } else {
+ return NGX_OK;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
+
+ start_time = (uint64_t) start_sec * trak->timescale / 1000;
+
+ entries = trak->time_to_sample_entries;
start_sample = 0;
entry = (ngx_mp4_stts_entry_t *) data->pos;
end = (ngx_mp4_stts_entry_t *) data->last;
@@ -2020,13 +2138,13 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
count = ngx_mp4_get_32value(entry->count);
duration = ngx_mp4_get_32value(entry->duration);
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "count:%uD, duration:%uD", count, duration);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "time:%uL, count:%uD, duration:%uD",
+ start_time, count, duration);
if (start_time < (uint64_t) count * duration) {
start_sample += (ngx_uint_t) (start_time / duration);
- count -= (uint32_t) (start_time / duration);
- ngx_mp4_set_32value(entry->count, count);
+ rest = (uint32_t) (start_time / duration);
goto found;
}
@@ -2036,27 +2154,44 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
entry++;
}
- ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
- "start time is out mp4 stts samples in \"%s\"",
- mp4->file.name.data);
+ if (start) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "start time is out mp4 stts samples in \"%s\"",
+ mp4->file.name.data);
- return NGX_ERROR;
+ return NGX_ERROR;
+
+ } else {
+ trak->end_sample = trak->start_sample + start_sample;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end_sample:%ui", trak->end_sample);
+
+ return NGX_OK;
+ }
found:
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start_sample:%ui, new count:%uD", start_sample, count);
+ if (start) {
+ ngx_mp4_set_32value(entry->count, count - rest);
+ data->pos = (u_char *) entry;
+ trak->time_to_sample_entries = entries;
+ trak->start_sample = start_sample;
- trak->start_sample = start_sample;
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "start_sample:%ui, new count:%uD",
+ trak->start_sample, count - rest);
- data->pos = (u_char *) entry;
- atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
+ } else {
+ ngx_mp4_set_32value(entry->count, rest);
+ data->last = (u_char *) (entry + 1);
+ trak->time_to_sample_entries -= entries - 1;
+ trak->end_sample = trak->start_sample + start_sample;
- atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
- stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
- ngx_mp4_set_32value(stts_atom->size, atom_size);
- ngx_mp4_set_32value(stts_atom->entries, entries);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end_sample:%ui, new count:%uD",
+ trak->end_sample, rest);
+ }
return NGX_OK;
}
@@ -2138,7 +2273,7 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
- uint32_t entries, sample, start_sample, *entry, *end;
+ uint32_t sample, start_sample, *entry, *end;
ngx_buf_t *atom, *data;
ngx_http_mp4_stss_atom_t *stss_atom;
@@ -2157,18 +2292,79 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
return NGX_OK;
}
+ ngx_http_mp4_crop_stss_data(mp4, trak, 1);
+ ngx_http_mp4_crop_stss_data(mp4, trak, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sync sample entries:%uD", trak->sync_samples_entries);
+
+ if (trak->sync_samples_entries) {
+ entry = (uint32_t *) data->pos;
+ end = (uint32_t *) data->last;
+
+ start_sample = trak->start_sample;
+
+ while (entry < end) {
+ sample = ngx_mp4_get_32value(entry);
+ sample -= start_sample;
+ ngx_mp4_set_32value(entry, sample);
+ entry++;
+ }
+
+ } else {
+ trak->out[NGX_HTTP_MP4_STSS_DATA].buf = NULL;
+ }
+
+ atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
+ stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
+
+ ngx_mp4_set_32value(stss_atom->size, atom_size);
+ ngx_mp4_set_32value(stss_atom->entries, trak->sync_samples_entries);
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t sample, start_sample, *entry, *end;
+ ngx_buf_t *data;
+ ngx_uint_t entries;
+
/* sync samples starts from 1 */
- start_sample = trak->start_sample + 1;
- entries = trak->sync_samples_entries;
+ if (start) {
+ start_sample = trak->start_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stss crop start_sample:%uD", start_sample);
+
+ } else if (mp4->length) {
+ start_sample = trak->end_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stss crop end_sample:%uD", start_sample);
+
+ } else {
+ return;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf;
+
+ entries = trak->sync_samples_entries;
entry = (uint32_t *) data->pos;
end = (uint32_t *) data->last;
while (entry < end) {
sample = ngx_mp4_get_32value(entry);
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start:%uD, sync:%uD", start_sample, sample);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sync:%uD", sample);
if (sample >= start_sample) {
goto found;
@@ -2179,31 +2375,18 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start sample is out of mp4 stss atom");
+ "sample is out of mp4 stss atom");
found:
- data->pos = (u_char *) entry;
-
- start_sample = trak->start_sample;
+ if (start) {
+ data->pos = (u_char *) entry;
+ trak->sync_samples_entries = entries;
- while (entry < end) {
- sample = ngx_mp4_get_32value(entry);
- sample -= start_sample;
- ngx_mp4_set_32value(entry, sample);
- entry++;
+ } else {
+ data->last = (u_char *) entry;
+ trak->sync_samples_entries -= entries;
}
-
- atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
-
- atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
- stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
-
- ngx_mp4_set_32value(stss_atom->size, atom_size);
- ngx_mp4_set_32value(stss_atom->entries, entries);
-
- return NGX_OK;
}
@@ -2287,11 +2470,9 @@ static void
ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
- size_t atom_size;
- uint32_t entries, count, start_sample;
- ngx_buf_t *atom, *data;
- ngx_mp4_ctts_atom_t *ctts_atom;
- ngx_mp4_ctts_entry_t *entry, *end;
+ size_t atom_size;
+ ngx_buf_t *atom, *data;
+ ngx_mp4_ctts_atom_t *ctts_atom;
/*
* mdia.minf.stbl.ctts updating requires trak->start_sample
@@ -2308,8 +2489,61 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
return;
}
+ ngx_http_mp4_crop_ctts_data(mp4, trak, 1);
+ ngx_http_mp4_crop_ctts_data(mp4, trak, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "composition offset entries:%uD",
+ trak->composition_offset_entries);
+
+ if (trak->composition_offset_entries == 0) {
+ trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
+ trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
+ return;
+ }
+
+ atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
+ ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
+
+ ngx_mp4_set_32value(ctts_atom->size, atom_size);
+ ngx_mp4_set_32value(ctts_atom->entries, trak->composition_offset_entries);
+
+ return;
+}
+
+
+static void
+ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t count, start_sample, rest;
+ ngx_buf_t *data;
+ ngx_uint_t entries;
+ ngx_mp4_ctts_entry_t *entry, *end;
+
/* sync samples starts from 1 */
- start_sample = trak->start_sample + 1;
+
+ if (start) {
+ start_sample = trak->start_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 ctts crop start_sample:%uD", start_sample);
+
+ } else if (mp4->length) {
+ start_sample = trak->end_sample - trak->start_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 ctts crop end_sample:%uD", start_sample);
+
+ } else {
+ return;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf;
+
entries = trak->composition_offset_entries;
entry = (ngx_mp4_ctts_entry_t *) data->pos;
end = (ngx_mp4_ctts_entry_t *) data->last;
@@ -2318,12 +2552,11 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
count = ngx_mp4_get_32value(entry->count);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start:%uD, count:%uD, offset:%uD",
+ "sample:%uD, count:%uD, offset:%uD",
start_sample, count, ngx_mp4_get_32value(entry->offset));
if (start_sample <= count) {
- count -= (start_sample - 1);
- ngx_mp4_set_32value(entry->count, count);
+ rest = start_sample - 1;
goto found;
}
@@ -2332,24 +2565,25 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
entry++;
}
- trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
- trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
+ if (start) {
+ data->pos = (u_char *) end;
+ trak->composition_offset_entries = 0;
+ }
return;
found:
- data->pos = (u_char *) entry;
- atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
+ if (start) {
+ ngx_mp4_set_32value(entry->count, count - rest);
+ data->pos = (u_char *) entry;
+ trak->composition_offset_entries = entries;
- atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
- ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
-
- ngx_mp4_set_32value(ctts_atom->size, atom_size);
- ngx_mp4_set_32value(ctts_atom->entries, entries);
-
- return;
+ } else {
+ ngx_mp4_set_32value(entry->count, rest);
+ data->last = (u_char *) (entry + 1);
+ trak->composition_offset_entries -= entries - 1;
+ }
}
@@ -2428,11 +2662,10 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
- uint32_t start_sample, entries, chunk, samples, id,
- next_chunk, n;
- ngx_buf_t *atom, *data, *buf;
+ uint32_t chunk;
+ ngx_buf_t *atom, *data;
ngx_mp4_stsc_atom_t *stsc_atom;
- ngx_mp4_stsc_entry_t *entry, *first, *end;
+ ngx_mp4_stsc_entry_t *entry, *end;
/*
* mdia.minf.stbl.stsc updating requires trak->start_sample
@@ -2459,15 +2692,97 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
return NGX_ERROR;
}
- start_sample = (uint32_t) trak->start_sample;
+ if (ngx_http_mp4_crop_stsc_data(mp4, trak, 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_http_mp4_crop_stsc_data(mp4, trak, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sample-to-chunk entries:%uD",
+ trak->sample_to_chunk_entries);
+
+ entry = (ngx_mp4_stsc_entry_t *) data->pos;
+ end = (ngx_mp4_stsc_entry_t *) data->last;
+
+ while (entry < end) {
+ chunk = ngx_mp4_get_32value(entry->chunk);
+ chunk -= trak->start_chunk;
+ ngx_mp4_set_32value(entry->chunk, chunk);
+ entry++;
+ }
+
+ atom_size = sizeof(ngx_mp4_stsc_atom_t)
+ + trak->sample_to_chunk_entries * sizeof(ngx_mp4_stsc_entry_t);
+
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
+ stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
+
+ ngx_mp4_set_32value(stsc_atom->size, atom_size);
+ ngx_mp4_set_32value(stsc_atom->entries, trak->sample_to_chunk_entries);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t start_sample, chunk, samples, id, next_chunk, n,
+ prev_samples;
+ ngx_buf_t *data, *buf;
+ ngx_uint_t entries, target_chunk, chunk_samples;
+ ngx_mp4_stsc_entry_t *entry, *end, *first;
+
entries = trak->sample_to_chunk_entries - 1;
+ if (start) {
+ start_sample = (uint32_t) trak->start_sample;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stsc crop start_sample:%uD", start_sample);
+
+ } else if (mp4->length) {
+ start_sample = (uint32_t) (trak->end_sample - trak->start_sample);
+ samples = 0;
+
+ data = trak->out[NGX_HTTP_MP4_STSC_START].buf;
+
+ if (data) {
+ entry = (ngx_mp4_stsc_entry_t *) data->pos;
+ samples = ngx_mp4_get_32value(entry->samples);
+ entries--;
+
+ if (samples > start_sample) {
+ samples = start_sample;
+ ngx_mp4_set_32value(entry->samples, samples);
+ }
+
+ start_sample -= samples;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stsc crop end_sample:%uD, ext_samples:%uD",
+ start_sample, samples);
+
+ } else {
+ return NGX_OK;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf;
+
entry = (ngx_mp4_stsc_entry_t *) data->pos;
end = (ngx_mp4_stsc_entry_t *) data->last;
chunk = ngx_mp4_get_32value(entry->chunk);
samples = ngx_mp4_get_32value(entry->samples);
id = ngx_mp4_get_32value(entry->id);
+ prev_samples = 0;
entry++;
while (entry < end) {
@@ -2475,7 +2790,7 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
next_chunk = ngx_mp4_get_32value(entry->chunk);
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start_sample:%uD, chunk:%uD, chunks:%uD, "
+ "sample:%uD, chunk:%uD, chunks:%uD, "
"samples:%uD, id:%uD",
start_sample, chunk, next_chunk - chunk, samples, id);
@@ -2487,6 +2802,7 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
start_sample -= n;
+ prev_samples = samples;
chunk = next_chunk;
samples = ngx_mp4_get_32value(entry->samples);
id = ngx_mp4_get_32value(entry->id);
@@ -2497,15 +2813,15 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
next_chunk = trak->chunks + 1;
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start_sample:%uD, chunk:%uD, chunks:%uD, samples:%uD",
+ "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD",
start_sample, chunk, next_chunk - chunk, samples);
n = (next_chunk - chunk) * samples;
if (start_sample > n) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
- "start time is out mp4 stsc chunks in \"%s\"",
- mp4->file.name.data);
+ "%s time is out mp4 stsc chunks in \"%s\"",
+ start ? "start" : "end", mp4->file.name.data);
return NGX_ERROR;
}
@@ -2521,59 +2837,91 @@ found:
return NGX_ERROR;
}
- trak->start_chunk = chunk - 1;
+ target_chunk = chunk - 1;
+ target_chunk += start_sample / samples;
+ chunk_samples = start_sample % samples;
- trak->start_chunk += start_sample / samples;
- trak->chunk_samples = start_sample % samples;
+ if (start) {
+ data->pos = (u_char *) entry;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start chunk:%ui, samples:%uD",
- trak->start_chunk, trak->chunk_samples);
+ trak->sample_to_chunk_entries = entries;
+ trak->start_chunk = target_chunk;
+ trak->start_chunk_samples = chunk_samples;
+
+ ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 1);
+
+ samples -= chunk_samples;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "start_chunk:%ui, start_chunk_samples:%ui",
+ trak->start_chunk, trak->start_chunk_samples);
+
+ } else {
+ if (start_sample) {
+ data->last = (u_char *) (entry + 1);
+ trak->sample_to_chunk_entries -= entries - 1;
+ trak->end_chunk_samples = samples;
- data->pos = (u_char *) entry;
- atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos);
+ } else {
+ data->last = (u_char *) entry;
+ trak->sample_to_chunk_entries -= entries;
+ trak->end_chunk_samples = prev_samples;
+ }
- ngx_mp4_set_32value(entry->chunk, 1);
+ if (chunk_samples) {
+ trak->end_chunk = target_chunk + 1;
+ trak->end_chunk_samples = chunk_samples;
- if (trak->chunk_samples && next_chunk - trak->start_chunk == 2) {
+ } else {
+ trak->end_chunk = target_chunk;
+ }
- /* last chunk in the entry */
+ samples = chunk_samples;
+ next_chunk = chunk + 1;
- ngx_mp4_set_32value(entry->samples, samples - trak->chunk_samples);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end_chunk:%ui, end_chunk_samples:%ui",
+ trak->end_chunk, trak->end_chunk_samples);
+ }
- } else if (trak->chunk_samples) {
+ if (chunk_samples && next_chunk - target_chunk == 2) {
- first = &trak->stsc_chunk_entry;
+ ngx_mp4_set_32value(entry->samples, samples);
+
+ } else if (chunk_samples && start) {
+
+ first = &trak->stsc_start_chunk_entry;
ngx_mp4_set_32value(first->chunk, 1);
- ngx_mp4_set_32value(first->samples, samples - trak->chunk_samples);
+ ngx_mp4_set_32value(first->samples, samples);
ngx_mp4_set_32value(first->id, id);
- buf = &trak->stsc_chunk_buf;
+ buf = &trak->stsc_start_chunk_buf;
buf->temporary = 1;
buf->pos = (u_char *) first;
buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t);
- trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf;
+ trak->out[NGX_HTTP_MP4_STSC_START].buf = buf;
- ngx_mp4_set_32value(entry->chunk, 2);
+ ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 2);
- entries++;
- atom_size += sizeof(ngx_mp4_stsc_entry_t);
- }
+ trak->sample_to_chunk_entries++;
- while (++entry < end) {
- chunk = ngx_mp4_get_32value(entry->chunk);
- chunk -= trak->start_chunk;
- ngx_mp4_set_32value(entry->chunk, chunk);
- }
+ } else if (chunk_samples) {
- trak->size += atom_size;
+ first = &trak->stsc_end_chunk_entry;
+ ngx_mp4_set_32value(first->chunk, trak->end_chunk - trak->start_chunk);
+ ngx_mp4_set_32value(first->samples, samples);
+ ngx_mp4_set_32value(first->id, id);
- atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
- stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
+ buf = &trak->stsc_end_chunk_buf;
+ buf->temporary = 1;
+ buf->pos = (u_char *) first;
+ buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t);
- ngx_mp4_set_32value(stsc_atom->size, atom_size);
- ngx_mp4_set_32value(stsc_atom->entries, entries);
+ trak->out[NGX_HTTP_MP4_STSC_END].buf = buf;
+
+ trak->sample_to_chunk_entries++;
+ }
return NGX_OK;
}
@@ -2669,7 +3017,7 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
- uint32_t *pos, *end;
+ uint32_t *pos, *end, entries;
ngx_buf_t *atom, *data;
ngx_mp4_stsz_atom_t *stsz_atom;
@@ -2685,22 +3033,47 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf;
if (data) {
- if (trak->start_sample > trak->sample_sizes_entries) {
+ entries = trak->sample_sizes_entries;
+
+ if (trak->start_sample > entries) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"start time is out mp4 stsz samples in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
+ entries -= trak->start_sample;
data->pos += trak->start_sample * sizeof(uint32_t);
end = (uint32_t *) data->pos;
- for (pos = end - trak->chunk_samples; pos < end; pos++) {
- trak->chunk_samples_size += ngx_mp4_get_32value(pos);
+ for (pos = end - trak->start_chunk_samples; pos < end; pos++) {
+ trak->start_chunk_samples_size += ngx_mp4_get_32value(pos);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "chunk samples sizes:%uL", trak->chunk_samples_size);
+ "chunk samples sizes:%uL",
+ trak->start_chunk_samples_size);
+
+ if (mp4->length) {
+ if (trak->end_sample - trak->start_sample > entries) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "end time is out mp4 stsz samples in \"%s\"",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ entries = trak->end_sample - trak->start_sample;
+ data->last = data->pos + entries * sizeof(uint32_t);
+ end = (uint32_t *) data->last;
+
+ for (pos = end - trak->end_chunk_samples; pos < end; pos++) {
+ trak->end_chunk_samples_size += ngx_mp4_get_32value(pos);
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stsz end_chunk_samples_size:%uL",
+ trak->end_chunk_samples_size);
+ }
atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos);
trak->size += atom_size;
@@ -2709,8 +3082,7 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos;
ngx_mp4_set_32value(stsz_atom->size, atom_size);
- ngx_mp4_set_32value(stsz_atom->entries,
- trak->sample_sizes_entries - trak->start_sample);
+ ngx_mp4_set_32value(stsz_atom->entries, entries);
}
return NGX_OK;
@@ -2791,6 +3163,7 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
+ uint32_t entries;
ngx_buf_t *atom, *data;
ngx_mp4_stco_atom_t *stco_atom;
@@ -2820,21 +3193,53 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
}
data->pos += trak->start_chunk * sizeof(uint32_t);
- atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
trak->start_offset = ngx_mp4_get_32value(data->pos);
- trak->start_offset += trak->chunk_samples_size;
+ trak->start_offset += trak->start_chunk_samples_size;
ngx_mp4_set_32value(data->pos, trak->start_offset);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start chunk offset:%uD", trak->start_offset);
+ "start chunk offset:%O", trak->start_offset);
+
+ if (mp4->length) {
+
+ if (trak->end_chunk > trak->chunks) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "end time is out mp4 stco chunks in \"%s\"",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ entries = trak->end_chunk - trak->start_chunk;
+ data->last = data->pos + entries * sizeof(uint32_t);
+
+ if (entries) {
+ trak->end_offset =
+ ngx_mp4_get_32value(data->last - sizeof(uint32_t));
+ trak->end_offset += trak->end_chunk_samples_size;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end chunk offset:%O", trak->end_offset);
+ }
+
+ } else {
+ entries = trak->chunks - trak->start_chunk;
+ trak->end_offset = mp4->mdat_data.buf->file_last;
+ }
+
+ if (entries == 0) {
+ trak->start_offset = mp4->end;
+ trak->end_offset = 0;
+ }
+
+ atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf;
stco_atom = (ngx_mp4_stco_atom_t *) atom->pos;
ngx_mp4_set_32value(stco_atom->size, atom_size);
- ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk);
+ ngx_mp4_set_32value(stco_atom->entries, entries);
return NGX_OK;
}
@@ -2942,6 +3347,7 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
+ uint64_t entries;
ngx_buf_t *atom, *data;
ngx_mp4_co64_atom_t *co64_atom;
@@ -2971,21 +3377,53 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
}
data->pos += trak->start_chunk * sizeof(uint64_t);
- atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
trak->start_offset = ngx_mp4_get_64value(data->pos);
- trak->start_offset += trak->chunk_samples_size;
+ trak->start_offset += trak->start_chunk_samples_size;
ngx_mp4_set_64value(data->pos, trak->start_offset);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start chunk offset:%uL", trak->start_offset);
+ "start chunk offset:%O", trak->start_offset);
+
+ if (mp4->length) {
+
+ if (trak->end_chunk > trak->chunks) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "end time is out mp4 co64 chunks in \"%s\"",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ entries = trak->end_chunk - trak->start_chunk;
+ data->last = data->pos + entries * sizeof(uint64_t);
+
+ if (entries) {
+ trak->end_offset =
+ ngx_mp4_get_64value(data->last - sizeof(uint64_t));
+ trak->end_offset += trak->end_chunk_samples_size;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end chunk offset:%O", trak->end_offset);
+ }
+
+ } else {
+ entries = trak->chunks - trak->start_chunk;
+ trak->end_offset = mp4->mdat_data.buf->file_last;
+ }
+
+ if (entries == 0) {
+ trak->start_offset = mp4->end;
+ trak->end_offset = 0;
+ }
+
+ atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf;
co64_atom = (ngx_mp4_co64_atom_t *) atom->pos;
ngx_mp4_set_32value(co64_atom->size, atom_size);
- ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk);
+ ngx_mp4_set_32value(co64_atom->entries, entries);
return NGX_OK;
}
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index bcc64fd30..6a65e4849 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -148,6 +148,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
{
time_t if_range_time;
ngx_str_t *if_range, *etag;
+ ngx_uint_t ranges;
ngx_http_core_loc_conf_t *clcf;
ngx_http_range_filter_ctx_t *ctx;
@@ -227,7 +228,9 @@ parse:
return NGX_ERROR;
}
- switch (ngx_http_range_parse(r, ctx, clcf->max_ranges)) {
+ ranges = r->single_range ? 1 : clcf->max_ranges;
+
+ switch (ngx_http_range_parse(r, ctx, ranges)) {
case NGX_OK:
ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index b023bdbc8..bfaa90e76 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -3432,25 +3432,16 @@ ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_core_main_conf_t *cmcf = conf;
- if (cmcf->server_names_hash_max_size == NGX_CONF_UNSET_UINT) {
- cmcf->server_names_hash_max_size = 512;
- }
-
- if (cmcf->server_names_hash_bucket_size == NGX_CONF_UNSET_UINT) {
- cmcf->server_names_hash_bucket_size = ngx_cacheline_size;
- }
+ ngx_conf_init_uint_value(cmcf->server_names_hash_max_size, 512);
+ ngx_conf_init_uint_value(cmcf->server_names_hash_bucket_size,
+ ngx_cacheline_size);
cmcf->server_names_hash_bucket_size =
ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
- if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) {
- cmcf->variables_hash_max_size = 512;
- }
-
- if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) {
- cmcf->variables_hash_bucket_size = 64;
- }
+ ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
+ ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);
cmcf->variables_hash_bucket_size =
ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
@@ -3719,8 +3710,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->types_hash_max_size, 1024);
ngx_conf_merge_uint_value(conf->types_hash_bucket_size,
- prev->types_hash_bucket_size,
- ngx_cacheline_size);
+ prev->types_hash_bucket_size, 64);
conf->types_hash_bucket_size = ngx_align(conf->types_hash_bucket_size,
ngx_cacheline_size);
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 8c1a62a7b..02b4a0fd1 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -886,6 +886,19 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
break;
}
+ if (ch == '_') {
+ if (allow_underscores) {
+ hash = ngx_hash(0, ch);
+ r->lowcase_header[0] = ch;
+ i = 1;
+
+ } else {
+ r->invalid_header = 1;
+ }
+
+ break;
+ }
+
if (ch == '\0') {
return NGX_HTTP_PARSE_INVALID_HEADER;
}
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index a1295e799..705c4e904 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -528,6 +528,7 @@ struct ngx_http_request_s {
unsigned filter_need_in_memory:1;
unsigned filter_need_temporary:1;
unsigned allow_ranges:1;
+ unsigned single_range:1;
#if (NGX_STAT_STUB)
unsigned stat_reading:1;
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index 6e45f4b46..33f0f03ac 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -47,11 +47,11 @@
#define ngx_spdy_ctl_frame_check(h) \
- (((h) & 0xffffff00) == ngx_spdy_ctl_frame_head(0))
+ (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0))
#define ngx_spdy_data_frame_check(h) \
(!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))
-#define ngx_spdy_ctl_frame_type(h) ((h) & 0x000000ff)
+#define ngx_spdy_ctl_frame_type(h) ((h) & 0x0000ffff)
#define ngx_spdy_frame_flags(p) ((p) >> 24)
#define ngx_spdy_frame_length(p) ((p) & 0x00ffffff)
#define ngx_spdy_frame_id(p) ((p) & 0x00ffffff)
@@ -836,7 +836,8 @@ static u_char *
ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
- uint32_t head, flen;
+ uint32_t head, flen;
+ ngx_uint_t type;
if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
@@ -859,7 +860,9 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
head, sc->flags, sc->length);
if (ngx_spdy_ctl_frame_check(head)) {
- switch (ngx_spdy_ctl_frame_type(head)) {
+ type = ngx_spdy_ctl_frame_type(head);
+
+ switch (type) {
case NGX_SPDY_SYN_STREAM:
return ngx_http_spdy_state_syn_stream(sc, pos, end);
@@ -885,7 +888,9 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
case NGX_SPDY_WINDOW_UPDATE:
return ngx_http_spdy_state_window_update(sc, pos, end);
- default: /* TODO logging */
+ default:
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy control frame with unknown type %ui", type);
return ngx_http_spdy_state_skip(sc, pos, end);
}
}
@@ -1049,6 +1054,15 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
if (r->headers_in.headers.part.elts == NULL) {
if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
+
+ if (complete) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame "
+ "with invalid HEADERS block");
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_headers);
}
@@ -1187,10 +1201,10 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
- if (buf->pos != buf->last) {
- /* TODO: improve error message */
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "end %ui %p %p", complete, buf->pos, buf->last);
+ if (buf->pos != buf->last || sc->zstream_in.avail_in) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame "
+ "with invalid HEADERS block");
ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -1489,7 +1503,6 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
ssize_t n;
ngx_buf_t *buf;
ngx_int_t rc;
- ngx_uint_t complete;
ngx_temp_file_t *tf;
ngx_http_request_t *r;
ngx_http_spdy_stream_t *stream;
@@ -1514,13 +1527,8 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
size = end - pos;
- if (size >= sc->length) {
+ if (size > sc->length) {
size = sc->length;
- complete = 1;
-
- } else {
- sc->length -= size;
- complete = 0;
}
r = stream->request;
@@ -1562,6 +1570,8 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
+ sc->length -= size;
+
if (tf) {
buf->start = pos;
buf->pos = pos;
@@ -1590,7 +1600,7 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
r->request_length += size;
}
- if (!complete) {
+ if (sc->length) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_read_data);
}
@@ -1599,6 +1609,19 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
stream->in_closed = 1;
+ if (r->headers_in.content_length_n < 0) {
+ r->headers_in.content_length_n = rb->rest;
+
+ } else if (r->headers_in.content_length_n != rb->rest) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client prematurely closed stream: "
+ "%O of %O bytes of request body received",
+ rb->rest, r->headers_in.content_length_n);
+
+ stream->skip_data = NGX_SPDY_DATA_ERROR;
+ goto error;
+ }
+
if (tf) {
ngx_memzero(buf, sizeof(ngx_buf_t));
@@ -1609,10 +1632,6 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
rb->buf = NULL;
}
- if (r->headers_in.content_length_n < 0) {
- r->headers_in.content_length_n = rb->rest;
- }
-
if (rb->post_handler) {
r->read_event_handler = ngx_http_block_reading;
rb->post_handler(r);
@@ -1872,18 +1891,20 @@ static u_char *
ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
{
-#if 1
- if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) {
+ size_t size;
+
+ size = end - pos;
+
+ if (size > NGX_SPDY_STATE_BUFFER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
"spdy state buffer overflow: "
- "%z bytes required", end - pos);
+ "%uz bytes required", size);
return ngx_http_spdy_state_internal_error(sc);
}
-#endif
ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);
- sc->buffer_used = end - pos;
+ sc->buffer_used = size;
sc->handler = handler;
sc->incomplete = 1;
@@ -2941,6 +2962,16 @@ ngx_http_spdy_run_request(ngx_http_request_t *r)
return;
}
+ if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client prematurely closed stream");
+
+ r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR;
+
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return;
+ }
+
ngx_http_process_request(r);
}
diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c
index 92c760243..559fb4aab 100644
--- a/src/http/ngx_http_spdy_filter_module.c
+++ b/src/http/ngx_http_spdy_filter_module.c
@@ -625,6 +625,20 @@ ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
r = fc->data;
stream = r->spdy_stream;
+#if (NGX_SUPPRESS_WARN)
+ size = 0;
+#endif
+
+ while (in) {
+ size = ngx_buf_size(in->buf);
+
+ if (size || in->buf->last_buf) {
+ break;
+ }
+
+ in = in->next;
+ }
+
if (in == NULL) {
if (stream->queued) {
@@ -638,8 +652,6 @@ ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
sc = stream->connection;
- size = ngx_buf_size(in->buf);
-
if (size && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) {
fc->write->delayed = 1;
return in;
@@ -850,48 +862,45 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
"spdy:%ui create DATA frame %p: len:%uz flags:%ui",
stream->id, frame, len, flags);
- if (len || flags) {
-
- cl = ngx_chain_get_free_buf(stream->request->pool,
- &stream->free_data_headers);
- if (cl == NULL) {
- return NULL;
- }
+ cl = ngx_chain_get_free_buf(stream->request->pool,
+ &stream->free_data_headers);
+ if (cl == NULL) {
+ return NULL;
+ }
- buf = cl->buf;
+ buf = cl->buf;
- if (buf->start) {
- p = buf->start;
- buf->pos = p;
+ if (buf->start) {
+ p = buf->start;
+ buf->pos = p;
- p += NGX_SPDY_SID_SIZE;
+ p += NGX_SPDY_SID_SIZE;
- (void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
+ (void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
- } else {
- p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE);
- if (p == NULL) {
- return NULL;
- }
+ } else {
+ p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE);
+ if (p == NULL) {
+ return NULL;
+ }
- buf->pos = p;
- buf->start = p;
+ buf->pos = p;
+ buf->start = p;
- p = ngx_spdy_frame_write_sid(p, stream->id);
- p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
+ p = ngx_spdy_frame_write_sid(p, stream->id);
+ p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
- buf->last = p;
- buf->end = p;
+ buf->last = p;
+ buf->end = p;
- buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame;
- buf->memory = 1;
- }
+ buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame;
+ buf->memory = 1;
+ }
- cl->next = first;
- first = cl;
+ cl->next = first;
+ first = cl;
- last->buf->flush = 1;
- }
+ last->buf->flush = 1;
frame->first = first;
frame->last = last;
diff --git a/src/http/ngx_http_spdy_module.c b/src/http/ngx_http_spdy_module.c
index 8307f15c8..5178a36f2 100644
--- a/src/http/ngx_http_spdy_module.c
+++ b/src/http/ngx_http_spdy_module.c
@@ -251,9 +251,7 @@ ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_spdy_main_conf_t *smcf = conf;
- if (smcf->recv_buffer_size == NGX_CONF_UNSET_SIZE) {
- smcf->recv_buffer_size = 256 * 1024;
- }
+ ngx_conf_init_size_value(smcf->recv_buffer_size, 256 * 1024);
return NGX_CONF_OK;
}
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index cf9ca0d5c..040bda106 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -4183,7 +4183,12 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
if (r->cached) {
r->allow_ranges = 1;
return NGX_OK;
+ }
+ if (r->upstream->cacheable) {
+ r->allow_ranges = 1;
+ r->single_range = 1;
+ return NGX_OK;
}
#endif
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c
index 9212a121c..47ddb0dcf 100644
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -559,8 +559,13 @@ ngx_mail_send(ngx_event_t *wev)
n = c->send(c, s->out.data, s->out.len);
if (n > 0) {
+ s->out.data += n;
s->out.len -= n;
+ if (s->out.len != 0) {
+ goto again;
+ }
+
if (wev->timer_set) {
ngx_del_timer(wev);
}
@@ -584,6 +589,8 @@ ngx_mail_send(ngx_event_t *wev)
/* n == NGX_AGAIN */
+again:
+
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
ngx_add_timer(c->write, cscf->timeout);
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index 4b2016500..a78ec9613 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -53,7 +53,9 @@ typedef struct {
#ifdef __CYGWIN__
+#ifndef NGX_HAVE_CASELESS_FILESYSTEM
#define NGX_HAVE_CASELESS_FILESYSTEM 1
+#endif
#define ngx_open_file(name, mode, create, access) \
open((const char *) name, mode|create|O_BINARY, access)