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