From fa1dd3fbfd0dcc372f603bca6a41f38d9d80fb79 Mon Sep 17 00:00:00 2001 From: "roberto@maverick64" Date: Tue, 8 Feb 2011 16:04:41 +0100 Subject: [PATCH] the new (production-friendly) HTTP server --- buildconf/default.ini | 3 +- http.c | 464 ----------------------- plugins/http/http.c | 725 ++++++++++++++++++++++++++++++++++++ plugins/http/uwsgiplugin.py | 7 + uwsgi.c | 92 ----- uwsgi.h | 15 +- uwsgiconfig.py | 4 - 7 files changed, 735 insertions(+), 575 deletions(-) delete mode 100644 http.c create mode 100644 plugins/http/http.c create mode 100644 plugins/http/uwsgiplugin.py diff --git a/buildconf/default.ini b/buildconf/default.ini index e4f6e5ba..f1f28f9a 100644 --- a/buildconf/default.ini +++ b/buildconf/default.ini @@ -12,7 +12,6 @@ threading = true sendfile = true minterpreters = true async = true -http = true evdis = false ldap = false pcre = auto @@ -23,7 +22,7 @@ xml_implementation = libxml2 plugins = bin_name = uwsgi plugin_dir = . -embedded_plugins = python, ping, nagios, rpc, fastrouter +embedded_plugins = python, ping, nagios, rpc, fastrouter, http locking = auto event = auto diff --git a/http.c b/http.c deleted file mode 100644 index 669072ea..00000000 --- a/http.c +++ /dev/null @@ -1,464 +0,0 @@ -#include "uwsgi.h" - -struct uwsgi_server uwsgi; - -struct uwsgi_http_req { - pthread_t a_new_thread; - int fd; - struct sockaddr_in c_addr; - socklen_t c_len; -}; - -enum { - uwsgi_http_method, - uwsgi_http_uri, - uwsgi_http_protocol, - uwsgi_http_protocol_r, - - uwsgi_http_header_key, - uwsgi_http_header_key_colon, - - uwsgi_http_header_val, - uwsgi_http_header_val_r, - - uwsgi_http_end -}; - -void http_end() { - uwsgi_log("closing uWSGI embedded HTTP server.\n"); - exit(0); -} - -void http_wait_end() { - pid_t wp_p; - int wp_c; - wp_p = waitpid(-1, &wp_c, 0); - uwsgi_log("closing uWSGI embedded HTTP server.\n"); - exit(0); -} - -static char *add_uwsgi_var(char *up, char *key, uint16_t keylen, char *val, uint16_t vallen, int header, char *watermark) { - int i; - - if (!header) { - - if ( (up + 2 + keylen + 2 + vallen) > watermark ) return up; - - *up++ = (unsigned char) (keylen & 0xff); - *up++ = (unsigned char) ((keylen >> 8) & 0xff); - - memcpy(up, key, keylen); - up += keylen; - } else { - - for (i = 0; i < keylen; i++) { - if (key[i] == '-') { - key[i] = '_'; - } else { - key[i] = toupper( (int) key[i]); - } - } - - if (strncmp("CONTENT_TYPE", key, keylen) && strncmp("CONTENT_LENGTH", key, keylen)) { - if ( (up + 2 + keylen + 5 + 2 + vallen) > watermark ) return up; - *up++ = (unsigned char) (((uint16_t) keylen + 5) & 0xff); - *up++ = (unsigned char) ((((uint16_t) keylen + 5) >> 8) & 0xff); - memcpy(up, "HTTP_", 5); - up += 5; - } else { - if ( (up + 2 + keylen + 2 + vallen) > watermark ) return up; - *up++ = (unsigned char) (keylen & 0xff); - *up++ = (unsigned char) ((keylen >> 8) & 0xff); - } - - - memcpy(up, key, keylen); - up += keylen; - } - - *up++ = (unsigned char) (vallen & 0xff); - *up++ = (unsigned char) ((vallen >> 8) & 0xff); - memcpy(up, val, vallen); - up += vallen; - - return up; -} - -static void *http_request(void *); - -void http_loop() { - struct uwsgi_http_req *ur; - int ret; - pthread_attr_t pa; - int stat_loc; - - ret = pthread_attr_init(&pa); - if (ret) { - uwsgi_log("pthread_attr_init() = %d\n", ret); - exit(1); - } - - ret = pthread_attr_setdetachstate(&pa, PTHREAD_CREATE_DETACHED); - if (ret) { - uwsgi_log("pthread_attr_setdetachstate() = %d\n", ret); - exit(1); - } - - // ignore broken pipes; - signal(SIGPIPE, SIG_IGN); - if (!uwsgi.http_only) { - signal(SIGCHLD, &http_end); - signal(SIGINT, &http_wait_end); - } - else { - signal(SIGINT, &http_end); - } - - uwsgi.http_server_name = malloc(256); - if (!uwsgi.http_server_name) { - uwsgi_error("malloc()"); - exit(1); - } - - memset(uwsgi.http_server_name, 0, 256); - if (gethostname(uwsgi.http_server_name, 255)) { - uwsgi_error("gethostname()"); - memcpy(uwsgi.http_server_name, "localhost", 9); - } - - uwsgi_log("starting HTTP loop on %s (pid: %d)\n", uwsgi.http_server_name, (int) getpid()); - for(;;) { - - if (!uwsgi.http_only) { - if (waitpid(-1, &stat_loc, WNOHANG) != 0) { - http_end(); - } - } - ur = malloc(sizeof(struct uwsgi_http_req)); - if (!ur) { - uwsgi_error("malloc()"); - sleep(1); - continue; - } - ur->c_len = sizeof(struct sockaddr_in); - ur->fd = accept(uwsgi.http_fd, (struct sockaddr *) &ur->c_addr, &ur->c_len); - - if (ur->fd < 0) { - uwsgi_error("accept()"); - free(ur); - continue; - } - - ret = pthread_create(&ur->a_new_thread, &pa, http_request, (void *) ur); - if (ret) { - uwsgi_log("pthread_create() = %d\n", ret); - free(ur); - // sleep a bit to allow some resource gaining - sleep(1); - continue; - } - } -} - -static void *http_request(void *u_h_r) { - char buf[4096]; - - char tmp_buf[4096]; - - char uwsgipkt[4096]; - - struct uwsgi_http_req *ur = (struct uwsgi_http_req *) u_h_r; - - int clientfd = ur->fd; - int uwsgi_fd = -1; - - int need_to_read = 1; - int state = uwsgi_http_method; - - int http_body_len = 0; - int http_upgrade = 0; - - struct pollfd http_poll[2]; - - size_t len; - - int i, j, rlen; - - char HTTP_header_key[1024]; - - uint16_t ulen; - - char *ptr = tmp_buf; - - int qs = 0; - - char *up = uwsgipkt; - - char *watermark = up + 4096; - char *watermark2 = tmp_buf + 4096; - - int path_info_len; - char *ip; - - up[0] = uwsgi.http_modifier1; - up[3] = 0; - up += 4; - - while (need_to_read) { - len = read(clientfd, buf, 4096); - if (len <= 0) { - uwsgi_error("read()"); - break; - } - for (i = 0; i < (int) len; i++) { - - if (buf[i] == ' ') { - - if (state == uwsgi_http_method) { - - up = add_uwsgi_var(up, "REQUEST_METHOD", 14, tmp_buf, ptr - tmp_buf, 0, watermark); - ptr = tmp_buf; - state = uwsgi_http_uri; - - } else if (state == uwsgi_http_uri) { - - up = add_uwsgi_var(up, "REQUEST_URI", 11, tmp_buf, ptr - tmp_buf, 0, watermark); - - path_info_len = ptr - tmp_buf; - for (j = 0; j < ptr - tmp_buf; j++) { - if (tmp_buf[j] == '?') { - path_info_len = j; - if (j + 1 < (ptr - tmp_buf)) { - up = add_uwsgi_var(up, "QUERY_STRING", 12, tmp_buf + j + 1, (ptr - tmp_buf) - (j + 1), 0, watermark); - qs = 1; - } - break; - } - } - - if (!qs) { - up = add_uwsgi_var(up, "QUERY_STRING", 12, NULL, 0, 0, watermark); - } - - up = add_uwsgi_var(up, "SCRIPT_NAME", 11, "", 0, 0, watermark); - up = add_uwsgi_var(up, "PATH_INFO", 9, tmp_buf, path_info_len, 0, watermark); - - - ptr = tmp_buf; - state = uwsgi_http_protocol; - - } else if (state == uwsgi_http_header_key_colon) { - - if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;} - *ptr++ = 0; - - memset(HTTP_header_key, 0, sizeof(HTTP_header_key)); - memcpy(HTTP_header_key, tmp_buf, strlen(tmp_buf)); - ptr = tmp_buf; - state = uwsgi_http_header_val; - } else { - //check for overflow - if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;} - *ptr++ = buf[i]; - } - - } else if (buf[i] == '\r') { - - if (state == uwsgi_http_protocol) { - state = uwsgi_http_protocol_r; - } - if (state == uwsgi_http_header_val) { - state = uwsgi_http_header_val_r; - } else if (state == uwsgi_http_header_key) { - state = uwsgi_http_end; - } - } else if (buf[i] == '\n') { - - if (state == uwsgi_http_header_val_r) { - - up = add_uwsgi_var(up, HTTP_header_key, strlen(HTTP_header_key), tmp_buf, ptr - tmp_buf, 1, watermark); - if (!strcmp("CONTENT_LENGTH", HTTP_header_key)) { - if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;} - *ptr++ = 0; - http_body_len = atoi(tmp_buf); - } - else if (!strcmp("CONNECTION", HTTP_header_key)) { - if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;} - *ptr++ = 0; - if (!strcmp(tmp_buf, "Upgrade")) { - http_upgrade = 1; - } - } - ptr = tmp_buf; - state = uwsgi_http_header_key; - } else if (state == uwsgi_http_protocol_r) { - - up = add_uwsgi_var(up, "SERVER_PROTOCOL", 15, tmp_buf, ptr - tmp_buf, 0, watermark); - ptr = tmp_buf; - state = uwsgi_http_header_key; - } else if (state == uwsgi_http_end) { - need_to_read = 0; - - - up = add_uwsgi_var(up, "SERVER_NAME", 11, uwsgi.http_server_name, strlen(uwsgi.http_server_name), 0, watermark); - up = add_uwsgi_var(up, "SERVER_PORT", 11, uwsgi.http_server_port, strlen(uwsgi.http_server_port), 0, watermark); - - - ip = inet_ntoa(ur->c_addr.sin_addr); - up = add_uwsgi_var(up, "REMOTE_ADDR", 11, ip, strlen(ip), 0, watermark); - - //up = add_uwsgi_var(up, "REMOTE_ADDR", 11, "127.0.0.1", 9, 0, watermark); - //up = add_uwsgi_var(up, "REMOTE_USER", 11, "unknown", 7, 0); - - for(j=0;j watermark2) { close(uwsgi_fd); goto clear;} - *ptr++ = buf[i]; - } - } else { - - //check for overflow - if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;} - *ptr++ = buf[i]; - } - - } - - } - -clear: - close(clientfd); - - free(ur); - pthread_exit(NULL); - - return NULL; -} diff --git a/plugins/http/http.c b/plugins/http/http.c new file mode 100644 index 00000000..34147762 --- /dev/null +++ b/plugins/http/http.c @@ -0,0 +1,725 @@ +/* + + uWSGI http + + requires: + + - async + - caching + - pcre (optional) + +*/ + +#include "../../uwsgi.h" + +#define MAX_HTTP_VEC 128 +#define MAX_HTTP_EXTRA_VARS 64 + +#define LONG_ARGS_HTTP_EVENTS 300001 +#define LONG_ARGS_HTTP_USE_PATTERN 300002 +#define LONG_ARGS_HTTP_USE_BASE 300003 +#define LONG_ARGS_HTTP_USE_TO 300004 + +#define HTTP_STATUS_FREE 0 +#define HTTP_STATUS_CONNECTING 1 +#define HTTP_STATUS_RECV 2 +#define HTTP_STATUS_RESPONSE 4 + +struct uwsgi_http { + char *socket_name; + int use_cache; + int nevents; + + char *pattern; + int pattern_len; + + char *base; + int base_len; + + char *to; + int to_len; + + char *http_vars[MAX_HTTP_EXTRA_VARS]; + int http_vars_cnt; + + uint8_t modifier1; + int load; +} uhttp; + +struct option http_options[] = { + {"http", required_argument, 0, LONG_ARGS_HTTP}, + {"http-var", required_argument, 0, LONG_ARGS_HTTP_VAR}, + {"http-to", required_argument, 0, LONG_ARGS_HTTP_USE_TO}, + {"http-modifier1", required_argument, 0, LONG_ARGS_HTTP_MODIFIER1}, + {"http-use-cache", no_argument, &uhttp.use_cache, 1}, + {"http-use-pattern", required_argument, 0, LONG_ARGS_HTTP_USE_PATTERN}, + {"http-use-base", required_argument, 0, LONG_ARGS_HTTP_USE_BASE}, + {"http-events", required_argument, 0, LONG_ARGS_HTTP_EVENTS}, + {0, 0, 0, 0}, +}; + +extern struct uwsgi_server uwsgi; + +struct http_session { + + int fd; + int instance_fd; + int status; + struct uwsgi_header uh; + uint8_t h_pos; + uint16_t pos; + uint16_t parse_pos; + char *ptr; + + int rnrn; + + char *hostname; + uint16_t hostname_len; + + char *instance_address; + uint16_t instance_address_len; + + int pass_fd; + + int remains; + + struct iovec iov[MAX_HTTP_VEC]; + int iov_len; + + char uss[MAX_HTTP_VEC*2]; + + char buffer[0xffff]; +}; + +struct http_session *alloc_uhttp_session() { + + return uwsgi_malloc(sizeof(struct http_session)); +} + +uint16_t http_add_uwsgi_header(struct http_session *h_session, struct iovec *iov, char *strsize1, char *strsize2, char *hh, uint16_t hhlen, int *c) { + + int i; + int status = 0; + char *val = hh; + uint16_t keylen = 0, vallen = 0; + int prefix = 0; + + if (*c >= MAX_HTTP_VEC) return 0; + + for(i=0;i= MAX_HTTP_VEC) return 0; + + if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) { + keylen += 5; + prefix = 1; + if ((*c) + 5 >= MAX_HTTP_VEC) return 0; + } + else if (uwsgi_strncmp("HOST", 4, hh, keylen)) { + h_session->hostname = val; + h_session->hostname_len = vallen; + } + + strsize1[0] = (uint8_t) (keylen & 0xff); + strsize1[1] = (uint8_t) ((keylen >> 8) & 0xff); + + iov[*c].iov_base = strsize1 ; + iov[*c].iov_len = 2 ; + *c+=1; + + if (prefix) { + iov[*c].iov_base = "HTTP_" ; + iov[*c].iov_len = 5 ; + *c+=1; + } + + iov[*c].iov_base = hh ; + iov[*c].iov_len = keylen - (prefix*5) ; + *c+=1; + + strsize2[0] = (uint8_t) (vallen & 0xff); + strsize2[1] = (uint8_t) ((vallen >> 8) & 0xff); + + iov[*c].iov_base = strsize2 ; + iov[*c].iov_len = 2 ; + *c+=1; + + iov[*c].iov_base = val ; + iov[*c].iov_len = vallen ; + *c+=1; + + return 2+keylen+2+vallen; +} + + +uint16_t http_add_uwsgi_var(struct iovec *iov, char *strsize1, char *strsize2, char *key, uint16_t keylen, char *val, uint16_t vallen, int *c) { + + if ((*c) + 4 >= MAX_HTTP_VEC) return 0; + + strsize1[0] = (uint8_t) (keylen & 0xff); + strsize1[1] = (uint8_t) ((keylen >> 8) & 0xff); + + iov[*c].iov_base = strsize1 ; + iov[*c].iov_len = 2 ; + *c+=1; + + iov[*c].iov_base = key ; + iov[*c].iov_len = keylen ; + *c+=1; + + strsize2[0] = (uint8_t) (vallen & 0xff); + strsize2[1] = (uint8_t) ((vallen >> 8) & 0xff); + + iov[*c].iov_base = strsize2 ; + iov[*c].iov_len = 2 ; + *c+=1; + + iov[*c].iov_base = val ; + iov[*c].iov_len = vallen ; + *c+=1; + + return 2+keylen+2+vallen; +} + +int http_parse(struct http_session *h_session) { + + char *ptr = h_session->buffer; + char *watermark = h_session->ptr; + char *base = ptr; + // leave a slot for uwsgi header + int c = 1; + char *query_string = NULL; + + // REQUEST_METHOD + while(ptr < watermark) { + if (*ptr == ' ') { + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REQUEST_METHOD", 14, base, ptr-base, &c); + ptr++; + break; + } + ptr++; + } + + // REQUEST_URI / PATH_INFO / QUERY_STRING + base = ptr; + while(ptr < watermark) { + if (*ptr == '?' && !query_string) { + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, base, ptr-base, &c); + query_string = ptr+1; + } + else if (*ptr == ' ') { + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REQUEST_URI", 11, base, ptr-base, &c); + if (!query_string) { + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, base, ptr-base, &c); + } + else { + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "QUERY_STRING", 12, query_string, ptr-query_string, &c); + } + ptr++; + break; + } + ptr++; + } + + // SERVER_PROTOCOL + base = ptr; + while(ptr < watermark) { + if (*ptr == '\r') { + if (ptr + 1 >= watermark) return 0; + if (*(ptr+1) != '\n') return 0; + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SERVER_PROTOCOL", 15, base, ptr-base, &c); + ptr+=2; + break; + } + ptr++; + } + + // SCRIPT_NAME + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SCRIPT_NAME", 11, "", 0, &c); + + // SERVER_NAME + h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len, &c); + h_session->hostname = uwsgi.hostname; + h_session->hostname_len = uwsgi.hostname_len; + + + //HEADERS + + base = ptr; + + while(ptr < watermark) { + if (*ptr == '\r') { + if (ptr + 1 >= watermark) return 0; + if (*(ptr+1) != '\n') return 0; + // multiline header ? + if (ptr+2 < watermark) { + if (*(ptr+2) == ' ' || *(ptr+2) == '\t') { + ptr+=2; + continue; + } + } + h_session->uh.pktsize += http_add_uwsgi_header(h_session, h_session->iov, h_session->uss+c, h_session->uss+c+2, base, ptr-base, &c); + ptr++; + base = ptr+1; + } + ptr++; + } + + uwsgi_log("vec size: %d pkt size: %d load %d\n", c, h_session->uh.pktsize, uhttp.load); + + return c; + +} + +void http_loop() { + + int uhttp_queue; + int uhttp_server; + int nevents; + int interesting_fd; + int new_connection; + ssize_t len; + int i,j; + + char *magic_table[0xff]; + + char bbuf[0xffff]; + + void *events; + struct msghdr msg; + union { + struct cmsghdr cmsg; + char control [CMSG_SPACE (sizeof (int))]; + } msg_control; + struct cmsghdr *cmsg; + + struct sockaddr_un uhttp_addr; + socklen_t uhttp_addr_len = sizeof(struct sockaddr_un); + + struct http_session *uhttp_session; + + struct http_session *uhttp_table[2048]; + + int soopt; + socklen_t solen = sizeof(int); + + for(i=0;i<2048;i++) { + uhttp_table[i] = NULL; + } + + uhttp_server = bind_to_tcp(uhttp.socket_name, uwsgi.listen_queue, strchr(uhttp.socket_name,':')); + + uhttp_queue = event_queue_init(); + + events = event_queue_alloc(uhttp.nevents); + + event_queue_add_fd_read(uhttp_queue, uhttp_server); + + if (uhttp.pattern) { + init_magic_table(magic_table); + } + + for (;;) { + + nevents = event_queue_wait_multi(uhttp_queue, -1, events, uhttp.nevents); + + for (i=0;ifd = new_connection; + uhttp_table[new_connection]->instance_fd = -1; + uhttp_table[new_connection]->status = HTTP_STATUS_RECV; + uhttp_table[new_connection]->h_pos = 0; + uhttp_table[new_connection]->pos = 0; + uhttp_table[new_connection]->rnrn = 0; + uhttp_table[new_connection]->parse_pos = 0; + uhttp_table[new_connection]->pass_fd = 0; + uhttp_table[new_connection]->ptr = uhttp_table[new_connection]->buffer; + uhttp_table[new_connection]->instance_address_len = 0; + uhttp_table[new_connection]->uh.modifier1 = uhttp.modifier1; + uhttp_table[new_connection]->uh.pktsize = 0; + uhttp_table[new_connection]->uh.modifier2 = 0; + + uhttp.load++; + + event_queue_add_fd_read(uhttp_queue, new_connection); + + } + else { + uhttp_session = uhttp_table[interesting_fd]; + + // something is going wrong... + if (uhttp_session == NULL) continue; + + if (event_queue_interesting_fd_has_error(events, i)) { + close(uhttp_session->fd); + uhttp_table[uhttp_session->fd] = NULL; + if (uhttp_session->instance_fd != -1) { + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->instance_fd] = NULL; + } + uhttp.load--; + free(uhttp_session); + continue; + } + + switch(uhttp_session->status) { + + case HTTP_STATUS_RECV: + len = recv(uhttp_session->fd, uhttp_session->buffer + uhttp_session->h_pos, 0xffff-uhttp_session->h_pos, 0); + if (len <= 0) { + uwsgi_error("recv()"); + close(uhttp_session->fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + uhttp_session->h_pos += len; + + for(j=0;jptr, uhttp_session->rnrn); + if (*uhttp_session->ptr == '\r' && (uhttp_session->rnrn == 0 || uhttp_session->rnrn == 2)) { + uhttp_session->rnrn++; + } + else if (*uhttp_session->ptr == '\r') { + uhttp_session->rnrn = 1; + } + else if (*uhttp_session->ptr == '\n' && uhttp_session->rnrn == 1) { + uhttp_session->rnrn = 2; + } + else if (*uhttp_session->ptr == '\n' && uhttp_session->rnrn == 3) { + uhttp_session->ptr++; + uhttp_session->remains = len-(j+1); + uhttp_session->iov_len = http_parse(uhttp_session); + + if (uhttp_session->iov_len == 0) { + close(uhttp_session->fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + + if (uhttp.base) { + uhttp_session->instance_address = uwsgi_cache_get(uhttp_session->hostname, uhttp_session->hostname_len, &uhttp_session->instance_address_len); + } + else if (uhttp.pattern) { + magic_table['s'] = uwsgi_concat2n(uhttp_session->hostname, uhttp_session->hostname_len, "", 0); + int tmp_addr_len = 0; + uhttp_session->instance_address = magic_sub(uhttp.pattern, uhttp.pattern_len, &tmp_addr_len, magic_table); + uhttp_session->instance_address_len = tmp_addr_len; + free(magic_table['s']); + } + else if (uhttp.to) { + uhttp_session->instance_address = uhttp.to; + uhttp_session->instance_address_len = uhttp.to_len; + } + else if (uwsgi.sockets_cnt > 0) { + uhttp_session->instance_address = uwsgi.sockets[0].name; + uhttp_session->instance_address_len = strlen(uwsgi.sockets[0].name); + } + + uhttp_session->pass_fd = is_unix(uhttp_session->instance_address, uhttp_session->instance_address_len); + + uhttp_session->instance_fd = uwsgi_connectn(uhttp_session->instance_address, uhttp_session->instance_address_len, 0, 1); + + if (uhttp.pattern) { + free(uhttp_session->instance_address); + } + + if (uhttp_session->instance_fd < 0) { + close(uhttp_session->fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + + uhttp_session->status = HTTP_STATUS_CONNECTING; + uhttp_table[uhttp_session->instance_fd] = uhttp_session; + event_queue_add_fd_write(uhttp_queue, uhttp_session->instance_fd); + break; + } + else { + uhttp_session->rnrn = 0; + } + uhttp_session->ptr++; + } + + + break; + + + case HTTP_STATUS_CONNECTING: + + if (interesting_fd == uhttp_session->instance_fd) { + + if (getsockopt(uhttp_session->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { + uwsgi_error("getsockopt()"); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + if (soopt) { + uwsgi_log("unable to connect() to uwsgi instance: %s\n", strerror(soopt)); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + uhttp_session->iov[0].iov_base = &uhttp_session->uh; + uhttp_session->iov[0].iov_len = 4; + + if (uhttp_session->remains > 0) { + uhttp_session->iov[uhttp_session->iov_len].iov_base = uhttp_session->ptr; + uhttp_session->iov[uhttp_session->iov_len].iov_len = uhttp_session->remains; + uhttp_session->iov_len++; + } + + // fd passing: PERFORMANCE EXTREME BOOST !!! + if (uhttp_session->pass_fd) { + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = uhttp_session->iov; + msg.msg_iovlen = uhttp_session->iov_len; + msg.msg_flags = 0; + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof (msg_control); + + cmsg = CMSG_FIRSTHDR (&msg); + cmsg->cmsg_len = CMSG_LEN (sizeof (int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + *((int *) CMSG_DATA (cmsg)) = uhttp_session->fd; + + if (sendmsg(uhttp_session->instance_fd, &msg, 0) < 0) { + uwsgi_error("sendmsg()"); + } + + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + if (writev(uhttp_session->instance_fd, uhttp_session->iov, uhttp_session->iov_len) <= 0) { + uwsgi_error("writev()"); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + event_queue_del_fd(uhttp_queue, uhttp_session->instance_fd); + event_queue_add_fd_read(uhttp_queue, uhttp_session->instance_fd); + uhttp_session->status = HTTP_STATUS_RESPONSE; + } + + break; + + case HTTP_STATUS_RESPONSE: + + // data from instance + if (interesting_fd == uhttp_session->instance_fd) { + len = recv(uhttp_session->instance_fd, bbuf, 0xffff, 0); + if (len <= 0) { + if (len < 0) uwsgi_error("recv()"); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + len = send(uhttp_session->fd, bbuf, len, 0); + + if (len <= 0) { + if (len < 0) uwsgi_error("send()"); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + } + // body from client + else if (interesting_fd == uhttp_session->fd) { + + //uwsgi_log("receiving body...\n"); + len = recv(uhttp_session->fd, bbuf, 0xffff, 0); + if (len <= 0) { + if (len < 0) uwsgi_error("recv()"); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + + + len = send(uhttp_session->instance_fd, bbuf, len, 0); + + if (len <= 0) { + if (len < 0) uwsgi_error("send()"); + close(uhttp_session->fd); + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->fd] = NULL; + uhttp_table[uhttp_session->instance_fd] = NULL; + uhttp.load--; + free(uhttp_session); + break; + } + } + + break; + + + + // fallback to destroy !!! + default: + uwsgi_log("default action\n"); + close(uhttp_session->fd); + uhttp_table[uhttp_session->fd] = NULL; + if (uhttp_session->instance_fd != -1) { + close(uhttp_session->instance_fd); + uhttp_table[uhttp_session->instance_fd] = NULL; + } + uhttp.load--; + free(uhttp_session); + break; + + } + } + + } + } +} + +int http_init() { + + if (uhttp.socket_name) { + + if (uhttp.use_cache && !uwsgi.cache_max_items) { + uwsgi_log("you need to create a uwsgi cache to use the http (add --cache )\n"); + exit(1); + } + + if (!uhttp.nevents) uhttp.nevents = 64; + + if (!uhttp.base && !uhttp.use_cache && !uhttp.to && !uwsgi.sockets_cnt) { + uwsgi.sockets[0].name = uwsgi_malloc(64); + uwsgi.sockets_cnt++; + snprintf(uwsgi.sockets[0].name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid()); + } + + if (register_gateway("http", http_loop) == NULL) { + uwsgi_log("unable to register the http gateway\n"); + exit(1); + } + } + + return 0; +} + +int http_opt(int i, char *optarg) { + + switch(i) { + case LONG_ARGS_HTTP: + uhttp.socket_name = optarg; + return 1; + case LONG_ARGS_HTTP_EVENTS: + uhttp.nevents = atoi(optarg); + return 1; + case LONG_ARGS_HTTP_USE_PATTERN: + uhttp.pattern = optarg; + // optimization + uhttp.pattern_len = strlen(uhttp.pattern); + return 1; + case LONG_ARGS_HTTP_USE_BASE: + uhttp.base = optarg; + // optimization + uhttp.base_len = strlen(uhttp.base); + return 1; + case LONG_ARGS_HTTP_USE_TO: + uhttp.to = optarg; + // optimization + uhttp.to_len = strlen(uhttp.to); + return 1; + case LONG_ARGS_HTTP_VAR: + if (uhttp.http_vars_cnt < MAX_HTTP_EXTRA_VARS) { + uhttp.http_vars[uhttp.http_vars_cnt] = optarg; + uhttp.http_vars_cnt++; + } else { + uwsgi_log("you can specify at most 64 --http-var options\n"); + } + return 1; + case LONG_ARGS_HTTP_MODIFIER1: + uhttp.modifier1 = (uint8_t) atoi(optarg); + return 1; + } + return 0; +} + + + +struct uwsgi_plugin http_plugin = { + + .options = http_options, + .manage_opt = http_opt, + .init = http_init, +}; + diff --git a/plugins/http/uwsgiplugin.py b/plugins/http/uwsgiplugin.py new file mode 100644 index 00000000..0ef91c95 --- /dev/null +++ b/plugins/http/uwsgiplugin.py @@ -0,0 +1,7 @@ + +NAME='http' +CFLAGS = [] +LDFLAGS = [] +LIBS = [] + +GCC_LIST = ['http'] diff --git a/uwsgi.c b/uwsgi.c index f751f2af..51659a6a 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -135,17 +135,6 @@ static struct option long_base_options[] = { #ifdef UWSGI_ROUTING {"routing", no_argument, &uwsgi.routing, 1}, #endif - -#ifdef UWSGI_HTTP - {"http", required_argument, 0, LONG_ARGS_HTTP}, - {"http-only", no_argument, &uwsgi.http_only, 1}, - {"http-var", required_argument, 0, LONG_ARGS_HTTP_VAR}, - {"http-modifier1", required_argument, 0, LONG_ARGS_HTTP_MODIFIER1}, -#endif -#ifdef UWSGI_ERLANG - {"erlang", required_argument, 0, LONG_ARGS_ERLANG}, - {"erlang-cookie", required_argument, 0, LONG_ARGS_ERLANG_COOKIE}, -#endif {"check-static", required_argument, 0, LONG_ARGS_CHECK_STATIC}, {"close-on-exec", no_argument, &uwsgi.close_on_exec, 1}, {"mode", required_argument, 0, LONG_ARGS_MODE}, @@ -784,10 +773,6 @@ int uwsgi_start(void *v_argv) { #endif -#ifdef UWSGI_HTTP - pid_t http_pid; -#endif - pid_t pid; int i, j; @@ -797,8 +782,6 @@ int uwsgi_start(void *v_argv) { int emperor_pipe[2]; - FILE *pidfile; - uwsgi_log("my PID is %d\n", (int) getpid()); #ifdef __linux__ @@ -928,63 +911,6 @@ int uwsgi_start(void *v_argv) { } sanitize_args(); -#ifdef UWSGI_HTTP - if (uwsgi.http && !uwsgi.is_a_reload) { - char *tcp_port = strchr(uwsgi.http, ':'); - if (tcp_port) { - uwsgi.http_server_port = tcp_port + 1; - uwsgi.http_fd = bind_to_tcp(uwsgi.http, uwsgi.listen_queue, tcp_port); -#ifdef UWSGI_DEBUG - uwsgi_debug("HTTP FD: %d\n", uwsgi.http_fd); -#endif - } else { - uwsgi_log("invalid http address.\n"); - exit(1); - } - - if (uwsgi.http_fd < 0) { - uwsgi_log("unable to create http server socket.\n"); - exit(1); - } - if (!uwsgi.sockets[0].name) { - - uwsgi.sockets[0].name = uwsgi_malloc(64); - uwsgi.sockets_cnt++; - snprintf(uwsgi.sockets[0].name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid()); - uwsgi_log("using %s as uwsgi protocol socket\n", uwsgi.sockets[0].name); - } - if (uwsgi.http_only) { - http_loop(); - //never here - exit(1); - } - http_pid = fork(); - - if (http_pid > 0) { - masterpid = http_pid; - http_loop(); - //never here - exit(1); - } else if (http_pid < 0) { - uwsgi_error("fork()"); - exit(1); - } - if (uwsgi.pidfile && !uwsgi.is_a_reload) { - uwsgi_log("updating pidfile with pid %d\n", (int) getpid()); - pidfile = fopen(uwsgi.pidfile, "w"); - if (!pidfile) { - uwsgi_error("fopen"); - exit(1); - } - if (fprintf(pidfile, "%d\n", (int) getpid()) < 0) { - uwsgi_log("could not update pidfile.\n"); - } - fclose(pidfile); - } - close(uwsgi.http_fd); - } -#endif - // end of generic initialization // start the Emperor if needed @@ -1846,11 +1772,6 @@ end: case LONG_ARGS_CHDIR2: uwsgi.chdir2 = optarg; return 1; -#ifdef UWSGI_HTTP - case LONG_ARGS_HTTP: - uwsgi.http = optarg; - return 1; -#endif #ifdef UWSGI_LDAP case LONG_ARGS_LDAP: uwsgi.ldap = optarg; @@ -1952,19 +1873,6 @@ end: case LONG_ARGS_ERLANG_COOKIE: uwsgi.erlang_cookie = optarg; return 1; -#endif -#ifdef UWSGI_HTTP - case LONG_ARGS_HTTP_VAR: - if (uwsgi.http_vars_cnt < 63) { - uwsgi.http_vars[uwsgi.http_vars_cnt] = optarg; - uwsgi.http_vars_cnt++; - } else { - uwsgi_log("you can specify at most 64 --http-var options\n"); - } - return 1; - case LONG_ARGS_HTTP_MODIFIER1: - uwsgi.http_modifier1 = (uint8_t) atoi(optarg); - return 1; #endif case LONG_ARGS_CHECK_STATIC: uwsgi.check_static = optarg; diff --git a/uwsgi.h b/uwsgi.h index 9a88d257..c78e5ebb 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -413,6 +413,7 @@ struct uwsgi_loop { struct uwsgi_socket { int fd; char *name; + int name_len; int family; int bound; int arg; @@ -661,6 +662,7 @@ struct uwsgi_server { char hostname[256]; + int hostname_len; int no_initial_output; int has_threads; int apps_cnt; @@ -695,17 +697,6 @@ struct uwsgi_server { int gateways_cnt; -#ifdef UWSGI_HTTP - char *http; - char *http_server_name; - char *http_server_port; - int http_only; - int http_fd; - char *http_vars[64]; - int http_vars_cnt; - uint8_t http_modifier1; -#endif - int ignore_script_name; int manage_script_name; int no_default_app; @@ -1242,8 +1233,6 @@ int uwsgi_load_plugin(int, char *, char *, int); void embed_plugins(void); -void http_loop(void); - int unconfigured_hook(struct wsgi_request *); #ifdef UWSGI_INI diff --git a/uwsgiconfig.py b/uwsgiconfig.py index a65e2353..fc7c6598 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -378,10 +378,6 @@ class uConf(object): self.gcc_list.append('ldap') self.libs.append('-lldap') - if self.get('http'): - self.cflags.append("-DUWSGI_HTTP") - self.gcc_list.append('http') - if self.get('evdis'): self.cflags.append("-DUWSGI_EVDIS") self.gcc_list.append('evdis')