Mercurial > hg > nginx
comparison src/http/modules/proxy/ngx_http_proxy_handler.c @ 137:2a615b036870
nginx-0.0.1-2003-10-03-19:50:53 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 03 Oct 2003 15:50:53 +0000 |
parents | da00cde00e8a |
children | 3b168e12bd2d |
comparison
equal
deleted
inserted
replaced
136:da00cde00e8a | 137:2a615b036870 |
---|---|
6 #include <ngx_http.h> | 6 #include <ngx_http.h> |
7 #include <ngx_http_proxy_handler.h> | 7 #include <ngx_http_proxy_handler.h> |
8 | 8 |
9 | 9 |
10 | 10 |
11 static void ngx_http_proxy_send_request(ngx_event_t *wev); | 11 static int ngx_http_proxy_handler(ngx_http_request_t *r); |
12 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); | |
13 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev); | |
14 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p); | |
15 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev); | |
16 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev); | |
17 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *); | |
18 static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p); | |
12 static void ngx_http_proxy_close_connection(ngx_connection_t *c); | 19 static void ngx_http_proxy_close_connection(ngx_connection_t *c); |
13 static ngx_chain_t *ngx_http_proxy_copy_request_hunks(ngx_http_proxy_ctx_t *p); | 20 |
21 static int ngx_http_proxy_init(ngx_cycle_t *cycle); | |
14 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); | 22 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); |
15 | 23 |
16 | 24 |
17 static ngx_command_t ngx_http_proxy_commands[] = { | 25 static ngx_command_t ngx_http_proxy_commands[] = { |
18 ngx_null_command | 26 ngx_null_command |
38 ngx_module_t ngx_http_proxy_module = { | 46 ngx_module_t ngx_http_proxy_module = { |
39 NGX_MODULE, | 47 NGX_MODULE, |
40 &ngx_http_proxy_module_ctx, /* module context */ | 48 &ngx_http_proxy_module_ctx, /* module context */ |
41 ngx_http_proxy_commands, /* module directives */ | 49 ngx_http_proxy_commands, /* module directives */ |
42 NGX_HTTP_MODULE, /* module type */ | 50 NGX_HTTP_MODULE, /* module type */ |
43 NULL, /* init module */ | 51 ngx_http_proxy_init, /* init module */ |
44 NULL /* init child */ | 52 NULL /* init child */ |
45 }; | 53 }; |
46 | 54 |
47 | 55 |
56 static ngx_str_t http_methods[] = { | |
57 ngx_string("GET "), | |
58 ngx_string("HEAD "), | |
59 ngx_string("POST ") | |
60 }; | |
61 | |
62 | |
48 #if 0 | 63 #if 0 |
49 static | 64 static char *header_errors[] = { |
65 "upstream sent too long status line", | |
66 "upstream sent invalid header", | |
67 "upstream sent too long header line" | |
68 }; | |
50 #endif | 69 #endif |
51 | 70 |
52 int ngx_http_proxy_handler(ngx_http_request_t *r) | 71 |
72 static ngx_http_header_t headers_in[] = { | |
73 { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) }, | |
74 { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) }, | |
75 { ngx_string("Connection"), | |
76 offsetof(ngx_http_proxy_headers_in_t, connection) }, | |
77 { ngx_string("Content-Type"), | |
78 offsetof(ngx_http_proxy_headers_in_t, content_type) }, | |
79 { ngx_string("Content-Length"), | |
80 offsetof(ngx_http_proxy_headers_in_t, content_length) }, | |
81 { ngx_string("Last-Modified"), | |
82 offsetof(ngx_http_proxy_headers_in_t, last_modified) }, | |
83 | |
84 { ngx_null_string, 0 } | |
85 }; | |
86 | |
87 | |
88 static char http_version[] = " HTTP/1.0" CRLF; | |
89 static char host_header[] = "Host: "; | |
90 static char conn_close_header[] = "Connection: close" CRLF; | |
91 | |
92 | |
93 | |
94 static int ngx_http_proxy_translate_handler(ngx_http_request_t *r) | |
95 { | |
96 r->handler = ngx_http_proxy_handler; | |
97 return NGX_OK; | |
98 } | |
99 | |
100 | |
101 static int ngx_http_proxy_handler(ngx_http_request_t *r) | |
53 { | 102 { |
54 int rc; | 103 int rc; |
55 ngx_http_proxy_ctx_t *p; | 104 ngx_http_proxy_ctx_t *p; |
56 ngx_http_proxy_loc_conf_t *lcf; | 105 ngx_http_proxy_loc_conf_t *lcf; |
57 | 106 |
58 ngx_http_create_ctx(r, p, ngx_http_proxy_module, | 107 ngx_http_create_ctx(r, p, ngx_http_proxy_module, |
59 sizeof(ngx_http_proxy_ctx_t), | 108 sizeof(ngx_http_proxy_ctx_t), |
60 NGX_HTTP_INTERNAL_SERVER_ERROR); | 109 NGX_HTTP_INTERNAL_SERVER_ERROR); |
61 | 110 |
62 p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | 111 p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); |
63 | |
64 #if 0 | |
65 create_request; | |
66 #endif | |
67 | |
68 p->action = "connecting to upstream"; | |
69 p->request = r; | |
70 p->upstream.peers = p->lcf->peers; | 112 p->upstream.peers = p->lcf->peers; |
71 p->upstream.tries = p->lcf->peers->number; | 113 p->upstream.tries = p->lcf->peers->number; |
72 | 114 |
115 p->request = r; | |
116 p->method = r->method; | |
117 p->uri.data = "/"; | |
118 p->uri.len = 1; | |
119 p->location_len = 1; | |
120 | |
121 p->host_header = p->upstream.peers->peers[0].host; | |
122 | |
123 ngx_test_null(p->request_hunks, ngx_http_proxy_create_request(p), | |
124 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
125 | |
126 p->action = "connecting to upstream"; | |
127 | |
73 /* TODO: log->data would be changed, how to restore log->data ? */ | 128 /* TODO: log->data would be changed, how to restore log->data ? */ |
74 p->upstream.log = r->connection->log; | 129 p->upstream.log = r->connection->log; |
75 | 130 |
76 for ( ;; ) { | 131 ngx_http_proxy_send_request(p); |
77 rc = ngx_event_connect_peer(&p->upstream); | 132 |
78 | 133 return NGX_OK; |
79 if (rc == NGX_ERROR) { | 134 } |
80 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 135 |
81 } | 136 |
82 | 137 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) |
83 if (rc == NGX_CONNECT_ERROR) { | 138 { |
84 ngx_event_connect_peer_failed(&p->upstream); | 139 int i; |
85 | 140 size_t len; |
86 if (p->upstream.tries == 0) { | 141 ngx_hunk_t *h; |
87 return NGX_HTTP_BAD_GATEWAY; | 142 ngx_chain_t *chain; |
88 } | 143 ngx_table_elt_t *header; |
89 } | 144 ngx_http_request_t *r; |
90 | 145 |
91 p->upstream.connection->data = p; | 146 r = p->request; |
92 p->upstream.connection->write->event_handler = | 147 |
93 ngx_http_proxy_send_request; | 148 len = http_methods[p->method - 1].len |
94 p->upstream.connection->read->event_handler = /* STUB */ NULL; | 149 + p->uri.len |
95 | 150 + r->uri.len - p->location_len |
96 if (p->upstream.tries > 1) { | 151 + 1 + r->args.len /* 1 is for "?" */ |
97 ngx_test_null(p->work_request_hunks, | 152 + sizeof(http_version) - 1 |
98 ngx_http_proxy_copy_request_hunks(p), | 153 + sizeof(host_header) - 1 + p->host_header.len + 2 |
99 NGX_HTTP_INTERNAL_SERVER_ERROR); | 154 /* 2 is for "\r\n" */ |
100 } else { | 155 + sizeof(conn_close_header) - 1 |
101 p->work_request_hunks = p->request_hunks; | 156 + 2; /* 2 is for "\r\n" at the header end */ |
102 } | 157 |
103 | 158 header = (ngx_table_elt_t *) r->headers_in.headers->elts; |
104 if (rc == NGX_OK) { | 159 for (i = 0; i < r->headers_in.headers->nelts; i++) { |
105 ngx_http_proxy_send_request(p->upstream.connection->write); | 160 |
106 return NGX_OK; | 161 if (&header[i] == r->headers_in.host) { |
107 } | 162 continue; |
108 | 163 } |
109 /* rc == NGX_AGAIN */ | 164 |
110 | 165 if (&header[i] == r->headers_in.connection) { |
111 /* timer */ | 166 continue; |
112 | 167 } |
113 /* TODO */ return NGX_OK; | 168 |
114 } | 169 /* 2 is for ": " and 2 is for "\r\n" */ |
115 } | 170 len += header[i].key.len + 2 + header[i].value.len + 2; |
116 | 171 } |
117 | 172 |
118 static void ngx_http_proxy_send_request(ngx_event_t *wev) | 173 /* STUB */ len++; |
119 { | 174 |
120 int rc; | 175 ngx_test_null(h, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL); |
121 ngx_chain_t *chain; | 176 ngx_add_hunk_to_chain(chain, h, r->pool, NULL); |
177 | |
178 | |
179 /* the request line */ | |
180 | |
181 h->last = ngx_cpymem(h->last, http_methods[p->method - 1].data, | |
182 http_methods[p->method - 1].len); | |
183 | |
184 h->last = ngx_cpymem(h->last, p->uri.data, p->uri.len); | |
185 | |
186 h->last = ngx_cpymem(h->last, | |
187 r->uri.data + p->location_len, | |
188 r->uri.len - p->location_len); | |
189 | |
190 if (r->args.len > 0) { | |
191 *(h->last++) = '?'; | |
192 h->last = ngx_cpymem(h->last, r->args.data, r->args.len); | |
193 } | |
194 | |
195 h->last = ngx_cpymem(h->last, http_version, sizeof(http_version) - 1); | |
196 | |
197 | |
198 /* the "Host" header */ | |
199 | |
200 h->last = ngx_cpymem(h->last, host_header, sizeof(host_header) - 1); | |
201 h->last = ngx_cpymem(h->last, p->host_header.data, p->host_header.len); | |
202 *(h->last++) = CR; *(h->last++) = LF; | |
203 | |
204 | |
205 /* the "Connection: close" header */ | |
206 | |
207 h->last = ngx_cpymem(h->last, conn_close_header, | |
208 sizeof(conn_close_header) - 1); | |
209 | |
210 | |
211 for (i = 0; i < r->headers_in.headers->nelts; i++) { | |
212 | |
213 if (&header[i] == r->headers_in.host) { | |
214 continue; | |
215 } | |
216 | |
217 if (&header[i] == r->headers_in.connection) { | |
218 continue; | |
219 } | |
220 | |
221 /* TODO: delete "Keep-Alive" header */ | |
222 | |
223 h->last = ngx_cpymem(h->last, header[i].key.data, header[i].key.len); | |
224 | |
225 *(h->last++) = ':'; *(h->last++) = ' '; | |
226 | |
227 h->last = ngx_cpymem(h->last, header[i].value.data, | |
228 header[i].value.len); | |
229 | |
230 *(h->last++) = CR; *(h->last++) = LF; | |
231 | |
232 ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _ | |
233 header[i].key.data _ header[i].value.data); | |
234 } | |
235 | |
236 /* add "\r\n" at the header end */ | |
237 *(h->last++) = CR; *(h->last++) = LF; | |
238 | |
239 /* STUB */ *(h->last++) = '\0'; | |
240 ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ h->pos); | |
241 | |
242 return chain; | |
243 } | |
244 | |
245 | |
246 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev) | |
247 { | |
122 ngx_connection_t *c; | 248 ngx_connection_t *c; |
123 ngx_http_proxy_ctx_t *p; | 249 ngx_http_proxy_ctx_t *p; |
124 | 250 |
125 c = wev->data; | 251 c = wev->data; |
126 p = c->data; | 252 p = c->data; |
127 | 253 |
254 ngx_http_proxy_send_request(p); | |
255 | |
256 return; | |
257 } | |
258 | |
259 | |
260 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p) | |
261 { | |
262 int rc; | |
263 ngx_chain_t *chain, *ce, *te, **le; | |
264 ngx_connection_t *c; | |
265 | |
266 c = p->upstream.connection; | |
267 | |
128 for ( ;; ) { | 268 for ( ;; ) { |
129 chain = ngx_write_chain(c, p->request_hunks); | 269 if (c) { |
130 | 270 chain = ngx_write_chain(c, p->work_request_hunks); |
131 if (chain == (ngx_chain_t *) -1) { | 271 |
272 if (chain != NGX_CHAIN_ERROR) { | |
273 p->work_request_hunks = chain; | |
274 | |
275 if (c->write->timer_set) { | |
276 ngx_del_timer(c->write); | |
277 } | |
278 | |
279 if (chain) { | |
280 ngx_add_timer(c->write, p->lcf->send_timeout); | |
281 c->write->timer_set = 1; | |
282 | |
283 } else { | |
284 c->write->timer_set = 0; | |
285 /* TODO: del event */ | |
286 } | |
287 | |
288 return; | |
289 } | |
290 | |
132 ngx_http_proxy_close_connection(c); | 291 ngx_http_proxy_close_connection(c); |
133 | 292 } |
134 for ( ;; ) { | 293 |
135 rc = ngx_event_connect_peer(&p->upstream); | 294 for ( ;; ) { |
136 | 295 rc = ngx_event_connect_peer(&p->upstream); |
137 if (rc == NGX_ERROR) { | 296 |
297 if (rc == NGX_ERROR) { | |
298 ngx_http_finalize_request(p->request, | |
299 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
300 return; | |
301 } | |
302 | |
303 if (rc == NGX_CONNECT_ERROR) { | |
304 ngx_event_connect_peer_failed(&p->upstream); | |
305 | |
306 if (p->upstream.tries == 0) { | |
307 ngx_http_finalize_request(p->request, | |
308 NGX_HTTP_BAD_GATEWAY); | |
309 return; | |
310 } | |
311 | |
312 continue; | |
313 } | |
314 | |
315 p->upstream.connection->data = p; | |
316 p->upstream.connection->write->event_handler = | |
317 ngx_http_proxy_send_request_handler; | |
318 p->upstream.connection->read->event_handler = | |
319 ngx_http_proxy_process_upstream_status_line; | |
320 | |
321 c = p->upstream.connection; | |
322 c->pool = p->request->pool; | |
323 c->read->log = c->write->log = c->log = p->request->connection->log; | |
324 | |
325 if (p->upstream.tries > 1) { | |
326 #if (NGX_SUPPRESS_WARN) | |
327 le = NULL; | |
328 #endif | |
329 p->work_request_hunks = | |
330 ngx_alloc_chain_entry(p->request->pool); | |
331 if (p->work_request_hunks == NULL) { | |
332 ngx_http_proxy_close_connection(c); | |
138 ngx_http_finalize_request(p->request, | 333 ngx_http_finalize_request(p->request, |
139 NGX_HTTP_INTERNAL_SERVER_ERROR); | 334 NGX_HTTP_INTERNAL_SERVER_ERROR); |
140 return; | 335 return; |
141 } | 336 } |
142 | 337 |
143 if (rc == NGX_CONNECT_ERROR) { | 338 te = p->work_request_hunks; |
144 ngx_event_connect_peer_failed(&p->upstream); | 339 |
145 | 340 for (ce = p->request_hunks; ce; ce = ce->next) { |
146 if (p->upstream.tries == 0) { | 341 te->hunk = ce->hunk; |
342 *le = te; | |
343 le = &te->next; | |
344 ce->hunk->pos = ce->hunk->start; | |
345 | |
346 te = ngx_alloc_chain_entry(p->request->pool); | |
347 if (te == NULL) { | |
348 ngx_http_proxy_close_connection(c); | |
349 ngx_http_finalize_request(p->request, | |
350 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
147 return; | 351 return; |
148 } | 352 } |
149 } | 353 } |
150 | 354 |
151 if (p->upstream.tries > 1) { | 355 *le = NULL; |
152 ngx_test_null(p->work_request_hunks, | 356 |
153 ngx_http_proxy_copy_request_hunks(p), | 357 } else { |
154 /* void */); | 358 p->work_request_hunks = p->request_hunks; |
155 } else { | 359 } |
156 p->work_request_hunks = p->request_hunks; | 360 |
361 if (rc == NGX_OK) { | |
362 break; | |
363 } | |
364 | |
365 /* rc == NGX_AGAIN */ | |
366 | |
367 ngx_add_timer(c->write, p->lcf->connect_timeout); | |
368 c->write->timer_set = 1; | |
369 | |
370 return; | |
371 } | |
372 } | |
373 } | |
374 | |
375 | |
376 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev) | |
377 { | |
378 int rc; | |
379 ssize_t n; | |
380 ngx_connection_t *c; | |
381 ngx_http_proxy_ctx_t *p; | |
382 | |
383 c = rev->data; | |
384 p = c->data; | |
385 | |
386 ngx_log_debug(rev->log, "http proxy process status line"); | |
387 | |
388 if (rev->timedout) { | |
389 ngx_http_proxy_close_connection(c); | |
390 ngx_http_finalize_request(p->request, NGX_HTTP_GATEWAY_TIME_OUT); | |
391 return; | |
392 } | |
393 | |
394 if (p->header_in == NULL) { | |
395 p->header_in = ngx_create_temp_hunk(p->request->pool, | |
396 p->lcf->header_size, | |
397 0, 0); | |
398 if (p->header_in == NULL) { | |
399 ngx_http_proxy_close_connection(c); | |
400 ngx_http_finalize_request(p->request, | |
401 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
402 return; | |
403 } | |
404 } | |
405 | |
406 n = ngx_http_proxy_read_upstream_header(p); | |
407 | |
408 if (n == NGX_AGAIN || n == NGX_ERROR) { | |
409 return; | |
410 } | |
411 | |
412 rc = ngx_http_proxy_parse_status_line(p); | |
413 | |
414 if (rc == NGX_AGAIN) { | |
415 if (p->header_in->pos == p->header_in->last) { | |
416 ngx_log_error(NGX_LOG_ERR, rev->log, 0, | |
417 "upstream sent too big header"); | |
418 ngx_http_proxy_close_connection(c); | |
419 ngx_http_finalize_request(p->request, NGX_HTTP_BAD_GATEWAY); | |
420 return; | |
421 } | |
422 | |
423 return; | |
424 } | |
425 | |
426 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { | |
427 /* TODO: HTTP/0.9 */ | |
428 return; | |
429 } | |
430 | |
431 /* rc == NGX_OK */ | |
432 | |
433 p->status_line.len = p->status_end - p->status_start; | |
434 p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1); | |
435 if (p->status_line.data == NULL) { | |
436 ngx_http_proxy_close_connection(c); | |
437 ngx_http_finalize_request(p->request, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
438 return; | |
439 } | |
440 ngx_cpystrn(p->status_line.data, p->status_start, p->status_line.len + 1); | |
441 | |
442 ngx_log_debug(rev->log, "http proxy status %d '%s'" _ | |
443 p->status _ p->status_line.data); | |
444 | |
445 | |
446 if (p->headers_in.headers) { | |
447 p->headers_in.headers->nelts = 0; | |
448 } else { | |
449 p->headers_in.headers = ngx_create_table(p->request->pool, 10); | |
450 } | |
451 | |
452 c->read->event_handler = ngx_http_proxy_process_upstream_headers; | |
453 ngx_http_proxy_process_upstream_headers(rev); | |
454 | |
455 return; | |
456 } | |
457 | |
458 | |
459 | |
460 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev) | |
461 { | |
462 int i, rc; | |
463 ssize_t n; | |
464 ngx_table_elt_t *h; | |
465 ngx_connection_t *c; | |
466 ngx_http_request_t *r; | |
467 ngx_http_proxy_ctx_t *p; | |
468 | |
469 c = rev->data; | |
470 p = c->data; | |
471 r = p->request; | |
472 | |
473 ngx_log_debug(rev->log, "http proxy process header line"); | |
474 | |
475 if (rev->timedout) { | |
476 ngx_http_proxy_close_connection(c); | |
477 ngx_http_finalize_request(p->request, NGX_HTTP_GATEWAY_TIME_OUT); | |
478 return; | |
479 } | |
480 | |
481 rc = NGX_AGAIN; | |
482 | |
483 for ( ;; ) { | |
484 if (rc == NGX_AGAIN) { | |
485 n = ngx_http_proxy_read_upstream_header(p); | |
486 | |
487 if (n == NGX_AGAIN || n == NGX_ERROR) { | |
488 return; | |
489 } | |
490 } | |
491 | |
492 rc = ngx_http_parse_header_line(p->request, p->header_in); | |
493 | |
494 if (rc == NGX_OK) { | |
495 | |
496 /* a header line has been parsed successfully */ | |
497 | |
498 h = ngx_push_table(p->headers_in.headers); | |
499 if (h == NULL) { | |
500 ngx_http_proxy_close_connection(c); | |
501 ngx_http_finalize_request(p->request, | |
502 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
503 return; | |
504 } | |
505 | |
506 h->key.len = r->header_name_end - r->header_name_start; | |
507 h->value.len = r->header_end - r->header_start; | |
508 | |
509 h->key.data = ngx_palloc(p->request->pool, | |
510 h->key.len + 1 + h->value.len + 1); | |
511 if (h->key.data == NULL) { | |
512 ngx_http_proxy_close_connection(c); | |
513 ngx_http_finalize_request(p->request, | |
514 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
515 return; | |
516 } | |
517 | |
518 h->value.data = h->key.data + h->key.len + 1; | |
519 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); | |
520 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); | |
521 | |
522 for (i = 0; headers_in[i].name.len != 0; i++) { | |
523 if (headers_in[i].name.len != h->key.len) { | |
524 continue; | |
157 } | 525 } |
158 | 526 |
159 if (rc == NGX_OK) { | 527 if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) { |
160 c = p->connection; | 528 *((ngx_table_elt_t **) |
161 wev = c->write; | 529 ((char *) &p->headers_in + headers_in[i].offset)) = h; |
162 | |
163 break; | |
164 } | 530 } |
165 | 531 } |
166 /* rc == NGX_AGAIN */ | 532 |
167 return; | 533 ngx_log_debug(c->log, "HTTP proxy header: '%s: %s'" _ |
168 | 534 h->key.data _ h->value.data); |
169 } | 535 |
170 | 536 continue; |
537 | |
538 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
539 | |
540 /* a whole header has been parsed successfully */ | |
541 | |
542 ngx_log_debug(c->log, "HTTP header done"); | |
543 | |
544 return; | |
545 | |
546 } else if (rc != NGX_AGAIN) { | |
547 | |
548 /* there was error while a header line parsing */ | |
549 | |
550 #if 0 | |
551 ngx_http_header_parse_error(r, rc); | |
552 #endif | |
553 ngx_http_proxy_close_connection(c); | |
554 ngx_http_finalize_request(p->request, NGX_HTTP_BAD_GATEWAY); | |
555 return; | |
556 } | |
557 | |
558 /* NGX_AGAIN: a header line parsing is still not complete */ | |
559 | |
560 if (p->header_in->last == p->header_in->end) { | |
561 ngx_log_error(NGX_LOG_ERR, rev->log, 0, | |
562 "upstream sent too big header"); | |
563 ngx_http_proxy_close_connection(c); | |
564 ngx_http_finalize_request(p->request, NGX_HTTP_BAD_GATEWAY); | |
565 return; | |
566 } | |
567 } | |
568 } | |
569 | |
570 | |
571 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p) | |
572 { | |
573 int event; | |
574 ssize_t n; | |
575 ngx_event_t *rev; | |
576 | |
577 rev = p->upstream.connection->read; | |
578 | |
579 n = p->header_in->last - p->header_in->pos; | |
580 | |
581 if (n > 0) { | |
582 rev->ready = 0; | |
583 return n; | |
584 } | |
585 | |
586 n = ngx_recv(p->upstream.connection, p->header_in->last, | |
587 p->header_in->end - p->header_in->last); | |
588 | |
589 if (n == NGX_AGAIN) { | |
590 if (rev->timer_set) { | |
591 ngx_del_timer(rev); | |
171 } else { | 592 } else { |
172 p->work_request_hunks = chain; | 593 rev->timer_set = 1; |
173 | 594 } |
174 ngx_del_timer(wev); | 595 |
175 | 596 ngx_add_timer(rev, p->lcf->read_timeout); |
176 if (chain) { | 597 |
177 ngx_add_timer(wev, p->lcf->send_timeout); | 598 if (!rev->active) { |
178 wev->timer_set = 1; | 599 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { |
600 /* kqueue */ | |
601 event = NGX_CLEAR_EVENT; | |
179 | 602 |
180 } else { | 603 } else { |
181 wev->timer_set = 0; | 604 /* select, poll, /dev/poll */ |
182 /* TODO: del event */ | 605 event = NGX_LEVEL_EVENT; |
183 } | 606 } |
184 | 607 |
185 return; | 608 if (ngx_add_event(rev, NGX_READ_EVENT, event) == NGX_ERROR) { |
186 } | 609 ngx_http_proxy_close_connection(p->upstream.connection); |
187 } | 610 ngx_http_finalize_request(p->request, |
188 } | 611 NGX_HTTP_INTERNAL_SERVER_ERROR); |
612 return NGX_ERROR; | |
613 } | |
614 } | |
615 | |
616 return NGX_AGAIN; | |
617 } | |
618 | |
619 if (n == 0) { | |
620 ngx_log_error(NGX_LOG_INFO, rev->log, 0, | |
621 "upstream closed prematurely connection"); | |
622 } | |
623 | |
624 if (n == 0 || n == NGX_ERROR) { | |
625 ngx_http_proxy_close_connection(p->upstream.connection); | |
626 ngx_http_finalize_request(p->request, NGX_HTTP_BAD_GATEWAY); | |
627 return NGX_ERROR; | |
628 } | |
629 | |
630 p->header_in->last += n; | |
631 | |
632 return n; | |
633 } | |
634 | |
635 | |
636 static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p) | |
637 { | |
638 char ch; | |
639 char *pos; | |
640 enum { | |
641 sw_start = 0, | |
642 sw_H, | |
643 sw_HT, | |
644 sw_HTT, | |
645 sw_HTTP, | |
646 sw_first_major_digit, | |
647 sw_major_digit, | |
648 sw_first_minor_digit, | |
649 sw_minor_digit, | |
650 sw_status, | |
651 sw_space_after_status, | |
652 sw_status_text, | |
653 sw_almost_done, | |
654 sw_done | |
655 } state; | |
656 | |
657 state = p->state; | |
658 pos = p->header_in->pos; | |
659 | |
660 while (pos < p->header_in->last && state < sw_done) { | |
661 ch = *pos++; | |
662 | |
663 switch (state) { | |
664 | |
665 /* "HTTP/" */ | |
666 case sw_start: | |
667 switch (ch) { | |
668 case 'H': | |
669 state = sw_H; | |
670 break; | |
671 default: | |
672 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
673 } | |
674 break; | |
675 | |
676 case sw_H: | |
677 switch (ch) { | |
678 case 'T': | |
679 state = sw_HT; | |
680 break; | |
681 default: | |
682 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
683 } | |
684 break; | |
685 | |
686 case sw_HT: | |
687 switch (ch) { | |
688 case 'T': | |
689 state = sw_HTT; | |
690 break; | |
691 default: | |
692 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
693 } | |
694 break; | |
695 | |
696 case sw_HTT: | |
697 switch (ch) { | |
698 case 'P': | |
699 state = sw_HTTP; | |
700 break; | |
701 default: | |
702 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
703 } | |
704 break; | |
705 | |
706 case sw_HTTP: | |
707 switch (ch) { | |
708 case '/': | |
709 state = sw_first_major_digit; | |
710 break; | |
711 default: | |
712 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
713 } | |
714 break; | |
715 | |
716 /* the first digit of major HTTP version */ | |
717 case sw_first_major_digit: | |
718 if (ch < '1' || ch > '9') { | |
719 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
720 } | |
721 | |
722 state = sw_major_digit; | |
723 break; | |
724 | |
725 /* the major HTTP version or dot */ | |
726 case sw_major_digit: | |
727 if (ch == '.') { | |
728 state = sw_first_minor_digit; | |
729 break; | |
730 } | |
731 | |
732 if (ch < '0' || ch > '9') { | |
733 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
734 } | |
735 | |
736 break; | |
737 | |
738 /* the first digit of minor HTTP version */ | |
739 case sw_first_minor_digit: | |
740 if (ch < '0' || ch > '9') { | |
741 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
742 } | |
743 | |
744 state = sw_minor_digit; | |
745 break; | |
746 | |
747 /* the minor HTTP version or the end of the request line */ | |
748 case sw_minor_digit: | |
749 if (ch == ' ') { | |
750 state = sw_status; | |
751 break; | |
752 } | |
753 | |
754 if (ch < '0' || ch > '9') { | |
755 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
756 } | |
757 | |
758 break; | |
759 | |
760 /* HTTP status code */ | |
761 case sw_status: | |
762 if (ch < '0' || ch > '9') { | |
763 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
764 } | |
765 | |
766 p->status = p->status * 10 + ch - '0'; | |
767 | |
768 if (++p->status_count == 3) { | |
769 state = sw_space_after_status; | |
770 p->status_start = pos - 3; | |
771 } | |
772 | |
773 break; | |
774 | |
775 /* space or end of line */ | |
776 case sw_space_after_status: | |
777 switch (ch) { | |
778 case ' ': | |
779 state = sw_status_text; | |
780 break; | |
781 case CR: | |
782 state = sw_almost_done; | |
783 break; | |
784 case LF: | |
785 state = sw_done; | |
786 break; | |
787 default: | |
788 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
789 } | |
790 break; | |
791 | |
792 /* any text until end of line */ | |
793 case sw_status_text: | |
794 switch (ch) { | |
795 case CR: | |
796 state = sw_almost_done; | |
797 | |
798 break; | |
799 case LF: | |
800 state = sw_done; | |
801 break; | |
802 } | |
803 break; | |
804 | |
805 /* end of request line */ | |
806 case sw_almost_done: | |
807 p->status_end = pos - 2; | |
808 switch (ch) { | |
809 case LF: | |
810 state = sw_done; | |
811 break; | |
812 default: | |
813 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
814 } | |
815 break; | |
816 } | |
817 } | |
818 | |
819 p->header_in->pos = pos; | |
820 | |
821 if (state == sw_done) { | |
822 if (p->status_end == NULL) { | |
823 p->status_end = pos - 1; | |
824 } | |
825 | |
826 p->state = sw_start; | |
827 return NGX_OK; | |
828 } | |
829 | |
830 p->state = state; | |
831 return NGX_AGAIN; | |
832 } | |
833 | |
189 | 834 |
190 static void ngx_http_proxy_close_connection(ngx_connection_t *c) | 835 static void ngx_http_proxy_close_connection(ngx_connection_t *c) |
191 { | 836 { |
837 ngx_log_debug(c->log, "close connection: %d" _ c->fd); | |
838 | |
839 if (c->fd == -1) { | |
840 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); | |
841 return; | |
842 } | |
843 | |
844 if (c->read->timer_set) { | |
845 ngx_del_timer(c->read); | |
846 c->read->timer_set = 0; | |
847 } | |
848 | |
849 if (c->write->timer_set) { | |
850 ngx_del_timer(c->write); | |
851 c->write->timer_set = 0; | |
852 } | |
853 | |
854 if (ngx_del_conn) { | |
855 ngx_del_conn(c); | |
856 | |
857 } else { | |
858 if (c->read->active) { | |
859 ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); | |
860 } | |
861 | |
862 if (c->write->active) { | |
863 ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); | |
864 } | |
865 } | |
866 | |
867 if (ngx_close_socket(c->fd) == -1) { | |
868 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, | |
869 ngx_close_socket_n " failed"); | |
870 } | |
871 | |
872 c->fd = -1; | |
873 | |
192 return; | 874 return; |
193 } | |
194 | |
195 static ngx_chain_t *ngx_http_proxy_copy_request_hunks(ngx_http_proxy_ctx_t *p) | |
196 { | |
197 ngx_chain_t *ce, *te, *fe, **le; | |
198 | |
199 #if (NGX_SUPPRESS_WARN) | |
200 le = NULL; | |
201 #endif | |
202 | |
203 ngx_test_null(fe, ngx_alloc_chain_entry(p->request->pool), NULL); | |
204 | |
205 te = fe; | |
206 | |
207 for (ce = p->request_hunks; ce; ce = ce->next) { | |
208 te->hunk = ce->hunk; | |
209 *le = te; | |
210 le = &te->next; | |
211 ce->hunk->pos = ce->hunk->start; | |
212 | |
213 ngx_test_null(te, ngx_alloc_chain_entry(p->request->pool), NULL); | |
214 } | |
215 | |
216 *le = NULL; | |
217 | |
218 return fe; | |
219 } | 875 } |
220 | 876 |
221 | 877 |
222 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len) | 878 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len) |
223 { | 879 { |
227 " while %s, upstream: %s, client: %s, URL: %s", | 883 " while %s, upstream: %s, client: %s, URL: %s", |
228 p->action, | 884 p->action, |
229 p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data, | 885 p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data, |
230 p->request->connection->addr_text.data, | 886 p->request->connection->addr_text.data, |
231 p->request->unparsed_uri.data); | 887 p->request->unparsed_uri.data); |
888 } | |
889 | |
890 | |
891 static int ngx_http_proxy_init(ngx_cycle_t *cycle) | |
892 { | |
893 ngx_http_handler_pt *h; | |
894 ngx_http_conf_ctx_t *ctx; | |
895 ngx_http_core_main_conf_t *cmcf; | |
896 | |
897 ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; | |
898 cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; | |
899 | |
900 ngx_test_null(h, ngx_push_array(&cmcf->translate_handlers), NGX_ERROR); | |
901 | |
902 *h = ngx_http_proxy_translate_handler; | |
903 | |
904 return NGX_OK; | |
232 } | 905 } |
233 | 906 |
234 | 907 |
235 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) | 908 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) |
236 { | 909 { |
250 conf->peers->peers[0].host.len = sizeof("localhost") - 1; | 923 conf->peers->peers[0].host.len = sizeof("localhost") - 1; |
251 conf->peers->peers[0].port = htons(9000); | 924 conf->peers->peers[0].port = htons(9000); |
252 conf->peers->peers[0].addr_port_text.data = "127.0.0.1:9000"; | 925 conf->peers->peers[0].addr_port_text.data = "127.0.0.1:9000"; |
253 conf->peers->peers[0].addr_port_text.len = sizeof("127.0.0.1:9000") - 1; | 926 conf->peers->peers[0].addr_port_text.len = sizeof("127.0.0.1:9000") - 1; |
254 | 927 |
928 conf->connect_timeout = 30000; | |
255 conf->send_timeout = 30000; | 929 conf->send_timeout = 30000; |
930 conf->header_size = 4096; | |
931 conf->read_timeout = 30000; | |
256 /* */ | 932 /* */ |
257 | 933 |
258 return conf; | 934 return conf; |
259 } | 935 } |