Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 1 | |
Igor Sysoev | 1d8d9ee | 2003-04-28 15:06:39 +0000 | [diff] [blame] | 2 | #include <ngx_config.h> |
| 3 | #include <ngx_core.h> |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 4 | #include <ngx_event.h> |
Igor Sysoev | 1d8d9ee | 2003-04-28 15:06:39 +0000 | [diff] [blame] | 5 | #include <ngx_http.h> |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 6 | |
| 7 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 8 | static void ngx_http_read_client_request_body_handler(ngx_event_t *rev); |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 9 | static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 10 | |
| 11 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 12 | ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r) |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 13 | { |
Igor Sysoev | dbb2776 | 2004-04-01 16:20:53 +0000 | [diff] [blame^] | 14 | ssize_t size; |
| 15 | ngx_hunk_t *h; |
| 16 | ngx_chain_t *cl; |
| 17 | ngx_http_core_loc_conf_t *clcf; |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 18 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 19 | size = r->header_in->last - r->header_in->pos; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 20 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 21 | if (size) { |
Igor Sysoev | 14f02ed | 2004-03-26 16:13:01 +0000 | [diff] [blame] | 22 | |
| 23 | /* there is the pre-read part of the request body */ |
| 24 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 25 | ngx_test_null(h, ngx_calloc_hunk(r->pool), |
| 26 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 27 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 28 | h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP; |
| 29 | h->start = h->pos = r->header_in->pos; |
| 30 | h->end = h->last = r->header_in->last; |
| 31 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 32 | ngx_alloc_link_and_set_hunk(r->request_body->bufs, h, r->pool, |
| 33 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 34 | |
| 35 | if (size >= r->headers_in.content_length_n) { |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 36 | |
Igor Sysoev | 14f02ed | 2004-03-26 16:13:01 +0000 | [diff] [blame] | 37 | /* the whole request body was pre-read */ |
| 38 | |
| 39 | r->header_in->pos += r->headers_in.content_length_n; |
Igor Sysoev | 6707ba9 | 2004-03-30 15:59:50 +0000 | [diff] [blame] | 40 | |
| 41 | r->request_body->handler(r->request_body->data); |
| 42 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 43 | return NGX_OK; |
| 44 | } |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 45 | |
| 46 | r->header_in->pos = r->header_in->last; |
Igor Sysoev | 1d8d9ee | 2003-04-28 15:06:39 +0000 | [diff] [blame] | 47 | } |
| 48 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 49 | |
Igor Sysoev | dbb2776 | 2004-04-01 16:20:53 +0000 | [diff] [blame^] | 50 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
| 51 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 52 | r->request_body->rest = r->headers_in.content_length_n - size; |
Igor Sysoev | 14f02ed | 2004-03-26 16:13:01 +0000 | [diff] [blame] | 53 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 54 | if (r->request_body->rest |
Igor Sysoev | dbb2776 | 2004-04-01 16:20:53 +0000 | [diff] [blame^] | 55 | < clcf->client_body_buffer_size |
| 56 | + (clcf->client_body_buffer_size >> 2)) |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 57 | { |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 58 | size = r->request_body->rest; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 59 | |
| 60 | } else { |
Igor Sysoev | dbb2776 | 2004-04-01 16:20:53 +0000 | [diff] [blame^] | 61 | size = clcf->client_body_buffer_size; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 62 | } |
| 63 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 64 | ngx_test_null(r->request_body->buf, ngx_create_temp_hunk(r->pool, size), |
| 65 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 66 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 67 | ngx_alloc_link_and_set_hunk(cl, r->request_body->buf, r->pool, |
| 68 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 69 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 70 | if (r->request_body->bufs) { |
| 71 | r->request_body->bufs->next = cl; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 72 | |
| 73 | } else { |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 74 | r->request_body->bufs = cl; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 75 | } |
| 76 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 77 | r->connection->read->event_handler = |
| 78 | ngx_http_read_client_request_body_handler; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 79 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 80 | return ngx_http_do_read_client_request_body(r); |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 84 | static void ngx_http_read_client_request_body_handler(ngx_event_t *rev) |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 85 | { |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 86 | ngx_int_t rc; |
| 87 | ngx_connection_t *c; |
| 88 | ngx_http_request_t *r; |
| 89 | |
| 90 | c = rev->data; |
| 91 | r = c->data; |
| 92 | |
Igor Sysoev | 6707ba9 | 2004-03-30 15:59:50 +0000 | [diff] [blame] | 93 | if (rev->timedout) { |
| 94 | ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); |
| 95 | return; |
| 96 | } |
| 97 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 98 | rc = ngx_http_do_read_client_request_body(r); |
| 99 | |
| 100 | if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { |
| 101 | ngx_http_finalize_request(r, rc); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | |
| 106 | static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) |
| 107 | { |
Igor Sysoev | 10a543a | 2004-03-16 07:10:12 +0000 | [diff] [blame] | 108 | size_t size; |
| 109 | ssize_t n; |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 110 | ngx_hunk_t *h; |
| 111 | ngx_connection_t *c; |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 112 | ngx_http_core_loc_conf_t *clcf; |
Igor Sysoev | 1d8d9ee | 2003-04-28 15:06:39 +0000 | [diff] [blame] | 113 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 114 | c = r->connection; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 115 | |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 116 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
| 117 | "http read client request body"); |
| 118 | |
| 119 | for ( ;; ) { |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 120 | if (r->request_body->buf->last == r->request_body->buf->end) { |
| 121 | n = ngx_write_chain_to_temp_file(r->request_body->temp_file, |
| 122 | r->request_body->bufs->next ? r->request_body->bufs->next: |
| 123 | r->request_body->bufs); |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 124 | |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 125 | /* TODO: n == 0 or not complete and level event */ |
| 126 | |
| 127 | if (n == NGX_ERROR) { |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 128 | return NGX_HTTP_INTERNAL_SERVER_ERROR; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 129 | } |
| 130 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 131 | r->request_body->temp_file->offset += n; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 132 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 133 | r->request_body->buf->pos = r->request_body->buf->start; |
| 134 | r->request_body->buf->last = r->request_body->buf->start; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 135 | } |
| 136 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 137 | size = r->request_body->buf->end - r->request_body->buf->last; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 138 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 139 | if (size > r->request_body->rest) { |
| 140 | size = r->request_body->rest; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 141 | } |
| 142 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 143 | n = ngx_recv(c, r->request_body->buf->last, size); |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 144 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 145 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
| 146 | "http client request body recv " SIZE_T_FMT, n); |
| 147 | |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 148 | if (n == NGX_AGAIN) { |
| 149 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 150 | ngx_add_timer(c->read, clcf->client_body_timeout); |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 151 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 152 | if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { |
| 153 | return NGX_HTTP_INTERNAL_SERVER_ERROR; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 154 | } |
| 155 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 156 | return NGX_AGAIN; |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 157 | } |
| 158 | |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 159 | if (n == 0) { |
| 160 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
| 161 | "client closed prematurely connection"); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 162 | } |
| 163 | |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 164 | if (n == 0 || n == NGX_ERROR) { |
Igor Sysoev | 89690bf | 2004-03-23 06:01:52 +0000 | [diff] [blame] | 165 | r->closed = 1; |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 166 | return NGX_HTTP_BAD_REQUEST; |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 167 | } |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 168 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 169 | r->request_body->buf->last += n; |
| 170 | r->request_body->rest -= n; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 171 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 172 | if (r->request_body->rest == 0) { |
Igor Sysoev | 89690bf | 2004-03-23 06:01:52 +0000 | [diff] [blame] | 173 | break; |
| 174 | } |
| 175 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 176 | if (r->request_body->buf->last < r->request_body->buf->end) { |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 177 | break; |
| 178 | } |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 179 | } |
| 180 | |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 181 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 182 | "http client request body rest " SIZE_T_FMT, |
| 183 | r->request_body->rest); |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 184 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 185 | if (r->request_body->rest) { |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 186 | return NGX_AGAIN; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 187 | } |
| 188 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 189 | if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 190 | |
| 191 | /* save the last part */ |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 192 | n = ngx_write_chain_to_temp_file(r->request_body->temp_file, |
| 193 | r->request_body->bufs->next ? r->request_body->bufs->next: |
| 194 | r->request_body->bufs); |
Igor Sysoev | da85f7f | 2004-03-16 21:26:01 +0000 | [diff] [blame] | 195 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 196 | /* TODO: n == 0 or not complete and level event */ |
| 197 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 198 | if (n == NGX_ERROR) { |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 199 | return NGX_HTTP_INTERNAL_SERVER_ERROR; |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame] | 200 | } |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 201 | |
| 202 | h = ngx_calloc_hunk(r->pool); |
| 203 | if (h == NULL) { |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 204 | return NGX_HTTP_INTERNAL_SERVER_ERROR; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | h->type = NGX_HUNK_FILE; |
| 208 | h->file_pos = 0; |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 209 | h->file_last = r->request_body->temp_file->file.offset; |
| 210 | h->file = &r->request_body->temp_file->file; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 211 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 212 | if (r->request_body->bufs->next) { |
| 213 | r->request_body->bufs->next->hunk = h; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 214 | |
| 215 | } else { |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 216 | r->request_body->bufs->hunk = h; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 217 | } |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 218 | } |
| 219 | |
Igor Sysoev | 11dbe97 | 2004-03-29 17:43:58 +0000 | [diff] [blame] | 220 | r->request_body->handler(r->request_body->data); |
Igor Sysoev | ae02c19 | 2004-03-19 05:25:53 +0000 | [diff] [blame] | 221 | |
| 222 | return NGX_OK; |
Igor Sysoev | a09f08d | 2003-04-25 14:43:13 +0000 | [diff] [blame] | 223 | } |