the new (production-friendly) HTTP server

This commit is contained in:
roberto@maverick64
2011-02-08 16:04:41 +01:00
parent 0288313524
commit fa1dd3fbfd
7 changed files with 735 additions and 575 deletions
+1 -2
View File
@@ -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
-464
View File
@@ -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<uwsgi.http_vars_cnt;j++) {
char *separator;
separator = strchr(uwsgi.http_vars[j], '=');
if (separator) {
up = add_uwsgi_var(up, uwsgi.http_vars[j], separator - uwsgi.http_vars[j], separator + 1, strlen(separator + 1), 0, watermark);
}
else {
up = add_uwsgi_var(up, uwsgi.http_vars[j], strlen(uwsgi.http_vars[j]), NULL, 0, 0, watermark);
}
}
uwsgi_fd = uwsgi_connect(uwsgi.sockets[0].name, 10, 0);
if (uwsgi_fd >= 0) {
ulen = (up - uwsgipkt) - 4;
uwsgipkt[1] = (unsigned char) (ulen & 0xff);
uwsgipkt[2] = (unsigned char) ((ulen >> 8) & 0xff);
if (write(uwsgi_fd, uwsgipkt, ulen + 4) < 0) {
uwsgi_error("write()");
}
if (http_upgrade) {
// send already available data
if ( (len - (i + 1)) > 0) {
if (write(uwsgi_fd, buf + i + 1, len - (i + 1)) < 0) {
uwsgi_error("write()");
close(uwsgi_fd);
goto clear;
}
}
http_poll[0].fd = clientfd;
http_poll[0].events = POLLIN;
http_poll[1].fd = uwsgi_fd;
http_poll[1].events = POLLIN;
for(;;) {
rlen = poll(http_poll, 2, -1);
if (rlen < 0) {
uwsgi_error("poll()");
close(uwsgi_fd);
goto clear;
}
else if (rlen > 0) {
if (http_poll[0].revents & POLLIN) {
len = read(clientfd, uwsgipkt, 4096);
if (len > 0) {
if (write(uwsgi_fd, uwsgipkt, len) < 0) {
uwsgi_error("write()");
close(uwsgi_fd);
goto clear;
}
}
else {
// client disconnected
close(uwsgi_fd);
goto clear;
}
}
else if (http_poll[1].revents & POLLIN) {
len = read(uwsgi_fd, uwsgipkt, 4096);
if (len > 0) {
if (write(clientfd, uwsgipkt, len) < 0) {
uwsgi_error("write()");
close(uwsgi_fd);
goto clear;
}
}
else {
// client disconnected
close(uwsgi_fd);
goto clear;
}
}
}
else {
// timeout
close(uwsgi_fd);
goto clear;
}
}
}
else {
if (http_body_len > 0) {
if (http_body_len >= (int) len - (i + 1)) {
if (write(uwsgi_fd, buf + i + 1, len - (i + 1)) < 0) {
uwsgi_error("write()");
}
http_body_len -= len - (i + 1);
} else {
if (write(uwsgi_fd, buf + i, http_body_len) < 0) {
uwsgi_error("write()");
}
http_body_len = 0;
}
while (http_body_len > 0) {
int to_read = 4096;
if (http_body_len < to_read) {
to_read = http_body_len;
}
len = read(clientfd, uwsgipkt, to_read);
if (write(uwsgi_fd, uwsgipkt, len) < 0) {
uwsgi_error("write()");
}
http_body_len -= len;
}
}
}
while ((len = read(uwsgi_fd, uwsgipkt, 4096)) > 0) {
if (write(clientfd, uwsgipkt, len) < 0) {
uwsgi_error("write()");
}
}
close(uwsgi_fd);
}
else {
close(uwsgi_fd);
goto clear;
}
}
} else if (buf[i] == ':') {
if (state == uwsgi_http_header_key) {
state = uwsgi_http_header_key_colon;
} else {
//check for overflow
if (ptr+1 > 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;
}
+725
View File
@@ -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<hhlen;i++) {
if (!status) {
hh[i] = toupper(hh[i]);
if (hh[i] == '-') hh[i] = '_';
if (hh[i] == ':') {
status = 1;
keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
vallen++;
}
else if (status == 2) {
vallen++;
}
}
if (!keylen) return 0;
if ((*c) + 4 >= 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;i<nevents;i++) {
interesting_fd = event_queue_interesting_fd(events, i);
if (interesting_fd == uhttp_server) {
new_connection = accept(uhttp_server, (struct sockaddr *) &uhttp_addr, &uhttp_addr_len);
if (new_connection < 0) {
continue;
}
uhttp_table[new_connection] = alloc_uhttp_session();
uhttp_table[new_connection]->fd = 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;j<len;j++) {
//uwsgi_log("%d %d %d\n", j, *uhttp_session->ptr, 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>)\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,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='http'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['http']
-92
View File
@@ -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;
+2 -13
View File
@@ -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
-4
View File
@@ -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')