# HG changeset patch # User Igor Sysoev # Date 1051281793 0 # Node ID fccdb921e8b8484eaed76757a520b833b770e0f3 # Parent b2ece31c976a67def9e77afc4372fc537d74b81b nginx-0.0.1-2003-04-25-18:43:13 import diff --git a/src/core/ngx_auto_config.h b/src/core/ngx_auto_config.h --- a/src/core/ngx_auto_config.h +++ b/src/core/ngx_auto_config.h @@ -2,3 +2,6 @@ #ifndef OFF_EQUAL_PTR #define OFF_EQUAL_PTR 0 #endif + + +#define NGX_PAGE_SIZE 4096 diff --git a/src/http/modules/proxy/ngx_http_event_proxy_handler.c b/src/http/modules/proxy/ngx_http_event_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_event_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_event_proxy_handler.c @@ -24,6 +24,7 @@ typedef struct { static int ngx_http_proxy_handler(ngx_http_request_t *r); +static int ngx_http_proxy_read_client_body(ngx_http_proxy_ctx_t *p); static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); static int ngx_http_proxy_process_upstream(ngx_http_proxy_ctx_t *p, ngx_event_t *ev); @@ -182,7 +183,11 @@ static int ngx_http_proxy_handler(ngx_ht p->method = r->method; p->headers_in.headers = ngx_create_table(r->pool, 10); - /* TODO: read a client's body */ + if (r->headers_in.content_length_n > 0) { + if (ngx_http_proxy_read_client_body(p) == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } chain = ngx_http_proxy_create_request(p); if (chain == NULL) { @@ -204,6 +209,53 @@ static int ngx_http_proxy_handler(ngx_ht } +static int ngx_http_proxy_read_client_body(ngx_http_proxy_ctx_t *p) +{ + int size, first_part; + ngx_hunk_t *h; + ngx_http_request_t *r; + + r = p->request; + + first_part = r->header_in->last - r->header_in->pos; + + if (first_part > r->headers_in.content_length_n) { + first_part = r->headers_in.content_length_n; + size = 0; + + } else { + size = r->headers_in.content_length_n - first_part; + if (size > p->lcf->client_request_buffer_size) { + size = p->lcf->client_request_buffer_size; + + } else if (size > NGX_PAGE_SIZE) { + size = ((size + NGX_PAGE_SIZE) / NGX_PAGE_SIZE) * NGX_PAGE_SIZE; + } + + if (size) { + ngx_test_null(p->client_request_hunk, ngx_palloc(r->pool, size), + NGX_ERROR); + } + } + + if (first_part) { + ngx_test_null(h, ngx_alloc_hunk(r->pool), NGX_ERROR); + + h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP; + h->pos = h->start = h->pre_start = r->header_in->pos; + h->last = h->end = h->post_end = r->header_in->pos + first_part; + h->file_pos = h->file_last = 0; + h->file = NULL; + h->shadow = NULL; + h->tag = 0; + + p->client_first_part_hunk = h; + } + + return NGX_OK; +} + + static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) { int i; diff --git a/src/http/modules/proxy/ngx_http_event_proxy_handler.h b/src/http/modules/proxy/ngx_http_event_proxy_handler.h --- a/src/http/modules/proxy/ngx_http_event_proxy_handler.h +++ b/src/http/modules/proxy/ngx_http_event_proxy_handler.h @@ -61,6 +61,7 @@ typedef struct { ngx_http_proxy_upstreams_t *upstreams; ngx_http_proxy_upstream_url_t *upstream_url; + int client_request_buffer_size; int rcvbuf; int conn_pool_size; int connect_timeout; @@ -99,6 +100,7 @@ typedef struct ngx_http_proxy_ctx_s ngx struct ngx_http_proxy_ctx_s { ngx_event_proxy_t *event_proxy; + ngx_chain_t *in_hunks; ngx_chain_t *last_in_hunk; @@ -109,8 +111,12 @@ struct ngx_http_proxy_ctx_s { ngx_chain_t *free_hunks; + ngx_chain_t *request_hunks; + ngx_hunk_t *client_request_hunk; + ngx_hunk_t *client_first_part_hunk; + ngx_connection_t *connection; ngx_http_request_t *request; ngx_http_proxy_headers_in_t headers_in; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -27,14 +27,15 @@ #define NGX_HTTP_CONN_KEEP_ALIVE 1 -#define NGX_HTTP_PARSE_HEADER_DONE 1 -#define NGX_HTTP_PARSE_INVALID_METHOD 10 -#define NGX_HTTP_PARSE_INVALID_REQUEST 11 -#define NGX_HTTP_PARSE_TOO_LONG_URI 12 -#define NGX_HTTP_PARSE_INVALID_HEAD 13 -#define NGX_HTTP_PARSE_INVALID_HEADER 14 -#define NGX_HTTP_PARSE_TOO_LONG_HEADER 15 -#define NGX_HTTP_PARSE_NO_HOST_HEADER 16 +#define NGX_HTTP_PARSE_HEADER_DONE 1 +#define NGX_HTTP_PARSE_INVALID_METHOD 10 +#define NGX_HTTP_PARSE_INVALID_REQUEST 11 +#define NGX_HTTP_PARSE_TOO_LONG_URI 12 +#define NGX_HTTP_PARSE_INVALID_HEAD 13 +#define NGX_HTTP_PARSE_INVALID_HEADER 14 +#define NGX_HTTP_PARSE_TOO_LONG_HEADER 15 +#define NGX_HTTP_PARSE_NO_HOST_HEADER 16 +#define NGX_HTTP_PARSE_INVALID_CL_HEADER 17 #define NGX_HTTP_OK 200 @@ -70,10 +71,12 @@ typedef struct { typedef struct { size_t host_name_len; + ssize_t content_length_n; ngx_table_elt_t *host; ngx_table_elt_t *connection; ngx_table_elt_t *if_modified_since; + ngx_table_elt_t *content_length; ngx_table_elt_t *accept_encoding; ngx_table_elt_t *user_agent; @@ -141,7 +144,6 @@ struct ngx_http_request_s { int filter; - ssize_t client_content_length; char *discarded_buffer; ngx_str_t path; diff --git a/src/http/ngx_http_event.c b/src/http/ngx_http_event.c --- a/src/http/ngx_http_event.c +++ b/src/http/ngx_http_event.c @@ -47,7 +47,8 @@ static char *header_errors[] = { "client %s sent invalid header, URL: %s", "client %s sent too long header line, URL: %s", - "client %s sent HTTP/1.1 request without \"Host\" header, URL: %s" + "client %s sent HTTP/1.1 request without \"Host\" header, URL: %s", + "client %s sent invalid \"Content-Length\" header, URL: %s" }; @@ -57,6 +58,8 @@ static ngx_http_header_t headers_in[] = { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection) }, { ngx_string("If-Modified-Since"), offsetof(ngx_http_headers_in_t, if_modified_since) }, + { ngx_string("Content-Length"), + offsetof(ngx_http_headers_in_t, content_length) }, { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent) }, @@ -169,6 +172,7 @@ static int ngx_http_init_request(ngx_eve r->srv_conf = ctx->srv_conf; r->loc_conf = ctx->loc_conf; + r->headers_in.content_length_n = -1; r->headers_out.headers = ngx_create_table(r->pool, 10); r->headers_out.content_length = -1; r->headers_out.last_modified_time = -1; @@ -531,6 +535,17 @@ static int ngx_http_process_request_head r->headers_in.host_name_len = 0; } + if (r->headers_in.content_length) { + r->headers_in.content_length_n = + ngx_atoi(r->headers_in.content_length->value.data, + r->headers_in.content_length->value.len); + if (r->headers_in.content_length_n == NGX_ERROR) { + ngx_http_header_parse_error(r, + NGX_HTTP_PARSE_INVALID_CL_HEADER); + return NGX_HTTP_BAD_REQUEST; + } + } + r->state_handler = NULL; return NGX_OK; @@ -815,7 +830,7 @@ int ngx_http_discard_body(ngx_http_reque ev->timer_set = 0; } - if (r->client_content_length) { + if (r->headers_in.content_length_n) { ev->event_handler = ngx_http_read_discarded_body; /* if blocked - read */ /* else add timer */ @@ -852,7 +867,7 @@ static int ngx_http_read_discarded_body( NGX_ERROR); } - size = r->client_content_length; + size = r->headers_in.content_length_n; if (size > lcf->discarded_buffer_size) { size = lcf->discarded_buffer_size; } @@ -866,7 +881,7 @@ static int ngx_http_read_discarded_body( return NGX_OK; } - r->client_content_length -= n; + r->headers_in.content_length_n -= n; /* XXX: what if r->client_content_length == 0 ? */ return NGX_OK; } diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_request_body.c @@ -0,0 +1,196 @@ + + + + +int ngx_http_start_read_client_body(ngx_http_proxy_ctx_t *p) +{ + int first_part, size; + ngx_hunk_t *h; + ngx_http_request_t *r; + + r = p->request; + + first_part = r->header_in->last - r->header_in->pos; + + if (first_part > r->headers_in.content_length_n) { + first_part = r->headers_in.content_length_n; + size = 0; + + } else { + size = r->headers_in.content_length_n - first_part; + if (size > p->lcf->client_request_buffer_size) { + size = p->lcf->client_request_buffer_size; + + } else if (size > NGX_PAGE_SIZE) { + size = ((size + NGX_PAGE_SIZE) / NGX_PAGE_SIZE) * NGX_PAGE_SIZE; + } + + if (size) { + ngx_test_null(p->client_request_hunk, ngx_palloc(r->pool, size), + NGX_ERROR); + } + } + + if (first_part) { + ngx_test_null(h, ngx_alloc_hunk(r->pool), NGX_ERROR); + + h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP; + h->pos = h->start = h->pre_start = r->header_in->pos; + h->last = h->end = h->post_end = r->header_in->pos + first_part; + h->file_pos = h->file_last = 0; + h->file = NULL; + h->shadow = NULL; + h->tag = 0; + + p->client_first_part_hunk = h; + } + + return NGX_OK; +} + + +int ngx_http_read_client_body(ngx_event_t *rev) +{ + + do { + if (r->header_in->last < r->header_in->end) { + rb->chain[0].hunk = r->header_in; + + if (rb->hunk) { + rb->chain[0].next = &rb->chain[1]; + rb->chain[1].hunk = rb->hunk; + rb->chain[1].next = NULL; + + } else { + rb->chain[0].next = NULL; + } + + } else { + rb->chain[0].hunk = rb->hunk; + rb->chain[0].next = NULL; + } + + n = ngx_recv_chain(c, &rb->chain); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n == NGX_AGAIN) { + return NGX_AGAIN; + } + + for (entry = &rb->chain; entry; entry = entry->next) { + size = entry->hunk->end - entry->hunk->last; + + if (n >= size) { + n -= size; + entry->hunk->last = entry->hunk->end; + + continue; + } + + entry->hunk->last += n; + + break; + } + + if (rb->hunk && rb->hunk->last == rb->hunk->end) { + if (rb->temp_file->fd == NGX_INVALID_FILE) { + rc = ngx_create_temp_file(rb->temp_file, rb->temp_path, r->pool, + rb->number, rb->random, 0); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + } + + n = ngx_write_file(rb->temp_file, rb->hunk, + rb->hunk->last - rb->hunk->pos, rb->offset); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + rb->offset += n; + rb->hunk->last = rb->hunk->pos; + } + + } while (rev->ready); + + return NGX_OK; +} + + +int ngx_init_client_request_body_chain(ngx_http_reuqest_t *r) +{ + int i; + ngx_hunk_t *h; + ngx_http_request_body_t *rb; + + rb = r->request_body; + + rb->chain[0].hunk = rb->header_out; + i = 0; + + if (r->header_in->pos < r->header_in->last) { + rb->chain[i].next = &rb->chain[i + 1]; + i++; + rb->chain[i].hunk = r->header_in; + } + + if (rb->temp_file->fd != NGX_INVALID_FILE) { + if (rb->file_hunk == NULL) { + ngx_test_null(h, ngx_alloc_hunk(r->pool), NGX_ERROR); + + h->type = NGX_HUNK_FILE; + h->pos = h->start = h->pre_start = 0; + h->last = h->end = h->post_end = 0; + h->file_pos = 0; + h->file_last = rb->offset; + h->file = rb->temp_file; + h->shadow = NULL; + h->tag = 0; + + rb->file_hunk = h; + } + + rb->chain[i].next = &rb->chain[i + 1]; + i++; + rb->chain[i].hunk = rb->file_hunk; + } + + if (rb->hunk && rb->hunk->pos < rb->hunk->last) { + rb->chain[i].next = &rb->chain[i + 1]; + i++; + rb->chain[i].hunk = h; + } + + rb->chain[i].next = NULL; + + return NGX_OK; +} + + +int ngx_reinit_client_request_body_hunks(ngx_http_reuqest_t *r) +{ + ngx_http_request_body_t *rb; + + rb = r->request_body; + + if (rb->header_in_pos) { + r->header_in->pos = rb->header_in_pos; + } + + if (rb->file_hunk) { + rb->file_hunk->file_pos = rb->file_hunk->file_start; + } + + if (rb->hunk) { + rb->hunk->pos = rb->hunk->start; + } +}