diff src/http/ngx_http_request_body.c @ 0:f0b350454894 NGINX_0_1_0

nginx 0.1.0 *) The first public version.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Oct 2004 00:00:00 +0400
parents
children 46833bd150cb
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_request_body.c
@@ -0,0 +1,227 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#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);
+static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
+
+
+ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r)
+{
+    ssize_t                    size;
+    ngx_buf_t                 *b;
+    ngx_chain_t               *cl;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    size = r->header_in->last - r->header_in->pos;
+
+    if (size) {
+
+        /* there is the pre-read part of the request body */
+
+        ngx_test_null(b, ngx_calloc_buf(r->pool),
+                      NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+        b->temporary = 1;
+        b->start = b->pos = r->header_in->pos;
+        b->end = b->last = r->header_in->last;
+
+        ngx_alloc_link_and_set_buf(r->request_body->bufs, b, r->pool,
+                                    NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+        if (size >= r->headers_in.content_length_n) {
+
+            /* the whole request body was pre-read */
+
+            r->header_in->pos += r->headers_in.content_length_n;
+
+            r->request_body->handler(r->request_body->data);
+
+            return NGX_OK;
+        }
+
+        r->header_in->pos = r->header_in->last;
+    }
+
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    r->request_body->rest = r->headers_in.content_length_n - size;
+
+    if (r->request_body->rest
+                             < clcf->client_body_buffer_size
+                                        + (clcf->client_body_buffer_size >> 2))
+    {
+        size = r->request_body->rest;
+
+    } else {
+        size = clcf->client_body_buffer_size;
+    }
+
+    ngx_test_null(r->request_body->buf, ngx_create_temp_buf(r->pool, size),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+    ngx_alloc_link_and_set_buf(cl, r->request_body->buf, r->pool,
+                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+    if (r->request_body->bufs) {
+        r->request_body->bufs->next = cl;
+
+    } else {
+        r->request_body->bufs = cl;
+    }
+
+    r->connection->read->event_handler =
+                                     ngx_http_read_client_request_body_handler;
+
+    return ngx_http_do_read_client_request_body(r);
+}
+
+
+static void ngx_http_read_client_request_body_handler(ngx_event_t *rev)
+{
+    ngx_int_t            rc;
+    ngx_connection_t    *c;
+    ngx_http_request_t  *r;
+
+    c = rev->data;
+    r = c->data;
+
+    if (rev->timedout) {
+        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+        return;
+    }
+
+    rc = ngx_http_do_read_client_request_body(r);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        ngx_http_finalize_request(r, rc);
+    }
+}
+
+
+static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r)
+{
+    size_t                     size;
+    ssize_t                    n;
+    ngx_buf_t                 *b;
+    ngx_connection_t          *c;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    c = r->connection;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http read client request body");
+
+    for ( ;; ) {
+        if (r->request_body->buf->last == r->request_body->buf->end) {
+            n = ngx_write_chain_to_temp_file(r->request_body->temp_file,
+                     r->request_body->bufs->next ? r->request_body->bufs->next:
+                                                   r->request_body->bufs);
+
+            /* TODO: n == 0 or not complete and level event */
+
+            if (n == NGX_ERROR) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            r->request_body->temp_file->offset += n;
+
+            r->request_body->buf->pos = r->request_body->buf->start;
+            r->request_body->buf->last = r->request_body->buf->start;
+        }
+
+        size = r->request_body->buf->end - r->request_body->buf->last;
+
+        if (size > r->request_body->rest) {
+            size = r->request_body->rest;
+        }
+
+        n = c->recv(c, r->request_body->buf->last, size);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http client request body recv " SIZE_T_FMT, n);
+
+        if (n == NGX_AGAIN) {
+            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+            ngx_add_timer(c->read, clcf->client_body_timeout);
+
+            if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            return NGX_AGAIN;
+        }
+
+        if (n == 0) {
+            ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                          "client closed prematurely connection");
+        }
+
+        if (n == 0 || n == NGX_ERROR) {
+            r->closed = 1;
+            return NGX_HTTP_BAD_REQUEST;
+        }
+
+        r->request_body->buf->last += n;
+        r->request_body->rest -= n;
+
+        if (r->request_body->rest == 0) {
+            break;
+        }
+
+        if (r->request_body->buf->last < r->request_body->buf->end) {
+            break;
+        }
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http client request body rest " SIZE_T_FMT,
+                   r->request_body->rest);
+
+    if (r->request_body->rest) {
+        return NGX_AGAIN;
+    }
+
+    if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) {
+
+        /* save the last part */
+        n = ngx_write_chain_to_temp_file(r->request_body->temp_file,
+                     r->request_body->bufs->next ? r->request_body->bufs->next:
+                                                   r->request_body->bufs);
+
+        /* TODO: n == 0 or not complete and level event */
+
+        if (n == NGX_ERROR) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        if (!(b = ngx_calloc_buf(r->pool))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        b->in_file = 1;
+        b->file_pos = 0;
+        b->file_last = r->request_body->temp_file->file.offset;
+        b->file = &r->request_body->temp_file->file;
+
+        if (r->request_body->bufs->next) {
+            r->request_body->bufs->next->buf = b;
+
+        } else {
+            r->request_body->bufs->buf = b;
+        }
+    }
+
+    r->request_body->handler(r->request_body->data);
+
+    return NGX_OK;
+}