changeset 23:f540a63026c9

nginx-0.0.1-2002-12-06-19:32:33 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 06 Dec 2002 16:32:33 +0000
parents aa3b53e74728
children 77c7629a2627
files src/event/modules/ngx_select_module.c src/event/ngx_event.h src/http/modules/ngx_http_event_proxy_handler.c src/http/modules/ngx_http_event_proxy_handler.h src/http/ngx_http_event.c src/http/ngx_http_output_filter.c src/http/ngx_http_parse.c
diffstat 7 files changed, 318 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -126,6 +126,8 @@ int ngx_select_del_event(ngx_event_t *ev
     ngx_connection_t *c;
     c = (ngx_connection_t *) ev->data;
 
+    ngx_log_debug(c->log, "del event: %d" _ c->fd);
+
 #if (WIN32)
     if (event == NGX_READ_EVENT) {
         FD_CLR(c->fd, &master_read_fd_set);
@@ -146,13 +148,13 @@ int ngx_select_del_event(ngx_event_t *ev
         max_fd = -1;
 #endif
 
+    nevents--;
+
     if (ev->index < nevents) {
         event_index[ev->index] = event_index[nevents];
         event_index[ev->index]->index = ev->index;
     }
 
-    nevents--;
-
     return NGX_OK;
 }
 
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -22,8 +22,8 @@ struct ngx_event_s {
 
     int              index;
 
-    ngx_event_t     *prev;     /* queue in select(), poll(), mutex(),        */
-    ngx_event_t     *next;     /*   aio_read(), aio_write()                  */
+    ngx_event_t     *prev;     /* queue in mutex(), aio_read(), aio_write()  */
+    ngx_event_t     *next;     /*                                            */
 
     int            (*timer_handler)(ngx_event_t *ev);
     ngx_event_t     *timer_prev;
@@ -43,9 +43,9 @@ struct ngx_event_s {
                                 /*   accept: 1 if accept many, 0 otherwise   */
 
     /* flags - int are probably faster on write then bits ??? */
-#if !(USE_KQUEUE)
+
     unsigned         oneshot:1;
-#endif
+
     unsigned         listening:1;
     unsigned         write:1;
 
--- a/src/http/modules/ngx_http_event_proxy_handler.c
+++ b/src/http/modules/ngx_http_event_proxy_handler.c
@@ -16,8 +16,15 @@ static int ngx_http_proxy_connect(ngx_ht
                                   struct sockaddr_in *addr,
                                   char *addr_text);
 static int ngx_http_proxy_send_request(ngx_event_t *ev);
+
 static int ngx_http_proxy_read_response_header(ngx_event_t *ev);
+static int ngx_http_proxy_process_status_line(ngx_http_request_t *r,
+                                               ngx_http_proxy_ctx_t *p);
+
 static int ngx_http_proxy_read_response_body(ngx_event_t *ev);
+static int ngx_http_proxy_write_to_client(ngx_event_t *ev);
+
+static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx);
 
 
 static char conn_close[] = "Connection: close" CRLF;
@@ -250,7 +257,8 @@ static int ngx_http_proxy_send_request(n
 
 static int ngx_http_proxy_read_response_header(ngx_event_t *ev)
 {
-    int  n;
+    int  n, rc;
+    ngx_hunk_t           **ph;
     ngx_connection_t      *c;
     ngx_http_request_t    *r;
     ngx_http_proxy_ctx_t  *p;
@@ -264,7 +272,14 @@ static int ngx_http_proxy_read_response_
 
     if (p->header_in == NULL) {
         ngx_test_null(p->header_in,
-                      ngx_palloc(r->pool, sizeof(ngx_http_proxy_header_in_t)),
+                      ngx_create_temp_hunk(r->pool,
+                                           /* STUB */ 1024 /**/, 0, 0),
+                      NGX_ERROR);
+
+        p->header_in->type = NGX_HUNK_MEMORY;
+
+        ngx_test_null(p->headers_in,
+                      ngx_palloc(r->pool, sizeof(ngx_http_proxy_headers_in_t)),
                       NGX_ERROR);
 
         ngx_test_null(p->hunks,
@@ -273,36 +288,87 @@ static int ngx_http_proxy_read_response_
                                        sizeof(ngx_hunk_t *)),
                       NGX_ERROR);
 
-        p->last_hunk = 0;
+        ngx_test_null(ph, ngx_push_array(p->hunks), NGX_ERROR);
+        *ph = p->header_in;
 
-        ngx_test_null(p->hunk,
-                      ngx_create_temp_hunk(r->pool,
-                                           /* STUB */ 1024 /**/, 0, 0),
-                      NGX_ERROR);
-
-        p->hunk->type = NGX_HUNK_MEMORY;
+        p->state_handler = ngx_http_proxy_process_status_line;
     }
 
-    n = ngx_event_recv(c, p->hunk->last.mem, p->hunk->end - p->hunk->last.mem);
+    n = ngx_event_recv(c, p->header_in->last.mem,
+                       p->header_in->end - p->header_in->last.mem);
 
     ngx_log_debug(c->log, "READ:%d" _ n);
 
-    p->hunk->last.mem += n;
+    p->header_in->last.mem += n;
+
+    /* STUB */
+    *p->header_in->last.mem = '\0';
+    ngx_log_debug(c->log, "PROXY:\n'%s'" _ p->header_in->pos.mem);
+    /**/
+
+    if (n == 0) {
+        ngx_log_debug(c->log, "CLOSE proxy");
+        ngx_del_event(ev, NGX_READ_EVENT);
+        ngx_event_close_connection(ev);
 
-    *p->hunk->last.mem = '\0';
-    ngx_log_debug(c->log, "PROXY:\n'%s'" _ p->hunk->pos.mem);
+        p->hunk_n = 0;
+        c->write->event_handler = ngx_http_proxy_write_to_client;
+        return ngx_http_proxy_write_to_client(c->write);
+    }
+
+    /* state_handlers are called in following order:
+        ngx_http_proxy_process_status_line(r, p)
+        ngx_http_proxy_process_reponse_header(r, p) */
+
+    do {
+        rc = (p->state_handler)(r, p);
+
+        if (rc == NGX_ERROR)
+            return rc;
+
+        /* rc == NGX_OK || rc == NGX_AGAIN */
+
+    } while (p->header_in->pos.mem < p->header_in->last.mem);
 
     ev->event_handler = ngx_http_proxy_read_response_body;
-    if (p->hunk->end - p->hunk->last.mem == 0)
+    if (p->header_in->end - p->header_in->last.mem == 0)
         return ngx_http_proxy_read_response_body(ev);
 
+    return NGX_WAITING;
+}
+
+static int ngx_http_proxy_process_status_line(ngx_http_request_t *r,
+                                              ngx_http_proxy_ctx_t *p)
+{
+    int  rc;
+
+    ngx_log_debug(r->connection->log, "STATUS: %d" _ p->status);
+
+    rc = ngx_read_http_proxy_status_line(p);
+
+    ngx_log_debug(r->connection->log, "STATUS: %d" _ p->status);
+
+    if (rc == NGX_OK) {
+        /* STUB */
+        ngx_log_debug(r->connection->log, "STATUS: %d" _ p->status);
+
+        p->state_handler = NULL;
+    }
+
+    if (p->header_in->last.mem >= p->header_in->end) {
+        rc = NGX_HTTP_PARSE_TOO_LONG_STATUS_LINE;
+
+    } else if (rc == NGX_AGAIN) {
+        return NGX_AGAIN;
+    }
+
     /* STUB */ return NGX_ERROR;
 }
 
 static int ngx_http_proxy_read_response_body(ngx_event_t *ev)
 {
     int     n;
-    size_t  size;
+    size_t  left;
     ngx_hunk_t            *h, **ph;
     ngx_connection_t      *c;
     ngx_http_request_t    *r;
@@ -315,15 +381,24 @@ static int ngx_http_proxy_read_response_
     r = (ngx_http_request_t *) c->data;
     p = (ngx_http_proxy_ctx_t *) ngx_get_module_ctx(r, ngx_http_proxy_module);
 
-    size = 0;
+    left = 0;
 
     if (p->hunks->nelts > 0) {
         h = ((ngx_hunk_t **) p->hunks->elts)[p->hunks->nelts - 1];
-        size = h->end - h->last.mem;
+        left = h->end - h->last.mem;
     }
 
     do {
-        if (size == 0) {
+
+#if (HAVE_KQUEUE)
+#if !(USE_KQUEUE)
+        if (ngx_event_type == NGX_KQUEUE_EVENT)
+#endif
+            /* do not allocate new block if there is EOF */
+            if (ev->eof && ev->available == 0)
+                left = 1;
+#endif
+        if (left == 0) {
             ngx_test_null(ph, ngx_push_array(p->hunks), NGX_ERROR);
             ngx_test_null(h,
                           ngx_create_temp_hunk(r->pool,
@@ -338,29 +413,211 @@ static int ngx_http_proxy_read_response_
 
         ngx_log_debug(c->log, "READ:%d" _ n);
 
+        if (n == NGX_AGAIN)
+            return NGX_WAITING;
+
+        if (n == NGX_ERROR)
+            return NGX_ERROR;
+
         h->last.mem += n;
+        left = h->end - h->last.mem;
 
+        /* STUB */
         *h->last.mem = '\0';
         ngx_log_debug(c->log, "PROXY:\n'%s'" _ h->pos.mem);
-        size = h->end - h->last.mem;
+        /**/
 
-        /* TODO: close if KEVENT and (ev->available == 0 && ev->eof) */
-
-    } while (size == 0);
+    } while (n > 0 && left == 0);
 
     if (n == 0) {
-        return ngx_event_close_connection(ev);
+        ngx_log_debug(c->log, "CLOSE proxy");
+        ngx_del_event(ev, NGX_READ_EVENT);
+        ngx_event_close_connection(ev);
+
+        p->hunk_n = 0;
+        c->write->event_handler = ngx_http_proxy_write_to_client;
+        return ngx_http_proxy_write_to_client(c->write);
     }
 
     /* STUB */ return NGX_WAITING;
 }
 
-#if 0
 static int ngx_http_proxy_write_to_client(ngx_event_t *ev)
 {
-    /* если бэкенд быстрее, то CLEAR, иначе - ONESHOT */
+    int  rc;
+    ngx_hunk_t            *h;
+    ngx_connection_t      *c;
+    ngx_http_request_t    *r;
+    ngx_http_proxy_ctx_t  *p;
+
+    c = (ngx_connection_t *) ev->data;
+    r = (ngx_http_request_t *) c->data;
+    p = (ngx_http_proxy_ctx_t *) ngx_get_module_ctx(r, ngx_http_proxy_module);
+
+    do {
+        h = ((ngx_hunk_t **) p->hunks->elts)[p->hunk_n];
 
-    rc = ngx_http_output_filter(r, h);
+        rc = ngx_http_output_filter(r, h);
+        if (rc != NGX_OK)
+            return rc;
+
+        if (p->hunk_n >= p->hunks->nelts)
+            break;
+
+        p->hunk_n++;
+
+    } while (rc == NGX_OK);
+
+    return NGX_OK;
 }
 
-#endif
+
+static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx)
+{
+    char   ch;
+    char  *p;
+    enum  {
+        sw_start = 0,
+        sw_first_major_digit,
+        sw_major_digit,
+        sw_first_minor_digit,
+        sw_minor_digit,
+        sw_status,
+        sw_space_after_status,
+        sw_status_text,
+        sw_almost_done,
+        sw_done
+    } state;
+
+    state = ctx->state;
+    p = ctx->header_in->pos.mem;
+
+    while (p < ctx->header_in->last.mem && state < sw_done) {
+        ch = *p++;
+
+fprintf(stderr, "state: %d, pos: %x, end: %x, char: '%c', status: %d\n",
+       state, p, ctx->header_in->last.mem, ch, ctx->status);
+
+        switch (state) {
+
+        /* "HTTP/" */
+        case sw_start:
+            if (p + 3 >= ctx->header_in->last.mem)
+                return NGX_AGAIN;
+
+            if (ch != 'H' || *p != 'T' || *(p + 1) != 'T' || *(p + 2) != 'P'
+                          || *(p + 3) != '/')
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+
+            p += 4;
+            state = sw_first_major_digit;
+            break;
+
+        /* first digit of major HTTP version */
+        case sw_first_major_digit:
+            if (ch < '1' || ch > '9')
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+
+            state = sw_major_digit;
+            break;
+
+        /* major HTTP version or dot */
+        case sw_major_digit:
+            if (ch == '.') {
+                state = sw_first_minor_digit;
+                break;
+            }
+
+            if (ch < '0' || ch > '9')
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+
+            break;
+
+        /* first digit of minor HTTP version */
+        case sw_first_minor_digit:
+            if (ch < '0' || ch > '9')
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+
+            state = sw_minor_digit;
+            break;
+
+        /* minor HTTP version or end of request line */
+        case sw_minor_digit:
+            if (ch == ' ') {
+                state = sw_status;
+                break;
+            }
+
+            if (ch < '0' || ch > '9')
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+
+            break;
+
+        /* HTTP status code */
+        case sw_status:
+            if (ch < '0' || ch > '9')
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+
+            ctx->status = ctx->status * 10 + ch - '0';
+
+            if (++ctx->status_count == 3)
+                state = sw_space_after_status;
+
+            break;
+
+         /* space or end of line */
+         case sw_space_after_status:
+            switch (ch) {
+            case ' ':
+                ctx->status_text = p - 1;
+                state = sw_status_text;
+                break;
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                state = sw_done;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        /* any text until end of line */
+        case sw_status_text:
+            switch (ch) {
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                state = sw_done;
+                break;
+            }
+            break;
+
+        /* end of request line */
+        case sw_almost_done:
+            ctx->request_end = p - 2;
+            switch (ch) {
+            case LF:
+                state = sw_done;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+        }
+    }
+
+    ctx->header_in->pos.mem = p;
+
+    if (state == sw_done) {
+        if (ctx->request_end == NULL)
+            ctx->request_end = p - 1;
+        ctx->state = sw_start;
+        return NGX_OK;
+    } else {
+        ctx->state = state;
+        return NGX_AGAIN;
+    }
+}
--- a/src/http/modules/ngx_http_event_proxy_handler.h
+++ b/src/http/modules/ngx_http_event_proxy_handler.h
@@ -7,19 +7,33 @@
 #include <ngx_http.h>
 
 
+#define NGX_HTTP_PROXY_PARSE_NO_HEADER          20
+#define NGX_HTTP_PARSE_TOO_LONG_STATUS_LINE     21
+
 typedef struct {
     int dummy;
-} ngx_http_proxy_header_in_t;
+} ngx_http_proxy_headers_in_t;
 
-typedef struct {
+typedef struct ngx_http_proxy_ctx_s  ngx_http_proxy_ctx_t;
+
+struct ngx_http_proxy_ctx_s {
     ngx_chain_t  *out;
 
-    ngx_hunk_t   *hunk;
     int           last_hunk;
     ngx_array_t  *hunks;
 
-    ngx_http_proxy_header_in_t  *header_in;
-} ngx_http_proxy_ctx_t;
+    int           hunk_n;
+
+    ngx_http_proxy_headers_in_t  *headers_in;
+
+    ngx_hunk_t  *header_in;
+    int          state;
+    int          status;
+    int          status_count;
+    char        *status_text;
+    char        *request_end;
+    int        (*state_handler)(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p);
+};
 
 
 extern ngx_http_module_t  ngx_http_proxy_module;
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -323,7 +323,7 @@ static int ngx_http_process_request_line
     }
 
     if (r->header_in->last.mem >= r->header_in->end) {
-        rc == NGX_HTTP_PARSE_TOO_LONG_URI;
+        rc = NGX_HTTP_PARSE_TOO_LONG_URI;
 
     } else if (rc == NGX_AGAIN) {
         return NGX_AGAIN;
@@ -495,10 +495,11 @@ static int ngx_http_event_handler(ngx_ht
 
     rc = ngx_http_handler(r);
 
+    /* handler is still busy */
     if (rc == NGX_WAITING)
         return rc;
 
-    /* transfer not completed */
+    /* handler has done its work but transfer is not completed */
     if (rc == NGX_AGAIN) {
 #if (HAVE_CLEAR_EVENT)
         if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
@@ -567,7 +568,7 @@ static int ngx_http_handler(ngx_http_req
     r->connection->read->event_handler = ngx_http_block_read;
 
     /* STUB: should find handler */
-#if 1
+#if 0
     r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
 #endif
     rc = ngx_http_set_default_handler(r);
--- a/src/http/ngx_http_output_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -126,7 +126,7 @@ int ngx_http_output_filter(ngx_http_requ
                      ctx->in = ce->next;
             }
 
-            if (rc == NGX_OK)
+            if (rc == NGX_OK && ctx->hunk)
                 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
             else
                 return rc;
@@ -218,7 +218,8 @@ int ngx_http_output_filter(ngx_http_requ
         return NGX_OK;
 
     if (rc == NGX_OK) {
-        ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
+        if (ctx->hunk)
+            ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
 #if level_event
         ngx_del_event(r->connection->write, NGX_WRITE_EVENT);
 #endif
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -312,86 +312,6 @@ printf("\nstate: %d, pos: %x, end: %x, c
     }
 }
 
-#if 0
-int ngx_read_http_response_line(ngx_http_request_t *r)
-{
-    char   c, ch;
-    char  *p;
-    enum  {
-        sw_start = 0,
-        sw_done
-    } state;
-
-    state = r->state;
-    p = r->header_in->pos.mem;
-
-    while (p < r->header_in->last.mem && state < sw_done) {
-        ch = *p++;
-
-/*
-printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s",
-       state, p, r->header_in->last, ch, p);
-*/
-
-        switch (state) {
-
-        /* "HTTP/" */
-        case sw_start:
-            if (p + 3 >= r->header_in->last.mem)
-                return NGX_AGAIN;
-
-            if (ch != 'H' || *p != 'T' || *(p + 1) != 'T' || *(p + 2) != 'P'
-                          || *(p + 3) != '/')
-                return NGX_HTTP_PARSE_NO_HEADER;
-
-            p += 4;
-            state = sw_first_major_digit;
-            break;
-
-        /* first digit of major HTTP version */
-        case sw_first_major_digit:
-            if (ch < '1' || ch > '9')
-                return NGX_HTTP_PARSE_NO_HEADER;
-
-            state = sw_major_digit;
-            break;
-
-        /* major HTTP version or dot */
-        case sw_major_digit:
-            if (ch == '.') {
-                state = sw_first_minor_digit;
-                break;
-            }
-
-            if (ch < '0' || ch > '9')
-                return NGX_HTTP_PARSE_NO_HEADER;
-
-            break;
-
-        /* first digit of minor HTTP version */
-        case sw_first_minor_digit:
-            if (ch < '0' || ch > '9')
-                return NGX_HTTP_PARSE_NO_HEADER;
-
-            state = sw_minor_digit;
-            break;
-
-        /* minor HTTP version or end of request line */
-        case sw_minor_digit:
-            if (ch == ' ') {
-                state = sw_code;
-                break;
-            }
-
-            if (ch < '0' || ch > '9')
-                return NGX_HTTP_PARSE_NO_HEADER;
-
-            break;
-        }
-    }
-}
-#endif
-
 int ngx_read_http_header_line(ngx_http_request_t *r)
 {
     char   c, ch;