| #include <ngx_config.h> | |
| #include <ngx_core.h> | |
| #include <ngx_event.h> | |
| #include <ngx_http.h> | |
| static void ngx_http_read_client_request_body_handler(ngx_event_t *rev); | |
| int ngx_http_read_client_request_body(ngx_http_request_t *r, | |
| int request_buffer_size) | |
| { | |
| ssize_t size; | |
| ngx_hunk_t *h; | |
| ngx_chain_t *cl; | |
| size = r->header_in->last - r->header_in->pos; | |
| if (size) { | |
| ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); | |
| h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP; | |
| h->start = h->pos = r->header_in->pos; | |
| h->end = h->last = r->header_in->last; | |
| ngx_alloc_link_and_set_hunk(r->request_hunks, h, r->pool, NGX_ERROR); | |
| if (size >= r->headers_in.content_length_n) { | |
| r->header_in->pos += r->headers_in.content_length_n; | |
| return NGX_OK; | |
| } | |
| r->header_in->pos = r->header_in->last; | |
| } | |
| r->request_body_len = r->headers_in.content_length_n - size; | |
| if (r->request_body_len < request_buffer_size + (request_buffer_size >> 2)) | |
| { | |
| size = r->request_body_len; | |
| } else { | |
| size = request_buffer_size; | |
| } | |
| ngx_test_null(r->request_body_hunk, ngx_create_temp_hunk(r->pool, size), | |
| NGX_ERROR); | |
| r->connection->read->event_handler = | |
| ngx_http_read_client_request_body_handler; | |
| ngx_http_read_client_request_body_handler(r->connection->read); | |
| ngx_alloc_link_and_set_hunk(cl, r->request_body_hunk, r->pool, | |
| NGX_ERROR); | |
| if (r->request_hunks) { | |
| r->request_hunks->next = cl; | |
| } else { | |
| r->request_hunks = cl; | |
| } | |
| if (r->request_body_len) { | |
| return NGX_AGAIN; | |
| } | |
| return NGX_OK; | |
| } | |
| static void ngx_http_read_client_request_body_handler(ngx_event_t *rev) | |
| { | |
| ssize_t n, size; | |
| ngx_hunk_t *h; | |
| ngx_connection_t *c; | |
| ngx_http_request_t *r; | |
| ngx_http_core_loc_conf_t *clcf; | |
| c = rev->data; | |
| r = c->data; | |
| if (r->request_body_hunk->end - r->request_body_hunk->last == 0) { | |
| n = ngx_write_chain_to_temp_file(r->temp_file, | |
| r->request_hunks->next ? r->request_hunks->next: | |
| r->request_hunks); | |
| /* TODO: n == 0 or not complete and level event */ | |
| if (n == NGX_ERROR) { | |
| ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
| return; | |
| } | |
| r->temp_file->offset += n; | |
| r->request_body_hunk->pos = r->request_body_hunk->start; | |
| r->request_body_hunk->last = r->request_body_hunk->start; | |
| } | |
| size = r->request_body_hunk->end - r->request_body_hunk->last; | |
| if (size > r->request_body_len) { | |
| size = r->request_body_len; | |
| } | |
| n = ngx_recv(c, r->request_body_hunk->last, size); | |
| if (n == NGX_AGAIN) { | |
| clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
| ngx_add_timer(rev, clcf->client_body_timeout); | |
| if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { | |
| ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
| } | |
| return; | |
| } | |
| if (n == 0) { | |
| ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
| "client closed prematurely connection"); | |
| } | |
| if (n == 0 || n == NGX_ERROR) { | |
| ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
| return; | |
| } | |
| r->request_body_hunk->last += n; | |
| r->request_body_len -= n; | |
| if (r->request_body_len) { | |
| return; | |
| } | |
| if (r->temp_file->file.fd != NGX_INVALID_FILE) { | |
| /* save the last part */ | |
| n = ngx_write_chain_to_temp_file(r->temp_file, | |
| r->request_hunks->next ? r->request_hunks->next: | |
| r->request_hunks); | |
| /* TODO: n == 0 or not complete and level event */ | |
| if (n == NGX_ERROR) { | |
| ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
| return; | |
| } | |
| h = ngx_calloc_hunk(r->pool); | |
| if (h == NULL) { | |
| ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
| return; | |
| } | |
| h->type = NGX_HUNK_FILE; | |
| h->file_pos = 0; | |
| h->file_last = r->temp_file->file.offset; | |
| h->file = &r->temp_file->file; | |
| if (r->request_hunks->next) { | |
| r->request_hunks->next->hunk = h; | |
| } else { | |
| r->request_hunks->hunk = h; | |
| } | |
| } | |
| r->request_body_handler(r->data); | |
| } |