changeset 82:fccdb921e8b8

nginx-0.0.1-2003-04-25-18:43:13 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 25 Apr 2003 14:43:13 +0000
parents b2ece31c976a
children a7e45c45a95c
files src/core/ngx_auto_config.h src/http/modules/proxy/ngx_http_event_proxy_handler.c src/http/modules/proxy/ngx_http_event_proxy_handler.h src/http/ngx_http.h src/http/ngx_http_event.c src/http/ngx_http_request_body.c
diffstat 6 files changed, 288 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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;
--- 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;
--- 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;
--- 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;
 }
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;
+    }
+}