diff src/http/modules/proxy/ngx_http_proxy_handler.c @ 160:e7e094d34162

nginx-0.0.1-2003-10-27-11:53:49 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 27 Oct 2003 08:53:49 +0000
parents 981e4af2a425
children 88abd07d9f62
line wrap: on
line diff
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -10,6 +10,7 @@
 
 
 static int ngx_http_proxy_handler(ngx_http_request_t *r);
+static void ngx_http_proxy_init_request(void *data);
 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
@@ -20,7 +21,7 @@ static void ngx_http_proxy_send_response
 static void ngx_http_proxy_process_body(ngx_event_t *ev);
 
 static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p);
+static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type);
 static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
 static void ngx_http_proxy_close_connection(ngx_connection_t *c);
 
@@ -46,6 +47,13 @@ static ngx_command_t ngx_http_proxy_comm
      0,
      NULL},
 
+    {ngx_string("proxy_request_buffer_size"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_size_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_proxy_loc_conf_t, request_buffer_size),
+     NULL},
+
     {ngx_string("proxy_connect_timeout"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
@@ -135,13 +143,10 @@ static ngx_str_t http_methods[] = {
 };
 
 
-#if 0
-static char *header_errors[] = {
-    "upstream sent too long status line",
+static char *upstream_header_errors[] = {
     "upstream sent invalid header",
     "upstream sent too long header line"
 };
-#endif
 
 
 static ngx_http_header_t headers_in[] = {
@@ -170,6 +175,7 @@ static char connection_close_header[] = 
 
 static int ngx_http_proxy_handler(ngx_http_request_t *r)
 {
+    int                    rc;
     ngx_http_proxy_ctx_t  *p;
 
     ngx_http_create_ctx(r, p, ngx_http_proxy_module,
@@ -186,20 +192,89 @@ static int ngx_http_proxy_handler(ngx_ht
     /* TODO: we currently support reverse proxy only */
     p->accel = 1;
 
-    ngx_test_null(p->request_hunks, ngx_http_proxy_create_request(p),
-                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+    if (r->headers_in.content_length_n > 0) {
+        ngx_test_null(r->temp_file,
+                      ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)),
+                      NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+        r->temp_file->file.fd = NGX_INVALID_FILE;
+        r->temp_file->file.log = r->connection->log;
+        r->temp_file->path = *p->lcf->temp_path;
+        r->temp_file->pool = r->pool;
+        r->temp_file->warn = "a client request body is buffered "
+                             "to a temporary file";
+        /* STUB */ r->temp_file->persistent = 1;
+
+        r->request_body_handler = ngx_http_proxy_init_request;
+        r->data = p;
+
+        rc = ngx_http_read_client_request_body(r, p->lcf->request_buffer_size);
+
+        if (rc != NGX_OK) {
+            return rc;
+        }
+    }
+
+    ngx_http_proxy_init_request(p);
 
-    /* TODO: read request body */
+    return NGX_DONE;
+}
+
+
+static void ngx_http_proxy_init_request(void *data)
+{
+    ngx_http_proxy_ctx_t *p = data;
+
+    ngx_chain_t             *cl;
+    ngx_http_request_t      *r;
+    ngx_output_chain_ctx_t  *ctx;
+
+
+    r = p->request;
+
+    cl = ngx_http_proxy_create_request(p);
+    if (cl == NULL) {
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    if (r->request_hunks) {
+        cl->next = r->request_hunks;
+    }
+
+    r->request_hunks = cl;
 
     p->upstream.log = r->connection->log;
     p->saved_ctx = r->connection->log->data;
-    r->connection->log->data = p;;
+    p->saved_handler = r->connection->log->handler;
+    r->connection->log->data = p;
     r->connection->log->handler = ngx_http_proxy_log_error;
     p->action = "connecting to upstream";
 
-    ngx_http_proxy_send_request(p);
+    ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
+    if (ctx == NULL) {
+        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    }
+
+    p->output_chain_ctx = ctx;
 
-    return NGX_DONE;
+    if (r->request_body_hunk) {
+        ctx->free = ngx_alloc_chain_link(r->pool);
+        if (ctx->free == NULL) {
+            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        }
+        ctx->free->hunk = r->request_body_hunk;
+        ctx->free->next = NULL;
+    }
+
+    ctx->sendfile = r->sendfile;
+    ctx->copy_chain = 1;
+    ctx->pool = r->pool;
+    ctx->bufs.num = 1;
+    ctx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
+    ctx->output_filter = (ngx_output_chain_filter_pt) ngx_write_chain;
+
+    ngx_http_proxy_send_request(p);
 }
 
 
@@ -324,9 +399,11 @@ static void ngx_http_proxy_send_request_
     c = wev->data;
     p = c->data;
 
+    p->action = "sending request to upstream";
+
     if (wev->timedout) {
         p->timedout = 1;
-        ngx_http_proxy_next_upstream(p);
+        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
         return;
     }
 
@@ -338,30 +415,43 @@ static void ngx_http_proxy_send_request_
 
 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
 {
-    int                rc;
-    ngx_chain_t       *chain, *cl, *tl, **ll;
-    ngx_connection_t  *c;
+    int                      rc;
+    ngx_chain_t             *cl;
+    ngx_connection_t        *c;
 
     c = p->upstream.connection;
 
     for ( ;; ) {
 
         if (c) {
-            chain = ngx_write_chain(c, p->work_request_hunks);
+            p->output_chain_ctx->output_ctx = c;
+            rc = ngx_output_chain(p->output_chain_ctx,
+                                  p->request->request_hunks);
 
-            if (chain != NGX_CHAIN_ERROR) {
-                p->work_request_hunks = chain;
+            if (rc != NGX_ERROR) {
                 p->request_sent = 1;
 
                 if (c->write->timer_set) {
                     ngx_del_timer(c->write);
                 }
 
-                if (chain) {
+                if (rc == NGX_AGAIN) {
                     ngx_add_timer(c->write, p->lcf->send_timeout);
 
                 } else {
                     /* TODO: del event */
+
+                    if (c->tcp_nopush) {
+                        if (ngx_tcp_push(c->fd) == NGX_ERROR) {
+                            ngx_log_error(NGX_LOG_CRIT, c->log,
+                                          ngx_socket_errno,
+                                          ngx_tcp_push_n " failed");
+                            ngx_http_proxy_finalize_request(p,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+                            return; 
+                        }
+                        c->tcp_nopush = 0;
+                    }
                 }
 
                 return;
@@ -404,34 +494,9 @@ static void ngx_http_proxy_send_request(
 
                 /* reinit the request chain */
 
-                p->work_request_hunks = ngx_alloc_chain_link(p->request->pool);
-                if (p->work_request_hunks == NULL) {
-                    ngx_http_proxy_finalize_request(p,
-                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
-                    return;
+                for (cl = p->request->request_hunks; cl; cl = cl->next) {
+                    cl->hunk->pos = cl->hunk->start;
                 }
-
-                tl = p->work_request_hunks;
-                ll = &p->work_request_hunks;
-
-                for (cl = p->request_hunks; cl; cl = cl->next) {
-                    tl->hunk = cl->hunk;
-                    *ll = tl;
-                    ll = &tl->next;
-                    cl->hunk->pos = cl->hunk->start;
-
-                    tl = ngx_alloc_chain_link(p->request->pool);
-                    if (tl == NULL) {
-                        ngx_http_proxy_finalize_request(p,
-                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
-                        return;
-                    }
-                }
-
-                *ll = NULL;
-
-            } else {
-                p->work_request_hunks = p->request_hunks;
             }
 
             p->request_sent = 0;
@@ -461,11 +526,13 @@ static void ngx_http_proxy_process_upstr
     c = rev->data;
     p = c->data;
 
+    p->action = "reading upstream status line";
+
     ngx_log_debug(rev->log, "http proxy process status line");
 
     if (rev->timedout) {
         p->timedout = 1;
-        ngx_http_proxy_next_upstream(p);
+        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
         return;
     }
 
@@ -483,7 +550,7 @@ static void ngx_http_proxy_process_upstr
     n = ngx_http_proxy_read_upstream_header(p);
 
     if (n == NGX_ERROR) {
-        ngx_http_proxy_next_upstream(p);
+        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
         return;
     }
 
@@ -496,21 +563,39 @@ static void ngx_http_proxy_process_upstr
     if (rc == NGX_AGAIN) {
         if (p->header_in->pos == p->header_in->last) {
             ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                          "upstream sent too big header");
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
-            return;
+                          "upstream sent too long status line");
+            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
         }
 
         return;
     }
 
     if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
-        /* TODO: HTTP/0.9 */
+        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+                      "upstream sent no valid HTTP/1.0 header");
+
+        if (p->accel) {
+            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
+
+        } else {
+            p->request->http_version = NGX_HTTP_VERSION_9;
+            p->status = NGX_HTTP_OK;
+            ngx_http_proxy_send_response(p);
+        }
+
         return;
     }
 
     /* rc == NGX_OK */
 
+    if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR
+        && p->upstream.tries > 1
+        && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
+    {
+        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
+        return;
+    }
+
     p->status_line.len = p->status_end - p->status_start;
     p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1);
     if (p->status_line.data == NULL) {
@@ -522,7 +607,6 @@ static void ngx_http_proxy_process_upstr
     ngx_log_debug(rev->log, "http proxy status %d '%s'" _
                   p->status _ p->status_line.data);
 
-
     if (p->headers_in.headers) {
         p->headers_in.headers->nelts = 0;
     } else {
@@ -549,11 +633,13 @@ static void ngx_http_proxy_process_upstr
     p = c->data;
     r = p->request;
 
+    p->action = "reading upstream headers";
+
     ngx_log_debug(rev->log, "http proxy process header line");
 
     if (rev->timedout) {
         p->timedout = 1;
-        ngx_http_proxy_next_upstream(p);
+        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
         return;
     }
 
@@ -564,7 +650,7 @@ static void ngx_http_proxy_process_upstr
             n = ngx_http_proxy_read_upstream_header(p);
 
             if (n == NGX_ERROR) {
-                ngx_http_proxy_next_upstream(p);
+                ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
                 return;
             }
 
@@ -609,6 +695,7 @@ static void ngx_http_proxy_process_upstr
                 if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) {
                     *((ngx_table_elt_t **)
                         ((char *) &p->headers_in + headers_in[i].offset)) = h;
+                    break;
                 }
             }
 
@@ -631,7 +718,10 @@ static void ngx_http_proxy_process_upstr
 
             /* there was error while a header line parsing */
 
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
+            ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+                      upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
+
+            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
             return;
         }
 
@@ -640,7 +730,8 @@ static void ngx_http_proxy_process_upstr
         if (p->header_in->last == p->header_in->end) {
             ngx_log_error(NGX_LOG_ERR, rev->log, 0,
                           "upstream sent too big header");
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
+
+            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
             return;
         }
     }
@@ -679,7 +770,7 @@ static ssize_t ngx_http_proxy_read_upstr
     }
 
     if (n == 0) {
-        ngx_log_error(NGX_LOG_INFO, rev->log, 0,
+        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
                       "upstream closed prematurely connection");
     }
 
@@ -834,11 +925,6 @@ static void ngx_http_proxy_send_response
 
     p->event_pipe = ep;
 
-#if 0
-    lcx = p->log->data;
-    lcx->action = "reading an upstream";
-#endif
-
     p->upstream.connection->read->event_handler = ngx_http_proxy_process_body;
     r->connection->write->event_handler = ngx_http_proxy_process_body;
 
@@ -861,11 +947,13 @@ static void ngx_http_proxy_process_body(
         ngx_log_debug(ev->log, "http proxy process downstream");
         r = c->data;
         p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+        p->action = "sending to client";
 
     } else {
         ngx_log_debug(ev->log, "http proxy process upstream");
         p = c->data;
         r = p->request;
+        p->action = "reading upstream body";
     }
 
     ep = p->event_pipe;
@@ -1123,7 +1211,7 @@ static int ngx_http_proxy_parse_status_l
 }
 
 
-static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p)
+static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type)
 {
     ngx_event_connect_peer_failed(&p->upstream);
 
@@ -1137,7 +1225,7 @@ static void ngx_http_proxy_next_upstream
         p->upstream.connection = NULL;
     }
 
-    if (p->upstream.tries == 0) {
+    if (p->upstream.tries == 0 || !(p->lcf->next_upstream & ft_type)) {
         ngx_http_proxy_finalize_request(p,
                                         p->timedout ? NGX_HTTP_GATEWAY_TIME_OUT:
                                                       NGX_HTTP_BAD_GATEWAY);
@@ -1146,8 +1234,11 @@ static void ngx_http_proxy_next_upstream
 
     if (!p->fatal_error) {
         ngx_http_proxy_send_request(p);
+        return;
     }
 
+ngx_log_debug(p->request->connection->log, "FATAL ERROR IN NEXT UPSTREAM");
+
     return;
 }
 
@@ -1164,6 +1255,9 @@ static void ngx_http_proxy_finalize_requ
         rc = 0;
     }
 
+    p->request->connection->log->data = p->saved_ctx;
+    p->request->connection->log->handler = p->saved_handler;
+
     ngx_http_finalize_request(p->request, rc);
 
     p->fatal_error = 1;
@@ -1223,11 +1317,15 @@ static size_t ngx_http_proxy_log_error(v
     ngx_http_proxy_ctx_t *p = data;
 
     return ngx_snprintf(buf, len,
-            " while %s, upstream: %s, client: %s, URL: %s",
+            " while %s, client: %s, URL: %s, upstream: %s%s%s%s%s",
             p->action,
+            p->request->connection->addr_text.data,
+            p->request->unparsed_uri.data,
             p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data,
-            p->request->connection->addr_text.data,
-            p->request->unparsed_uri.data);
+            p->lcf->upstream->uri.data,
+            p->request->uri.data + p->lcf->upstream->location->len,
+            p->request->args.len ? "?" : "",
+            p->request->args.len ? p->request->args.data : "");
 }
 
 
@@ -1250,6 +1348,7 @@ static void *ngx_http_proxy_create_loc_c
 
     */
 
+    conf->request_buffer_size = NGX_CONF_UNSET;
     conf->connect_timeout = NGX_CONF_UNSET;
     conf->send_timeout = NGX_CONF_UNSET;
     conf->header_buffer_size = NGX_CONF_UNSET;
@@ -1267,6 +1366,8 @@ static void *ngx_http_proxy_create_loc_c
     /* "proxy_cyclic_temp_file" is disabled */
     conf->cyclic_temp_file = 0;
 
+    conf->next_upstream = NGX_CONF_UNSET;
+
     return conf;
 }
 
@@ -1277,6 +1378,8 @@ static char *ngx_http_proxy_merge_loc_co
     ngx_http_proxy_loc_conf_t *prev = parent;
     ngx_http_proxy_loc_conf_t *conf = child;
 
+    ngx_conf_merge_size_value(conf->request_buffer_size,
+                              prev->request_buffer_size, 8192);
     ngx_conf_merge_msec_value(conf->connect_timeout,
                               prev->connect_timeout, 60000);
     ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 30000);
@@ -1297,6 +1400,9 @@ static char *ngx_http_proxy_merge_loc_co
     ngx_conf_merge_size_value(conf->temp_file_write_size,
                               prev->temp_file_write_size, 16384);
 
+    ngx_conf_merge_value(conf->next_upstream, prev->next_upstream,
+                         (NGX_HTTP_PROXY_FT_ERROR|NGX_HTTP_PROXY_FT_TIMEOUT));
+
     ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
                               "temp", 1, 2, 0, cf->pool);