Ticket #39773: patch-nginx_upload_module.tmp-ngx_http_upload_module.c.diff
File patch-nginx_upload_module.tmp-ngx_http_upload_module.c.diff, 50.9 KB (added by anthropologoi@…, 11 years ago) |
---|
-
nginx_upload_module.tmp/ngx_http_upload_module.c
old new 95 95 } ngx_http_upload_field_template_t; 96 96 97 97 /* 98 * Template for a header 99 */ 100 typedef struct { 101 ngx_http_complex_value_t *name; 102 ngx_http_complex_value_t *value; 103 } ngx_http_upload_header_template_t; 104 105 /* 98 106 * Filter for fields in output form 99 107 */ 100 108 typedef struct { … … 106 114 #endif 107 115 } ngx_http_upload_field_filter_t; 108 116 117 typedef struct { 118 ngx_path_t *path; 119 ngx_http_complex_value_t dynamic; 120 unsigned is_dynamic:1; 121 } ngx_http_upload_path_t; 122 109 123 /* 110 124 * Upload cleanup record 111 125 */ … … 124 138 typedef struct { 125 139 ngx_str_t url; 126 140 ngx_http_complex_value_t *url_cv; 127 ngx_ path_t*state_store_path;128 ngx_ path_t*store_path;141 ngx_http_upload_path_t *state_store_path; 142 ngx_http_upload_path_t *store_path; 129 143 ngx_uint_t store_access; 130 144 size_t buffer_size; 131 145 size_t merge_buffer_size; … … 137 151 ngx_array_t *aggregate_field_templates; 138 152 ngx_array_t *field_filters; 139 153 ngx_array_t *cleanup_statuses; 154 ngx_array_t *header_templates; 140 155 ngx_flag_t forward_args; 141 156 ngx_flag_t tame_arrays; 142 157 ngx_flag_t resumable_uploads; 158 ngx_flag_t empty_field_names; 143 159 size_t limit_rate; 144 160 145 161 unsigned int md5:1; 146 162 unsigned int sha1:1; 163 unsigned int sha256:1; 164 unsigned int sha512:1; 147 165 unsigned int crc32:1; 148 166 } ngx_http_upload_loc_conf_t; 149 167 … … 157 175 u_char sha1_digest[SHA_DIGEST_LENGTH * 2]; 158 176 } ngx_http_upload_sha1_ctx_t; 159 177 178 typedef struct ngx_http_upload_sha256_ctx_s { 179 SHA256_CTX sha256; 180 u_char sha256_digest[SHA256_DIGEST_LENGTH * 2]; 181 } ngx_http_upload_sha256_ctx_t; 182 183 typedef struct ngx_http_upload_sha512_ctx_s { 184 SHA512_CTX sha512; 185 u_char sha512_digest[SHA512_DIGEST_LENGTH * 2]; 186 } ngx_http_upload_sha512_ctx_t; 187 160 188 struct ngx_http_upload_ctx_s; 161 189 162 190 /* … … 219 247 220 248 ngx_http_upload_md5_ctx_t *md5_ctx; 221 249 ngx_http_upload_sha1_ctx_t *sha1_ctx; 250 ngx_http_upload_sha256_ctx_t *sha256_ctx; 251 ngx_http_upload_sha512_ctx_t *sha512_ctx; 222 252 uint32_t crc32; 253 ngx_path_t *store_path; 254 ngx_path_t *state_store_path; 223 255 224 256 unsigned int first_part:1; 225 257 unsigned int discard_data:1; … … 233 265 unsigned int raw_input:1; 234 266 } ngx_http_upload_ctx_t; 235 267 268 static ngx_int_t ngx_http_upload_test_expect(ngx_http_request_t *r); 269 270 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); 271 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); 272 273 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); 274 static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in); 275 276 static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in); 277 static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in); 278 279 static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in); 280 236 281 static ngx_int_t ngx_http_upload_handler(ngx_http_request_t *r); 282 static ngx_int_t ngx_http_upload_options_handler(ngx_http_request_t *r); 237 283 static ngx_int_t ngx_http_upload_body_handler(ngx_http_request_t *r); 238 284 239 285 static void *ngx_http_upload_create_loc_conf(ngx_conf_t *cf); … … 248 294 ngx_http_variable_value_t *v, uintptr_t data); 249 295 static ngx_int_t ngx_http_upload_sha1_variable(ngx_http_request_t *r, 250 296 ngx_http_variable_value_t *v, uintptr_t data); 297 static ngx_int_t ngx_http_upload_sha256_variable(ngx_http_request_t *r, 298 ngx_http_variable_value_t *v, uintptr_t data); 299 static ngx_int_t ngx_http_upload_sha512_variable(ngx_http_request_t *r, 300 ngx_http_variable_value_t *v, uintptr_t data); 251 301 static ngx_int_t ngx_http_upload_file_size_variable(ngx_http_request_t *r, 252 302 ngx_http_variable_value_t *v, uintptr_t data); 253 303 static void ngx_http_upload_content_range_variable_set(ngx_http_request_t *r, … … 271 321 static ngx_int_t ngx_http_upload_merge_ranges(ngx_http_upload_ctx_t *u, ngx_http_upload_range_t *range_n); 272 322 static ngx_int_t ngx_http_upload_parse_range(ngx_str_t *range, ngx_http_upload_range_t *range_n); 273 323 324 274 325 static void ngx_http_read_upload_client_request_body_handler(ngx_http_request_t *r); 275 326 static ngx_int_t ngx_http_do_read_upload_client_request_body(ngx_http_request_t *r); 276 327 static ngx_int_t ngx_http_process_request_body(ngx_http_request_t *r, ngx_chain_t *body); … … 279 330 280 331 static char *ngx_http_upload_set_form_field(ngx_conf_t *cf, ngx_command_t *cmd, 281 332 void *conf); 333 static char *ngx_http_upload_add_header(ngx_conf_t *cf, ngx_command_t *cmd, 334 void *conf); 335 static ngx_int_t ngx_http_upload_eval_path(ngx_http_request_t *r); 336 static ngx_int_t ngx_http_upload_eval_state_path(ngx_http_request_t *r); 282 337 static char *ngx_http_upload_pass_form_field(ngx_conf_t *cf, ngx_command_t *cmd, 283 338 void *conf); 339 static char *ngx_http_upload_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, 340 void *conf); 341 static char *ngx_http_upload_merge_path_value(ngx_conf_t *cf, ngx_http_upload_path_t **path, ngx_http_upload_path_t *prev, 342 ngx_path_init_t *init); 284 343 static char *ngx_http_upload_cleanup(ngx_conf_t *cf, ngx_command_t *cmd, 285 344 void *conf); 286 345 static void ngx_upload_cleanup_handler(void *data); … … 391 450 { ngx_string("upload_store"), 392 451 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_HTTP_LIF_CONF 393 452 |NGX_CONF_TAKE1234, 394 ngx_ conf_set_path_slot,453 ngx_http_upload_set_path_slot, 395 454 NGX_HTTP_LOC_CONF_OFFSET, 396 455 offsetof(ngx_http_upload_loc_conf_t, store_path), 397 456 NULL }, … … 401 460 */ 402 461 { ngx_string("upload_state_store"), 403 462 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, 404 ngx_ conf_set_path_slot,463 ngx_http_upload_set_path_slot, 405 464 NGX_HTTP_LOC_CONF_OFFSET, 406 465 offsetof(ngx_http_upload_loc_conf_t, state_store_path), 407 466 NULL }, … … 575 634 offsetof(ngx_http_upload_loc_conf_t, resumable_uploads), 576 635 NULL }, 577 636 637 /* 638 * Specifies whether empty field names are allowed 639 */ 640 { ngx_string("upload_empty_fiels_names"), 641 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_HTTP_LIF_CONF 642 |NGX_CONF_FLAG, 643 ngx_conf_set_flag_slot, 644 NGX_HTTP_LOC_CONF_OFFSET, 645 offsetof(ngx_http_upload_loc_conf_t, empty_field_names), 646 NULL }, 647 648 /* 649 * Specifies the name and content of the header that will be added to the response 650 */ 651 { ngx_string("upload_add_header"), 652 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_HTTP_LIF_CONF 653 |NGX_CONF_TAKE2, 654 ngx_http_upload_add_header, 655 NGX_HTTP_LOC_CONF_OFFSET, 656 offsetof(ngx_http_upload_loc_conf_t, header_templates), 657 NULL}, 658 578 659 ngx_null_command 579 660 }; /* }}} */ 580 661 … … 658 739 (uintptr_t) "0123456789ABCDEF", 659 740 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 660 741 742 { ngx_string("upload_file_sha256"), NULL, ngx_http_upload_sha256_variable, 743 (uintptr_t) "0123456789abcdef", 744 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 745 746 { ngx_string("upload_file_sha256_uc"), NULL, ngx_http_upload_sha256_variable, 747 (uintptr_t) "0123456789ABCDEF", 748 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 749 750 { ngx_string("upload_file_sha512"), NULL, ngx_http_upload_sha512_variable, 751 (uintptr_t) "0123456789abcdef", 752 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 753 754 { ngx_string("upload_file_sha512_uc"), NULL, ngx_http_upload_sha512_variable, 755 (uintptr_t) "0123456789ABCDEF", 756 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 757 661 758 { ngx_string("upload_file_crc32"), NULL, ngx_http_upload_crc32_variable, 662 759 (uintptr_t) offsetof(ngx_http_upload_ctx_t, crc32), 663 760 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, … … 688 785 ngx_http_upload_ctx_t *u; 689 786 ngx_int_t rc; 690 787 788 if(r->method & NGX_HTTP_OPTIONS) 789 return ngx_http_upload_options_handler(r); 790 691 791 if (!(r->method & NGX_HTTP_POST)) 692 792 return NGX_HTTP_NOT_ALLOWED; 693 793 … … 724 824 }else 725 825 u->sha1_ctx = NULL; 726 826 827 if(ulcf->sha256) { 828 if(u->sha256_ctx == NULL) { 829 u->sha256_ctx = ngx_palloc(r->pool, sizeof(ngx_http_upload_sha256_ctx_t)); 830 if (u->sha256_ctx == NULL) { 831 return NGX_HTTP_INTERNAL_SERVER_ERROR; 832 } 833 } 834 }else 835 u->sha256_ctx = NULL; 836 837 if(ulcf->sha512) { 838 if(u->sha512_ctx == NULL) { 839 u->sha512_ctx = ngx_palloc(r->pool, sizeof(ngx_http_upload_sha512_ctx_t)); 840 if (u->sha512_ctx == NULL) { 841 return NGX_HTTP_INTERNAL_SERVER_ERROR; 842 } 843 } 844 }else 845 u->sha512_ctx = NULL; 846 727 847 u->calculate_crc32 = ulcf->crc32; 728 848 729 849 u->request = r; … … 746 866 return rc; 747 867 } 748 868 869 rc = ngx_http_upload_eval_path(r); 870 871 if(rc != NGX_OK) { 872 upload_shutdown_ctx(u); 873 return rc; 874 } 875 876 rc = ngx_http_upload_eval_state_path(r); 877 878 if(rc != NGX_OK) { 879 upload_shutdown_ctx(u); 880 return rc; 881 } 882 883 if (ngx_http_upload_test_expect(r) != NGX_OK) { 884 upload_shutdown_ctx(u); 885 return NGX_HTTP_INTERNAL_SERVER_ERROR; 886 } 887 749 888 if(upload_start(u, ulcf) != NGX_OK) 750 889 return NGX_HTTP_INTERNAL_SERVER_ERROR; 751 890 … … 758 897 return NGX_DONE; 759 898 } /* }}} */ 760 899 900 static ngx_int_t ngx_http_upload_add_headers(ngx_http_request_t *r, ngx_http_upload_loc_conf_t *ulcf) { /* {{{ */ 901 ngx_str_t name; 902 ngx_str_t value; 903 ngx_http_upload_header_template_t *t; 904 ngx_table_elt_t *h; 905 ngx_uint_t i; 906 907 if(ulcf->header_templates != NULL) { 908 t = ulcf->header_templates->elts; 909 for(i = 0; i < ulcf->header_templates->nelts; i++) { 910 if(ngx_http_complex_value(r, t->name, &name) != NGX_OK) { 911 return NGX_ERROR; 912 } 913 914 if(ngx_http_complex_value(r, t->value, &value) != NGX_OK) { 915 return NGX_ERROR; 916 } 917 918 if(name.len != 0 && value.len != 0) { 919 h = ngx_list_push(&r->headers_out.headers); 920 if(h == NULL) { 921 return NGX_ERROR; 922 } 923 924 h->hash = 1; 925 h->key.len = name.len; 926 h->key.data = name.data; 927 h->value.len = value.len; 928 h->value.data = value.data; 929 } 930 931 t++; 932 } 933 } 934 935 return NGX_OK; 936 } /* }}} */ 937 938 static ngx_int_t /* {{{ */ 939 ngx_http_upload_eval_path(ngx_http_request_t *r) { 940 ngx_http_upload_ctx_t *u; 941 ngx_http_upload_loc_conf_t *ulcf; 942 ngx_str_t value; 943 944 ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); 945 u = ngx_http_get_module_ctx(r, ngx_http_upload_module); 946 947 if(ulcf->store_path->is_dynamic) { 948 u->store_path = ngx_pcalloc(r->pool, sizeof(ngx_path_t)); 949 if(u->store_path == NULL) { 950 return NGX_ERROR; 951 } 952 953 ngx_memcpy(u->store_path, ulcf->store_path->path, sizeof(ngx_path_t)); 954 955 if(ngx_http_complex_value(r, &ulcf->store_path->dynamic, &value) != NGX_OK) { 956 return NGX_ERROR; 957 } 958 959 u->store_path->name.data = value.data; 960 u->store_path->name.len = value.len; 961 } 962 else{ 963 u->store_path = ulcf->store_path->path; 964 } 965 966 return NGX_OK; 967 } /* }}} */ 968 969 static ngx_int_t /* {{{ */ 970 ngx_http_upload_eval_state_path(ngx_http_request_t *r) { 971 ngx_http_upload_ctx_t *u; 972 ngx_http_upload_loc_conf_t *ulcf; 973 ngx_str_t value; 974 975 ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); 976 u = ngx_http_get_module_ctx(r, ngx_http_upload_module); 977 978 if(ulcf->state_store_path->is_dynamic) { 979 u->state_store_path = ngx_pcalloc(r->pool, sizeof(ngx_path_t)); 980 if(u->store_path == NULL) { 981 return NGX_ERROR; 982 } 983 984 ngx_memcpy(u->state_store_path, ulcf->state_store_path->path, sizeof(ngx_path_t)); 985 986 if(ngx_http_complex_value(r, &ulcf->state_store_path->dynamic, &value) != NGX_OK) { 987 return NGX_ERROR; 988 } 989 990 u->state_store_path->name.data = value.data; 991 u->state_store_path->name.len = value.len; 992 } 993 else{ 994 u->state_store_path = ulcf->state_store_path->path; 995 } 996 997 return NGX_OK; 998 } /* }}} */ 999 1000 static ngx_int_t ngx_http_upload_options_handler(ngx_http_request_t *r) { /* {{{ */ 1001 ngx_http_upload_loc_conf_t *ulcf; 1002 1003 ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); 1004 1005 r->headers_out.status = NGX_HTTP_OK; 1006 1007 if(ngx_http_upload_add_headers(r, ulcf) != NGX_OK) { 1008 return NGX_HTTP_INTERNAL_SERVER_ERROR; 1009 } 1010 1011 r->header_only = 1; 1012 r->headers_out.content_length_n = 0; 1013 r->allow_ranges = 0; 1014 1015 return ngx_http_send_header(r); 1016 } /* }}} */ 1017 761 1018 static ngx_int_t ngx_http_upload_body_handler(ngx_http_request_t *r) { /* {{{ */ 762 1019 ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); 763 1020 ngx_http_upload_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_upload_module); … … 771 1028 ngx_str_t dummy = ngx_string("<ngx_upload_module_dummy>"); 772 1029 ngx_table_elt_t *h; 773 1030 1031 if(ngx_http_upload_add_headers(r, ulcf) != NGX_OK) { 1032 return NGX_HTTP_INTERNAL_SERVER_ERROR; 1033 } 1034 774 1035 if(ctx->prevent_output) { 775 1036 r->headers_out.status = NGX_HTTP_CREATED; 776 1037 … … 952 1213 ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); 953 1214 954 1215 ngx_file_t *file = &u->output_file; 955 ngx_path_t *path = ulcf->store_path; 1216 ngx_path_t *path = u->store_path; 1217 ngx_path_t *state_path = u->state_store_path; 956 1218 uint32_t n; 957 1219 ngx_uint_t i; 958 1220 ngx_int_t rc; … … 992 1254 "hashed path: %s", file->name.data); 993 1255 994 1256 if(u->partial_content) { 1257 ngx_file_t *state_file = &u->state_file; 995 1258 if(u->merge_buffer == NULL) { 996 1259 u->merge_buffer = ngx_palloc(r->pool, ulcf->merge_buffer_size); 997 1260 … … 999 1262 return NGX_UPLOAD_NOMEM; 1000 1263 } 1001 1264 1002 u->state_file.name.len = file->name.len + sizeof(".state") - 1;1003 u->state_file.name.data = ngx_palloc(u->request->pool, u->state_file.name.len + 1);1265 state_file->name.len = state_path->name.len + 1 + state_path->len + u->session_id.len + sizeof(".state"); 1266 state_file->name.data = ngx_palloc(u->request->pool, state_file->name.len + 1); 1004 1267 1005 if( u->state_file.name.data == NULL)1268 if(state_file->name.data == NULL) 1006 1269 return NGX_UPLOAD_NOMEM; 1007 1270 1008 ngx_memcpy(u->state_file.name.data, file->name.data, file->name.len); 1271 ngx_memcpy(state_file->name.data, state_path->name.data, state_path->name.len); 1272 (void) ngx_sprintf(state_file->name.data + state_path->name.len + 1 + state_path->len, 1273 "%V.state%Z", &u->session_id); 1009 1274 1010 /* 1011 * NOTE: we add terminating zero for system calls 1012 */ 1013 ngx_memcpy(u->state_file.name.data + file->name.len, ".state", sizeof(".state") - 1 + 1); 1275 ngx_create_hashed_filename(state_path, state_file->name.data, state_file->name.len); 1014 1276 1015 1277 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, 1016 "hashed path of state file: %s", u->state_file.name.data);1278 "hashed path of state file: %s", state_file->name.data); 1017 1279 } 1018 1280 1019 1281 file->fd = ngx_open_file(file->name.data, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, ulcf->store_access); … … 1117 1379 if(u->sha1_ctx != NULL) 1118 1380 SHA1_Init(&u->sha1_ctx->sha1); 1119 1381 1382 if(u->sha256_ctx != NULL) 1383 SHA256_Init(&u->sha256_ctx->sha256); 1384 1385 if(u->sha512_ctx != NULL) 1386 SHA512_Init(&u->sha512_ctx->sha512); 1387 1120 1388 if(u->calculate_crc32) 1121 1389 ngx_crc32_init(u->crc32); 1122 1390 … … 1150 1418 #if (NGX_PCRE) 1151 1419 rc = ngx_regex_exec(f[i].regex, &u->field_name, NULL, 0); 1152 1420 1153 if (rc != NGX_REGEX_NO_MATCHED && rc < 0) { 1421 /* Modified by Naren to work around iMovie and Quicktime which send empty values Added: && u->field_name.len > 0 */ 1422 if ((ulcf->empty_field_names && rc != NGX_REGEX_NO_MATCHED && rc < 0 && u->field_name.len != 0) 1423 || (!ulcf->empty_field_names && rc != NGX_REGEX_NO_MATCHED && rc < 0)) 1424 { 1154 1425 return NGX_UPLOAD_SCRIPTERROR; 1155 1426 } 1156 1427 … … 1166 1437 } 1167 1438 } 1168 1439 1169 if(pass_field && u->field_name.len >0) {1440 if(pass_field && u->field_name.len != 0) { 1170 1441 /* 1171 1442 * Here we do a small hack: the content of a non-file field 1172 1443 * is not known until ngx_http_upload_flush_output_buffer … … 1207 1478 if(u->sha1_ctx) 1208 1479 SHA1_Final(u->sha1_ctx->sha1_digest, &u->sha1_ctx->sha1); 1209 1480 1481 if(u->sha256_ctx) 1482 SHA256_Final(u->sha256_ctx->sha256_digest, &u->sha256_ctx->sha256); 1483 1484 if(u->sha512_ctx) 1485 SHA512_Final(u->sha512_ctx->sha512_digest, &u->sha512_ctx->sha512); 1486 1210 1487 if(u->calculate_crc32) 1211 1488 ngx_crc32_final(u->crc32); 1212 1489 … … 1369 1646 if(u->sha1_ctx) 1370 1647 SHA1_Update(&u->sha1_ctx->sha1, buf, len); 1371 1648 1649 if(u->sha256_ctx) 1650 SHA256_Update(&u->sha256_ctx->sha256, buf, len); 1651 1652 if(u->sha512_ctx) 1653 SHA512_Update(&u->sha512_ctx->sha512, buf, len); 1654 1372 1655 if(u->calculate_crc32) 1373 1656 ngx_crc32_update(&u->crc32, buf, len); 1374 1657 … … 1678 1961 ngx_http_upload_merger_state_t ms; 1679 1962 off_t remaining; 1680 1963 ssize_t rc; 1681 intresult;1964 __attribute__((__unused__)) int result; 1682 1965 ngx_buf_t in_buf; 1683 1966 ngx_buf_t out_buf; 1684 1967 ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(u->request, ngx_http_upload_module); … … 1799 2082 conf->forward_args = NGX_CONF_UNSET; 1800 2083 conf->tame_arrays = NGX_CONF_UNSET; 1801 2084 conf->resumable_uploads = NGX_CONF_UNSET; 2085 conf->empty_field_names = NGX_CONF_UNSET; 1802 2086 1803 2087 conf->buffer_size = NGX_CONF_UNSET_SIZE; 1804 2088 conf->merge_buffer_size = NGX_CONF_UNSET_SIZE; … … 1809 2093 conf->limit_rate = NGX_CONF_UNSET_SIZE; 1810 2094 1811 2095 /* 2096 * conf->header_templates, 1812 2097 * conf->field_templates, 1813 2098 * conf->aggregate_field_templates, 1814 2099 * and conf->field_filters are … … 1830 2115 } 1831 2116 1832 2117 if(conf->url.len != 0) { 1833 #if defined nginx_version && nginx_version >= 7052 1834 ngx_conf_merge_path_value(cf, 2118 ngx_http_upload_merge_path_value(cf, 1835 2119 &conf->store_path, 1836 2120 prev->store_path, 1837 2121 &ngx_http_upload_temp_path); 1838 2122 1839 ngx_ conf_merge_path_value(cf,2123 ngx_http_upload_merge_path_value(cf, 1840 2124 &conf->state_store_path, 1841 2125 prev->state_store_path, 1842 2126 &ngx_http_upload_temp_path); 1843 #else1844 ngx_conf_merge_path_value(conf->store_path,1845 prev->store_path,1846 NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,1847 ngx_garbage_collector_temp_handler, cf);1848 1849 ngx_conf_merge_path_value(conf->state_store_path,1850 prev->state_store_path,1851 NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,1852 ngx_garbage_collector_temp_handler, cf);1853 #endif1854 2127 } 1855 2128 1856 2129 ngx_conf_merge_uint_value(conf->store_access, … … 1897 2170 prev->resumable_uploads : 0; 1898 2171 } 1899 2172 2173 if(conf->empty_field_names == NGX_CONF_UNSET) { 2174 conf->empty_field_names = (prev->empty_field_names != NGX_CONF_UNSET) ? 2175 prev->empty_field_names : 0; 2176 } 2177 1900 2178 if(conf->field_templates == NULL) { 1901 2179 conf->field_templates = prev->field_templates; 1902 2180 } … … 1912 2190 conf->sha1 = prev->sha1; 1913 2191 } 1914 2192 2193 if(prev->sha256) { 2194 conf->sha256 = prev->sha256; 2195 } 2196 2197 if(prev->sha512) { 2198 conf->sha512 = prev->sha512; 2199 } 2200 1915 2201 if(prev->crc32) { 1916 2202 conf->crc32 = prev->crc32; 1917 2203 } … … 1925 2211 conf->cleanup_statuses = prev->cleanup_statuses; 1926 2212 } 1927 2213 2214 if(conf->header_templates == NULL) { 2215 conf->header_templates = prev->header_templates; 2216 } 2217 1928 2218 return NGX_CONF_OK; 1929 2219 } /* }}} */ 1930 2220 … … 2066 2356 return NGX_OK; 2067 2357 } /* }}} */ 2068 2358 2359 static ngx_int_t /* {{{ ngx_http_upload_sha256_variable */ 2360 ngx_http_upload_sha256_variable(ngx_http_request_t *r, 2361 ngx_http_variable_value_t *v, uintptr_t data) 2362 { 2363 ngx_uint_t i; 2364 ngx_http_upload_ctx_t *u; 2365 u_char *c; 2366 u_char *hex_table; 2367 2368 u = ngx_http_get_module_ctx(r, ngx_http_upload_module); 2369 2370 if(u->sha256_ctx == NULL || u->partial_content) { 2371 v->not_found = 1; 2372 return NGX_OK; 2373 } 2374 2375 v->valid = 1; 2376 v->no_cacheable = 0; 2377 v->not_found = 0; 2378 2379 hex_table = (u_char*)data; 2380 c = u->sha256_ctx->sha256_digest + SHA256_DIGEST_LENGTH * 2; 2381 2382 i = SHA256_DIGEST_LENGTH; 2383 2384 do{ 2385 i--; 2386 *--c = hex_table[u->sha256_ctx->sha256_digest[i] & 0xf]; 2387 *--c = hex_table[u->sha256_ctx->sha256_digest[i] >> 4]; 2388 }while(i != 0); 2389 2390 v->data = u->sha256_ctx->sha256_digest; 2391 v->len = SHA256_DIGEST_LENGTH * 2; 2392 2393 return NGX_OK; 2394 } /* }}} */ 2395 2396 static ngx_int_t /* {{{ ngx_http_upload_sha512_variable */ 2397 ngx_http_upload_sha512_variable(ngx_http_request_t *r, 2398 ngx_http_variable_value_t *v, uintptr_t data) 2399 { 2400 ngx_uint_t i; 2401 ngx_http_upload_ctx_t *u; 2402 u_char *c; 2403 u_char *hex_table; 2404 2405 u = ngx_http_get_module_ctx(r, ngx_http_upload_module); 2406 2407 if(u->sha512_ctx == NULL || u->partial_content) { 2408 v->not_found = 1; 2409 return NGX_OK; 2410 } 2411 2412 v->valid = 1; 2413 v->no_cacheable = 0; 2414 v->not_found = 0; 2415 2416 hex_table = (u_char*)data; 2417 c = u->sha512_ctx->sha512_digest + SHA512_DIGEST_LENGTH * 2; 2418 2419 i = SHA512_DIGEST_LENGTH; 2420 2421 do{ 2422 i--; 2423 *--c = hex_table[u->sha512_ctx->sha512_digest[i] & 0xf]; 2424 *--c = hex_table[u->sha512_ctx->sha512_digest[i] >> 4]; 2425 }while(i != 0); 2426 2427 v->data = u->sha512_ctx->sha512_digest; 2428 v->len = SHA512_DIGEST_LENGTH * 2; 2429 2430 return NGX_OK; 2431 } /* }}} */ 2432 2069 2433 static ngx_int_t /* {{{ ngx_http_upload_crc32_variable */ 2070 2434 ngx_http_upload_crc32_variable(ngx_http_request_t *r, 2071 2435 ngx_http_variable_value_t *v, uintptr_t data) … … 2299 2663 ", upload_file_md5_uc" 2300 2664 ", upload_file_sha1" 2301 2665 ", upload_file_sha1_uc" 2666 ", upload_file_sha256" 2667 ", upload_file_sha256_uc" 2668 ", upload_file_sha512" 2669 ", upload_file_sha512_uc" 2302 2670 ", upload_file_crc32" 2303 2671 ", upload_content_range" 2304 2672 " and upload_file_size" … … 2312 2680 if(v->get_handler == ngx_http_upload_sha1_variable) 2313 2681 ulcf->sha1 = 1; 2314 2682 2683 if(v->get_handler == ngx_http_upload_sha256_variable) 2684 ulcf->sha256 = 1; 2685 2686 if(v->get_handler == ngx_http_upload_sha512_variable) 2687 ulcf->sha512 = 1; 2688 2315 2689 if(v->get_handler == ngx_http_upload_crc32_variable) 2316 2690 ulcf->crc32 = 1; 2317 2691 } … … 2396 2770 return NGX_CONF_OK; 2397 2771 } /* }}} */ 2398 2772 2399 static char * /* {{{ ngx_http_upload_ cleanup*/2400 ngx_http_upload_ cleanup(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)2773 static char * /* {{{ ngx_http_upload_add_header */ 2774 ngx_http_upload_add_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2401 2775 { 2402 ngx_http_upload_loc_conf_t *ulcf = conf;2403 2404 2776 ngx_str_t *value; 2405 ngx_uint_t i; 2406 ngx_int_t status, lo, hi; 2407 uint16_t *s; 2777 ngx_http_upload_header_template_t *h; 2778 ngx_array_t **field; 2779 ngx_http_compile_complex_value_t ccv; 2780 2781 field = (ngx_array_t**) (((u_char*)conf) + cmd->offset); 2408 2782 2409 2783 value = cf->args->elts; 2410 2784 2411 if (ulcf->cleanup_statuses == NULL) { 2412 ulcf->cleanup_statuses = ngx_array_create(cf->pool, 1, 2413 sizeof(uint16_t)); 2414 if (ulcf->cleanup_statuses == NULL) { 2785 /* 2786 * Add new entry to header template list 2787 */ 2788 if (*field == NULL) { 2789 *field = ngx_array_create(cf->pool, 1, 2790 sizeof(ngx_http_upload_header_template_t)); 2791 if (*field == NULL) { 2415 2792 return NGX_CONF_ERROR; 2416 2793 } 2417 2794 } 2418 2795 2419 for (i = 1; i < cf->args->nelts; i++) { 2420 if(value[i].len > 4 && value[i].data[3] == '-') { 2421 lo = ngx_atoi(value[i].data, 3); 2422 2423 if (lo == NGX_ERROR) { 2424 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2425 "invalid lower bound \"%V\"", &value[i]); 2426 return NGX_CONF_ERROR; 2427 } 2428 2429 hi = ngx_atoi(value[i].data + 4, value[i].len - 4); 2796 h = ngx_array_push(*field); 2797 if (h == NULL) { 2798 return NGX_CONF_ERROR; 2799 } 2800 2801 /* 2802 * Compile header name 2803 */ 2804 h->name = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); 2805 if(h->name == NULL) { 2806 return NGX_CONF_ERROR; 2807 } 2808 2809 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 2810 2811 ccv.cf = cf; 2812 ccv.value = &value[1]; 2813 ccv.complex_value = h->name; 2814 2815 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 2816 return NGX_CONF_ERROR; 2817 } 2818 2819 /* 2820 * Compile header value 2821 */ 2822 h->value = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); 2823 if(h->value == NULL) { 2824 return NGX_CONF_ERROR; 2825 } 2826 2827 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 2828 2829 ccv.cf = cf; 2830 ccv.value = &value[2]; 2831 ccv.complex_value = h->value; 2832 2833 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 2834 return NGX_CONF_ERROR; 2835 } 2836 2837 return NGX_CONF_OK; 2838 } /* }}} */ 2839 2840 static char * /* {{{ ngx_http_upload_cleanup */ 2841 ngx_http_upload_cleanup(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2842 { 2843 ngx_http_upload_loc_conf_t *ulcf = conf; 2844 2845 ngx_str_t *value; 2846 ngx_uint_t i; 2847 ngx_int_t status, lo, hi; 2848 uint16_t *s; 2849 2850 value = cf->args->elts; 2851 2852 if (ulcf->cleanup_statuses == NULL) { 2853 ulcf->cleanup_statuses = ngx_array_create(cf->pool, 1, 2854 sizeof(uint16_t)); 2855 if (ulcf->cleanup_statuses == NULL) { 2856 return NGX_CONF_ERROR; 2857 } 2858 } 2859 2860 for (i = 1; i < cf->args->nelts; i++) { 2861 if(value[i].len > 4 && value[i].data[3] == '-') { 2862 lo = ngx_atoi(value[i].data, 3); 2863 2864 if (lo == NGX_ERROR) { 2865 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2866 "invalid lower bound \"%V\"", &value[i]); 2867 return NGX_CONF_ERROR; 2868 } 2869 2870 hi = ngx_atoi(value[i].data + 4, value[i].len - 4); 2430 2871 2431 2872 if (hi == NGX_ERROR) { 2432 2873 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, … … 2453 2894 hi = lo = status; 2454 2895 } 2455 2896 2456 if (lo < 400 || hi > 599) {2897 if (lo < 200 || hi > 599) { 2457 2898 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2458 "value(s) \"%V\" must be between 400 and 599",2899 "value(s) \"%V\" must be between 200 and 599", 2459 2900 &value[i]); 2460 2901 return NGX_CONF_ERROR; 2461 2902 } … … 2523 2964 return NGX_CONF_OK; 2524 2965 } /* }}} */ 2525 2966 2967 static char * /* {{{ ngx_http_upload_set_path_slot */ 2968 ngx_http_upload_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2969 { 2970 char *p = conf; 2971 2972 ssize_t level; 2973 ngx_str_t *value; 2974 ngx_uint_t i, n; 2975 ngx_http_upload_path_t *path, **slot; 2976 ngx_http_compile_complex_value_t ccv; 2977 2978 slot = (ngx_http_upload_path_t **) (p + cmd->offset); 2979 2980 if (*slot) { 2981 return "is duplicate"; 2982 } 2983 2984 path = ngx_pcalloc(cf->pool, sizeof(ngx_http_upload_path_t)); 2985 if (path == NULL) { 2986 return NGX_CONF_ERROR; 2987 } 2988 2989 path->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); 2990 if (path->path == NULL) { 2991 return NGX_CONF_ERROR; 2992 } 2993 2994 value = cf->args->elts; 2995 2996 path->path->name = value[1]; 2997 2998 if (path->path->name.data[path->path->name.len - 1] == '/') { 2999 path->path->name.len--; 3000 } 3001 3002 if (ngx_conf_full_name(cf->cycle, &path->path->name, 0) != NGX_OK) { 3003 return NULL; 3004 } 3005 3006 path->path->len = 0; 3007 path->path->manager = NULL; 3008 path->path->loader = NULL; 3009 path->path->conf_file = cf->conf_file->file.name.data; 3010 path->path->line = cf->conf_file->line; 3011 3012 for (i = 0, n = 2; n < cf->args->nelts; i++, n++) { 3013 level = ngx_atoi(value[n].data, value[n].len); 3014 if (level == NGX_ERROR || level == 0) { 3015 return "invalid value"; 3016 } 3017 3018 path->path->level[i] = level; 3019 path->path->len += level + 1; 3020 } 3021 3022 while (i < 3) { 3023 path->path->level[i++] = 0; 3024 } 3025 3026 *slot = path; 3027 3028 if(ngx_http_script_variables_count(&value[1])) { 3029 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 3030 3031 ccv.cf = cf; 3032 ccv.value = &value[1]; 3033 ccv.complex_value = &path->dynamic; 3034 3035 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 3036 return NGX_CONF_ERROR; 3037 } 3038 3039 path->is_dynamic = 1; 3040 } 3041 else { 3042 if (ngx_add_path(cf, &path->path) == NGX_ERROR) { 3043 return NGX_CONF_ERROR; 3044 } 3045 } 3046 3047 return NGX_CONF_OK; 3048 } /* }}} */ 3049 3050 3051 static char * /* {{{ ngx_http_upload_merge_path_value */ 3052 ngx_http_upload_merge_path_value(ngx_conf_t *cf, ngx_http_upload_path_t **path, ngx_http_upload_path_t *prev, 3053 ngx_path_init_t *init) 3054 { 3055 if (*path) { 3056 return NGX_CONF_OK; 3057 } 3058 3059 if (prev) { 3060 *path = prev; 3061 return NGX_CONF_OK; 3062 } 3063 3064 *path = ngx_palloc(cf->pool, sizeof(ngx_http_upload_path_t)); 3065 if(*path == NULL) { 3066 return NGX_CONF_ERROR; 3067 } 3068 3069 (*path)->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); 3070 if((*path)->path == NULL) { 3071 return NGX_CONF_ERROR; 3072 } 3073 3074 (*path)->path->name = init->name; 3075 3076 if(ngx_conf_full_name(cf->cycle, &(*path)->path->name, 0) != NGX_OK) { 3077 return NGX_CONF_ERROR; 3078 } 3079 3080 (*path)->path->level[0] = init->level[0]; 3081 (*path)->path->level[1] = init->level[1]; 3082 (*path)->path->level[2] = init->level[2]; 3083 3084 (*path)->path->len = init->level[0] + (init->level[0] ? 1 : 0) 3085 + init->level[1] + (init->level[1] ? 1 : 0) 3086 + init->level[2] + (init->level[2] ? 1 : 0); 3087 3088 (*path)->path->manager = NULL; 3089 (*path)->path->loader = NULL; 3090 (*path)->path->conf_file = NULL; 3091 3092 if(ngx_add_path(cf, &(*path)->path) != NGX_OK) { 3093 return NGX_CONF_ERROR; 3094 } 3095 3096 return NGX_CONF_OK; 3097 } /* }}} */ 3098 3099 static ngx_int_t 3100 ngx_http_write_request_body(ngx_http_request_t *r) 3101 { 3102 ssize_t n; 3103 ngx_chain_t *cl; 3104 ngx_temp_file_t *tf; 3105 ngx_http_request_body_t *rb; 3106 ngx_http_core_loc_conf_t *clcf; 3107 3108 rb = r->request_body; 3109 3110 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 3111 "http write client request body, bufs %p", rb->bufs); 3112 3113 if (rb->temp_file == NULL) { 3114 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); 3115 if (tf == NULL) { 3116 return NGX_ERROR; 3117 } 3118 3119 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 3120 3121 tf->file.fd = NGX_INVALID_FILE; 3122 tf->file.log = r->connection->log; 3123 tf->path = clcf->client_body_temp_path; 3124 tf->pool = r->pool; 3125 tf->warn = "a client request body is buffered to a temporary file"; 3126 tf->log_level = r->request_body_file_log_level; 3127 tf->persistent = r->request_body_in_persistent_file; 3128 tf->clean = r->request_body_in_clean_file; 3129 3130 if (r->request_body_file_group_access) { 3131 tf->access = 0660; 3132 } 3133 3134 rb->temp_file = tf; 3135 3136 if (rb->bufs == NULL) { 3137 /* empty body with r->request_body_in_file_only */ 3138 3139 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, 3140 tf->persistent, tf->clean, tf->access) 3141 != NGX_OK) 3142 { 3143 return NGX_ERROR; 3144 } 3145 3146 return NGX_OK; 3147 } 3148 } 3149 3150 if (rb->bufs == NULL) { 3151 return NGX_OK; 3152 } 3153 3154 n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs); 3155 3156 /* TODO: n == 0 or not complete and level event */ 3157 3158 if (n == NGX_ERROR) { 3159 return NGX_ERROR; 3160 } 3161 3162 rb->temp_file->offset += n; 3163 3164 /* mark all buffers as written */ 3165 3166 for (cl = rb->bufs; cl; cl = cl->next) { 3167 cl->buf->pos = cl->buf->last; 3168 } 3169 3170 rb->bufs = NULL; 3171 3172 return NGX_OK; 3173 } 3174 3175 static ngx_int_t 3176 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 3177 { 3178 if (r->headers_in.chunked) { 3179 return ngx_http_request_body_chunked_filter(r, in); 3180 3181 } else { 3182 return ngx_http_request_body_length_filter(r, in); 3183 } 3184 } 3185 3186 static ngx_int_t 3187 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) 3188 { 3189 #if (NGX_DEBUG) 3190 ngx_chain_t *cl; 3191 #endif 3192 ngx_http_request_body_t *rb; 3193 3194 rb = r->request_body; 3195 3196 #if (NGX_DEBUG) 3197 3198 for (cl = rb->bufs; cl; cl = cl->next) { 3199 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, 3200 "http body old buf t:%d f:%d %p, pos %p, size: %z " 3201 "file: %O, size: %z", 3202 cl->buf->temporary, cl->buf->in_file, 3203 cl->buf->start, cl->buf->pos, 3204 cl->buf->last - cl->buf->pos, 3205 cl->buf->file_pos, 3206 cl->buf->file_last - cl->buf->file_pos); 3207 } 3208 3209 for (cl = in; cl; cl = cl->next) { 3210 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, 3211 "http body new buf t:%d f:%d %p, pos %p, size: %z " 3212 "file: %O, size: %z", 3213 cl->buf->temporary, cl->buf->in_file, 3214 cl->buf->start, cl->buf->pos, 3215 cl->buf->last - cl->buf->pos, 3216 cl->buf->file_pos, 3217 cl->buf->file_last - cl->buf->file_pos); 3218 } 3219 3220 #endif 3221 3222 /* TODO: coalesce neighbouring buffers */ 3223 3224 if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { 3225 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3226 } 3227 3228 return NGX_OK; 3229 } 3230 3231 3232 static ngx_int_t 3233 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) 3234 { 3235 size_t size; 3236 ngx_int_t rc; 3237 ngx_buf_t *b; 3238 ngx_chain_t *cl, *tl, *out, **ll; 3239 ngx_http_request_body_t *rb; 3240 3241 rb = r->request_body; 3242 3243 if (rb->rest == -1) { 3244 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 3245 "http request body content length filter"); 3246 3247 rb->rest = r->headers_in.content_length_n; 3248 } 3249 3250 out = NULL; 3251 ll = &out; 3252 3253 for (cl = in; cl; cl = cl->next) { 3254 3255 tl = ngx_chain_get_free_buf(r->pool, &rb->free); 3256 if (tl == NULL) { 3257 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3258 } 3259 3260 b = tl->buf; 3261 3262 ngx_memzero(b, sizeof(ngx_buf_t)); 3263 3264 b->temporary = 1; 3265 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; 3266 b->start = cl->buf->start; 3267 b->pos = cl->buf->pos; 3268 b->last = cl->buf->last; 3269 b->end = cl->buf->end; 3270 3271 size = cl->buf->last - cl->buf->pos; 3272 3273 if ((off_t) size < rb->rest) { 3274 cl->buf->pos = cl->buf->last; 3275 rb->rest -= size; 3276 3277 } else { 3278 cl->buf->pos += rb->rest; 3279 rb->rest = 0; 3280 b->last = cl->buf->pos; 3281 b->last_buf = 1; 3282 } 3283 3284 *ll = tl; 3285 ll = &tl->next; 3286 } 3287 3288 rc = ngx_http_request_body_save_filter(r, out); 3289 3290 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, 3291 (ngx_buf_tag_t) &ngx_http_read_client_request_body); 3292 3293 return rc; 3294 } 3295 3296 static ngx_int_t 3297 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) 3298 { 3299 size_t size; 3300 ngx_int_t rc; 3301 ngx_buf_t *b; 3302 ngx_chain_t *cl, *out, *tl, **ll; 3303 ngx_http_request_body_t *rb; 3304 ngx_http_core_loc_conf_t *clcf; 3305 3306 rb = r->request_body; 3307 3308 if (rb->rest == -1) { 3309 3310 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 3311 "http request body chunked filter"); 3312 3313 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); 3314 if (rb->chunked == NULL) { 3315 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3316 } 3317 3318 r->headers_in.content_length_n = 0; 3319 rb->rest = 3; 3320 } 3321 3322 out = NULL; 3323 ll = &out; 3324 3325 for (cl = in; cl; cl = cl->next) { 3326 3327 for ( ;; ) { 3328 3329 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, 3330 "http body chunked buf " 3331 "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z", 3332 cl->buf->temporary, cl->buf->in_file, 3333 cl->buf->start, cl->buf->pos, 3334 cl->buf->last - cl->buf->pos, 3335 cl->buf->file_pos, 3336 cl->buf->file_last - cl->buf->file_pos); 3337 3338 rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked); 3339 3340 if (rc == NGX_OK) { 3341 3342 /* a chunk has been parsed successfully */ 3343 3344 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 3345 3346 if (clcf->client_max_body_size 3347 && clcf->client_max_body_size 3348 < r->headers_in.content_length_n + rb->chunked->size) 3349 { 3350 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 3351 "client intended to send too large chunked " 3352 "body: %O bytes", 3353 r->headers_in.content_length_n 3354 + rb->chunked->size); 3355 3356 r->lingering_close = 1; 3357 3358 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; 3359 } 3360 3361 tl = ngx_chain_get_free_buf(r->pool, &rb->free); 3362 if (tl == NULL) { 3363 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3364 } 3365 3366 b = tl->buf; 3367 3368 ngx_memzero(b, sizeof(ngx_buf_t)); 3369 3370 b->temporary = 1; 3371 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; 3372 b->start = cl->buf->start; 3373 b->pos = cl->buf->pos; 3374 b->last = cl->buf->last; 3375 b->end = cl->buf->end; 3376 3377 *ll = tl; 3378 ll = &tl->next; 3379 3380 size = cl->buf->last - cl->buf->pos; 3381 3382 if ((off_t) size > rb->chunked->size) { 3383 cl->buf->pos += rb->chunked->size; 3384 r->headers_in.content_length_n += rb->chunked->size; 3385 rb->chunked->size = 0; 3386 3387 } else { 3388 rb->chunked->size -= size; 3389 r->headers_in.content_length_n += size; 3390 cl->buf->pos = cl->buf->last; 3391 } 3392 3393 b->last = cl->buf->pos; 3394 3395 continue; 3396 } 3397 3398 if (rc == NGX_DONE) { 3399 3400 /* a whole response has been parsed successfully */ 3401 3402 rb->rest = 0; 3403 3404 tl = ngx_chain_get_free_buf(r->pool, &rb->free); 3405 if (tl == NULL) { 3406 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3407 } 3408 3409 b = tl->buf; 3410 3411 ngx_memzero(b, sizeof(ngx_buf_t)); 3412 3413 b->last_buf = 1; 3414 3415 *ll = tl; 3416 ll = &tl->next; 3417 3418 break; 3419 } 3420 3421 if (rc == NGX_AGAIN) { 3422 3423 /* set rb->rest, amount of data we want to see next time */ 3424 3425 rb->rest = rb->chunked->length; 3426 3427 break; 3428 } 3429 3430 /* invalid */ 3431 3432 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 3433 "client sent invalid chunked body"); 3434 3435 return NGX_HTTP_BAD_REQUEST; 3436 } 3437 } 3438 3439 rc = ngx_http_request_body_save_filter(r, out); 3440 3441 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, 3442 (ngx_buf_tag_t) &ngx_http_read_client_request_body); 3443 3444 return rc; 3445 } 3446 3447 static ngx_int_t 3448 ngx_http_do_read_client_request_body(ngx_http_request_t *r) 3449 { 3450 off_t rest; 3451 size_t size; 3452 ssize_t n; 3453 ngx_int_t rc; 3454 ngx_buf_t *b; 3455 ngx_chain_t *cl, out; 3456 ngx_connection_t *c; 3457 ngx_http_request_body_t *rb; 3458 ngx_http_core_loc_conf_t *clcf; 3459 3460 c = r->connection; 3461 rb = r->request_body; 3462 3463 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, 3464 "http read client request body"); 3465 3466 for ( ;; ) { 3467 for ( ;; ) { 3468 if (rb->buf->last == rb->buf->end) { 3469 3470 /* pass buffer to request body filter chain */ 3471 3472 out.buf = rb->buf; 3473 out.next = NULL; 3474 3475 rc = ngx_http_request_body_filter(r, &out); 3476 3477 if (rc != NGX_OK) { 3478 return rc; 3479 } 3480 3481 /* write to file */ 3482 3483 if (ngx_http_write_request_body(r) != NGX_OK) { 3484 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3485 } 3486 3487 /* update chains */ 3488 3489 rc = ngx_http_request_body_filter(r, NULL); 3490 3491 if (rc != NGX_OK) { 3492 return rc; 3493 } 3494 3495 if (rb->busy != NULL) { 3496 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3497 } 3498 3499 rb->buf->pos = rb->buf->start; 3500 rb->buf->last = rb->buf->start; 3501 } 3502 size = rb->buf->end - rb->buf->last; 3503 rest = rb->rest - (rb->buf->last - rb->buf->pos); 3504 3505 if ((off_t) size > rest) { 3506 size = (size_t) rest; 3507 } 3508 3509 n = c->recv(c, rb->buf->last, size); 3510 3511 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 3512 "http client request body recv %z", n); 3513 3514 if (n == NGX_AGAIN) { 3515 break; 3516 } 3517 3518 if (n == 0) { 3519 ngx_log_error(NGX_LOG_INFO, c->log, 0, 3520 "client prematurely closed connection"); 3521 } 3522 3523 if (n == 0 || n == NGX_ERROR) { 3524 c->error = 1; 3525 return NGX_HTTP_BAD_REQUEST; 3526 } 3527 3528 rb->buf->last += n; 3529 r->request_length += n; 3530 3531 if (n == rest) { 3532 /* pass buffer to request body filter chain */ 3533 3534 out.buf = rb->buf; 3535 out.next = NULL; 3536 3537 rc = ngx_http_request_body_filter(r, &out); 3538 3539 if (rc != NGX_OK) { 3540 return rc; 3541 } 3542 } 3543 3544 if (rb->rest == 0) { 3545 break; 3546 } 3547 3548 if (rb->buf->last < rb->buf->end) { 3549 break; 3550 } 3551 } 3552 3553 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 3554 "http client request body rest %O", rb->rest); 3555 if (rb->rest == 0) { 3556 break; 3557 } 3558 3559 if (!c->read->ready) { 3560 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 3561 ngx_add_timer(c->read, clcf->client_body_timeout); 3562 3563 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 3564 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3565 } 3566 3567 return NGX_AGAIN; 3568 } 3569 } 3570 3571 if (c->read->timer_set) { 3572 ngx_del_timer(c->read); 3573 } 3574 3575 if (rb->temp_file || r->request_body_in_file_only) { 3576 3577 /* save the last part */ 3578 3579 if (ngx_http_write_request_body(r) != NGX_OK) { 3580 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3581 } 3582 3583 cl = ngx_chain_get_free_buf(r->pool, &rb->free); 3584 if (cl == NULL) { 3585 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3586 } 3587 3588 b = cl->buf; 3589 3590 ngx_memzero(b, sizeof(ngx_buf_t)); 3591 3592 b->in_file = 1; 3593 b->file_last = rb->temp_file->file.offset; 3594 b->file = &rb->temp_file->file; 3595 3596 rb->bufs = cl; 3597 } 3598 3599 r->read_event_handler = ngx_http_block_reading; 3600 3601 rb->post_handler(r); 3602 3603 return NGX_OK; 3604 } 3605 3606 3607 static void 3608 ngx_http_read_client_request_body_handler(ngx_http_request_t *r) 3609 { 3610 ngx_int_t rc; 3611 3612 if (r->connection->read->timedout) { 3613 r->connection->timedout = 1; 3614 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); 3615 return; 3616 } 3617 3618 rc = ngx_http_do_read_client_request_body(r); 3619 3620 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { 3621 ngx_http_finalize_request(r, rc); 3622 } 3623 } 3624 3625 2526 3626 ngx_int_t /* {{{ ngx_http_read_upload_client_request_body */ 2527 3627 ngx_http_read_upload_client_request_body(ngx_http_request_t *r) { 2528 3628 ssize_t size, preread; … … 2625 3725 2626 3726 /* the whole request body may be placed in r->header_in */ 2627 3727 2628 rb-> to_write = rb->bufs;2629 2630 r-> read_event_handler = ngx_http_read_upload_client_request_body_handler;3728 rb->buf = r->header_in; 3729 r->read_event_handler = ngx_http_read_client_request_body_handler; 3730 r->write_event_handler = ngx_http_request_empty_handler; 2631 3731 2632 3732 return ngx_http_do_read_upload_client_request_body(r); 2633 3733 } … … 2684 3784 2685 3785 *next = cl; 2686 3786 2687 rb->to_write = rb->bufs; 3787 /* 3788 * rb->to_write = rb->bufs; 3789 */ 2688 3790 2689 3791 r->read_event_handler = ngx_http_read_upload_client_request_body_handler; 2690 3792 … … 2766 3868 for ( ;; ) { 2767 3869 if (rb->buf->last == rb->buf->end) { 2768 3870 2769 rc = ngx_http_process_request_body(r, rb->to_write);3871 rc = ngx_http_process_request_body(r, rb->bufs); 2770 3872 2771 3873 switch(rc) { 2772 3874 case NGX_OK: … … 2781 3883 default: 2782 3884 return NGX_HTTP_INTERNAL_SERVER_ERROR; 2783 3885 } 2784 2785 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; 3886 /* 3887 * rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; 3888 */ 2786 3889 rb->buf->last = rb->buf->start; 2787 3890 } 2788 3891 … … 2874 3977 ngx_del_timer(c->read); 2875 3978 } 2876 3979 2877 rc = ngx_http_process_request_body(r, rb-> to_write);3980 rc = ngx_http_process_request_body(r, rb->bufs); 2878 3981 2879 3982 switch(rc) { 2880 3983 case NGX_OK: … … 3299 4402 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; 3300 4403 } 3301 4404 4405 if( (upload_ctx->content_range_n.end - upload_ctx->content_range_n.start + 1) 4406 != headers_in->content_length_n) 4407 { 4408 ngx_log_error(NGX_LOG_ERR, upload_ctx->log, 0, 4409 "range length is not equal to content length"); 4410 return NGX_HTTP_RANGE_NOT_SATISFIABLE; 4411 } 4412 3302 4413 upload_ctx->partial_content = 1; 3303 4414 } 3304 4415 } … … 3436 4547 return NGX_ERROR; 3437 4548 } 3438 4549 3439 if(range_n->start > =range_n->end || range_n->start >= range_n->total3440 || range_n->end > range_n->total)4550 if(range_n->start > range_n->end || range_n->start >= range_n->total 4551 || range_n->end >= range_n->total) 3441 4552 { 3442 4553 return NGX_ERROR; 3443 4554 } … … 3673 4784 } 3674 4785 } /* }}} */ 3675 4786 4787 static ngx_int_t /* {{{ */ 4788 ngx_http_upload_test_expect(ngx_http_request_t *r) 4789 { 4790 ngx_int_t n; 4791 ngx_str_t *expect; 4792 4793 if (r->expect_tested 4794 || r->headers_in.expect == NULL 4795 || r->http_version < NGX_HTTP_VERSION_11) 4796 { 4797 return NGX_OK; 4798 } 4799 4800 r->expect_tested = 1; 4801 4802 expect = &r->headers_in.expect->value; 4803 4804 if (expect->len != sizeof("100-continue") - 1 4805 || ngx_strncasecmp(expect->data, (u_char *) "100-continue", 4806 sizeof("100-continue") - 1) 4807 != 0) 4808 { 4809 return NGX_OK; 4810 } 4811 4812 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 4813 "send 100 Continue"); 4814 4815 n = r->connection->send(r->connection, 4816 (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF, 4817 sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1); 4818 4819 if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) { 4820 return NGX_OK; 4821 } 4822 4823 /* we assume that such small packet should be send successfully */ 4824 4825 return NGX_ERROR; 4826 } /* }}} */