mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c9ebdaa69 | ||
|
|
fbd9e5b4d7 | ||
|
|
b9a3425b6d | ||
|
|
d4742c611b | ||
|
|
c645a590aa | ||
|
|
275a7fe63f | ||
|
|
0ff16d8312 | ||
|
|
1cb31d6c7e | ||
|
|
8a6eb553df | ||
|
|
946af8b9ee | ||
|
|
098a1f647e | ||
|
|
c9681dc430 | ||
|
|
ff0b8b2d53 | ||
|
|
75f520d43a | ||
|
|
65209748ba | ||
|
|
cd604ef07b | ||
|
|
51da8bc531 | ||
|
|
2374ba12bd | ||
|
|
0a75aaec25 | ||
|
|
a8c286ae83 | ||
|
|
9cbdfc7764 | ||
|
|
cb1423436f | ||
|
|
2fb391795a | ||
|
|
9ec20f2d8f | ||
|
|
9323ca5136 | ||
|
|
978e6072ab | ||
|
|
d0e3869d54 | ||
|
|
15c7e956f2 | ||
|
|
ed61545ec7 | ||
|
|
1aac5becdc | ||
|
|
4bca26debc | ||
|
|
d6eecd1637 | ||
|
|
00e7620d2e | ||
|
|
d657283aad | ||
|
|
70a879ea94 | ||
|
|
591ee22472 | ||
|
|
956b05d39d | ||
|
|
5bdad6d4cb | ||
|
|
29a6ac6ed7 | ||
|
|
8f7f091e9b | ||
|
|
63dfe7628b | ||
|
|
ce507e7851 | ||
|
|
a9cd76173e | ||
|
|
44f8ffb434 | ||
|
|
28c395f111 | ||
|
|
39df68c38e | ||
|
|
b33ca9225a | ||
|
|
bd137afecf | ||
|
|
a3b9bed8c2 | ||
|
|
0a157739bc | ||
|
|
c46b08ad5e | ||
|
|
754e6193a4 | ||
|
|
56b49fe2dd | ||
|
|
36a7215f94 | ||
|
|
702247affd | ||
|
|
e752b1f8e5 | ||
|
|
920eee36e3 | ||
|
|
a5070a5d98 | ||
|
|
ccb5aefa61 | ||
|
|
378b08e37c | ||
|
|
5763483c91 | ||
|
|
559f8ee095 | ||
|
|
4382ef360c | ||
|
|
0cb576cf1a | ||
|
|
dee4d047b4 | ||
|
|
2520cc7bb9 | ||
|
|
192c31efe0 | ||
|
|
a1d8ebc2d2 | ||
|
|
14a9de2147 | ||
|
|
a760a9a3f1 | ||
|
|
efd14e1c7a | ||
|
|
6019c46cee | ||
|
|
ec6acfbc1c | ||
|
|
e925dbaad6 | ||
|
|
8321adf0bc | ||
|
|
e1c5e9e874 | ||
|
|
0aec581714 | ||
|
|
b77b8623d1 | ||
|
|
5ab986d6d9 | ||
|
|
09b8332236 | ||
|
|
d05345abc0 | ||
|
|
804c369f0d | ||
|
|
8f67fc886c | ||
|
|
ca3b1a9b30 | ||
|
|
63c1dbb3ed | ||
|
|
9a424dfe29 | ||
|
|
0a6eb596bb | ||
|
|
34452376db | ||
|
|
53a90a59c5 | ||
|
|
ec491ebd83 | ||
|
|
cdc41c305e | ||
|
|
6cf67b399c | ||
|
|
dc3c56bccc | ||
|
|
4657f2039a | ||
|
|
b0082fbd0d | ||
|
|
ede1b4df11 | ||
|
|
d78a3d1f8a | ||
|
|
6152555f26 | ||
|
|
bbad505044 | ||
|
|
11c5429184 | ||
|
|
4e865c4525 | ||
|
|
2fa785a539 | ||
|
|
296a8449c9 | ||
|
|
f20213ff10 | ||
|
|
8a7067ee24 | ||
|
|
a3024e9f5a | ||
|
|
86e651f5e7 | ||
|
|
409710b2b1 | ||
|
|
14a406a276 | ||
|
|
28a283b1c1 | ||
|
|
ccf298a148 | ||
|
|
914b600af4 | ||
|
|
4944994667 | ||
|
|
3a487578a5 | ||
|
|
39eeccb16a | ||
|
|
32acd3b9d1 | ||
|
|
c57baae477 |
+1
-1
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi
|
||||
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap
|
||||
inherit = base
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
+126
-94
@@ -2,6 +2,24 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
This is a general purpose async loop engine (it expects a coroutine based approach)
|
||||
|
||||
You can see it as an hub holding the following structures:
|
||||
|
||||
1) the runqueue, cores ready to be run are appended in this list
|
||||
|
||||
2) the fd list, this is a list of monitored file descriptors, a core can wait for all the file descriptors it needs
|
||||
|
||||
3) the timeout value, if set the current core will timeout aftert he specified number of seconds (unless an event cancel it)
|
||||
|
||||
|
||||
IMPORTANT: this is not a callback based engine !!!
|
||||
|
||||
*/
|
||||
|
||||
// this is called whenever a new connection is ready, but there are no cores to handle it
|
||||
void uwsgi_async_queue_is_full(time_t now) {
|
||||
if (now > uwsgi.async_queue_is_full) {
|
||||
uwsgi_log_verbose("[DANGER] async queue is full !!!\n");
|
||||
@@ -22,12 +40,15 @@ void uwsgi_async_init() {
|
||||
|
||||
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
|
||||
|
||||
// a stack of unused cores
|
||||
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
|
||||
|
||||
// fill it with default values
|
||||
for (i = 0; i < uwsgi.async; i++) {
|
||||
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
|
||||
}
|
||||
|
||||
// the first available core is the last one
|
||||
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
|
||||
|
||||
}
|
||||
@@ -52,7 +73,7 @@ static void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
child->prev = parent;
|
||||
}
|
||||
|
||||
if (parent == NULL) {
|
||||
if (u_request == uwsgi.async_runqueue) {
|
||||
uwsgi.async_runqueue = child;
|
||||
}
|
||||
|
||||
@@ -61,33 +82,33 @@ static void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
}
|
||||
|
||||
free(u_request);
|
||||
|
||||
uwsgi.async_runqueue_cnt--;
|
||||
}
|
||||
|
||||
static void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_async_request *uar;
|
||||
// do not push the same request in the runqueue
|
||||
struct uwsgi_async_request *uar = uwsgi.async_runqueue;
|
||||
while(uar) {
|
||||
if (uar->wsgi_req == wsgi_req) return;
|
||||
uar = uar->next;
|
||||
}
|
||||
|
||||
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uar->prev = NULL;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
|
||||
if (uwsgi.async_runqueue == NULL) {
|
||||
// empty runqueue, create a new one
|
||||
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uwsgi.async_runqueue->next = NULL;
|
||||
uwsgi.async_runqueue->prev = NULL;
|
||||
uwsgi.async_runqueue->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
|
||||
uwsgi.async_runqueue = uar;
|
||||
}
|
||||
else {
|
||||
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
}
|
||||
|
||||
uwsgi.async_runqueue_cnt++;
|
||||
|
||||
if (uwsgi.async_runqueue_last) {
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
}
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
}
|
||||
|
||||
struct wsgi_request *find_first_available_wsgi_req() {
|
||||
@@ -103,11 +124,28 @@ struct wsgi_request *find_first_available_wsgi_req() {
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
void async_reset_request(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->async_timeout) {
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout);
|
||||
free(wsgi_req->async_timeout);
|
||||
wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_async_fd *uaf = wsgi_req->waiting_fds;
|
||||
while (uaf) {
|
||||
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
|
||||
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
|
||||
struct uwsgi_async_fd *current_uaf = uaf;
|
||||
uaf = current_uaf->next;
|
||||
free(current_uaf);
|
||||
}
|
||||
|
||||
wsgi_req->waiting_fds = NULL;
|
||||
}
|
||||
|
||||
static void async_expire_timeouts(uint64_t now) {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for (;;) {
|
||||
@@ -121,20 +159,9 @@ static void async_expire_timeouts(uint64_t now) {
|
||||
wsgi_req = (struct wsgi_request *) urbt->data;
|
||||
// timeout expired
|
||||
wsgi_req->async_timed_out = 1;
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout);
|
||||
free(wsgi_req->async_timeout);
|
||||
wsgi_req->async_timeout = NULL;
|
||||
uaf = wsgi_req->waiting_fds;
|
||||
// remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready)
|
||||
while (uaf) {
|
||||
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
|
||||
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
|
||||
current_uaf = uaf;
|
||||
uaf = current_uaf->next;
|
||||
free(current_uaf);
|
||||
}
|
||||
wsgi_req->waiting_fds = NULL;
|
||||
// put th request in the runqueue
|
||||
// reset teh request
|
||||
async_reset_request(wsgi_req);
|
||||
// push it in the runqueue
|
||||
runqueue_push(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
@@ -151,7 +178,7 @@ int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
// find first slot
|
||||
// find last slot
|
||||
while (uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
@@ -208,7 +235,7 @@ int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
// find first slot
|
||||
// find last slot
|
||||
while (uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
@@ -252,7 +279,49 @@ static int async_wait_fd_write(int fd, int timeout) {
|
||||
}
|
||||
|
||||
void async_schedule_to_req(void) {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
// a trick to avoid calling routes again
|
||||
uwsgi.wsgi_req->is_routing = 1;
|
||||
#endif
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(uwsgi.wsgi_req);
|
||||
}
|
||||
return;
|
||||
|
||||
end:
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
}
|
||||
|
||||
void async_schedule_to_req_green(void) {
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
for(;;) {
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
uwsgi.wsgi_req->switches++;
|
||||
// switch after each yield
|
||||
uwsgi.schedule_to_main(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
end:
|
||||
#endif
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
}
|
||||
|
||||
void async_loop() {
|
||||
@@ -262,7 +331,6 @@ void async_loop() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_async_fd *tmp_uaf;
|
||||
int interesting_fd, i;
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
int timeout;
|
||||
@@ -271,13 +339,12 @@ void async_loop() {
|
||||
|
||||
uint64_t now;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
struct uwsgi_async_request *current_request = NULL;
|
||||
|
||||
void *events = event_queue_alloc(64);
|
||||
struct uwsgi_socket *uwsgi_sock;
|
||||
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
|
||||
uwsgi.wait_write_hook = async_wait_fd_write;
|
||||
uwsgi.wait_read_hook = async_wait_fd_read;
|
||||
@@ -298,7 +365,7 @@ void async_loop() {
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
now = (uint64_t) uwsgi_now();
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
if (uwsgi.async_runqueue) {
|
||||
timeout = 0;
|
||||
}
|
||||
else {
|
||||
@@ -328,16 +395,15 @@ void async_loop() {
|
||||
// manage events
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
// signals are executed in the main stack... in the future we could have dedicated stacks for them
|
||||
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
|
||||
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
is_a_new_connection = 0;
|
||||
|
||||
// new request coming in ?
|
||||
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
|
||||
@@ -351,6 +417,7 @@ void async_loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
// on error re-insert the request in the queue
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock);
|
||||
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
@@ -364,6 +431,9 @@ void async_loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
// by default the core is in UWSGI_AGAIN mode
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
// some protocol (like zeromq) do not need additional parsing, just push it in the runqueue
|
||||
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
@@ -380,9 +450,7 @@ void async_loop() {
|
||||
if (uwsgi.wsgi_req) {
|
||||
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
|
||||
// reset timeout
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
// parsing complete
|
||||
if (!proto_parser_status) {
|
||||
// remove fd from event poll and fd proto table
|
||||
@@ -393,8 +461,6 @@ void async_loop() {
|
||||
continue;
|
||||
}
|
||||
else if (proto_parser_status < 0) {
|
||||
if (proto_parser_status == -1)
|
||||
uwsgi_log("error parsing request\n");
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
@@ -404,7 +470,7 @@ void async_loop() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// app event
|
||||
// app-registered event
|
||||
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
|
||||
// unknown fd, remove it (for safety)
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
@@ -413,79 +479,45 @@ void async_loop() {
|
||||
}
|
||||
|
||||
// remove all the fd monitors and timeout
|
||||
while (uwsgi.wsgi_req->waiting_fds) {
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_ready_fd = 1;
|
||||
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
|
||||
|
||||
// put the request in the runqueue again
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
// avoid managing other enqueued events...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// event queue managed, give cpu to runqueue
|
||||
if (!current_request)
|
||||
current_request = uwsgi.async_runqueue;
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
// event queue managed, give cpu to runqueue
|
||||
current_request = uwsgi.async_runqueue;
|
||||
|
||||
while(current_request) {
|
||||
|
||||
// current_request could be nulled on error/end of request
|
||||
struct uwsgi_async_request *next_request = current_request->next;
|
||||
|
||||
uwsgi.wsgi_req = current_request->wsgi_req;
|
||||
|
||||
uwsgi.schedule_to_req();
|
||||
uwsgi.wsgi_req->switches++;
|
||||
|
||||
next_async_request = current_request->next;
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
// remove all the monitored fds and timeout
|
||||
while (uwsgi.wsgi_req->waiting_fds) {
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
// remove from the list
|
||||
// remove from the runqueue
|
||||
runqueue_remove(current_request);
|
||||
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
|
||||
// push wsgi_request in the unused stack
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
|
||||
}
|
||||
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove this request from suspended list
|
||||
// remove this request from the runqueue
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
current_request = next_async_request;
|
||||
|
||||
current_request = next_request;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -354,3 +354,11 @@ struct uwsgi_buffer *uwsgi_buffer_from_file(char *filename) {
|
||||
return ub;
|
||||
}
|
||||
|
||||
void uwsgi_buffer_map(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
if (ub->buf) {
|
||||
free(ub->buf);
|
||||
}
|
||||
ub->buf = buf;
|
||||
ub->pos = len;
|
||||
ub->len = len;
|
||||
}
|
||||
|
||||
+77
-4
@@ -416,6 +416,24 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t uwsgi_cache_num2(struct uwsgi_cache *uc, char *key, uint16_t keylen) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
|
||||
if (index) {
|
||||
struct uwsgi_cache_item *uci = cache_item(index);
|
||||
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
|
||||
return 0;
|
||||
uci->hits++;
|
||||
uc->hits++;
|
||||
int64_t *num = (int64_t *) (uc->data + (uci->first_block * uc->blocksize));
|
||||
return *num;
|
||||
}
|
||||
|
||||
uc->miss++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize, uint64_t *expires) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
@@ -543,6 +561,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
|
||||
if (vallen > uc->max_item_size) return -1;
|
||||
|
||||
if ((flags & UWSGI_CACHE_FLAG_MATH) && vallen != 8) return -1;
|
||||
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
if (!index) {
|
||||
@@ -602,7 +622,33 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
uci->hits = 0;
|
||||
uci->flags = flags;
|
||||
memcpy(uci->key, key, keylen);
|
||||
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
|
||||
|
||||
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
|
||||
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
|
||||
}
|
||||
// ok math operations here
|
||||
else {
|
||||
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
|
||||
*num = uc->math_initial;
|
||||
int64_t *delta = (int64_t *) val;
|
||||
if (flags & UWSGI_CACHE_FLAG_INC) {
|
||||
*num += *delta;
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_DEC) {
|
||||
*num -= *delta;
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_MUL) {
|
||||
*num *= *delta;
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_DIV) {
|
||||
if (*delta == 0) {
|
||||
*num = 0;
|
||||
}
|
||||
else {
|
||||
*num /= *delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
|
||||
@@ -634,7 +680,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = cache_item(index);
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
uci->expires = expires;
|
||||
@@ -661,7 +707,30 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
// unmark the old blocks
|
||||
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
}
|
||||
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
|
||||
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
|
||||
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
|
||||
}
|
||||
else {
|
||||
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
|
||||
int64_t *delta = (int64_t *) val;
|
||||
if (flags & UWSGI_CACHE_FLAG_INC) {
|
||||
*num += *delta;
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_DEC) {
|
||||
*num -= *delta;
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_MUL) {
|
||||
*num *= *delta;
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_DIV) {
|
||||
if (*delta == 0) {
|
||||
*num = 0;
|
||||
}
|
||||
else {
|
||||
*num /= *delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
uci->valsize = vallen;
|
||||
ret = 0;
|
||||
}
|
||||
@@ -968,6 +1037,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
char *c_udp_servers = NULL;
|
||||
char *c_bitmap = NULL;
|
||||
char *c_use_last_modified = NULL;
|
||||
char *c_math_initial = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"name", &c_name,
|
||||
@@ -994,6 +1064,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
"udpserver", &c_udp_servers,
|
||||
"bitmap", &c_bitmap,
|
||||
"lastmod", &c_use_last_modified,
|
||||
"math_initial", &c_math_initial,
|
||||
NULL)) {
|
||||
uwsgi_log("unable to parse cache definition\n");
|
||||
exit(1);
|
||||
@@ -1040,6 +1111,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
}
|
||||
if (c_use_last_modified) uc->use_last_modified = 1;
|
||||
|
||||
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
|
||||
|
||||
uc->store_sync = uwsgi.cache_store_sync;
|
||||
if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); }
|
||||
|
||||
@@ -1737,7 +1810,7 @@ void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
uwsgi_hooked_parse(ub->buf, ub->pos, cache_sync_hook, uc);
|
||||
uwsgi_hooked_parse(ub->buf, rlen, cache_sync_hook, uc);
|
||||
|
||||
if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
+98
-8
@@ -1,4 +1,4 @@
|
||||
#include "../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -42,6 +42,31 @@ void uwsgi_daemons_smart_check() {
|
||||
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (ud->legion) {
|
||||
if (uwsgi_legion_i_am_the_lord(ud->legion)) {
|
||||
// lord, spawn if not running
|
||||
if (ud->pid <= 0) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// not lord, kill daemon if running
|
||||
if (ud->pid > 0) {
|
||||
if (!kill(ud->pid, 0)) {
|
||||
uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid);
|
||||
kill(-ud->pid, SIGTERM);
|
||||
}
|
||||
else {
|
||||
// pid already died
|
||||
ud->pid = -1;
|
||||
}
|
||||
}
|
||||
ud = ud->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ud->pidfile) {
|
||||
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (checked_pid <= 0) {
|
||||
@@ -70,12 +95,13 @@ void uwsgi_daemons_smart_check() {
|
||||
}
|
||||
}
|
||||
|
||||
// this function is called when a dumb daemon dies and we do not wat to respawn it
|
||||
// this function is called when a dumb daemon dies and we do not want to respawn it
|
||||
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pid == diedpid && !ud->pidfile) {
|
||||
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
|
||||
ud->pid = -1;
|
||||
return -1;
|
||||
}
|
||||
ud = ud->next;
|
||||
@@ -87,6 +113,15 @@ int uwsgi_daemon_check_pid_death(pid_t diedpid) {
|
||||
int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (ud->pid == diedpid && ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
|
||||
// part of legion but not lord, don't respawn
|
||||
ud->pid = -1;
|
||||
uwsgi_log("uwsgi-daemons] legion \"%s\" daemon \"%s\" (pid: %d) annihilated\n", ud->legion, ud->command, (int) diedpid);
|
||||
ud = ud->next;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (ud->pid == diedpid && !ud->pidfile) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
return 1;
|
||||
@@ -133,6 +168,20 @@ void uwsgi_daemons_spawn_all() {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (!ud->registered) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
|
||||
// part of legion, register but don't spawn it yet
|
||||
if (ud->pidfile) {
|
||||
ud->pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (ud->pid > 0)
|
||||
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
|
||||
}
|
||||
ud->registered = 1;
|
||||
ud = ud->next;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ud->registered = 1;
|
||||
if (ud->pidfile) {
|
||||
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (checked_pid <= 0) {
|
||||
@@ -146,7 +195,6 @@ void uwsgi_daemons_spawn_all() {
|
||||
else {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
ud->registered = 1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
@@ -156,8 +204,29 @@ void uwsgi_daemons_spawn_all() {
|
||||
void uwsgi_detach_daemons() {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pid > 0 && !ud->pidfile)
|
||||
kill(-ud->pid, SIGKILL);
|
||||
#ifdef UWSGI_SSL
|
||||
// stop any legion daemon, doesn't matter if dumb or smart
|
||||
if (ud->pid > 0 && (ud->legion || !ud->pidfile)) {
|
||||
#else
|
||||
// stop only dumb daemons
|
||||
if (ud->pid > 0 && !ud->pidfile) {
|
||||
#endif
|
||||
uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
// try to gracefully stop daemon, kill it if it won't die
|
||||
// if mercy is not set than wait up to 3 seconds
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
while (!kill(ud->pid, 0)) {
|
||||
kill(-ud->pid, SIGTERM);
|
||||
sleep(1);
|
||||
if (uwsgi_now() >= timeout) {
|
||||
uwsgi_log("[uwsgi-daemons] daemon did not died in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
kill(-ud->pid, SIGKILL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// unregister daemon to prevent it from being respawned
|
||||
ud->registered = 0;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
}
|
||||
@@ -165,6 +234,9 @@ void uwsgi_detach_daemons() {
|
||||
|
||||
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
// skip unregistered daemons
|
||||
if (!ud->registered) return;
|
||||
|
||||
int devnull = -1;
|
||||
int throttle = 0;
|
||||
|
||||
@@ -261,11 +333,26 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
|
||||
char *pidfile = NULL;
|
||||
int daemonize = 0;
|
||||
int freq = 10;
|
||||
char *space = NULL;
|
||||
|
||||
char *command = uwsgi_str(value);
|
||||
|
||||
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2")) {
|
||||
char *space = strchr(command, ' ');
|
||||
#ifdef UWSGI_SSL
|
||||
char *legion = NULL;
|
||||
if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) {
|
||||
space = strchr(command, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion daemon syntax: %s\n", command);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
legion = command;
|
||||
command = space+1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) {
|
||||
space = strchr(command, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command);
|
||||
exit(1);
|
||||
@@ -279,7 +366,7 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
|
||||
freq = atoi(comma + 1);
|
||||
}
|
||||
command = space + 1;
|
||||
if (!strcmp(opt, "smart-attach-daemon2")) {
|
||||
if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) {
|
||||
daemonize = 1;
|
||||
}
|
||||
}
|
||||
@@ -308,6 +395,9 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
|
||||
uwsgi_ud->last_spawn = 0;
|
||||
uwsgi_ud->daemonize = daemonize;
|
||||
uwsgi_ud->pidfile = pidfile;
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_ud->legion = legion;
|
||||
#endif
|
||||
|
||||
uwsgi.daemons_cnt++;
|
||||
|
||||
|
||||
+3
-1
@@ -18,7 +18,9 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
|
||||
}
|
||||
}
|
||||
|
||||
char *fullname = uwsgi_concat3(name, " ", uwsgi_num2str(num));
|
||||
char *str = uwsgi_num2str(num);
|
||||
char *fullname = uwsgi_concat3(name, " ", str);
|
||||
free(str);
|
||||
|
||||
ug = &ushared->gateways[ushared->gateways_cnt];
|
||||
ug->pid = 0;
|
||||
|
||||
@@ -347,6 +347,11 @@ void uwsgi_setup_workers() {
|
||||
// allocate signal table
|
||||
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
uwsgi_fixup_routes(uwsgi.routes);
|
||||
uwsgi_fixup_routes(uwsgi.final_routes);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
pid_t uwsgi_daemonize2() {
|
||||
|
||||
+3
-1
@@ -659,7 +659,9 @@ ready:
|
||||
// application generic lock
|
||||
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
|
||||
for (i = 0; i < uwsgi.locks + 1; i++) {
|
||||
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i)));
|
||||
char *num = uwsgi_num2str(i);
|
||||
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", num));
|
||||
free(num);
|
||||
}
|
||||
|
||||
// event queue lock (mitigate same event on multiple queues)
|
||||
|
||||
@@ -473,6 +473,18 @@ int master_loop(char **argv, char **environ) {
|
||||
uwsgi_check_touches(uwsgi.touch_chain_reload);
|
||||
uwsgi_check_touches(uwsgi.touch_workers_reload);
|
||||
uwsgi_check_touches(uwsgi.touch_gracefully_stop);
|
||||
// update exec touches
|
||||
struct uwsgi_string_list *usl = uwsgi.touch_exec;
|
||||
while(usl) {
|
||||
char *space = strchr(usl->value, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
usl->len = strlen(usl->value);
|
||||
usl->custom_ptr = space + 1;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_check_touches(uwsgi.touch_exec);
|
||||
|
||||
// setup cheaper algos (can be stacked)
|
||||
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
|
||||
@@ -748,6 +760,14 @@ int master_loop(char **argv, char **environ) {
|
||||
uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched);
|
||||
}
|
||||
}
|
||||
|
||||
// be sure to run it as the last touch check
|
||||
touched = uwsgi_check_touches(uwsgi.touch_exec);
|
||||
if (touched) {
|
||||
if (uwsgi_run_command( touched , NULL, -1) >= 0) {
|
||||
uwsgi_log_verbose("[uwsgi-touch-exec] running %s\n", touched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -833,6 +853,7 @@ next:
|
||||
// ok, if we are reloading or dying, just continue the master loop
|
||||
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered
|
||||
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) {
|
||||
if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now();
|
||||
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now()-uwsgi.workers[thewid].cursed_at));
|
||||
uwsgi.workers[thewid].cursed_at = 0;
|
||||
continue;
|
||||
|
||||
@@ -177,6 +177,7 @@ void uwsgi_master_check_gateways_deadline() {
|
||||
if (ushared->gateways_harakiri[i] > 0) {
|
||||
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
|
||||
if (ushared->gateways[i].pid > 0) {
|
||||
uwsgi_log("*** HARAKIRI ON GATEWAY %s %d (pid: %d) ***\n", ushared->gateways[i].name, ushared->gateways[i].num, ushared->gateways[i].pid);
|
||||
kill(ushared->gateways[i].pid, SIGKILL);
|
||||
}
|
||||
ushared->gateways_harakiri[i] = 0;
|
||||
|
||||
+9
-3
@@ -388,6 +388,12 @@ void uwsgi_reload(char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.alarm_thread) {
|
||||
if (i == uwsgi.alarm_thread->queue) continue;
|
||||
if (i == uwsgi.alarm_thread->pipe[0]) continue;
|
||||
if (i == uwsgi.alarm_thread->pipe[1]) continue;
|
||||
}
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (i == uwsgi.original_log_fd) {
|
||||
@@ -418,7 +424,7 @@ void uwsgi_reload(char **argv) {
|
||||
|
||||
#ifndef UWSGI_IPCSEM_ATEXIT
|
||||
// free ipc semaphores if in use
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
if (uwsgi.lock_engine && !strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
uwsgi_ipcsem_clear();
|
||||
}
|
||||
#endif
|
||||
@@ -692,9 +698,9 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
goto end;
|
||||
if (uwsgi_stats_keyval_comma(us, "cmd", ud->command))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) ud->pid))
|
||||
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) (ud->pid < 0) ? 0 : ud->pid))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) (ud->respawns - 1)))
|
||||
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) ud->respawns ? 0 : ud->respawns))
|
||||
goto end;
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
+20
-14
@@ -77,19 +77,8 @@ void uwsgi_mule(int id) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_run();
|
||||
|
||||
if (uwsgi.mules[id - 1].patch) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
@@ -98,6 +87,23 @@ void uwsgi_mule(int id) {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule_run() {
|
||||
int id = uwsgi.muleid;
|
||||
int i;
|
||||
if (uwsgi.mules[id - 1].patch) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
|
||||
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
|
||||
struct uwsgi_mule_farm *umf = farm->mules;
|
||||
@@ -441,7 +447,7 @@ void uwsgi_setup_mules_and_farms() {
|
||||
mules_list++;
|
||||
|
||||
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
|
||||
free(farm_value);
|
||||
|
||||
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
@@ -462,7 +468,7 @@ void uwsgi_setup_mules_and_farms() {
|
||||
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
|
||||
|
||||
farm_name = farm_name->next;
|
||||
|
||||
free(farm_value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+261
-61
@@ -45,9 +45,13 @@ struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, stru
|
||||
char *pass1 = data;
|
||||
size_t pass1_len = data_len;
|
||||
|
||||
if (ur->condition_ub[wsgi_req->async_id] && ur->ovn[wsgi_req->async_id] > 0) {
|
||||
pass1 = uwsgi_regexp_apply_ovec(ur->condition_ub[wsgi_req->async_id]->buf, ur->condition_ub[wsgi_req->async_id]->pos, data, data_len, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id]);
|
||||
pass1_len = strlen(pass1);
|
||||
}
|
||||
// cannot fail
|
||||
if (subject) {
|
||||
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector, ur->ovn);
|
||||
else if (subject) {
|
||||
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id]);
|
||||
pass1_len = strlen(pass1);
|
||||
}
|
||||
|
||||
@@ -146,10 +150,24 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
static void uwsgi_routing_reset_memory(struct wsgi_request *wsgi_req, struct uwsgi_route *routes) {
|
||||
// free dynamic memory structures
|
||||
if (routes->if_func) {
|
||||
routes->ovn[wsgi_req->async_id] = 0;
|
||||
if (routes->ovector[wsgi_req->async_id]) {
|
||||
free(routes->ovector[wsgi_req->async_id]);
|
||||
routes->ovector[wsgi_req->async_id] = NULL;
|
||||
}
|
||||
if (routes->condition_ub[wsgi_req->async_id]) {
|
||||
uwsgi_buffer_destroy(routes->condition_ub[wsgi_req->async_id]);
|
||||
routes->condition_ub[wsgi_req->async_id] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_do(struct uwsgi_route *routes, struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
void *goon_func = NULL;
|
||||
int n = -1;
|
||||
|
||||
char *orig_subject = subject;
|
||||
@@ -163,10 +181,6 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (goon_func && goon_func == routes->func) {
|
||||
goto next;
|
||||
}
|
||||
goon_func = NULL;
|
||||
wsgi_req->route_goto = 0;
|
||||
|
||||
if (!routes->if_func) {
|
||||
@@ -181,23 +195,26 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
|
||||
subject = *subject2 ;
|
||||
subject_len = *subject_len2;
|
||||
}
|
||||
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector, routes->ovn);
|
||||
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector[wsgi_req->async_id], routes->ovn[wsgi_req->async_id]);
|
||||
}
|
||||
else {
|
||||
int ret = routes->if_func(wsgi_req, routes);
|
||||
// error
|
||||
if (ret < 0) {
|
||||
uwsgi_routing_reset_memory(wsgi_req, routes);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
// true
|
||||
if (!routes->if_negate) {
|
||||
if (ret == 0) {
|
||||
uwsgi_routing_reset_memory(wsgi_req, routes);
|
||||
goto next;
|
||||
}
|
||||
n = ret;
|
||||
}
|
||||
else {
|
||||
if (ret > 0) {
|
||||
uwsgi_routing_reset_memory(wsgi_req, routes);
|
||||
goto next;
|
||||
}
|
||||
n = 1;
|
||||
@@ -208,6 +225,7 @@ run:
|
||||
if (n >= 0) {
|
||||
wsgi_req->is_routing = 1;
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
uwsgi_routing_reset_memory(wsgi_req, routes);
|
||||
wsgi_req->is_routing = 0;
|
||||
if (ret == UWSGI_ROUTE_BREAK) {
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
@@ -217,10 +235,6 @@ run:
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == UWSGI_ROUTE_GOON) {
|
||||
goon_func = routes->func;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
@@ -253,9 +267,22 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
|
||||
return uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
void uwsgi_apply_final_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (!uwsgi.final_routes) return;
|
||||
|
||||
// avoid loops
|
||||
if (wsgi_req->is_routing) return;
|
||||
|
||||
wsgi_req->is_final_routing = 1;
|
||||
|
||||
uwsgi_apply_routes_do(uwsgi.final_routes, wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static void *uwsgi_route_get_condition_func(char *name) {
|
||||
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
|
||||
while(urc) {
|
||||
@@ -271,7 +298,10 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *space = NULL;
|
||||
char *command = NULL;
|
||||
struct uwsgi_route *old_ur = NULL,*ur = uwsgi.routes;
|
||||
struct uwsgi_route *old_ur = NULL, *ur = uwsgi.routes;
|
||||
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
|
||||
ur = uwsgi.final_routes;
|
||||
}
|
||||
uint64_t pos = 0;
|
||||
while(ur) {
|
||||
old_ur = ur;
|
||||
@@ -283,7 +313,12 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
old_ur->next = ur;
|
||||
}
|
||||
else {
|
||||
uwsgi.routes = ur;
|
||||
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
|
||||
uwsgi.final_routes = ur;
|
||||
}
|
||||
else {
|
||||
uwsgi.routes = ur;
|
||||
}
|
||||
}
|
||||
|
||||
ur->pos = pos;
|
||||
@@ -295,14 +330,14 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *route = uwsgi_str(value);
|
||||
ur->orig_route = uwsgi_str(value);
|
||||
|
||||
if (!strcmp(foobar, "run")) {
|
||||
command = route;
|
||||
command = ur->orig_route;
|
||||
goto done;
|
||||
}
|
||||
|
||||
space = strchr(route, ' ');
|
||||
space = strchr(ur->orig_route, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid route syntax\n");
|
||||
exit(1);
|
||||
@@ -311,7 +346,7 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
*space = 0;
|
||||
|
||||
if (!strcmp(foobar, "if") || !strcmp(foobar, "if-not")) {
|
||||
char *colon = strchr(route, ':');
|
||||
char *colon = strchr(ur->orig_route, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid route condition syntax\n");
|
||||
exit(1);
|
||||
@@ -323,9 +358,9 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
}
|
||||
|
||||
foobar = colon+1;
|
||||
ur->if_func = uwsgi_route_get_condition_func(route);
|
||||
ur->if_func = uwsgi_route_get_condition_func(ur->orig_route);
|
||||
if (!ur->if_func) {
|
||||
uwsgi_log("unable to find \"%s\" route condition\n", route);
|
||||
uwsgi_log("unable to find \"%s\" route condition\n", ur->orig_route);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -365,18 +400,7 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
ur->subject_str = foobar;
|
||||
ur->subject_str_len = strlen(ur->subject_str);
|
||||
ur->regexp = route;
|
||||
|
||||
if (ur->subject && ur->subject_len) {
|
||||
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn > 0) {
|
||||
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
|
||||
}
|
||||
}
|
||||
ur->regexp = ur->orig_route;
|
||||
|
||||
command = space + 1;
|
||||
done:
|
||||
@@ -394,16 +418,6 @@ done:
|
||||
while (r) {
|
||||
if (!strcmp(r->name, command)) {
|
||||
if (r->func(ur, colon + 1) == 0) {
|
||||
// apply is_last
|
||||
struct uwsgi_route *last_ur = ur;
|
||||
ur = uwsgi.routes;
|
||||
while (ur) {
|
||||
if (ur->func == last_ur->func) {
|
||||
ur->is_last = 0;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
last_ur->is_last = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -415,6 +429,31 @@ done:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void uwsgi_fixup_routes(struct uwsgi_route *ur) {
|
||||
while(ur) {
|
||||
// prepare the main pointers
|
||||
ur->ovn = uwsgi_calloc(sizeof(int) * uwsgi.cores);
|
||||
ur->ovector = uwsgi_calloc(sizeof(int *) * uwsgi.cores);
|
||||
ur->condition_ub = uwsgi_calloc( sizeof(struct uwsgi_buffer *) * uwsgi.cores);
|
||||
|
||||
// fill them if needed... (this is an optimization for route with a static subject)
|
||||
if (ur->subject && ur->subject_len) {
|
||||
if (uwsgi_regexp_build(ur->orig_route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
ur->ovn[i] = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn[i] > 0) {
|
||||
ur->ovector[i] = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn[i] + 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args) {
|
||||
struct uwsgi_route *ur = NULL;
|
||||
struct uwsgi_router *r = uwsgi.routers;
|
||||
@@ -476,14 +515,49 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// goon route
|
||||
static int uwsgi_router_goon_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
return UWSGI_ROUTE_GOON;
|
||||
// flush response
|
||||
static int transform_flush(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
// avoid loops !!!
|
||||
if (ut->chunk->pos == 0) return 0;
|
||||
wsgi_req->transformed_chunk = ut->chunk->buf;
|
||||
wsgi_req->transformed_chunk_len = ut->chunk->pos;
|
||||
int ret = uwsgi_response_write_body_do(wsgi_req, ut->chunk->buf, ut->chunk->pos);
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
ut->flushed = 1;
|
||||
return ret;
|
||||
}
|
||||
static int uwsgi_router_goon(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_goon_func;
|
||||
static int uwsgi_router_flush_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_flush, NULL);
|
||||
ut->can_stream = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_flush(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_flush_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fix content length
|
||||
static int transform_fixcl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
// do not check for errors !!!
|
||||
uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_router_fixcl_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_add_transformation(wsgi_req, transform_fixcl, NULL);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_fixcl_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// log route
|
||||
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
@@ -506,6 +580,16 @@ static int uwsgi_router_log(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// do not log !!!
|
||||
static int uwsgi_router_donotlog_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->do_not_log = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_donotlog(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_donotlog_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// logvar route
|
||||
static int uwsgi_router_logvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
@@ -547,6 +631,9 @@ static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_ro
|
||||
|
||||
// find the label
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
if (wsgi_req->is_final_routing) {
|
||||
routes = uwsgi.final_routes;
|
||||
}
|
||||
while(routes) {
|
||||
if (!routes->label) goto next;
|
||||
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
|
||||
@@ -711,6 +798,62 @@ static int uwsgi_router_setapp(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// setscriptname route
|
||||
static int uwsgi_router_setscriptname_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
char *ptr = uwsgi_req_append(wsgi_req, "SCRIPT_NAME", 11, ub->buf, ub->pos);
|
||||
if (!ptr) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
wsgi_req->script_name = ptr;
|
||||
wsgi_req->script_name_len = ub->pos;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setscriptname(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setscriptname_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// setuser route
|
||||
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uint16_t user_len = ub->pos;
|
||||
// stop at the first colon (useful for various tricks)
|
||||
char *colon = memchr(ub->buf, ':', ub->pos);
|
||||
if (colon) {
|
||||
user_len = colon - ub->buf;
|
||||
}
|
||||
char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, ub->buf, user_len);
|
||||
if (!ptr) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
wsgi_req->remote_user = ptr;
|
||||
wsgi_req->remote_user_len = ub->pos;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setuser(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setuser_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// sethome route
|
||||
static int uwsgi_router_sethome_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
@@ -859,21 +1002,25 @@ static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uw
|
||||
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
|
||||
if (!semicolon) return 0;
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
|
||||
if (!ub) return -1;
|
||||
ur->condition_ub[wsgi_req->async_id] = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
|
||||
if (!ur->condition_ub[wsgi_req->async_id]) return -1;
|
||||
|
||||
pcre *pattern;
|
||||
pcre_extra *pattern_extra;
|
||||
char *re = uwsgi_concat2n(semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str), "", 0);
|
||||
if (uwsgi_regexp_build(re, &pattern, &pattern_extra)) {
|
||||
free(re);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
}
|
||||
free(re);
|
||||
|
||||
if (uwsgi_regexp_match(pattern, pattern_extra, ub->buf, ub->pos) >= 0) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
// a condition has no initialized vectors, let's create them
|
||||
ur->ovn[wsgi_req->async_id] = uwsgi_regexp_ovector(pattern, pattern_extra);
|
||||
if (ur->ovn[wsgi_req->async_id] > 0) {
|
||||
ur->ovector[wsgi_req->async_id] = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn[wsgi_req->async_id] + 1)));
|
||||
}
|
||||
|
||||
if (uwsgi_regexp_match_ovec(pattern, pattern_extra, ur->condition_ub[wsgi_req->async_id]->buf, ur->condition_ub[wsgi_req->async_id]->pos, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id] ) >= 0) {
|
||||
pcre_free(pattern);
|
||||
#ifdef PCRE_STUDY_JIT_COMPILE
|
||||
pcre_free_study(pattern_extra);
|
||||
@@ -883,7 +1030,6 @@ static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uw
|
||||
return 1;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
pcre_free(pattern);
|
||||
#ifdef PCRE_STUDY_JIT_COMPILE
|
||||
pcre_free_study(pattern_extra);
|
||||
@@ -1103,7 +1249,7 @@ static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ub2->pos < ub->pos) goto zero;
|
||||
if (ub2->pos > ub->pos) goto zero;
|
||||
if(!uwsgi_strncmp(ub->buf + (ub->pos - ub2->pos), ub2->pos, ub2->buf, ub2->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
@@ -1162,17 +1308,48 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
|
||||
ret = uwsgi_num2str(uwsgi.mypid);
|
||||
*vallen = strlen(ret);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) {
|
||||
ret = uwsgi_malloc(37);
|
||||
uwsgi_uuid(ret);
|
||||
*vallen = 36;
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "status", 6)) {
|
||||
ret = uwsgi_num2str(wsgi_req->status);
|
||||
*vallen = strlen(ret);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "rtime", 5)) {
|
||||
ret = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
|
||||
*vallen = strlen(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
size_t mime_type_len = 0;
|
||||
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
|
||||
if (ret) *vallen = mime_type_len;
|
||||
char *ret = NULL;
|
||||
uint16_t var_vallen = 0;
|
||||
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
|
||||
if (var_value) {
|
||||
size_t mime_type_len = 0;
|
||||
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
|
||||
if (ret) *vallen = mime_type_len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *uwsgi_route_var_httptime(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
// 30+1
|
||||
char *ht = uwsgi_calloc(31);
|
||||
size_t t = uwsgi_str_num(key, keylen);
|
||||
int len = uwsgi_http_date(uwsgi_now() + t, ht);
|
||||
if (len == 0) {
|
||||
free(ht);
|
||||
return NULL;
|
||||
}
|
||||
*vallen = len;
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
||||
static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
char *ret = NULL;
|
||||
@@ -1253,8 +1430,8 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("continue", uwsgi_router_continue);
|
||||
uwsgi_register_router("last", uwsgi_router_continue);
|
||||
uwsgi_register_router("break", uwsgi_router_break);
|
||||
uwsgi_register_router("goon", uwsgi_router_goon);
|
||||
uwsgi_register_router("log", uwsgi_router_log);
|
||||
uwsgi_register_router("donotlog", uwsgi_router_donotlog);
|
||||
uwsgi_register_router("logvar", uwsgi_router_logvar);
|
||||
uwsgi_register_router("goto", uwsgi_router_goto);
|
||||
uwsgi_register_router("addvar", uwsgi_router_addvar);
|
||||
@@ -1266,11 +1443,16 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
|
||||
uwsgi_register_router("chdir", uwsgi_router_chdir);
|
||||
uwsgi_register_router("setapp", uwsgi_router_setapp);
|
||||
uwsgi_register_router("setuser", uwsgi_router_setuser);
|
||||
uwsgi_register_router("sethome", uwsgi_router_sethome);
|
||||
uwsgi_register_router("setfile", uwsgi_router_setfile);
|
||||
uwsgi_register_router("setscriptname", uwsgi_router_setscriptname);
|
||||
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
|
||||
uwsgi_register_router("alarm", uwsgi_router_alarm);
|
||||
|
||||
uwsgi_register_router("flush", uwsgi_router_flush);
|
||||
uwsgi_register_router("fixcl", uwsgi_router_fixcl);
|
||||
|
||||
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
|
||||
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
|
||||
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
|
||||
@@ -1307,6 +1489,8 @@ void uwsgi_register_embedded_routers() {
|
||||
urv->need_free = 1;
|
||||
urv = uwsgi_register_route_var("time", uwsgi_route_var_time);
|
||||
urv->need_free = 1;
|
||||
urv = uwsgi_register_route_var("httptime", uwsgi_route_var_httptime);
|
||||
urv->need_free = 1;
|
||||
#ifdef UWSGI_MATHEVAL
|
||||
urv = uwsgi_register_route_var("math", uwsgi_route_var_math);
|
||||
urv->need_free = 1;
|
||||
@@ -1383,5 +1567,21 @@ void uwsgi_routing_dump() {
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal routing table ***\n");
|
||||
routes = uwsgi.final_routes;
|
||||
if (!routes) return;
|
||||
uwsgi_log("*** dumping internal final routing table ***\n");
|
||||
while(routes) {
|
||||
if (routes->label) {
|
||||
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
|
||||
}
|
||||
else if (!routes->subject_str && !routes->if_func) {
|
||||
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal final routing table ***\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
+69
-25
@@ -2,6 +2,10 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int connect_to_unix(char *, int, int);
|
||||
static int connect_to_tcp(char *, int, int, int);
|
||||
static int connect_to_udp(char *, int);
|
||||
|
||||
static int uwsgi_socket_strcmp(char *sock1, char *sock2) {
|
||||
size_t sock1_len = strlen(sock1);
|
||||
size_t sock2_len = strlen(sock2);
|
||||
@@ -312,36 +316,46 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_connect_do(char *socket_name, int timeout, int async) {
|
||||
char *tcp_port = strchr(socket_name, ':');
|
||||
|
||||
if (tcp_port) {
|
||||
tcp_port[0] = 0;
|
||||
tcp_port++;
|
||||
return connect_to_tcp(socket_name, atoi(tcp_port), timeout, async);
|
||||
}
|
||||
|
||||
return connect_to_unix(socket_name, timeout, async);
|
||||
}
|
||||
|
||||
int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) {
|
||||
|
||||
int fd;
|
||||
|
||||
char *zeroed_socket_name = uwsgi_concat2n(socket_name, len, "", 0);
|
||||
fd = uwsgi_connect(zeroed_socket_name, timeout, async);
|
||||
|
||||
int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async);
|
||||
free(zeroed_socket_name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int uwsgi_connect(char *socket_name, int timeout, int async) {
|
||||
|
||||
int ret;
|
||||
char *tcp_port = strchr(socket_name, ':');
|
||||
|
||||
if (tcp_port) {
|
||||
tcp_port[0] = 0;
|
||||
tcp_port++;
|
||||
ret = connect_to_tcp(socket_name, atoi(tcp_port), timeout, async);
|
||||
// reset the socket name
|
||||
tcp_port--;
|
||||
tcp_port[0] = ':';
|
||||
return ret;
|
||||
}
|
||||
|
||||
return connect_to_unix(socket_name, timeout, async);
|
||||
char *zeroed_socket_name = uwsgi_str(socket_name);
|
||||
int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async);
|
||||
free(zeroed_socket_name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int connect_to_unix(char *socket_name, int timeout, int async) {
|
||||
int uwsgi_connect_udp(char *socket_name) {
|
||||
int fd = -1;
|
||||
char *zeroed_socket_name = uwsgi_str(socket_name);
|
||||
char *udp_port = strchr(zeroed_socket_name, ':');
|
||||
if (!udp_port) goto end;
|
||||
*udp_port = 0;
|
||||
udp_port++;
|
||||
fd = connect_to_udp(zeroed_socket_name, atoi(udp_port));
|
||||
end:
|
||||
free(zeroed_socket_name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int connect_to_unix(char *socket_name, int timeout, int async) {
|
||||
|
||||
struct pollfd uwsgi_poll;
|
||||
struct sockaddr_un uws_addr;
|
||||
@@ -386,7 +400,7 @@ int connect_to_unix(char *socket_name, int timeout, int async) {
|
||||
|
||||
}
|
||||
|
||||
int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
|
||||
static int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
|
||||
|
||||
struct pollfd uwsgi_poll;
|
||||
struct sockaddr_in uws_addr;
|
||||
@@ -403,15 +417,13 @@ int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
|
||||
uws_addr.sin_addr.s_addr = inet_addr(socket_name);
|
||||
}
|
||||
|
||||
socket_name[strlen(socket_name)] = ':';
|
||||
|
||||
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
|
||||
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
#else
|
||||
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
#endif
|
||||
if (uwsgi_poll.fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_error("connect_to_tcp()/socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -427,6 +439,38 @@ int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
|
||||
|
||||
}
|
||||
|
||||
static int connect_to_udp(char *socket_name, int port) {
|
||||
|
||||
struct sockaddr_in uws_addr;
|
||||
memset(&uws_addr, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
uws_addr.sin_family = AF_INET;
|
||||
uws_addr.sin_port = htons(port);
|
||||
|
||||
if (socket_name[0] == 0) {
|
||||
uws_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
uws_addr.sin_addr.s_addr = inet_addr(socket_name);
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("connect_to_udp()/socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(fd, (const struct sockaddr *) &uws_addr, sizeof(struct sockaddr_in))) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *generate_socket_name(char *socket_name) {
|
||||
|
||||
char *asterisk = strchr(socket_name, '*');
|
||||
|
||||
+21
-15
@@ -122,21 +122,7 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->spooler_init) {
|
||||
uwsgi.p[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->spooler_init) {
|
||||
uwsgi.gp[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
spooler(uspool);
|
||||
uwsgi_spooler_run();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid);
|
||||
@@ -145,6 +131,26 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
|
||||
return pid;
|
||||
}
|
||||
|
||||
void uwsgi_spooler_run() {
|
||||
int i;
|
||||
struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler;
|
||||
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->spooler_init) {
|
||||
uwsgi.p[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->spooler_init) {
|
||||
uwsgi.gp[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
spooler(uspool);
|
||||
}
|
||||
|
||||
void destroy_spool(char *dir, char *file) {
|
||||
|
||||
if (chdir(dir)) {
|
||||
|
||||
+13
-2
@@ -1,5 +1,7 @@
|
||||
#include "../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
/*
|
||||
@@ -412,8 +414,9 @@ char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
|
||||
}
|
||||
|
||||
char *uwsgi_ssl_rand(size_t len) {
|
||||
unsigned char *buf = uwsgi_calloc(len+1);
|
||||
unsigned char *buf = uwsgi_calloc(len);
|
||||
if (RAND_bytes(buf, len) <= 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
return (char *) buf;
|
||||
@@ -427,6 +430,14 @@ char *uwsgi_sha1(char *src, size_t len, char *dst) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *uwsgi_md5(char *src, size_t len, char *dst) {
|
||||
MD5_CTX md5;
|
||||
MD5_Init(&md5);
|
||||
MD5_Update(&md5, src, len);
|
||||
MD5_Final((unsigned char *)dst, &md5);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
|
||||
+1
-1
@@ -644,7 +644,7 @@ safe:
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// before sending the file, we need to check if some rule applies
|
||||
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
||||
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->routes_applied = 1;
|
||||
|
||||
+115
-21
@@ -4,10 +4,11 @@
|
||||
|
||||
uWSGI transformations
|
||||
|
||||
responses can be buffered in the wsgi_request structure (instead of being sent to the client)
|
||||
Before closing the request, the transformations are applied in chain to the response buffer
|
||||
each body chunk is passed (in chain) to every transformation
|
||||
|
||||
Finally the resulting buffer is sent to the client
|
||||
some of them supports streaming, other requires buffering
|
||||
|
||||
at the end of the request the "final chain" is called (and the whole chain freed)
|
||||
|
||||
Transformations (if required) could completely swallow already set headers
|
||||
|
||||
@@ -15,33 +16,128 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req) {
|
||||
int ret = 0;
|
||||
// -1 error, 0 = no buffer, send the body, 1 = buffer
|
||||
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
struct uwsgi_transformation *ut = wsgi_req->transformations;
|
||||
char *t_buf = buf;
|
||||
size_t t_len = len;
|
||||
uint8_t flushed = 0;
|
||||
while(ut) {
|
||||
struct uwsgi_buffer *new_ub = NULL;
|
||||
if (ut->func(wsgi_req, wsgi_req->response_buffer, &new_ub, ut->data)) {
|
||||
ret = -1;
|
||||
goto end;
|
||||
// allocate the buffer (if needed)
|
||||
if (!ut->chunk) {
|
||||
ut->chunk = uwsgi_buffer_new(t_len);
|
||||
}
|
||||
if (new_ub) {
|
||||
uwsgi_buffer_destroy(wsgi_req->response_buffer);
|
||||
wsgi_req->response_buffer = new_ub;
|
||||
// skip final transformations before appending data
|
||||
if (ut->is_final) goto next;
|
||||
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the transformation cannot stream, continue buffering (the func will be called at the end)
|
||||
if (!ut->can_stream) return 1;
|
||||
|
||||
ut->round++;
|
||||
if (ut->func(wsgi_req, ut)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ut->flushed) flushed = 1;
|
||||
|
||||
t_buf = ut->chunk->buf;
|
||||
t_len = ut->chunk->pos;
|
||||
// we reset the buffer, so we do not waste memory
|
||||
ut->chunk->pos = 0;
|
||||
next:
|
||||
ut = ut->next;
|
||||
}
|
||||
|
||||
end:
|
||||
ut = wsgi_req->transformations;
|
||||
// if we are here we can tell the writer to send the body to the client
|
||||
// no buffering please
|
||||
if (!flushed) {
|
||||
wsgi_req->transformed_chunk = t_buf;
|
||||
wsgi_req->transformed_chunk_len = t_len;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
run all the remaining (or buffered) transformations
|
||||
|
||||
*/
|
||||
int uwsgi_apply_final_transformations(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_transformation *ut = wsgi_req->transformations;
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
char *t_buf = NULL;
|
||||
size_t t_len = 0;
|
||||
uint8_t flushed = 0;
|
||||
int found_nostream = 0;
|
||||
while(ut) {
|
||||
if (!found_nostream) {
|
||||
if (!ut->can_stream) {
|
||||
found_nostream = 1;
|
||||
}
|
||||
else {
|
||||
t_buf = ut->chunk->buf;
|
||||
t_len = ut->chunk->pos;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ut->chunk) {
|
||||
if (t_len > 0) {
|
||||
ut->chunk = uwsgi_buffer_new(t_len);
|
||||
}
|
||||
else {
|
||||
ut->chunk = uwsgi_buffer_new(uwsgi.page_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (t_len > 0) {
|
||||
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// run the transformation
|
||||
ut->round++;
|
||||
if (ut->func(wsgi_req, ut)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ut->flushed) flushed = 1;
|
||||
|
||||
t_buf = ut->chunk->buf;
|
||||
t_len = ut->chunk->pos;
|
||||
next:
|
||||
ut = ut->next;
|
||||
}
|
||||
|
||||
// if we are here, all of the transformations are applied
|
||||
if (!flushed) {
|
||||
wsgi_req->transformed_chunk = t_buf;
|
||||
wsgi_req->transformed_chunk_len = t_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_free_transformations(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_transformation *ut = wsgi_req->transformations;
|
||||
while(ut) {
|
||||
struct uwsgi_transformation *current_ut = ut;
|
||||
if (current_ut->chunk) {
|
||||
uwsgi_buffer_destroy(current_ut->chunk);
|
||||
}
|
||||
ut = ut->next;
|
||||
free(current_ut);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_buffer *, struct uwsgi_buffer **, void *), void *data) {
|
||||
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *data) {
|
||||
struct uwsgi_transformation *old_ut = NULL, *ut = wsgi_req->transformations;
|
||||
while(ut) {
|
||||
old_ut = ut;
|
||||
@@ -50,7 +146,10 @@ struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_
|
||||
|
||||
ut = uwsgi_malloc(sizeof(struct uwsgi_transformation));
|
||||
ut->func = func;
|
||||
ut->is_final = 0;
|
||||
ut->next = NULL;
|
||||
ut->chunk = NULL;
|
||||
ut->can_stream = 0;
|
||||
ut->data = data;
|
||||
|
||||
if (old_ut) {
|
||||
@@ -60,10 +159,5 @@ struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_
|
||||
wsgi_req->transformations = ut;
|
||||
}
|
||||
|
||||
// start buffering
|
||||
if (!wsgi_req->response_buffer) {
|
||||
wsgi_req->response_buffer = uwsgi_buffer_new(uwsgi.page_size);
|
||||
}
|
||||
|
||||
return ut;
|
||||
}
|
||||
|
||||
+92
-41
@@ -574,21 +574,14 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
int tmp_id;
|
||||
uint64_t tmp_rt, rss = 0, vsz = 0;
|
||||
|
||||
// flush the response buf (if any)
|
||||
if (wsgi_req->response_buffer) {
|
||||
// send the body only if transformations are successfull
|
||||
struct uwsgi_buffer *ub = wsgi_req->response_buffer;
|
||||
if (uwsgi_apply_transformations(wsgi_req) == 0) {
|
||||
// the response_buffer could be changed by translations
|
||||
ub = wsgi_req->response_buffer;
|
||||
// force true write
|
||||
wsgi_req->response_buffer = NULL;
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
// apply transformations
|
||||
if (wsgi_req->transformations) {
|
||||
if (uwsgi_apply_final_transformations(wsgi_req) == 0) {
|
||||
if (wsgi_req->transformed_chunk && wsgi_req->transformed_chunk_len > 0) {
|
||||
uwsgi_response_write_body_do(wsgi_req, wsgi_req->transformed_chunk, wsgi_req->transformed_chunk_len);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsgi_req->write_errors++;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_free_transformations(wsgi_req);
|
||||
}
|
||||
|
||||
// check if headers should be sent
|
||||
@@ -614,6 +607,20 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = rss;
|
||||
}
|
||||
|
||||
if (!wsgi_req->do_not_account) {
|
||||
uwsgi.workers[0].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
|
||||
// this is used for MAX_REQUESTS
|
||||
uwsgi.workers[uwsgi.mywid].delta_requests++;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply final routes after accounting
|
||||
uwsgi_apply_final_routes(wsgi_req);
|
||||
#endif
|
||||
|
||||
// close the connection with the client
|
||||
if (!wsgi_req->fd_closed) {
|
||||
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
|
||||
@@ -636,15 +643,6 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
}
|
||||
|
||||
if (!wsgi_req->do_not_account) {
|
||||
uwsgi.workers[0].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
|
||||
// this is used for MAX_REQUESTS
|
||||
uwsgi.workers[uwsgi.mywid].delta_requests++;
|
||||
}
|
||||
|
||||
// after_request hook
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->after_request)
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->after_request(wsgi_req);
|
||||
@@ -664,12 +662,14 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
set_user_harakiri(0);
|
||||
}
|
||||
|
||||
// this is racy in multithread mode
|
||||
if (wsgi_req->response_size > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->response_size;
|
||||
}
|
||||
if (wsgi_req->headers_size > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->headers_size;
|
||||
if (!wsgi_req->do_not_account) {
|
||||
// this is racy in multithread mode
|
||||
if (wsgi_req->response_size > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->response_size;
|
||||
}
|
||||
if (wsgi_req->headers_size > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->headers_size;
|
||||
}
|
||||
}
|
||||
|
||||
// defunct process reaper
|
||||
@@ -1808,18 +1808,21 @@ void init_magic_table(char *magic_table[]) {
|
||||
}
|
||||
|
||||
char *uwsgi_get_last_char(char *what, char c) {
|
||||
int i;
|
||||
char *ptr = NULL;
|
||||
|
||||
for (i = 0; i < (int) strlen(what); i++) {
|
||||
if (what[i] == c) {
|
||||
ptr = what + i;
|
||||
}
|
||||
size_t len = strlen(what);
|
||||
while(len--) {
|
||||
if (what[len] == c) return what + len;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *uwsgi_get_last_charn(char *what, size_t len, char c) {
|
||||
while(len--) {
|
||||
if (what[len] == c) return what + len;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_num2str(int num) {
|
||||
|
||||
char *str = uwsgi_malloc(11);
|
||||
@@ -1828,6 +1831,12 @@ char *uwsgi_num2str(int num) {
|
||||
return str;
|
||||
}
|
||||
|
||||
char *uwsgi_64bit2str(int64_t num) {
|
||||
char *str = uwsgi_malloc(sizeof(MAX64_STR)+1);
|
||||
snprintf(str, sizeof(MAX64_STR)+1, "%lld", (long long) num);
|
||||
return str;
|
||||
}
|
||||
|
||||
int uwsgi_num2str2(int num, char *ptr) {
|
||||
|
||||
return snprintf(ptr, 11, "%d", num);
|
||||
@@ -2221,6 +2230,7 @@ struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **list,
|
||||
uwsgi_string->next = NULL;
|
||||
uwsgi_string->custom = 0;
|
||||
uwsgi_string->custom2 = 0;
|
||||
uwsgi_string->custom_ptr = NULL;
|
||||
|
||||
return uwsgi_string;
|
||||
}
|
||||
@@ -3098,6 +3108,7 @@ void http_url_decode(char *buf, uint16_t * len, char *dst) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
we scan the table in reverse, as updated values are at the end
|
||||
*/
|
||||
@@ -3141,6 +3152,10 @@ struct uwsgi_app *uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int
|
||||
}
|
||||
}
|
||||
|
||||
if ((mountpoint_len == 0 || (mountpoint_len =- 1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
|
||||
uwsgi.default_app = id;
|
||||
}
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
@@ -3160,7 +3175,7 @@ char *uwsgi_check_touches(struct uwsgi_string_list *touch_list) {
|
||||
uwsgi_log("[uwsgi-check-touches] File %s was removed\n", touch->value);
|
||||
#endif
|
||||
touch->custom2 = 1;
|
||||
return touch->value;
|
||||
return touch->custom_ptr ? touch->custom_ptr : touch->value;
|
||||
}
|
||||
else if (!touch->custom && !touch->custom2) {
|
||||
uwsgi_log("unable to stat() %s, events will be triggered as soon as the file is created\n", touch->value);
|
||||
@@ -3175,14 +3190,14 @@ char *uwsgi_check_touches(struct uwsgi_string_list *touch_list) {
|
||||
#endif
|
||||
touch->custom = (uint64_t) tr_st.st_mtime;
|
||||
touch->custom2 = 0;
|
||||
return touch->value;
|
||||
return touch->custom_ptr ? touch->custom_ptr : touch->value;
|
||||
}
|
||||
else if (touch->custom && (uint64_t) tr_st.st_mtime > touch->custom) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-check-touches] modification detected on %s: %llu -> %llu\n", touch->value, (unsigned long long) touch->custom, (unsigned long long) tr_st.st_mtime);
|
||||
#endif
|
||||
touch->custom = (uint64_t) tr_st.st_mtime;
|
||||
return touch->value;
|
||||
return touch->custom_ptr ? touch->custom_ptr : touch->value;
|
||||
}
|
||||
touch->custom = (uint64_t) tr_st.st_mtime;
|
||||
}
|
||||
@@ -3905,3 +3920,39 @@ char *uwsgi_str_to_hex(char *src, size_t slen) {
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
// dst has to be 3 times buf size (USE IT ONLY FOR PATH_INFO !!!)
|
||||
void http_url_encode(char *buf, uint16_t *len, char *dst) {
|
||||
|
||||
uint16_t i;
|
||||
char *ptr = dst;
|
||||
for(i=0;i<*len;i++) {
|
||||
if ((buf[i] >= 'A' && buf[i] <= 'Z') ||
|
||||
(buf[i] >= 'a' && buf[i] <= 'z') ||
|
||||
(buf[i] >= '0' && buf[i] <= '9') ||
|
||||
buf[i] == '-' || buf[i] == '_' || buf[i] == '.' || buf[i] == '~' || buf[i] == '/' ) {
|
||||
*ptr++= buf[i];
|
||||
}
|
||||
else {
|
||||
char *h = uwsgi_hex_table[(int) buf[i]];
|
||||
*ptr++= '%';
|
||||
*ptr++= h[0];
|
||||
*ptr++= h[1];
|
||||
}
|
||||
}
|
||||
|
||||
*len = ptr-dst;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_takeover() {
|
||||
if (uwsgi.i_am_a_spooler) {
|
||||
uwsgi_spooler_run();
|
||||
}
|
||||
else if (uwsgi.muleid) {
|
||||
uwsgi_mule_run();
|
||||
}
|
||||
else {
|
||||
uwsgi_worker_run();
|
||||
}
|
||||
}
|
||||
|
||||
+54
-16
@@ -65,7 +65,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
|
||||
{"no-harakiri-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
|
||||
{"no-harakiri-after-req-hook", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
|
||||
{"backtrace-depth", no_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
|
||||
{"backtrace-depth", required_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
|
||||
{"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MULE_HARAKIRI, 0},
|
||||
#ifdef UWSGI_XML
|
||||
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
@@ -344,6 +344,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"touch-chain-reload", required_argument, 0, "trigger chain reload if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_chain_reload, UWSGI_OPT_MASTER},
|
||||
{"touch-logrotate", required_argument, 0, "trigger logrotation if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logrotate, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
{"touch-logreopen", required_argument, 0, "trigger log reopen if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logreopen, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
{"touch-exec", required_argument, 0, "run command when the specified file is modified/touched (syntax: file command)", uwsgi_opt_add_string_list, &uwsgi.touch_exec, UWSGI_OPT_MASTER},
|
||||
{"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal mamagement", uwsgi_opt_true, &uwsgi.propagate_touch, 0},
|
||||
{"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0},
|
||||
{"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0},
|
||||
@@ -457,6 +458,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
|
||||
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
|
||||
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
|
||||
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
|
||||
{"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
|
||||
#ifdef UWSGI_PCRE
|
||||
{"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
{"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
@@ -528,6 +531,22 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0},
|
||||
{"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
|
||||
{"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0},
|
||||
|
||||
|
||||
|
||||
{"final-route", required_argument, 0, "add a final route", uwsgi_opt_add_route, "path_info", 0},
|
||||
{"final-route-host", required_argument, 0, "add a final route based on Host header", uwsgi_opt_add_route, "http_host", 0},
|
||||
{"final-route-uri", required_argument, 0, "add a final route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
|
||||
{"final-route-qs", required_argument, 0, "add a final route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
|
||||
{"final-route-remote-addr", required_argument, 0, "add a final route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
|
||||
{"final-route-user-agent", required_argument, 0, "add a final route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
|
||||
{"final-route-remote-user", required_argument, 0, "add a final route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
|
||||
{"final-route-referer", required_argument, 0, "add a final route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
|
||||
{"final-route-label", required_argument, 0, "add a final routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
|
||||
{"final-route-if", required_argument, 0, "add a final route based on condition", uwsgi_opt_add_route, "if", 0},
|
||||
{"final-route-if-not", required_argument, 0, "add a final route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
|
||||
{"final-route-run", required_argument, 0, "always run the specified final route action", uwsgi_opt_add_route, "run", 0},
|
||||
|
||||
{"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
|
||||
{"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
|
||||
#endif
|
||||
@@ -628,6 +647,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
#ifdef UWSGI_SSL
|
||||
{"legion-attach-daemon", required_argument, 0, "same as --attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"legion-smart-attach-daemon", required_argument, 0, "same as --smart-attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"legion-smart-attach-daemon2", required_argument, 0, "same as --smart-attach-daemon2 but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
#endif
|
||||
{"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
|
||||
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
@@ -1447,15 +1471,28 @@ void uwsgi_backtrace(int depth) {
|
||||
|
||||
bt_strings = backtrace_symbols(btrace, bt_size);
|
||||
|
||||
uwsgi_log("*** backtrace of %d ***\n", (int) getpid());
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
uwsgi_buffer_append(ub, "*** backtrace of ",17);
|
||||
uwsgi_buffer_num64(ub, (int64_t) getpid());
|
||||
uwsgi_buffer_append(ub, " ***\n", 5);
|
||||
for (i = 0; i < bt_size; i++) {
|
||||
uwsgi_log("%s\n", bt_strings[i]);
|
||||
uwsgi_buffer_append(ub, bt_strings[i], strlen(bt_strings[i]));
|
||||
uwsgi_buffer_append(ub, "\n", 1);
|
||||
}
|
||||
|
||||
free(btrace);
|
||||
uwsgi_log("*** end of backtrace ***\n");
|
||||
|
||||
uwsgi_buffer_append(ub, "*** end of backtrace ***\n", 25);
|
||||
|
||||
uwsgi_log("%.*s", ub->pos, ub->buf);
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.alarm_segfault;
|
||||
while(usl) {
|
||||
uwsgi_alarm_trigger(usl->value, ub->buf, ub->pos);
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -2202,18 +2239,9 @@ int uwsgi_start(void *v_argv) {
|
||||
}
|
||||
}
|
||||
uwsgi_log("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
|
||||
uwsgi.async_waiting_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
if (!uwsgi.async_waiting_fd_table) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
memset(uwsgi.async_waiting_fd_table, 0, sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
uwsgi.async_proto_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
if (!uwsgi.async_proto_fd_table) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
memset(uwsgi.async_proto_fd_table, 0, sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
// optimization, this array maps file descriptor to requests
|
||||
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
@@ -2778,6 +2806,16 @@ next2:
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_worker_run();
|
||||
// never here
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_worker_run() {
|
||||
|
||||
int i;
|
||||
|
||||
if (uwsgi.lazy || uwsgi.lazy_apps) {
|
||||
uwsgi_init_all_apps();
|
||||
}
|
||||
|
||||
+68
-24
@@ -23,6 +23,28 @@ int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) {
|
||||
return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) {
|
||||
// 30+1
|
||||
char d[31];
|
||||
int len = uwsgi_http_date((time_t) t, d);
|
||||
if (!len) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) {
|
||||
// 30+1
|
||||
char lm[31];
|
||||
int len = uwsgi_http_date((time_t) t, lm);
|
||||
if (!len) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
|
||||
char buf[6+(sizeof(UMAX64_STR)*3)+4];
|
||||
if (end == 0) {
|
||||
@@ -86,6 +108,24 @@ error:
|
||||
}
|
||||
|
||||
//each protocol has its header generator
|
||||
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
|
||||
if (!hh) { wsgi_req->write_errors++ ; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
wsgi_req->header_cnt++;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
|
||||
@@ -105,21 +145,14 @@ int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t
|
||||
rh = rh->next;
|
||||
}
|
||||
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
|
||||
if (!hh) { wsgi_req->write_errors++ ; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
wsgi_req->header_cnt++;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
int uwsgi_response_add_header_force(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
|
||||
|
||||
return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
|
||||
}
|
||||
|
||||
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
|
||||
@@ -176,8 +209,27 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
|
||||
// do not commit headers until a response_buffer is available
|
||||
if (!wsgi_req->response_buffer && !wsgi_req->headers_sent) {
|
||||
// if the transformation chain returns 1, we are in buffering mode
|
||||
if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
|
||||
int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
|
||||
if (t_ret == 0) {
|
||||
buf = wsgi_req->transformed_chunk;
|
||||
len = wsgi_req->transformed_chunk_len;
|
||||
// reset transformation
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
goto write;
|
||||
}
|
||||
if (t_ret == 1) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
write:
|
||||
// send headers if not already sent
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendbody;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
@@ -189,14 +241,6 @@ sendbody:
|
||||
|
||||
if (len == 0) return UWSGI_OK;
|
||||
|
||||
if (wsgi_req->response_buffer) {
|
||||
if (uwsgi_buffer_append(wsgi_req->response_buffer, buf, len)) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
|
||||
if (ret < 0) {
|
||||
|
||||
+29
-1
@@ -1,6 +1,11 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
|
||||
char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
|
||||
|
||||
char *uwsgi_gzip_chunk(z_stream *z, uint32_t *crc32, char *buf, size_t len, size_t *dlen) {
|
||||
uwsgi_crc32(crc32, buf, len);
|
||||
return uwsgi_deflate(z, buf, len, dlen);
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_gzip(char *buf, size_t len) {
|
||||
z_stream z;
|
||||
@@ -49,6 +54,29 @@ int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_gzip_prepare(z_stream *z, char *dict, size_t dict_len, uint32_t *crc32) {
|
||||
uwsgi_crc32(crc32, NULL, 0);
|
||||
if (uwsgi_deflate_init(z, NULL, 0)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fix and free a gzip stream
|
||||
int uwsgi_gzip_fix(z_stream *z, uint32_t crc32, struct uwsgi_buffer *ub, size_t len) {
|
||||
size_t dlen0 = 0;
|
||||
char *gzipped0 = uwsgi_deflate(z, NULL, 0, &dlen0);
|
||||
if (!gzipped0) goto end;
|
||||
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
|
||||
free(gzipped0);
|
||||
if (uwsgi_buffer_u32le(ub, crc32)) goto end;
|
||||
if (uwsgi_buffer_u32le(ub, len)) goto end;
|
||||
deflateEnd(z);
|
||||
return 0;
|
||||
end:
|
||||
if (gzipped0) free(gzipped0);
|
||||
deflateEnd(z);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
|
||||
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
#include <uwsgi.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_airbrake_config {
|
||||
int first;
|
||||
char *arg;
|
||||
char *apikey;
|
||||
char *env;
|
||||
};
|
||||
|
||||
struct uwsgi_airbrake_opt {
|
||||
char *name;
|
||||
CURLoption option;
|
||||
void (*func)(CURL *, CURLoption, char *, struct uwsgi_airbrake_config*);
|
||||
};
|
||||
|
||||
static void uwsgi_airbrake_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
|
||||
curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL);
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_int(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
|
||||
curl_easy_setopt(curl, option, atoi(arg));
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
|
||||
uacc->apikey = arg;
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_set_env(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
|
||||
uacc->env = arg;
|
||||
}
|
||||
|
||||
static struct uwsgi_airbrake_opt uaco[] = {
|
||||
{"url", CURLOPT_URL, NULL},
|
||||
{"apikey", 0, uwsgi_airbrake_set_apikey},
|
||||
{"env", 0, uwsgi_airbrake_set_env},
|
||||
{"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl},
|
||||
{"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int},
|
||||
{"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int},
|
||||
{NULL, 0, NULL},
|
||||
};
|
||||
|
||||
static void uwsgi_airbrake_setopt(CURL *curl, char *opt, struct uwsgi_airbrake_config *uacc) {
|
||||
struct uwsgi_airbrake_opt *o = uaco;
|
||||
char *equal = strchr(opt,'=');
|
||||
if (!equal) {
|
||||
if (!uacc->first) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, opt);
|
||||
uacc->first = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
uacc->first = 1;
|
||||
*equal = 0;
|
||||
while(o->name) {
|
||||
if (!strcmp(o->name, opt)) {
|
||||
if (o->func) {
|
||||
o->func(curl, o->option, equal+1, uacc);
|
||||
}
|
||||
else {
|
||||
curl_easy_setopt(curl, o->option, equal+1);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
o++;
|
||||
}
|
||||
end:
|
||||
*equal = '=';
|
||||
}
|
||||
|
||||
char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) {
|
||||
|
||||
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
|
||||
|
||||
xmlChar *xmlbuff;
|
||||
int buffersize;
|
||||
xmlDocPtr doc = NULL;
|
||||
xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL;
|
||||
char *msg = NULL;
|
||||
|
||||
doc = xmlNewDoc(BAD_CAST "1.0");
|
||||
notice_node = xmlNewNode(NULL, BAD_CAST "notice");
|
||||
xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3");
|
||||
xmlDocSetRootElement(doc, notice_node);
|
||||
|
||||
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey);
|
||||
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL);
|
||||
xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI");
|
||||
xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION);
|
||||
xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi");
|
||||
|
||||
// request env
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL);
|
||||
node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL);
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version");
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version");
|
||||
|
||||
struct utsname uuts;
|
||||
#ifdef __sun__
|
||||
if (uname(&uuts) < 0) {
|
||||
#else
|
||||
if (uname(&uuts)) {
|
||||
#endif
|
||||
uwsgi_error("uname()");
|
||||
}
|
||||
else {
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname");
|
||||
|
||||
char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version);
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version");
|
||||
free(os_version);
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine");
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename");
|
||||
|
||||
}
|
||||
// end request env
|
||||
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
|
||||
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
|
||||
if (uacc->env) {
|
||||
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env);
|
||||
}
|
||||
else {
|
||||
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
|
||||
}
|
||||
|
||||
errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL);
|
||||
xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError");
|
||||
node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL);
|
||||
|
||||
char *ctx = NULL;
|
||||
char *text = uwsgi_str(ut->buf);
|
||||
char *p = strtok_r(text, "\n", &ctx);
|
||||
while (p) {
|
||||
// skip log messages
|
||||
if (!uwsgi_startswith(p, "***", 3))
|
||||
goto next;
|
||||
// backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555]
|
||||
// we take binary/lib as filename
|
||||
// and extract method name from remaining string
|
||||
char *n = strchr(p, '(');
|
||||
if (n) {
|
||||
*n = 0;
|
||||
|
||||
char *pls = strchr(n+1, '+');
|
||||
if (pls) {
|
||||
*pls = 0;
|
||||
}
|
||||
|
||||
if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) {
|
||||
goto next;
|
||||
}
|
||||
else if (!strcmp("uwsgi_fpe", n+1)) {
|
||||
msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!msg) {
|
||||
if (strlen(n+1)) {
|
||||
msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p);
|
||||
}
|
||||
else {
|
||||
// method name might be missing
|
||||
msg = uwsgi_concat2("uWSGI segfault in ", p);
|
||||
}
|
||||
}
|
||||
|
||||
// skip empty lines
|
||||
if (!p)
|
||||
goto next;
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
|
||||
|
||||
if ((n+1)[0] == ')') {
|
||||
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()");
|
||||
}
|
||||
else {
|
||||
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST n+1);
|
||||
}
|
||||
|
||||
xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p);
|
||||
|
||||
//xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
|
||||
}
|
||||
next:
|
||||
p = strtok_r(NULL, "\n", &ctx);
|
||||
}
|
||||
|
||||
xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg);
|
||||
|
||||
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
xmlCleanupParser();
|
||||
xmlMemoryDump();
|
||||
free(msg);
|
||||
free(text);
|
||||
|
||||
return (char *) xmlbuff;
|
||||
}
|
||||
|
||||
|
||||
static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
|
||||
int interesting_fd;
|
||||
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
// ARGH !!!
|
||||
if (!curl) return;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
|
||||
|
||||
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
|
||||
char *opts = uwsgi_str(uacc->arg);
|
||||
|
||||
// fill curl options
|
||||
char *ctx = NULL;
|
||||
char *p = strtok_r(opts, ";", &ctx);
|
||||
while(p) {
|
||||
uwsgi_airbrake_setopt(curl, uwsgi_str(p), uacc);
|
||||
p = strtok_r(NULL, ";", &ctx);
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret < 0) return;
|
||||
if (ret == 0) continue;
|
||||
if (interesting_fd != ut->pipe[1]) continue;
|
||||
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
|
||||
if (rlen <= 0) continue;
|
||||
ut->pos = 0;
|
||||
ut->len = (size_t) rlen;
|
||||
ut->custom0 = 0;
|
||||
|
||||
char *notice = uwsgi_format_airbrake_backtrace(ut);
|
||||
|
||||
curl_slist_append(expect, "Accept: */*");
|
||||
curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice));
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
}
|
||||
free(notice);
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) {
|
||||
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_airbrake_loop);
|
||||
if (!ut) return;
|
||||
uai->data_ptr = ut;
|
||||
struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config));
|
||||
uacc->arg = uai->arg;
|
||||
ut->data = uacc;
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
|
||||
ut->rlen = write(ut->pipe[0], msg, len);
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_load(void) {
|
||||
uwsgi_register_alarm("airbrake", uwsgi_airbrake_init, uwsgi_airbrake_func);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin airbrake_plugin = {
|
||||
.name = "airbrake",
|
||||
.on_load = uwsgi_airbrake_load,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from uwsgiconfig import spcall
|
||||
|
||||
NAME='airbrake'
|
||||
|
||||
CFLAGS = [spcall('xml2-config --cflags')]
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lcurl', spcall('xml2-config --libs')]
|
||||
GCC_LIST = ['airbrake_plugin']
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -168,7 +168,8 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
|
||||
|
||||
for(;;) {
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret <= 0) continue;
|
||||
if (ret < 0) return;
|
||||
if (ret == 0) continue;
|
||||
if (interesting_fd != ut->pipe[1]) continue;
|
||||
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
|
||||
if (rlen <= 0) continue;
|
||||
|
||||
@@ -293,18 +293,17 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (peer->failed) {
|
||||
|
||||
if (peer->soopt) {
|
||||
if (!ucr->quiet)
|
||||
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\": %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, strerror(peer->soopt));
|
||||
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt));
|
||||
}
|
||||
else if (peer->timed_out) {
|
||||
if (peer->instance_address_len > 0) {
|
||||
if (peer->connecting) {
|
||||
if (!ucr->quiet)
|
||||
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\": timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address);
|
||||
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,9 +154,14 @@ XS(XS_coroae_accept_request) {
|
||||
|
||||
request:
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
|
||||
if (wsgi_req->async_status <= UWSGI_OK) {
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req)) {
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->switches++;
|
||||
|
||||
+19
-7
@@ -16,8 +16,7 @@ struct uwsgi_option fiber_options[] = {
|
||||
|
||||
|
||||
VALUE uwsgi_fiber_request() {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
async_schedule_to_req_green();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
@@ -32,30 +31,43 @@ VALUE rb_fiber_schedule_to_req() {
|
||||
|
||||
rb_fiber_resume(ufiber.fib[id], 0, NULL);
|
||||
|
||||
if (uwsgi.wsgi_req->suspended) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static void fiber_schedule_to_req() {
|
||||
|
||||
int id = uwsgi.wsgi_req->async_id;
|
||||
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
|
||||
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->suspend) {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
int error = 0;
|
||||
rb_protect(rb_fiber_schedule_to_req, 0, &error);
|
||||
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
rack_plugin.exception_log(NULL);
|
||||
rb_gc_unregister_address(&ufiber.fib[id]);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
rb_fiber_yield(0, NULL);
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
}
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
Soon before official Go 1.1, we understand supporting Go in a fork() heavy
|
||||
environment was not blessed by the Go community.
|
||||
|
||||
Instead of completely dropping support for Go, we studied how the gccgo project works and we
|
||||
decided it was a better approach for uWSGI.
|
||||
|
||||
This new plugin works by initializing a new "go runtime" after each fork().
|
||||
|
||||
The runtime calls the Go main function (developed by the user), and pass the whole
|
||||
uWSGI control to it.
|
||||
|
||||
the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically
|
||||
manages mules, spoolers and workers)
|
||||
|
||||
As well as before each core maps to a goroutine mapped to a real pthread. (goroutines called
|
||||
from your apps are native goroutines)
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_plugin gccgo_plugin;
|
||||
|
||||
struct uwsgi_gccgo{
|
||||
struct uwsgi_string_list *libs;
|
||||
char *args;
|
||||
} ugccgo;
|
||||
|
||||
/*
|
||||
static void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
|
||||
// set async mode
|
||||
uwsgi_opt_set_int(opt, value, &uwsgi.async);
|
||||
// set loop engine
|
||||
uwsgi.loop = "goroutines";
|
||||
}
|
||||
*/
|
||||
|
||||
struct uwsgi_option uwsgi_gccgo_options[] = {
|
||||
{"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
|
||||
{"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
|
||||
{"go-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
|
||||
{"gccgo-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
|
||||
// {"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
// no_split_stack is the key to avoid crashing !!!
|
||||
void* runtime_m(void) __attribute__ ((noinline, no_split_stack));
|
||||
|
||||
void runtime_check(void);
|
||||
void runtime_args(int, char **);
|
||||
void runtime_osinit(void);
|
||||
void runtime_schedinit(void);
|
||||
void *__go_go(void *, void *);
|
||||
void runtime_main(void);
|
||||
void runtime_mstart(void *);
|
||||
|
||||
extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler");
|
||||
extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env");
|
||||
extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd");
|
||||
extern void uwsgigo_run_core(int) __asm__ ("go.uwsgi.RunCore");
|
||||
extern void uwsgigo_signal_handler(void *, uint8_t) __asm__ ("go.uwsgi.SignalHandler");
|
||||
//extern void uwsgigo_loop(void) __asm__ ("go.uwsgi.Loop");
|
||||
|
||||
static void mainstart(void *arg __attribute__((unused))) {
|
||||
runtime_main();
|
||||
}
|
||||
|
||||
void uwsgigo_main_main(void) __asm__ ("main.main");
|
||||
void uwsgigo_main_init(void) __asm__ ("__go_init_main");
|
||||
|
||||
void (*uwsgigo_hook_init)(void);
|
||||
void (*uwsgigo_hook_main)(void);
|
||||
|
||||
void uwsgigo_main_init(void) {
|
||||
uwsgigo_hook_init();
|
||||
}
|
||||
|
||||
void uwsgigo_main_main(void) {
|
||||
uwsgigo_hook_main();
|
||||
}
|
||||
|
||||
int uwsgi_gccgo_helper_request_body_read(struct wsgi_request *wsgi_req, char *p, uint64_t len) {
|
||||
ssize_t rlen = 0;
|
||||
char *buf = uwsgi_request_body_read(wsgi_req, len, &rlen);
|
||||
if (buf == uwsgi.empty) {
|
||||
return 0;
|
||||
}
|
||||
else if (buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(p, buf, rlen);
|
||||
return (int) rlen;
|
||||
}
|
||||
|
||||
int uwsgi_gccgo_helper_register_signal(uint8_t signum, char *receiver, void *handler) {
|
||||
return uwsgi_register_signal(signum, receiver, handler, gccgo_plugin.modifier1);
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_initialize() {
|
||||
struct uwsgi_string_list *usl = ugccgo.libs;
|
||||
while(usl) {
|
||||
void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!handle) {
|
||||
uwsgi_log("unable to open go shared library: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
|
||||
uwsgigo_hook_init = dlsym(handle, "__go_init_main");
|
||||
uwsgigo_hook_main = dlsym(handle, "main.main");
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (!uwsgigo_hook_init || !uwsgigo_hook_main) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Go runtime initialization
|
||||
int argc = 0;
|
||||
if (ugccgo.args) {
|
||||
char *argv_list = uwsgi_str(ugccgo.args);
|
||||
char *p = strtok(argv_list, " ");
|
||||
while(p) {
|
||||
argc++;
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
free(argv_list);
|
||||
}
|
||||
runtime_check();
|
||||
if (argc > 0) {
|
||||
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 1));
|
||||
char *argv_list = uwsgi_str(ugccgo.args);
|
||||
char *p = strtok(argv_list, " ");
|
||||
int n = 0;
|
||||
while(p) {
|
||||
argv[n] = p;
|
||||
n++;
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
runtime_args(argc, argv);
|
||||
}
|
||||
else {
|
||||
char *argv[2] = {0,0};
|
||||
runtime_args(0, argv);
|
||||
}
|
||||
runtime_osinit();
|
||||
runtime_schedinit();
|
||||
__go_go(mainstart, NULL);
|
||||
runtime_mstart(runtime_m());
|
||||
// never here
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
|
||||
/* Standard GO request */
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
uwsgi_log("Empty GO request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsgi_req->async_environ = uwsgigo_env(wsgi_req);
|
||||
int i;
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
uwsgigo_env_add(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
|
||||
i++;
|
||||
}
|
||||
uwsgigo_request(wsgi_req->async_environ, wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_signal_handler(uint8_t signum, void *handler) {
|
||||
uwsgigo_signal_handler(handler, signum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin gccgo_plugin = {
|
||||
.name = "gccgo",
|
||||
.modifier1 = 11,
|
||||
.options = uwsgi_gccgo_options,
|
||||
//.on_load = uwsgi_gccgo_on_load,
|
||||
.request = uwsgi_gccgo_request,
|
||||
.after_request = uwsgi_gccgo_after_request,
|
||||
.post_fork = uwsgi_gccgo_initialize,
|
||||
.signal_handler = uwsgi_gccgo_signal_handler,
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
package uwsgi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"net/http"
|
||||
"net/http/cgi"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
||||
//extern uwsgi_takeover
|
||||
func uwsgi_takeover()
|
||||
//extern uwsgi_response_write_body_do
|
||||
func uwsgi_response_write_body_do(*interface{}, *byte, uint64) int
|
||||
//extern uwsgi_response_prepare_headers_int
|
||||
func uwsgi_response_prepare_headers_int(*interface{}, int) int
|
||||
//extern uwsgi_response_add_header
|
||||
func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int
|
||||
//extern uwsgi_gccgo_helper_request_body_read
|
||||
func uwsgi_request_body_read(*interface{}, *byte, uint64) int
|
||||
//extern uwsgi_gccgo_helper_register_signal
|
||||
func uwsgi_register_signal(uint8, *byte, func(uint8)) int
|
||||
|
||||
var uwsgi_signals_gc [256]func(uint8)
|
||||
|
||||
func Env(wsgi_req *interface{}) *map[string]string {
|
||||
var env map[string]string
|
||||
env = make(map[string]string)
|
||||
return &env
|
||||
}
|
||||
|
||||
func EnvAdd(env *map[string]string, k *[65536]byte, kl uint16, v *[65536]byte, vl uint16) {
|
||||
(*env)[ string((*k)[0:kl]) ] = string((*v)[0:vl])
|
||||
}
|
||||
|
||||
type ResponseWriter struct {
|
||||
r *http.Request
|
||||
wsgi_req *interface{}
|
||||
headers http.Header
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
|
||||
if !w.wroteHeader {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
uwsgi_response_write_body_do(w.wsgi_req, &p[0], uint64(len(p)))
|
||||
return len(p), err
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) WriteHeader(status int) {
|
||||
uwsgi_response_prepare_headers_int(w.wsgi_req, status )
|
||||
if w.headers.Get("Content-Type") == "" {
|
||||
w.headers.Set("Content-Type", "text/html; charset=utf-8")
|
||||
}
|
||||
for k := range w.headers {
|
||||
for _, v := range w.headers[k] {
|
||||
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
|
||||
v = strings.TrimSpace(v)
|
||||
kb := []byte(k)
|
||||
vb := []byte(v)
|
||||
uwsgi_response_add_header(w.wsgi_req, &kb[0], uint16(len(k)), &vb[0], uint16(len(v)))
|
||||
}
|
||||
}
|
||||
w.wroteHeader = true
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) Header() http.Header {
|
||||
return w.headers
|
||||
}
|
||||
|
||||
|
||||
type BodyReader struct {
|
||||
wsgi_req *interface{}
|
||||
}
|
||||
|
||||
// there is no close in request body
|
||||
func (br *BodyReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (br *BodyReader) Read(p []byte) (n int, err error) {
|
||||
var rlen int = uwsgi_request_body_read(br.wsgi_req, &p[0], uint64(len(p)))
|
||||
if (rlen == 0) {
|
||||
err = io.EOF;
|
||||
return 0, err
|
||||
} else if (rlen == -1) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
return 0, err
|
||||
}
|
||||
return rlen, err
|
||||
}
|
||||
|
||||
func RequestHandler(env *map[string]string, wsgi_req *interface{}) {
|
||||
httpReq, err := cgi.RequestFromMap(*env)
|
||||
if err == nil {
|
||||
httpReq.Body = &BodyReader{wsgi_req}
|
||||
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
|
||||
http.DefaultServeMux.ServeHTTP(&w, httpReq)
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool {
|
||||
var b []byte = []byte(receiver)
|
||||
if (uwsgi_register_signal(signum, &b[0], handler) < 0) {
|
||||
return false
|
||||
}
|
||||
uwsgi_signals_gc[signum] = handler
|
||||
return true
|
||||
}
|
||||
|
||||
func SignalHandler(handler func(uint8), signum uint8) {
|
||||
handler(signum)
|
||||
}
|
||||
|
||||
func Run() {
|
||||
uwsgi_takeover()
|
||||
}
|
||||
+34
-4
@@ -29,7 +29,7 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
|
||||
|
||||
uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
|
||||
|
||||
|
||||
uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
|
||||
PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL);
|
||||
PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL);
|
||||
@@ -54,7 +54,16 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
|
||||
|
||||
if (running_cores > 0) {
|
||||
uwsgi_log_verbose("waiting for %d running requests on worker %d (pid: %d)...\n", running_cores, uwsgi.mywid, uwsgi.mypid);
|
||||
}
|
||||
} else {
|
||||
// no need to worry about freeing memory
|
||||
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
|
||||
if (uwsgi_dict) {
|
||||
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
|
||||
if (ae) {
|
||||
python_call(ae, PyTuple_New(0), 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
@@ -242,8 +251,7 @@ request:
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
|
||||
if (wsgi_req->async_status <= UWSGI_OK) {
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->switches++;
|
||||
@@ -259,6 +267,28 @@ end2:
|
||||
uwsgi_close_request(wsgi_req);
|
||||
free_req_queue;
|
||||
|
||||
|
||||
if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) {
|
||||
int running_cores = 0;
|
||||
int i;
|
||||
for(i=0;i<uwsgi.async;i++) {
|
||||
if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) {
|
||||
running_cores++;
|
||||
}
|
||||
}
|
||||
|
||||
if (running_cores == 0) {
|
||||
// no need to worry about freeing memory
|
||||
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
|
||||
if (uwsgi_dict) {
|
||||
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
|
||||
if (ae) {
|
||||
python_call(ae, PyTuple_New(0), 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -48,9 +48,6 @@ static int uwsgi_go_init() {
|
||||
|
||||
uwsgi_log("Go version \"%s\" initialized\n", uwsgi_go_helper_version_c());
|
||||
|
||||
// call PostInit()
|
||||
uwsgi_go_helper_post_init_c();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -80,9 +77,7 @@ static int uwsgi_go_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
static void uwsgi_go_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
log_request(wsgi_req);
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_go_signal_handler(uint8_t signum, void *handler) {
|
||||
@@ -101,11 +96,18 @@ static void uwsgi_go_on_load() {
|
||||
uwsgi_register_loop("goroutines", goroutines_loop);
|
||||
}
|
||||
|
||||
static void uwsgi_go_call_init_hook() {
|
||||
if (uwsgi_go_helper_post_init_c) {
|
||||
uwsgi_go_helper_post_init_c();
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_plugin go_plugin = {
|
||||
.name = "go",
|
||||
.modifier1 = 11,
|
||||
.request = uwsgi_go_request,
|
||||
.after_request = uwsgi_go_after_request,
|
||||
.preinit_apps = uwsgi_go_call_init_hook,
|
||||
.post_fork = uwsgi_go_post_fork,
|
||||
.init = uwsgi_go_init,
|
||||
.signal_handler = uwsgi_go_signal_handler,
|
||||
|
||||
@@ -411,10 +411,10 @@ func uwsgi_go_helper_run_core(core_id int) {
|
||||
the main function, running the uWSGI server via libuwsgi.so
|
||||
*/
|
||||
func Run() {
|
||||
argc := len(os.Args)
|
||||
argc := len(os.Args) + 1
|
||||
argv := C.uwsgi_go_helper_create_argv(C.int(argc))
|
||||
for i, s := range os.Args {
|
||||
C.uwsgi_go_helper_set_argv(argv, C.int(i), C.CString(s))
|
||||
}
|
||||
C.uwsgi_init(C.int(argc), argv, nil)
|
||||
C.uwsgi_init(C.int(argc-1), argv, nil)
|
||||
}
|
||||
|
||||
+46
-21
@@ -2,6 +2,7 @@
|
||||
#include <greenlet/greenlet.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
struct ugreenlet {
|
||||
int enabled;
|
||||
@@ -10,15 +11,22 @@ struct ugreenlet {
|
||||
PyGreenlet **gl;
|
||||
} ugl;
|
||||
|
||||
struct uwsgi_option greenlet_options[] = {
|
||||
static struct uwsgi_option greenlet_options[] = {
|
||||
{"greenlet", no_argument, 0, "enable greenlet as suspend engine", uwsgi_opt_true, &ugl.enabled, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
|
||||
static void gil_greenlet_get() {
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
static void gil_greenlet_release() {
|
||||
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
|
||||
}
|
||||
|
||||
static PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
|
||||
|
||||
async_schedule_to_req_green();
|
||||
|
||||
Py_DECREF(ugl.gl[uwsgi.wsgi_req->async_id]);
|
||||
|
||||
@@ -28,45 +36,66 @@ PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
|
||||
|
||||
PyMethodDef uwsgi_greenlet_request_method[] = {{"uwsgi_greenlet_request", py_uwsgi_greenlet_request, METH_VARARGS, ""}};
|
||||
|
||||
static inline void greenlet_schedule_to_req() {
|
||||
static void greenlet_schedule_to_req() {
|
||||
|
||||
int id = uwsgi.wsgi_req->async_id;
|
||||
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
|
||||
|
||||
// ensure gil
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (!uwsgi.wsgi_req->suspended) {
|
||||
ugl.gl[id] = PyGreenlet_New(ugl.callable, NULL);
|
||||
uwsgi.wsgi_req->suspended = 1;
|
||||
}
|
||||
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->suspend) {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
|
||||
|
||||
if (uwsgi.wsgi_req->suspended) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static inline void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// ensure gil
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
PyGreenlet_Switch(ugl.main, NULL, NULL);
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
}
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
static int greenlet_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void greenlet_init_apps(void) {
|
||||
|
||||
if (!ugl.enabled) {
|
||||
return;
|
||||
}
|
||||
if (!ugl.enabled) return;
|
||||
|
||||
if (uwsgi.async <= 1) {
|
||||
uwsgi_log("the greenlet loop engine requires async mode\n");
|
||||
uwsgi_log("the greenlet suspend engine requires async mode\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.has_threads) {
|
||||
up.gil_get = gil_greenlet_get;
|
||||
up.gil_release = gil_greenlet_release;
|
||||
}
|
||||
|
||||
// blindy call it as the stackless gil engine is already set
|
||||
UWSGI_GET_GIL
|
||||
|
||||
|
||||
PyGreenlet_Import();
|
||||
|
||||
@@ -77,15 +106,11 @@ static void greenlet_init_apps(void) {
|
||||
|
||||
uwsgi.schedule_to_main = greenlet_schedule_to_main;
|
||||
uwsgi.schedule_to_req = greenlet_schedule_to_req;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_plugin greenlet_plugin = {
|
||||
|
||||
.name = "greenlet",
|
||||
.init = greenlet_init,
|
||||
.init_apps = greenlet_init_apps,
|
||||
.options = greenlet_options,
|
||||
};
|
||||
|
||||
+278
-1
@@ -1,5 +1,13 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
Authors:
|
||||
|
||||
Roberto De Ioris <roberto@unbit.it> - general LDAP support, reading uWSGI configuration from LDAP servers
|
||||
|
||||
Łukasz Mierzwa <l.mierzwa@gmail.com> - LDAP auth router support
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <ldap.h>
|
||||
@@ -366,7 +374,276 @@ static void uwsgi_ldap_config(char *url) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
struct uwsgi_ldapauth_config {
|
||||
char *url;
|
||||
LDAPURLDesc *ldap_url;
|
||||
char *binddn;
|
||||
char *bindpw;
|
||||
char *basedn;
|
||||
char *filter;
|
||||
char *login_attr;
|
||||
int loglevel;
|
||||
};
|
||||
|
||||
static uint16_t ldap_passwd_check(struct uwsgi_ldapauth_config *ulc, char *auth) {
|
||||
|
||||
char *colon = strchr(auth, ':');
|
||||
if (!colon) return 0;
|
||||
|
||||
int ret;
|
||||
uint16_t ulen = 0;
|
||||
LDAP *ldp;
|
||||
int desired_version = LDAP_VERSION3;
|
||||
|
||||
#if LDAP_API_VERSION >= 3000
|
||||
if ((ret = ldap_initialize(&ldp, ulc->url)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("[router-ldapauth] can't connect to LDAP server at %s\n", ulc->url);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if ((ldp = ldap_init(ulc->ldap_url->lud_host, ulc->ldap_url->lud_port)) == NULL) {
|
||||
uwsgi_log("[router-ldapauth] can't connect to LDAP server at %s\n", ulc->url);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) {
|
||||
uwsgi_log("[router-ldapauth] LDAP protocol version mismatch: %s\n", ldap_err2string(ret));
|
||||
goto close;
|
||||
}
|
||||
|
||||
// first bind if needed
|
||||
if (ulc->binddn && ulc->bindpw) {
|
||||
#if LDAP_API_VERSION >= 3000
|
||||
struct berval bval;
|
||||
bval.bv_val = ulc->bindpw;
|
||||
bval.bv_len = strlen(bval.bv_val);
|
||||
if ((ret = ldap_sasl_bind_s(ldp, ulc->binddn, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL)) != LDAP_OPT_SUCCESS) {
|
||||
#else
|
||||
if ((ret = ldap_bind_s(ldp, ulc->binddn, ulc->bindpw, LDAP_AUTH_SIMPLE)) != LDAP_OPT_SUCCESS) {
|
||||
#endif
|
||||
uwsgi_log("[router-ldapauth] can't bind as user '%s' to '%s': %s\n", ulc->binddn, ulc->url, ldap_err2string(ret));
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
|
||||
// search for user
|
||||
char *userdn = NULL;
|
||||
LDAPMessage *msg, *entry;
|
||||
// use the minimal amount of memory
|
||||
char *filter = uwsgi_malloc( strlen(ulc->login_attr) + (colon-auth) + strlen(ulc->filter) + 7);
|
||||
if (snprintf(filter, 1024, "(&(%s=%.*s)%s)", ulc->login_attr, (int) (colon-auth), auth, ulc->filter) <= 0) {
|
||||
free(filter);
|
||||
uwsgi_error("ldap_passwd_check()/sprintfn(filter)");
|
||||
goto close;
|
||||
}
|
||||
|
||||
if ((ret = ldap_search_ext_s(ldp, ulc->basedn, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS) {
|
||||
free(filter);
|
||||
uwsgi_log("[router-ldapauth] search error on '%s': %s\n", ulc->url, ldap_err2string(ret));
|
||||
goto close;
|
||||
}
|
||||
else {
|
||||
free(filter);
|
||||
entry = ldap_first_entry(ldp, msg);
|
||||
while (entry) {
|
||||
struct berval **vals = ldap_get_values_len(ldp, entry, ulc->login_attr);
|
||||
if (!uwsgi_strncmp(auth, colon-auth, vals[0]->bv_val, vals[0]->bv_len)) {
|
||||
userdn = ldap_get_dn(ldp, entry);
|
||||
free(vals);
|
||||
break;
|
||||
}
|
||||
free(vals);
|
||||
entry = ldap_next_entry(ldp, entry);
|
||||
}
|
||||
ldap_msgfree(msg);
|
||||
}
|
||||
|
||||
if (userdn) {
|
||||
// user found in ldap, try to bind
|
||||
|
||||
#if LDAP_API_VERSION >= 3000
|
||||
struct berval bval;
|
||||
bval.bv_val = colon+1;
|
||||
bval.bv_len = strlen(bval.bv_val);
|
||||
if ((ret = ldap_sasl_bind_s(ldp, userdn, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL)) != LDAP_OPT_SUCCESS) {
|
||||
#else
|
||||
if ((ret = ldap_bind_s(ldp, userdn, colon+1, LDAP_AUTH_SIMPLE)) != LDAP_OPT_SUCCESS) {
|
||||
#endif
|
||||
if (ulc->loglevel)
|
||||
uwsgi_log("[router-ldapauth] can't bind as user '%s' to '%s': %s\n", userdn, ulc->url, ldap_err2string(ret));
|
||||
}
|
||||
else {
|
||||
if (ulc->loglevel > 1)
|
||||
uwsgi_log("[router-ldapauth] successful bind as user '%s' to '%s'\n", userdn, ulc->url);
|
||||
ulen = colon-auth;
|
||||
}
|
||||
|
||||
ldap_memfree(userdn);
|
||||
}
|
||||
else if (ulc->loglevel) {
|
||||
uwsgi_log("router-ldapauth] user '%.*s' not found in LDAP server at '%s'\n", colon-auth, auth, ulc->url);
|
||||
}
|
||||
|
||||
close:
|
||||
if ((ret = ldap_unbind_ext_s(ldp, NULL, NULL)) != LDAP_OPT_SUCCESS) {
|
||||
uwsgi_log("[router-ldapauth] LDAP unbind error: %s\n", ldap_err2string(ret));
|
||||
}
|
||||
|
||||
return ulen;
|
||||
}
|
||||
|
||||
int uwsgi_routing_func_ldapauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
// skip if already authenticated
|
||||
if (wsgi_req->remote_user_len > 0) {
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
if (wsgi_req->authorization_len > 7 && ur->data2) {
|
||||
if (strncmp(wsgi_req->authorization, "Basic ", 6))
|
||||
goto forbidden;
|
||||
|
||||
size_t auth_len = 0;
|
||||
char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len);
|
||||
if (auth) {
|
||||
if (!ur->custom) {
|
||||
uint16_t ulen = ldap_passwd_check(ur->data2, auth);
|
||||
if (ulen > 0) {
|
||||
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen);
|
||||
if (wsgi_req->remote_user)
|
||||
wsgi_req->remote_user_len = ulen;
|
||||
}
|
||||
else if (ur->data3_len == 0) {
|
||||
free(auth);
|
||||
goto forbidden;
|
||||
}
|
||||
}
|
||||
free(auth);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
forbidden:
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
|
||||
char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1);
|
||||
int ret = uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
|
||||
free(realm);
|
||||
if (ret) goto end;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
|
||||
end:
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
static int uwsgi_router_ldapauth(struct uwsgi_route *ur, char *args) {
|
||||
|
||||
ur->func = uwsgi_routing_func_ldapauth;
|
||||
|
||||
char *comma = strchr(args, ',');
|
||||
if (!comma) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
*comma = 0;
|
||||
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
|
||||
char *url = NULL;
|
||||
char *binddn = NULL;
|
||||
char *bindpw = NULL;
|
||||
char *basedn = NULL;
|
||||
char *filter = NULL;
|
||||
char *attr = NULL;
|
||||
char *loglevel = NULL;
|
||||
if (uwsgi_kvlist_parse(comma+1, strlen(comma+1), ';', '=',
|
||||
"url", &url,
|
||||
"binddn", &binddn,
|
||||
"bindpw", &bindpw,
|
||||
"basedn", &basedn,
|
||||
"filter", &filter,
|
||||
"attr", &attr,
|
||||
"loglevel", &loglevel,
|
||||
NULL)) {
|
||||
uwsgi_log("[router-ldapauth] unable to parse options: %s\n", comma+1);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
struct uwsgi_ldapauth_config *ulc = uwsgi_malloc(sizeof(struct uwsgi_ldapauth_config));
|
||||
|
||||
if (!basedn) {
|
||||
uwsgi_log("[router-ldapauth] missing LDAP base dn (basedn option) on line: %s\n", comma+1);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
ulc->basedn = basedn;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
uwsgi_log("[router-ldapauth] missing LDAP server url (url option) on line: %s\n", comma+1);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
if (!ldap_is_ldap_url(url)) {
|
||||
uwsgi_log("[router-ldapauth] invalid LDAP url: %s\n", url);
|
||||
exit(1);
|
||||
}
|
||||
if (ldap_url_parse(url, &ulc->ldap_url) != LDAP_SUCCESS) {
|
||||
uwsgi_log("[router-ldapauth] unable to parse LDAP url: %s\n", url);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!filter) {
|
||||
ulc->filter = uwsgi_str("(objectClass=*)");
|
||||
}
|
||||
else {
|
||||
ulc->filter = filter;
|
||||
}
|
||||
|
||||
if (!attr) {
|
||||
ulc->login_attr = uwsgi_str("uid");
|
||||
}
|
||||
else {
|
||||
ulc->login_attr = attr;
|
||||
}
|
||||
|
||||
ulc->url = url;
|
||||
|
||||
ulc->binddn = binddn;
|
||||
ulc->bindpw = bindpw;
|
||||
|
||||
if (loglevel) {
|
||||
ulc->loglevel = atoi(loglevel);
|
||||
}
|
||||
else {
|
||||
ulc->loglevel = 0;
|
||||
}
|
||||
|
||||
ur->data2 = ulc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_ldapauth_next(struct uwsgi_route *ur, char *args) {
|
||||
ur->data3_len = 1;
|
||||
return uwsgi_router_ldapauth(ur, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
void uwsgi_ldap_register(void) {
|
||||
#ifdef UWSGI_ROUTING
|
||||
uwsgi_register_router("ldapauth", uwsgi_router_ldapauth);
|
||||
uwsgi_register_router("ldapauth-next", uwsgi_router_ldapauth_next);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct uwsgi_plugin ldap_plugin = {
|
||||
.name = "ldap",
|
||||
.options = uwsgi_ldap_options,
|
||||
.options = uwsgi_ldap_options,
|
||||
.on_load = uwsgi_ldap_register,
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
|
||||
char *chitem, *chitem2;
|
||||
SV **harakiri;
|
||||
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if (wsgi_req->async_force_again) {
|
||||
|
||||
wsgi_req->async_force_again = 0;
|
||||
|
||||
@@ -53,7 +53,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
SvREFCNT_dec(chunk);
|
||||
|
||||
wsgi_req->async_force_again = 1;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,6 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
|
||||
chitem = SvPV( chunk, hlen);
|
||||
if (uwsgi.async > 1 && wsgi_req->async_force_again) {
|
||||
SvREFCNT_dec(chunk);
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
wsgi_req->async_placeholder = (SV *) *hitem;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
@@ -157,8 +156,8 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
|
||||
}
|
||||
SvREFCNT_dec(chunk);
|
||||
if (uwsgi.async > 1) {
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
wsgi_req->async_placeholder = (SV *) *hitem;
|
||||
wsgi_req->async_force_again = 1;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
#include "uwsgi_python.h"
|
||||
|
||||
/*
|
||||
|
||||
This is the official python plugin, the one with the modifier1 mapped to 0
|
||||
|
||||
Since uWSGI 1.0 it is heavily based on Graham Dumpleton mod_wsgi (for Apache)
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_python up;
|
||||
|
||||
|
||||
@@ -2555,7 +2555,7 @@ PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) {
|
||||
|
||||
uint64_t expires = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#s#|is:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) {
|
||||
if (!PyArg_ParseTuple(args, "s#s#|ls:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2582,7 +2582,7 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
|
||||
|
||||
uint64_t expires = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#s#|is:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) {
|
||||
if (!PyArg_ParseTuple(args, "s#s#|ls:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2599,6 +2599,106 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_cache_inc(PyObject * self, PyObject * args) {
|
||||
|
||||
char *key;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *remote = NULL;
|
||||
int64_t value = 1;
|
||||
uint64_t expires = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|lls:cache_inc", &key, &keylen, &value, &expires, &remote)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_INC, remote)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_cache_dec(PyObject * self, PyObject * args) {
|
||||
|
||||
char *key;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *remote = NULL;
|
||||
int64_t value = 1;
|
||||
uint64_t expires = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|lls:cache_dec", &key, &keylen, &value, &expires, &remote)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DEC, remote)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_cache_mul(PyObject * self, PyObject * args) {
|
||||
|
||||
char *key;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *remote = NULL;
|
||||
int64_t value = 2;
|
||||
uint64_t expires = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|lls:cache_mul", &key, &keylen, &value, &expires, &remote)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_MUL, remote)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_cache_div(PyObject * self, PyObject * args) {
|
||||
|
||||
char *key;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *remote = NULL;
|
||||
int64_t value = 2;
|
||||
uint64_t expires = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|lls:cache_div", &key, &keylen, &value, &expires, &remote)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DIV, remote)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) {
|
||||
@@ -2940,6 +3040,31 @@ PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) {
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_cache_num(PyObject * self, PyObject * args) {
|
||||
|
||||
char *key;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *cache = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|s:cache_num", &key, &keylen, &cache)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t vallen = 0;
|
||||
UWSGI_RELEASE_GIL
|
||||
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache);
|
||||
UWSGI_GET_GIL
|
||||
if (value && vallen == 8) {
|
||||
int64_t *num = (int64_t *) value;
|
||||
PyObject *ret = PyLong_FromLong(*num);
|
||||
free(value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return PyLong_FromLong(0);
|
||||
|
||||
}
|
||||
|
||||
static PyMethodDef uwsgi_cache_methods[] = {
|
||||
{"cache_get", py_uwsgi_cache_get, METH_VARARGS, ""},
|
||||
{"cache_set", py_uwsgi_cache_set, METH_VARARGS, ""},
|
||||
@@ -2947,6 +3072,11 @@ static PyMethodDef uwsgi_cache_methods[] = {
|
||||
{"cache_del", py_uwsgi_cache_del, METH_VARARGS, ""},
|
||||
{"cache_exists", py_uwsgi_cache_exists, METH_VARARGS, ""},
|
||||
{"cache_clear", py_uwsgi_cache_clear, METH_VARARGS, ""},
|
||||
{"cache_inc", py_uwsgi_cache_inc, METH_VARARGS, ""},
|
||||
{"cache_dec", py_uwsgi_cache_dec, METH_VARARGS, ""},
|
||||
{"cache_mul", py_uwsgi_cache_mul, METH_VARARGS, ""},
|
||||
{"cache_div", py_uwsgi_cache_div, METH_VARARGS, ""},
|
||||
{"cache_num", py_uwsgi_cache_num, METH_VARARGS, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -293,8 +293,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_app *wi;
|
||||
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if (wsgi_req->async_force_again) {
|
||||
wi = &uwsgi_apps[wsgi_req->app_id];
|
||||
wsgi_req->async_force_again = 0;
|
||||
UWSGI_GET_GIL
|
||||
// get rid of timeout
|
||||
if (wsgi_req->async_timed_out) {
|
||||
@@ -315,6 +316,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
int ret = manage_python_response(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto end;
|
||||
UWSGI_RELEASE_GIL
|
||||
if (ret == UWSGI_AGAIN) {
|
||||
wsgi_req->async_force_again = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -328,13 +332,15 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsgi_req->dynamic) {
|
||||
// this part must be heavy locked in threaded modes
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_lock(&up.lock_pyloaders);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
|
||||
if (wsgi_req->dynamic) {
|
||||
// this part must be heavy locked in threaded modes
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_lock(&up.lock_pyloaders);
|
||||
}
|
||||
|
||||
UWSGI_GET_GIL
|
||||
if (uwsgi.single_interpreter) {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
|
||||
@@ -343,9 +349,12 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL, PYTHON_APP_TYPE_WSGI);
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&up.lock_pyloaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->dynamic) {
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&up.lock_pyloaders);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,6 +397,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
while (wi->response_subhandler(wsgi_req) != UWSGI_OK) {
|
||||
if (uwsgi.async > 1) {
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->async_force_again = 1;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -957,18 +957,15 @@ clear:
|
||||
}
|
||||
|
||||
void uwsgi_rack_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
void uwsgi_rack_suspend(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uwsgi_log("SUSPENDING RUBY\n");
|
||||
//uwsgi_log("SUSPENDING RUBY\n");
|
||||
}
|
||||
|
||||
void uwsgi_rack_resume(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uwsgi_log("RESUMING RUBY\n");
|
||||
//uwsgi_log("RESUMING RUBY\n");
|
||||
}
|
||||
|
||||
VALUE init_rack_app( VALUE script ) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
@@ -60,7 +60,13 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
static int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
// skip if already authenticated
|
||||
if (wsgi_req->remote_user_len > 0) {
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
if (wsgi_req->authorization_len > 7 && ur->data2_len > 0) {
|
||||
if (strncmp(wsgi_req->authorization, "Basic ", 6))
|
||||
@@ -74,28 +80,32 @@ int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_rou
|
||||
uint16_t ulen = htpasswd_check(ur->data2, auth);
|
||||
if (ulen > 0) {
|
||||
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen);
|
||||
if (wsgi_req->remote_user)
|
||||
wsgi_req->remote_user_len = ulen;
|
||||
if (!wsgi_req->remote_user) {
|
||||
free(auth);
|
||||
goto forbidden;
|
||||
}
|
||||
wsgi_req->remote_user_len = ulen;
|
||||
}
|
||||
else if (ur->data3_len == 0) {
|
||||
free(auth);
|
||||
if (ur->data3_len > 0)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
return UWSGI_ROUTE_GOON;
|
||||
goto forbidden;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!uwsgi_strncmp(auth, auth_len, ur->data2, ur->data2_len)) {
|
||||
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ur->custom);
|
||||
if (wsgi_req->remote_user)
|
||||
wsgi_req->remote_user_len = ur->custom;
|
||||
if (!wsgi_req->remote_user) {
|
||||
free(auth);
|
||||
goto forbidden;
|
||||
}
|
||||
wsgi_req->remote_user_len = ur->custom;
|
||||
}
|
||||
else if (ur->data3_len == 0) {
|
||||
free(auth);
|
||||
if (ur->data3_len > 0)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
return UWSGI_ROUTE_GOON;
|
||||
goto forbidden;
|
||||
}
|
||||
}
|
||||
free(auth);
|
||||
if (ur->is_last)
|
||||
goto forbidden;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
@@ -103,16 +113,16 @@ int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_rou
|
||||
forbidden:
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
|
||||
char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1);
|
||||
int ret = uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
|
||||
// no need to check for errors
|
||||
uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
|
||||
free(realm);
|
||||
if (ret) goto end;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
|
||||
end:
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
void router_basicauth_init_lock() {
|
||||
static void router_basicauth_init_lock() {
|
||||
pthread_mutex_init(&ur_basicauth_crypt_mutex, NULL);
|
||||
}
|
||||
#endif
|
||||
@@ -147,17 +157,14 @@ static int uwsgi_router_basicauth(struct uwsgi_route *ur, char *args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_basicauth_last(struct uwsgi_route *ur, char *args) {
|
||||
uwsgi_router_basicauth(ur, args);
|
||||
static int uwsgi_router_basicauth_next(struct uwsgi_route *ur, char *args) {
|
||||
ur->data3_len = 1;
|
||||
return 0;
|
||||
return uwsgi_router_basicauth(ur, args);
|
||||
}
|
||||
|
||||
|
||||
void router_basicauth_register(void) {
|
||||
|
||||
static void router_basicauth_register(void) {
|
||||
uwsgi_register_router("basicauth", uwsgi_router_basicauth);
|
||||
uwsgi_register_router("basicauth-last", uwsgi_router_basicauth_last);
|
||||
uwsgi_register_router("basicauth-next", uwsgi_router_basicauth_next);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_basicauth_plugin = {
|
||||
|
||||
@@ -23,9 +23,17 @@ struct uwsgi_router_cache_conf {
|
||||
char *key;
|
||||
size_t key_len;
|
||||
|
||||
char *var;
|
||||
size_t var_len;
|
||||
|
||||
char *value;
|
||||
size_t value_len;
|
||||
|
||||
// use mime types ?
|
||||
char *mime;
|
||||
|
||||
char *as_num;
|
||||
|
||||
#ifdef UWSGI_ZLIB
|
||||
char *gzip;
|
||||
size_t gzip_len;
|
||||
@@ -41,6 +49,13 @@ struct uwsgi_router_cache_conf {
|
||||
|
||||
char *expires_str;
|
||||
uint64_t expires;
|
||||
|
||||
int64_t default_num;
|
||||
|
||||
uint64_t flags;
|
||||
|
||||
char *status_str;
|
||||
int status;
|
||||
};
|
||||
|
||||
// this is allocated for each transformation
|
||||
@@ -50,15 +65,22 @@ struct uwsgi_transformation_cache_conf {
|
||||
struct uwsgi_buffer *cache_it_gzip;
|
||||
#endif
|
||||
|
||||
int status;
|
||||
struct uwsgi_buffer *value;
|
||||
|
||||
struct uwsgi_buffer *cache_it_to;
|
||||
uint64_t cache_it_expires;
|
||||
};
|
||||
|
||||
static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
|
||||
struct uwsgi_transformation_cache_conf *utcc = (struct uwsgi_transformation_cache_conf *) data;
|
||||
|
||||
static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
struct uwsgi_transformation_cache_conf *utcc = (struct uwsgi_transformation_cache_conf *) ut->data;
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
// force value
|
||||
if (utcc->value) {
|
||||
ub = utcc->value;
|
||||
}
|
||||
// store only successfull response
|
||||
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
|
||||
if (wsgi_req->write_errors == 0 && (wsgi_req->status == 200 || (utcc->status && wsgi_req->status == utcc->status)) && ub->pos > 0) {
|
||||
if (utcc->cache_it) {
|
||||
uwsgi_cache_magic_set(utcc->cache_it->buf, utcc->cache_it->pos, ub->buf, ub->pos, utcc->cache_it_expires,
|
||||
UWSGI_CACHE_FLAG_UPDATE, utcc->cache_it_to ? utcc->cache_it_to->buf : NULL);
|
||||
@@ -81,6 +103,7 @@ static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_buffer *u
|
||||
if (utcc->cache_it_gzip) uwsgi_buffer_destroy(utcc->cache_it_gzip);
|
||||
#endif
|
||||
if (utcc->cache_it_to) uwsgi_buffer_destroy(utcc->cache_it_to);
|
||||
if (utcc->value) uwsgi_buffer_destroy(utcc->value);
|
||||
free(utcc);
|
||||
return 0;
|
||||
}
|
||||
@@ -104,6 +127,13 @@ static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct
|
||||
if (!utcc->cache_it_to) goto error;
|
||||
}
|
||||
|
||||
if (urcc->value) {
|
||||
utcc->value = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
|
||||
if (!utcc->value) goto error;
|
||||
}
|
||||
|
||||
utcc->status = urcc->status;
|
||||
|
||||
#ifdef UWSGI_ZLIB
|
||||
if (urcc->gzip) {
|
||||
utcc->cache_it_gzip = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->gzip, urcc->gzip_len);
|
||||
@@ -172,6 +202,102 @@ error:
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
// place a cache value in a request var
|
||||
static int uwsgi_routing_func_cachevar(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
|
||||
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
uint64_t valsize = 0;
|
||||
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, NULL, urcc->name);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (value) {
|
||||
if (urcc->as_num) {
|
||||
char *tmp = value;
|
||||
if (valsize == 8) {
|
||||
int64_t *num = (int64_t *) value;
|
||||
value = uwsgi_64bit2str(*num);
|
||||
}
|
||||
else {
|
||||
value = uwsgi_64bit2str(0);
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
if (!uwsgi_req_append(wsgi_req, urcc->var, urcc->var_len, value, valsize)) {
|
||||
free(value);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
// set a cache item
|
||||
static int uwsgi_routing_func_cacheset(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
|
||||
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
|
||||
if (!ub_val) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
if (uwsgi_cache_magic_set(ub->buf, ub->pos, ub_val->buf, ub_val->pos, urcc->expires, 0, urcc->name)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub_val);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub_val);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
// cacheinc/cachedec/cachemul/cachediv
|
||||
static int uwsgi_routing_func_cachemath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
|
||||
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
int64_t num = urcc->default_num;
|
||||
|
||||
if (urcc->value) {
|
||||
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
|
||||
if (!ub_val) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
num = strtol(ub_val->buf, NULL, 10);
|
||||
uwsgi_buffer_destroy(ub_val);
|
||||
}
|
||||
|
||||
if (uwsgi_cache_magic_set(ub->buf, ub->pos, (char *) &num, 8, urcc->expires, urcc->flags, urcc->name)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_cache_store;
|
||||
ur->data = args;
|
||||
@@ -183,6 +309,9 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
|
||||
"gzip", &urcc->gzip,
|
||||
#endif
|
||||
"name", &urcc->name,
|
||||
"value", &urcc->value,
|
||||
"status", &urcc->status_str,
|
||||
"code", &urcc->status_str,
|
||||
"expires", &urcc->expires_str, NULL)) {
|
||||
uwsgi_log("invalid cachestore route syntax: %s\n", args);
|
||||
goto error;
|
||||
@@ -211,6 +340,14 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
|
||||
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
|
||||
}
|
||||
|
||||
if (urcc->value) {
|
||||
urcc->value_len = strlen(urcc->value);
|
||||
}
|
||||
|
||||
if (urcc->status_str) {
|
||||
urcc->status = atoi(urcc->status_str);
|
||||
}
|
||||
|
||||
ur->data2 = urcc;
|
||||
return 0;
|
||||
error:
|
||||
@@ -264,11 +401,207 @@ static int uwsgi_router_cache_continue(struct uwsgi_route *ur, char *args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct uwsgi_router_cache_conf *uwsgi_router_cachemath(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_cachemath;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"key", &urcc->key,
|
||||
"value", &urcc->value,
|
||||
"name", &urcc->name,
|
||||
"expires", &urcc->expires_str, NULL)) {
|
||||
uwsgi_log("invalid cachemath route syntax: %s\n", args);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (urcc->key) {
|
||||
urcc->key_len = strlen(urcc->key);
|
||||
}
|
||||
|
||||
if (urcc->value) {
|
||||
urcc->value_len = strlen(urcc->value);
|
||||
}
|
||||
|
||||
if (urcc->name) {
|
||||
urcc->name_len = strlen(urcc->name);
|
||||
}
|
||||
|
||||
if (!urcc->key) {
|
||||
uwsgi_log("invalid cachemath route syntax: you need to specify a cache key\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (urcc->expires_str) {
|
||||
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
|
||||
}
|
||||
|
||||
urcc->flags = UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE;
|
||||
ur->data2 = urcc;
|
||||
return urcc;
|
||||
error:
|
||||
if (urcc->key) free(urcc->key);
|
||||
if (urcc->name) free(urcc->name);
|
||||
if (urcc->value) free(urcc->value);
|
||||
if (urcc->expires_str) free(urcc->expires_str);
|
||||
free(urcc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uwsgi_router_cacheinc(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
|
||||
if (!urcc) return -1;
|
||||
urcc->default_num = 1;
|
||||
urcc->flags |= UWSGI_CACHE_FLAG_INC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_cachedec(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
|
||||
if (!urcc) return -1;
|
||||
urcc->default_num = 1;
|
||||
urcc->flags |= UWSGI_CACHE_FLAG_DEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_cachemul(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
|
||||
if (!urcc) return -1;
|
||||
urcc->default_num = 2;
|
||||
urcc->flags |= UWSGI_CACHE_FLAG_MUL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_cachediv(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
|
||||
if (!urcc) return -1;
|
||||
urcc->default_num = 2;
|
||||
urcc->flags |= UWSGI_CACHE_FLAG_DIV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_cacheset(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_cacheset;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"key", &urcc->key,
|
||||
"value", &urcc->value,
|
||||
"name", &urcc->name,
|
||||
"expires", &urcc->expires_str, NULL)) {
|
||||
uwsgi_log("invalid cacheset route syntax: %s\n", args);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (urcc->key) {
|
||||
urcc->key_len = strlen(urcc->key);
|
||||
}
|
||||
|
||||
if (urcc->value) {
|
||||
urcc->value_len = strlen(urcc->value);
|
||||
}
|
||||
|
||||
if (urcc->name) {
|
||||
urcc->name_len = strlen(urcc->name);
|
||||
}
|
||||
|
||||
if (!urcc->key || !urcc->value) {
|
||||
uwsgi_log("invalid cacheset route syntax: you need to specify a cache key and a value\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (urcc->expires_str) {
|
||||
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
|
||||
}
|
||||
|
||||
ur->data2 = urcc;
|
||||
return 0;
|
||||
error:
|
||||
if (urcc->key) free(urcc->key);
|
||||
if (urcc->name) free(urcc->name);
|
||||
if (urcc->value) free(urcc->value);
|
||||
if (urcc->expires_str) free(urcc->expires_str);
|
||||
free(urcc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_cachevar(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_cachevar;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"key", &urcc->key,
|
||||
"var", &urcc->var,
|
||||
"name", &urcc->name,
|
||||
"num", &urcc->as_num,
|
||||
"as_num", &urcc->as_num,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (urcc->key) {
|
||||
urcc->key_len = strlen(urcc->key);
|
||||
}
|
||||
|
||||
if (urcc->var) {
|
||||
urcc->var_len = strlen(urcc->var);
|
||||
}
|
||||
|
||||
if (!urcc->key || !urcc->var) {
|
||||
uwsgi_log("invalid route syntax: you need to specify a cache key and a request var\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ur->data2 = urcc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_incache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
int ret = 0;
|
||||
char *key = NULL;
|
||||
size_t key_len = 0;
|
||||
char *name = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(ur->subject_str, ur->subject_str_len, ',', '=',
|
||||
"key", &key,
|
||||
"name", &name,
|
||||
NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!key) goto end;
|
||||
|
||||
key_len = strlen(key);
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, key, key_len);
|
||||
if (!ub) goto end;
|
||||
|
||||
ret = uwsgi_cache_magic_exists(ub->buf, ub->pos, name);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
end:
|
||||
if (key) free(key);
|
||||
if (name) free(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void router_cache_register() {
|
||||
uwsgi_register_router("cache", uwsgi_router_cache);
|
||||
uwsgi_register_router("cache-continue", uwsgi_router_cache_continue);
|
||||
uwsgi_register_router("cachevar", uwsgi_router_cachevar);
|
||||
uwsgi_register_router("cacheset", uwsgi_router_cacheset);
|
||||
uwsgi_register_router("cachestore", uwsgi_router_cache_store);
|
||||
uwsgi_register_router("cache-store", uwsgi_router_cache_store);
|
||||
uwsgi_register_route_condition("incache", uwsgi_route_condition_incache);
|
||||
|
||||
uwsgi_register_router("cacheinc", uwsgi_router_cacheinc);
|
||||
uwsgi_register_router("cachedec", uwsgi_router_cachedec);
|
||||
uwsgi_register_router("cachemul", uwsgi_router_cachemul);
|
||||
uwsgi_register_router("cachediv", uwsgi_router_cachediv);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_cache_plugin = {
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_radius_conf {
|
||||
char *realm;
|
||||
uint16_t realm_len;
|
||||
char *server;
|
||||
char *secret;
|
||||
uint16_t secret_len;
|
||||
char *nas_port_str;
|
||||
uint32_t nas_port;
|
||||
char *nas_address_str;
|
||||
uint32_t nas_address;
|
||||
};
|
||||
|
||||
static uint16_t uwsgi_radius_auth(struct uwsgi_radius_conf *urc, char *auth, size_t auth_len) {
|
||||
static uint8_t packet_identifier = 0;
|
||||
char access_request[4096];
|
||||
char hash[4096];
|
||||
// md5 result
|
||||
char md5_hash[16];
|
||||
|
||||
size_t i;
|
||||
char *password = memchr(auth, ':', auth_len);
|
||||
if (!password) return 0;
|
||||
char *username = auth;
|
||||
uint16_t username_len = password - auth;
|
||||
password++;
|
||||
uint16_t password_len = auth_len - (username_len+1);
|
||||
|
||||
int fd = uwsgi_connect_udp(urc->server);
|
||||
if (fd < 0) return 0;
|
||||
|
||||
uwsgi_socket_nb(fd);
|
||||
|
||||
// start generating authenticator
|
||||
char authenticator[16];
|
||||
for(i=0;i<16;i++) authenticator[i] = rand();
|
||||
|
||||
// generate the User-Password attribute
|
||||
char *md5 = authenticator;
|
||||
|
||||
// step 1 pad to 16 bytes boundary
|
||||
size_t pwd16_len = password_len + (16 - (password_len % 16));
|
||||
if (pwd16_len > 128) return 0;
|
||||
|
||||
// compute the whole packet size
|
||||
uint16_t access_request_len = 4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 6;
|
||||
memset(access_request, 0, access_request_len);
|
||||
if (access_request_len > 4096) return 0;
|
||||
char *pwd16_buf = access_request + (access_request_len - (pwd16_len + 6 + 6));
|
||||
memcpy(pwd16_buf, password, password_len);
|
||||
|
||||
// allocate a buffer for the hash
|
||||
if (urc->secret_len + 16 > 4096) return 0;
|
||||
memcpy(hash, urc->secret, urc->secret_len);
|
||||
|
||||
for(i=0;i<pwd16_len;i+=16) {
|
||||
// append the last md5 to the hash (after the secret)
|
||||
memcpy(hash + urc->secret_len, md5, 16);
|
||||
// calculate its md5
|
||||
if (!uwsgi_md5(hash, urc->secret_len + 16, md5_hash)) {
|
||||
goto end;
|
||||
}
|
||||
size_t j;
|
||||
// set md5 to the new result
|
||||
md5 = &pwd16_buf[i];
|
||||
// xor the result (we use the authenticator as destination buffer)
|
||||
for(j=0;j<16;j++) {
|
||||
md5[j] = md5_hash[j] ^ md5[j];
|
||||
}
|
||||
}
|
||||
|
||||
// complete the packet
|
||||
packet_identifier++;
|
||||
access_request[0] = 1;
|
||||
access_request[1] = packet_identifier;
|
||||
access_request[2] = (uint8_t) ((access_request_len >> 8) & 0xff);
|
||||
access_request[3] = (uint8_t) (access_request_len & 0xff);
|
||||
memcpy(access_request + 4, authenticator, 16);
|
||||
access_request[4 + 16] = 1;
|
||||
access_request[4 + 16 + 1] = username_len + 2;
|
||||
memcpy(access_request + (4 + 16 + 2), username, username_len);
|
||||
access_request[4 + 16 + 2 + username_len] = 2;
|
||||
access_request[4 + 16 + 2 + username_len + 1] = pwd16_len + 2;
|
||||
// add nas port
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len] = 5;
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 1] = 6;
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 2] = (uint8_t) ((urc->nas_port >> 24) & 0xff);
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 3] = (uint8_t) ((urc->nas_port >> 16) & 0xff);
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 4] = (uint8_t) ((urc->nas_port >> 8) & 0xff);
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 5] = (uint8_t) (urc->nas_port & 0xff);
|
||||
// add nas address
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6] = 4;
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 1] = 6;
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 2] = (uint8_t) ((urc->nas_address >> 24) & 0xff);
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 3] = (uint8_t) ((urc->nas_address >> 16) & 0xff);
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 4] = (uint8_t) ((urc->nas_address >> 8) & 0xff);
|
||||
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 5] = (uint8_t) (urc->nas_address & 0xff);
|
||||
|
||||
if (write(fd, access_request, access_request_len) != access_request_len) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// now wait for the response
|
||||
int ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) goto end;
|
||||
|
||||
ssize_t rlen = read(fd, access_request, access_request_len);
|
||||
// we need at least 4 + 16
|
||||
if (rlen >= 20) {
|
||||
char response_authenticator[16];
|
||||
if (access_request[1] != packet_identifier) goto end;
|
||||
if (rlen + urc->secret_len > 4096) goto end;
|
||||
// get the authenticator
|
||||
memcpy(response_authenticator, access_request+4, 16);
|
||||
// append the secret
|
||||
memcpy(access_request+rlen, urc->secret, urc->secret_len);
|
||||
// change the authenticator
|
||||
memcpy(access_request+4, authenticator, 16);
|
||||
// compute the md5
|
||||
if (!uwsgi_md5(access_request, rlen + urc->secret_len, md5_hash)) {
|
||||
goto end;
|
||||
}
|
||||
if (memcmp(md5_hash, response_authenticator, 16)) goto end;
|
||||
// Access-Accept
|
||||
if (access_request[0] == 2) {
|
||||
close(fd);
|
||||
return username_len;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_routing_func_radius(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
struct uwsgi_radius_conf *urc = (struct uwsgi_radius_conf *) ur->data2;
|
||||
|
||||
// skip if already authenticated
|
||||
if (wsgi_req->remote_user_len > 0) {
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
if (wsgi_req->authorization_len > 7) {
|
||||
if (strncmp(wsgi_req->authorization, "Basic ", 6))
|
||||
goto forbidden;
|
||||
|
||||
size_t auth_len = 0;
|
||||
char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len);
|
||||
if (auth) {
|
||||
uint16_t rlen = uwsgi_radius_auth(urc, auth, auth_len);
|
||||
if (rlen > 0) {
|
||||
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, rlen);
|
||||
free(auth);
|
||||
if (!wsgi_req->remote_user) goto forbidden;
|
||||
wsgi_req->remote_user_len = rlen;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
free(auth);
|
||||
if (ur->custom) return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
forbidden:
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
|
||||
char *realm = uwsgi_concat3n("Basic realm=\"", 13, urc->realm, urc->realm_len, "\"", 1);
|
||||
// no need to check for errors
|
||||
uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + urc->realm_len + 1);
|
||||
free(realm);
|
||||
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
|
||||
end:
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
static int uwsgi_router_radius(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_radius;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_radius_conf *urc = uwsgi_calloc(sizeof(struct uwsgi_radius_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"realm", &urc->realm,
|
||||
"server", &urc->server,
|
||||
"secret", &urc->secret,
|
||||
"nas_port", &urc->nas_port_str,
|
||||
"nas_address", &urc->nas_address_str,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!urc->realm || !urc->server || !urc->secret) {
|
||||
uwsgi_log("invalid radius route syntax: you need to specify a realm a server and a secret\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
urc->realm_len = strlen(urc->realm);
|
||||
urc->secret_len = strlen(urc->secret);
|
||||
|
||||
if (urc->nas_port_str) {
|
||||
urc->nas_port = strtoul(urc->nas_port_str, NULL, 10);
|
||||
}
|
||||
|
||||
if (!urc->nas_address_str) {
|
||||
urc->nas_address_str = uwsgi.hostname;
|
||||
}
|
||||
|
||||
struct hostent *he = gethostbyname(urc->nas_address_str);
|
||||
if (he) {
|
||||
if (he->h_addr_list[0]) {
|
||||
memcpy(&urc->nas_address, he->h_addr_list[0], 4);
|
||||
urc->nas_address = htonl(urc->nas_address);
|
||||
}
|
||||
}
|
||||
ur->data2 = urc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_radius_next(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 1;
|
||||
return uwsgi_router_radius(ur, args);
|
||||
}
|
||||
|
||||
static void router_radius_register(void) {
|
||||
uwsgi_register_router("radius", uwsgi_router_radius);
|
||||
uwsgi_register_router("radius-next", uwsgi_router_radius_next);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_radius_plugin = {
|
||||
.name = "router_radius",
|
||||
.on_load = router_radius_register,
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='router_radius'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['radius']
|
||||
@@ -1,13 +1,19 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
#include <uwsgi.h>
|
||||
|
||||
#include <gssapi/gssapi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
At the first request (without authentication) uWSGI sends back a token
|
||||
The client resend-the request with its token
|
||||
Following requests could need a new token or are simply accepted
|
||||
|
||||
*/
|
||||
|
||||
// log errors...
|
||||
static void uwsgi_spnego_err(OM_uint32 err_maj, OM_uint32 err_min) {
|
||||
static void uwsgi_spnego_err(const char *func, OM_uint32 err_maj, OM_uint32 err_min) {
|
||||
|
||||
OM_uint32 ret;
|
||||
OM_uint32 min_stat;
|
||||
@@ -21,11 +27,9 @@ static void uwsgi_spnego_err(OM_uint32 err_maj, OM_uint32 err_min) {
|
||||
&msg_ctx,
|
||||
&status_string);
|
||||
|
||||
if (GSS_ERROR(ret)) {
|
||||
return;
|
||||
}
|
||||
if (GSS_ERROR(ret)) return;
|
||||
|
||||
uwsgi_log("[uwsgi-spnego] error: %.*s\n", status_string.length, status_string.value);
|
||||
uwsgi_log("[uwsgi-spnego] %s() error (major): %.*s\n", func, status_string.length, status_string.value);
|
||||
|
||||
gss_release_buffer(&min_stat, &status_string);
|
||||
|
||||
@@ -36,73 +40,138 @@ static void uwsgi_spnego_err(OM_uint32 err_maj, OM_uint32 err_min) {
|
||||
&msg_ctx,
|
||||
&status_string);
|
||||
|
||||
if (GSS_ERROR(ret)) {
|
||||
return;
|
||||
if (GSS_ERROR(ret)) return;
|
||||
|
||||
if (status_string.length > 0) {
|
||||
uwsgi_log("[uwsgi-spnego] %s() error (minor): %.*s\n",func, status_string.length, status_string.value);
|
||||
}
|
||||
if (status_string.value) {
|
||||
gss_release_buffer(&min_stat, &status_string);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_log("[uwsgi-spnego] error: %.*s\n", status_string.length, status_string.value);
|
||||
|
||||
gss_release_buffer(&min_stat, &status_string);
|
||||
|
||||
}
|
||||
|
||||
static char *uwsgi_spnego_new_token(struct wsgi_request *wsgi_req, gss_cred_id_t cred, char *token_buf, size_t token_buf_len, size_t *b64_len) {
|
||||
static char *uwsgi_spnego_new_token(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *token_buf, size_t token_buf_len, size_t *b64_len) {
|
||||
|
||||
char *b64 = NULL;
|
||||
|
||||
OM_uint32 ret;
|
||||
OM_uint32 min_ret;
|
||||
|
||||
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
|
||||
gss_name_t client_name = GSS_C_NO_NAME;
|
||||
gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
|
||||
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
|
||||
if (ur->data_len) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) goto end;
|
||||
service.value = ub->buf;
|
||||
service.length = ub->pos;
|
||||
}
|
||||
|
||||
gss_name_t server_name = GSS_C_NO_NAME;
|
||||
gss_name_t client_name = GSS_C_NO_NAME;
|
||||
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
|
||||
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
|
||||
|
||||
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
|
||||
token.value = token_buf;
|
||||
token.length = token_buf_len;
|
||||
|
||||
if (service.length == 0) {
|
||||
service.value = "HTTP";
|
||||
service.length = 4;
|
||||
}
|
||||
|
||||
ret = gss_import_name(&min_ret, &service, GSS_C_NT_HOSTBASED_SERVICE, &server_name);
|
||||
if (GSS_ERROR(ret)) {
|
||||
uwsgi_spnego_err("gss_import_name", ret, min_ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
ret = gss_acquire_cred(&min_ret, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL, NULL);
|
||||
if (GSS_ERROR(ret)) {
|
||||
uwsgi_spnego_err("gss_acquire_cred", ret, min_ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
|
||||
ret = gss_accept_sec_context(&min_ret, &context, cred, &token, GSS_C_NO_CHANNEL_BINDINGS, &client_name, NULL, &output, NULL, NULL, NULL);
|
||||
|
||||
if (GSS_ERROR(ret)) {
|
||||
uwsgi_spnego_err(ret, min_ret);
|
||||
uwsgi_spnego_err("gss_accept_sec_context", ret, min_ret);
|
||||
if (output.value) {
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (output.length) {
|
||||
b64 = uwsgi_base64_encode(output.value, output.length, b64_len);
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
if (output.value) {
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
}
|
||||
if (!b64) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = gss_display_name(&min_ret, client_name, &output, NULL);
|
||||
if (GSS_ERROR(ret)) {
|
||||
uwsgi_spnego_err(ret, min_ret);
|
||||
uwsgi_spnego_err("gss_display_name", ret, min_ret);
|
||||
if (output.value) {
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
}
|
||||
free(b64);
|
||||
b64 = NULL;
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, output.value, output.length);
|
||||
if (!wsgi_req->remote_user) {
|
||||
if (output.value) {
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
}
|
||||
free(b64);
|
||||
b64 = NULL;
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->remote_user_len = output.length;
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
if (output.value) {
|
||||
gss_release_buffer(&min_ret, &output);
|
||||
}
|
||||
if (!wsgi_req->remote_user) {
|
||||
wsgi_req->remote_user_len = 0;
|
||||
uwsgi_spnego_err(ret, min_ret);
|
||||
free(b64);
|
||||
b64 = NULL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (context != GSS_C_NO_CONTEXT) {
|
||||
gss_delete_sec_context(&min_ret, &context, GSS_C_NO_BUFFER);
|
||||
if (server_name != GSS_C_NO_NAME) {
|
||||
gss_release_name(&min_ret, &server_name);
|
||||
}
|
||||
|
||||
if (client_name != GSS_C_NO_NAME) {
|
||||
gss_release_name(&min_ret, &client_name);
|
||||
}
|
||||
|
||||
if (cred != GSS_C_NO_CREDENTIAL) {
|
||||
gss_release_cred(&min_ret, &cred);
|
||||
}
|
||||
|
||||
if (context != GSS_C_NO_CONTEXT) {
|
||||
gss_delete_sec_context(&min_ret, &context, GSS_C_NO_BUFFER);
|
||||
}
|
||||
|
||||
|
||||
if (ub) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
return b64;
|
||||
}
|
||||
|
||||
@@ -111,7 +180,6 @@ static int uwsgi_routing_func_spnego(struct wsgi_request *wsgi_req, struct uwsgi
|
||||
|
||||
char *negotiate = NULL;
|
||||
size_t negotiate_len = 0;
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
size_t b64_len = 0;
|
||||
|
||||
// check for "Negotiate " string at least
|
||||
@@ -120,19 +188,18 @@ static int uwsgi_routing_func_spnego(struct wsgi_request *wsgi_req, struct uwsgi
|
||||
goto forbidden;
|
||||
|
||||
char *token = uwsgi_base64_decode(wsgi_req->authorization+10, wsgi_req->authorization_len-10, &b64_len);
|
||||
if (token && b64_len) {
|
||||
negotiate = uwsgi_spnego_new_token(wsgi_req, ur->data2, token, b64_len, &negotiate_len);
|
||||
if (token) {
|
||||
negotiate = uwsgi_spnego_new_token(wsgi_req, ur, token, b64_len, &negotiate_len);
|
||||
free(token);
|
||||
if (negotiate) {
|
||||
char *auth_header = uwsgi_concat2n("WWW-Authenticate: Negotiate ", 28, negotiate, negotiate_len);
|
||||
free(negotiate);
|
||||
uwsgi_additional_header_add(wsgi_req, auth_header, negotiate_len + 28);
|
||||
free(auth_header);
|
||||
if (ur->custom)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
return UWSGI_ROUTE_GOON;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
|
||||
}
|
||||
if (ur->custom) return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,8 +218,9 @@ forbidden:
|
||||
if (uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, "Negotiate", 9)) goto end;
|
||||
}
|
||||
|
||||
uwsgi_response_write_body(wsgi_req, "Unauthorized", 12);
|
||||
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
|
||||
end:
|
||||
if (ur->custom) return UWSGI_ROUTE_NEXT;
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
@@ -161,60 +229,25 @@ end:
|
||||
static int uwsgi_router_spnego(struct uwsgi_route *ur, char *args) {
|
||||
|
||||
ur->func = uwsgi_routing_func_spnego;
|
||||
|
||||
OM_uint32 ret;
|
||||
OM_uint32 min_ret;
|
||||
|
||||
gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
|
||||
service.value = args;
|
||||
service.length = strlen(args);
|
||||
|
||||
if (service.length == 0) {
|
||||
service.value = "HTTP";
|
||||
service.length = 4;
|
||||
ur->data = args ;
|
||||
if (args) {
|
||||
ur->data_len = strlen(args);
|
||||
}
|
||||
|
||||
gss_name_t server_name = GSS_C_NO_NAME;
|
||||
|
||||
ret = gss_import_name(&min_ret, &service, GSS_C_NT_HOSTBASED_SERVICE, &server_name);
|
||||
if (GSS_ERROR(ret)) {
|
||||
uwsgi_spnego_err(ret, min_ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
|
||||
|
||||
ret = gss_acquire_cred(&min_ret, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL, NULL);
|
||||
if (GSS_ERROR(ret)) {
|
||||
uwsgi_spnego_err(ret, min_ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ur->data2 = cred;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_spnego_last(struct uwsgi_route *ur, char *args) {
|
||||
uwsgi_router_spnego(ur, args);
|
||||
static int uwsgi_router_spnego_next(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 1;
|
||||
return 0;
|
||||
return uwsgi_router_spnego(ur, args);
|
||||
}
|
||||
|
||||
|
||||
static void router_spnego_register(void) {
|
||||
|
||||
uwsgi_register_router("spnego", uwsgi_router_spnego);
|
||||
uwsgi_register_router("spnego-last", uwsgi_router_spnego_last);
|
||||
uwsgi_register_router("spnego-next", uwsgi_router_spnego_next);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_spnego_plugin = {
|
||||
|
||||
.name = "router_spnego",
|
||||
.on_load = router_spnego_register,
|
||||
};
|
||||
#else
|
||||
struct uwsgi_plugin router_spnego_plugin = {
|
||||
.name = "router_spnego",
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import os
|
||||
NAME='router_spnego'
|
||||
|
||||
CFLAGS = []
|
||||
CFLAGS = os.popen('krb5-config --cflags gssapi').read().rstrip().split()
|
||||
LDFLAGS = []
|
||||
LIBS = ['-L' + os.popen('krb5-config --libs gssapi').read().rstrip()]
|
||||
LIBS = os.popen('krb5-config --libs gssapi').read().rstrip().split()
|
||||
|
||||
GCC_LIST = ['router_spnego']
|
||||
|
||||
@@ -247,9 +247,6 @@ static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsg
|
||||
else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
|
||||
ret = UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
else if (!uwsgi_strncmp(response, size, "goon", 4 )) {
|
||||
ret = UWSGI_ROUTE_GOON;
|
||||
}
|
||||
else if (!uwsgi_starts_with(response, size, "break", 5 )) {
|
||||
ret = UWSGI_ROUTE_BREAK;
|
||||
if (size > 6) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stackless_api.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
struct ustackless {
|
||||
int enabled;
|
||||
@@ -9,16 +10,22 @@ struct ustackless {
|
||||
PyTaskletObject **sl;
|
||||
} usl;
|
||||
|
||||
struct uwsgi_option stackless_options[] = {
|
||||
static void gil_stackless_get() {
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
|
||||
}
|
||||
|
||||
static void gil_stackless_release() {
|
||||
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
|
||||
}
|
||||
|
||||
static struct uwsgi_option stackless_options[] = {
|
||||
{"stackless", no_argument, 0, "use stackless as suspend engine", uwsgi_opt_true, &usl.enabled, 0},
|
||||
{ 0, 0, 0, 0 }
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
|
||||
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
static PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
|
||||
|
||||
async_schedule_to_req_green();
|
||||
Py_DECREF(usl.sl[uwsgi.wsgi_req->async_id]);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
@@ -27,9 +34,13 @@ PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
|
||||
|
||||
PyMethodDef uwsgi_stackless_request_method[] = {{"uwsgi_stackless_request", py_uwsgi_stackless_request, METH_VARARGS, ""}};
|
||||
|
||||
static inline static void stackless_schedule_to_req() {
|
||||
static void stackless_schedule_to_req() {
|
||||
|
||||
int id = uwsgi.wsgi_req->async_id;
|
||||
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
|
||||
|
||||
// ensure gil
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (!uwsgi.wsgi_req->suspended) {
|
||||
usl.sl[id] = PyTasklet_New(NULL, usl.callable);
|
||||
@@ -39,46 +50,65 @@ static inline static void stackless_schedule_to_req() {
|
||||
uwsgi.wsgi_req->suspended = 1;
|
||||
}
|
||||
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->suspend) {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
PyTasklet_Run(usl.sl[id]);
|
||||
|
||||
if (uwsgi.wsgi_req->suspended) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// ensure gil
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
PyStackless_Schedule(Py_None, 1);
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
}
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
int stackless_init() {
|
||||
return 0;
|
||||
}
|
||||
static void stackless_init_apps(void) {
|
||||
|
||||
void stackless_init_apps(void) {
|
||||
if (!usl.enabled) return;
|
||||
|
||||
if (!usl.enabled) {
|
||||
return;
|
||||
if (uwsgi.async <= 1) {
|
||||
uwsgi_log("the stackless suspend engine requires async mode\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.has_threads) {
|
||||
up.gil_get = gil_stackless_get;
|
||||
up.gil_release = gil_stackless_release;
|
||||
}
|
||||
|
||||
// blindy call it as the stackless gil engine is already set
|
||||
UWSGI_GET_GIL
|
||||
|
||||
usl.sl = uwsgi_malloc( sizeof(PyTaskletObject *) * uwsgi.async );
|
||||
usl.callable = PyCFunction_New(uwsgi_stackless_request_method, NULL);
|
||||
Py_INCREF(usl.callable);
|
||||
uwsgi_log("enabled stackless engine\n");
|
||||
uwsgi.schedule_to_main = stackless_schedule_to_main;
|
||||
uwsgi.schedule_to_req = stackless_schedule_to_req;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_plugin stackless_plugin = {
|
||||
|
||||
.name = "stackless",
|
||||
.init = stackless_init,
|
||||
.init_apps = stackless_init_apps,
|
||||
.options = stackless_options,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ struct uwsgi_symcall {
|
||||
int (*symcall_function)(struct wsgi_request *);
|
||||
|
||||
struct uwsgi_string_list *rpc;
|
||||
struct uwsgi_string_list *post_fork;
|
||||
} usym;
|
||||
|
||||
struct uwsgi_plugin symcall_plugin;
|
||||
@@ -14,6 +15,7 @@ struct uwsgi_plugin symcall_plugin;
|
||||
static struct uwsgi_option uwsgi_symcall_options[] = {
|
||||
{"symcall", required_argument, 0, "load the specified C symbol as the symcall request handler", uwsgi_opt_set_str, &usym.symcall_function_name, 0},
|
||||
{"symcall-register-rpc", required_argument, 0, "load the specified C symbol as an RPC function (syntax: name function)", uwsgi_opt_add_string_list, &usym.rpc, 0},
|
||||
{"symcall-post-fork", required_argument, 0, "call the specified C symbol after each fork()", uwsgi_opt_add_string_list, &usym.post_fork, 0},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -66,6 +68,20 @@ static uint16_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_
|
||||
return casted_func(argc, argv, argvs, buffer);
|
||||
}
|
||||
|
||||
static void uwsgi_symcall_post_fork() {
|
||||
void (*func)(void);
|
||||
struct uwsgi_string_list *usl = usym.post_fork;
|
||||
while(usl) {
|
||||
func = dlsym(RTLD_DEFAULT, usl->value);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to find symbol \"%s\" in process address space\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
func();
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_plugin symcall_plugin = {
|
||||
|
||||
.name = "symcall",
|
||||
@@ -75,6 +91,7 @@ struct uwsgi_plugin symcall_plugin = {
|
||||
.request = uwsgi_symcall_request,
|
||||
.after_request = uwsgi_symcall_after_request,
|
||||
.rpc = uwsgi_symcall_rpc,
|
||||
.post_fork = uwsgi_symcall_post_fork,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#if defined(UWSGI_ROUTING)
|
||||
|
||||
/*
|
||||
|
||||
transfer-encoding is added to the headers
|
||||
|
||||
*/
|
||||
|
||||
static int transform_chunked(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
|
||||
if (ut->is_final) {
|
||||
if (uwsgi_buffer_append(ub, "0\r\n\r\n", 5)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ut->round == 1) {
|
||||
// do not check for errors !!!
|
||||
uwsgi_response_add_header(wsgi_req, "Transfer-Encoding", 17, "chunked", 7);
|
||||
}
|
||||
|
||||
if (ub->pos > 0) {
|
||||
if (uwsgi_buffer_insert_chunked(ub, 0, ub->pos)) return -1;
|
||||
if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_routing_func_chunked(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL);
|
||||
ut->can_stream = 1;
|
||||
// add a "final" transformation to add the trailing chunk
|
||||
ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL);
|
||||
ut->is_final = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_chunked(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_chunked;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void router_chunked_register(void) {
|
||||
uwsgi_register_router("chunked", uwsgi_router_chunked);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin transformation_chunked_plugin = {
|
||||
.name = "transformation_chunked",
|
||||
.on_load = router_chunked_register,
|
||||
};
|
||||
#else
|
||||
struct uwsgi_plugin transformation_chunked_plugin = {
|
||||
.name = "transformation_chunked",
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='transformation_chunked'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['chunked']
|
||||
@@ -4,27 +4,62 @@
|
||||
|
||||
/*
|
||||
|
||||
gzip transformations reset your headers !!!
|
||||
gzip transformations add content-encoding to your headers and changes the final size !!!
|
||||
|
||||
remember to re-add the content type via routing rules
|
||||
remember to fix the content_length (or use chunked encoding) !!!
|
||||
|
||||
*/
|
||||
|
||||
static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
|
||||
struct uwsgi_buffer *gzipped = uwsgi_gzip(ub->buf, ub->pos);
|
||||
if (!gzipped) {
|
||||
return -1;
|
||||
struct uwsgi_transformation_gzip {
|
||||
z_stream z;
|
||||
uint32_t crc32;
|
||||
size_t len;
|
||||
uint8_t header;
|
||||
};
|
||||
|
||||
extern char gzheader[];
|
||||
|
||||
static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
struct uwsgi_transformation_gzip *utgz = (struct uwsgi_transformation_gzip *) ut->data;
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
|
||||
if (ut->is_final) {
|
||||
if (uwsgi_gzip_fix(&utgz->z, utgz->crc32, ub, utgz->len)) {
|
||||
free(utgz);
|
||||
return -1;
|
||||
}
|
||||
free(utgz);
|
||||
return 0;
|
||||
}
|
||||
// use this new buffer
|
||||
*new = gzipped;
|
||||
if (uwsgi_response_prepare_headers_int(wsgi_req, wsgi_req->status)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, gzipped->pos)) return -1;
|
||||
|
||||
size_t dlen = 0;
|
||||
char *gzipped = uwsgi_gzip_chunk(&utgz->z, &utgz->crc32, ub->buf, ub->pos, &dlen);
|
||||
if (!gzipped) return -1;
|
||||
utgz->len += ub->pos;
|
||||
uwsgi_buffer_map(ub, gzipped, dlen);
|
||||
if (!utgz->header) {
|
||||
// do not check for errors !!!
|
||||
uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4);
|
||||
utgz->header = 1;
|
||||
if (uwsgi_buffer_insert(ub, 0, gzheader, 10)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_routing_func_gzip(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
uwsgi_add_transformation(wsgi_req, transform_gzip, NULL);
|
||||
struct uwsgi_transformation_gzip *utgz = uwsgi_calloc(sizeof(struct uwsgi_transformation_gzip));
|
||||
if (uwsgi_gzip_prepare(&utgz->z, NULL, 0, &utgz->crc32)) {
|
||||
free(utgz);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
|
||||
ut->can_stream = 1;
|
||||
// this is the trasformation clearing the memory
|
||||
ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
|
||||
ut->is_final = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,15 @@ struct uwsgi_transformation_tofile_conf {
|
||||
struct uwsgi_buffer *filename;
|
||||
};
|
||||
|
||||
static int transform_tofile(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
|
||||
struct uwsgi_transformation_tofile_conf *uttc = (struct uwsgi_transformation_tofile_conf *) data;
|
||||
static int transform_tofile(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
|
||||
struct uwsgi_transformation_tofile_conf *uttc = (struct uwsgi_transformation_tofile_conf *) ut->data;
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
|
||||
// store only successfull response
|
||||
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
|
||||
if (uttc->filename) {
|
||||
int fd = open(uttc->filename->buf, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
int fd = open(uttc->filename->buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(uttc->filename->buf);
|
||||
goto end;
|
||||
@@ -56,6 +58,7 @@ end:
|
||||
// free resources
|
||||
if (uttc->filename) uwsgi_buffer_destroy(uttc->filename);
|
||||
free(uttc);
|
||||
// reset the buffer
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
static int transform_toupper(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **foobar, void *data) {
|
||||
static int transform_toupper(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
size_t i;
|
||||
for(i=0;i<ub->pos;i++) {
|
||||
ub->buf[i] = toupper((int) ub->buf[i]);
|
||||
for(i=0;i<ut->chunk->pos;i++) {
|
||||
ut->chunk->buf[i] = toupper((int) ut->chunk->buf[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_routing_func_toupper(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
uwsgi_add_transformation(wsgi_req, transform_toupper, NULL);
|
||||
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_toupper, NULL);
|
||||
ut->can_stream = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
+15
-25
@@ -21,47 +21,35 @@ struct uwsgi_ugreen {
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_option ugreen_options[] = {
|
||||
{"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 1},
|
||||
static struct uwsgi_option ugreen_options[] = {
|
||||
{"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 0},
|
||||
{"ugreen-stacksize", required_argument, 0, "set ugreen stack size in pages", uwsgi_opt_set_int, &ug.stackpages, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void u_green_request() {
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// end of the request
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
}
|
||||
|
||||
static void u_green_schedule_to_req() {
|
||||
|
||||
int id = uwsgi.wsgi_req->async_id;
|
||||
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
|
||||
|
||||
// first round ?
|
||||
if (!uwsgi.wsgi_req->suspended) {
|
||||
ug.contexts[id].uc_link = &ug.main;
|
||||
makecontext(&ug.contexts[id], u_green_request, 0);
|
||||
makecontext(&ug.contexts[id], async_schedule_to_req_green, 0);
|
||||
uwsgi.wsgi_req->suspended = 1;
|
||||
}
|
||||
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->suspend(NULL);
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->suspend) {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
// save the main stack and switch to the core
|
||||
swapcontext(&ug.main, &ug.contexts[id] );
|
||||
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
if (uwsgi.wsgi_req->suspended) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,7 +60,9 @@ static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
|
||||
// back to main
|
||||
swapcontext(&ug.contexts[wsgi_req->async_id], &ug.main);
|
||||
// back to core
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
@@ -82,7 +72,7 @@ static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
|
||||
int u_green_init() {
|
||||
static int u_green_init() {
|
||||
|
||||
static int i;
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import os
|
||||
|
||||
NAME='webdav'
|
||||
CFLAGS = os.popen('xml2-config --cflags').read().rstrip().split()
|
||||
LDFLAGS = []
|
||||
LIBS = os.popen('xml2-config --libs').read().rstrip().split()
|
||||
|
||||
GCC_LIST = ['webdav']
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
NAME='xattr'
|
||||
CFLAGS=[]
|
||||
LDFLAGS=[]
|
||||
LIBS=[]
|
||||
GCC_LIST = ['xattr']
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
xattr-related plugin
|
||||
|
||||
exposes two routing vars:
|
||||
|
||||
file is a var, key is a string
|
||||
${xattr[PATH_INFO:user.uwsgi.webdav.foobar]}
|
||||
|
||||
file is a var, key is a var
|
||||
${xattr2[PATH_INFO:MYKEY]}
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include <attr/xattr.h>
|
||||
#endif
|
||||
|
||||
static char *uwsgi_route_var_xattr(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
char *colon = memchr(key, ':', keylen);
|
||||
if (!colon) return NULL;
|
||||
uint16_t var_vallen = 0;
|
||||
char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen);
|
||||
if (var_value) {
|
||||
char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0);
|
||||
char *name = uwsgi_concat2n(colon+1, (keylen-1) - (colon-key), "", 0);
|
||||
ssize_t rlen = getxattr(filename, name, NULL, 0);
|
||||
if (rlen > 0) {
|
||||
char *value = uwsgi_calloc(rlen);
|
||||
getxattr(filename, name, value, rlen);
|
||||
*vallen = rlen;
|
||||
free(filename);
|
||||
free(name);
|
||||
return value;
|
||||
}
|
||||
free(filename);
|
||||
free(name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *uwsgi_route_var_xattr2(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
char *colon = memchr(key, ':', keylen);
|
||||
if (!colon) return NULL;
|
||||
uint16_t var_vallen = 0;
|
||||
char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen);
|
||||
if (var_value) {
|
||||
uint16_t var2_vallen = 0;
|
||||
char *var2_value = uwsgi_get_var(wsgi_req, colon+1, (keylen-1) - (colon-key), &var2_vallen);
|
||||
if (var2_value) {
|
||||
char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0);
|
||||
char *name = uwsgi_concat2n(var2_value, var2_vallen, "", 0);
|
||||
ssize_t rlen = getxattr(filename, name, NULL, 0);
|
||||
if (rlen > 0) {
|
||||
char *value = uwsgi_calloc(rlen);
|
||||
getxattr(filename, name, value, rlen);
|
||||
*vallen = rlen;
|
||||
free(filename);
|
||||
free(name);
|
||||
return value;
|
||||
}
|
||||
free(filename);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void register_route_vars_xattr() {
|
||||
struct uwsgi_route_var *urv = uwsgi_register_route_var("xattr", uwsgi_route_var_xattr);
|
||||
urv->need_free = 1;
|
||||
urv = uwsgi_register_route_var("xattr2", uwsgi_route_var_xattr2);
|
||||
urv->need_free = 1;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin xattr_plugin = {
|
||||
.name = "xattr",
|
||||
.on_load = register_route_vars_xattr,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import os
|
||||
|
||||
NAME='xslt'
|
||||
CFLAGS = os.popen('xslt-config --cflags').read().rstrip().split()
|
||||
LDFLAGS = os.popen('xslt-config --libs').read().rstrip().split()
|
||||
LIBS = []
|
||||
LDFLAGS = []
|
||||
LIBS = os.popen('xslt-config --libs').read().rstrip().split()
|
||||
|
||||
GCC_LIST = ['xslt']
|
||||
|
||||
+10
-15
@@ -282,7 +282,7 @@ apply:
|
||||
return UWSGI_OK;
|
||||
}
|
||||
output = uwsgi_xslt_apply(doc, stylesheet, params, &output_rlen);
|
||||
xmlFree(doc);
|
||||
xmlFreeDoc(doc);
|
||||
if (params) free(params);
|
||||
if (!output) {
|
||||
uwsgi_500(wsgi_req);
|
||||
@@ -316,9 +316,10 @@ static void uwsgi_xslt_log(struct wsgi_request *wsgi_req) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
static int transform_toxslt(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
|
||||
static int transform_toxslt(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
int ret = -1;
|
||||
struct uwsgi_transformation_xslt_conf *utxc = (struct uwsgi_transformation_xslt_conf *) data;
|
||||
struct uwsgi_transformation_xslt_conf *utxc = (struct uwsgi_transformation_xslt_conf *) ut->data;
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
|
||||
xmlDoc *doc = xmlReadMemory(ub->buf, ub->pos, NULL, NULL, 0);
|
||||
if (!doc) goto end;
|
||||
@@ -327,18 +328,12 @@ static int transform_toxslt(struct wsgi_request *wsgi_req, struct uwsgi_buffer *
|
||||
char *output = uwsgi_xslt_apply( doc, utxc->stylesheet->buf, utxc->params ? utxc->params->buf : NULL, &rlen);
|
||||
if (!output) goto end;
|
||||
|
||||
if (uwsgi_response_prepare_headers_int(wsgi_req, wsgi_req->status)) goto end;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, rlen)) goto end;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, utxc->content_type->buf, utxc->content_type->pos)) goto end;
|
||||
|
||||
*new = uwsgi_buffer_new(rlen);
|
||||
if (uwsgi_buffer_append(*new, output, rlen)) {
|
||||
xmlFree(output);
|
||||
uwsgi_buffer_destroy(*new);
|
||||
*new = NULL;
|
||||
goto end;
|
||||
// do not check for errors !!!
|
||||
if (ut->round == 1) {
|
||||
uwsgi_response_add_content_type(wsgi_req, utxc->content_type->buf, utxc->content_type->pos);
|
||||
}
|
||||
xmlFree(output);
|
||||
|
||||
uwsgi_buffer_map(ub, output, rlen);
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
@@ -413,7 +408,7 @@ static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
xmlDoc *doc = xmlParseFile(ub_doc->buf) ;
|
||||
if (!doc) goto end;
|
||||
char *output = uwsgi_xslt_apply(doc, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen);
|
||||
xmlFree(doc);
|
||||
xmlFreeDoc(doc);
|
||||
if (!output) goto end;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
|
||||
|
||||
+2
-2
@@ -107,7 +107,7 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
free(path_info);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("not enough space in wsgi_req http proto_parser_buf to encode PATH_INFO, consider tuning it with --buffer-size\n");
|
||||
uwsgi_log("not enough space in wsgi_req http proto_parser_buf to decode PATH_INFO, consider tuning it with --buffer-size\n");
|
||||
return -1;
|
||||
}
|
||||
query_string = ptr + 1;
|
||||
@@ -124,7 +124,7 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
free(path_info);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("not enough space in wsgi_req http proto_parser_buf to encode PATH_INFO, consider tuning it with --buffer-size\n");
|
||||
uwsgi_log("not enough space in wsgi_req http proto_parser_buf to decode PATH_INFO, consider tuning it with --buffer-size\n");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
|
||||
|
||||
@@ -4,6 +4,7 @@ import "uwsgi"
|
||||
import "net/http"
|
||||
import "fmt"
|
||||
import "io/ioutil"
|
||||
import "os"
|
||||
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -24,6 +25,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(os.Args)
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/post/", postHandler)
|
||||
uwsgi.Run()
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
[uwsgi]
|
||||
http-socket = :9090
|
||||
module = werkzeug.testapp:test_app
|
||||
|
||||
; allows up to 100 authenticated users
|
||||
cache = 100
|
||||
master = true
|
||||
|
||||
; check if a uwsgiauth cookie is available
|
||||
route-if-not = empty:${cookie[uwsgiauth]} goto:cookieauth
|
||||
|
||||
; 2 users
|
||||
route-run = basicauth-next:Test0001,uno:due
|
||||
route-run = basicauth:Test0001,test:foo
|
||||
|
||||
; create an uuid for authorization and place it in AUTH_UUID request var
|
||||
route-run = addvar:AUTH_UUID=${uwsgi[uuid]}
|
||||
; place it in the cache as REMOTE_USER:REMOTE_ADDR for 1 hour
|
||||
route-run = cacheset:key=${AUTH_UUID},value=${REMOTE_USER}:${REMOTE_ADDR},expires=3600
|
||||
; set the auth cookie
|
||||
route-run = addheader:Set-Cookie: uwsgiauth=${AUTH_UUID}; Expires=${httptime[3600]}
|
||||
; continue to the request plugin handler
|
||||
route-run = last:
|
||||
|
||||
; here we manage the cookie (with some logging for debug)
|
||||
route-label = cookieauth
|
||||
route-run = log:COOKIE FOUND
|
||||
; set AUTH_UUID with the cookie value
|
||||
route-run = addvar:AUTH_UUID=${cookie[uwsgiauth]}
|
||||
route-run = log:AUTH_UUID=${AUTH_UUID}
|
||||
; get the cache value and place it in the var
|
||||
route-run = cachevar:key=${AUTH_UUID},var=AUTH_VALUE
|
||||
route-run = log:AUTH_VALUE=${AUTH_VALUE}
|
||||
; if the item is not found reset credentials
|
||||
route-if = empty:${AUTH_VALUE} goto:reset
|
||||
; check if the cookie is valid for the remote address
|
||||
route-if-not = endswith:${AUTH_VALUE};:${REMOTE_ADDR} goto:reset
|
||||
route-run = log:OK
|
||||
; set REMOTE_USER (the parser stops at the first colon)
|
||||
route-run = setuser:${AUTH_VALUE}
|
||||
; set the auth cookie (could be useless when using some framework)
|
||||
route-run = addheader:Set-Cookie: uwsgiauth=${AUTH_UUID}
|
||||
route-run = last:
|
||||
|
||||
; reset credentials
|
||||
route-label = reset
|
||||
route-run = log:RESETTING CREDENTIALS
|
||||
route-run = addheader:Set-Cookie: uwsgiauth=invalid; expires=Thu, 01 Jan 1970 00:00:00 GMT
|
||||
; force a 401
|
||||
route-run = basicauth:Test0001,
|
||||
@@ -0,0 +1,35 @@
|
||||
[uwsgi]
|
||||
plugins = geoip, router_cache
|
||||
http-socket = :9090
|
||||
|
||||
; 8 bytes blocksize is the right thing to do
|
||||
cache2 = name=limiter,items=1000,blocksize=8
|
||||
; allows expiring items
|
||||
master = true
|
||||
|
||||
; get the cache value for the current ip (if any)
|
||||
route-run = cachevar:key=${REMOTE_ADDR},as_num=1,var=LIMIT
|
||||
; block the peer if it did more than 10 404 requests in the last 30 seconds
|
||||
route-if = >:${LIMIT};10 goto:blockit
|
||||
; end of routing
|
||||
route-run = last:
|
||||
|
||||
|
||||
module = werkzeug.testapp:test_app
|
||||
threads = 10
|
||||
|
||||
; track the user if a 404 is returned
|
||||
final-route-if = equal:${uwsgi[status]};404 goto:trackit
|
||||
; end of final routing
|
||||
final-route-run = last:
|
||||
|
||||
final-route-label = trackit
|
||||
; increase the value in the 'limiter' cache
|
||||
final-route-run = cacheinc:key=${REMOTE_ADDR},expires=30
|
||||
; increase the value if the connection is from italy !!!
|
||||
final-route-if = equal:${geoip[country_name]};Italy cacheinc:key=${REMOTE_ADDR},expires=30
|
||||
|
||||
; block the client
|
||||
route-label = blockit
|
||||
route-run = log:STOP YOU BASTARD !!!
|
||||
route-run = break:503
|
||||
@@ -0,0 +1,24 @@
|
||||
[uwsgi]
|
||||
http-socket = :9090
|
||||
|
||||
; 8 bytes blocksize is the right thing to do
|
||||
cache2 = name=limiter,items=1000,blocksize=8
|
||||
; allows expiring items
|
||||
master = true
|
||||
|
||||
; get the cache value for the current ip (if any)
|
||||
route-run = cachevar:key=${REMOTE_ADDR},as_num=1,var=LIMIT
|
||||
; block the peer if it did more than 10 requests in the last 30 seconds
|
||||
route-if = >:${LIMIT};10 goto:blockit
|
||||
; increment the value (expires value will not be updated)
|
||||
route-run = cacheinc:key=${REMOTE_ADDR},expires=30
|
||||
; end of the checks
|
||||
route-run = last:
|
||||
|
||||
module = werkzeug.testapp:test_app
|
||||
threads = 10
|
||||
|
||||
; block the client
|
||||
route-label = blockit
|
||||
route-run = log:STOP YOU BASTARD !!!
|
||||
route-run = break:503
|
||||
@@ -0,0 +1,16 @@
|
||||
#! uwsgi -S addressbook=./carddav carddav.ini
|
||||
[uwsgi]
|
||||
plugin = webdav
|
||||
|
||||
http-socket = :9090
|
||||
http-socket-modifier1 = 35
|
||||
|
||||
route-run = basicauth:CardDav uWSGI server,unbit:unbit
|
||||
|
||||
webdav-add-option = addressbook
|
||||
webdav-principal-base = /principals/users/
|
||||
|
||||
webdav-add-prop-href = urn:ietf:params:xml:ns:carddav addressbook-home-set /principals/users/unbit
|
||||
webdav-add-rtype-collection-prop = urn:ietf:params:xml:ns:carddav addressbook
|
||||
webdav-mount = %(addressbook)
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
|
||||
s.name = 'uwsgi'
|
||||
s.license = 'GPL-2'
|
||||
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
|
||||
s.date = '2013-04-22'
|
||||
s.date = '2013-05-11'
|
||||
s.summary = "uWSGI"
|
||||
s.description = "The uWSGI server for Ruby/Rack"
|
||||
s.authors = ["Unbit"]
|
||||
|
||||
@@ -9,7 +9,8 @@ extern "C" {
|
||||
#define UMAX16 65536
|
||||
#define UMAX8 256
|
||||
|
||||
#define UMAX64_STR "18446744073709551616"
|
||||
#define UMAX64_STR "18446744073709551615"
|
||||
#define MAX64_STR "−9223372036854775808"
|
||||
|
||||
#define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
|
||||
#define uwsgi_error_realpath(x) uwsgi_log("realpath() of %s failed: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
|
||||
@@ -242,7 +243,9 @@ extern int pivot_root(const char *new_root, const char *put_old);
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifndef MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
|
||||
#endif
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
@@ -311,9 +314,15 @@ extern int pivot_root(const char *new_root, const char *put_old);
|
||||
#endif
|
||||
|
||||
#define UWSGI_CACHE_FLAG_UNGETTABLE 0x01
|
||||
#define UWSGI_CACHE_FLAG_UPDATE 0x02
|
||||
#define UWSGI_CACHE_FLAG_LOCAL 0x04
|
||||
#define UWSGI_CACHE_FLAG_ABSEXPIRE 0x08
|
||||
#define UWSGI_CACHE_FLAG_UPDATE 1 << 1
|
||||
#define UWSGI_CACHE_FLAG_LOCAL 1 << 2
|
||||
#define UWSGI_CACHE_FLAG_ABSEXPIRE 1 << 3
|
||||
#define UWSGI_CACHE_FLAG_MATH 1 << 4
|
||||
#define UWSGI_CACHE_FLAG_INC 1 << 5
|
||||
#define UWSGI_CACHE_FLAG_DEC 1 << 6
|
||||
#define UWSGI_CACHE_FLAG_MUL 1 << 7
|
||||
#define UWSGI_CACHE_FLAG_DIV 1 << 8
|
||||
#define UWSGI_CACHE_FLAG_FIXEXPIRE 1 << 9
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
#include "openssl/conf.h"
|
||||
@@ -540,6 +549,10 @@ struct uwsgi_daemon {
|
||||
// frequency of pidfile checks (default 10 secs)
|
||||
int freq;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
char *legion;
|
||||
#endif
|
||||
|
||||
struct uwsgi_daemon *next;
|
||||
};
|
||||
|
||||
@@ -727,7 +740,7 @@ struct uwsgi_cache {
|
||||
uint64_t filesize;
|
||||
uint64_t store_sync;
|
||||
|
||||
int thread_server_fd;
|
||||
int64_t math_initial;
|
||||
|
||||
struct uwsgi_string_list *nodes;
|
||||
int udp_node_socket;
|
||||
@@ -1049,15 +1062,18 @@ struct uwsgi_spooler {
|
||||
#define UWSGI_ROUTE_CONTINUE 1
|
||||
// close the request
|
||||
#define UWSGI_ROUTE_BREAK 2
|
||||
// go to the next group of routes
|
||||
#define UWSGI_ROUTE_GOON 3
|
||||
|
||||
struct uwsgi_route {
|
||||
|
||||
pcre *pattern;
|
||||
pcre_extra *pattern_extra;
|
||||
int ovn;
|
||||
int *ovector;
|
||||
|
||||
char *orig_route;
|
||||
|
||||
// one for each core
|
||||
int *ovn;
|
||||
int **ovector;
|
||||
struct uwsgi_buffer **condition_ub;
|
||||
|
||||
char *subject_str;
|
||||
size_t subject_str_len;
|
||||
@@ -1081,9 +1097,6 @@ struct uwsgi_route {
|
||||
// 64bit value for custom usage
|
||||
uint64_t custom;
|
||||
|
||||
// true ifthis is the last rule of this kind
|
||||
int is_last;
|
||||
|
||||
uint64_t pos;
|
||||
char *label;
|
||||
size_t label_len;
|
||||
@@ -1195,8 +1208,13 @@ struct uwsgi_logvar {
|
||||
};
|
||||
|
||||
struct uwsgi_transformation {
|
||||
int (*func)(struct wsgi_request *, struct uwsgi_buffer *, struct uwsgi_buffer **, void *);
|
||||
int (*func)(struct wsgi_request *, struct uwsgi_transformation *);
|
||||
struct uwsgi_buffer *chunk;
|
||||
uint8_t can_stream;
|
||||
uint8_t is_final;
|
||||
uint8_t flushed;
|
||||
void *data;
|
||||
uint64_t round;
|
||||
struct uwsgi_transformation *next;
|
||||
};
|
||||
|
||||
@@ -1407,14 +1425,16 @@ struct wsgi_request {
|
||||
|
||||
// avoid routing loops
|
||||
int is_routing;
|
||||
int is_final_routing;
|
||||
int routes_applied;
|
||||
// internal routing vm program counter
|
||||
uint32_t route_pc;
|
||||
// internal routing goto instruction
|
||||
uint32_t route_goto;
|
||||
|
||||
struct uwsgi_buffer *response_buffer;
|
||||
struct uwsgi_transformation *transformations;
|
||||
char *transformed_chunk;
|
||||
size_t transformed_chunk_len;
|
||||
|
||||
struct msghdr msg;
|
||||
union {
|
||||
@@ -1844,6 +1864,7 @@ struct uwsgi_server {
|
||||
struct uwsgi_string_list *alarm_logs_list;
|
||||
struct uwsgi_alarm_fd *alarm_fds;
|
||||
struct uwsgi_string_list *alarm_fd_list;
|
||||
struct uwsgi_string_list *alarm_segfault;
|
||||
struct uwsgi_alarm *alarms;
|
||||
struct uwsgi_alarm_instance *alarm_instances;
|
||||
struct uwsgi_alarm_log *alarm_logs;
|
||||
@@ -1932,7 +1953,6 @@ struct uwsgi_server {
|
||||
struct wsgi_request **async_proto_fd_table;
|
||||
struct uwsgi_async_request *async_runqueue;
|
||||
struct uwsgi_async_request *async_runqueue_last;
|
||||
int async_runqueue_cnt;
|
||||
|
||||
struct uwsgi_rbtree *rb_async_timeouts;
|
||||
|
||||
@@ -1961,6 +1981,7 @@ struct uwsgi_server {
|
||||
struct uwsgi_string_list *touch_gracefully_stop;
|
||||
struct uwsgi_string_list *touch_logrotate;
|
||||
struct uwsgi_string_list *touch_logreopen;
|
||||
struct uwsgi_string_list *touch_exec;
|
||||
|
||||
int propagate_touch;
|
||||
|
||||
@@ -2093,6 +2114,7 @@ struct uwsgi_server {
|
||||
#ifdef UWSGI_ROUTING
|
||||
struct uwsgi_router *routers;
|
||||
struct uwsgi_route *routes;
|
||||
struct uwsgi_route *final_routes;
|
||||
struct uwsgi_route_condition *route_conditions;
|
||||
struct uwsgi_route_var *route_vars;
|
||||
#endif
|
||||
@@ -2557,9 +2579,8 @@ int bind_to_udp(char *, int, int);
|
||||
int bind_to_unix_dgram(char *);
|
||||
int timed_connect(struct pollfd *, const struct sockaddr *, int, int, int);
|
||||
int uwsgi_connect(char *, int, int);
|
||||
int uwsgi_connect_udp(char *);
|
||||
int uwsgi_connectn(char *, uint16_t, int, int);
|
||||
int connect_to_tcp(char *, int, int, int);
|
||||
int connect_to_unix(char *, int, int);
|
||||
|
||||
void daemonize(char *);
|
||||
void logto(char *);
|
||||
@@ -2620,9 +2641,11 @@ struct wsgi_request *find_first_available_wsgi_req(void);
|
||||
struct wsgi_request *find_first_accepting_wsgi_req(void);
|
||||
struct wsgi_request *find_wsgi_req_by_fd(int);
|
||||
struct wsgi_request *find_wsgi_req_by_id(int);
|
||||
void async_schedule_to_req_green(void);
|
||||
|
||||
int async_add_fd_write(struct wsgi_request *, int, int);
|
||||
int async_add_fd_read(struct wsgi_request *, int, int);
|
||||
void async_reset_request(struct wsgi_request *);
|
||||
|
||||
struct wsgi_request *next_wsgi_req(struct wsgi_request *);
|
||||
|
||||
@@ -2740,6 +2763,7 @@ struct uwsgi_cache *uwsgi_cache_by_namelen(char *, uint16_t);
|
||||
void uwsgi_cache_create_all(void);
|
||||
void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *);
|
||||
void uwsgi_cache_setup_nodes(struct uwsgi_cache *);
|
||||
int64_t uwsgi_cache_num2(struct uwsgi_cache *, char *, uint16_t);
|
||||
|
||||
void uwsgi_cache_sync_all(void);
|
||||
void uwsgi_cache_start_sweepers(void);
|
||||
@@ -2802,12 +2826,14 @@ void uwsgi_gateway_go_cheap(char *, int, int *);
|
||||
|
||||
char *uwsgi_open_and_read(char *, size_t *, int, char *[]);
|
||||
char *uwsgi_get_last_char(char *, char);
|
||||
char *uwsgi_get_last_charn(char *, size_t, char);
|
||||
|
||||
void uwsgi_spawn_daemon(struct uwsgi_daemon *);
|
||||
void uwsgi_detach_daemons();
|
||||
|
||||
void emperor_loop(void);
|
||||
char *uwsgi_num2str(int);
|
||||
char *uwsgi_64bit2str(int64_t);
|
||||
|
||||
char *magic_sub(char *, size_t, size_t *, char *[]);
|
||||
void init_magic_table(char *[]);
|
||||
@@ -3054,6 +3080,7 @@ void uwsgi_fixup_fds(int, int, struct uwsgi_gateway *);
|
||||
void uwsgi_set_processname(char *);
|
||||
|
||||
void http_url_decode(char *, uint16_t *, char *);
|
||||
void http_url_encode(char *, uint16_t *, char *);
|
||||
|
||||
pid_t uwsgi_fork(char *);
|
||||
|
||||
@@ -3302,12 +3329,14 @@ char *uwsgi_tmpname(char *, char *);
|
||||
struct uwsgi_router *uwsgi_register_router(char *, int (*)(struct uwsgi_route *, char *));
|
||||
void uwsgi_opt_add_route(char *, char *, void *);
|
||||
int uwsgi_apply_routes(struct wsgi_request *);
|
||||
int uwsgi_apply_routes_do(struct wsgi_request *, char *, uint16_t);
|
||||
void uwsgi_apply_final_routes(struct wsgi_request *);
|
||||
int uwsgi_apply_routes_do(struct uwsgi_route *, struct wsgi_request *, char *, uint16_t);
|
||||
void uwsgi_register_embedded_routers(void);
|
||||
void uwsgi_routing_dump();
|
||||
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *, struct uwsgi_route *, char *, uint16_t, char *, size_t);
|
||||
int uwsgi_route_api_func(struct wsgi_request *, char *, char *);
|
||||
struct uwsgi_route_condition *uwsgi_register_route_condition(char *, int (*) (struct wsgi_request *, struct uwsgi_route *));
|
||||
void uwsgi_fixup_routes(struct uwsgi_route *);
|
||||
#endif
|
||||
|
||||
void uwsgi_reload(char **);
|
||||
@@ -3450,6 +3479,7 @@ int uwsgi_subscription_sign_check(struct uwsgi_subscribe_slot *, struct uwsgi_su
|
||||
|
||||
char *uwsgi_sha1(char *, size_t, char *);
|
||||
char *uwsgi_sha1_2n(char *, size_t, char *, size_t, char *);
|
||||
char *uwsgi_md5(char *, size_t, char *);
|
||||
#endif
|
||||
|
||||
void uwsgi_opt_ssa(char *, char *, void *);
|
||||
@@ -3601,6 +3631,7 @@ int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *, size_t, size_t);
|
||||
int uwsgi_buffer_append_chunked(struct uwsgi_buffer *, size_t);
|
||||
int uwsgi_buffer_append_json(struct uwsgi_buffer *, char *, size_t);
|
||||
int uwsgi_buffer_set_uh(struct uwsgi_buffer *, uint8_t, uint8_t);
|
||||
void uwsgi_buffer_map(struct uwsgi_buffer *, char *, size_t);
|
||||
struct uwsgi_buffer *uwsgi_buffer_from_file(char *);
|
||||
|
||||
ssize_t uwsgi_buffer_write_simple(struct wsgi_request *, struct uwsgi_buffer *);
|
||||
@@ -3796,6 +3827,7 @@ int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, u
|
||||
int uwsgi_response_prepare_headers(struct wsgi_request *, char *, uint16_t);
|
||||
int uwsgi_response_prepare_headers_int(struct wsgi_request *, int);
|
||||
int uwsgi_response_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_response_add_header_force(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_response_commit_headers(struct wsgi_request *);
|
||||
int uwsgi_response_sendfile_do(struct wsgi_request *, int, size_t, size_t);
|
||||
|
||||
@@ -3819,6 +3851,8 @@ int uwsgi_proto_base_fix_headers(struct wsgi_request *);
|
||||
int uwsgi_response_add_content_length(struct wsgi_request *, uint64_t);
|
||||
int uwsgi_response_add_content_range(struct wsgi_request *, uint64_t, uint64_t, uint64_t);
|
||||
int uwsgi_response_add_expires(struct wsgi_request *, uint64_t);
|
||||
int uwsgi_response_add_last_modified(struct wsgi_request *, uint64_t);
|
||||
int uwsgi_response_add_date(struct wsgi_request *, char *, uint16_t, uint64_t);
|
||||
|
||||
const char *uwsgi_http_status_msg(char *, uint16_t *);
|
||||
int uwsgi_stats_dump_vars(struct uwsgi_stats *, struct uwsgi_core *);
|
||||
@@ -3928,6 +3962,9 @@ int uwsgi_deflate_init(z_stream *, char *, size_t);
|
||||
char *uwsgi_deflate(z_stream *, char *, size_t, size_t *);
|
||||
void uwsgi_crc32(uint32_t *, char *, size_t);
|
||||
struct uwsgi_buffer *uwsgi_gzip(char *, size_t);
|
||||
int uwsgi_gzip_fix(z_stream *, uint32_t, struct uwsgi_buffer *, size_t);
|
||||
char *uwsgi_gzip_chunk(z_stream *, uint32_t *, char *, size_t, size_t *);
|
||||
int uwsgi_gzip_prepare(z_stream *, char *, size_t, uint32_t *);
|
||||
#endif
|
||||
|
||||
char *uwsgi_get_cookie(struct wsgi_request *, char *, uint16_t, uint16_t *);
|
||||
@@ -3946,8 +3983,10 @@ int uwsgi_is_full_http(struct uwsgi_buffer *);
|
||||
|
||||
int uwsgi_http_date(time_t t, char *);
|
||||
|
||||
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req);
|
||||
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_buffer *, struct uwsgi_buffer **, void *), void *);
|
||||
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *, size_t);
|
||||
int uwsgi_apply_final_transformations(struct wsgi_request *);
|
||||
void uwsgi_free_transformations(struct wsgi_request *);
|
||||
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *);
|
||||
|
||||
void uwsgi_file_write_do(struct uwsgi_string_list *);
|
||||
|
||||
@@ -3957,6 +3996,12 @@ void uwsgi_add_safe_fd(int);
|
||||
void uwsgi_ipcsem_clear(void);
|
||||
char *uwsgi_str_to_hex(char *, size_t);
|
||||
|
||||
// this 3 functions have been added 1.9.10 to allow plugins take the control over processes
|
||||
void uwsgi_worker_run(void);
|
||||
void uwsgi_mule_run(void);
|
||||
void uwsgi_spooler_run(void);
|
||||
void uwsgi_takeover(void);
|
||||
|
||||
void uwsgi_check_emperor(void);
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
int uwsgi_init(int, char **, char **);
|
||||
|
||||
+8
-6
@@ -1,6 +1,6 @@
|
||||
# uWSGI build system
|
||||
|
||||
uwsgi_version = '1.9.7'
|
||||
uwsgi_version = '1.9.10'
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -153,7 +153,7 @@ def spcall3(cmd):
|
||||
def add_o(x):
|
||||
if x == 'uwsgi':
|
||||
x = 'main'
|
||||
elif x.endswith('.a'):
|
||||
elif x.endswith('.a') or x.endswith('.o'):
|
||||
return x
|
||||
x = x + '.o'
|
||||
return x
|
||||
@@ -277,7 +277,7 @@ def build_uwsgi(uc, print_only=False):
|
||||
objfile = file
|
||||
if objfile == 'uwsgi':
|
||||
objfile = 'main'
|
||||
if not objfile.endswith('.a'):
|
||||
if not objfile.endswith('.a') and not objfile.endswith('.o'):
|
||||
compile(' '.join(cflags), last_cflags_ts, objfile + '.o', file + '.c')
|
||||
|
||||
if uc.get('embedded_plugins'):
|
||||
@@ -346,6 +346,8 @@ def build_uwsgi(uc, print_only=False):
|
||||
for cfile in up['GCC_LIST']:
|
||||
if cfile.endswith('.a'):
|
||||
gcc_list.append(cfile)
|
||||
elif cfile.endswith('.o'):
|
||||
gcc_list.append('%s/%s' % (path, cfile))
|
||||
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
|
||||
compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts,
|
||||
path + '/' + cfile + '.o', path + '/' + cfile + '.c')
|
||||
@@ -471,7 +473,7 @@ class uConf(object):
|
||||
self.gcc_list.append('proto/scgi')
|
||||
self.include_path = []
|
||||
|
||||
self.cflags = ['-O2', '-I.', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split()
|
||||
self.cflags = ['-O2', '-I.', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split() + self.get('cflags','').split()
|
||||
|
||||
report['kernel'] = uwsgi_os
|
||||
|
||||
@@ -568,7 +570,7 @@ class uConf(object):
|
||||
return None
|
||||
return value
|
||||
except:
|
||||
if default:
|
||||
if default is not None:
|
||||
return default
|
||||
return None
|
||||
|
||||
@@ -1122,7 +1124,7 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
|
||||
for cfile in up['GCC_LIST']:
|
||||
if cfile.endswith('.a'):
|
||||
gcc_list.append(cfile)
|
||||
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
|
||||
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m') and not cfile.endswith('.o'):
|
||||
gcc_list.append(path + '/' + cfile + '.c')
|
||||
else:
|
||||
gcc_list.append(path + '/' + cfile)
|
||||
|
||||
Reference in New Issue
Block a user