Compare commits

..
117 Commits
Author SHA1 Message Date
Unbit 2c9ebdaa69 updated gemspec for 1.9.10 2013-05-11 17:12:00 +02:00
Unbit fbd9e5b4d7 goroutines support must be completely rewritten :( 2013-05-11 16:57:41 +02:00
unbit b9a3425b6d Merge pull request #276 from prymitive/build_fixes
better check for default value, this allows using false or empty string ...
2013-05-11 02:53:56 -07:00
Łukasz Mierzwa d4742c611b better check for default value, this allows using false or empty string as defaults 2013-05-11 11:43:29 +02:00
Unbit c645a590aa added goroutine reference to gccgo 2013-05-11 08:43:46 +02:00
Unbit 275a7fe63f added --go-args 2013-05-11 08:26:02 +02:00
unbit 0ff16d8312 Merge pull request #275 from prymitive/df
fixed legion-smart-attach-daemon2
2013-05-10 14:21:42 -07:00
Łukasz Mierzwa 1cb31d6c7e fixed legion-smart-attach-daemon2 2013-05-10 20:51:39 +02:00
Unbit 8a6eb553df fixed attach-daemon 2013-05-10 17:20:44 +02:00
Unbit 946af8b9ee added errorlimiter.ini example config 2013-05-10 15:15:51 +02:00
Unbit 098a1f647e added final routes or running rules at the end of the request 2013-05-10 15:08:33 +02:00
Unbit c9681dc430 Merge branch 'master' of github.com:unbit/uwsgi 2013-05-10 08:18:33 +02:00
Unbit ff0b8b2d53 fixed #274 2013-05-10 08:17:54 +02:00
unbit 75f520d43a Merge pull request #255 from prymitive/airbrake_fixes
few airbrake fixes
2013-05-09 11:52:29 -07:00
Unbit 65209748ba completed the first phase of the gccgo plugin 2013-05-09 19:55:27 +02:00
Unbit cd604ef07b extended the build system to support .o files and added preliminary gccgo plugin 2013-05-09 18:38:53 +02:00
Łukasz Mierzwa 51da8bc531 * report more data in airbrake plugin
* preserve text version of backtrace (there might be multiple alarm handlers for any segfault)
* fix reload errors
2013-05-09 15:44:29 +02:00
Unbit 2374ba12bd better file descriptor management for alarm threads 2013-05-09 15:17:57 +02:00
Unbit 0a75aaec25 added the uwsgi_takeover commodity function 2013-05-09 13:53:22 +02:00
Unbit a8c286ae83 prepare for gccgo integration 2013-05-09 11:43:01 +02:00
Unbit 9cbdfc7764 updated gemspec for 1.9.9 2013-05-08 17:48:41 +02:00
Unbit cb1423436f fixed radius-next 2013-05-08 16:30:32 +02:00
Unbit 2fb391795a added symcall-post-fork 2013-05-08 13:29:21 +02:00
Unbit 9ec20f2d8f allows cache math from the routing subsystem 2013-05-08 11:00:23 +02:00
Unbit 9323ca5136 added cache math api to python 2013-05-08 10:34:34 +02:00
Unbit 978e6072ab prepare for math operations in cache 2013-05-08 09:41:24 +02:00
Unbit d0e3869d54 fixed go arguments on osx 2013-05-07 16:35:34 +02:00
unbit 15c7e956f2 Merge pull request #270 from prymitive/numleaks
2 small memory leaks valgrind complains about
2013-05-07 07:01:11 -07:00
Łukasz Mierzwa ed61545ec7 2 small memory leaks valgrind complains about 2013-05-07 15:54:35 +02:00
Unbit 1aac5becdc added --touch-exec 2013-05-07 15:14:09 +02:00
Unbit 4bca26debc added the radius plugin 2013-05-07 14:38:44 +02:00
Unbit d6eecd1637 report gateway harakiri 2013-05-07 13:41:40 +02:00
unbit 00e7620d2e Merge pull request #269 from prymitive/legion_daemons
legion daemons
2013-05-07 03:36:25 -07:00
Łukasz Mierzwa d657283aad legion daemons 2013-05-07 12:09:26 +02:00
Unbit 70a879ea94 added incache routing condition 2013-05-07 11:56:18 +02:00
Unbit 591ee22472 fixed support for go 1.1rc2 2013-05-07 11:11:25 +02:00
Unbit 956b05d39d Merge branch 'master' of github.com:unbit/uwsgi 2013-05-07 10:02:00 +02:00
Roberto De Ioris 5bdad6d4cb support for go 1.1 on osx 2013-05-07 04:36:05 +02:00
unbit 29a6ac6ed7 Merge pull request #267 from prymitive/log_retries
log retry count on router error
2013-05-06 09:16:07 -07:00
Łukasz Mierzwa 8f7f091e9b log retry count on router error 2013-05-06 16:20:04 +02:00
Unbit 63dfe7628b added uwsgi_connect_udp 2013-05-06 15:22:13 +02:00
Unbit ce507e7851 try to fix multithread + dynamic mode 2013-05-04 15:44:44 +02:00
Unbit a9cd76173e added default app for psgi 2013-05-04 15:41:12 +02:00
Unbit 44f8ffb434 another fix in spnego 2013-05-04 15:27:40 +02:00
Unbit 28c395f111 it looks like both MIT krb5 and heimdal leaks memory... 2013-05-04 15:14:17 +02:00
Unbit 39df68c38e better next support for spnego 2013-05-04 13:49:32 +02:00
Unbit b33ca9225a improved route-if regexp to store vectors 2013-05-04 13:36:09 +02:00
Unbit bd137afecf fixed thread bug with routing regexp vectors 2013-05-04 12:39:08 +02:00
Roberta Giordano a3b9bed8c2 fixed spnego build 2013-05-04 08:37:55 +02:00
Unbit 0a157739bc Merge branch 'master' of github.com:unbit/uwsgi 2013-05-04 08:11:37 +02:00
Unbit c46b08ad5e completed spnego plugin 2013-05-04 08:11:19 +02:00
unbit 754e6193a4 Merge pull request #265 from ttreptow/master
Fix mule farm initialization
2013-05-03 12:03:26 -07:00
Tim Treptow 56b49fe2dd fix mule farm initialization 2013-05-03 09:40:10 -07:00
Unbit 36a7215f94 added setscriptname and donotlog routing actions 2013-05-03 17:49:06 +02:00
Unbit 702247affd spnego plugin is almost ready 2013-05-03 17:44:21 +02:00
Unbit e752b1f8e5 added Graham credits 2013-05-03 10:21:15 +02:00
Unbit 920eee36e3 fixed a wrong cast in gevent plugin 2013-05-02 17:28:06 +02:00
unbit a5070a5d98 Merge pull request #262 from edevil/master
Call atexit hook after all requests are done, or immediately if there are no requests
2013-05-02 08:24:57 -07:00
Unbit ccb5aefa61 do not use the stack on ldapauth filter generation 2013-05-02 16:50:55 +02:00
Unbit 378b08e37c fixed a memory leak in ldapauth 2013-05-02 16:48:04 +02:00
Unbit 5763483c91 avoid using deprecated apis in the ldap plugin 2013-05-02 15:54:45 +02:00
Andre Cruz 559f8ee095 Call atexit hook when we want to graceful reload and there are no requests being served. Otherwise call it when the last request finishes. 2013-05-02 14:36:50 +01:00
Unbit 4382ef360c Merge branch 'master' of github.com:unbit/uwsgi 2013-05-02 15:12:07 +02:00
Unbit 0cb576cf1a added ldap to all buildconf 2013-05-02 15:11:57 +02:00
unbit dee4d047b4 Merge pull request #261 from prymitive/ldapauth1
remove useless reconnect
2013-05-02 06:11:25 -07:00
Łukasz Mierzwa 2520cc7bb9 remove useless reconnect 2013-05-02 12:24:11 +02:00
unbit 192c31efe0 Merge pull request #257 from prymitive/router_ldapauth
router_ldapauth plugin with simple bind support
2013-05-02 02:54:23 -07:00
Łukasz Mierzwa a1d8ebc2d2 router_ldapauth plugin with simple bind support 2013-05-02 11:47:31 +02:00
Unbit 14a9de2147 spnego authentication is still broken 2013-05-02 10:17:28 +02:00
Unbit a760a9a3f1 ported the xslt plugin to the new api 2013-05-02 10:04:04 +02:00
Unbit efd14e1c7a added cookie-based authentication test 2013-05-02 09:34:31 +02:00
Unbit 6019c46cee removed the GOON routing return value 2013-05-02 08:45:37 +02:00
Unbit ec6acfbc1c improved transformation system 2013-05-01 19:36:13 +02:00
Unbit e925dbaad6 other gzip improvements 2013-05-01 12:04:41 +02:00
Unbit 8321adf0bc completed chunked transformation 2013-05-01 10:21:35 +02:00
Unbit e1c5e9e874 prepare for gzip streaming 2013-05-01 10:05:39 +02:00
Unbit 0aec581714 prepare for streaming transformations 2013-05-01 09:56:56 +02:00
Unbit b77b8623d1 added a simple dumper for REPORT method 2013-04-30 18:49:58 +02:00
Unbit 5ab986d6d9 send only requested webdav props 2013-04-30 11:41:16 +02:00
Unbit 09b8332236 prepare for caldav support 2013-04-29 21:42:46 +02:00
Unbit d05345abc0 added current-user-privilege-set 2013-04-29 15:06:37 +02:00
Unbit 804c369f0d toward programmable webdav, carddav support ensured 2013-04-29 14:42:04 +02:00
Roberta Giordano 8f67fc886c added support for OSX xattr in WebDAV plugin 2013-04-28 11:37:20 +02:00
Roberta Giordano ca3b1a9b30 support for OSX in the webdav plugin 2013-04-28 11:24:07 +02:00
Unbit 63c1dbb3ed windows-webdav compatibility fix 2013-04-28 11:16:44 +02:00
Unbit 9a424dfe29 prepare for webdav locking 2013-04-28 10:07:36 +02:00
Unbit 0a6eb596bb completed PROPPATCH 2013-04-28 09:46:10 +02:00
Unbit 34452376db added PROPFIND + xattr in the webdav plugin 2013-04-28 08:31:47 +02:00
Unbit 53a90a59c5 added xattr plugin 2013-04-27 19:01:09 +02:00
Unbit ec491ebd83 added the WebDAV plugin (beta) 2013-04-27 18:24:21 +02:00
Unbit cdc41c305e improved url encoding api 2013-04-27 11:45:48 +02:00
Unbit 6cf67b399c new api functions for http headers 2013-04-27 09:10:11 +02:00
unbit dc3c56bccc Merge pull request #253 from prymitive/alarm_airbrake_plugin
airbrake plugin
2013-04-26 07:55:23 -07:00
Łukasz Mierzwa 4657f2039a airbrake plugin 2013-04-26 16:29:18 +02:00
Unbit b0082fbd0d added --alarm-segfault 2013-04-26 15:09:04 +02:00
Unbit ede1b4df11 fixed initial flush 2013-04-26 08:36:41 +02:00
unbit d78a3d1f8a Merge pull request #247 from prymitive/cache_sync_fix
fixed cache sync parsing
2013-04-25 05:44:08 -07:00
Unbit 6152555f26 another fix in python async mode 2013-04-25 14:43:40 +02:00
Unbit bbad505044 fixed python async mode with the improved api 2013-04-25 14:28:38 +02:00
Łukasz Mierzwa 11c5429184 fixed cache sync parsing - uwsgi_hooked_parse() was getting invalid data lenght 2013-04-25 14:28:18 +02:00
Unbit 4e865c4525 fixed stackless + threads 2013-04-25 14:03:40 +02:00
Unbit 2fa785a539 improved fiber support 2013-04-25 13:51:05 +02:00
Unbit 296a8449c9 improved stackless plugin 2013-04-25 13:46:30 +02:00
Unbit f20213ff10 various async/green mode improvements and fixes 2013-04-25 11:33:45 +02:00
Unbit 8a7067ee24 added routing support to coroae and fixed backtrace-depth 2013-04-25 09:09:46 +02:00
Unbit a3024e9f5a refactored async mode 2013-04-25 08:57:58 +02:00
Unbit 86e651f5e7 call gevent atexit hook before destroying uwsgi-related greenlets 2013-04-25 07:09:39 +02:00
unbit 409710b2b1 Merge pull request #245 from prymitive/dont_count_tx_on_pings
don't increment tx counter on requests that should not be accounted
2013-04-24 04:27:27 -07:00
Łukasz Mierzwa 14a406a276 don't increment tx counter on requests that should not be accounted (ping plugin requests) 2013-04-24 10:57:05 +02:00
Unbit 28a283b1c1 added uwsgi.atexit management to gevent 2013-04-23 21:20:42 +02:00
Unbit ccf298a148 updated gemspec 2013-04-23 14:29:45 +02:00
Unbit 914b600af4 prepare for 1.9.8 2013-04-23 14:27:47 +02:00
Unbit 4944994667 fixed #244 2013-04-23 14:27:08 +02:00
Unbit 3a487578a5 remove annoying logline in async mode 2013-04-23 10:10:13 +02:00
Unbit 39eeccb16a refactored async runqueue management 2013-04-23 10:02:36 +02:00
Roberta Giordano 32acd3b9d1 added the flush instruction 2013-04-23 07:07:53 +02:00
Roberta Giordano c57baae477 mime route var has to take variables 2013-04-23 06:46:47 +02:00
72 changed files with 4938 additions and 619 deletions
+1 -1
View File
@@ -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
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin =
inherit = base
+126 -94
View File
@@ -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;
}
}
}
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+5
View File
@@ -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
View File
@@ -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)
+21
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+294
View File
@@ -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,
};
+9
View File
@@ -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']
+3 -2
View File
@@ -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;
+2 -3
View File
@@ -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);
}
}
}
+7 -2
View File
@@ -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
View File
@@ -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;
}
+196
View File
@@ -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,
};
+118
View File
@@ -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
View File
@@ -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;
+8 -6
View File
@@ -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,
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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,
};
+3 -4
View File
@@ -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;
}
}
+8
View File
@@ -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;
+132 -2
View File
@@ -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},
};
+19 -9
View File
@@ -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 {
+2 -5
View File
@@ -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 ) {
+31 -24
View File
@@ -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 = {
+337 -4
View File
@@ -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 = {
+235
View File
@@ -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,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='router_radius'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['radius']
+107 -74
View File
@@ -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
+2 -2
View File
@@ -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']
-3
View File
@@ -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) {
+50 -20
View File
@@ -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,
};
+17
View File
@@ -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,
};
+58
View File
@@ -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']
+47 -12
View File
@@ -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;
}
+6 -3
View File
@@ -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;
}
+5 -4
View File
@@ -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
View File
@@ -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;
+8
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
NAME='xattr'
CFLAGS=[]
LDFLAGS=[]
LIBS=[]
GCC_LIST = ['xattr']
+82
View File
@@ -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 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2
View File
@@ -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()
+50
View File
@@ -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,
+35
View File
@@ -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
+24
View File
@@ -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
+16
View File
@@ -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
View File
@@ -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"]
+65 -20
View File
@@ -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
View File
@@ -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)