Mercurial > hg > nginx-quic
view src/http/modules/ngx_http_event_proxy_handler.c @ 45:f1ee46c036a4
nginx-0.0.1-2003-01-10-09:09:20 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 10 Jan 2003 06:09:20 +0000 |
parents | 0e81ac0bb3e2 |
children | e8cdc2989cee |
line wrap: on
line source
#include <ngx_config.h> #include <ngx_core.h> #include <ngx_string.h> #include <ngx_file.h> #include <ngx_hunk.h> #include <ngx_event_write.h> #include <ngx_http.h> #include <ngx_http_event_proxy_handler.h> ngx_http_module_t ngx_http_proxy_module_ctx; static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_request_t *r); static int ngx_http_proxy_connect(ngx_http_request_t *r, 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; int ngx_http_proxy_handler(ngx_http_request_t *r) { struct sockaddr_in addr; ngx_chain_t *chain; ngx_http_proxy_ctx_t *p; p = (ngx_http_proxy_ctx_t *) ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); if (p == NULL) { ngx_http_create_ctx(r, p, ngx_http_proxy_module_ctx, sizeof(ngx_http_proxy_ctx_t)); } chain = ngx_http_proxy_create_request(r); if (chain == NULL) { return NGX_ERROR; } p->out = chain; ngx_memzero(&addr, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(9000); ngx_http_proxy_connect(r, &addr, "connecting to 127.0.0.1:9000"); } static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_request_t *r) { int i; size_t len; ngx_hunk_t *hunk; ngx_chain_t *chain; ngx_table_elt_t *header; /* 2 is for "\r\n" after request line and 2 is for "\r\n" at the header end */ len = r->request_line.len + 2 + 2; /* "Connection: close\r\n" */ len += sizeof(conn_close) - 1; header = (ngx_table_elt_t *) r->headers_in.headers->elts; for (i = 0; i < r->headers_in.headers->nelts; i++) { if (&header[i] == r->headers_in.host) { continue; } if (&header[i] == r->headers_in.connection) { continue; } /* 2 is for ": " and 2 is for "\r\n" */ len += header[i].key.len + 2 + header[i].value.len + 2; } /* STUB */ len++; ngx_test_null(hunk, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL); ngx_add_hunk_to_chain(chain, hunk, r->pool, NULL); ngx_memcpy(hunk->last.mem, r->request_line.data, r->request_line.len); hunk->last.mem += r->request_line.len; *(hunk->last.mem++) = CR; *(hunk->last.mem++) = LF; ngx_memcpy(hunk->last.mem, conn_close, sizeof(conn_close) - 1); hunk->last.mem += sizeof(conn_close) - 1; for (i = 0; i < r->headers_in.headers->nelts; i++) { if (&header[i] == r->headers_in.host) { continue; } if (&header[i] == r->headers_in.connection) { continue; } ngx_memcpy(hunk->last.mem, header[i].key.data, header[i].key.len); hunk->last.mem += header[i].key.len; *(hunk->last.mem++) = ':'; *(hunk->last.mem++) = ' '; ngx_memcpy(hunk->last.mem, header[i].value.data, header[i].value.len); hunk->last.mem += header[i].value.len; *(hunk->last.mem++) = CR; *(hunk->last.mem++) = LF; ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _ header[i].key.data _ header[i].value.data); } /* add "\r\n" at the header end */ *(hunk->last.mem++) = CR; *(hunk->last.mem++) = LF; /* STUB */ *(hunk->last.mem++) = '\0'; ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ hunk->pos.mem); return chain; } static int ngx_http_proxy_connect(ngx_http_request_t *r, struct sockaddr_in *addr, char *addr_text) { int rc; ngx_err_t err; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c, *pc; ngx_http_log_ctx_t *ctx; c = r->connection; ctx = c->log->data; ctx->action = addr_text; s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0); if (s == -1) { ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } #if 0 if (rcvbuf) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const void *) &rcvbuf, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } return NGX_ERROR; } } #endif if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_nonblocking_n " failed"); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } return NGX_ERROR; } rc = connect(s, (struct sockaddr *) addr, sizeof(struct sockaddr_in)); if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS) { ngx_log_error(NGX_LOG_ERR, c->log, err, "connect() failed"); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } return NGX_ERROR; } } pc = &ngx_connections[s]; rev = &ngx_read_events[s]; wev = &ngx_write_events[s]; ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); ngx_memzero(pc, sizeof(ngx_connection_t)); rev->data = wev->data = pc; pc->read = rev; pc->write = wev; pc->data = r; pc->fd = s; pc->servers = c->servers; pc->log = rev->log = wev->log = c->log; ngx_test_null(pc->pool, ngx_create_pool(/* STUB */ 1024 /**/, pc->log), NGX_ERROR); wev->event_handler = ngx_http_proxy_send_request; rev->event_handler = ngx_http_proxy_read_response_header; #if (HAVE_CLEAR_EVENT) if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) != NGX_OK) { #else if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) != NGX_OK) { #endif return NGX_ERROR; } if (rc == -1) { return ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT); } wev->write = 1; wev->ready = 1; return ngx_http_proxy_send_request(wev); } static int ngx_http_proxy_send_request(ngx_event_t *ev) { ngx_chain_t *chain; 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_http_get_module_ctx(r, ngx_http_proxy_module_ctx); chain = ngx_event_write(c, p->out, 0); if (chain == (ngx_chain_t *) -1) { return NGX_ERROR; } p->out = chain; return NGX_WAITING; } static int ngx_http_proxy_read_response_header(ngx_event_t *ev) { int n, rc; ngx_hunk_t **ph; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_proxy_ctx_t *p; if (ev->timedout) { return NGX_ERROR; } c = (ngx_connection_t *) ev->data; r = (ngx_http_request_t *) c->data; p = (ngx_http_proxy_ctx_t *) ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); if (p->header_in == NULL) { ngx_test_null(p->header_in, 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, ngx_create_array(r->pool, /* STUB */ 10 /**/, sizeof(ngx_hunk_t *)), NGX_ERROR); ngx_test_null(ph, ngx_push_array(p->hunks), NGX_ERROR); *ph = p->header_in; p->state_handler = ngx_http_proxy_process_status_line; } 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->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"); #if 0 ngx_del_event(ev, NGX_READ_EVENT, NGX_CLOSE_EVENT); #endif 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); } /* state_handlers are called in following order: ngx_http_proxy_process_status_line(r, p) ngx_http_proxy_process_reponse_header(r, p) */ #if 0 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); #endif ev->event_handler = ngx_http_proxy_read_response_body; 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; rc = ngx_read_http_proxy_status_line(p); if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { p->status = 200; } 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_process_response_header(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) { } static int ngx_http_proxy_read_response_body(ngx_event_t *ev) { int n; size_t left; ngx_hunk_t *h, **ph; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_proxy_ctx_t *p; if (ev->timedout) return NGX_ERROR; c = (ngx_connection_t *) ev->data; r = (ngx_http_request_t *) c->data; p = (ngx_http_proxy_ctx_t *) ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); left = 0; if (p->hunks->nelts > 0) { h = ((ngx_hunk_t **) p->hunks->elts)[p->hunks->nelts - 1]; left = h->end - h->last.mem; } do { #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; } #if !(USE_KQUEUE) } #endif #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, /* STUB */ 4096 /**/, 0, 0), NGX_ERROR); h->type = NGX_HUNK_MEMORY; *ph = h; } n = ngx_event_recv(c, h->last.mem, h->end - h->last.mem); 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); /**/ } while (n > 0 && left == 0); if (n == 0) { ngx_log_debug(c->log, "CLOSE proxy"); #if 0 ngx_del_event(ev, NGX_READ_EVENT, NGX_CLOSE_EVENT); #endif 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; } static int ngx_http_proxy_write_to_client(ngx_event_t *ev) { 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_http_get_module_ctx(r, ngx_http_proxy_module_ctx); do { h = ((ngx_hunk_t **) p->hunks->elts)[p->hunk_n]; 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; } 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; ctx->status_line = p - 3; } break; /* space or end of line */ case sw_space_after_status: switch (ch) { case ' ': 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; } }