| |
| #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_HTTP_INTERNAL_SERVER_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_HTTP_INTERNAL_SERVER_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_HTTP_INTERNAL_SERVER_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_HTTP_INTERNAL_SERVER_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); |
| } |