diff options
Diffstat (limited to 'www/tengine/files/extra-patch-ngx_http_upload_module.c')
-rw-r--r-- | www/tengine/files/extra-patch-ngx_http_upload_module.c | 1658 |
1 files changed, 0 insertions, 1658 deletions
diff --git a/www/tengine/files/extra-patch-ngx_http_upload_module.c b/www/tengine/files/extra-patch-ngx_http_upload_module.c deleted file mode 100644 index d626021fa649..000000000000 --- a/www/tengine/files/extra-patch-ngx_http_upload_module.c +++ /dev/null @@ -1,1658 +0,0 @@ ---- ../nginx_upload_module-2.2.0/ngx_http_upload_module.c.orig 2010-09-27 21:54:15.000000000 +0300 -+++ ../nginx_upload_module-2.2.0/ngx_http_upload_module.c 2013-09-10 17:40:59.570815847 +0300 -@@ -50,7 +50,7 @@ - * State of multipart/form-data parser - */ - typedef enum { -- upload_state_boundary_seek, -+ upload_state_boundary_seek, - upload_state_after_boundary, - upload_state_headers, - upload_state_data, -@@ -95,6 +95,14 @@ - } ngx_http_upload_field_template_t; - - /* -+ * Template for a header -+ */ -+typedef struct { -+ ngx_http_complex_value_t *name; -+ ngx_http_complex_value_t *value; -+} ngx_http_upload_header_template_t; -+ -+/* - * Filter for fields in output form - */ - typedef struct { -@@ -106,6 +114,12 @@ - #endif - } ngx_http_upload_field_filter_t; - -+typedef struct { -+ ngx_path_t *path; -+ ngx_http_complex_value_t dynamic; -+ unsigned is_dynamic:1; -+} ngx_http_upload_path_t; -+ - /* - * Upload cleanup record - */ -@@ -124,8 +138,8 @@ - typedef struct { - ngx_str_t url; - ngx_http_complex_value_t *url_cv; -- ngx_path_t *state_store_path; -- ngx_path_t *store_path; -+ ngx_http_upload_path_t *state_store_path; -+ ngx_http_upload_path_t *store_path; - ngx_uint_t store_access; - size_t buffer_size; - size_t merge_buffer_size; -@@ -137,13 +151,17 @@ - ngx_array_t *aggregate_field_templates; - ngx_array_t *field_filters; - ngx_array_t *cleanup_statuses; -+ ngx_array_t *header_templates; - ngx_flag_t forward_args; - ngx_flag_t tame_arrays; - ngx_flag_t resumable_uploads; -+ ngx_flag_t empty_field_names; - size_t limit_rate; - - unsigned int md5:1; - unsigned int sha1:1; -+ unsigned int sha256:1; -+ unsigned int sha512:1; - unsigned int crc32:1; - } ngx_http_upload_loc_conf_t; - -@@ -157,6 +175,16 @@ - u_char sha1_digest[SHA_DIGEST_LENGTH * 2]; - } ngx_http_upload_sha1_ctx_t; - -+typedef struct ngx_http_upload_sha256_ctx_s { -+ SHA256_CTX sha256; -+ u_char sha256_digest[SHA256_DIGEST_LENGTH * 2]; -+} ngx_http_upload_sha256_ctx_t; -+ -+typedef struct ngx_http_upload_sha512_ctx_s { -+ SHA512_CTX sha512; -+ u_char sha512_digest[SHA512_DIGEST_LENGTH * 2]; -+} ngx_http_upload_sha512_ctx_t; -+ - struct ngx_http_upload_ctx_s; - - /* -@@ -219,7 +247,11 @@ - - ngx_http_upload_md5_ctx_t *md5_ctx; - ngx_http_upload_sha1_ctx_t *sha1_ctx; -+ ngx_http_upload_sha256_ctx_t *sha256_ctx; -+ ngx_http_upload_sha512_ctx_t *sha512_ctx; - uint32_t crc32; -+ ngx_path_t *store_path; -+ ngx_path_t *state_store_path; - - unsigned int first_part:1; - unsigned int discard_data:1; -@@ -233,7 +265,21 @@ - unsigned int raw_input:1; - } ngx_http_upload_ctx_t; - -+static ngx_int_t ngx_http_upload_test_expect(ngx_http_request_t *r); -+ -+static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); -+static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); -+ -+static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); -+static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in); -+ -+static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in); -+static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in); -+ -+static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in); -+ - static ngx_int_t ngx_http_upload_handler(ngx_http_request_t *r); -+static ngx_int_t ngx_http_upload_options_handler(ngx_http_request_t *r); - static ngx_int_t ngx_http_upload_body_handler(ngx_http_request_t *r); - - static void *ngx_http_upload_create_loc_conf(ngx_conf_t *cf); -@@ -248,6 +294,10 @@ - ngx_http_variable_value_t *v, uintptr_t data); - static ngx_int_t ngx_http_upload_sha1_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); -+static ngx_int_t ngx_http_upload_sha256_variable(ngx_http_request_t *r, -+ ngx_http_variable_value_t *v, uintptr_t data); -+static ngx_int_t ngx_http_upload_sha512_variable(ngx_http_request_t *r, -+ ngx_http_variable_value_t *v, uintptr_t data); - static ngx_int_t ngx_http_upload_file_size_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - static void ngx_http_upload_content_range_variable_set(ngx_http_request_t *r, -@@ -271,6 +321,7 @@ - static ngx_int_t ngx_http_upload_merge_ranges(ngx_http_upload_ctx_t *u, ngx_http_upload_range_t *range_n); - static ngx_int_t ngx_http_upload_parse_range(ngx_str_t *range, ngx_http_upload_range_t *range_n); - -+ - static void ngx_http_read_upload_client_request_body_handler(ngx_http_request_t *r); - static ngx_int_t ngx_http_do_read_upload_client_request_body(ngx_http_request_t *r); - static ngx_int_t ngx_http_process_request_body(ngx_http_request_t *r, ngx_chain_t *body); -@@ -279,8 +330,16 @@ - - static char *ngx_http_upload_set_form_field(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -+static char *ngx_http_upload_add_header(ngx_conf_t *cf, ngx_command_t *cmd, -+ void *conf); -+static ngx_int_t ngx_http_upload_eval_path(ngx_http_request_t *r); -+static ngx_int_t ngx_http_upload_eval_state_path(ngx_http_request_t *r); - static char *ngx_http_upload_pass_form_field(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -+static char *ngx_http_upload_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, -+ void *conf); -+static char *ngx_http_upload_merge_path_value(ngx_conf_t *cf, ngx_http_upload_path_t **path, ngx_http_upload_path_t *prev, -+ ngx_path_init_t *init); - static char *ngx_http_upload_cleanup(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - static void ngx_upload_cleanup_handler(void *data); -@@ -391,7 +450,7 @@ - { ngx_string("upload_store"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE1234, -- ngx_conf_set_path_slot, -+ ngx_http_upload_set_path_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_upload_loc_conf_t, store_path), - NULL }, -@@ -401,7 +460,7 @@ - */ - { ngx_string("upload_state_store"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, -- ngx_conf_set_path_slot, -+ ngx_http_upload_set_path_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_upload_loc_conf_t, state_store_path), - NULL }, -@@ -575,6 +634,28 @@ - offsetof(ngx_http_upload_loc_conf_t, resumable_uploads), - NULL }, - -+ /* -+ * Specifies whether empty field names are allowed -+ */ -+ { ngx_string("upload_empty_fiels_names"), -+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_HTTP_LIF_CONF -+ |NGX_CONF_FLAG, -+ ngx_conf_set_flag_slot, -+ NGX_HTTP_LOC_CONF_OFFSET, -+ offsetof(ngx_http_upload_loc_conf_t, empty_field_names), -+ NULL }, -+ -+ /* -+ * Specifies the name and content of the header that will be added to the response -+ */ -+ { ngx_string("upload_add_header"), -+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_HTTP_LIF_CONF -+ |NGX_CONF_TAKE2, -+ ngx_http_upload_add_header, -+ NGX_HTTP_LOC_CONF_OFFSET, -+ offsetof(ngx_http_upload_loc_conf_t, header_templates), -+ NULL}, -+ - ngx_null_command - }; /* }}} */ - -@@ -658,6 +739,22 @@ - (uintptr_t) "0123456789ABCDEF", - NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - -+ { ngx_string("upload_file_sha256"), NULL, ngx_http_upload_sha256_variable, -+ (uintptr_t) "0123456789abcdef", -+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, -+ -+ { ngx_string("upload_file_sha256_uc"), NULL, ngx_http_upload_sha256_variable, -+ (uintptr_t) "0123456789ABCDEF", -+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, -+ -+ { ngx_string("upload_file_sha512"), NULL, ngx_http_upload_sha512_variable, -+ (uintptr_t) "0123456789abcdef", -+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, -+ -+ { ngx_string("upload_file_sha512_uc"), NULL, ngx_http_upload_sha512_variable, -+ (uintptr_t) "0123456789ABCDEF", -+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, -+ - { ngx_string("upload_file_crc32"), NULL, ngx_http_upload_crc32_variable, - (uintptr_t) offsetof(ngx_http_upload_ctx_t, crc32), - NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, -@@ -688,6 +785,9 @@ - ngx_http_upload_ctx_t *u; - ngx_int_t rc; - -+ if(r->method & NGX_HTTP_OPTIONS) -+ return ngx_http_upload_options_handler(r); -+ - if (!(r->method & NGX_HTTP_POST)) - return NGX_HTTP_NOT_ALLOWED; - -@@ -724,6 +824,26 @@ - }else - u->sha1_ctx = NULL; - -+ if(ulcf->sha256) { -+ if(u->sha256_ctx == NULL) { -+ u->sha256_ctx = ngx_palloc(r->pool, sizeof(ngx_http_upload_sha256_ctx_t)); -+ if (u->sha256_ctx == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ } -+ }else -+ u->sha256_ctx = NULL; -+ -+ if(ulcf->sha512) { -+ if(u->sha512_ctx == NULL) { -+ u->sha512_ctx = ngx_palloc(r->pool, sizeof(ngx_http_upload_sha512_ctx_t)); -+ if (u->sha512_ctx == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ } -+ }else -+ u->sha512_ctx = NULL; -+ - u->calculate_crc32 = ulcf->crc32; - - u->request = r; -@@ -746,6 +866,25 @@ - return rc; - } - -+ rc = ngx_http_upload_eval_path(r); -+ -+ if(rc != NGX_OK) { -+ upload_shutdown_ctx(u); -+ return rc; -+ } -+ -+ rc = ngx_http_upload_eval_state_path(r); -+ -+ if(rc != NGX_OK) { -+ upload_shutdown_ctx(u); -+ return rc; -+ } -+ -+ if (ngx_http_upload_test_expect(r) != NGX_OK) { -+ upload_shutdown_ctx(u); -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ - if(upload_start(u, ulcf) != NGX_OK) - return NGX_HTTP_INTERNAL_SERVER_ERROR; - -@@ -758,6 +897,124 @@ - return NGX_DONE; - } /* }}} */ - -+static ngx_int_t ngx_http_upload_add_headers(ngx_http_request_t *r, ngx_http_upload_loc_conf_t *ulcf) { /* {{{ */ -+ ngx_str_t name; -+ ngx_str_t value; -+ ngx_http_upload_header_template_t *t; -+ ngx_table_elt_t *h; -+ ngx_uint_t i; -+ -+ if(ulcf->header_templates != NULL) { -+ t = ulcf->header_templates->elts; -+ for(i = 0; i < ulcf->header_templates->nelts; i++) { -+ if(ngx_http_complex_value(r, t->name, &name) != NGX_OK) { -+ return NGX_ERROR; -+ } -+ -+ if(ngx_http_complex_value(r, t->value, &value) != NGX_OK) { -+ return NGX_ERROR; -+ } -+ -+ if(name.len != 0 && value.len != 0) { -+ h = ngx_list_push(&r->headers_out.headers); -+ if(h == NULL) { -+ return NGX_ERROR; -+ } -+ -+ h->hash = 1; -+ h->key.len = name.len; -+ h->key.data = name.data; -+ h->value.len = value.len; -+ h->value.data = value.data; -+ } -+ -+ t++; -+ } -+ } -+ -+ return NGX_OK; -+} /* }}} */ -+ -+static ngx_int_t /* {{{ */ -+ngx_http_upload_eval_path(ngx_http_request_t *r) { -+ ngx_http_upload_ctx_t *u; -+ ngx_http_upload_loc_conf_t *ulcf; -+ ngx_str_t value; -+ -+ ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); -+ u = ngx_http_get_module_ctx(r, ngx_http_upload_module); -+ -+ if(ulcf->store_path->is_dynamic) { -+ u->store_path = ngx_pcalloc(r->pool, sizeof(ngx_path_t)); -+ if(u->store_path == NULL) { -+ return NGX_ERROR; -+ } -+ -+ ngx_memcpy(u->store_path, ulcf->store_path->path, sizeof(ngx_path_t)); -+ -+ if(ngx_http_complex_value(r, &ulcf->store_path->dynamic, &value) != NGX_OK) { -+ return NGX_ERROR; -+ } -+ -+ u->store_path->name.data = value.data; -+ u->store_path->name.len = value.len; -+ } -+ else{ -+ u->store_path = ulcf->store_path->path; -+ } -+ -+ return NGX_OK; -+} /* }}} */ -+ -+static ngx_int_t /* {{{ */ -+ngx_http_upload_eval_state_path(ngx_http_request_t *r) { -+ ngx_http_upload_ctx_t *u; -+ ngx_http_upload_loc_conf_t *ulcf; -+ ngx_str_t value; -+ -+ ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); -+ u = ngx_http_get_module_ctx(r, ngx_http_upload_module); -+ -+ if(ulcf->state_store_path->is_dynamic) { -+ u->state_store_path = ngx_pcalloc(r->pool, sizeof(ngx_path_t)); -+ if(u->store_path == NULL) { -+ return NGX_ERROR; -+ } -+ -+ ngx_memcpy(u->state_store_path, ulcf->state_store_path->path, sizeof(ngx_path_t)); -+ -+ if(ngx_http_complex_value(r, &ulcf->state_store_path->dynamic, &value) != NGX_OK) { -+ return NGX_ERROR; -+ } -+ -+ u->state_store_path->name.data = value.data; -+ u->state_store_path->name.len = value.len; -+ } -+ else{ -+ u->state_store_path = ulcf->state_store_path->path; -+ } -+ -+ return NGX_OK; -+} /* }}} */ -+ -+static ngx_int_t ngx_http_upload_options_handler(ngx_http_request_t *r) { /* {{{ */ -+ ngx_http_upload_loc_conf_t *ulcf; -+ -+ ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); -+ -+ r->headers_out.status = NGX_HTTP_OK; -+ -+ if(ngx_http_upload_add_headers(r, ulcf) != NGX_OK) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ r->header_only = 1; -+ r->headers_out.content_length_n = 0; -+ r->allow_ranges = 0; -+ -+ return ngx_http_send_header(r); -+} /* }}} */ -+ - static ngx_int_t ngx_http_upload_body_handler(ngx_http_request_t *r) { /* {{{ */ - ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); - ngx_http_upload_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_upload_module); -@@ -771,6 +1028,10 @@ - ngx_str_t dummy = ngx_string("<ngx_upload_module_dummy>"); - ngx_table_elt_t *h; - -+ if(ngx_http_upload_add_headers(r, ulcf) != NGX_OK) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ - if(ctx->prevent_output) { - r->headers_out.status = NGX_HTTP_CREATED; - -@@ -952,7 +1213,8 @@ - ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); - - ngx_file_t *file = &u->output_file; -- ngx_path_t *path = ulcf->store_path; -+ ngx_path_t *path = u->store_path; -+ ngx_path_t *state_path = u->state_store_path; - uint32_t n; - ngx_uint_t i; - ngx_int_t rc; -@@ -992,6 +1254,7 @@ - "hashed path: %s", file->name.data); - - if(u->partial_content) { -+ ngx_file_t *state_file = &u->state_file; - if(u->merge_buffer == NULL) { - u->merge_buffer = ngx_palloc(r->pool, ulcf->merge_buffer_size); - -@@ -999,21 +1262,20 @@ - return NGX_UPLOAD_NOMEM; - } - -- u->state_file.name.len = file->name.len + sizeof(".state") - 1; -- u->state_file.name.data = ngx_palloc(u->request->pool, u->state_file.name.len + 1); -+ state_file->name.len = state_path->name.len + 1 + state_path->len + u->session_id.len + sizeof(".state"); -+ state_file->name.data = ngx_palloc(u->request->pool, state_file->name.len + 1); - -- if(u->state_file.name.data == NULL) -+ if(state_file->name.data == NULL) - return NGX_UPLOAD_NOMEM; - -- ngx_memcpy(u->state_file.name.data, file->name.data, file->name.len); -+ ngx_memcpy(state_file->name.data, state_path->name.data, state_path->name.len); -+ (void) ngx_sprintf(state_file->name.data + state_path->name.len + 1 + state_path->len, -+ "%V.state%Z", &u->session_id); - -- /* -- * NOTE: we add terminating zero for system calls -- */ -- ngx_memcpy(u->state_file.name.data + file->name.len, ".state", sizeof(".state") - 1 + 1); -+ ngx_create_hashed_filename(state_path, state_file->name.data, state_file->name.len); - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, -- "hashed path of state file: %s", u->state_file.name.data); -+ "hashed path of state file: %s", state_file->name.data); - } - - file->fd = ngx_open_file(file->name.data, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, ulcf->store_access); -@@ -1117,6 +1379,12 @@ - if(u->sha1_ctx != NULL) - SHA1_Init(&u->sha1_ctx->sha1); - -+ if(u->sha256_ctx != NULL) -+ SHA256_Init(&u->sha256_ctx->sha256); -+ -+ if(u->sha512_ctx != NULL) -+ SHA512_Init(&u->sha512_ctx->sha512); -+ - if(u->calculate_crc32) - ngx_crc32_init(u->crc32); - -@@ -1150,7 +1418,10 @@ - #if (NGX_PCRE) - rc = ngx_regex_exec(f[i].regex, &u->field_name, NULL, 0); - -- if (rc != NGX_REGEX_NO_MATCHED && rc < 0) { -+ /* Modified by Naren to work around iMovie and Quicktime which send empty values Added: && u->field_name.len > 0 */ -+ if ((ulcf->empty_field_names && rc != NGX_REGEX_NO_MATCHED && rc < 0 && u->field_name.len != 0) -+ || (!ulcf->empty_field_names && rc != NGX_REGEX_NO_MATCHED && rc < 0)) -+ { - return NGX_UPLOAD_SCRIPTERROR; - } - -@@ -1166,7 +1437,7 @@ - } - } - -- if(pass_field && u->field_name.len > 0) { -+ if(pass_field && u->field_name.len != 0) { - /* - * Here we do a small hack: the content of a non-file field - * is not known until ngx_http_upload_flush_output_buffer -@@ -1207,6 +1478,12 @@ - if(u->sha1_ctx) - SHA1_Final(u->sha1_ctx->sha1_digest, &u->sha1_ctx->sha1); - -+ if(u->sha256_ctx) -+ SHA256_Final(u->sha256_ctx->sha256_digest, &u->sha256_ctx->sha256); -+ -+ if(u->sha512_ctx) -+ SHA512_Final(u->sha512_ctx->sha512_digest, &u->sha512_ctx->sha512); -+ - if(u->calculate_crc32) - ngx_crc32_final(u->crc32); - -@@ -1369,6 +1646,12 @@ - if(u->sha1_ctx) - SHA1_Update(&u->sha1_ctx->sha1, buf, len); - -+ if(u->sha256_ctx) -+ SHA256_Update(&u->sha256_ctx->sha256, buf, len); -+ -+ if(u->sha512_ctx) -+ SHA512_Update(&u->sha512_ctx->sha512, buf, len); -+ - if(u->calculate_crc32) - ngx_crc32_update(&u->crc32, buf, len); - -@@ -1678,7 +1961,7 @@ - ngx_http_upload_merger_state_t ms; - off_t remaining; - ssize_t rc; -- int result; -+ __attribute__((__unused__)) int result; - ngx_buf_t in_buf; - ngx_buf_t out_buf; - ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(u->request, ngx_http_upload_module); -@@ -1799,6 +2082,7 @@ - conf->forward_args = NGX_CONF_UNSET; - conf->tame_arrays = NGX_CONF_UNSET; - conf->resumable_uploads = NGX_CONF_UNSET; -+ conf->empty_field_names = NGX_CONF_UNSET; - - conf->buffer_size = NGX_CONF_UNSET_SIZE; - conf->merge_buffer_size = NGX_CONF_UNSET_SIZE; -@@ -1809,6 +2093,7 @@ - conf->limit_rate = NGX_CONF_UNSET_SIZE; - - /* -+ * conf->header_templates, - * conf->field_templates, - * conf->aggregate_field_templates, - * and conf->field_filters are -@@ -1830,27 +2115,15 @@ - } - - if(conf->url.len != 0) { --#if defined nginx_version && nginx_version >= 7052 -- ngx_conf_merge_path_value(cf, -+ ngx_http_upload_merge_path_value(cf, - &conf->store_path, - prev->store_path, - &ngx_http_upload_temp_path); - -- ngx_conf_merge_path_value(cf, -+ ngx_http_upload_merge_path_value(cf, - &conf->state_store_path, - prev->state_store_path, - &ngx_http_upload_temp_path); --#else -- ngx_conf_merge_path_value(conf->store_path, -- prev->store_path, -- NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, -- ngx_garbage_collector_temp_handler, cf); -- -- ngx_conf_merge_path_value(conf->state_store_path, -- prev->state_store_path, -- NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, -- ngx_garbage_collector_temp_handler, cf); --#endif - } - - ngx_conf_merge_uint_value(conf->store_access, -@@ -1897,6 +2170,11 @@ - prev->resumable_uploads : 0; - } - -+ if(conf->empty_field_names == NGX_CONF_UNSET) { -+ conf->empty_field_names = (prev->empty_field_names != NGX_CONF_UNSET) ? -+ prev->empty_field_names : 0; -+ } -+ - if(conf->field_templates == NULL) { - conf->field_templates = prev->field_templates; - } -@@ -1912,6 +2190,14 @@ - conf->sha1 = prev->sha1; - } - -+ if(prev->sha256) { -+ conf->sha256 = prev->sha256; -+ } -+ -+ if(prev->sha512) { -+ conf->sha512 = prev->sha512; -+ } -+ - if(prev->crc32) { - conf->crc32 = prev->crc32; - } -@@ -1925,6 +2211,10 @@ - conf->cleanup_statuses = prev->cleanup_statuses; - } - -+ if(conf->header_templates == NULL) { -+ conf->header_templates = prev->header_templates; -+ } -+ - return NGX_CONF_OK; - } /* }}} */ - -@@ -2066,6 +2356,80 @@ - return NGX_OK; - } /* }}} */ - -+static ngx_int_t /* {{{ ngx_http_upload_sha256_variable */ -+ngx_http_upload_sha256_variable(ngx_http_request_t *r, -+ ngx_http_variable_value_t *v, uintptr_t data) -+{ -+ ngx_uint_t i; -+ ngx_http_upload_ctx_t *u; -+ u_char *c; -+ u_char *hex_table; -+ -+ u = ngx_http_get_module_ctx(r, ngx_http_upload_module); -+ -+ if(u->sha256_ctx == NULL || u->partial_content) { -+ v->not_found = 1; -+ return NGX_OK; -+ } -+ -+ v->valid = 1; -+ v->no_cacheable = 0; -+ v->not_found = 0; -+ -+ hex_table = (u_char*)data; -+ c = u->sha256_ctx->sha256_digest + SHA256_DIGEST_LENGTH * 2; -+ -+ i = SHA256_DIGEST_LENGTH; -+ -+ do{ -+ i--; -+ *--c = hex_table[u->sha256_ctx->sha256_digest[i] & 0xf]; -+ *--c = hex_table[u->sha256_ctx->sha256_digest[i] >> 4]; -+ }while(i != 0); -+ -+ v->data = u->sha256_ctx->sha256_digest; -+ v->len = SHA256_DIGEST_LENGTH * 2; -+ -+ return NGX_OK; -+} /* }}} */ -+ -+static ngx_int_t /* {{{ ngx_http_upload_sha512_variable */ -+ngx_http_upload_sha512_variable(ngx_http_request_t *r, -+ ngx_http_variable_value_t *v, uintptr_t data) -+{ -+ ngx_uint_t i; -+ ngx_http_upload_ctx_t *u; -+ u_char *c; -+ u_char *hex_table; -+ -+ u = ngx_http_get_module_ctx(r, ngx_http_upload_module); -+ -+ if(u->sha512_ctx == NULL || u->partial_content) { -+ v->not_found = 1; -+ return NGX_OK; -+ } -+ -+ v->valid = 1; -+ v->no_cacheable = 0; -+ v->not_found = 0; -+ -+ hex_table = (u_char*)data; -+ c = u->sha512_ctx->sha512_digest + SHA512_DIGEST_LENGTH * 2; -+ -+ i = SHA512_DIGEST_LENGTH; -+ -+ do{ -+ i--; -+ *--c = hex_table[u->sha512_ctx->sha512_digest[i] & 0xf]; -+ *--c = hex_table[u->sha512_ctx->sha512_digest[i] >> 4]; -+ }while(i != 0); -+ -+ v->data = u->sha512_ctx->sha512_digest; -+ v->len = SHA512_DIGEST_LENGTH * 2; -+ -+ return NGX_OK; -+} /* }}} */ -+ - static ngx_int_t /* {{{ ngx_http_upload_crc32_variable */ - ngx_http_upload_crc32_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -@@ -2299,6 +2663,10 @@ - ", upload_file_md5_uc" - ", upload_file_sha1" - ", upload_file_sha1_uc" -+ ", upload_file_sha256" -+ ", upload_file_sha256_uc" -+ ", upload_file_sha512" -+ ", upload_file_sha512_uc" - ", upload_file_crc32" - ", upload_content_range" - " and upload_file_size" -@@ -2312,6 +2680,12 @@ - if(v->get_handler == ngx_http_upload_sha1_variable) - ulcf->sha1 = 1; - -+ if(v->get_handler == ngx_http_upload_sha256_variable) -+ ulcf->sha256 = 1; -+ -+ if(v->get_handler == ngx_http_upload_sha512_variable) -+ ulcf->sha512 = 1; -+ - if(v->get_handler == ngx_http_upload_crc32_variable) - ulcf->crc32 = 1; - } -@@ -2396,37 +2770,104 @@ - return NGX_CONF_OK; - } /* }}} */ - --static char * /* {{{ ngx_http_upload_cleanup */ --ngx_http_upload_cleanup(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -+static char * /* {{{ ngx_http_upload_add_header */ -+ngx_http_upload_add_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) - { -- ngx_http_upload_loc_conf_t *ulcf = conf; -- - ngx_str_t *value; -- ngx_uint_t i; -- ngx_int_t status, lo, hi; -- uint16_t *s; -+ ngx_http_upload_header_template_t *h; -+ ngx_array_t **field; -+ ngx_http_compile_complex_value_t ccv; -+ -+ field = (ngx_array_t**) (((u_char*)conf) + cmd->offset); - - value = cf->args->elts; - -- if (ulcf->cleanup_statuses == NULL) { -- ulcf->cleanup_statuses = ngx_array_create(cf->pool, 1, -- sizeof(uint16_t)); -- if (ulcf->cleanup_statuses == NULL) { -+ /* -+ * Add new entry to header template list -+ */ -+ if (*field == NULL) { -+ *field = ngx_array_create(cf->pool, 1, -+ sizeof(ngx_http_upload_header_template_t)); -+ if (*field == NULL) { - return NGX_CONF_ERROR; - } - } - -- for (i = 1; i < cf->args->nelts; i++) { -- if(value[i].len > 4 && value[i].data[3] == '-') { -- lo = ngx_atoi(value[i].data, 3); -- -- if (lo == NGX_ERROR) { -- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, -- "invalid lower bound \"%V\"", &value[i]); -- return NGX_CONF_ERROR; -- } -- -- hi = ngx_atoi(value[i].data + 4, value[i].len - 4); -+ h = ngx_array_push(*field); -+ if (h == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ /* -+ * Compile header name -+ */ -+ h->name = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); -+ if(h->name == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); -+ -+ ccv.cf = cf; -+ ccv.value = &value[1]; -+ ccv.complex_value = h->name; -+ -+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { -+ return NGX_CONF_ERROR; -+ } -+ -+ /* -+ * Compile header value -+ */ -+ h->value = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); -+ if(h->value == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); -+ -+ ccv.cf = cf; -+ ccv.value = &value[2]; -+ ccv.complex_value = h->value; -+ -+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { -+ return NGX_CONF_ERROR; -+ } -+ -+ return NGX_CONF_OK; -+} /* }}} */ -+ -+static char * /* {{{ ngx_http_upload_cleanup */ -+ngx_http_upload_cleanup(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -+{ -+ ngx_http_upload_loc_conf_t *ulcf = conf; -+ -+ ngx_str_t *value; -+ ngx_uint_t i; -+ ngx_int_t status, lo, hi; -+ uint16_t *s; -+ -+ value = cf->args->elts; -+ -+ if (ulcf->cleanup_statuses == NULL) { -+ ulcf->cleanup_statuses = ngx_array_create(cf->pool, 1, -+ sizeof(uint16_t)); -+ if (ulcf->cleanup_statuses == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ } -+ -+ for (i = 1; i < cf->args->nelts; i++) { -+ if(value[i].len > 4 && value[i].data[3] == '-') { -+ lo = ngx_atoi(value[i].data, 3); -+ -+ if (lo == NGX_ERROR) { -+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, -+ "invalid lower bound \"%V\"", &value[i]); -+ return NGX_CONF_ERROR; -+ } -+ -+ hi = ngx_atoi(value[i].data + 4, value[i].len - 4); - - if (hi == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, -@@ -2453,9 +2894,9 @@ - hi = lo = status; - } - -- if (lo < 400 || hi > 599) { -+ if (lo < 200 || hi > 599) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, -- "value(s) \"%V\" must be between 400 and 599", -+ "value(s) \"%V\" must be between 200 and 599", - &value[i]); - return NGX_CONF_ERROR; - } -@@ -2523,6 +2964,665 @@ - return NGX_CONF_OK; - } /* }}} */ - -+static char * /* {{{ ngx_http_upload_set_path_slot */ -+ngx_http_upload_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -+{ -+ char *p = conf; -+ -+ ssize_t level; -+ ngx_str_t *value; -+ ngx_uint_t i, n; -+ ngx_http_upload_path_t *path, **slot; -+ ngx_http_compile_complex_value_t ccv; -+ -+ slot = (ngx_http_upload_path_t **) (p + cmd->offset); -+ -+ if (*slot) { -+ return "is duplicate"; -+ } -+ -+ path = ngx_pcalloc(cf->pool, sizeof(ngx_http_upload_path_t)); -+ if (path == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ path->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); -+ if (path->path == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ value = cf->args->elts; -+ -+ path->path->name = value[1]; -+ -+ if (path->path->name.data[path->path->name.len - 1] == '/') { -+ path->path->name.len--; -+ } -+ -+ if (ngx_conf_full_name(cf->cycle, &path->path->name, 0) != NGX_OK) { -+ return NULL; -+ } -+ -+ path->path->len = 0; -+ path->path->manager = NULL; -+ path->path->loader = NULL; -+ path->path->conf_file = cf->conf_file->file.name.data; -+ path->path->line = cf->conf_file->line; -+ -+ for (i = 0, n = 2; n < cf->args->nelts; i++, n++) { -+ level = ngx_atoi(value[n].data, value[n].len); -+ if (level == NGX_ERROR || level == 0) { -+ return "invalid value"; -+ } -+ -+ path->path->level[i] = level; -+ path->path->len += level + 1; -+ } -+ -+ while (i < 3) { -+ path->path->level[i++] = 0; -+ } -+ -+ *slot = path; -+ -+ if(ngx_http_script_variables_count(&value[1])) { -+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); -+ -+ ccv.cf = cf; -+ ccv.value = &value[1]; -+ ccv.complex_value = &path->dynamic; -+ -+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { -+ return NGX_CONF_ERROR; -+ } -+ -+ path->is_dynamic = 1; -+ } -+ else { -+ if (ngx_add_path(cf, &path->path) == NGX_ERROR) { -+ return NGX_CONF_ERROR; -+ } -+ } -+ -+ return NGX_CONF_OK; -+} /* }}} */ -+ -+ -+static char * /* {{{ ngx_http_upload_merge_path_value */ -+ngx_http_upload_merge_path_value(ngx_conf_t *cf, ngx_http_upload_path_t **path, ngx_http_upload_path_t *prev, -+ ngx_path_init_t *init) -+{ -+ if (*path) { -+ return NGX_CONF_OK; -+ } -+ -+ if (prev) { -+ *path = prev; -+ return NGX_CONF_OK; -+ } -+ -+ *path = ngx_palloc(cf->pool, sizeof(ngx_http_upload_path_t)); -+ if(*path == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ (*path)->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); -+ if((*path)->path == NULL) { -+ return NGX_CONF_ERROR; -+ } -+ -+ (*path)->path->name = init->name; -+ -+ if(ngx_conf_full_name(cf->cycle, &(*path)->path->name, 0) != NGX_OK) { -+ return NGX_CONF_ERROR; -+ } -+ -+ (*path)->path->level[0] = init->level[0]; -+ (*path)->path->level[1] = init->level[1]; -+ (*path)->path->level[2] = init->level[2]; -+ -+ (*path)->path->len = init->level[0] + (init->level[0] ? 1 : 0) -+ + init->level[1] + (init->level[1] ? 1 : 0) -+ + init->level[2] + (init->level[2] ? 1 : 0); -+ -+ (*path)->path->manager = NULL; -+ (*path)->path->loader = NULL; -+ (*path)->path->conf_file = NULL; -+ -+ if(ngx_add_path(cf, &(*path)->path) != NGX_OK) { -+ return NGX_CONF_ERROR; -+ } -+ -+ return NGX_CONF_OK; -+} /* }}} */ -+ -+static ngx_int_t -+ngx_http_write_request_body(ngx_http_request_t *r) -+{ -+ ssize_t n; -+ ngx_chain_t *cl; -+ ngx_temp_file_t *tf; -+ ngx_http_request_body_t *rb; -+ ngx_http_core_loc_conf_t *clcf; -+ -+ rb = r->request_body; -+ -+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -+ "http write client request body, bufs %p", rb->bufs); -+ -+ if (rb->temp_file == NULL) { -+ tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); -+ if (tf == NULL) { -+ return NGX_ERROR; -+ } -+ -+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); -+ -+ tf->file.fd = NGX_INVALID_FILE; -+ tf->file.log = r->connection->log; -+ tf->path = clcf->client_body_temp_path; -+ tf->pool = r->pool; -+ tf->warn = "a client request body is buffered to a temporary file"; -+ tf->log_level = r->request_body_file_log_level; -+ tf->persistent = r->request_body_in_persistent_file; -+ tf->clean = r->request_body_in_clean_file; -+ -+ if (r->request_body_file_group_access) { -+ tf->access = 0660; -+ } -+ -+ rb->temp_file = tf; -+ -+ if (rb->bufs == NULL) { -+ /* empty body with r->request_body_in_file_only */ -+ -+ if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, -+ tf->persistent, tf->clean, tf->access) -+ != NGX_OK) -+ { -+ return NGX_ERROR; -+ } -+ -+ return NGX_OK; -+ } -+ } -+ -+ if (rb->bufs == NULL) { -+ return NGX_OK; -+ } -+ -+ n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs); -+ -+ /* TODO: n == 0 or not complete and level event */ -+ -+ if (n == NGX_ERROR) { -+ return NGX_ERROR; -+ } -+ -+ rb->temp_file->offset += n; -+ -+ /* mark all buffers as written */ -+ -+ for (cl = rb->bufs; cl; cl = cl->next) { -+ cl->buf->pos = cl->buf->last; -+ } -+ -+ rb->bufs = NULL; -+ -+ return NGX_OK; -+} -+ -+static ngx_int_t -+ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in) -+{ -+ if (r->headers_in.chunked) { -+ return ngx_http_request_body_chunked_filter(r, in); -+ -+ } else { -+ return ngx_http_request_body_length_filter(r, in); -+ } -+} -+ -+static ngx_int_t -+ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) -+{ -+#if (NGX_DEBUG) -+ ngx_chain_t *cl; -+#endif -+ ngx_http_request_body_t *rb; -+ -+ rb = r->request_body; -+ -+#if (NGX_DEBUG) -+ -+ for (cl = rb->bufs; cl; cl = cl->next) { -+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, -+ "http body old buf t:%d f:%d %p, pos %p, size: %z " -+ "file: %O, size: %z", -+ cl->buf->temporary, cl->buf->in_file, -+ cl->buf->start, cl->buf->pos, -+ cl->buf->last - cl->buf->pos, -+ cl->buf->file_pos, -+ cl->buf->file_last - cl->buf->file_pos); -+ } -+ -+ for (cl = in; cl; cl = cl->next) { -+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, -+ "http body new buf t:%d f:%d %p, pos %p, size: %z " -+ "file: %O, size: %z", -+ cl->buf->temporary, cl->buf->in_file, -+ cl->buf->start, cl->buf->pos, -+ cl->buf->last - cl->buf->pos, -+ cl->buf->file_pos, -+ cl->buf->file_last - cl->buf->file_pos); -+ } -+ -+#endif -+ -+ /* TODO: coalesce neighbouring buffers */ -+ -+ if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ return NGX_OK; -+} -+ -+ -+static ngx_int_t -+ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) -+{ -+ size_t size; -+ ngx_int_t rc; -+ ngx_buf_t *b; -+ ngx_chain_t *cl, *tl, *out, **ll; -+ ngx_http_request_body_t *rb; -+ -+ rb = r->request_body; -+ -+ if (rb->rest == -1) { -+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -+ "http request body content length filter"); -+ -+ rb->rest = r->headers_in.content_length_n; -+ } -+ -+ out = NULL; -+ ll = &out; -+ -+ for (cl = in; cl; cl = cl->next) { -+ -+ tl = ngx_chain_get_free_buf(r->pool, &rb->free); -+ if (tl == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ b = tl->buf; -+ -+ ngx_memzero(b, sizeof(ngx_buf_t)); -+ -+ b->temporary = 1; -+ b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; -+ b->start = cl->buf->start; -+ b->pos = cl->buf->pos; -+ b->last = cl->buf->last; -+ b->end = cl->buf->end; -+ -+ size = cl->buf->last - cl->buf->pos; -+ -+ if ((off_t) size < rb->rest) { -+ cl->buf->pos = cl->buf->last; -+ rb->rest -= size; -+ -+ } else { -+ cl->buf->pos += rb->rest; -+ rb->rest = 0; -+ b->last = cl->buf->pos; -+ b->last_buf = 1; -+ } -+ -+ *ll = tl; -+ ll = &tl->next; -+ } -+ -+ rc = ngx_http_request_body_save_filter(r, out); -+ -+ ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, -+ (ngx_buf_tag_t) &ngx_http_read_client_request_body); -+ -+ return rc; -+} -+ -+static ngx_int_t -+ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) -+{ -+ size_t size; -+ ngx_int_t rc; -+ ngx_buf_t *b; -+ ngx_chain_t *cl, *out, *tl, **ll; -+ ngx_http_request_body_t *rb; -+ ngx_http_core_loc_conf_t *clcf; -+ -+ rb = r->request_body; -+ -+ if (rb->rest == -1) { -+ -+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -+ "http request body chunked filter"); -+ -+ rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); -+ if (rb->chunked == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ r->headers_in.content_length_n = 0; -+ rb->rest = 3; -+ } -+ -+ out = NULL; -+ ll = &out; -+ -+ for (cl = in; cl; cl = cl->next) { -+ -+ for ( ;; ) { -+ -+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, -+ "http body chunked buf " -+ "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z", -+ cl->buf->temporary, cl->buf->in_file, -+ cl->buf->start, cl->buf->pos, -+ cl->buf->last - cl->buf->pos, -+ cl->buf->file_pos, -+ cl->buf->file_last - cl->buf->file_pos); -+ -+ rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked); -+ -+ if (rc == NGX_OK) { -+ -+ /* a chunk has been parsed successfully */ -+ -+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); -+ -+ if (clcf->client_max_body_size -+ && clcf->client_max_body_size -+ < r->headers_in.content_length_n + rb->chunked->size) -+ { -+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, -+ "client intended to send too large chunked " -+ "body: %O bytes", -+ r->headers_in.content_length_n -+ + rb->chunked->size); -+ -+ r->lingering_close = 1; -+ -+ return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; -+ } -+ -+ tl = ngx_chain_get_free_buf(r->pool, &rb->free); -+ if (tl == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ b = tl->buf; -+ -+ ngx_memzero(b, sizeof(ngx_buf_t)); -+ -+ b->temporary = 1; -+ b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; -+ b->start = cl->buf->start; -+ b->pos = cl->buf->pos; -+ b->last = cl->buf->last; -+ b->end = cl->buf->end; -+ -+ *ll = tl; -+ ll = &tl->next; -+ -+ size = cl->buf->last - cl->buf->pos; -+ -+ if ((off_t) size > rb->chunked->size) { -+ cl->buf->pos += rb->chunked->size; -+ r->headers_in.content_length_n += rb->chunked->size; -+ rb->chunked->size = 0; -+ -+ } else { -+ rb->chunked->size -= size; -+ r->headers_in.content_length_n += size; -+ cl->buf->pos = cl->buf->last; -+ } -+ -+ b->last = cl->buf->pos; -+ -+ continue; -+ } -+ -+ if (rc == NGX_DONE) { -+ -+ /* a whole response has been parsed successfully */ -+ -+ rb->rest = 0; -+ -+ tl = ngx_chain_get_free_buf(r->pool, &rb->free); -+ if (tl == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ b = tl->buf; -+ -+ ngx_memzero(b, sizeof(ngx_buf_t)); -+ -+ b->last_buf = 1; -+ -+ *ll = tl; -+ ll = &tl->next; -+ -+ break; -+ } -+ -+ if (rc == NGX_AGAIN) { -+ -+ /* set rb->rest, amount of data we want to see next time */ -+ -+ rb->rest = rb->chunked->length; -+ -+ break; -+ } -+ -+ /* invalid */ -+ -+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, -+ "client sent invalid chunked body"); -+ -+ return NGX_HTTP_BAD_REQUEST; -+ } -+ } -+ -+ rc = ngx_http_request_body_save_filter(r, out); -+ -+ ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, -+ (ngx_buf_tag_t) &ngx_http_read_client_request_body); -+ -+ return rc; -+} -+ -+static ngx_int_t -+ngx_http_do_read_client_request_body(ngx_http_request_t *r) -+{ -+ off_t rest; -+ size_t size; -+ ssize_t n; -+ ngx_int_t rc; -+ ngx_buf_t *b; -+ ngx_chain_t *cl, out; -+ ngx_connection_t *c; -+ ngx_http_request_body_t *rb; -+ ngx_http_core_loc_conf_t *clcf; -+ -+ c = r->connection; -+ rb = r->request_body; -+ -+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, -+ "http read client request body"); -+ -+ for ( ;; ) { -+ for ( ;; ) { -+ if (rb->buf->last == rb->buf->end) { -+ -+ /* pass buffer to request body filter chain */ -+ -+ out.buf = rb->buf; -+ out.next = NULL; -+ -+ rc = ngx_http_request_body_filter(r, &out); -+ -+ if (rc != NGX_OK) { -+ return rc; -+ } -+ -+ /* write to file */ -+ -+ if (ngx_http_write_request_body(r) != NGX_OK) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ /* update chains */ -+ -+ rc = ngx_http_request_body_filter(r, NULL); -+ -+ if (rc != NGX_OK) { -+ return rc; -+ } -+ -+ if (rb->busy != NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ rb->buf->pos = rb->buf->start; -+ rb->buf->last = rb->buf->start; -+ } -+ size = rb->buf->end - rb->buf->last; -+ rest = rb->rest - (rb->buf->last - rb->buf->pos); -+ -+ if ((off_t) size > rest) { -+ size = (size_t) rest; -+ } -+ -+ n = c->recv(c, rb->buf->last, size); -+ -+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, -+ "http client request body recv %z", n); -+ -+ if (n == NGX_AGAIN) { -+ break; -+ } -+ -+ if (n == 0) { -+ ngx_log_error(NGX_LOG_INFO, c->log, 0, -+ "client prematurely closed connection"); -+ } -+ -+ if (n == 0 || n == NGX_ERROR) { -+ c->error = 1; -+ return NGX_HTTP_BAD_REQUEST; -+ } -+ -+ rb->buf->last += n; -+ r->request_length += n; -+ -+ if (n == rest) { -+ /* pass buffer to request body filter chain */ -+ -+ out.buf = rb->buf; -+ out.next = NULL; -+ -+ rc = ngx_http_request_body_filter(r, &out); -+ -+ if (rc != NGX_OK) { -+ return rc; -+ } -+ } -+ -+ if (rb->rest == 0) { -+ break; -+ } -+ -+ if (rb->buf->last < rb->buf->end) { -+ break; -+ } -+ } -+ -+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, -+ "http client request body rest %O", rb->rest); -+ if (rb->rest == 0) { -+ break; -+ } -+ -+ if (!c->read->ready) { -+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); -+ ngx_add_timer(c->read, clcf->client_body_timeout); -+ -+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ return NGX_AGAIN; -+ } -+ } -+ -+ if (c->read->timer_set) { -+ ngx_del_timer(c->read); -+ } -+ -+ if (rb->temp_file || r->request_body_in_file_only) { -+ -+ /* save the last part */ -+ -+ if (ngx_http_write_request_body(r) != NGX_OK) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ cl = ngx_chain_get_free_buf(r->pool, &rb->free); -+ if (cl == NULL) { -+ return NGX_HTTP_INTERNAL_SERVER_ERROR; -+ } -+ -+ b = cl->buf; -+ -+ ngx_memzero(b, sizeof(ngx_buf_t)); -+ -+ b->in_file = 1; -+ b->file_last = rb->temp_file->file.offset; -+ b->file = &rb->temp_file->file; -+ -+ rb->bufs = cl; -+ } -+ -+ r->read_event_handler = ngx_http_block_reading; -+ -+ rb->post_handler(r); -+ -+ return NGX_OK; -+} -+ -+ -+static void -+ngx_http_read_client_request_body_handler(ngx_http_request_t *r) -+{ -+ ngx_int_t rc; -+ -+ if (r->connection->read->timedout) { -+ r->connection->timedout = 1; -+ ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); -+ return; -+ } -+ -+ rc = ngx_http_do_read_client_request_body(r); -+ -+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { -+ ngx_http_finalize_request(r, rc); -+ } -+} -+ -+ - ngx_int_t /* {{{ ngx_http_read_upload_client_request_body */ - ngx_http_read_upload_client_request_body(ngx_http_request_t *r) { - ssize_t size, preread; -@@ -2625,9 +3725,9 @@ - - /* the whole request body may be placed in r->header_in */ - -- rb->to_write = rb->bufs; -- -- r->read_event_handler = ngx_http_read_upload_client_request_body_handler; -+ rb->buf = r->header_in; -+ r->read_event_handler = ngx_http_read_client_request_body_handler; -+ r->write_event_handler = ngx_http_request_empty_handler; - - return ngx_http_do_read_upload_client_request_body(r); - } -@@ -2684,7 +3784,9 @@ - - *next = cl; - -- rb->to_write = rb->bufs; -+ /* -+ * rb->to_write = rb->bufs; -+ */ - - r->read_event_handler = ngx_http_read_upload_client_request_body_handler; - -@@ -2766,7 +3868,7 @@ - for ( ;; ) { - if (rb->buf->last == rb->buf->end) { - -- rc = ngx_http_process_request_body(r, rb->to_write); -+ rc = ngx_http_process_request_body(r, rb->bufs); - - switch(rc) { - case NGX_OK: -@@ -2781,8 +3883,7 @@ - default: - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } -- -- rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; -+ rb->bufs = rb->bufs->next ? rb->bufs->next : rb->bufs; - rb->buf->last = rb->buf->start; - } - -@@ -2874,7 +3975,7 @@ - ngx_del_timer(c->read); - } - -- rc = ngx_http_process_request_body(r, rb->to_write); -+ rc = ngx_http_process_request_body(r, rb->bufs); - - switch(rc) { - case NGX_OK: -@@ -3299,6 +4400,14 @@ - return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; - } - -+ if( (upload_ctx->content_range_n.end - upload_ctx->content_range_n.start + 1) -+ != headers_in->content_length_n) -+ { -+ ngx_log_error(NGX_LOG_ERR, upload_ctx->log, 0, -+ "range length is not equal to content length"); -+ return NGX_HTTP_RANGE_NOT_SATISFIABLE; -+ } -+ - upload_ctx->partial_content = 1; - } - } -@@ -3436,8 +4545,8 @@ - return NGX_ERROR; - } - -- if(range_n->start >= range_n->end || range_n->start >= range_n->total -- || range_n->end > range_n->total) -+ if(range_n->start > range_n->end || range_n->start >= range_n->total -+ || range_n->end >= range_n->total) - { - return NGX_ERROR; - } -@@ -3673,3 +4782,43 @@ - } - } /* }}} */ - -+static ngx_int_t /* {{{ */ -+ngx_http_upload_test_expect(ngx_http_request_t *r) -+{ -+ ngx_int_t n; -+ ngx_str_t *expect; -+ -+ if (r->expect_tested -+ || r->headers_in.expect == NULL -+ || r->http_version < NGX_HTTP_VERSION_11) -+ { -+ return NGX_OK; -+ } -+ -+ r->expect_tested = 1; -+ -+ expect = &r->headers_in.expect->value; -+ -+ if (expect->len != sizeof("100-continue") - 1 -+ || ngx_strncasecmp(expect->data, (u_char *) "100-continue", -+ sizeof("100-continue") - 1) -+ != 0) -+ { -+ return NGX_OK; -+ } -+ -+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -+ "send 100 Continue"); -+ -+ n = r->connection->send(r->connection, -+ (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF, -+ sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1); -+ -+ if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) { -+ return NGX_OK; -+ } -+ -+ /* we assume that such small packet should be send successfully */ -+ -+ return NGX_ERROR; -+} /* }}} */ - |