Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 1 | |
| 2 | #include <ngx_config.h> |
| 3 | #include <ngx_core.h> |
| 4 | #include <ngx_event.h> |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 5 | #include <ngx_event_connect.h> |
| 6 | #include <ngx_event_pipe.h> |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 7 | #include <ngx_http.h> |
| 8 | #include <ngx_http_proxy_handler.h> |
| 9 | |
| 10 | |
| 11 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 12 | static int ngx_http_proxy_handler(ngx_http_request_t *r); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 13 | static void ngx_http_proxy_init_request(void *data); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 14 | static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); |
| 15 | static void ngx_http_proxy_send_request_handler(ngx_event_t *wev); |
| 16 | static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p); |
| 17 | static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev); |
| 18 | static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev); |
| 19 | static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 20 | static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p); |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 21 | static void ngx_http_proxy_process_body(ngx_event_t *ev); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 22 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 23 | static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 24 | static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 25 | static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc); |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 26 | static void ngx_http_proxy_close_connection(ngx_connection_t *c); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 27 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 28 | static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len); |
| 29 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 30 | static int ngx_http_proxy_init(ngx_cycle_t *cycle); |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 31 | static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 32 | static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, |
| 33 | void *parent, void *child); |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 34 | |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 35 | static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, |
| 36 | void *conf); |
| 37 | static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, |
| 38 | ngx_http_proxy_upstream_t *u); |
| 39 | |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 40 | |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 41 | static ngx_command_t ngx_http_proxy_commands[] = { |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 42 | |
| 43 | {ngx_string("proxy_pass"), |
| 44 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 45 | ngx_http_proxy_set_pass, |
| 46 | NGX_HTTP_LOC_CONF_OFFSET, |
| 47 | 0, |
| 48 | NULL}, |
| 49 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 50 | {ngx_string("proxy_request_buffer_size"), |
| 51 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 52 | ngx_conf_set_size_slot, |
| 53 | NGX_HTTP_LOC_CONF_OFFSET, |
| 54 | offsetof(ngx_http_proxy_loc_conf_t, request_buffer_size), |
| 55 | NULL}, |
| 56 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 57 | {ngx_string("proxy_connect_timeout"), |
| 58 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 59 | ngx_conf_set_msec_slot, |
| 60 | NGX_HTTP_LOC_CONF_OFFSET, |
| 61 | offsetof(ngx_http_proxy_loc_conf_t, connect_timeout), |
| 62 | NULL}, |
| 63 | |
| 64 | {ngx_string("proxy_send_timeout"), |
| 65 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 66 | ngx_conf_set_msec_slot, |
| 67 | NGX_HTTP_LOC_CONF_OFFSET, |
| 68 | offsetof(ngx_http_proxy_loc_conf_t, send_timeout), |
| 69 | NULL}, |
| 70 | |
| 71 | {ngx_string("proxy_header_buffer_size"), |
| 72 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 73 | ngx_conf_set_size_slot, |
| 74 | NGX_HTTP_LOC_CONF_OFFSET, |
| 75 | offsetof(ngx_http_proxy_loc_conf_t, header_buffer_size), |
| 76 | NULL}, |
| 77 | |
| 78 | {ngx_string("proxy_read_timeout"), |
| 79 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 80 | ngx_conf_set_msec_slot, |
| 81 | NGX_HTTP_LOC_CONF_OFFSET, |
| 82 | offsetof(ngx_http_proxy_loc_conf_t, read_timeout), |
| 83 | NULL}, |
| 84 | |
| 85 | {ngx_string("proxy_buffers"), |
| 86 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, |
| 87 | ngx_conf_set_bufs_slot, |
| 88 | NGX_HTTP_LOC_CONF_OFFSET, |
| 89 | offsetof(ngx_http_proxy_loc_conf_t, bufs), |
| 90 | NULL}, |
| 91 | |
| 92 | {ngx_string("proxy_busy_buffers_size"), |
| 93 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 94 | ngx_conf_set_size_slot, |
| 95 | NGX_HTTP_LOC_CONF_OFFSET, |
| 96 | offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size), |
| 97 | NULL}, |
| 98 | |
| 99 | {ngx_string("proxy_temp_path"), |
| 100 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, |
| 101 | ngx_conf_set_path_slot, |
| 102 | NGX_HTTP_LOC_CONF_OFFSET, |
| 103 | offsetof(ngx_http_proxy_loc_conf_t, temp_path), |
| 104 | NULL}, |
| 105 | |
| 106 | {ngx_string("proxy_temp_file_write_size"), |
| 107 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
| 108 | ngx_conf_set_size_slot, |
| 109 | NGX_HTTP_LOC_CONF_OFFSET, |
| 110 | offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size), |
| 111 | NULL}, |
| 112 | |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 113 | ngx_null_command |
| 114 | }; |
| 115 | |
| 116 | |
| 117 | ngx_http_module_t ngx_http_proxy_module_ctx = { |
| 118 | NULL, /* create main configuration */ |
| 119 | NULL, /* init main configuration */ |
| 120 | |
| 121 | NULL, /* create server configuration */ |
| 122 | NULL, /* merge server configuration */ |
| 123 | |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 124 | ngx_http_proxy_create_loc_conf, /* create location configration */ |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 125 | ngx_http_proxy_merge_loc_conf /* merge location configration */ |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 126 | }; |
| 127 | |
| 128 | |
| 129 | ngx_module_t ngx_http_proxy_module = { |
| 130 | NGX_MODULE, |
| 131 | &ngx_http_proxy_module_ctx, /* module context */ |
| 132 | ngx_http_proxy_commands, /* module directives */ |
| 133 | NGX_HTTP_MODULE, /* module type */ |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 134 | NULL, /* init module */ |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 135 | NULL /* init child */ |
| 136 | }; |
| 137 | |
| 138 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 139 | static ngx_str_t http_methods[] = { |
| 140 | ngx_string("GET "), |
| 141 | ngx_string("HEAD "), |
| 142 | ngx_string("POST ") |
| 143 | }; |
| 144 | |
| 145 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 146 | static char *upstream_header_errors[] = { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 147 | "upstream sent invalid header", |
| 148 | "upstream sent too long header line" |
| 149 | }; |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 150 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 151 | |
| 152 | static ngx_http_header_t headers_in[] = { |
| 153 | { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) }, |
| 154 | { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) }, |
| 155 | { ngx_string("Connection"), |
| 156 | offsetof(ngx_http_proxy_headers_in_t, connection) }, |
| 157 | { ngx_string("Content-Type"), |
| 158 | offsetof(ngx_http_proxy_headers_in_t, content_type) }, |
| 159 | { ngx_string("Content-Length"), |
| 160 | offsetof(ngx_http_proxy_headers_in_t, content_length) }, |
| 161 | { ngx_string("Last-Modified"), |
| 162 | offsetof(ngx_http_proxy_headers_in_t, last_modified) }, |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 163 | { ngx_string("Accept-Ranges"), |
| 164 | offsetof(ngx_http_proxy_headers_in_t, accept_ranges) }, |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 165 | |
| 166 | { ngx_null_string, 0 } |
| 167 | }; |
| 168 | |
| 169 | |
| 170 | static char http_version[] = " HTTP/1.0" CRLF; |
| 171 | static char host_header[] = "Host: "; |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 172 | static char connection_close_header[] = "Connection: close" CRLF; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 173 | |
| 174 | |
| 175 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 176 | static int ngx_http_proxy_handler(ngx_http_request_t *r) |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 177 | { |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 178 | ngx_http_proxy_ctx_t *p; |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 179 | |
| 180 | ngx_http_create_ctx(r, p, ngx_http_proxy_module, |
| 181 | sizeof(ngx_http_proxy_ctx_t), |
| 182 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 183 | |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 184 | p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 185 | p->upstream.peers = p->lcf->peers; |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 186 | p->upstream.tries = p->lcf->peers->number; |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 187 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 188 | p->request = r; |
| 189 | p->method = r->method; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 190 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 191 | /* TODO: we currently support reverse proxy only */ |
| 192 | p->accel = 1; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 193 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 194 | if (r->headers_in.content_length_n > 0) { |
| 195 | ngx_test_null(r->temp_file, |
| 196 | ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)), |
| 197 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 198 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 199 | r->temp_file->file.fd = NGX_INVALID_FILE; |
| 200 | r->temp_file->file.log = r->connection->log; |
| 201 | r->temp_file->path = *p->lcf->temp_path; |
| 202 | r->temp_file->pool = r->pool; |
| 203 | r->temp_file->warn = "a client request body is buffered " |
| 204 | "to a temporary file"; |
| 205 | /* STUB */ r->temp_file->persistent = 1; |
| 206 | |
| 207 | r->request_body_handler = ngx_http_proxy_init_request; |
| 208 | r->data = p; |
| 209 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 210 | ngx_http_read_client_request_body(r, p->lcf->request_buffer_size); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 211 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 212 | return NGX_DONE; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | ngx_http_proxy_init_request(p); |
| 216 | |
| 217 | return NGX_DONE; |
| 218 | } |
| 219 | |
| 220 | |
| 221 | static void ngx_http_proxy_init_request(void *data) |
| 222 | { |
| 223 | ngx_http_proxy_ctx_t *p = data; |
| 224 | |
| 225 | ngx_chain_t *cl; |
| 226 | ngx_http_request_t *r; |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 227 | ngx_output_chain_ctx_t *out_ctx; |
| 228 | ngx_chain_write_ctx_t *write_ctx; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 229 | |
| 230 | |
| 231 | r = p->request; |
| 232 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 233 | ngx_log_debug(r->connection->log, "timer_set: %d" _ |
| 234 | r->connection->read->timer_set); |
| 235 | |
| 236 | if (r->connection->read->timer_set) { |
| 237 | ngx_del_timer(r->connection->read); |
| 238 | } |
| 239 | |
| 240 | ngx_is_null(cl, ngx_http_proxy_create_request(p)) { |
| 241 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 242 | return; |
| 243 | } |
| 244 | |
| 245 | #if 0 |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 246 | cl = ngx_http_proxy_create_request(p); |
| 247 | if (cl == NULL) { |
| 248 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 249 | return; |
| 250 | } |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 251 | #endif |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 252 | |
| 253 | if (r->request_hunks) { |
| 254 | cl->next = r->request_hunks; |
| 255 | } |
| 256 | |
| 257 | r->request_hunks = cl; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 258 | |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 259 | p->upstream.log = r->connection->log; |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 260 | p->saved_ctx = r->connection->log->data; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 261 | p->saved_handler = r->connection->log->handler; |
| 262 | r->connection->log->data = p; |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 263 | r->connection->log->handler = ngx_http_proxy_log_error; |
| 264 | p->action = "connecting to upstream"; |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 265 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 266 | out_ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); |
| 267 | if (out_ctx == NULL) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 268 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 269 | } |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 270 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 271 | p->output_chain_ctx = out_ctx; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 272 | |
| 273 | if (r->request_body_hunk) { |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 274 | out_ctx->free = ngx_alloc_chain_link(r->pool); |
| 275 | if (out_ctx->free == NULL) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 276 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 277 | } |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 278 | out_ctx->free->hunk = r->request_body_hunk; |
| 279 | out_ctx->free->next = NULL; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 280 | } |
| 281 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 282 | out_ctx->sendfile = r->sendfile; |
| 283 | out_ctx->pool = r->pool; |
| 284 | out_ctx->bufs.num = 1; |
| 285 | out_ctx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module; |
| 286 | out_ctx->output_filter = (ngx_output_chain_filter_pt) ngx_chain_write; |
| 287 | |
| 288 | write_ctx = ngx_pcalloc(r->pool, sizeof(ngx_chain_write_ctx_t)); |
| 289 | if (write_ctx == NULL) { |
| 290 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 291 | } |
| 292 | |
| 293 | out_ctx->output_ctx = write_ctx; |
| 294 | write_ctx->pool = r->pool; |
| 295 | write_ctx->last = &write_ctx->out; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 296 | |
| 297 | ngx_http_proxy_send_request(p); |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 298 | } |
| 299 | |
| 300 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 301 | static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 302 | { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 303 | int i; |
| 304 | size_t len; |
| 305 | ngx_hunk_t *h; |
| 306 | ngx_chain_t *chain; |
| 307 | ngx_table_elt_t *header; |
| 308 | ngx_http_request_t *r; |
| 309 | ngx_http_proxy_upstream_t *u; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 310 | |
| 311 | r = p->request; |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 312 | u = p->lcf->upstream; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 313 | |
| 314 | len = http_methods[p->method - 1].len |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 315 | + u->uri.len |
| 316 | + r->uri.len - u->location->len |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 317 | + 1 + r->args.len /* 1 is for "?" */ |
| 318 | + sizeof(http_version) - 1 |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 319 | + sizeof(host_header) - 1 + u->host_header.len + 2 |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 320 | /* 2 is for "\r\n" */ |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 321 | + sizeof(connection_close_header) - 1 |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 322 | + 2; /* 2 is for "\r\n" at the header end */ |
| 323 | |
| 324 | header = (ngx_table_elt_t *) r->headers_in.headers->elts; |
| 325 | for (i = 0; i < r->headers_in.headers->nelts; i++) { |
| 326 | |
| 327 | if (&header[i] == r->headers_in.host) { |
| 328 | continue; |
| 329 | } |
| 330 | |
| 331 | if (&header[i] == r->headers_in.connection) { |
| 332 | continue; |
| 333 | } |
| 334 | |
| 335 | /* 2 is for ": " and 2 is for "\r\n" */ |
| 336 | len += header[i].key.len + 2 + header[i].value.len + 2; |
| 337 | } |
| 338 | |
| 339 | /* STUB */ len++; |
| 340 | |
| 341 | ngx_test_null(h, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL); |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 342 | ngx_alloc_link_and_set_hunk(chain, h, r->pool, NULL); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 343 | |
| 344 | |
| 345 | /* the request line */ |
| 346 | |
| 347 | h->last = ngx_cpymem(h->last, http_methods[p->method - 1].data, |
| 348 | http_methods[p->method - 1].len); |
| 349 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 350 | h->last = ngx_cpymem(h->last, u->uri.data, u->uri.len); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 351 | |
| 352 | h->last = ngx_cpymem(h->last, |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 353 | r->uri.data + u->location->len, |
| 354 | r->uri.len - u->location->len); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 355 | |
| 356 | if (r->args.len > 0) { |
| 357 | *(h->last++) = '?'; |
| 358 | h->last = ngx_cpymem(h->last, r->args.data, r->args.len); |
| 359 | } |
| 360 | |
| 361 | h->last = ngx_cpymem(h->last, http_version, sizeof(http_version) - 1); |
| 362 | |
| 363 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 364 | /* "Host" header */ |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 365 | |
| 366 | h->last = ngx_cpymem(h->last, host_header, sizeof(host_header) - 1); |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 367 | h->last = ngx_cpymem(h->last, u->host_header.data, u->host_header.len); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 368 | *(h->last++) = CR; *(h->last++) = LF; |
| 369 | |
| 370 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 371 | /* "Connection: close" header */ |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 372 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 373 | h->last = ngx_cpymem(h->last, connection_close_header, |
| 374 | sizeof(connection_close_header) - 1); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 375 | |
| 376 | |
| 377 | for (i = 0; i < r->headers_in.headers->nelts; i++) { |
| 378 | |
| 379 | if (&header[i] == r->headers_in.host) { |
| 380 | continue; |
| 381 | } |
| 382 | |
| 383 | if (&header[i] == r->headers_in.connection) { |
| 384 | continue; |
| 385 | } |
| 386 | |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 387 | if (&header[i] == r->headers_in.keep_alive) { |
| 388 | continue; |
| 389 | } |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 390 | |
| 391 | h->last = ngx_cpymem(h->last, header[i].key.data, header[i].key.len); |
| 392 | |
| 393 | *(h->last++) = ':'; *(h->last++) = ' '; |
| 394 | |
| 395 | h->last = ngx_cpymem(h->last, header[i].value.data, |
| 396 | header[i].value.len); |
| 397 | |
| 398 | *(h->last++) = CR; *(h->last++) = LF; |
| 399 | |
| 400 | ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _ |
| 401 | header[i].key.data _ header[i].value.data); |
| 402 | } |
| 403 | |
| 404 | /* add "\r\n" at the header end */ |
| 405 | *(h->last++) = CR; *(h->last++) = LF; |
| 406 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 407 | /* STUB */ *(h->last) = '\0'; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 408 | ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ h->pos); |
| 409 | |
| 410 | return chain; |
| 411 | } |
| 412 | |
| 413 | |
| 414 | static void ngx_http_proxy_send_request_handler(ngx_event_t *wev) |
| 415 | { |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 416 | ngx_connection_t *c; |
| 417 | ngx_http_proxy_ctx_t *p; |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 418 | |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 419 | c = wev->data; |
| 420 | p = c->data; |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 421 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 422 | p->action = "sending request to upstream"; |
| 423 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 424 | if (wev->timedout) { |
| 425 | p->timedout = 1; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 426 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 427 | return; |
| 428 | } |
| 429 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 430 | ngx_http_proxy_send_request(p); |
| 431 | |
| 432 | return; |
| 433 | } |
| 434 | |
| 435 | |
| 436 | static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p) |
| 437 | { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 438 | int rc; |
| 439 | ngx_chain_t *cl; |
| 440 | ngx_connection_t *c; |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 441 | ngx_chain_write_ctx_t *ctx; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 442 | |
| 443 | c = p->upstream.connection; |
| 444 | |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 445 | for ( ;; ) { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 446 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 447 | if (c) { |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 448 | p->action = "sending request to upstream"; |
| 449 | ctx = p->output_chain_ctx->output_ctx; |
| 450 | ctx->connection = c; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 451 | rc = ngx_output_chain(p->output_chain_ctx, |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 452 | !p->request_sent ? p->request->request_hunks: |
| 453 | NULL); |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 454 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 455 | if (rc != NGX_ERROR) { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 456 | p->request_sent = 1; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 457 | |
| 458 | if (c->write->timer_set) { |
| 459 | ngx_del_timer(c->write); |
| 460 | } |
| 461 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 462 | if (rc == NGX_AGAIN) { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 463 | ngx_add_timer(c->write, p->lcf->send_timeout); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 464 | |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 465 | if (ngx_handle_write_event(c->write, /* STUB: lowat */ 0) |
| 466 | == NGX_ERROR) |
| 467 | { |
| 468 | ngx_http_proxy_finalize_request(p, |
| 469 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 470 | return; |
| 471 | } |
| 472 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 473 | } else { |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 474 | |
| 475 | /* rc == NGX_OK */ |
| 476 | |
| 477 | if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { |
| 478 | ngx_http_proxy_finalize_request(p, |
| 479 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 480 | return; |
| 481 | } |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 482 | |
| 483 | if (c->tcp_nopush) { |
| 484 | if (ngx_tcp_push(c->fd) == NGX_ERROR) { |
| 485 | ngx_log_error(NGX_LOG_CRIT, c->log, |
| 486 | ngx_socket_errno, |
| 487 | ngx_tcp_push_n " failed"); |
| 488 | ngx_http_proxy_finalize_request(p, |
| 489 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 490 | return; |
| 491 | } |
| 492 | c->tcp_nopush = 0; |
| 493 | } |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 494 | } |
| 495 | |
| 496 | return; |
| 497 | } |
| 498 | |
Igor Sysoev | 425a42c | 2003-10-27 16:16:17 +0000 | [diff] [blame] | 499 | ngx_event_connect_peer_failed(&p->upstream); |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 500 | ngx_http_proxy_close_connection(c); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 501 | } |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 502 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 503 | for ( ;; ) { |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 504 | p->action = "connecting to upstream"; |
| 505 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 506 | rc = ngx_event_connect_peer(&p->upstream); |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 507 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 508 | if (rc == NGX_ERROR) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 509 | ngx_http_proxy_finalize_request(p, |
| 510 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 511 | return; |
| 512 | } |
| 513 | |
| 514 | if (rc == NGX_CONNECT_ERROR) { |
| 515 | ngx_event_connect_peer_failed(&p->upstream); |
| 516 | |
| 517 | if (p->upstream.tries == 0) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 518 | ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 519 | return; |
| 520 | } |
| 521 | |
| 522 | continue; |
| 523 | } |
| 524 | |
| 525 | p->upstream.connection->data = p; |
| 526 | p->upstream.connection->write->event_handler = |
| 527 | ngx_http_proxy_send_request_handler; |
| 528 | p->upstream.connection->read->event_handler = |
| 529 | ngx_http_proxy_process_upstream_status_line; |
| 530 | |
| 531 | c = p->upstream.connection; |
| 532 | c->pool = p->request->pool; |
| 533 | c->read->log = c->write->log = c->log = p->request->connection->log; |
| 534 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 535 | if (p->upstream.tries > 1 && p->request_sent) { |
| 536 | |
| 537 | /* reinit the request chain */ |
| 538 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 539 | for (cl = p->request->request_hunks; cl; cl = cl->next) { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 540 | cl->hunk->pos = cl->hunk->start; |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 541 | } |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 542 | } |
| 543 | |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 544 | p->request_sent = 0; |
| 545 | p->timedout = 0; |
| 546 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 547 | if (rc == NGX_OK) { |
| 548 | break; |
| 549 | } |
| 550 | |
| 551 | /* rc == NGX_AGAIN */ |
| 552 | |
| 553 | ngx_add_timer(c->write, p->lcf->connect_timeout); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 554 | |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 555 | return; |
| 556 | } |
| 557 | } |
| 558 | } |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 559 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 560 | |
| 561 | static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev) |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 562 | { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 563 | int rc; |
| 564 | ssize_t n; |
| 565 | ngx_connection_t *c; |
| 566 | ngx_http_proxy_ctx_t *p; |
| 567 | |
| 568 | c = rev->data; |
| 569 | p = c->data; |
| 570 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 571 | p->action = "reading upstream status line"; |
| 572 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 573 | ngx_log_debug(rev->log, "http proxy process status line"); |
| 574 | |
| 575 | if (rev->timedout) { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 576 | p->timedout = 1; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 577 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 578 | return; |
| 579 | } |
| 580 | |
| 581 | if (p->header_in == NULL) { |
| 582 | p->header_in = ngx_create_temp_hunk(p->request->pool, |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 583 | p->lcf->header_buffer_size, |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 584 | 0, 0); |
| 585 | if (p->header_in == NULL) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 586 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 587 | return; |
| 588 | } |
Igor Sysoev | 5bf3d25 | 2003-10-22 07:05:29 +0000 | [diff] [blame] | 589 | p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 590 | } |
| 591 | |
| 592 | n = ngx_http_proxy_read_upstream_header(p); |
| 593 | |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 594 | if (n == NGX_ERROR) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 595 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 596 | return; |
| 597 | } |
| 598 | |
| 599 | if (n == NGX_AGAIN) { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 600 | return; |
| 601 | } |
| 602 | |
| 603 | rc = ngx_http_proxy_parse_status_line(p); |
| 604 | |
| 605 | if (rc == NGX_AGAIN) { |
| 606 | if (p->header_in->pos == p->header_in->last) { |
| 607 | ngx_log_error(NGX_LOG_ERR, rev->log, 0, |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 608 | "upstream sent too long status line"); |
| 609 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 610 | } |
| 611 | |
| 612 | return; |
| 613 | } |
| 614 | |
| 615 | if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 616 | ngx_log_error(NGX_LOG_ERR, rev->log, 0, |
| 617 | "upstream sent no valid HTTP/1.0 header"); |
| 618 | |
| 619 | if (p->accel) { |
| 620 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); |
| 621 | |
| 622 | } else { |
| 623 | p->request->http_version = NGX_HTTP_VERSION_9; |
| 624 | p->status = NGX_HTTP_OK; |
| 625 | ngx_http_proxy_send_response(p); |
| 626 | } |
| 627 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 628 | return; |
| 629 | } |
| 630 | |
| 631 | /* rc == NGX_OK */ |
| 632 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 633 | if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR |
| 634 | && p->upstream.tries > 1 |
| 635 | && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500)) |
| 636 | { |
| 637 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500); |
| 638 | return; |
| 639 | } |
| 640 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 641 | p->status_line.len = p->status_end - p->status_start; |
| 642 | p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1); |
| 643 | if (p->status_line.data == NULL) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 644 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 645 | return; |
| 646 | } |
| 647 | ngx_cpystrn(p->status_line.data, p->status_start, p->status_line.len + 1); |
| 648 | |
| 649 | ngx_log_debug(rev->log, "http proxy status %d '%s'" _ |
| 650 | p->status _ p->status_line.data); |
| 651 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 652 | if (p->headers_in.headers) { |
| 653 | p->headers_in.headers->nelts = 0; |
| 654 | } else { |
| 655 | p->headers_in.headers = ngx_create_table(p->request->pool, 10); |
| 656 | } |
| 657 | |
| 658 | c->read->event_handler = ngx_http_proxy_process_upstream_headers; |
| 659 | ngx_http_proxy_process_upstream_headers(rev); |
| 660 | |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 661 | return; |
| 662 | } |
| 663 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 664 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 665 | static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev) |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 666 | { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 667 | int i, rc; |
| 668 | ssize_t n; |
| 669 | ngx_table_elt_t *h; |
| 670 | ngx_connection_t *c; |
| 671 | ngx_http_request_t *r; |
| 672 | ngx_http_proxy_ctx_t *p; |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 673 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 674 | c = rev->data; |
| 675 | p = c->data; |
| 676 | r = p->request; |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 677 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 678 | p->action = "reading upstream headers"; |
| 679 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 680 | ngx_log_debug(rev->log, "http proxy process header line"); |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 681 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 682 | if (rev->timedout) { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 683 | p->timedout = 1; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 684 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 685 | return; |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 686 | } |
| 687 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 688 | rc = NGX_AGAIN; |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 689 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 690 | for ( ;; ) { |
| 691 | if (rc == NGX_AGAIN) { |
| 692 | n = ngx_http_proxy_read_upstream_header(p); |
| 693 | |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 694 | if (n == NGX_ERROR) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 695 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 696 | return; |
| 697 | } |
| 698 | |
| 699 | if (n == NGX_AGAIN) { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 700 | return; |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | rc = ngx_http_parse_header_line(p->request, p->header_in); |
| 705 | |
| 706 | if (rc == NGX_OK) { |
| 707 | |
| 708 | /* a header line has been parsed successfully */ |
| 709 | |
| 710 | h = ngx_push_table(p->headers_in.headers); |
| 711 | if (h == NULL) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 712 | ngx_http_proxy_finalize_request(p, |
| 713 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 714 | return; |
| 715 | } |
| 716 | |
| 717 | h->key.len = r->header_name_end - r->header_name_start; |
| 718 | h->value.len = r->header_end - r->header_start; |
| 719 | |
| 720 | h->key.data = ngx_palloc(p->request->pool, |
| 721 | h->key.len + 1 + h->value.len + 1); |
| 722 | if (h->key.data == NULL) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 723 | ngx_http_proxy_finalize_request(p, |
| 724 | NGX_HTTP_INTERNAL_SERVER_ERROR); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 725 | return; |
| 726 | } |
| 727 | |
| 728 | h->value.data = h->key.data + h->key.len + 1; |
| 729 | ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); |
| 730 | ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); |
| 731 | |
| 732 | for (i = 0; headers_in[i].name.len != 0; i++) { |
| 733 | if (headers_in[i].name.len != h->key.len) { |
| 734 | continue; |
| 735 | } |
| 736 | |
| 737 | if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) { |
| 738 | *((ngx_table_elt_t **) |
| 739 | ((char *) &p->headers_in + headers_in[i].offset)) = h; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 740 | break; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 741 | } |
| 742 | } |
| 743 | |
| 744 | ngx_log_debug(c->log, "HTTP proxy header: '%s: %s'" _ |
| 745 | h->key.data _ h->value.data); |
| 746 | |
| 747 | continue; |
| 748 | |
| 749 | } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) { |
| 750 | |
| 751 | /* a whole header has been parsed successfully */ |
| 752 | |
| 753 | ngx_log_debug(c->log, "HTTP header done"); |
| 754 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 755 | ngx_http_proxy_send_response(p); |
| 756 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 757 | return; |
| 758 | |
| 759 | } else if (rc != NGX_AGAIN) { |
| 760 | |
| 761 | /* there was error while a header line parsing */ |
| 762 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 763 | ngx_log_error(NGX_LOG_ERR, rev->log, 0, |
| 764 | upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]); |
| 765 | |
| 766 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 767 | return; |
| 768 | } |
| 769 | |
| 770 | /* NGX_AGAIN: a header line parsing is still not complete */ |
| 771 | |
| 772 | if (p->header_in->last == p->header_in->end) { |
| 773 | ngx_log_error(NGX_LOG_ERR, rev->log, 0, |
| 774 | "upstream sent too big header"); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 775 | |
| 776 | ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 777 | return; |
| 778 | } |
| 779 | } |
| 780 | } |
| 781 | |
| 782 | |
| 783 | static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p) |
| 784 | { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 785 | ssize_t n; |
| 786 | ngx_event_t *rev; |
| 787 | |
| 788 | rev = p->upstream.connection->read; |
| 789 | |
| 790 | n = p->header_in->last - p->header_in->pos; |
| 791 | |
| 792 | if (n > 0) { |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 793 | #if 0 |
| 794 | /* TODO THINK */ |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 795 | rev->ready = 0; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 796 | #endif |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 797 | return n; |
| 798 | } |
| 799 | |
| 800 | n = ngx_recv(p->upstream.connection, p->header_in->last, |
| 801 | p->header_in->end - p->header_in->last); |
| 802 | |
| 803 | if (n == NGX_AGAIN) { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 804 | ngx_add_timer(rev, p->lcf->read_timeout); |
| 805 | |
Igor Sysoev | 0a280a3 | 2003-10-12 16:49:16 +0000 | [diff] [blame] | 806 | if (ngx_handle_read_event(rev) == NGX_ERROR) { |
| 807 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 808 | return NGX_ERROR; |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 809 | } |
| 810 | |
| 811 | return NGX_AGAIN; |
| 812 | } |
| 813 | |
| 814 | if (n == 0) { |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 815 | ngx_log_error(NGX_LOG_ERR, rev->log, 0, |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 816 | "upstream closed prematurely connection"); |
| 817 | } |
| 818 | |
| 819 | if (n == 0 || n == NGX_ERROR) { |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 820 | return NGX_ERROR; |
| 821 | } |
| 822 | |
| 823 | p->header_in->last += n; |
| 824 | |
| 825 | return n; |
| 826 | } |
| 827 | |
| 828 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 829 | static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p) |
| 830 | { |
| 831 | int rc, i; |
| 832 | ngx_table_elt_t *ch, *ph; |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 833 | ngx_event_pipe_t *ep; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 834 | ngx_http_request_t *r; |
| 835 | |
| 836 | r = p->request; |
| 837 | |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 838 | r->headers_out.content_length_n = -1; |
| 839 | r->headers_out.content_length = NULL; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 840 | |
| 841 | /* copy an upstream header to r->headers_out */ |
| 842 | |
| 843 | ph = (ngx_table_elt_t *) p->headers_in.headers->elts; |
| 844 | for (i = 0; i < p->headers_in.headers->nelts; i++) { |
| 845 | |
| 846 | if (&ph[i] == p->headers_in.connection) { |
| 847 | continue; |
| 848 | } |
| 849 | |
| 850 | if (p->accel) { |
| 851 | if (&ph[i] == p->headers_in.date |
| 852 | || &ph[i] == p->headers_in.accept_ranges) { |
| 853 | continue; |
| 854 | } |
| 855 | } |
| 856 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 857 | ch = ngx_push_table(r->headers_out.headers); |
| 858 | if (ch == NULL) { |
| 859 | ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 860 | return; |
| 861 | } |
| 862 | |
| 863 | *ch = ph[i]; |
| 864 | |
| 865 | if (&ph[i] == p->headers_in.content_type) { |
| 866 | r->headers_out.content_type = ch; |
| 867 | r->headers_out.content_type->key.len = 0; |
| 868 | continue; |
| 869 | } |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 870 | |
| 871 | if (&ph[i] == p->headers_in.content_length) { |
| 872 | r->headers_out.content_length_n = |
| 873 | ngx_atoi(p->headers_in.content_length->value.data, |
| 874 | p->headers_in.content_length->value.len); |
| 875 | r->headers_out.content_length = ch; |
| 876 | continue; |
| 877 | } |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 878 | } |
| 879 | |
| 880 | /* STUB */ |
| 881 | |
| 882 | if (p->headers_in.server) { |
| 883 | r->headers_out.server = p->headers_in.server; |
| 884 | } |
| 885 | |
| 886 | if (!p->accel && p->headers_in.date) { |
| 887 | r->headers_out.date = p->headers_in.date; |
| 888 | } |
| 889 | |
| 890 | /* */ |
| 891 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 892 | |
| 893 | /* TODO: preallocate event_pipe hunks, look "Content-Length" */ |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 894 | |
| 895 | r->headers_out.status = p->status; |
| 896 | |
| 897 | rc = ngx_http_send_header(r); |
| 898 | |
| 899 | p->header_sent = 1; |
| 900 | |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 901 | ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 902 | if (ep == NULL) { |
| 903 | ngx_http_proxy_finalize_request(p, 0); |
| 904 | return; |
| 905 | } |
| 906 | |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 907 | ep->input_filter = ngx_event_pipe_copy_input_filter; |
| 908 | ep->output_filter = (ngx_event_pipe_output_filter_pt) |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 909 | ngx_http_output_filter; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 910 | ep->output_ctx = r; |
Igor Sysoev | 5bf3d25 | 2003-10-22 07:05:29 +0000 | [diff] [blame] | 911 | ep->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 912 | ep->bufs = p->lcf->bufs; |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 913 | ep->busy_size = p->lcf->busy_buffers_size; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 914 | ep->upstream = p->upstream.connection; |
| 915 | ep->downstream = r->connection; |
| 916 | ep->pool = r->pool; |
| 917 | ep->log = r->connection->log; |
| 918 | ep->temp_path = p->lcf->temp_path; |
| 919 | |
Igor Sysoev | 5bf3d25 | 2003-10-22 07:05:29 +0000 | [diff] [blame] | 920 | ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 921 | if (ep->temp_file == NULL) { |
| 922 | ngx_http_proxy_finalize_request(p, 0); |
| 923 | return; |
| 924 | } |
| 925 | |
| 926 | ep->temp_file->fd = NGX_INVALID_FILE; |
| 927 | ep->temp_file->log = r->connection->log; |
| 928 | |
| 929 | ep->max_temp_file_size = p->lcf->max_temp_file_size; |
| 930 | ep->temp_file_write_size = p->lcf->temp_file_write_size; |
| 931 | ep->temp_file_warn = "an upstream response is buffered " |
| 932 | "to a temporary file"; |
| 933 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 934 | ep->preread_hunks = ngx_alloc_chain_link(r->pool); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 935 | if (ep->preread_hunks == NULL) { |
| 936 | ngx_http_proxy_finalize_request(p, 0); |
| 937 | return; |
| 938 | } |
| 939 | ep->preread_hunks->hunk = p->header_in; |
| 940 | ep->preread_hunks->next = NULL; |
| 941 | |
| 942 | ep->preread_size = p->header_in->last - p->header_in->pos; |
| 943 | |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 944 | /* |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 945 | * event_pipe would do p->header_in->last += ep->preread_size |
| 946 | * as though these bytes were read. |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 947 | */ |
| 948 | p->header_in->last = p->header_in->pos; |
| 949 | |
Igor Sysoev | 5bf3d25 | 2003-10-22 07:05:29 +0000 | [diff] [blame] | 950 | /* STUB */ ep->cachable = 0; |
| 951 | |
| 952 | if (p->lcf->cyclic_temp_file) { |
| 953 | |
| 954 | /* |
| 955 | * we need to disable the use of sendfile() if we use cyclic temp file |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 956 | * because the writing a new data can interfere with sendfile() |
| 957 | * that uses the same kernel file pages (at least on FreeBSD) |
Igor Sysoev | 5bf3d25 | 2003-10-22 07:05:29 +0000 | [diff] [blame] | 958 | */ |
| 959 | |
| 960 | ep->cyclic_temp_file = 1; |
| 961 | r->sendfile = 0; |
| 962 | |
| 963 | } else { |
| 964 | ep->cyclic_temp_file = 0; |
| 965 | r->sendfile = 1; |
| 966 | } |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 967 | |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 968 | p->event_pipe = ep; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 969 | |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 970 | p->upstream.connection->read->event_handler = ngx_http_proxy_process_body; |
| 971 | r->connection->write->event_handler = ngx_http_proxy_process_body; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 972 | |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 973 | ngx_http_proxy_process_body(p->upstream.connection->read); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 974 | |
| 975 | return; |
| 976 | } |
| 977 | |
| 978 | |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 979 | static void ngx_http_proxy_process_body(ngx_event_t *ev) |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 980 | { |
| 981 | ngx_connection_t *c; |
Igor Sysoev | 13829b7 | 2003-10-19 19:57:23 +0000 | [diff] [blame] | 982 | ngx_http_request_t *r; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 983 | ngx_http_proxy_ctx_t *p; |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 984 | ngx_event_pipe_t *ep; |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 985 | |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 986 | c = ev->data; |
| 987 | |
| 988 | if (ev->write) { |
| 989 | ngx_log_debug(ev->log, "http proxy process downstream"); |
| 990 | r = c->data; |
| 991 | p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 992 | p->action = "sending to client"; |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 993 | |
| 994 | } else { |
| 995 | ngx_log_debug(ev->log, "http proxy process upstream"); |
| 996 | p = c->data; |
| 997 | r = p->request; |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 998 | p->action = "reading upstream body"; |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 999 | } |
| 1000 | |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 1001 | ep = p->event_pipe; |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1002 | |
| 1003 | if (ev->timedout) { |
| 1004 | if (ev->write) { |
| 1005 | ep->downstream_error = 1; |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 1006 | ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, |
| 1007 | "client timed out"); |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1008 | |
| 1009 | } else { |
| 1010 | ep->upstream_error = 1; |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 1011 | ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, |
| 1012 | "upstream timed out"); |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1013 | } |
| 1014 | |
| 1015 | } else { |
Igor Sysoev | 419f9ac | 2003-10-21 16:49:56 +0000 | [diff] [blame] | 1016 | if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) { |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1017 | ngx_http_proxy_finalize_request(p, 0); |
| 1018 | return; |
| 1019 | } |
| 1020 | } |
| 1021 | |
| 1022 | if (p->upstream.connection) { |
| 1023 | if (ep->upstream_done) { |
| 1024 | /* TODO: update cache */ |
| 1025 | |
| 1026 | } else if (ep->upstream_eof) { |
| 1027 | /* TODO: check length & update cache */ |
| 1028 | } |
| 1029 | |
| 1030 | if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) { |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1031 | ngx_http_proxy_close_connection(p->upstream.connection); |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1032 | p->upstream.connection = NULL; |
| 1033 | } |
| 1034 | } |
| 1035 | |
| 1036 | if (ep->downstream_done) { |
| 1037 | ngx_log_debug(ev->log, "http proxy downstream done"); |
| 1038 | ngx_http_proxy_finalize_request(p, r->main ? 0 : ngx_http_send_last(r)); |
| 1039 | return; |
| 1040 | } |
| 1041 | |
| 1042 | if (ep->downstream_error) { |
| 1043 | if (!p->cachable && p->upstream.connection) { |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1044 | ngx_http_proxy_close_connection(p->upstream.connection); |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1045 | p->upstream.connection = NULL; |
| 1046 | } |
Igor Sysoev | 13829b7 | 2003-10-19 19:57:23 +0000 | [diff] [blame] | 1047 | |
Igor Sysoev | 54276be | 2003-10-20 17:14:07 +0000 | [diff] [blame] | 1048 | if (p->upstream.connection == NULL) { |
| 1049 | ngx_http_close_connection(c); |
| 1050 | } |
Igor Sysoev | fd3e374 | 2003-10-08 04:34:07 +0000 | [diff] [blame] | 1051 | } |
| 1052 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1053 | return; |
| 1054 | } |
| 1055 | |
| 1056 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1057 | static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p) |
| 1058 | { |
| 1059 | char ch; |
| 1060 | char *pos; |
| 1061 | enum { |
| 1062 | sw_start = 0, |
| 1063 | sw_H, |
| 1064 | sw_HT, |
| 1065 | sw_HTT, |
| 1066 | sw_HTTP, |
| 1067 | sw_first_major_digit, |
| 1068 | sw_major_digit, |
| 1069 | sw_first_minor_digit, |
| 1070 | sw_minor_digit, |
| 1071 | sw_status, |
| 1072 | sw_space_after_status, |
| 1073 | sw_status_text, |
| 1074 | sw_almost_done, |
| 1075 | sw_done |
| 1076 | } state; |
| 1077 | |
| 1078 | state = p->state; |
| 1079 | pos = p->header_in->pos; |
| 1080 | |
| 1081 | while (pos < p->header_in->last && state < sw_done) { |
| 1082 | ch = *pos++; |
| 1083 | |
| 1084 | switch (state) { |
| 1085 | |
| 1086 | /* "HTTP/" */ |
| 1087 | case sw_start: |
| 1088 | switch (ch) { |
| 1089 | case 'H': |
| 1090 | state = sw_H; |
| 1091 | break; |
| 1092 | default: |
| 1093 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1094 | } |
| 1095 | break; |
| 1096 | |
| 1097 | case sw_H: |
| 1098 | switch (ch) { |
| 1099 | case 'T': |
| 1100 | state = sw_HT; |
| 1101 | break; |
| 1102 | default: |
| 1103 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1104 | } |
| 1105 | break; |
| 1106 | |
| 1107 | case sw_HT: |
| 1108 | switch (ch) { |
| 1109 | case 'T': |
| 1110 | state = sw_HTT; |
| 1111 | break; |
| 1112 | default: |
| 1113 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1114 | } |
| 1115 | break; |
| 1116 | |
| 1117 | case sw_HTT: |
| 1118 | switch (ch) { |
| 1119 | case 'P': |
| 1120 | state = sw_HTTP; |
| 1121 | break; |
| 1122 | default: |
| 1123 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1124 | } |
| 1125 | break; |
| 1126 | |
| 1127 | case sw_HTTP: |
| 1128 | switch (ch) { |
| 1129 | case '/': |
| 1130 | state = sw_first_major_digit; |
| 1131 | break; |
| 1132 | default: |
| 1133 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1134 | } |
| 1135 | break; |
| 1136 | |
| 1137 | /* the first digit of major HTTP version */ |
| 1138 | case sw_first_major_digit: |
| 1139 | if (ch < '1' || ch > '9') { |
| 1140 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1141 | } |
| 1142 | |
| 1143 | state = sw_major_digit; |
| 1144 | break; |
| 1145 | |
| 1146 | /* the major HTTP version or dot */ |
| 1147 | case sw_major_digit: |
| 1148 | if (ch == '.') { |
| 1149 | state = sw_first_minor_digit; |
| 1150 | break; |
| 1151 | } |
| 1152 | |
| 1153 | if (ch < '0' || ch > '9') { |
| 1154 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1155 | } |
| 1156 | |
| 1157 | break; |
| 1158 | |
| 1159 | /* the first digit of minor HTTP version */ |
| 1160 | case sw_first_minor_digit: |
| 1161 | if (ch < '0' || ch > '9') { |
| 1162 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1163 | } |
| 1164 | |
| 1165 | state = sw_minor_digit; |
| 1166 | break; |
| 1167 | |
| 1168 | /* the minor HTTP version or the end of the request line */ |
| 1169 | case sw_minor_digit: |
| 1170 | if (ch == ' ') { |
| 1171 | state = sw_status; |
| 1172 | break; |
| 1173 | } |
| 1174 | |
| 1175 | if (ch < '0' || ch > '9') { |
| 1176 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1177 | } |
| 1178 | |
| 1179 | break; |
| 1180 | |
| 1181 | /* HTTP status code */ |
| 1182 | case sw_status: |
| 1183 | if (ch < '0' || ch > '9') { |
| 1184 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1185 | } |
| 1186 | |
| 1187 | p->status = p->status * 10 + ch - '0'; |
| 1188 | |
| 1189 | if (++p->status_count == 3) { |
| 1190 | state = sw_space_after_status; |
| 1191 | p->status_start = pos - 3; |
| 1192 | } |
| 1193 | |
| 1194 | break; |
| 1195 | |
| 1196 | /* space or end of line */ |
| 1197 | case sw_space_after_status: |
| 1198 | switch (ch) { |
| 1199 | case ' ': |
| 1200 | state = sw_status_text; |
| 1201 | break; |
| 1202 | case CR: |
| 1203 | state = sw_almost_done; |
| 1204 | break; |
| 1205 | case LF: |
| 1206 | state = sw_done; |
| 1207 | break; |
| 1208 | default: |
| 1209 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1210 | } |
| 1211 | break; |
| 1212 | |
| 1213 | /* any text until end of line */ |
| 1214 | case sw_status_text: |
| 1215 | switch (ch) { |
| 1216 | case CR: |
| 1217 | state = sw_almost_done; |
| 1218 | |
| 1219 | break; |
| 1220 | case LF: |
| 1221 | state = sw_done; |
| 1222 | break; |
| 1223 | } |
| 1224 | break; |
| 1225 | |
| 1226 | /* end of request line */ |
| 1227 | case sw_almost_done: |
| 1228 | p->status_end = pos - 2; |
| 1229 | switch (ch) { |
| 1230 | case LF: |
| 1231 | state = sw_done; |
| 1232 | break; |
| 1233 | default: |
| 1234 | return NGX_HTTP_PROXY_PARSE_NO_HEADER; |
| 1235 | } |
| 1236 | break; |
| 1237 | } |
| 1238 | } |
| 1239 | |
| 1240 | p->header_in->pos = pos; |
| 1241 | |
| 1242 | if (state == sw_done) { |
| 1243 | if (p->status_end == NULL) { |
| 1244 | p->status_end = pos - 1; |
| 1245 | } |
| 1246 | |
| 1247 | p->state = sw_start; |
| 1248 | return NGX_OK; |
| 1249 | } |
| 1250 | |
| 1251 | p->state = state; |
| 1252 | return NGX_AGAIN; |
| 1253 | } |
| 1254 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1255 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1256 | static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type) |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 1257 | { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 1258 | ngx_event_connect_peer_failed(&p->upstream); |
| 1259 | |
| 1260 | if (p->timedout) { |
| 1261 | ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT, |
| 1262 | "upstream timed out"); |
| 1263 | } |
| 1264 | |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 1265 | if (p->upstream.connection) { |
| 1266 | ngx_http_proxy_close_connection(p->upstream.connection); |
| 1267 | p->upstream.connection = NULL; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1268 | } |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 1269 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1270 | if (p->upstream.tries == 0 || !(p->lcf->next_upstream & ft_type)) { |
Igor Sysoev | 6414b96 | 2003-10-24 16:10:38 +0000 | [diff] [blame] | 1271 | ngx_http_proxy_finalize_request(p, |
| 1272 | p->timedout ? NGX_HTTP_GATEWAY_TIME_OUT: |
| 1273 | NGX_HTTP_BAD_GATEWAY); |
| 1274 | return; |
| 1275 | } |
| 1276 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1277 | if (!p->fatal_error) { |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 1278 | ngx_http_proxy_send_request(p); |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1279 | return; |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 1280 | } |
| 1281 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1282 | ngx_log_debug(p->request->connection->log, "FATAL ERROR IN NEXT UPSTREAM"); |
| 1283 | |
Igor Sysoev | 1dd4ac8 | 2003-10-06 03:56:42 +0000 | [diff] [blame] | 1284 | return; |
| 1285 | } |
| 1286 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1287 | static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc) |
| 1288 | { |
Igor Sysoev | 2b0c76c | 2003-10-27 21:01:00 +0000 | [diff] [blame^] | 1289 | ngx_log_debug(p->request->connection->log, |
| 1290 | "finalize http proxy request"); |
| 1291 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1292 | if (p->upstream.connection) { |
| 1293 | ngx_http_proxy_close_connection(p->upstream.connection); |
| 1294 | p->upstream.connection = NULL; |
| 1295 | } |
| 1296 | |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1297 | if (p->header_sent |
| 1298 | && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) |
| 1299 | { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1300 | rc = 0; |
| 1301 | } |
| 1302 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1303 | p->request->connection->log->data = p->saved_ctx; |
| 1304 | p->request->connection->log->handler = p->saved_handler; |
| 1305 | |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1306 | ngx_http_finalize_request(p->request, rc); |
| 1307 | |
| 1308 | p->fatal_error = 1; |
| 1309 | |
| 1310 | return; |
| 1311 | } |
| 1312 | |
| 1313 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1314 | |
| 1315 | static void ngx_http_proxy_close_connection(ngx_connection_t *c) |
| 1316 | { |
| 1317 | ngx_log_debug(c->log, "close connection: %d" _ c->fd); |
| 1318 | |
| 1319 | if (c->fd == -1) { |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1320 | #if 0 |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1321 | ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1322 | #endif |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1323 | return; |
| 1324 | } |
| 1325 | |
| 1326 | if (c->read->timer_set) { |
| 1327 | ngx_del_timer(c->read); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1328 | } |
| 1329 | |
| 1330 | if (c->write->timer_set) { |
| 1331 | ngx_del_timer(c->write); |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1332 | } |
| 1333 | |
Igor Sysoev | fd3e374 | 2003-10-08 04:34:07 +0000 | [diff] [blame] | 1334 | /* TODO: move connection to the connection pool */ |
| 1335 | |
Igor Sysoev | e677922 | 2003-10-03 15:50:53 +0000 | [diff] [blame] | 1336 | if (ngx_del_conn) { |
| 1337 | ngx_del_conn(c); |
| 1338 | |
| 1339 | } else { |
| 1340 | if (c->read->active) { |
| 1341 | ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); |
| 1342 | } |
| 1343 | |
| 1344 | if (c->write->active) { |
| 1345 | ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | if (ngx_close_socket(c->fd) == -1) { |
| 1350 | ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, |
| 1351 | ngx_close_socket_n " failed"); |
| 1352 | } |
| 1353 | |
| 1354 | c->fd = -1; |
| 1355 | |
| 1356 | return; |
Igor Sysoev | 87a01ea | 2003-10-02 05:39:37 +0000 | [diff] [blame] | 1357 | } |
| 1358 | |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 1359 | |
| 1360 | static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len) |
| 1361 | { |
| 1362 | ngx_http_proxy_ctx_t *p = data; |
| 1363 | |
| 1364 | return ngx_snprintf(buf, len, |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1365 | " while %s, client: %s, URL: %s, upstream: %s%s%s%s%s", |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 1366 | p->action, |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 1367 | p->request->connection->addr_text.data, |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1368 | p->request->unparsed_uri.data, |
| 1369 | p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data, |
| 1370 | p->lcf->upstream->uri.data, |
| 1371 | p->request->uri.data + p->lcf->upstream->location->len, |
| 1372 | p->request->args.len ? "?" : "", |
| 1373 | p->request->args.len ? p->request->args.data : ""); |
Igor Sysoev | 0441050 | 2003-08-01 14:56:33 +0000 | [diff] [blame] | 1374 | } |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 1375 | |
| 1376 | |
| 1377 | static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) |
| 1378 | { |
| 1379 | ngx_http_proxy_loc_conf_t *conf; |
| 1380 | |
| 1381 | ngx_test_null(conf, |
| 1382 | ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)), |
| 1383 | NGX_CONF_ERROR); |
| 1384 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1385 | /* set by ngx_pcalloc(): |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 1386 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1387 | conf->bufs.num = 0; |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 1388 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1389 | conf->path = NULL; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1390 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1391 | conf->upstreams = NULL; |
| 1392 | conf->peers = NULL; |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1393 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1394 | */ |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1395 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1396 | conf->request_buffer_size = NGX_CONF_UNSET; |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1397 | conf->connect_timeout = NGX_CONF_UNSET; |
| 1398 | conf->send_timeout = NGX_CONF_UNSET; |
| 1399 | conf->header_buffer_size = NGX_CONF_UNSET; |
| 1400 | conf->read_timeout = NGX_CONF_UNSET; |
| 1401 | conf->busy_buffers_size = NGX_CONF_UNSET; |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1402 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1403 | /* |
| 1404 | * "proxy_max_temp_file_size" is hardcoded to 1G for reverse proxy, |
| 1405 | * it should be configurable in the generic proxy |
| 1406 | */ |
| 1407 | conf->max_temp_file_size = 1024 * 1024 * 1024; |
Igor Sysoev | 9760a13 | 2003-10-21 07:47:21 +0000 | [diff] [blame] | 1408 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1409 | conf->temp_file_write_size = NGX_CONF_UNSET; |
Igor Sysoev | 931a400 | 2003-10-07 15:30:05 +0000 | [diff] [blame] | 1410 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1411 | /* "proxy_cyclic_temp_file" is disabled */ |
| 1412 | conf->cyclic_temp_file = 0; |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 1413 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1414 | conf->next_upstream = NGX_CONF_UNSET; |
| 1415 | |
Igor Sysoev | ae5c59c | 2003-08-14 06:00:28 +0000 | [diff] [blame] | 1416 | return conf; |
| 1417 | } |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 1418 | |
| 1419 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1420 | static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, |
| 1421 | void *parent, void *child) |
| 1422 | { |
| 1423 | ngx_http_proxy_loc_conf_t *prev = parent; |
| 1424 | ngx_http_proxy_loc_conf_t *conf = child; |
| 1425 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1426 | ngx_conf_merge_size_value(conf->request_buffer_size, |
| 1427 | prev->request_buffer_size, 8192); |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1428 | ngx_conf_merge_msec_value(conf->connect_timeout, |
| 1429 | prev->connect_timeout, 60000); |
| 1430 | ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 30000); |
| 1431 | ngx_conf_merge_size_value(conf->header_buffer_size, |
| 1432 | prev->header_buffer_size, 4096); |
| 1433 | ngx_conf_merge_msec_value(conf->read_timeout, prev->read_timeout, 30000); |
| 1434 | ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 8, 4096); |
| 1435 | ngx_conf_merge_size_value(conf->busy_buffers_size, |
| 1436 | prev->busy_buffers_size, 8192); |
| 1437 | |
| 1438 | #if 0 |
| 1439 | if (conf->max_temp_file_size > conf->bufs.size) { |
| 1440 | return "\"proxy_max_temp_file\" must be greater " |
| 1441 | "than one of the \"proxy_buffers\""; |
| 1442 | } |
| 1443 | #endif |
| 1444 | |
| 1445 | ngx_conf_merge_size_value(conf->temp_file_write_size, |
| 1446 | prev->temp_file_write_size, 16384); |
| 1447 | |
Igor Sysoev | 10fc9ef | 2003-10-27 08:53:49 +0000 | [diff] [blame] | 1448 | ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, |
| 1449 | (NGX_HTTP_PROXY_FT_ERROR|NGX_HTTP_PROXY_FT_TIMEOUT)); |
| 1450 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1451 | ngx_conf_merge_path_value(conf->temp_path, prev->temp_path, |
| 1452 | "temp", 1, 2, 0, cf->pool); |
| 1453 | |
| 1454 | return NULL; |
| 1455 | } |
| 1456 | |
| 1457 | |
| 1458 | |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 1459 | static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, |
| 1460 | void *conf) |
| 1461 | { |
| 1462 | ngx_http_proxy_loc_conf_t *lcf = conf; |
| 1463 | |
| 1464 | int i, len; |
| 1465 | char *err, *host; |
| 1466 | ngx_str_t *value; |
| 1467 | struct hostent *h; |
| 1468 | u_int32_t addr; |
| 1469 | ngx_http_conf_ctx_t *ctx; |
| 1470 | ngx_http_core_loc_conf_t *clcf; |
| 1471 | |
| 1472 | |
| 1473 | value = cf->args->elts; |
| 1474 | |
| 1475 | if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) { |
| 1476 | return "invalid URL prefix"; |
| 1477 | } |
| 1478 | |
| 1479 | ngx_test_null(lcf->upstream, |
| 1480 | ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_t)), |
| 1481 | NGX_CONF_ERROR); |
| 1482 | |
| 1483 | value[1].data += 7; |
| 1484 | value[1].len -= 7; |
| 1485 | |
| 1486 | err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream); |
| 1487 | |
| 1488 | if (err) { |
| 1489 | return err; |
| 1490 | } |
| 1491 | |
| 1492 | ngx_test_null(host, ngx_palloc(cf->pool, lcf->upstream->host.len + 1), |
| 1493 | NGX_CONF_ERROR); |
| 1494 | ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1); |
| 1495 | |
| 1496 | addr = inet_addr(host); |
| 1497 | |
| 1498 | if (addr == INADDR_NONE) { |
| 1499 | h = gethostbyname(host); |
| 1500 | |
| 1501 | if (h == NULL || h->h_addr_list[0] == NULL) { |
| 1502 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host); |
| 1503 | return NGX_CONF_ERROR; |
| 1504 | } |
| 1505 | |
| 1506 | for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } |
| 1507 | |
| 1508 | /* MP: ngx_shared_palloc() */ |
| 1509 | |
| 1510 | ngx_test_null(lcf->peers, |
| 1511 | ngx_pcalloc(cf->pool, |
| 1512 | sizeof(ngx_peers_t) |
| 1513 | + sizeof(ngx_peer_t) * (i - 1)), |
| 1514 | NGX_CONF_ERROR); |
| 1515 | |
| 1516 | lcf->peers->number = i; |
| 1517 | |
| 1518 | for (i = 0; h->h_addr_list[i] != NULL; i++) { |
| 1519 | lcf->peers->peers[i].host.data = host; |
| 1520 | lcf->peers->peers[i].host.len = lcf->upstream->host.len; |
| 1521 | lcf->peers->peers[i].addr = *(u_int32_t *)(h->h_addr_list[i]); |
| 1522 | lcf->peers->peers[i].port = lcf->upstream->port; |
| 1523 | |
| 1524 | len = INET_ADDRSTRLEN + lcf->upstream->port_text.len + 1; |
| 1525 | ngx_test_null(lcf->peers->peers[i].addr_port_text.data, |
| 1526 | ngx_palloc(cf->pool, len), |
| 1527 | NGX_CONF_ERROR); |
| 1528 | |
| 1529 | len = ngx_inet_ntop(AF_INET, |
| 1530 | (char *) &lcf->peers->peers[i].addr, |
| 1531 | lcf->peers->peers[i].addr_port_text.data, |
| 1532 | len); |
| 1533 | |
| 1534 | lcf->peers->peers[i].addr_port_text.data[len++] = ':'; |
| 1535 | |
| 1536 | ngx_cpystrn(lcf->peers->peers[i].addr_port_text.data + len, |
| 1537 | lcf->upstream->port_text.data, |
| 1538 | lcf->upstream->port_text.len + 1); |
| 1539 | |
| 1540 | lcf->peers->peers[i].addr_port_text.len = |
| 1541 | len + lcf->upstream->port_text.len + 1; |
| 1542 | } |
| 1543 | |
| 1544 | } else { |
| 1545 | |
| 1546 | /* MP: ngx_shared_palloc() */ |
| 1547 | |
| 1548 | ngx_test_null(lcf->peers, ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)), |
| 1549 | NGX_CONF_ERROR); |
| 1550 | |
| 1551 | lcf->peers->number = 1; |
| 1552 | |
| 1553 | lcf->peers->peers[0].host.data = host; |
| 1554 | lcf->peers->peers[0].host.len = lcf->upstream->host.len; |
| 1555 | lcf->peers->peers[0].addr = addr; |
| 1556 | lcf->peers->peers[0].port = lcf->upstream->port; |
| 1557 | |
| 1558 | len = lcf->upstream->host.len + lcf->upstream->port_text.len + 1; |
| 1559 | |
| 1560 | ngx_test_null(lcf->peers->peers[0].addr_port_text.data, |
| 1561 | ngx_palloc(cf->pool, len + 1), |
| 1562 | NGX_CONF_ERROR); |
| 1563 | |
| 1564 | len = lcf->upstream->host.len; |
| 1565 | |
| 1566 | ngx_memcpy(lcf->peers->peers[0].addr_port_text.data, |
| 1567 | lcf->upstream->host.data, len); |
| 1568 | |
| 1569 | lcf->peers->peers[0].addr_port_text.data[len++] = ':'; |
| 1570 | |
| 1571 | ngx_cpystrn(lcf->peers->peers[0].addr_port_text.data + len, |
| 1572 | lcf->upstream->port_text.data, |
| 1573 | lcf->upstream->port_text.len + 1); |
| 1574 | } |
| 1575 | |
| 1576 | ctx = cf->ctx; |
| 1577 | clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; |
| 1578 | lcf->upstream->location = &clcf->name; |
| 1579 | clcf->handler = ngx_http_proxy_handler; |
| 1580 | |
| 1581 | return NULL; |
| 1582 | } |
| 1583 | |
Igor Sysoev | dc9dd43 | 2003-10-22 16:38:26 +0000 | [diff] [blame] | 1584 | |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 1585 | static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, |
| 1586 | ngx_http_proxy_upstream_t *u) |
| 1587 | { |
| 1588 | size_t i; |
| 1589 | |
| 1590 | if (url->data[0] == ':' || url->data[0] == '/') { |
| 1591 | return "invalid upstream URL"; |
| 1592 | } |
| 1593 | |
| 1594 | u->host.data = url->data; |
| 1595 | u->host_header.data = url->data; |
| 1596 | |
| 1597 | for (i = 1; i < url->len; i++) { |
| 1598 | if (url->data[i] == ':') { |
| 1599 | u->port_text.data = &url->data[i] + 1; |
| 1600 | u->host.len = i; |
| 1601 | } |
| 1602 | |
| 1603 | if (url->data[i] == '/') { |
| 1604 | u->uri.data = &url->data[i]; |
| 1605 | u->uri.len = url->len - i; |
| 1606 | u->host_header.len = i; |
| 1607 | |
| 1608 | if (u->host.len == 0) { |
| 1609 | u->host.len = i; |
| 1610 | } |
| 1611 | |
| 1612 | if (u->port_text.data == NULL) { |
| 1613 | u->port = htons(80); |
| 1614 | u->port_text.len = 2; |
| 1615 | u->port_text.data = "80"; |
| 1616 | return NULL; |
| 1617 | } |
| 1618 | |
| 1619 | u->port_text.len = &url->data[i] - u->port_text.data; |
| 1620 | |
| 1621 | if (u->port_text.len > 0) { |
| 1622 | u->port = ngx_atoi(u->port_text.data, u->port_text.len); |
| 1623 | if (u->port > 0) { |
| 1624 | u->port = htons((u_short) u->port); |
| 1625 | return NULL; |
| 1626 | } |
| 1627 | } |
| 1628 | |
| 1629 | return "invalid port in upstream URL"; |
| 1630 | } |
| 1631 | } |
| 1632 | |
| 1633 | if (u->host.len == 0) { |
| 1634 | u->host.len = i; |
| 1635 | } |
| 1636 | |
| 1637 | u->host_header.len = i; |
| 1638 | |
| 1639 | u->uri.data = "/"; |
| 1640 | u->uri.len = 1; |
| 1641 | |
| 1642 | if (u->port_text.data == NULL) { |
| 1643 | u->port = htons(80); |
| 1644 | u->port_text.len = 2; |
| 1645 | u->port_text.data = "80"; |
| 1646 | return NULL; |
| 1647 | } |
| 1648 | |
| 1649 | u->port_text.len = &url->data[i] - u->port_text.data; |
| 1650 | |
| 1651 | if (u->port_text.len > 0) { |
| 1652 | u->port = ngx_atoi(u->port_text.data, u->port_text.len); |
| 1653 | if (u->port > 0) { |
| 1654 | u->port = htons((u_short) u->port); |
| 1655 | return NULL; |
| 1656 | } |
| 1657 | } |
| 1658 | |
| 1659 | return "invalid port in upstream URL"; |
| 1660 | } |