Compare commits

...
148 Commits
Author SHA1 Message Date
roberto@debian32 d57d5acb30 --idle mode 2011-05-29 06:52:47 +02:00
roberto@debian32 43e6664dd9 --cheap option 2011-05-28 19:43:29 +02:00
roberto@dj1 d0c6dff83e --add-header option 2011-05-28 05:20:48 -05:00
roberto@dj1 54b40f5978 better cgroup support 2011-05-27 14:23:22 -05:00
roberto@dj1 1c59c03261 unlimited sockets for fastrouter 2011-05-27 08:55:15 -05:00
roberto@dj1 ce23fd38ab better emperor+master mode 2011-05-27 05:11:41 -05:00
roberto@dj1 4818efa7de emperor+amqp fixes 2011-05-27 04:07:07 -05:00
roberto@dj1 ea19e74229 better netlink ns detection 2011-05-27 03:21:21 -05:00
roberto@dj1 fe353de5a8 fixed netlink compilation 2011-05-27 01:58:43 -05:00
roberto@dj1 1d89266f2e unlimited shared sockets 2011-05-27 01:39:01 -05:00
roberto@debian32 61d79394ca --fastrouter-subscription-slot 2011-05-26 05:35:43 +02:00
roberto@debian32 491f2828b5 --no-fd-passing 2011-05-26 05:29:01 +02:00
roberto@nexenta32 431e05d4f4 fixed ifaddrs support 2011-05-26 06:17:46 +02:00
roberto@solarisexpress ae6780a487 remember: do not use the word 'sun' as variable on solaris... 2011-05-26 04:54:55 +00:00
roberto@debian32 5707a70141 added --log-socket 2011-05-25 08:57:13 +02:00
roberto@debian32 e9a7bd7da1 add abstract unix socket 2011-05-23 21:50:04 +02:00
roberto@debian32 91e45daf6c better unix socket support in abstract namespace (Linux only) 2011-05-23 16:10:27 +02:00
roberto@debian32 9f69998075 grunt improvement 2011-05-23 11:43:22 +02:00
roberto@debian32 4f6270976b fixed python3.x spooler 2011-05-22 14:07:01 +02:00
roberto@debian32 328caa43f2 allow --auto-snapshot to take a value 2011-05-22 11:56:58 +02:00
roberto@debian32 368408374a preliminary snapshotting support 2011-05-22 11:43:28 +02:00
roberto@debian32 c3a90db493 uWSGI 0.9.8-rc2 2011-05-21 08:10:03 +02:00
roberto@debian32 5bc0320877 Added tag 0.9.8-rc2 for changeset e91bc724325e 2011-05-21 08:09:49 +02:00
roberto@debian32 622ed620b9 fixed python 3.1 2011-05-21 08:03:22 +02:00
roberto@debian2 1b859413de add mercurial revision to uWSGI version string 2011-05-21 07:43:49 +02:00
roberto@maverick64 95432fd8e3 added --die-on-term 2011-05-19 20:35:47 +02:00
roberto@freebsd64 b3f3c5d7b3 fixed touch reload 2011-05-19 09:33:25 +02:00
roberto@debian32 02cef20462 another fix for wsgi.input 2011-05-19 08:33:11 +02:00
roberto@debian32 3edebe34ae improved upload test 2011-05-18 21:15:41 +02:00
roberto@longshot 28c9b75fb5 wsgi.input fix 2011-05-18 21:10:18 +02:00
roberto@fedora15 a2735e10b7 report number of vassals to systemd 2011-05-17 08:57:50 +02:00
roberto@fedora15 e03d26fd63 report emperor dead status to systemd 2011-05-17 08:36:54 +02:00
roberto@sirius 7c4c346e64 fix systemd on unsupported platform 2011-05-17 08:29:33 +02:00
roberto@fedora15 67b3c0c4a8 systemd integration 2011-05-17 08:26:39 +02:00
roberto@fedora15 dadca785e4 initial systemd support 2011-05-16 17:25:38 +02:00
roberto@debian32 accebe5597 add --log-prefix option 2011-05-16 10:06:47 +02:00
unbit@gambit 792965bedd uWSGI 0.9.8-rc1 2011-05-14 09:57:15 +02:00
unbit@localhost 1bb1bafe0c Added tag 0.9.8-rc1 for changeset d1e57707f631 2011-05-14 09:56:41 +02:00
roberto@debian32 28c11324ca merge 2011-05-14 09:34:29 +02:00
roberto@debian32 42d940c38e a bit of refactoring 2011-05-14 09:34:03 +02:00
roberto@freebsd64 c1ea05b925 fixed profiler compilation in older python 2011-05-14 07:08:33 +02:00
roberto@debian32 9435693865 removed old/useless writers.c 2011-05-13 18:49:31 +02:00
roberto@debian32 14da582637 various static file fixes 2011-05-13 18:46:21 +02:00
roberto@debian32 b2d4a795a1 various ruby.rack fixes 2011-05-13 18:19:26 +02:00
roberto@sirius 493696705b another off_t to size_t fix 2011-05-13 16:52:21 +02:00
roberto@debian32 d827c6f09a moved rack.input to the new POST api 2011-05-13 16:46:06 +02:00
roberto@debian32 df000b0cb2 support for jemalloc 2011-05-12 12:55:07 +02:00
roberto@debian32 d9630a32c7 added support for tcmalloc 2011-05-12 12:49:07 +02:00
roberto@debian32 71cc6f61bd fixed a stupid (really stupid) bug in uwsgi.core allocation 2011-05-11 19:04:52 +02:00
roberto@debian32 46eb832cc7 set in_request per core 2011-05-11 18:47:42 +02:00
roberto@debian32 11b2e4b430 lock goodbye_cruel_world in threading mode 2011-05-11 17:08:02 +02:00
roberto@debian32 11775532ee applied leonid patch for symlinks 2011-05-11 15:49:59 +02:00
roberto@debian32 f3388db8ba do not link core libraries in plugins 2011-05-11 12:28:15 +02:00
roberto@sirius 25ac86393f use size_t instead of off_t 2011-05-11 12:05:48 +02:00
roberto@debian32 b3432a95e1 finally fixed wsgi.input 2011-05-11 11:55:28 +02:00
roberto@debian32 e34d169fa6 merge 2011-05-11 06:24:11 +02:00
roberto@debian32 de84accb7a removed unused variable in pyerl 2011-05-11 06:23:40 +02:00
roberto@sirius 187577cbb5 fixed a stupid typo 2011-05-10 09:53:54 +02:00
roberto@debian32 72109b72d2 various rack fixes 2011-05-10 09:36:07 +02:00
roberto@debian32 f6c01d11e9 completed ruby 1.9 fiber support 2011-05-10 08:50:06 +02:00
roberto@debian32 d695ef4f57 removed garbage 2011-05-09 21:41:55 +02:00
roberto@debian32 16c6dcc573 better threading reload 2011-05-09 21:27:08 +02:00
roberto@debian32 3df19b286a support for plugin as symlinks 2011-05-09 20:18:49 +02:00
roberto@debian32 6f1b08762d adde fixup hook handler 2011-05-09 09:43:55 +02:00
roberto@debian32 a4a379f9d6 rack ported to new socket api 2011-05-07 09:32:49 +02:00
roberto@mrspurr 3d3d0304bc plugin autoloading (finally) 2011-05-07 09:21:07 +02:00
roberto@natty32 26135018a3 added check for patl method in psgi response 2011-05-06 08:09:30 +02:00
roberto@debian32 4bd381bb99 big PSGI update 2011-05-06 14:17:01 +02:00
roberto@debian32 cf08972e82 first round of memleak hunting in psgi/perl 2011-05-06 10:12:59 +02:00
roberto@natty32 d57a58d1e7 psgi input fix 2011-05-06 00:16:57 +02:00
roberto@natty32 f10789965e added seek to psgi custom object 2011-05-05 17:08:52 +02:00
roberto@natty32 94145bd300 temp --psgi-custom-input option 2011-05-05 17:04:51 +02:00
roberto@natty32 cdcb61d10d signal on python thread fix 2011-05-05 02:47:04 +02:00
roberto@natty32 56146a34af python get line number/profier fix 2011-05-05 02:40:53 +02:00
roberto@natty32 991e818449 fixes for python2.6 and forcing -bash in perl 2011-05-05 02:25:17 +02:00
roberto@natty32 80083cba76 funny hack to have a consistent __FILE__ in perl 2011-05-04 17:43:09 +02:00
roberto@natty32 2c44fd5aa2 fix stdout/stderr in python3 2011-05-04 15:39:24 +02:00
roberto@natty32 1561dd38fc another PSGI loading fix 2011-05-04 05:27:32 +02:00
roberto@natty32 8152648f66 psgi loading improvement 2011-05-04 04:59:01 +02:00
roberto@natty32 c1507d0381 put master logging in non-blocking mode 2011-05-04 03:33:44 +02:00
roberto@natty32 f0fb603af2 debug send/recv log buffer 2011-05-04 03:24:44 +02:00
roberto@natty32 93e891153f fixed sqlite3 support 2011-05-03 18:45:04 +02:00
roberto@natty32 26ece717b6 added support for sqlite3 configuration 2011-05-03 18:35:49 +02:00
roberto@natty32 93767335ca added --profiler 2011-05-03 15:01:51 +02:00
roberto@natty32 7cbe751a39 added --perl-local-lib 2011-05-02 17:12:32 +02:00
roberto@natty32 c45df83f19 set buffer size in $/ 2011-05-02 13:25:36 +02:00
roberto@natty32 fabce61a58 add PLACK_ENV and -bash 2011-05-02 12:11:38 +02:00
roberto@natty32 5c9ccae598 added PSGI streamer test 2011-05-02 08:44:50 +02:00
roberto@natty32 6c9d7239f2 uGreen support added to perl 2011-05-02 08:36:57 +02:00
roberto@natty32 4b75e2577e preliminary async/nonblocking support for PSGI 2011-05-02 07:58:16 +02:00
roberto@natty32 08c9d942a4 lazy mode support 2011-05-01 17:31:54 +02:00
roberto@natty32 3b59b4ad21 psgi: allows multiline headers 2011-05-01 17:01:05 +02:00
roberto@natty32 7682eec52a do not die on perl die() :P 2011-05-01 16:42:01 +02:00
roberto@sirius 694517bbe7 export all the required psgi.* vars and all of the supported psgix.* 2011-05-01 15:37:25 +02:00
roberto@natty32 7f443fdd05 allow globbed-pythonpath 2011-04-27 16:28:44 +02:00
roberto@natty32 01ab891c11 unlimited pythonpath entries 2011-04-27 15:56:33 +02:00
roberto@natty32 052aacfd36 fixed --map-socket 2011-04-27 15:46:00 +02:00
roberto@natty32 80a6d2ccfb various fixes in multiple sockets and support for file piped via stdin 2011-04-27 14:15:01 +02:00
roberto@debian32 b4ce175bdf add --master to carbon/graphite example 2011-04-27 08:08:59 +02:00
roberto@debian32 f6f52d32dc fixed a typo 2011-04-27 08:07:19 +02:00
roberto@debian32 865b2de9bb added an example script for graphite/carbon update 2011-04-27 08:04:45 +02:00
roberto@debian32 4a8233a041 support for libzmq 2.0 2011-04-26 19:39:40 +02:00
roberto@natty32 f856ad78a3 added --log-zeromq 2011-04-26 17:26:40 +02:00
roberto@debian32 653267cbe6 added libyaml support, for future advanced implementations 2011-04-26 08:45:44 +02:00
roberto@debian32 8b53df27ab gcc-4.6 fixes and applied Riccardo Magliocchetti patch for libm 2011-04-26 07:38:10 +02:00
roberto@debian32 c4b7c2b58c fix build without zeromq 2011-04-25 16:56:06 +02:00
roberto@maverick64 66f82f364c fixed clustering 2011-04-25 09:50:11 +02:00
roberto@maverick64 6d269607d2 allow clustering + zeromq 2011-04-25 09:38:26 +02:00
roberto@maverick64 8370977e5b fixed indentation 2011-04-25 07:15:41 +02:00
roberto@maverick64 e2c335ff73 threaded zeromq/mongrel2 support 2011-04-25 07:13:23 +02:00
roberto@maverick64 816b9d0343 refactored zeromq 2011-04-24 18:50:44 +02:00
roberto@maverick64 2922e1ba35 slowdown vassals spawn 2011-04-24 07:38:38 +02:00
roberto@maverick64 c86f341d29 first part of --socket-protocol option 2011-04-22 09:34:50 +02:00
roberto@maverick64 73cdd68283 fixed modifier1 30 2011-04-22 09:18:07 +02:00
roberto@maverick64 81641686bc various fixes 2011-04-22 08:51:29 +02:00
roberto@maverick64 14c58c8e62 fixed preforking+threading 2011-04-22 07:53:32 +02:00
roberto@maverick64 74b8f2587c prototype for uwsgidump protocol 2011-04-21 19:28:02 +02:00
roberto@mrspurr bebe041061 added psgi full streaming support 2011-04-21 06:24:41 +02:00
roberto@msrpurr 2e5d3d2952 fixed response size in PSGI 2011-04-21 04:26:58 +02:00
roberto@mrspurr c2d155b8ff --inherit and --vassals-inherit 2011-04-20 21:33:56 +02:00
roberto@natty32 fda368ff08 added support for mongrel2 tnetstrings 2011-04-20 11:49:41 +02:00
roberto@natty32 19cf592e77 fastcgi optimization 2011-04-20 09:32:37 +02:00
roberto@natty32 260cac6b59 fixed zeromq post-file close 2011-04-19 18:19:08 +02:00
roberto@natty32 673275e708 multiprotocol refactoring 2011-04-19 18:14:40 +02:00
roberto@freebsd64 a6bc778c25 conditionally compile libuuid 2011-04-19 20:46:31 +02:00
roberto@centos32 ef2f5879b6 conditionally compile netlink support 2011-04-19 13:46:26 +02:00
roberto@sirius ee725bf625 fixed compilation in no-zmq environments 2011-04-19 11:35:03 +02:00
roberto@natty32 5388fa442c completed zeromq support 2011-04-19 08:34:03 +02:00
roberto@natty32 913493fd2e mongrel2/zeromq support added 2011-04-19 06:59:34 +02:00
roberto@natty32 6d4a8c6619 added a pure-zeromq loop engine 2011-04-18 20:00:26 +02:00
roberto@natty32 4a57115336 edge triggered events support 2011-04-18 17:07:13 +02:00
roberto@natty32 1dd754a0d5 fallback to read/write instead of sendfile in fastcgi mode 2011-04-18 06:32:52 +02:00
roberto@natty32 509b78d906 fastcgi fixes 2011-04-18 05:04:11 +02:00
roberto@natty32 363366d012 preliminary fastcgi support 2011-04-17 07:35:15 +02:00
roberto@natty32 26d4fd4e00 fixed uwsgi protocol support 2011-04-16 20:02:27 +02:00
roberto@natty32 09ee97e775 first destructive commit for uWSGI 0.9.8 2011-04-16 19:41:58 +02:00
roberto@natty32 1400a95cec added JSON support to the Emperor 2011-04-14 09:38:06 +02:00
roberto@natty32 5e96c4ca79 fixed json support with pkg-config 2011-04-14 09:10:03 +02:00
roberto@sirius 3c068b2a00 fixed http support 2011-04-14 09:47:04 +02:00
roberto@sirius 81fd7757c1 JSON support, thanks jansson 2011-04-14 09:32:17 +02:00
roberto@natty32 1db64b72ae fixed build of PSGI plugin on non-Apple platform 2011-04-13 13:27:32 +02:00
roberto@natty32 ab1bed236c use close-on-exec instead of close() on osx reload 2011-04-13 07:38:46 +02:00
roberto@debian64 e503999392 fixed virtualhosting with dynamic virtualenv 2011-04-12 10:34:36 +02:00
roberto@dj1 2392eb7e0b fixed wait in emperor 2011-04-08 03:25:16 -05:00
roberto@dj1 c62b54f18d added vassal loyalty concept 2011-04-08 02:43:05 -05:00
roberto@natty32 603d46c1ae merge 2011-04-07 08:46:34 +02:00
roberto@natty32 c0e0ae551d use binary stream for wsgi.input in Python 3.x 2011-04-07 08:45:59 +02:00
unbit@localhost a0a2507c05 Added tag 0.9.7.2 for changeset a5f13497b392 2011-04-06 09:50:01 +02:00
88 changed files with 8647 additions and 3880 deletions
+3
View File
@@ -19,3 +19,6 @@ d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
0000000000000000000000000000000000000000 0.9.7.1
0000000000000000000000000000000000000000 0.9.7.1
486e7760bcbc2191ddb9b4aee6c98dbd5fc4c754 0.9.7.1
a5f13497b39269621f8f1e56e14d2cc141452e79 0.9.7.2
d1e57707f6317f134fea7d12f6588d8690f74f3f 0.9.8-rc1
e91bc724325e14c13b8f548c0b6a315c48a1c32a 0.9.8-rc2
+40
View File
@@ -1,3 +1,43 @@
*** may 2011 ***
* 0.9.8-rc2 [20110521]
- new option --die-on-term
- fixed touch reload
- a couple of optimizations for wsgi.input
- systemd integration
* 0.9.8-rc1 [20110514]
- massive code cleanup and refactoring
- added vassals loyalty concept
- fixed virtualhosting with dynamic virtualenv
- fixed reloading on grand-central-dispatch-enabled OSX
- improved PSGI support with uGreen and async support
- improved Rack support with complete fiber+async in ruby 1.9
- support for JSON config files
- native multi-protocol support (added fastcgi and http)
- Mongrel2 support
- support for templates in vassals
- various threading fixes
- gcc-4.6 support
- support for logging via zeromq
- support for configuration passed via pipe/stdin
- pythonpath entries are now unlimited
- socket entries are unlimited
- pythonpath can be a glob
- lazy mode added
- new language-independent profiling subsystem
- support for configuration stored in a sqlite3 db
- allow workers to survive to syslogd death (when --log-syslog is used)
- fix traceback in Python 3.x
- support for uwsgi signals in threads
- plugin autoloading
- graceful reloading for threads
- new wsgi.input object
- support for alternative allocators (tcmalloc and jemalloc)
*** april 2011 ***
* 0.9.7.2 [20110406]
+83 -26
View File
@@ -2,6 +2,10 @@
extern struct uwsgi_server uwsgi;
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
return uwsgi.async_proto_fd_table[fd];
}
struct wsgi_request *find_wsgi_req_by_fd(int fd) {
return uwsgi.async_waiting_fd_table[fd];
}
@@ -195,10 +199,13 @@ void *async_loop(void *arg1) {
int interesting_fd, i;
struct uwsgi_rb_timer *min_timeout;
int timeout;
int is_a_new_connection;
int proto_parser_status;
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
void *events = event_queue_alloc(64);
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
uwsgi.async_runqueue = NULL;
uwsgi.async_runqueue_cnt = 0;
@@ -235,49 +242,99 @@ void *async_loop(void *arg1) {
async_expire_timeouts();
}
for(i=0;i<uwsgi.async_nevents;i++) {
// manage events
interesting_fd = event_queue_interesting_fd(events, i);
// new request coming in
if (interesting_fd == uwsgi.sockets[0].fd) {
uwsgi.wsgi_req = find_first_available_wsgi_req();
if (uwsgi.wsgi_req == NULL) {
uwsgi_log("async queue is full !!!\n");
continue;
}
is_a_new_connection = 0;
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id );
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
// new request coming in ?
uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
is_a_new_connection = 1;
uwsgi.wsgi_req = find_first_available_wsgi_req();
if (uwsgi.wsgi_req == NULL) {
uwsgi_log("async queue is full !!!\n");
break;;
}
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
#endif
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
#endif
continue;
}
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
#endif
// on linux we do not need to reset the socket to blocking state
#ifndef __linux__
if (uwsgi.numproc > 1) {
/* re-set blocking socket */
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi.sockets[0].arg) < 0) {
uwsgi_error("fcntl()");
continue;
if (uwsgi.numproc > 1) {
/* re-set blocking socket */
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi_sock->arg) < 0) {
uwsgi_error("fcntl()");
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
}
}
#endif
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
if (wsgi_req_simple_recv(uwsgi.wsgi_req)) {
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
runqueue_push(uwsgi.wsgi_req);
}
break;
}
uwsgi_sock = uwsgi_sock->next;
}
if (!is_a_new_connection) {
// proto event
uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd);
if (uwsgi.wsgi_req) {
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
// reset timeout
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
// parsing complete
if (!proto_parser_status) {
// remove fd from event poll and fd proto table
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
// put request in the runqueue
runqueue_push(uwsgi.wsgi_req);
continue;
}
else if (proto_parser_status == -1) {
uwsgi_log("error parsing request\n");
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
close(interesting_fd);
continue;
}
// re-add timer
async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
continue;
}
// put request in the runqueue
runqueue_push(uwsgi.wsgi_req);
}
else {
// app event
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
// unknown fd, remove it (for safety)
@@ -324,7 +381,7 @@ void *async_loop(void *arg1) {
next_async_request = current_request->next;
// request ended ?
if (uwsgi.wsgi_req->async_status == UWSGI_OK) {
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
// remove all the monitored fds and timeout
while(uwsgi.wsgi_req->waiting_fds) {
#ifndef UWSGI_EVENT_USE_PORT
+6 -1
View File
@@ -2,6 +2,9 @@
xml = true
ini = true
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
snmp = true
sctp = false
spooler = true
@@ -18,10 +21,12 @@ pcre = auto
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = auto
malloc_implementation = libc
plugins =
bin_name = uwsgi
plugin_dir = .
embedded_plugins = python, ping, nagios, rpc, fastrouter, http, ugreen
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, ugreen
locking = auto
event = auto
+4 -32
View File
@@ -1,33 +1,5 @@
[uwsgi]
xml = true
ini = true
snmp = true
sctp = false
erlang = false
spooler = false
embedded = false
udp = true
multicast = false
threading = true
sendfile = true
nagios = true
proxy = true
minterpreters = true
async = true
ugreen = false
http = true
evdis = false
ldap = true
routing = false
stackless = false
debug = false
unbit = false
xml_implementation = libxml2
plugins = python, ping, rack
bin_name = uwsgi
plugin_dir = .
embedded_plugins =
[python]
paste = true
web3 = true
inherit = default
plugins = python, ping, rack, psgi, cache, http, fastrouter
plugin_dir = plugins
embedded_plugins = null
+92 -100
View File
@@ -2,6 +2,98 @@
extern struct uwsgi_server uwsgi;
void uwsgi_init_cache() {
int i;
if (!uwsgi.cache_blocksize)
uwsgi.cache_blocksize = UMAX16;
if (uwsgi.cache_blocksize % uwsgi.page_size != 0) {
uwsgi_log("invalid cache blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.cache_blocksize, uwsgi.page_size);
exit(1);
}
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.cache_hashtable) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.cache_unused_stack) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
// the first cache item is always zero
uwsgi.shared->cache_first_available_item = 1;
uwsgi.shared->cache_unused_stack_ptr = 0;
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (uwsgi.cache_store) {
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
int cache_fd;
struct stat cst;
if (stat(uwsgi.cache_store, &cst)) {
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (cache_fd >= 0) {
// fill the caching store
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
uwsgi_log("ftruncate()");
exit(1);
}
}
}
else {
if ((size_t) cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
exit(1);
}
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
}
if (cache_fd < 0) {
uwsgi_error_open(uwsgi.cache_store);
exit(1);
}
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
uwsgi_cache_fix();
}
else {
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
}
}
if (!uwsgi.cache_items) {
uwsgi_error("mmap()");
exit(1);
}
/*
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.cache) {
uwsgi_error("mmap()");
exit(1);
}
*/
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items);
uwsgi.cache_lock = uwsgi_mmap_shared_rwlock();
uwsgi_rwlock_init(uwsgi.cache_lock);
uwsgi_log("*** Cache subsystem initialized: %dMB preallocated ***\n", ((sizeof(uint64_t) * UMAX16) + (sizeof(uint64_t) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024));
}
struct uwsgi_subscriber_name *uwsgi_get_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen) {
uint64_t ovl;
@@ -486,103 +578,3 @@ end:
return ret;
}
void cache_command(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
struct wsgi_request *wsgi_req = (struct wsgi_request *) data;
uint64_t tmp_vallen = 0;
if (vallen > 0) {
if (!uwsgi_strncmp(key, keylen, "key", 3)) {
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
if (val && tmp_vallen > 0) {
wsgi_req->response_size = write(wsgi_req->poll.fd, val, tmp_vallen);
}
}
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
if (val && vallen > 0) {
wsgi_req->response_size = write(wsgi_req->poll.fd, val, tmp_vallen);
}
else {
wsgi_req->response_size = write(wsgi_req->poll.fd, "HTTP/1.0 404 Not Found\r\n\r\n<h1>Not Found</h1>", 44);
}
}
}
}
int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
uint64_t vallen = 0;
char *value;
char *argv[3];
uint8_t argc = 0;
switch(wsgi_req->uh.modifier2) {
case 0:
// get
if (wsgi_req->uh.pktsize > 0) {
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
if (value && vallen > 0) {
wsgi_req->uh.pktsize = vallen;
wsgi_req->response_size = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
wsgi_req->response_size += write(wsgi_req->poll.fd, value, vallen);
}
}
break;
case 1:
// set
if (wsgi_req->uh.pktsize > 0) {
argc = 3;
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, &argc)) {
if (argc > 1) {
uwsgi_cache_set(argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), 0, 0);
}
}
}
break;
case 2:
// del
if (wsgi_req->uh.pktsize > 0) {
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize);
}
break;
case 3:
case 4:
// dict
if (wsgi_req->uh.pktsize > 0) {
uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh.pktsize, cache_command, (void *) wsgi_req);
}
break;
case 5:
// get (uwsgi + stream)
if (wsgi_req->uh.pktsize > 0) {
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
if (value && vallen > 0) {
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 1;
wsgi_req->response_size = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
wsgi_req->response_size += write(wsgi_req->poll.fd, value, vallen);
}
else {
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 0;
wsgi_req->response_size = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
}
}
break;
}
return 0;
}
struct uwsgi_plugin uwsgi_cache_plugin = {
.name = "cache",
.modifier1 = 111,
.request = uwsgi_cache_request,
};
+33
View File
@@ -0,0 +1,33 @@
# uwsgi --master --chdir /opt/graphite/webapp/graphite --module graphite_uwsgi ...
#
#
# this module will update a carbon server (used by the graphite tool: http://graphite.wikidot.com/)
# with requests count made by a Django app (and can track graphite itself as it is a Django app ;)
#
#
import os
import uwsgi
import time
from django.core.handlers.wsgi import WSGIHandler
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
CARBON_SERVER = "127.0.0.1:2003"
def update_carbon(signum):
# connect to the carbon server
carbon_fd = uwsgi.connect(CARBON_SERVER)
# send data to the carbon server
uwsgi.send(carbon_fd, "uwsgi.%s.requests %d %d\n" % (uwsgi.hostname, uwsgi.total_requests(), int(time.time())))
# close the connection with the carbon server
uwsgi.close(carbon_fd)
# register a new uwsgi signal (signum: 17)
uwsgi.register_signal(17, '', update_carbon)
# attach a timer of 10 seconds to signal 17
uwsgi.add_timer(17, 10)
# the Django app
application = WSGIHandler()
+142 -11
View File
@@ -5,6 +5,13 @@
extern struct uwsgi_server uwsgi;
extern char **environ;
int emperor_queue;
static void royal_death(int signum) {
uwsgi_notify("The Emperor is buried.");
exit(0);
}
struct uwsgi_instance {
struct uwsgi_instance *ui_prev;
struct uwsgi_instance *ui_next;
@@ -15,6 +22,7 @@ struct uwsgi_instance {
int status;
time_t born;
time_t last_mod;
time_t last_loyal;
uint64_t respawns;
int use_config;
@@ -24,10 +32,27 @@ struct uwsgi_instance {
char *config;
uint32_t config_len;
int loyal;
};
struct uwsgi_instance *ui;
struct uwsgi_instance *emperor_get_by_fd(int fd) {
struct uwsgi_instance *c_ui = ui;
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
if (c_ui->pipe[0] == fd) {
return c_ui;
}
}
return NULL;
}
struct uwsgi_instance *emperor_get(char *name) {
struct uwsgi_instance *c_ui = ui;
@@ -102,9 +127,12 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
struct uwsgi_instance *c_ui = ui;
struct uwsgi_instance *n_ui = NULL;
pid_t pid;
char *argv[4];
char **argv;
char *uef;
char **uenvs;
int counter;
sleep(1);
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
@@ -120,17 +148,24 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
}
c_ui->ui_next = n_ui;
#ifdef UWSGI_DEBUG
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
#endif
n_ui->ui_prev = c_ui;
memcpy(n_ui->name, name, strlen(name));
n_ui->born = born;
n_ui->last_mod = born;
// start without loyalty
n_ui->last_loyal = born;
n_ui->loyal = 0;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
uwsgi_error("socketpair()");
goto clear;
}
event_queue_add_fd_read(emperor_queue, n_ui->pipe[0]);
if (n_ui->use_config) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
uwsgi_error("socketpair()");
@@ -138,6 +173,8 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
}
}
// TODO pre-start hook
// a new uWSGI instance will start
pid = fork();
if (pid < 0) {
@@ -162,6 +199,7 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
else {
unsetenv("UWSGI_RELOADS");
unsetenv("NOTIFY_SOCKET");
uef = uwsgi_num2str(n_ui->pipe[1]);
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
@@ -208,7 +246,14 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
close(n_ui->pipe_config[0]);
}
counter = 4;
struct uwsgi_config_template *uct = uwsgi.vassals_templates;
while(uct) {
counter+=2;
uct = uct->next;
}
argv = uwsgi_malloc(sizeof(char *) * counter);
// set args
argv[0] = uwsgi.binary_path;
if (!strcmp(name + (strlen(name) - 4), ".xml"))
@@ -219,14 +264,25 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 3), ".js"))
argv[1] = "--json";
argv[2] = name;
argv[3] = NULL;
counter = 3;
uct = uwsgi.vassals_templates;
while(uct) {
argv[counter] = "--inherit";
argv[counter+1] = uct->filename;
counter+=2;
uct = uct->next;
}
argv[counter] = NULL;
// start !!!
if (execvp(argv[0], argv)) {
uwsgi_error("execvp()");
}
uwsgi_log("is the uwsgi binary in your system PATH ?\n");
// never here
exit(1);
exit(UWSGI_EXILE_CODE);
}
clear:
@@ -256,15 +312,30 @@ void emperor_loop() {
int amqp_fd = -1;
char *amqp_routing_key;
void *events;
int nevents;
int interesting_fd;
char notification_message[64];
signal(SIGPIPE, SIG_IGN);
uwsgi_unix_signal(SIGINT, royal_death);
uwsgi_unix_signal(SIGTERM, royal_death);
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
emperor_queue = event_queue_init();
events = event_queue_alloc(64);
uwsgi_log("*** starting uWSGI Emperor ***\n");
amqp_port = strchr(uwsgi.emperor_dir, ':');
if (amqp_port) {
if (uwsgi.emperor_amqp_vhost == NULL) uwsgi.emperor_amqp_vhost = "/";
if (uwsgi.emperor_amqp_username == NULL) uwsgi.emperor_amqp_username = "guest";
if (uwsgi.emperor_amqp_password == NULL) uwsgi.emperor_amqp_password = "guest";
reconnect:
while(amqp_fd == -1) {
uwsgi_log("connecting to AMQP server...\n");
@@ -275,11 +346,14 @@ reconnect:
}
uwsgi_log("subscribing to queue...\n");
if (uwsgi_amqp_consume_queue(amqp_fd, "/", "", "uwsgi.emperor", "fanout") < 0) {
if (uwsgi_amqp_consume_queue(amqp_fd, uwsgi.emperor_amqp_vhost, uwsgi.emperor_amqp_username, uwsgi.emperor_amqp_password, "", "uwsgi.emperor", "fanout") < 0) {
close(amqp_fd);
amqp_fd = -1;
sleep(1);
goto reconnect;
}
event_queue_add_fd_read(emperor_queue, amqp_fd);
}
else {
if (!glob(uwsgi.emperor_dir, GLOB_MARK, NULL, &g)) {
@@ -299,6 +373,8 @@ reconnect:
ui = &ui_base;
int freq = 0 ;
for (;;) {
@@ -309,13 +385,19 @@ reconnect:
}
}
if (amqp_fd > -1) {
uint64_t msgsize;
if (uwsgi_waitfd(amqp_fd, 3)) {
nevents = event_queue_wait_multi(emperor_queue, freq, events, 64);
freq = 3;
for (i = 0; i<nevents;i++) {
interesting_fd = event_queue_interesting_fd(events, i);
if (amqp_fd > -1 && interesting_fd == amqp_fd ) {
uint64_t msgsize;
char *config = uwsgi_amqp_consume(amqp_fd, &msgsize, &amqp_routing_key);
if (!config) {
uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
event_queue_del_fd(emperor_queue, amqp_fd, event_queue_read());
close(amqp_fd);
amqp_fd = -1;
goto reconnect;
@@ -329,6 +411,8 @@ reconnect:
ui_current = emperor_get(config_file);
if (ui_current) {
// ignore event if i am not loyal
if (!ui_current->loyal) continue;
free(ui_current->config);
ui_current->config = config;
ui_current->config_len = msgsize;
@@ -352,7 +436,9 @@ reconnect:
if (msgsize) {
if (msgsize >= 0xff) { free(config); continue; }
#ifdef UWSGI_DEBUG
uwsgi_log("%.*s\n", (int)msgsize, config);
#endif
char *config_file = uwsgi_concat2n(config, msgsize, "", 0);
free(config);
@@ -371,6 +457,8 @@ reconnect:
ui_current = emperor_get(config_file);
if (ui_current) {
// ignore event if i am not loyal
if (!ui_current->loyal) continue;
emperor_respawn(ui_current, time(NULL));
}
else {
@@ -381,11 +469,40 @@ reconnect:
}
}
}
else {
ui_current = emperor_get_by_fd(interesting_fd);
if (ui_current) {
char byte;
ssize_t rlen = read(interesting_fd, &byte, 1);
if (rlen <= 0) {
emperor_del(ui_current);
}
else {
if (byte == 17) {
ui_current->loyal = 1;
uwsgi_log("*** vassal %s is now loyal ***\n", ui_current->name);
// TODO post-start hook
}
}
}
else {
uwsgi_log("unrecognized event on fd %d\n", interesting_fd);
event_queue_del_fd(emperor_queue, interesting_fd, event_queue_read());
close(interesting_fd);
}
}
}
else if (simple_mode) {
if (amqp_fd == -1) {
if (simple_mode) {
DIR *dir = opendir(".");
while ((de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") || !strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") || !strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") || !strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml")
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") ||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") ||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") ||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml") ||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js")
) {
@@ -423,6 +540,7 @@ reconnect:
if (!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".xml") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".ini") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".yml") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 3), ".js") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".yaml")
) {
@@ -451,6 +569,7 @@ reconnect:
}
}
}
// check for removed instances
@@ -461,6 +580,12 @@ reconnect:
has_children++;
}
if (uwsgi.notify) {
if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) {
uwsgi_notify(notification_message);
}
}
if (has_children) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
@@ -475,6 +600,14 @@ reconnect:
ui_current = ui;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
// check loyalty if not in simple/glob mode
if (amqp_fd > -1) {
if (!ui_current->loyal && (time(NULL)-ui_current->last_loyal) > 60) {
uwsgi_log("!!! no loyalty showed by instance %s !!!\n", ui_current->name);
emperor_del(ui_current);
break;
}
}
if (ui_current->status == 1) {
if (ui_current->config) free(ui_current->config);
emperor_del(ui_current);
@@ -504,8 +637,6 @@ reconnect:
}
}
if (amqp_fd < 0)
sleep(3);
}
+27 -1
View File
@@ -2,10 +2,36 @@ require 'fiber'
class SuspendingBody
def each
for i in 1..10
for i in 1..3
yield "number: #{i}\n"
UWSGI.async_sleep(1)
puts "sleep..."
Fiber.yield
end
fd = UWSGI.async_connect("81.174.68.52:80")
UWSGI.wait_fd_write(fd, 3)
Fiber.yield
io = IO.new(fd)
puts "connected"
io.syswrite("GET /uwsgi/export/1081%3A362d695b2f25/plugins/fiber/fiber.c HTTP/1.0\r\n")
io.syswrite("Host: projects.unbit.it\r\n")
io.syswrite("\r\n")
UWSGI.wait_fd_read(fd, 3)
Fiber.yield
puts "data available"
begin
while body = io.sysread(fd)
yield body
Fiber.yield
end
rescue
end
io.close
end
end
+27
View File
@@ -0,0 +1,27 @@
[uwsgi]
master = true
processes = 4
threads = 8
; initialize 4 sockets with 4 different protocols
socket = :3031
socket = :3032
socket = :3033
socket = :3034
socket-protocol = 0,uwsgi
socket-protocol = 1,http
socket-protocol = 2,fastcgi
socket-protocol = 3,uwsgidump
; add a cache with 1000 items of 96k
cache = 1000
cache-blocksize = 98304
log-micros = true
module = heavytest
mount = /cc=uwsgicc/__init__.py
+14
View File
@@ -0,0 +1,14 @@
import uwsgi
import werkzeug.testapp
uwsgi.cache_set("/cache/get", "HTTP 1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>I am the uWSGI cache</h1>")
def app001(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return "PATH_INFO=%s" % env['PATH_INFO']
def app002(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return "requests: %d" % uwsgi.total_requests()
uwsgi.applications = { '':werkzeug.testapp.test_app, '/app001':app001, '/app002':app002 }
+8 -1
View File
@@ -87,7 +87,14 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
char *section_asked = "uwsgi";
char *colon;
colon = uwsgi_get_last_char(file, ':');
if (!uwsgi_startswith(file, "http://", 7)) {
colon = uwsgi_get_last_char(file, '/');
colon = uwsgi_get_last_char(colon, ':');
}
else {
colon = uwsgi_get_last_char(file, ':');
}
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
+107
View File
@@ -0,0 +1,107 @@
#ifdef UWSGI_JSON
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
#include <jansson.h>
/*
I really love the jansson library...
*/
void uwsgi_json_config(char *file, char *magic_table[]) {
int len = 0;
char *json_data;
const char *key;
json_t *root;
json_error_t error;
json_t *config;
json_t *config_value, *config_array_item;
void *config_iter;
char *object_asked = "uwsgi";
char *colon;
int i;
if (!uwsgi_startswith(file, "http://", 7)) {
colon = uwsgi_get_last_char(file, '/');
colon = uwsgi_get_last_char(colon, ':');
}
else {
colon = uwsgi_get_last_char(file, ':');
}
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
object_asked = colon+1;
}
}
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
root = json_loads(json_data, 0, &error);
if (!root) {
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
exit(1);
}
config = json_object_get(root, object_asked);
if (!json_is_object(config)) {
uwsgi_log("you must define a object named %s in your JSON data\n", object_asked);
exit(1);
}
config_iter = json_object_iter(config);
while(config_iter) {
key = json_object_iter_key(config_iter);
config_value = json_object_iter_value(config_iter);
if (json_is_string(config_value)) {
add_exported_option((char *)key, (char *) json_string_value(config_value), 0);
}
else if (json_is_true(config_value)) {
add_exported_option((char *)key, (char *) "1", 0);
}
else if (json_is_false(config_value) || json_is_null(config_value)) {
add_exported_option((char *)key, (char *) "0", 0);
}
else if (json_is_integer(config_value)) {
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_value)), 0);
}
else if (json_is_array(config_value)) {
for(i=0;i<(int)json_array_size(config_value);i++) {
config_array_item = json_array_get(config_value, i);
if (json_is_string(config_array_item)) {
add_exported_option((char *)key, (char *) json_string_value(config_array_item), 0);
}
else if (json_is_true(config_array_item)) {
add_exported_option((char *)key, (char *) "1", 0);
}
else if (json_is_false(config_array_item) || json_is_null(config_array_item)) {
add_exported_option((char *)key, (char *) "0", 0);
}
else if (json_is_integer(config_array_item)) {
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_array_item)), 0);
}
}
}
config_iter = json_object_iter_next(config, config_iter);
}
}
#endif
+9 -2
View File
@@ -699,7 +699,9 @@ static int amqp_send_connection_start_ok(int fd, char *mech, char *sasl_response
}
int uwsgi_amqp_consume_queue(int fd, char *vhost, char *queue, char *exchange, char *exchange_type) {
int uwsgi_amqp_consume_queue(int fd, char *vhost, char *username, char *password, char *queue, char *exchange, char *exchange_type) {
char *auth = uwsgi_concat4n("\0",1, username, strlen(username), "\0",1, password, strlen(password));
if (send(fd, AMQP_CONNECTION_HEADER, 8, 0) < 0) {
uwsgi_error("send()");
@@ -712,11 +714,14 @@ int uwsgi_amqp_consume_queue(int fd, char *vhost, char *queue, char *exchange, c
}
uwsgi_log("sending Connection.start-ok\n");
if (amqp_send_connection_start_ok(fd, "PLAIN", "\0guest\0guest", 12, "en_US") < 0) {
if (amqp_send_connection_start_ok(fd, "PLAIN", auth, strlen(username)+strlen(password)+2, "en_US") < 0) {
free(auth);
uwsgi_log("AMQP error sending Connection.start-ok\n");
return -1;
}
free(auth);
if (amqp_wait_connection_tune(fd) < 0) {
uwsgi_log("AMQP error waiting for Connection.tune\n");
return -1;
@@ -795,5 +800,7 @@ int uwsgi_amqp_consume_queue(int fd, char *vhost, char *queue, char *exchange, c
}
free(queue);
uwsgi_log("AMQP subscription done, waiting for events...\n");
return 0;
}
+149
View File
@@ -0,0 +1,149 @@
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
#ifndef CLONE_NEWUTS
#define CLONE_NEWUTS 0x04000000
#endif
#ifndef CLONE_NEWPID
#define CLONE_NEWPID 0x20000000
#endif
#ifndef CLONE_NEWIPC
#define CLONE_NEWIPC 0x08000000
#endif
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000
#endif
void linux_namespace_start(void *argv) {
for (;;) {
char stack[PTHREAD_STACK_MIN];
int waitpid_status;
uwsgi_log("*** jailing uWSGI in %s ***\n", uwsgi.ns);
int clone_flags = SIGCHLD | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS;
if (uwsgi.ns_net) {
clone_flags |= CLONE_NEWNET;
}
pid_t pid = clone(uwsgi_start, stack + PTHREAD_STACK_MIN, clone_flags, (void *) argv);
if (pid == -1) {
uwsgi_error("clone()");
exit(1);
}
uwsgi_log("waiting for jailed master (pid: %d) death...\n", (int) pid);
pid = waitpid(pid, &waitpid_status, 0);
if (pid < 0) {
uwsgi_error("waitpid()");
exit(1);
}
// in Linux this is reliable
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == 1) {
exit(1);
}
uwsgi_log("pid %d ended. Respawning...\n", (int) pid);
}
// never here
}
void linux_namespace_jail() {
char *ns_tmp_mountpoint = NULL, *ns_tmp_mountpoint2 = NULL;
if (getpid() != 1) {
uwsgi_log("your kernel does not support linux pid namespace\n");
exit(1);
}
char *ns_hostname = strchr(uwsgi.ns, ':');
if (ns_hostname) {
ns_hostname[0] = 0;
ns_hostname++;
if (sethostname(ns_hostname, strlen(ns_hostname))) {
uwsgi_error("sethostname()");
}
}
FILE *procmounts;
char line[1024];
int unmounted = 1;
char *delim0, *delim1;
if (chdir(uwsgi.ns)) {
uwsgi_error("chdir()");
exit(1);
}
if (strcmp(uwsgi.ns, "/")) {
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint, S_IRWXU);
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint2, S_IRWXU);
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
uwsgi_error("mount()");
}
if (chdir(ns_tmp_mountpoint)) {
uwsgi_error("chdir()");
}
if (pivot_root(".", ns_tmp_mountpoint2)) {
uwsgi_error("pivot_root()");
exit(1);
}
if (chdir("/")) {
uwsgi_error("chdir()");
exit(1);
}
}
uwsgi_log("remounting /proc\n");
if (mount("proc", "/proc", "proc", 0, NULL)) {
uwsgi_error("mount()");
}
while (unmounted) {
unmounted = 0;
procmounts = fopen("/proc/self/mounts", "r");
while (fgets(line, 1024, procmounts) != NULL) {
delim0 = strchr(line, ' ');
delim0++;
delim1 = strchr(delim0, ' ');
*delim1 = 0;
if (!strcmp(delim0, "/") || !strcmp(delim0, "/proc"))
continue;
if (!umount(delim0)) {
unmounted++;
}
}
fclose(procmounts);
}
if (rmdir("/.uwsgi_ns_tmp_mountpoint/.uwsgi_ns_tmp_mountpoint")) {
uwsgi_error("rmdir()");
}
if (rmdir("/.uwsgi_ns_tmp_mountpoint")) {
uwsgi_error("rmdir()");
}
if (strcmp(uwsgi.ns, "/")) {
free(ns_tmp_mountpoint2);
free(ns_tmp_mountpoint);
}
}
+3
View File
@@ -4,6 +4,8 @@
#include <linux/rtnetlink.h>
#include <net/if.h>
#ifdef CLONE_NEWNET
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
@@ -377,3 +379,4 @@ int uwsgi_nl_send(struct nlmsghdr *nlmsg) {
close(nlfd);
return ret;
}
#endif
+2
View File
@@ -47,6 +47,8 @@ void log_request(struct wsgi_request *wsgi_req) {
struct uwsgi_app *wi;
if (wsgi_req->do_not_log) return ;
if (wsgi_req->app_id >= 0) {
wi = &uwsgi.apps[wsgi_req->app_id];
if (wi->requests > 0) {
+131 -18
View File
@@ -2,12 +2,16 @@
extern struct uwsgi_server uwsgi;
struct wsgi_request* threaded_current_wsgi_req() { return pthread_getspecific(uwsgi.tur_key); }
struct wsgi_request* simple_current_wsgi_req() { return uwsgi.wsgi_req; }
struct wsgi_request *threaded_current_wsgi_req() {
return pthread_getspecific(uwsgi.tur_key);
}
struct wsgi_request *simple_current_wsgi_req() {
return uwsgi.wsgi_req;
}
void uwsgi_register_loop(char *name, void *loop) {
if (uwsgi.loops_cnt >= MAX_LOOPS) {
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
exit(1);
@@ -21,8 +25,8 @@ void uwsgi_register_loop(char *name, void *loop) {
void *uwsgi_get_loop(char *name) {
int i;
for(i=0;i<uwsgi.loops_cnt;i++) {
for (i = 0; i < uwsgi.loops_cnt; i++) {
if (!strcmp(name, uwsgi.loops[i].name)) {
return uwsgi.loops[i].loop;
}
@@ -44,46 +48,155 @@ void *simple_loop(void *arg1) {
if (uwsgi.threads > 1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
for(i=0;i<0xFF;i++) {
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
/*
pts = PyThreadState_New(uwsgi.main_thread->interp);
pthread_setspecific(uwsgi.ut_save_key, (void *) pts);
*/
}
}
#endif
// initialize the main event queue to monitor sockets
uwsgi.main_queue = event_queue_init();
uwsgi_add_sockets_to_queue(uwsgi.main_queue);
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(uwsgi.main_queue, uwsgi.signal_socket);
}
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
UWSGI_CLEAR_STATUS;
wsgi_req_setup(wsgi_req, core_id);
wsgi_req_setup(wsgi_req, core_id, NULL);
if (wsgi_req_accept(wsgi_req)) {
continue;
}
if (wsgi_req_recv(wsgi_req)) {
uwsgi_destroy_request(wsgi_req);
continue;
}
uwsgi_close_request(wsgi_req);
}
pthread_exit(NULL);
//never here
// end of the loop
return NULL;
}
#ifdef UWSGI_ZEROMQ
void *zeromq_loop(void *arg1) {
sigset_t smask;
int i;
long core_id = (long) arg1;
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
uwsgi.zeromq_recv_flag = 0;
zmq_pollitem_t zmq_poll_items[2];
char uwsgi_signal;
if (uwsgi.threads > 1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi.zmq_receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi.zmq_pull, tmp_zmq_pull);
}
}
if (uwsgi.signal_socket > -1) {
zmq_poll_items[0].socket = pthread_getspecific(uwsgi.zmq_pull);
zmq_poll_items[0].fd = -1;
zmq_poll_items[0].events = ZMQ_POLLIN;
zmq_poll_items[1].socket = NULL;
zmq_poll_items[1].fd = uwsgi.signal_socket;
zmq_poll_items[1].events = ZMQ_POLLIN;
}
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
wsgi_req_setup(wsgi_req, core_id, NULL);
uwsgi.edge_triggered = 1;
wsgi_req->socket = uwsgi.zmq_socket;
if (uwsgi.signal_socket > -1) {
if (zmq_poll(zmq_poll_items, 2, -1) < 0) {
uwsgi_error("zmq_poll()");
continue;
}
if (zmq_poll_items[1].revents & ZMQ_POLLIN) {
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) <= 0) {
if (uwsgi.no_orphans) {
uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid);
end_me(0);
}
}
else {
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
}
}
continue;
}
if (zmq_poll_items[0].revents & ZMQ_POLLIN) {
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
}
}
else {
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
}
if (wsgi_req->poll.fd >= 0) {
wsgi_req_recv(wsgi_req);
}
uwsgi_close_request(wsgi_req);
}
// end of the loop
return NULL;
}
#endif
+183 -112
View File
@@ -2,6 +2,17 @@
extern struct uwsgi_server uwsgi;
void uwsgi_restore_auto_snapshot(int signum) {
if (uwsgi.workers[1].snapshot > 0) {
uwsgi.restore_snapshot = 1;
}
else {
uwsgi_log("[WARNING] no snapshot available\n");
}
}
void expire_rb_timeouts(struct rb_root *root) {
time_t current = time(NULL);
@@ -65,10 +76,10 @@ void uwsgi_subscribe(char *subscription) {
memcpy(ssb, "address", ustrlen);
ssb+=ustrlen;
ustrlen = strlen(uwsgi.sockets[0].name);
ustrlen = strlen(uwsgi.sockets->name);
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, uwsgi.sockets[0].name, ustrlen);
memcpy(ssb, uwsgi.sockets->name, ustrlen);
ssb+=ustrlen;
send_udp_message(224, udp_address, subscrbuf, ssb-subscrbuf);
@@ -121,24 +132,19 @@ void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t val
void master_loop(char **argv, char **environ) {
uint64_t master_cycles = 0;
uint64_t tmp_counter;
char log_buf[4096];
time_t current_time = time(NULL);
struct timeval last_respawn;
int last_respawn_rate = 0;
pid_t pid;
int pid_found = 0;
pid_t diedpid;
int waitpid_status;
int working_workers = 0;
int blocking_workers = 0;
int ready_to_reload = 0;
int ready_to_die = 0;
@@ -146,6 +152,9 @@ void master_loop(char **argv, char **environ) {
uint8_t uwsgi_signal;
time_t last_request_timecheck = 0;
uint64_t last_request_count = 0;
#ifdef UWSGI_UDP
struct sockaddr_in udp_client;
socklen_t udp_len;
@@ -168,7 +177,7 @@ void master_loop(char **argv, char **environ) {
int snmp_fd = -1;
#endif
int i=0,j;
int i=0;
int rlen;
int check_interval = 1;
@@ -177,12 +186,22 @@ void master_loop(char **argv, char **environ) {
struct rb_root *rb_timers = uwsgi_init_rb_timer();
struct tm *uwsgi_cron_delta;
uwsgi.current_time = time(NULL);
uwsgi_unix_signal(SIGHUP, grace_them_all);
uwsgi_unix_signal(SIGTERM, reap_them_all);
if (uwsgi.die_on_term) {
uwsgi_unix_signal(SIGTERM, kill_them_all);
uwsgi_unix_signal(SIGQUIT, reap_them_all);
}
else {
uwsgi_unix_signal(SIGTERM, reap_them_all);
uwsgi_unix_signal(SIGQUIT, kill_them_all);
}
uwsgi_unix_signal(SIGINT, kill_them_all);
uwsgi_unix_signal(SIGQUIT, kill_them_all);
uwsgi_unix_signal(SIGUSR1, stats);
if (uwsgi.auto_snapshot) {
uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot);
}
uwsgi.master_queue = event_queue_init();
@@ -217,6 +236,12 @@ void master_loop(char **argv, char **environ) {
event_queue_add_fd_read(uwsgi.master_queue, udp_fd);
}
}
if (uwsgi.cheap) {
uwsgi_add_sockets_to_queue(uwsgi.master_queue);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
}
#ifdef UWSGI_MULTICAST
if (uwsgi.cluster) {
@@ -379,29 +404,46 @@ void master_loop(char **argv, char **environ) {
}
}
}
if (ready_to_die >= uwsgi.numproc && uwsgi.to_hell) {
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
kill(uwsgi.shared->spooler_pid, SIGKILL);
uwsgi_log( "killed the spooler with pid %d\n", uwsgi.shared->spooler_pid);
if (uwsgi.respawn_workers) {
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi_respawn_worker(i)) return;
}
#endif
uwsgi.respawn_workers = 0;
}
if (uwsgi.restore_snapshot) {
uwsgi_log("[snapshot] restoring workers...\n");
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid == 0) continue;
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
if (uwsgi.auto_snapshot > 0 && i > uwsgi.auto_snapshot) {
uwsgi.workers[i].pid = 0;
uwsgi.workers[i].snapshot = 0;
}
else {
uwsgi.workers[i].pid = uwsgi.workers[i].snapshot;
uwsgi.workers[i].snapshot = 0;
kill(uwsgi.workers[i].pid, SIGURG);
uwsgi_log( "Restored uWSGI worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
}
}
uwsgi.restore_snapshot = 0;
continue;
}
if ((uwsgi.cheap || ready_to_die >= uwsgi.numproc) && uwsgi.to_hell) {
// call a series of waitpid to ensure all processes (gateways and daemons) are dead
for(i=0;i<(uwsgi.gateways_cnt+ushared->daemons_cnt);i++) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
// TODO kill all the gateways
uwsgi_log( "goodbye to uWSGI.\n");
exit(0);
}
if (ready_to_reload >= uwsgi.numproc && uwsgi.to_heaven) {
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
kill(uwsgi.shared->spooler_pid, SIGKILL);
uwsgi_log( "wait4() the spooler with pid %d...", uwsgi.shared->spooler_pid);
diedpid = waitpid(uwsgi.shared->spooler_pid, &waitpid_status, 0);
uwsgi_log( "done.");
}
#endif
if ( (uwsgi.cheap || ready_to_reload >= uwsgi.numproc) && uwsgi.to_heaven) {
// call a series of waitpid to ensure all processes (gateways and daemons) are dead
for(i=0;i<(uwsgi.gateways_cnt+ushared->daemons_cnt);i++) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
@@ -422,12 +464,14 @@ void master_loop(char **argv, char **environ) {
uwsgi_log( "closing all non-uwsgi socket fds > 2 (_SC_OPEN_MAX = %ld)...\n", sysconf(_SC_OPEN_MAX));
for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
int found = 0;
for(j=0;j<uwsgi.sockets_cnt;j++) {
if (i == uwsgi.sockets[j].fd) {
uwsgi_log("found fd %d mapped to socket %d (%s)\n", i, j, uwsgi.sockets[j].name);
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (i == uwsgi_sock->fd) {
uwsgi_log("found fd %d mapped to socket %d (%s)\n", i, uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
found = 1;
break;
}
uwsgi_sock = uwsgi_sock->next;
}
if (!found) {
@@ -438,7 +482,11 @@ void master_loop(char **argv, char **environ) {
}
}
if (!found) {
#ifdef __APPLE__
fcntl(i, F_SETFD, FD_CLOEXEC);
#else
close(i);
#endif
}
}
@@ -451,14 +499,17 @@ void master_loop(char **argv, char **environ) {
exit(1);
}
if (uwsgi.numproc > 0 || uwsgi.gateways_cnt > 0 || ushared->daemons_cnt > 0) {
master_has_children = 1;
}
if (!uwsgi.cheap) {
if (uwsgi.numproc > 0 || uwsgi.gateways_cnt > 0 || ushared->daemons_cnt > 0) {
master_has_children = 1;
}
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
master_has_children = 1;
}
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
master_has_children = 1;
}
#endif
}
if (!master_has_children) {
diedpid = 0;
@@ -546,8 +597,8 @@ void master_loop(char **argv, char **environ) {
// check uwsgi-cron table
if (ushared->cron_cnt) {
current_time = time(NULL);
uwsgi_cron_delta = localtime( &current_time );
uwsgi.current_time = time(NULL);
uwsgi_cron_delta = localtime( &uwsgi.current_time );
if (uwsgi_cron_delta) {
@@ -598,9 +649,9 @@ void master_loop(char **argv, char **environ) {
// date match, signal it ?
if (current_time - ucron->last_job > 60) {
if (uwsgi.current_time - ucron->last_job > 60) {
uwsgi_route_signal(ucron->sig);
ucron->last_job = current_time;
ucron->last_job = uwsgi.current_time;
}
}
@@ -621,6 +672,19 @@ void master_loop(char **argv, char **environ) {
if (uwsgi.log_syslog) {
syslog(LOG_INFO, "%.*s", rlen, log_buf);
}
#ifdef UWSGI_ZEROMQ
else if (uwsgi.zmq_log_socket) {
zmq_msg_t msg;
if (zmq_msg_init_size (&msg, rlen) == 0) {
memcpy(zmq_msg_data(&msg), log_buf, rlen);
zmq_send(uwsgi.zmq_log_socket, &msg, 0);
zmq_msg_close(&msg);
}
}
#endif
else if (uwsgi.log_socket) {
sendto(uwsgi.log_socket_fd, log_buf, rlen, 0, &uwsgi.log_socket_addr->sa, uwsgi.log_socket_size);
}
// TODO allow uwsgi.logger = func
}
}
@@ -651,6 +715,25 @@ void master_loop(char **argv, char **environ) {
}
}
}
if (uwsgi.cheap) {
int found = 0 ;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
found = 1;
uwsgi.cheap = 0;
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi_respawn_worker(i)) return;
}
break;
}
uwsgi_sock = uwsgi_sock->next;
}
if (found) continue;
}
#ifdef UWSGI_SNMP
if (uwsgi.snmp_addr && interesting_fd == snmp_fd) {
udp_len = sizeof(udp_client);
@@ -813,7 +896,7 @@ void master_loop(char **argv, char **environ) {
}
}
current_time = time(NULL);
uwsgi.current_time = time(NULL);
// checking logsize
if (uwsgi.logfile) {
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
@@ -831,19 +914,40 @@ void master_loop(char **argv, char **environ) {
}
master_cycles++;
working_workers = 0;
blocking_workers = 0;
uwsgi.master_cycles++;
// recalculate requests counter on race conditions risky configurations
// a bit of inaccuracy is better than locking;)
if (uwsgi.numproc > 1) {
tmp_counter = 0;
for(i=1;i<uwsgi.numproc+1;i++) {
for(i=1;i<uwsgi.numproc+1;i++)
tmp_counter += uwsgi.workers[i].requests;
}
uwsgi.workers[0].requests = tmp_counter;
if (uwsgi.idle > 0 && !uwsgi.cheap) {
uwsgi.current_time = time(NULL);
if (!last_request_timecheck) last_request_timecheck = uwsgi.current_time;
if (last_request_count != uwsgi.workers[0].requests) {
last_request_timecheck = uwsgi.current_time;
last_request_count = uwsgi.workers[0].requests;
}
else if (uwsgi.current_time - last_request_timecheck > uwsgi.idle) {
uwsgi_log("workers have been inactive for more than %d seconds\n", uwsgi.idle);
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid == 0) continue;
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
master_has_children = 0;
uwsgi.cheap = 1;
uwsgi_add_sockets_to_queue(uwsgi.master_queue);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
last_request_timecheck = 0;
continue;
}
}
}
// remove expired cache items TODO use rb_tree timeouts
@@ -851,7 +955,7 @@ void master_loop(char **argv, char **environ) {
for(i=0;i< (int)uwsgi.cache_max_items;i++) {
uwsgi_wlock(uwsgi.cache_lock);
if (uwsgi.cache_items[i].expires) {
if (uwsgi.cache_items[i].expires < (uint64_t) current_time) {
if (uwsgi.cache_items[i].expires < (uint64_t) uwsgi.current_time) {
uwsgi_cache_del(uwsgi.cache_items[i].key, uwsgi.cache_items[i].keysize);
}
}
@@ -865,16 +969,19 @@ void master_loop(char **argv, char **environ) {
#ifdef __linux__
for(i=0;i<uwsgi.sockets_cnt;i++) {
if (uwsgi.sockets[i].family != AF_INET) continue;
get_linux_tcp_info(uwsgi.sockets[i].fd);
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->family == AF_INET) {
get_linux_tcp_info(uwsgi_sock->fd);
}
uwsgi_sock = uwsgi_sock->next;
}
#endif
for (i = 1; i <= uwsgi.numproc; i++) {
/* first check for harakiri */
if (uwsgi.workers[i].harakiri > 0) {
if (uwsgi.workers[i].harakiri < (time_t) current_time) {
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
/* first try to invoke the harakiri() custom handler */
/* TODO */
/* then brutally kill the worker */
@@ -921,49 +1028,22 @@ void master_loop(char **argv, char **environ) {
uwsgi.workers[i].harakiri = 0;
}
}
/* load counters */
if (uwsgi.workers[i].status & UWSGI_STATUS_IN_REQUEST)
working_workers++;
if (uwsgi.workers[i].status & UWSGI_STATUS_BLOCKING)
blocking_workers++;
uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
// need to find a better way
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
}
#ifdef UWSGI_UDP
// check for cluster nodes
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
struct uwsgi_cluster_node *ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
// should i retry ?
if (master_cycles % ucn->errors == 0) {
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
ucn->status = UWSGI_NODE_OK;
uwsgi_log( "re-enabled cluster node %d/%s\n", i, ucn->name);
}
else {
ucn->errors++;
}
}
}
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
if ( (current_time - ucn->last_seen) > 30) {
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
ucn->name[0] = 0 ;
}
}
}
master_check_cluster_nodes();
// reannounce myself every 10 cycles
if (uwsgi.cluster && uwsgi.cluster_fd >= 0 && !uwsgi.cluster_nodes && (master_cycles % 10) == 0) {
if (uwsgi.cluster && uwsgi.cluster_fd >= 0 && !uwsgi.cluster_nodes && (uwsgi.master_cycles % 10) == 0) {
uwsgi_cluster_add_me();
}
// resubscribe every 10 cycles
if (uwsgi.subscriptions_cnt > 0 && ((master_cycles % 10) == 0 || master_cycles == 1)) {
if (uwsgi.subscriptions_cnt > 0 && ((uwsgi.master_cycles % 10) == 0 || uwsgi.master_cycles == 1)) {
for(i=0;i<uwsgi.subscriptions_cnt;i++) {
uwsgi_subscribe(uwsgi.subscriptions[i]);
}
@@ -971,13 +1051,13 @@ void master_loop(char **argv, char **environ) {
#endif
if (uwsgi.cache_store && uwsgi.cache_filesize && uwsgi.cache_store_sync && ((master_cycles % uwsgi.cache_store_sync) == 0)) {
if (uwsgi.cache_store && uwsgi.cache_filesize && uwsgi.cache_store_sync && ((uwsgi.master_cycles % uwsgi.cache_store_sync) == 0)) {
if (msync(uwsgi.cache_items, uwsgi.cache_filesize, MS_ASYNC)) {
uwsgi_error("msync()");
}
}
if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((master_cycles % uwsgi.queue_store_sync) == 0)) {
if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((uwsgi.master_cycles % uwsgi.queue_store_sync) == 0)) {
if (msync(uwsgi.queue, uwsgi.queue_filesize, MS_ASYNC)) {
uwsgi_error("msync()");
}
@@ -993,7 +1073,7 @@ void master_loop(char **argv, char **environ) {
}
else {
if (tr_st.st_mtime > uwsgi.last_touch_reload_mtime) {
uwsgi_log("*** %s has been touched... grace them all !!! ***\n");
uwsgi_log("*** %s has been touched... grace them all !!! ***\n", uwsgi.touch_reload);
grace_them_all(0);
}
}
@@ -1006,6 +1086,9 @@ void master_loop(char **argv, char **environ) {
continue;
}
// reload gateways and daemons only on normal workflow
if (!uwsgi.to_heaven && !uwsgi.to_hell) {
#ifdef UWSGI_SPOOLER
/* reload the spooler */
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
@@ -1017,8 +1100,6 @@ void master_loop(char **argv, char **environ) {
}
#endif
// reload gateways and daemons only on normal workflow
if (!uwsgi.to_heaven && !uwsgi.to_hell) {
/* reload the gateways */
// TODO reload_gateway(diedpid);
pid_found = 0;
@@ -1044,6 +1125,7 @@ void master_loop(char **argv, char **environ) {
}
if (pid_found) continue;
}
/* What happens here ?
@@ -1092,9 +1174,16 @@ void master_loop(char **argv, char **environ) {
}
gettimeofday(&last_respawn, NULL);
if (last_respawn.tv_sec == uwsgi.respawn_delta) {
uwsgi_log( "worker respawning too fast !!! i have to sleep a bit...\n");
/* TODO, user configurable fork throttler */
sleep(2);
last_respawn_rate++;
if (last_respawn_rate > uwsgi.numproc) {
uwsgi_log( "worker respawning too fast !!! i have to sleep a bit...\n");
/* TODO, user configurable fork throttler */
sleep(2);
last_respawn_rate = 0;
}
}
else {
last_respawn_rate = 0;
}
gettimeofday(&last_respawn, NULL);
uwsgi.respawn_delta = last_respawn.tv_sec;
@@ -1106,27 +1195,9 @@ void master_loop(char **argv, char **environ) {
continue;
}
*/
pid = fork();
if (pid == 0) {
// fix the communication pipe
close(uwsgi.shared->worker_signal_pipe[0]);
uwsgi.mypid = getpid();
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
uwsgi.workers[uwsgi.mywid].harakiri = 0;
uwsgi.workers[uwsgi.mywid].requests = 0;
uwsgi.workers[uwsgi.mywid].failed_requests = 0;
uwsgi.workers[uwsgi.mywid].respawn_count++;
uwsgi.workers[uwsgi.mywid].last_spawn = current_time;
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
break;
}
else if (pid < 1) {
uwsgi_error("fork()");
}
else {
uwsgi_log( "Respawned uWSGI worker %d (new pid: %d)\n", uwsgi.mywid, (int) pid);
}
if (uwsgi_respawn_worker(uwsgi.mywid)) return;
}
}
}
+69
View File
@@ -0,0 +1,69 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
void master_check_cluster_nodes() {
int i;
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
struct uwsgi_cluster_node *ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
// should i retry ?
if (uwsgi.master_cycles % ucn->errors == 0) {
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
ucn->status = UWSGI_NODE_OK;
uwsgi_log( "re-enabled cluster node %d/%s\n", i, ucn->name);
}
else {
ucn->errors++;
}
}
}
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
if ( (uwsgi.current_time - ucn->last_seen) > 30) {
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
ucn->name[0] = 0 ;
}
}
}
}
int uwsgi_respawn_worker(int wid) {
int respawns = uwsgi.workers[wid].respawn_count;
pid_t pid = fork();
if (pid == 0) {
uwsgi.mywid = wid;
// fix the communication pipe
close(uwsgi.shared->worker_signal_pipe[0]);
uwsgi.mypid = getpid();
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
uwsgi.workers[uwsgi.mywid].harakiri = 0;
uwsgi.workers[uwsgi.mywid].requests = 0;
uwsgi.workers[uwsgi.mywid].failed_requests = 0;
uwsgi.workers[uwsgi.mywid].respawn_count++;
uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time;
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
return 1;
}
else if (pid < 1) {
uwsgi_error("fork()");
}
else {
if (respawns > 0) {
uwsgi_log( "Respawned uWSGI worker %d (new pid: %d)\n", uwsgi.mywid, (int) pid);
}
else {
uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores);
}
}
return 0;
}
+23
View File
@@ -0,0 +1,23 @@
main = Server(
uuid="f400bf85-4538-4f7a-8908-67e313d515c2",
access_log="/logs/access.log",
error_log="/logs/error.log",
chroot="./",
default_host="192.168.173.18",
name="test",
pid_file="/run/mongrel2.pid",
port=6767,
hosts = [
Host(name="192.168.173.18", routes={
'/': Handler(send_spec='tcp://192.168.173.18:9999',
send_ident='54c6755b-9628-40a4-9a2d-cc82a816345e',
recv_spec='tcp://192.168.173.18:9998', recv_ident='')
})
]
)
settings = {'upload.temp_store':'tmp/mongrel2.upload.XXXXXX'}
servers = [main]
uwsgi = { 'socket':':3031', 'master':'true'}
+72
View File
@@ -0,0 +1,72 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
void uwsgi_systemd_notify(char *message) {
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
struct iovec *iovec = msghdr->msg_iov;
iovec[0].iov_base = "STATUS=";
iovec[0].iov_len = 7;
iovec[1].iov_base = message;
iovec[1].iov_len = strlen(message);
iovec[2].iov_base = "\n";
iovec[2].iov_len = 1;
msghdr->msg_iovlen = 3;
sendmsg(uwsgi.notification_fd, msghdr, 0);
}
void uwsgi_systemd_notify_ready(void) {
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
struct iovec *iovec = msghdr->msg_iov;
iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n";
iovec[0].iov_len = 30;
msghdr->msg_iovlen = 1;
sendmsg(uwsgi.notification_fd, msghdr, 0);
}
void uwsgi_systemd_init(char *systemd_socket) {
struct sockaddr_un *sd_sun;
struct msghdr *msghdr;
uwsgi.notification_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (uwsgi.notification_fd < 0) {
uwsgi_error("socket()");
return;
}
sd_sun = uwsgi_malloc(sizeof(struct sockaddr_un));
memset(sd_sun, 0, sizeof(struct sockaddr_un));
sd_sun->sun_family = AF_UNIX;
strncpy(sd_sun->sun_path, systemd_socket, sizeof(sd_sun->sun_path));
if (sd_sun->sun_path[0] == '@') sd_sun->sun_path[0] = 0;
msghdr = uwsgi_malloc(sizeof(struct msghdr));
memset(msghdr, 0, sizeof(struct msghdr));
msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec)*3);
memset(msghdr->msg_iov, 0, sizeof(struct iovec)*3);
msghdr->msg_name = sd_sun;
msghdr->msg_namelen = sizeof(struct sockaddr_un);
uwsgi.notification_object = msghdr;
uwsgi.notify = uwsgi_systemd_notify;
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
}
+67 -12
View File
@@ -2,13 +2,15 @@
extern struct uwsgi_server uwsgi;
int uwsgi_load_plugin(int modifier, char *plugin, char *pargs, int absolute) {
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option, int absolute) {
void *plugin_handle;
char *plugin_name;
char *plugin_entry_symbol;
struct uwsgi_plugin *up;
char linkpath_buf[1024], linkpath[1024];
int linkpath_size;
int i;
char *colon = strchr(plugin, ':');
@@ -23,7 +25,7 @@ check:
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
return NULL;
}
}
if (uwsgi.p[i]->alias) {
@@ -31,7 +33,7 @@ check:
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
return NULL;
}
}
}
@@ -43,7 +45,7 @@ check:
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
return NULL;
}
}
if (uwsgi.gp[i]->alias) {
@@ -51,7 +53,7 @@ check:
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
return NULL;
}
}
}
@@ -63,33 +65,86 @@ check:
goto check;
}
if (absolute) {
plugin_name = malloc(strlen(plugin) + 1);
memcpy(plugin_name, plugin, strlen(plugin) + 1);
if (absolute == 1) {
plugin_name = uwsgi_concat2(plugin, "");
// need to fix this... postpone until needed
plugin_entry_symbol = uwsgi_concat2n(plugin, strlen(plugin)-3 ,"", 0);
}
else if (absolute == 2) {
plugin_name = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin);
plugin_entry_symbol = uwsgi_concat2n(plugin, strlen(plugin)-3 ,"", 0);
}
else {
plugin_name = uwsgi_concat4(UWSGI_PLUGIN_DIR, "/", plugin, "_plugin.so");
plugin_entry_symbol = uwsgi_concat2(plugin, "_plugin");
}
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
free(plugin_name);
if (!plugin_handle) {
uwsgi_log( "%s\n", dlerror());
}
else {
plugin_entry_symbol = uwsgi_concat2(plugin, "_plugin");
up = dlsym(plugin_handle, plugin_entry_symbol);
if (!up) {
// is it a link ?
memset(linkpath_buf, 0, 1024);
memset(linkpath, 0, 1024);
if ((linkpath_size = readlink(plugin_name, linkpath_buf, 1023)) > 0) {
do {
linkpath_buf[linkpath_size] = '\0';
strcpy(linkpath, linkpath_buf);
} while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0);
uwsgi_log("%s\n", linkpath);
free(plugin_entry_symbol);
up = dlsym(plugin_handle, plugin_entry_symbol);
char *slash = uwsgi_get_last_char(linkpath, '/');
if (!slash) {
slash = linkpath;
}
else {
slash++;
}
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash)-3, "",0);
up = dlsym(plugin_handle, plugin_entry_symbol);
}
}
if (up) {
if (has_option) {
struct option *lopt = up->options, *aopt;
int found = 0;
while ((aopt = lopt)) {
if (!aopt->name)
break;
if (!strcmp(has_option, aopt->name)) {
found = 1;
break;
}
lopt++;
}
if (!found) {
if (dlclose(plugin_handle)) {
uwsgi_error("dlclose()");
}
free(plugin_name);
free(plugin_entry_symbol);
return NULL;
}
}
if (modifier != -1) {
fill_plugin_table(modifier, up);
}
else {
fill_plugin_table(up->modifier1, up);
}
return 1;
free(plugin_name);
free(plugin_entry_symbol);
return plugin_handle;
}
uwsgi_log( "%s\n", dlerror());
}
return 0;
free(plugin_name);
return NULL;
}
+101
View File
@@ -0,0 +1,101 @@
#include "../../uwsgi.h"
void cache_command(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
struct wsgi_request *wsgi_req = (struct wsgi_request *) data;
uint64_t tmp_vallen = 0;
if (vallen > 0) {
if (!uwsgi_strncmp(key, keylen, "key", 3)) {
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
if (val && tmp_vallen > 0) {
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
}
}
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
if (val && vallen > 0) {
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
}
else {
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 404 Not Found\r\n\r\n<h1>Not Found</h1>", 44);
}
}
}
}
int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
uint64_t vallen = 0;
char *value;
char *argv[3];
uint8_t argc = 0;
switch(wsgi_req->uh.modifier2) {
case 0:
// get
if (wsgi_req->uh.pktsize > 0) {
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
if (value && vallen > 0) {
wsgi_req->uh.pktsize = vallen;
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen);
}
}
break;
case 1:
// set
if (wsgi_req->uh.pktsize > 0) {
argc = 3;
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, &argc)) {
if (argc > 1) {
uwsgi_cache_set(argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), 0, 0);
}
}
}
break;
case 2:
// del
if (wsgi_req->uh.pktsize > 0) {
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize);
}
break;
case 3:
case 4:
// dict
if (wsgi_req->uh.pktsize > 0) {
uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh.pktsize, cache_command, (void *) wsgi_req);
}
break;
case 5:
// get (uwsgi + stream)
if (wsgi_req->uh.pktsize > 0) {
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
if (value && vallen > 0) {
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 1;
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen);
}
else {
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 0;
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
}
}
break;
}
return 0;
}
struct uwsgi_plugin cache_plugin = {
.name = "cache",
.modifier1 = 111,
.request = uwsgi_cache_request,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='cache'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['cache']
+1 -1
View File
@@ -5,7 +5,7 @@ extern struct uwsgi_server uwsgi;
int uwsgi_echo_request(struct wsgi_request *wsgi_req) {
wsgi_req->response_size = write(wsgi_req->poll.fd, wsgi_req->buffer, wsgi_req->uh.pktsize);
wsgi_req->response_size = wsgi_req->socket_proto_write(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
return 0;
}
+1 -1
View File
@@ -11,7 +11,7 @@ int uwsgi_request(struct wsgi_request *wsgi_req) {
char *http = "HTTP/1.1 200 Ok\r\nContent-type: text/html\r\n\r\n<h1>Hello World</h1>";
wsgi_req->response_size += write(wsgi_req->poll.fd, http, strlen(http));
wsgi_req->response_size += wsgi_req->socket_proto_write(wsgi_req, http, strlen(http));
return 0;
}
+108 -49
View File
@@ -18,6 +18,7 @@
#define LONG_ARGS_FASTROUTER_USE_BASE 150004
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER 150005
#define LONG_ARGS_FASTROUTER_TIMEOUT 150006
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT 150007
#define FASTROUTER_STATUS_FREE 0
#define FASTROUTER_STATUS_CONNECTING 1
@@ -28,25 +29,62 @@
#define add_timeout(x) uwsgi_add_rb_timer(ufr.timeouts, time(NULL)+ufr.socket_timeout, x)
#define del_timeout(x) rb_erase(&x->timeout->rbt, ufr.timeouts); free(x->timeout);
struct uwsgi_fastrouter_socket {
char *name;
int fd;
struct uwsgi_fastrouter_socket *next;
};
struct uwsgi_fastrouter {
char *socket_name;
int use_cache;
int nevents;
char *pattern;
int pattern_len;
struct uwsgi_fastrouter_socket *sockets;
char *base;
int base_len;
int use_cache;
int nevents;
char *subscription_server;
struct uwsgi_dict *subscription_dict;
int subscription_slot;
int socket_timeout;
char *pattern;
int pattern_len;
struct rb_root *timeouts;
char *base;
int base_len;
char *subscription_server;
struct uwsgi_dict *subscription_dict;
int socket_timeout;
struct rb_root *timeouts;
} ufr;
static struct uwsgi_fastrouter_socket *uwsgi_fastrouter_new_socket(char *name) {
struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets, *old_uwsgi_sock;
if (!uwsgi_sock) {
ufr.sockets = uwsgi_malloc(sizeof(struct uwsgi_fastrouter_socket));
uwsgi_sock = ufr.sockets;
}
else {
while(uwsgi_sock) {
old_uwsgi_sock = uwsgi_sock;
uwsgi_sock = uwsgi_sock->next;
}
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_fastrouter_socket));
old_uwsgi_sock->next = uwsgi_sock;
}
memset(uwsgi_sock, 0, sizeof(struct uwsgi_fastrouter_socket));
uwsgi_sock->name = name;
return uwsgi_sock;
}
struct option fastrouter_options[] = {
{"fastrouter", required_argument, 0, LONG_ARGS_FASTROUTER},
{"fastrouter-use-cache", no_argument, &ufr.use_cache, 1},
@@ -54,6 +92,7 @@ struct option fastrouter_options[] = {
{"fastrouter-use-base", required_argument, 0, LONG_ARGS_FASTROUTER_USE_BASE},
{"fastrouter-events", required_argument, 0, LONG_ARGS_FASTROUTER_EVENTS},
{"fastrouter-subscription-server", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER},
{"fastrouter-subscription-slot", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT},
{"fastrouter-timeout", required_argument, 0, LONG_ARGS_FASTROUTER_TIMEOUT},
{0, 0, 0, 0},
};
@@ -163,7 +202,6 @@ struct fastrouter_session *alloc_fr_session() {
void fastrouter_loop() {
int fr_queue;
int fr_server = -1;
int nevents;
int interesting_fd;
int new_connection;
@@ -210,37 +248,43 @@ void fastrouter_loop() {
fr_table[i] = NULL;
}
if (ufr.socket_name[0] == '=') {
int shared_socket = atoi(ufr.socket_name+1);
if (shared_socket >= 0 && shared_socket < uwsgi.shared_sockets_cnt) {
if (uwsgi.shared_sockets[shared_socket].name) {
fr_server = uwsgi.shared_sockets[shared_socket].fd;
}
else {
uwsgi_log("unable to use shared socket %d\n", shared_socket);
fr_queue = event_queue_init();
struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets;
while(ufr_sock) {
if (ufr_sock->name[0] == '=') {
int shared_socket = atoi(ufr_sock->name+1);
if (shared_socket >= 0) {
ufr_sock->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
if (ufr_sock->fd == -1) {
uwsgi_log("unable to use shared socket %d\n", shared_socket);
}
}
}
}
else {
tcp_port = strchr(ufr.socket_name, ':');
if (tcp_port) {
fr_server = bind_to_tcp(ufr.socket_name, uwsgi.listen_queue, tcp_port);
}
else {
fr_server = bind_to_unix(ufr.socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
tcp_port = strchr(ufr_sock->name, ':');
if (tcp_port) {
ufr_sock->fd = bind_to_tcp(ufr_sock->name, uwsgi.listen_queue, tcp_port);
}
else {
ufr_sock->fd = bind_to_unix(ufr_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
}
event_queue_add_fd_read(fr_queue, ufr_sock->fd);
ufr_sock = ufr_sock->next;
}
fr_queue = event_queue_init();
events = event_queue_alloc(ufr.nevents);
event_queue_add_fd_read(fr_queue, fr_server);
if (ufr.subscription_server) {
ufr_subserver = bind_to_udp(ufr.subscription_server, 0, 0);
event_queue_add_fd_read(fr_queue, ufr_subserver);
ufr.subscription_dict = uwsgi_dict_create(30, 0);
if (!ufr.subscription_slot) ufr.subscription_slot = 30;
ufr.subscription_dict = uwsgi_dict_create(ufr.subscription_slot, 0);
}
if (ufr.pattern) {
@@ -276,27 +320,39 @@ void fastrouter_loop() {
interesting_fd = event_queue_interesting_fd(events, i);
if (interesting_fd == fr_server) {
new_connection = accept(fr_server, (struct sockaddr *) &fr_addr, &fr_addr_len);
if (new_connection < 0) {
continue;
}
int taken = 0;
struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets;
while(uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
new_connection = accept(interesting_fd, (struct sockaddr *) &fr_addr, &fr_addr_len);
if (new_connection < 0) {
continue;
}
fr_table[new_connection] = alloc_fr_session();
fr_table[new_connection]->fd = new_connection;
fr_table[new_connection]->instance_fd = -1;
fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR;
fr_table[new_connection]->h_pos = 0;
fr_table[new_connection]->pos = 0;
fr_table[new_connection]->instance_failed = 0;
fr_table[new_connection]->instance_address_len = 0;
fr_table[new_connection] = alloc_fr_session();
fr_table[new_connection]->fd = new_connection;
fr_table[new_connection]->instance_fd = -1;
fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR;
fr_table[new_connection]->h_pos = 0;
fr_table[new_connection]->pos = 0;
fr_table[new_connection]->instance_failed = 0;
fr_table[new_connection]->instance_address_len = 0;
fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]);
fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]);
event_queue_add_fd_read(fr_queue, new_connection);
event_queue_add_fd_read(fr_queue, new_connection);
taken = 1;
break;
}
uwsgi_sock = uwsgi_sock->next;
}
else if (interesting_fd == ufr_subserver) {
if (taken) {
continue;
}
if (interesting_fd == ufr_subserver) {
len = recv(ufr_subserver, bbuf, 4096, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(fr_queue, ufr_subserver);
@@ -437,7 +493,7 @@ void fastrouter_loop() {
iov[1].iov_len = fr_session->uh.pktsize;
// fd passing: PERFORMANCE EXTREME BOOST !!!
if (fr_session->pass_fd) {
if (fr_session->pass_fd && !uwsgi.no_fd_passing) {
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
@@ -532,7 +588,7 @@ void fastrouter_loop() {
int fastrouter_init() {
if (ufr.socket_name) {
if (ufr.sockets) {
if (ufr.use_cache && !uwsgi.cache_max_items) {
uwsgi_log("you need to create a uwsgi cache to use the fastrouter (add --cache <n>)\n");
@@ -554,7 +610,7 @@ int fastrouter_opt(int i, char *optarg) {
switch(i) {
case LONG_ARGS_FASTROUTER:
ufr.socket_name = optarg;
uwsgi_fastrouter_new_socket(generate_socket_name(optarg));
return 1;
case LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER:
ufr.subscription_server = optarg;
@@ -575,6 +631,9 @@ int fastrouter_opt(int i, char *optarg) {
case LONG_ARGS_FASTROUTER_TIMEOUT:
ufr.socket_timeout = atoi(optarg);
return -1;
case LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT:
ufr.subscription_slot = atoi(optarg);
return 1;
}
return 0;
}
+85
View File
@@ -0,0 +1,85 @@
#include "../rack/uwsgi_rack.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_rack ur;
struct ufib {
VALUE *fib;
} ufiber;
struct option fiber_options[] = {
{ 0, 0, 0, 0 }
};
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;
return Qnil;
}
inline static void fiber_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
if (!uwsgi.wsgi_req->suspended) {
ufiber.fib[id] = rb_fiber_new(uwsgi_fiber_request, Qnil);
rb_gc_register_address(&ufiber.fib[id]);
uwsgi.wsgi_req->suspended = 1;
}
rb_fiber_resume(ufiber.fib[id], 0, NULL);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
}
inline static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
rb_fiber_yield(0, NULL);
uwsgi.wsgi_req = wsgi_req;
}
VALUE protected_async_loop() {
async_loop(NULL);
return Qnil;
}
void fiber_loop() {
int error = 0;
ufiber.fib = uwsgi_malloc( sizeof(VALUE) * uwsgi.async );
uwsgi.schedule_to_main = fiber_schedule_to_main;
uwsgi.schedule_to_req = fiber_schedule_to_req;
// must run all the rack/ruby plugins without protection
ur.unprotected = 1;
rb_protect(protected_async_loop, 0, &error);
if (error) {
uwsgi_ruby_exception();
exit(1);
}
// never here
}
int fiber_init() {
uwsgi_register_loop( (char *) "fiber", fiber_loop);
return 0;
}
struct uwsgi_plugin fiber_plugin = {
.name = "fiber",
.init = fiber_init,
.options = fiber_options,
};
+27
View File
@@ -0,0 +1,27 @@
import os
try:
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
except:
RUBYPATH = 'ruby'
NAME='fiber'
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
if includedir == 'nil':
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
CFLAGS.append('-I' + includedir)
else:
CFLAGS.append('-I' + includedir)
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['arch']\"").read().rstrip()
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
LDFLAGS = []
LIBS = []
GCC_LIST = ['fiber']
+8 -8
View File
@@ -628,9 +628,9 @@ void http_loop() {
uhttp_session->instance_address_len = uhttp_session->un->len;
}
}
else if (uwsgi.sockets_cnt > 0) {
uhttp_session->instance_address = uwsgi.sockets[0].name;
uhttp_session->instance_address_len = strlen(uwsgi.sockets[0].name);
else if (uwsgi.sockets) {
uhttp_session->instance_address = uwsgi.sockets->name;
uhttp_session->instance_address_len = strlen(uwsgi.sockets->name);
}
if (!uhttp_session->instance_address_len) {
@@ -710,7 +710,7 @@ void http_loop() {
#ifndef __sun__
// fd passing: PERFORMANCE EXTREME BOOST !!!
if (uhttp_session->pass_fd && !uhttp_session->remains) {
if (uhttp_session->pass_fd && !uhttp_session->remains && !uwsgi.no_fd_passing) {
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = uhttp_session->iov;
@@ -868,10 +868,10 @@ int http_init() {
if (!uhttp.nevents) uhttp.nevents = 64;
if (!uhttp.base && !uhttp.use_cache && !uhttp.to && !uwsgi.sockets_cnt && !uhttp.subscription_server && !uhttp.use_cluster) {
uwsgi.sockets[0].name = uwsgi_malloc(64);
uwsgi.sockets_cnt++;
snprintf(uwsgi.sockets[0].name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid());
if (!uhttp.base && !uhttp.use_cache && !uhttp.to && !uwsgi.sockets && !uhttp.subscription_server && !uhttp.use_cluster) {
char *rand_name = uwsgi_malloc(64);
snprintf(rand_name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid());
uwsgi.sockets = uwsgi_new_socket(rand_name);
}
uhttp.server = bind_to_tcp(uhttp.socket_name, uwsgi.listen_queue, strchr(uhttp.socket_name,':'));
+4 -4
View File
@@ -22,11 +22,11 @@ int nagios() {
if (!use_nagios) {
return 1;
}
if (uwsgi.sockets[0].name == NULL) {
if (!uwsgi.sockets) {
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
exit(3);
}
tcp_port = strchr(uwsgi.sockets[0].name, ':');
tcp_port = strchr(uwsgi.sockets->name, ':');
if (tcp_port == NULL) {
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
exit(3);
@@ -34,7 +34,7 @@ int nagios() {
tcp_port[0] = 0;
nagios_poll.fd = connect_to_tcp(uwsgi.sockets[0].name, atoi(tcp_port + 1), uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
nagios_poll.fd = connect_to_tcp(uwsgi.sockets->name, atoi(tcp_port + 1), uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
if (nagios_poll.fd < 0) {
fprintf(stdout, "UWSGI CRITICAL: could not connect() to workers\n");
exit(2);
@@ -48,7 +48,7 @@ int nagios() {
exit(2);
}
nagios_poll.events = POLLIN;
if (!uwsgi_parse_response(&nagios_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) uwsgi.wsgi_req, uwsgi.wsgi_req->buffer)) {
if (!uwsgi_parse_response(&nagios_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) uwsgi.wsgi_req, uwsgi.wsgi_req->buffer, uwsgi_proto_uwsgi_parser)) {
fprintf(stdout, "UWSGI CRITICAL: timed out waiting for response\n");
exit(2);
}
+1 -1
View File
@@ -36,7 +36,7 @@ static void ping() {
exit(2);
}
uwsgi_poll.events = POLLIN;
if (!uwsgi_parse_response(&uwsgi_poll, uping.ping_timeout, &uh, NULL)) {
if (!uwsgi_parse_response(&uwsgi_poll, uping.ping_timeout, &uh, NULL, uwsgi_proto_uwsgi_parser)) {
exit(1);
}
else {
+17 -2
View File
@@ -1,7 +1,9 @@
#undef __USE_GNU
#include "../../uwsgi.h"
#ifdef __APPLE__
#define HAS_BOOL 1
#endif
#include <EXTERN.h>
#include <perl.h>
#include "XSUB.h"
@@ -12,17 +14,30 @@ struct uwsgi_perl {
int fd;
char *psgibuffer;
char *psgi;
char *locallib;
char *embedding[3];
PerlInterpreter *main;
pthread_key_t u_interpreter;
PerlInterpreter **interp;
SV *psgi_main;
SV **psgi_func;
CV *stream_responder;
HV *streaming_stash;
HV *input_stash;
HV *error_stash;
};
#define LONG_ARGS_PERL_BASE 17000 + ((5 + 1) * 100)
#define LONG_ARGS_PSGI LONG_ARGS_PERL_BASE + 1
#define LONG_ARGS_PERL_BASE 17000 + ((5 + 1) * 1000)
#define LONG_ARGS_PSGI LONG_ARGS_PERL_BASE + 1
#define LONG_ARGS_PERL_LOCAL_LIB LONG_ARGS_PERL_BASE + 2
void init_perl_embedded_module(void);
void uwsgi_psgi_app(void);
int psgi_response(struct wsgi_request *, PerlInterpreter *, AV*);
#define psgi_xs(func) newXS("uwsgi::" #func, XS_##func, "uwsgi")
#define psgi_check_args(x) if (items < x) Perl_croak(aTHX_ "Usage: uwsgi::%s takes %d arguments", __FUNCTION__ + 3, x)
SV *uwsgi_perl_obj_call(SV *, char *);
int uwsgi_perl_obj_can(SV *, char *, size_t);
+315
View File
@@ -0,0 +1,315 @@
#include "psgi.h"
extern struct uwsgi_server uwsgi;
struct uwsgi_perl uperl;
XS(XS_input_seek) {
dXSARGS;
psgi_check_args(1);
XSRETURN(0);
}
XS(XS_error) {
dXSARGS;
psgi_check_args(0);
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.error_stash);
XSRETURN(1);
}
XS(XS_input) {
dXSARGS;
psgi_check_args(0);
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.input_stash);
XSRETURN(1);
}
XS(XS_stream)
{
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
psgi_check_args(1);
AV *response = (AV* ) SvREFCNT_inc(SvRV(ST(0))) ;
if (av_len(response) == 2) {
#ifdef my_perl
while (psgi_response(wsgi_req, my_perl, response) != UWSGI_OK);
#else
while (psgi_response(wsgi_req, uperl.main, response) != UWSGI_OK);
#endif
}
else if (av_len(response) == 1) {
#ifdef my_perl
while (psgi_response(wsgi_req, my_perl, response) != UWSGI_OK);
#else
while (psgi_response(wsgi_req, uperl.main, response) != UWSGI_OK);
#endif
SvREFCNT_dec(response);
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.streaming_stash);
XSRETURN(1);
}
else {
uwsgi_log("invalid PSGI response: array size %d\n", av_len(response));
}
SvREFCNT_dec(response);
XSRETURN(0);
}
XS(XS_input_read) {
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = -1;
char *tmp_buf;
ssize_t bytes = 0, len;
size_t remains;
SV *read_buf;
psgi_check_args(3);
read_buf = ST(1);
len = SvIV(ST(2));
// return empty string if no post_cl or pos >= post_cl
if (!wsgi_req->post_cl || (size_t) wsgi_req->post_pos >= wsgi_req->post_cl) {
sv_setpvn(read_buf, "", 0);
goto ret;
}
if (wsgi_req->body_as_file) {
fd = fileno((FILE *)wsgi_req->async_post);
}
else if (uwsgi.post_buffering > 0) {
fd = -1;
if (wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
fd = fileno((FILE *)wsgi_req->async_post);
}
}
else {
fd = wsgi_req->poll.fd;
}
// return the whole input
if (len <= 0) {
remains = wsgi_req->post_cl;
}
else {
remains = len ;
}
if (remains + wsgi_req->post_pos > wsgi_req->post_cl) {
remains = wsgi_req->post_cl - wsgi_req->post_pos;
}
if (remains <= 0) {
sv_setpvn(read_buf, "", 0);
goto ret;
}
// data in memory ?
if (fd == -1) {
sv_setpvn(read_buf, wsgi_req->post_buffering_buf, remains);
bytes = remains;
wsgi_req->post_pos += remains;
}
tmp_buf = uwsgi_malloc(remains);
if (uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
free(tmp_buf);
croak("error waiting for wsgi.input data");
goto ret;
}
bytes = read(fd, tmp_buf, remains);
if (bytes < 0) {
free(tmp_buf);
croak("error reading wsgi.input data");
goto ret;
}
wsgi_req->post_pos += bytes;
sv_setpvn(read_buf, tmp_buf, bytes);
free(tmp_buf);
ret:
XSRETURN_IV(bytes);
}
XS(XS_streaming_close) {
dXSARGS;
psgi_check_args(0);
XSRETURN(0);
}
XS(XS_streaming_write) {
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
STRLEN blen;
char *body;
psgi_check_args(2);
body = SvPV(ST(1), blen);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, body, blen);
XSRETURN(0);
}
XS(XS_error_print) {
dXSARGS;
STRLEN blen;
char *body;
psgi_check_args(1);
if (items > 1) {
body = SvPV(ST(1), blen);
uwsgi_log("%.*s", blen, body);
}
XSRETURN(0);
}
/* automatically generated */
EXTERN_C void xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void
xs_init(pTHX)
{
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
newXS("uwsgi::input::new", XS_input, "uwsgi::input");
newXS("uwsgi::input::read", XS_input_read, "uwsgi::input");
newXS("uwsgi::input::seek", XS_input_seek, "uwsgi::input");
uperl.input_stash = gv_stashpv("uwsgi::input", 0);
newXS("uwsgi::error::new", XS_error, "uwsgi::error");
newXS("uwsgi::error::print", XS_error_print, "uwsgi::print");
uperl.error_stash = gv_stashpv("uwsgi::error", 0);
uperl.stream_responder = newXS("uwsgi::stream", XS_stream, "uwsgi");
newXS("uwsgi::streaming::write", XS_streaming_write, "uwsgi::streaming");
newXS("uwsgi::streaming::close", XS_streaming_close, "uwsgi::streaming");
uperl.streaming_stash = gv_stashpv("uwsgi::streaming", 0);
#ifdef UWSGI_EMBEDDED
init_perl_embedded_module();
#endif
}
/* end of automagically generated part */
void uwsgi_psgi_app() {
struct stat stat_psgi;
if (uperl.psgi) {
// two-pass loading: parse the script -> eval the script
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
uperl.embedding[2] = uperl.psgi;
if (perl_parse(uperl.main, xs_init, 3, uperl.embedding, NULL)) {
exit(1);
}
}
else {
uperl.embedding[1] = uperl.psgi;
if (perl_parse(uperl.main, xs_init, 2, uperl.embedding, NULL)) {
exit(1);
}
}
perl_eval_pv("use IO::Handle;", 0);
perl_eval_pv("use IO::File;", 0);
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(uperl.psgi, 0));
SV *dollar_slash = get_sv("/", GV_ADD);
sv_setsv(dollar_slash, newRV_inc(newSViv(uwsgi.buffer_size)));
uperl.fd = open(uperl.psgi, O_RDONLY);
if (uperl.fd < 0) {
uwsgi_error_open(uperl.psgi);
exit(1);
}
if (fstat(uperl.fd, &stat_psgi)) {
uwsgi_error("fstat()");
exit(1);
}
uperl.psgibuffer = malloc(stat_psgi.st_size + 1);
if (!uperl.psgibuffer) {
uwsgi_error("malloc()");
exit(1);
}
if (read(uperl.fd, uperl.psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
uwsgi_error("read()");
exit(1);
}
uperl.psgibuffer[stat_psgi.st_size] = 0;
if (uwsgi.threads < 2) {
uperl.psgi_main = perl_eval_pv(uwsgi_concat4("#line 1 ", uperl.psgi, "\n", uperl.psgibuffer), 0);
if (!uperl.psgi_main) {
uwsgi_log("unable to find PSGI function entry point.\n");
exit(1);
}
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
exit(1);
}
free(uperl.psgibuffer);
close(uperl.fd);
}
uwsgi_log("PSGI app (%s) loaded at %p\n", uperl.psgi, uperl.psgi_main);
}
}
+288 -202
View File
@@ -8,70 +8,285 @@ struct uwsgi_perl uperl;
struct option uwsgi_perl_options[] = {
{"psgi", required_argument, 0, LONG_ARGS_PSGI},
{"perl-local-lib", required_argument, 0, LONG_ARGS_PERL_LOCAL_LIB},
{0, 0, 0, 0},
};
extern struct http_status_codes hsc[];
XS(XS_stream)
{
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
SV *stack;
AV *response;
SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
uwsgi_log("args: %d %p\n", items, wsgi_req);
stack = ST(0);
uwsgi_log("type %d\n", SvTYPE(stack));
response = (AV* ) SvRV(stack) ;
SV *newobj;
// set current context ?
//dTHX;
dSP;
#ifdef my_perl
psgi_response(wsgi_req, my_perl, response);
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv( class, class_len)));
PUTBACK;
call_method( "new", G_SCALAR);
SPAGAIN;
newobj = POPs;
PUTBACK;
FREETMPS;
LEAVE;
return newobj;
}
SV *uwsgi_perl_call_stream(SV *func) {
SV *ret = NULL;
// set current context ?
//dTHX;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs( sv_2mortal(newRV((SV*) uperl.stream_responder)));
PUTBACK;
call_sv( func, G_SCALAR | G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
}
else {
ret = SvREFCNT_inc(POPs);
}
PUTBACK;
FREETMPS;
LEAVE;
return ret;
}
int uwsgi_perl_obj_can(SV *obj, char *method, size_t len) {
int ret;
// set current context ? needed for threading
//dTHX;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(obj);
XPUSHs(sv_2mortal(newSVpv(method, len)));
PUTBACK;
call_method( "can", G_SCALAR);
SPAGAIN;
ret = SvROK(POPs);
PUTBACK;
FREETMPS;
LEAVE;
return ret;
}
SV *uwsgi_perl_obj_call(SV *obj, char *method) {
SV *ret = NULL;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(obj);
PUTBACK;
call_method( method, G_SCALAR | G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
}
else {
ret = SvREFCNT_inc(POPs);
}
PUTBACK;
FREETMPS;
LEAVE;
return ret;
}
AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) {
AV *ret = NULL;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(env);
PUTBACK;
call_sv(psgi_func, G_SCALAR | G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
internal_server_error(wsgi_req, "exception raised");
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
}
else {
ret = (AV *) SvREFCNT_inc(SvRV(POPs));
}
PUTBACK;
FREETMPS;
LEAVE;
return (AV *)ret;
}
SV *build_psgi_env(struct wsgi_request *wsgi_req) {
int i;
HV *env = newHV();
// fill perl hash
for(i=0;i<wsgi_req->var_cnt;i++) {
if (wsgi_req->hvec[i+1].iov_len > 0) {
// check for multiline header
if (hv_exists(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) {
SV **already_avalable_header = hv_fetch(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, 0);
STRLEN hlen;
char *old_value = SvPV(*already_avalable_header, hlen );
char *multiline_header = uwsgi_concat3n(old_value, hlen, ", ", 2, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
newSVpv(multiline_header, hlen+wsgi_req->hvec[i+1].iov_len+2), 0)) { free(multiline_header); goto clear;}
free(multiline_header);
}
else {
if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
newSVpv(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len), 0)) goto clear;
}
}
else {
if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0)) goto clear;
}
//uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base);
i++;
}
// psgi.version
AV *av = newAV();
av_store( av, 0, newSViv(1));
av_store( av, 1, newSViv(1));
if (!hv_store(env, "psgi.version", 12, newRV_noinc((SV *)av ), 0)) goto clear;
if (uwsgi.numproc > 1) {
if (!hv_store(env, "psgi.multiprocess", 17, newSViv(1), 0)) goto clear;
}
else {
if (!hv_store(env, "psgi.multiprocess", 17, newSViv(0), 0)) goto clear;
}
if (uwsgi.threads > 1) {
if (!hv_store(env, "psgi.multithread", 16, newSViv(1), 0)) goto clear;
}
else {
if (!hv_store(env, "psgi.multithread", 16, newSViv(0), 0)) goto clear;
}
if (!hv_store(env, "psgi.run_once", 13, newSViv(0), 0)) goto clear;
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
if (!hv_store(env, "psgi.nonblocking", 16, newSViv(1), 0)) goto clear;
}
else {
#else
psgi_response(wsgi_req, uperl.main, response);
if (!hv_store(env, "psgi.nonblocking", 16, newSViv(0), 0)) goto clear;
#endif
//mXPUSHp("x", 1);
XSRETURN(0);
}
/* automatically generated */
EXTERN_C void xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void
xs_init(pTHX)
{
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
uperl.stream_responder = newXS("uwsgi::stream", XS_stream, "uwsgi");
#ifdef UWSGI_EMBEDDED
init_perl_embedded_module();
#ifdef UWSGI_ASYNC
}
#endif
if (!hv_store(env, "psgi.streaming", 14, newSViv(1), 0)) goto clear;
SV *us;
// psgi.url_scheme, honour HTTPS var or UWSGI_SCHEME
if (wsgi_req->scheme_len > 0) {
us = newSVpv(wsgi_req->scheme, wsgi_req->scheme_len);
}
else if (wsgi_req->https_len > 0) {
if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') {
us = newSVpv("https", 5);
}
else {
us = newSVpv("http", 4);
}
}
else {
us = newSVpv("http", 4);
}
if (!hv_store(env, "psgi.url_scheme", 15, us, 0)) goto clear;
SV *pi = uwsgi_perl_obj_new("uwsgi::input", 12);
if (!hv_store(env, "psgi.input", 10, pi, 0)) goto clear;
if (!hv_store(env, "psgix.input.buffered", 20, newSViv(wsgi_req->body_as_file), 0)) goto clear;
SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12);
if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear;
return newRV_noinc((SV *)env);
clear:
SvREFCNT_dec((SV *)env);
return NULL;
}
/* end of automagically generated part */
int uwsgi_perl_init(){
struct http_status_codes *http_sc;
int argc = 4;
char *embedding[] = { "", "-e", "-e", "0" };
int argc = 3;
uperl.embedding[0] = "";
uperl.embedding[1] = "-e";
uperl.embedding[2] = "0";
if (setenv("PLACK_ENV", "uwsgi", 0)) {
uwsgi_error("setenv()");
}
#ifdef PERL_VERSION_STRING
uwsgi_log("initializing Perl %s environment\n", PERL_VERSION_STRING);
#else
uwsgi_log("initializing Perl environment\n");
PERL_SYS_INIT3(&argc, (char ***) &embedding, &environ);
#endif
PERL_SYS_INIT3(&argc, (char ***) &uperl.embedding, &environ);
uperl.main = perl_alloc();
if (!uperl.main) {
uwsgi_log("unable to allocate perl interpreter\n");
@@ -82,6 +297,7 @@ int uwsgi_perl_init(){
PERL_SET_CONTEXT(uperl.main);
PL_perl_destruct_level = 2;
PL_origalen = 1;
perl_construct(uperl.main);
// filling http status codes
@@ -90,65 +306,11 @@ int uwsgi_perl_init(){
}
PL_origalen = 1;
perl_parse(uperl.main, xs_init, 4, embedding, NULL);
perl_eval_pv("use IO::Handle;", 0);
return 1;
}
void uwsgi_psgi_app() {
struct stat stat_psgi;
if (uperl.psgi) {
uperl.fd = open(uperl.psgi, O_RDONLY);
if (uperl.fd < 0) {
uwsgi_error_open(uperl.psgi);
exit(1);
}
if (fstat(uperl.fd, &stat_psgi)) {
uwsgi_error("fstat()");
exit(1);
}
uperl.psgibuffer = malloc(stat_psgi.st_size + 1);
if (!uperl.psgibuffer) {
uwsgi_error("malloc()");
exit(1);
}
if (read(uperl.fd, uperl.psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
uwsgi_error("read()");
exit(1);
}
uperl.psgibuffer[stat_psgi.st_size] = 0;
if (uwsgi.threads < 2) {
uperl.psgi_main = perl_eval_pv(uperl.psgibuffer, 0);
if (!uperl.psgi_main) {
uwsgi_log("unable to find PSGI function entry point.\n");
exit(1);
}
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
exit(1);
}
free(uperl.psgibuffer);
close(uperl.fd);
}
uwsgi_log("PSGI app (%s) loaded at %p\n", uperl.psgi, uperl.psgi_main);
}
}
#ifdef my_perl
void uwsgi_perl_enable_threads() {
@@ -202,19 +364,15 @@ void uwsgi_perl_enable_threads() {
int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
HV *env;
SV **item;
AV *response;
SV *io_new, *io_err;
int i;
SV *psgi_func = uperl.psgi_main;
// ugly hack
register PerlInterpreter *my_perl = uperl.main;
dSP;
#ifdef UWSGI_ASYNC
if (wsgi_req->async_status == UWSGI_AGAIN) {
return psgi_response(wsgi_req, my_perl, wsgi_req->async_placeholder);
}
#endif
/* Standard PSGI request */
if (!wsgi_req->uh.pktsize) {
@@ -224,7 +382,6 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
if (uwsgi_parse_vars(wsgi_req)) {
uwsgi_log("Invalid PSGI request. skip.\n");
return -1;
}
@@ -241,116 +398,42 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
SAVETMPS;
env = (HV*) sv_2mortal((SV*)newHV());
wsgi_req->async_environ = build_psgi_env(wsgi_req);
if (!wsgi_req->async_environ) goto clear;
wsgi_req->async_result = psgi_call(wsgi_req, psgi_func, wsgi_req->async_environ);
if (!wsgi_req->async_result) goto clear;
// fill perl hash
for(i=0;i<wsgi_req->var_cnt;i++) {
if (wsgi_req->hvec[i+1].iov_len > 0) {
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
newSVpv(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len), 0);
if (SvTYPE((AV *)wsgi_req->async_result) == SVt_PVCV) {
SV *stream_result = uwsgi_perl_call_stream((SV*)wsgi_req->async_result);
if (!stream_result) {
internal_server_error(wsgi_req, "exception raised");
}
else {
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0);
SvREFCNT_dec(stream_result);
}
//uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base);
i++;
goto clear2;
}
SV *us = newSVpv("http", 4);
item = hv_store(env, "psgi.url_scheme", 15, us, 0);
SV* iohandle = newSVpv( "IO::Handle", 10 );
PUSHMARK(SP);
XPUSHs( sv_2mortal(iohandle));
PUTBACK;
perl_call_method( "new", G_SCALAR);
SPAGAIN;
io_new = POPs;
PUSHMARK(SP);
XPUSHs( io_new );
XPUSHs( sv_2mortal(newSViv( wsgi_req->poll.fd)));
XPUSHs( sv_2mortal(newSVpv( "r", 1)));
PUTBACK;
perl_call_method( "fdopen", G_SCALAR);
SPAGAIN;
SV *pi = SvREFCNT_inc(POPs);
item = hv_store(env, "psgi.input", 10, pi, 0);
PUSHMARK(SP);
XPUSHs( newSVpv( "IO::Handle", 10 ));
PUTBACK;
perl_call_method( "new", G_SCALAR);
SPAGAIN;
io_err = POPs;
PUSHMARK(SP);
XPUSHs( io_err );
XPUSHs( sv_2mortal( newSViv( 2 )));
XPUSHs( sv_2mortal( newSVpv( "w", 1)));
PUTBACK;
perl_call_method( "fdopen", G_SCALAR);
SPAGAIN;
SV *pe = SvREFCNT_inc(POPs);
item = hv_store(env, "psgi.errors", 11, pe, 0);
PUSHMARK(SP);
XPUSHs( sv_2mortal(newRV((SV *)env )) );
PUTBACK;
perl_call_sv(psgi_func, G_SCALAR);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
goto clear;
}
SPAGAIN;
// no leaks to here
// dereference output
response = (AV *) SvRV( POPs );
//uwsgi_log("response: %p %d\n", response, SvTYPE(response));
if (SvTYPE(response) == SVt_PVCV) {
uwsgi_log("streaming response\n");
PUSHMARK(SP);
XPUSHs( newRV((SV*) uperl.stream_responder));
PUTBACK;
perl_call_sv( (SV*)response, G_SCALAR);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
while (psgi_response(wsgi_req, my_perl, wsgi_req->async_result) != UWSGI_OK) {
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
FREETMPS;
LEAVE;
return UWSGI_AGAIN;
}
goto clear;
#endif
}
psgi_response(wsgi_req, my_perl, response);
clear2:
SvREFCNT_dec(wsgi_req->async_environ);
SvREFCNT_dec(wsgi_req->async_result);
clear:
FREETMPS;
LEAVE;
return 0;
return UWSGI_OK;
}
@@ -387,6 +470,9 @@ int uwsgi_perl_manage_options(int i, char *optarg) {
case LONG_ARGS_PSGI:
uperl.psgi = optarg;
return 1;
case LONG_ARGS_PERL_LOCAL_LIB:
uperl.locallib = optarg;
return 1;
}
return 0;
+103 -19
View File
@@ -1,5 +1,7 @@
#include "psgi.h"
extern struct uwsgi_server uwsgi;
/* statistically ordered */
struct http_status_codes hsc[] = {
{"200", "OK"},
@@ -55,16 +57,54 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
struct http_status_codes *http_sc;
int i,vi, base;
char *chitem;
dSP;
#ifdef UWSGI_ASYNC
if (wsgi_req->async_status == UWSGI_AGAIN) {
wsgi_req->async_force_again = 0;
wsgi_req->switches++;
SV *chunk = uwsgi_perl_obj_call(wsgi_req->async_placeholder, "getline");
if (!chunk) {
internal_server_error(wsgi_req, "exception raised");
return UWSGI_OK;
}
if (wsgi_req->async_force_again) {
SvREFCNT_dec(chunk);
return UWSGI_AGAIN;
}
chitem = SvPV( chunk, hlen);
if (hlen <= 0) {
SvREFCNT_dec(chunk);
SV *closed = uwsgi_perl_obj_call(wsgi_req->async_placeholder, "close");
if (closed) {
SvREFCNT_dec(closed);
}
SvREFCNT_dec(wsgi_req->async_environ);
SvREFCNT_dec(wsgi_req->async_result);
return UWSGI_OK;
}
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, chitem, hlen);
SvREFCNT_dec(chunk);
return UWSGI_AGAIN;
}
#endif
status_code = av_fetch(response, 0, 0);
if (!status_code) { uwsgi_log("invalid PSGI status code\n"); return UWSGI_OK;}
wsgi_req->hvec[0].iov_base = "HTTP/1.1 ";
wsgi_req->hvec[0].iov_len = 9;
//uwsgi_log("setting status %d %d\n", SvTYPE(*status_code), SvIV(*status_code));
wsgi_req->hvec[1].iov_base = SvPV(*status_code, hlen);
wsgi_req->hvec[1].iov_len = 3;
wsgi_req->status = atoi(wsgi_req->hvec[1].iov_base);
@@ -92,8 +132,10 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
wsgi_req->hvec[4].iov_len = 2;
hitem = av_fetch(response, 1, 0);
if (!hitem) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
headers = (AV *) SvRV(*hitem);
if (!headers) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
base = 5;
@@ -122,34 +164,76 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
vi = (i*2)+base;
wsgi_req->hvec[vi].iov_base = "\r\n"; wsgi_req->hvec[vi].iov_len = 2;
if ( !(wsgi_req->headers_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, vi+1)) ) {
if ( !(wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, vi+1)) ) {
uwsgi_error("writev()");
}
hitem = av_fetch(response, 2, 0);
if (SvTYPE(SvRV(*hitem)) == SVt_PVGV || SvTYPE(SvRV(*hitem)) == SVt_PVHV) {
if (!hitem) {
return UWSGI_OK;
}
if (!SvRV(*hitem)) { uwsgi_log("invalid PSGI response body\n") ; return UWSGI_OK; }
if (SvTYPE(SvRV(*hitem)) == SVt_PVGV || SvTYPE(SvRV(*hitem)) == SVt_PVHV || SvTYPE(SvRV(*hitem)) == SVt_PVMG) {
// respond to fileno ?
if (uwsgi.async < 2) {
if (uwsgi_perl_obj_can(*hitem, "fileno", 6)) {
SV *fn = uwsgi_perl_obj_call(*hitem, "fileno");
wsgi_req->sendfile_fd = SvIV(fn);
SvREFCNT_dec(fn);
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_perl_obj_can(*hitem, "path", 4)) {
SV *p = uwsgi_perl_obj_call(*hitem, "path");
wsgi_req->sendfile_fd = open(SvPV_nolen(p), O_RDONLY);
SvREFCNT_dec(p);
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
close(wsgi_req->sendfile_fd);
return UWSGI_OK;
}
}
for(;;) {
PUSHMARK(SP);
XPUSHs(*hitem);
PUTBACK;
perl_call_method("getline", G_SCALAR);
SPAGAIN;
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
break;
}
SV *chunk = POPs;
wsgi_req->switches++;
SV *chunk = uwsgi_perl_obj_call(*hitem, "getline");
if (!chunk) {
internal_server_error(wsgi_req, "exception raised");
break;
}
chitem = SvPV( chunk, hlen);
#ifdef UWSGI_ASYNC
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;
}
#endif
if (hlen <= 0) {
SvREFCNT_dec(chunk);
break;
}
wsgi_req->response_size = write(wsgi_req->poll.fd, chitem, hlen);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, chitem, hlen);
SvREFCNT_dec(chunk);
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
wsgi_req->async_status = UWSGI_AGAIN;
wsgi_req->async_placeholder = (SV *) *hitem;
return UWSGI_AGAIN;
}
#endif
}
SV *closed = uwsgi_perl_obj_call(*hitem, "close");
if (closed) {
SvREFCNT_dec(closed);
}
}
else if (SvTYPE(SvRV(*hitem)) == SVt_PVAV) {
@@ -159,7 +243,7 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
for(i=0; i<=av_len(body); i++) {
hitem = av_fetch(body,i,0);
chitem = SvPV(*hitem, hlen);
wsgi_req->response_size = write(wsgi_req->poll.fd, chitem, hlen);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, chitem, hlen);
}
}
@@ -167,6 +251,6 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
uwsgi_log("unsupported response body type: %d\n", SvTYPE(SvRV(*hitem)));
}
return 1;
return UWSGI_OK;
}
+116 -3
View File
@@ -2,12 +2,85 @@
extern struct uwsgi_server uwsgi;
#define psgi_xs(func) newXS("uwsgi::" #func, XS_##func, "uwsgi")
#define psgi_check_args(x) if (items < x) Perl_croak(aTHX_ "Usage: uwsgi::%s takes %d arguments", __FUNCTION__ + 3, x)
#ifdef UWSGI_ASYNC
XS(XS_async_sleep) {
dXSARGS;
int timeout ;
psgi_check_args(1);
struct wsgi_request *wsgi_req = current_wsgi_req();
timeout = SvIV(ST(0));
if (timeout >= 0) {
async_add_timeout(wsgi_req, timeout);
}
wsgi_req->async_force_again = 1;
XSRETURN_UNDEF;
}
XS(XS_wait_fd_read) {
dXSARGS;
int fd, timeout = 0;
psgi_check_args(1);
struct wsgi_request *wsgi_req = current_wsgi_req();
fd = SvIV(ST(0));
if (items > 1) {
timeout = SvIV(ST(1));
}
if (fd >= 0) {
async_add_fd_read(wsgi_req, fd, timeout);
}
wsgi_req->async_force_again = 1;
XSRETURN_UNDEF;
}
XS(XS_wait_fd_write) {
dXSARGS;
int fd, timeout = 0;
psgi_check_args(1);
struct wsgi_request *wsgi_req = current_wsgi_req();
fd = SvIV(ST(0));
if (items > 1) {
timeout = SvIV(ST(1));
}
if (fd >= 0) {
async_add_fd_read(wsgi_req, fd, timeout);
}
wsgi_req->async_force_again = 1;
XSRETURN_UNDEF;
}
#endif
XS(XS_reload) {
dXSARGS;
items = 0;
psgi_check_args(0);
uwsgi_log("SENDING HUP TO %d\n", (int) uwsgi.workers[0].pid);
if (kill(uwsgi.workers[0].pid, SIGHUP)) {
@@ -57,6 +130,27 @@ XS(XS_cache_get) {
}
XS(XS_log) {
dXSARGS;
psgi_check_args(1);
uwsgi_log("%s", SvPV_nolen(ST(0)));
XSRETURN_UNDEF;
}
XS(XS_async_connect) {
dXSARGS;
psgi_check_args(1);
ST(0) = newSViv(uwsgi_connect(SvPV_nolen(ST(0)), 0, 1));
XSRETURN(1);
}
XS(XS_call) {
dXSARGS;
@@ -88,11 +182,30 @@ XS(XS_call) {
}
XS(XS_suspend) {
dXSARGS;
psgi_check_args(0);
struct wsgi_request *wsgi_req = current_wsgi_req();
wsgi_req->async_force_again = 0;
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
XSRETURN_UNDEF;
}
void init_perl_embedded_module() {
psgi_xs(reload);
psgi_xs(cache_set);
psgi_xs(cache_get);
psgi_xs(call);
psgi_xs(wait_fd_read);
psgi_xs(wait_fd_write);
psgi_xs(async_sleep);
psgi_xs(log);
psgi_xs(async_connect);
psgi_xs(suspend);
}
+1 -1
View File
@@ -4,4 +4,4 @@ NAME='psgi'
CFLAGS = [os.popen('perl -MExtUtils::Embed -e ccopts').read().rstrip()]
LDFLAGS = [os.popen('perl -MExtUtils::Embed -e ldopts').read().rstrip()]
LIBS = []
GCC_LIST = ['uwsgi_plmodule', 'psgi_response', 'psgi_plugin']
GCC_LIST = ['uwsgi_plmodule', 'psgi_loader', 'psgi_response', 'psgi_plugin']
+1 -2
View File
@@ -301,11 +301,10 @@ recv:
void pyerl_call_registered(void *func, ei_x_buff *x) {
PyObject *pyargs = PyTuple_New(1);
PyObject *ret;
PyTuple_SetItem(pyargs, 0, erl_to_py(x));
ret = python_call((PyObject *) func, pyargs, 0);
python_call((PyObject *) func, pyargs, 0);
}
PyObject *pyerl_register_process(PyObject * self, PyObject * args) {
+34
View File
@@ -0,0 +1,34 @@
#include "uwsgi_python.h"
extern struct uwsgi_server uwsgi;
#ifdef HAS_NOT_PyFrame_GetLineNumber
int PyFrame_GetLineNumber(PyFrameObject *frame) {
if (frame->f_trace) {
return frame->f_lineno;
}
else {
return PyCode_Addr2Line(frame->f_code, frame->f_lasti);
}
}
#endif
int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
switch(what) {
case PyTrace_CALL:
uwsgi_log("[uWSGI Python profiler] CALL: %s (line %d) -> %s %d args, stacksize %d\n",
PyString_AsString(frame->f_code->co_filename),
PyFrame_GetLineNumber(frame),
PyString_AsString(frame->f_code->co_name), frame->f_code->co_argcount, frame->f_code->co_stacksize);
break;
case PyTrace_C_CALL:
uwsgi_log("[uWSGI Python profiler] C CALL: %s (line %d) -> %s %d args, stacksize %d\n",
PyString_AsString(frame->f_code->co_filename),
PyFrame_GetLineNumber(frame),
PyEval_GetFuncName(arg), frame->f_code->co_argcount, frame->f_code->co_stacksize);
break;
}
return 0;
}
+3 -2
View File
@@ -4,6 +4,8 @@
exit(1) on every malloc error: apps can be dinamically loaded so on memory problem
it is better to let the master process manager respawn the worker.
TODO dynamic loading on prefork+thread looks flaky... NEED TO FIX IT
*/
extern struct uwsgi_server uwsgi;
@@ -125,7 +127,6 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
}
}
if (interpreter == NULL && id) {
wi->interpreter = Py_NewInterpreter();
if (!wi->interpreter) {
@@ -320,7 +321,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
uwsgi_log( "Web3 application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
}
else {
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p pid: %d", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter, (int) getpid());
}
if (!wsgi_req->script_name_len) {
+52 -12
View File
@@ -3,6 +3,8 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_python up;
#include <glob.h>
extern PyTypeObject uwsgi_InputType;
struct option uwsgi_python_options[] = {
@@ -130,9 +132,6 @@ int uwsgi_python_init() {
uwsgi_log("Python main interpreter initialized at %p\n", up.main_thread);
// add the hacky modifier1 30
uwsgi.p[30]->request = uwsgi.p[0]->request;
return 1;
}
@@ -281,6 +280,15 @@ void init_uwsgi_vars() {
exit(1);
}
pysys_dict = PyModule_GetDict(pysys);
#ifdef PYTHREE
// fix stdout and stderr
PyObject *new_stdprint = PyFile_NewStdPrinter(2);
PyDict_SetItemString(pysys_dict, "stdout", new_stdprint);
PyDict_SetItemString(pysys_dict, "__stdout__", new_stdprint);
PyDict_SetItemString(pysys_dict, "stderr", new_stdprint);
PyDict_SetItemString(pysys_dict, "__stderr__", new_stdprint);
#endif
pypath = PyDict_GetItemString(pysys_dict, "path");
if (!pypath) {
PyErr_Print();
@@ -324,13 +332,16 @@ void init_uwsgi_vars() {
PyErr_Print();
}
for (i = 0; i < up.python_path_cnt; i++) {
if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(up.python_path[i])) != 0) {
struct uwsgi_string_list *uppp = up.python_path;
while(uppp) {
if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(uppp->value)) != 0) {
PyErr_Print();
}
else {
uwsgi_log("added %s to pythonpath.\n", up.python_path[i]);
uwsgi_log("added %s to pythonpath.\n", uppp->value);
}
uppp = uppp->next;
}
for (i = 0; i < up.pymodule_alias_cnt; i++) {
@@ -417,6 +428,11 @@ void init_uwsgi_embedded_module() {
exit(1);
}
if (PyDict_SetItemString(up.embedded_dict, "hostname", PyString_FromStringAndSize(uwsgi.hostname, uwsgi.hostname_len))) {
PyErr_Print();
exit(1);
}
if (uwsgi.mode) {
if (PyDict_SetItemString(up.embedded_dict, "mode", PyString_FromString(uwsgi.mode))) {
PyErr_Print();
@@ -653,6 +669,9 @@ int uwsgi_python_magic(char *mountpoint, char *lazy) {
int uwsgi_python_manage_options(int i, char *optarg) {
glob_t g;
int j;
switch (i) {
case 'w':
up.wsgi_config = optarg;
@@ -674,12 +693,13 @@ int uwsgi_python_manage_options(int i, char *optarg) {
}
return 1;
case LONG_ARGS_PYTHONPATH:
if (up.python_path_cnt < MAX_PYTHONPATH) {
up.python_path[up.python_path_cnt] = optarg;
up.python_path_cnt++;
if (glob(optarg, GLOB_MARK, NULL, &g)) {
uwsgi_string_new_list(&up.python_path, optarg);
}
else {
uwsgi_log("you can specify at most %d --pythonpath options\n", MAX_PYTHONPATH);
for (j = 0; j < (int) g.gl_pathc; j++) {
uwsgi_string_new_list(&up.python_path, g.gl_pathv[j]);
}
}
return 1;
case LONG_ARGS_PYARGV:
@@ -699,6 +719,7 @@ int uwsgi_python_manage_options(int i, char *optarg) {
return 1;
#ifdef UWSGI_INI
case LONG_ARGS_INI_PASTE:
uwsgi.ini = optarg;
if (uwsgi.ini[0] != '/') {
@@ -708,6 +729,7 @@ int uwsgi_python_manage_options(int i, char *optarg) {
up.paste = uwsgi_concat2("config:", uwsgi.ini);
}
return 1;
#endif
case LONG_ARGS_PASTE:
up.paste = optarg;
return 1;
@@ -778,6 +800,12 @@ void uwsgi_python_init_apps() {
init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread);
}
if (uwsgi.profiler) {
if (!strcmp(uwsgi.profiler, "pycall")) {
PyEval_SetProfile(uwsgi_python_profiler_call, NULL);
}
}
}
void uwsgi_python_enable_threads() {
@@ -881,13 +909,15 @@ void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
int uwsgi_python_signal_handler(uint8_t sig, void *handler) {
UWSGI_GET_GIL;
PyObject *args = PyTuple_New(1);
PyObject *ret;
if (!args)
return -1;
goto clear;
if (!handler) return -1;
if (!handler) goto clear;
PyTuple_SetItem(args, 0, PyInt_FromLong(sig));
@@ -895,9 +925,12 @@ int uwsgi_python_signal_handler(uint8_t sig, void *handler) {
ret = python_call(handler, args, 0);
if (ret) {
UWSGI_RELEASE_GIL;
return 0;
}
clear:
UWSGI_RELEASE_GIL;
return -1;
}
@@ -1001,6 +1034,11 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
}
void uwsgi_python_fixup() {
// set hacky modifier 30
uwsgi.p[30] = uwsgi.p[0];
}
struct uwsgi_plugin python_plugin = {
.name = "python",
@@ -1015,6 +1053,8 @@ struct uwsgi_plugin python_plugin = {
.after_request = uwsgi_after_request_wsgi,
.init_apps = uwsgi_python_init_apps,
.fixup = uwsgi_python_fixup,
.mount_app = uwsgi_python_mount_app,
.enable_threads = uwsgi_python_enable_threads,
+18 -21
View File
@@ -397,7 +397,7 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
if (rlen > 0) {
upoll.fd = fd;
upoll.events = POLLIN;
if (uwsgi_parse_response(&upoll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &uh, buffer)) {
if (uwsgi_parse_response(&upoll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &uh, buffer, uwsgi_proto_uwsgi_parser)) {
size = uh.pktsize;
}
}
@@ -874,7 +874,6 @@ PyObject *py_uwsgi_lock(PyObject * self, PyObject * args) {
if (uwsgi.numproc > 1 && uwsgi.mypid != uwsgi.workers[0].pid) {
#endif
uwsgi_lock(uwsgi.user_lock);
UWSGI_SET_LOCKING;
}
Py_INCREF(Py_None);
@@ -884,7 +883,6 @@ PyObject *py_uwsgi_lock(PyObject * self, PyObject * args) {
PyObject *py_uwsgi_unlock(PyObject * self, PyObject * args) {
uwsgi_unlock(uwsgi.user_lock);
UWSGI_UNSET_LOCKING;
Py_INCREF(Py_None);
return Py_None;
@@ -1353,7 +1351,7 @@ PyObject *py_uwsgi_send_multi_message(PyObject * self, PyObject * args) {
else {
for (i = 0; i < clen; i++) {
if (multipoll[i].revents & POLLIN) {
if (!uwsgi_parse_response(&multipoll[i], PyInt_AsLong(arg_timeout), &uh, &buffer[i])) {
if (!uwsgi_parse_response(&multipoll[i], PyInt_AsLong(arg_timeout), &uh, &buffer[i], uwsgi_proto_uwsgi_parser)) {
goto megamulticlear;
}
else {
@@ -1660,8 +1658,6 @@ PyObject *py_uwsgi_async_send_message(PyObject * self, PyObject * args) {
int modifier1 = 0;
int modifier2 = 0;
ssize_t ret;
char *encoded;
uint16_t esize = 0;
@@ -1676,14 +1672,14 @@ PyObject *py_uwsgi_async_send_message(PyObject * self, PyObject * args) {
if (PyDict_Check(pyobj)) {
encoded = uwsgi_encode_pydict(pyobj, &esize);
if (esize > 0) {
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
free(encoded);
}
}
else if (PyString_Check(pyobj)) {
encoded = PyString_AsString(pyobj);
esize = PyString_Size(pyobj);
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
}
else {
marshalled = PyMarshal_WriteObjectToString(pyobj, 1);
@@ -1694,7 +1690,7 @@ PyObject *py_uwsgi_async_send_message(PyObject * self, PyObject * args) {
encoded = PyString_AsString(marshalled);
esize = PyString_Size(marshalled);
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
}
UWSGI_GET_GIL clear:
@@ -1804,8 +1800,6 @@ PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
int fd = -1;
int cl = 0;
ssize_t ret;
int uwsgi_fd = -1;
char *encoded;
uint16_t esize = 0;
@@ -1834,14 +1828,14 @@ PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
if (PyDict_Check(pyobj)) {
encoded = uwsgi_encode_pydict(pyobj, &esize);
if (esize > 0) {
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
free(encoded);
}
}
else if (PyString_Check(pyobj)) {
encoded = PyString_AsString(pyobj);
esize = PyString_Size(pyobj);
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
}
else {
marshalled = PyMarshal_WriteObjectToString(pyobj, 1);
@@ -1852,7 +1846,7 @@ PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
encoded = PyString_AsString(marshalled);
esize = PyString_Size(marshalled);
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
}
UWSGI_GET_GIL
@@ -2011,7 +2005,6 @@ PyObject *py_uwsgi_reload(PyObject * self, PyObject * args) {
PyObject *py_uwsgi_set_blocking(PyObject * self, PyObject * args) {
if (uwsgi.master_process) {
uwsgi.workers[uwsgi.mywid].status |= UWSGI_STATUS_BLOCKING;
Py_INCREF(Py_True);
return Py_True;
}
@@ -2181,7 +2174,6 @@ PyObject *py_uwsgi_parse_file(PyObject * self, PyObject * args) {
PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
pid_t grunt_pid;
int i;
struct wsgi_request *wsgi_req = current_wsgi_req();
if (uwsgi.grunt) {
@@ -2198,9 +2190,7 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
goto clear;
}
else if (grunt_pid == 0) {
for (i = 0; i < uwsgi.sockets_cnt; i++) {
close(uwsgi.sockets[i].fd);
}
uwsgi_close_all_sockets();
// create a new session
setsid();
// exit on SIGPIPE
@@ -2219,8 +2209,10 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
}
// close connection on the worker
fclose(wsgi_req->async_post);
wsgi_req->fd_closed = 1;
if (PyTuple_Size(args) == 0) {
fclose(wsgi_req->async_post);
wsgi_req->fd_closed = 1;
}
clear:
Py_INCREF(Py_None);
@@ -2229,8 +2221,13 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
#ifdef UWSGI_SPOOLER
static PyMethodDef uwsgi_spooler_methods[] = {
#ifdef PYTHREE
{"send_to_spooler", (PyCFunction) py_uwsgi_send_spool, METH_VARARGS | METH_KEYWORDS, ""},
{"spool", (PyCFunction) py_uwsgi_send_spool, METH_VARARGS | METH_KEYWORDS, ""},
#else
{"send_to_spooler", (PyCFunction) py_uwsgi_send_spool, METH_KEYWORDS, ""},
{"spool", (PyCFunction) py_uwsgi_send_spool, METH_KEYWORDS, ""},
#endif
{"set_spooler_frequency", py_uwsgi_spooler_freq, METH_VARARGS, ""},
{"spooler_jobs", py_uwsgi_spooler_jobs, METH_VARARGS, ""},
{NULL, NULL},
+13 -4
View File
@@ -3,10 +3,10 @@
#include <frameobject.h>
#define MAX_PYTHONPATH 64
#define MAX_PYMODULE_ALIAS 64
#define MAX_PYARGV 10
#define LONG_ARGS_PYTHON_BASE 17000 + ((0 + 1) * 100)
#define LONG_ARGS_PYTHON_BASE 17000 + ((0 + 1) * 1000)
#define LONG_ARGS_PYTHONPATH LONG_ARGS_PYTHON_BASE + 1
#define LONG_ARGS_PASTE LONG_ARGS_PYTHON_BASE + 2
@@ -18,6 +18,14 @@
#define Py_ssize_t ssize_t
#endif
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7
#define HAS_NOT_PyFrame_GetLineNumber
#endif
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 2
#define HAS_NOT_PyFrame_GetLineNumber
#endif
#if PY_MAJOR_VERSION > 2
#define PYTHREE
#endif
@@ -90,8 +98,7 @@ struct uwsgi_python {
char *test_module;
char *python_path[MAX_PYTHONPATH];
int python_path_cnt;
struct uwsgi_string_list *python_path;
PyObject *loader_dict;
PyObject* (*loaders[LOADER_MAX]) (void *);
@@ -212,3 +219,5 @@ void threaded_swap_ts(struct wsgi_request *, struct uwsgi_app *);
void simple_swap_ts(struct wsgi_request *, struct uwsgi_app *);
void threaded_reset_ts(struct wsgi_request *, struct uwsgi_app *);
void simple_reset_ts(struct wsgi_request *, struct uwsgi_app *);
int uwsgi_python_profiler_call(PyObject *, PyFrameObject *, int, PyObject *);
+1 -1
View File
@@ -3,7 +3,7 @@ import os,sys
from distutils import sysconfig
NAME='python'
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule']
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler']
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
LDFLAGS = []
+184 -108
View File
@@ -6,18 +6,93 @@ extern struct uwsgi_python up;
typedef struct uwsgi_Input {
PyObject_HEAD
off_t pos;
char readline[1024];
size_t readline_size;
size_t readline_max_size;
size_t readline_pos;
size_t pos;
struct wsgi_request *wsgi_req;
} uwsgi_Input;
PyObject *uwsgi_Input_iter(PyObject * self) {
PyObject *uwsgi_Input_iter(PyObject *self) {
Py_INCREF(self);
return self;
}
PyObject *uwsgi_Input_next(PyObject * self) {
PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
size_t i;
ssize_t rlen;
struct wsgi_request *wsgi_req = self->wsgi_req;
PyObject *res;
return PyErr_Format(PyExc_NotImplementedError, "wsgi.input __iter__() is not implemented");
char *ptr = self->readline;
if (uwsgi.post_buffering > 0) {
ptr = wsgi_req->post_buffering_buf;
self->readline_size = wsgi_req->post_cl;
if (!self->readline_pos) {
self->pos += self->readline_size;
}
}
if (self->readline_pos > 0 || uwsgi.post_buffering) {
for(i=self->readline_pos;i<self->readline_size;i++) {
if (ptr[i] == '\n') {
res = PyString_FromStringAndSize(ptr+self->readline_pos, (i-self->readline_pos)+1);
self->readline_pos = i+1;
if (self->readline_pos >= self->readline_size) self->readline_pos = 0;
return res;
}
}
self->readline_pos = 0;
return PyString_FromStringAndSize(ptr + self->readline_pos, self->readline_size - self->readline_pos);
}
UWSGI_RELEASE_GIL;
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data");
}
if (self->readline_max_size > 0 && self->readline_max_size < 1024) {
rlen = read(wsgi_req->poll.fd, self->readline, self->readline_max_size);
}
else {
rlen = read(wsgi_req->poll.fd, self->readline, 1024);
}
if (rlen < 0) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
}
self->readline_size = rlen;
self->readline_pos = 0;
self->pos += rlen;
UWSGI_GET_GIL;
for(i=0;i<(size_t)rlen;i++) {
if (self->readline[i] == '\n') {
res = PyString_FromStringAndSize(self->readline, i);
self->readline_pos+= i+1;
if (self->readline_pos >= self->readline_size) self->readline_pos = 0;
return res;
}
}
self->readline_pos = 0;
return PyString_FromStringAndSize(self->readline, self->readline_size);
}
PyObject *uwsgi_Input_next(PyObject* self) {
if (!((uwsgi_Input *)self)->wsgi_req->post_cl || ((size_t) ((uwsgi_Input *)self)->pos >= ((uwsgi_Input *)self)->wsgi_req->post_cl && !((uwsgi_Input *)self)->readline_pos)) {
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
return uwsgi_Input_getline((uwsgi_Input *)self);
}
@@ -28,10 +103,9 @@ static void uwsgi_Input_free(uwsgi_Input *self) {
static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
long len = 0;
size_t remains;
size_t remains, tmp_pos = 0;
ssize_t rlen;
char *tmp_buf;
int fd;
PyObject *res;
if (!PyArg_ParseTuple(args, "|l:read", &len)) {
@@ -39,57 +113,70 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
}
// return empty string if no post_cl or pos >= post_cl
if (!self->wsgi_req->post_cl || (size_t) self->pos >= self->wsgi_req->post_cl) {
if ((!self->wsgi_req->post_cl || (size_t) self->pos >= self->wsgi_req->post_cl ) && !self->readline_pos) {
return PyString_FromString("");
}
if (uwsgi.post_buffering > 0) {
fd = -1;
if (self->wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
fd = fileno((FILE *)self->wsgi_req->async_post);
// some residual data ?
if (self->readline_pos && self->readline_size) {
if (len > 0) {
if ((size_t) len < (self->readline_size - self->readline_pos)) {
res = PyString_FromStringAndSize(self->readline + self->readline_pos, len);
self->readline_pos+=len;
if (self->readline_pos >= self->readline_size) self->readline_pos = 0;
return res;
}
}
self->readline_pos = 0;
return PyString_FromStringAndSize(self->readline + self->readline_pos, self->readline_size - self->readline_pos);
}
else {
fd = self->wsgi_req->poll.fd;
}
// return the whole input
if (len <= 0) {
remains = self->wsgi_req->post_cl;
}
else {
remains = len ;
}
if (len <= 0) {
remains = self->wsgi_req->post_cl;
}
else {
remains = len ;
}
if (remains + self->pos > self->wsgi_req->post_cl) {
remains = self->wsgi_req->post_cl - self->pos;
}
remains = self->wsgi_req->post_cl - self->pos;
}
if (remains <= 0) {
return PyString_FromString("");
}
if (remains <= 0) {
return PyString_FromString("");
}
if (fd == -1) {
res = PyString_FromStringAndSize( self->wsgi_req->post_buffering_buf, remains);
self->pos += remains;
if (uwsgi.post_buffering > 0) {
res = PyString_FromStringAndSize( self->wsgi_req->post_buffering_buf+self->pos, remains);
self->pos += remains;
return res;
}
UWSGI_RELEASE_GIL
tmp_buf = uwsgi_malloc(remains);
if (uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
free(tmp_buf);
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data");
while(remains) {
if (uwsgi_waitfd(self->wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data");
}
rlen = read(self->wsgi_req->poll.fd, tmp_buf+tmp_pos, remains);
if (rlen < 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
}
tmp_pos += rlen;
remains -= rlen;
}
rlen = read(fd, tmp_buf, remains);
if (rlen < 0) {
free(tmp_buf);
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
}
self->pos += rlen;
res = PyString_FromStringAndSize(tmp_buf, rlen);
UWSGI_GET_GIL
self->pos += tmp_pos;
res = PyString_FromStringAndSize(tmp_buf, tmp_pos);
free(tmp_buf);
return res;
@@ -97,13 +184,34 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
static PyObject *uwsgi_Input_readline(uwsgi_Input *self, PyObject *args) {
return PyErr_Format(PyExc_NotImplementedError, "wsgi.input readline() is not implemented");
if (!PyArg_ParseTuple(args, "|l:readline", &((uwsgi_Input *)self)->readline_max_size)) {
return NULL;
}
if (!((uwsgi_Input *)self)->wsgi_req->post_cl || ((size_t) ((uwsgi_Input *)self)->pos >= ((uwsgi_Input *)self)->wsgi_req->post_cl && !((uwsgi_Input *)self)->readline_pos)) {
return PyString_FromString("");
}
return uwsgi_Input_getline(self);
}
static PyObject *uwsgi_Input_readlines(uwsgi_Input *self, PyObject *args) {
return PyErr_Format(PyExc_NotImplementedError, "wsgi.input readlines() is not implemented");
PyObject *res;
if (!((uwsgi_Input *)self)->wsgi_req->post_cl || ((size_t) ((uwsgi_Input *)self)->pos >= ((uwsgi_Input *)self)->wsgi_req->post_cl && !((uwsgi_Input *)self)->readline_pos)) {
Py_INCREF(Py_None);
return Py_None;
}
res = PyList_New(0);
while( ((size_t) ((uwsgi_Input *)self)->pos < ((uwsgi_Input *)self)->wsgi_req->post_cl || ((uwsgi_Input *)self)->readline_pos > 0)) {
PyObject *a_line = uwsgi_Input_getline(self);
PyList_Append(res, a_line);
Py_DECREF(a_line);
}
return res;
}
static PyObject *uwsgi_Input_close(uwsgi_Input *self, PyObject *args) {
@@ -171,7 +279,7 @@ PyObject *py_uwsgi_write(PyObject * self, PyObject * args) {
content = PyString_AsString(data);
len = PyString_Size(data);
UWSGI_RELEASE_GIL
wsgi_req->response_size = write(wsgi_req->poll.fd, content, len);
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, content, len);
UWSGI_GET_GIL
}
@@ -229,9 +337,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
char *what;
int what_len;
PyObject *wsgi_socket;
#ifdef UWSGI_ASYNC
if (wsgi_req->async_status == UWSGI_AGAIN) {
// get rid of timeout
@@ -293,22 +398,22 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|| wsgi_req->file_len > 0
|| wsgi_req->paste_len > 0
) {
// a bit of magic: 1-1 = 0 / 0-1 = -1
// 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);
}
else {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
}
if (uwsgi.single_interpreter) {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread);
}
else {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
}
UWSGI_RELEASE_GIL
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
}
}
}
@@ -329,7 +434,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
wsgi_req->app_id = uwsgi.default_app;
}
else {
internal_server_error(wsgi_req->poll.fd, "wsgi application not found");
internal_server_error(wsgi_req, "wsgi application not found");
goto clear2;
}
@@ -351,13 +456,14 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
if (wsgi_req->protocol_len < 5) {
uwsgi_log( "INVALID PROTOCOL: %.*s\n", wsgi_req->protocol_len, wsgi_req->protocol);
internal_server_error(wsgi_req->poll.fd, "invalid HTTP protocol !!!");
internal_server_error(wsgi_req, "invalid HTTP protocol !!!");
goto clear;
}
if (strncmp(wsgi_req->protocol, "HTTP/", 5)) {
uwsgi_log( "INVALID PROTOCOL: %.*s\n", wsgi_req->protocol_len, wsgi_req->protocol);
internal_server_error(wsgi_req->poll.fd, "invalid HTTP protocol !!!");
internal_server_error(wsgi_req, "invalid HTTP protocol !!!");
goto clear;
}
@@ -395,6 +501,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
}
if (wsgi_req->uh.modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) {
wsgi_req->uh.modifier1 = 0;
pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME");
if (pydictkey) {
if (PyString_Check(pydictkey)) {
@@ -411,52 +518,25 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
if (uwsgi.post_buffering > 0) {
UWSGI_RELEASE_GIL
// read to disk if post_cl > post_buffering
if (!up.pep3333_input) {
if (wsgi_req->post_cl >= (size_t) uwsgi.post_buffering) {
if (!uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize)) {
goto clear;
}
}
else {
wsgi_req->async_post = fdopen(wsgi_req->poll.fd, "r");
}
}
else {
// read to disk if post_cl > post_buffering
if (wsgi_req->post_cl >= (size_t) uwsgi.post_buffering) {
if (!uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize)) {
goto clear;
}
}
// on tiny post use memory
else {
if (!uwsgi_read_whole_body_in_mem(wsgi_req, wsgi_req->post_buffering_buf)) {
goto clear;
}
}
}
UWSGI_GET_GIL
// if async_post is mapped as a file, directly use it as wsgi.input
if (wsgi_req->async_post) {
#ifdef PYTHREE
wsgi_req->async_input = PyFile_FromFd(fileno(wsgi_req->async_post), "wsgi_input", "rb", 0, NULL, NULL, NULL, 0);
#else
wsgi_req->async_input = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL);
#endif
}
else {
wsgi_req->async_post = fdopen(wsgi_req->poll.fd, "r");
// create wsgi.input custom object
wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req;
((uwsgi_Input*)wsgi_req->async_input)->pos = 0;
((uwsgi_Input*)wsgi_req->async_input)->readline_pos = 0;
((uwsgi_Input*)wsgi_req->async_input)->readline_max_size = 0;
}
if (!up.pep3333_input) {
wsgi_socket = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL);
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_socket);
Py_DECREF(wsgi_socket);
}
else {
wsgi_socket = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
((uwsgi_Input*)wsgi_socket)->wsgi_req = wsgi_req;
((uwsgi_Input*)wsgi_socket)->pos = 0;
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_socket);
}
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_req->async_input);
wsgi_req->async_result = wi->request_subhandler(wsgi_req, wi);
@@ -485,9 +565,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
// LOCK THIS PART
wsgi_req->response_size += write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->response_size += write(wsgi_req->poll.fd, " 500 Internal Server Error\r\n", 28 );
wsgi_req->response_size += write(wsgi_req->poll.fd, "Content-type: text/plain\r\n\r\n", 28 );
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, " 500 Internal Server Error\r\n", 28 );
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, "Content-type: text/plain\r\n\r\n", 28 );
wsgi_req->header_cnt = 1;
/*
@@ -516,9 +596,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
close(tmp_stderr);
}
if (up.pep3333_input) {
Py_DECREF(wsgi_socket);
}
clear:
up.reset_ts(wsgi_req, wi);
@@ -531,7 +608,6 @@ clear2:
void uwsgi_after_request_wsgi(struct wsgi_request *wsgi_req) {
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING] || wsgi_req->log_this) {
log_request(wsgi_req);
}
+21 -16
View File
@@ -13,7 +13,6 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
PyObject *headers, *head;
PyObject *h_key, *h_value;
int i, j;
struct uwsgi_header uh;
PyObject *exc_info = NULL;
struct wsgi_request *wsgi_req = current_wsgi_req();
@@ -70,10 +69,8 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
}
wsgi_req->hvec[0].iov_len = wsgi_req->protocol_len;
uh.pktsize = wsgi_req->hvec[0].iov_len;
wsgi_req->hvec[1].iov_base = " ";
wsgi_req->hvec[1].iov_len = 1;
uh.pktsize += wsgi_req->hvec[1].iov_len;
#ifdef PYTHREE
wsgi_req->hvec[2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head));
wsgi_req->hvec[2].iov_len = strlen(wsgi_req->hvec[2].iov_base);
@@ -81,18 +78,15 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[2].iov_base = PyString_AsString(head);
wsgi_req->hvec[2].iov_len = PyString_Size(head);
#endif
uh.pktsize += wsgi_req->hvec[2].iov_len;
wsgi_req->status = uwsgi_str3_num(wsgi_req->hvec[2].iov_base);
wsgi_req->hvec[3].iov_base = nl;
wsgi_req->hvec[3].iov_len = NL_SIZE;
uh.pktsize += wsgi_req->hvec[3].iov_len;
}
else {
// drop http status on cgi mode
base = 3;
wsgi_req->hvec[0].iov_base = "Status: ";
wsgi_req->hvec[0].iov_len = 8;
uh.pktsize = wsgi_req->hvec[0].iov_len;
#ifdef PYTHREE
wsgi_req->hvec[1].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head));
wsgi_req->hvec[1].iov_len = strlen(wsgi_req->hvec[1].iov_base);
@@ -100,11 +94,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[1].iov_base = PyString_AsString(head);
wsgi_req->hvec[1].iov_len = PyString_Size(head);
#endif
uh.pktsize += wsgi_req->hvec[1].iov_len;
wsgi_req->status = uwsgi_str3_num(wsgi_req->hvec[1].iov_base);
wsgi_req->hvec[2].iov_base = nl;
wsgi_req->hvec[2].iov_len = NL_SIZE;
uh.pktsize += wsgi_req->hvec[2].iov_len;
}
headers = PyTuple_GetItem(args, 1);
@@ -146,10 +138,8 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[j].iov_base = PyString_AsString(h_key);
wsgi_req->hvec[j].iov_len = PyString_Size(h_key);
#endif
uh.pktsize += wsgi_req->hvec[j].iov_len;
wsgi_req->hvec[j + 1].iov_base = h_sep;
wsgi_req->hvec[j + 1].iov_len = H_SEP_SIZE;
uh.pktsize += wsgi_req->hvec[j+1].iov_len;
#ifdef PYTHREE
wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_value));
wsgi_req->hvec[j + 2].iov_len = strlen(wsgi_req->hvec[j + 2].iov_base);
@@ -158,25 +148,40 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[j + 2].iov_len = PyString_Size(h_value);
#endif
uh.pktsize += wsgi_req->hvec[j+2].iov_len;
wsgi_req->hvec[j + 3].iov_base = nl;
wsgi_req->hvec[j + 3].iov_len = NL_SIZE;
uh.pktsize += wsgi_req->hvec[j+3].iov_len;
//uwsgi_log( "%.*s: %.*s\n", wsgi_req->hvec[j].iov_len, (char *)wsgi_req->hvec[j].iov_base, wsgi_req->hvec[j+2].iov_len, (char *) wsgi_req->hvec[j+2].iov_base);
}
j = (i * 4) + base;
struct uwsgi_string_list *ah = uwsgi.additional_headers;
while(ah) {
if (wsgi_req->header_cnt+1 <= uwsgi.max_vars) {
wsgi_req->header_cnt++;
wsgi_req->hvec[j].iov_base = ah->value;
wsgi_req->hvec[j].iov_len = ah->len;
j++;
wsgi_req->hvec[j].iov_base = nl;
wsgi_req->hvec[j].iov_len = NL_SIZE;
j++;
ah = ah->next;
}
else {
uwsgi_log("no more space in iovec. consider increasing max-vars...\n");
break;
}
}
// \r\n
j = (i * 4) + base;
wsgi_req->hvec[j].iov_base = nl;
wsgi_req->hvec[j].iov_len = NL_SIZE;
uh.pktsize += wsgi_req->hvec[j].iov_len;
UWSGI_RELEASE_GIL
wsgi_req->headers_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, j + 1);
wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, j + 1);
UWSGI_GET_GIL
if (wsgi_req->headers_size < 0) {
uwsgi_error("writev()");
+5 -8
View File
@@ -124,7 +124,7 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
// return or yield ?
if (PyString_Check((PyObject *)wsgi_req->async_result)) {
if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) {
if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) {
uwsgi_error("write()");
goto clear;
}
@@ -185,7 +185,7 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
if (PyString_Check(pychunk)) {
if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) {
if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) {
uwsgi_error("write()");
Py_DECREF(pychunk);
goto clear;
@@ -211,15 +211,12 @@ clear:
if (wsgi_req->sendfile_fd != -1) {
Py_DECREF((PyObject *)wsgi_req->async_sendfile);
}
if (wsgi_req->async_input) {
Py_DECREF((PyObject *)wsgi_req->async_input);
}
if (wsgi_req->async_environ) {
PyDict_Clear(wsgi_req->async_environ);
}
if (wsgi_req->async_post && !wsgi_req->fd_closed) {
fclose(wsgi_req->async_post);
if (!uwsgi.post_buffering || wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
wsgi_req->fd_closed = 1;
}
}
Py_XDECREF((PyObject *)wsgi_req->async_placeholder);
clear2:
Py_DECREF((PyObject *)wsgi_req->async_result);
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python24'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python2.4-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python25'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python2.5-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python26'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python2.6-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python27'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python2.7-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python30'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python3.0-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python31'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python3.1-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
+1 -1
View File
@@ -2,7 +2,7 @@ import os,sys
NAME='python32'
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
CFLAGS = os.popen('python3.2-config --cflags').read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
-146
View File
@@ -1,146 +0,0 @@
#include "uwsgi_rack.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_rack ur;
VALUE fiber_list[200];
void uwsgi_ruby_exception(void);
VALUE fiber_request() {
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
int async_id = wsgi_req->async_id;
for(;;) {
wsgi_req_setup(wsgi_req, async_id);
wsgi_req->async_status = UWSGI_ACCEPTING;
rb_fiber_yield(0, NULL);
if (wsgi_req_simple_accept(wsgi_req, uwsgi.sockets_poll[0].fd)) {
continue;
}
wsgi_req->async_status = UWSGI_OK;
rb_fiber_yield(0, NULL);
// reinitialize switches counter
wsgi_req->switches = 0;
if (wsgi_req_recv(wsgi_req)) {
continue;
}
while(wsgi_req->async_status == UWSGI_AGAIN) {
rb_fiber_yield(0, NULL);
wsgi_req->async_status = uwsgi.p[wsgi_req->uh.modifier1]->request(wsgi_req);
}
rb_fiber_yield(0, NULL);
uwsgi_close_request(wsgi_req);
}
return Qnil;
}
VALUE protected_fiber_loop() {
int i, current = 0;
struct wsgi_request *wsgi_req;
// create a ruby fiber for each async core
uwsgi_log("create a fiber for each async core...\n");
for(i=0;i<uwsgi.async;i++) {
fiber_list[i] = rb_fiber_new(fiber_request, Qnil);
rb_gc_register_address(&fiber_list[i]);
uwsgi.wsgi_requests[i]->async_status = UWSGI_ACCEPTING;
uwsgi.wsgi_requests[i]->async_id = i;
uwsgi.wsgi_req = uwsgi.wsgi_requests[i];
rb_fiber_resume(fiber_list[i], 0, NULL);
uwsgi_log("fiber %d ready\n", i);
}
for(;;) {
//uwsgi.async_running = u_green_blocking();
uwsgi.async_running = 0;
//timeout = u_green_get_timeout();
int timeout = 0;
uwsgi.async_nevents = async_wait(uwsgi.async_queue, uwsgi.async_events, uwsgi.async, uwsgi.async_running, timeout);
//u_green_expire_timeouts();
if (uwsgi.async_nevents < 0) {
continue;
}
for(i=0; i<uwsgi.async_nevents;i++) {
uwsgi_log("received I/O event on fd %d\n", (int) uwsgi.async_events[i].ASYNC_FD);
if ( (int) uwsgi.async_events[i].ASYNC_FD == uwsgi.sockets[0].fd) {
wsgi_req = find_first_accepting_wsgi_req();
if (!wsgi_req) goto cycle;
uwsgi_log("request passed to fiber core %d\n", wsgi_req->async_id);
uwsgi.wsgi_req = wsgi_req;
rb_fiber_resume(fiber_list[wsgi_req->async_id], 0, NULL);
}
else {
wsgi_req = find_wsgi_req_by_fd((int)uwsgi.async_events[i].ASYNC_FD, -1);
if (wsgi_req) {
uwsgi.wsgi_req = wsgi_req;
rb_fiber_resume(fiber_list[wsgi_req->async_id], 0, NULL);
}
else {
async_del(uwsgi.async_queue, (int) uwsgi.async_events[i].ASYNC_FD, uwsgi.async_events[i].ASYNC_EV);
}
}
}
cycle:
//uwsgi_log("resuming fiber %d %p\n", current, fiber_list[current]);
uwsgi.wsgi_req = uwsgi.wsgi_requests[current];
if (uwsgi.wsgi_req->async_status != UWSGI_ACCEPTING) {
uwsgi_log("passing control to fiber %d\n", current);
rb_fiber_resume(fiber_list[current], 0, NULL);
uwsgi_log("returned to main fiber\n");
}
current++;
if (current >= uwsgi.async) current = 0;
}
return Qnil;
}
void fiber_loop() {
int error;
// must run all the rack/ruby plugins without protection
ur.unprotected = 1;
rb_protect(protected_fiber_loop, 0, &error);
if (error) {
uwsgi_ruby_exception();
exit(1);
}
// never here
}
+120 -181
View File
@@ -87,52 +87,6 @@ VALUE rb_uwsgi_io_new(VALUE class, VALUE wr) {
Data_Get_Struct(wr, struct wsgi_request, wsgi_req);
VALUE self = Data_Wrap_Struct(class , 0, 0, wsgi_req);
ssize_t len = uwsgi.post_buffering_bufsize;
size_t post_remains = wsgi_req->post_cl;
char *ptr;
/* now the fun part:
We will try to emulate a StringIO ruby object if http body is littler than uwsgi.post_buffering_bufsize
otherwise we will map a *FILE object
*/
if (!wsgi_req->post_cl) {
return self;
}
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
//uwsgi_log("using file for http body storage %d\n", wsgi_req->post_cl);
//RUBY_GVL_UNLOCK
uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize);
//RUBY_GVL_LOCK
}
else {
//RUBY_GVL_UNLOCK
//uwsgi_log("using memory for http body storage %d\n", wsgi_req->post_cl);
ptr = wsgi_req->post_buffering_buf;
while(post_remains > 0) {
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
}
if (post_remains > (size_t) uwsgi.post_buffering_bufsize) {
len = read(wsgi_req->poll.fd, ptr, len);
}
else {
len = read(wsgi_req->poll.fd, ptr, post_remains);
}
if (len < 0) {
uwsgi_error("read()");
return Qnil;
}
ptr += len;
post_remains -= len;
}
wsgi_req->buf_pos = 0;
//RUBY_GVL_LOCK
}
rb_obj_call_init(self, 0, NULL);
return self;
@@ -150,6 +104,8 @@ VALUE rb_uwsgi_io_gets(VALUE obj, VALUE args) {
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
// return the whole body as string
uwsgi_log("rack.input gets is not implemented (req %p)\n", wsgi_req);
return Qnil;
}
@@ -159,6 +115,7 @@ VALUE rb_uwsgi_io_each(VALUE obj, VALUE args) {
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
// yield strings chunks
uwsgi_log("rack.input each is not implemented (req %p)\n", wsgi_req);
return Qnil;
}
@@ -168,63 +125,28 @@ VALUE rb_uwsgi_io_read(VALUE obj, VALUE args) {
struct wsgi_request *wsgi_req;
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
VALUE chunk;
size_t len;
int chunk_size;
if (!wsgi_req->post_cl) {
if (!wsgi_req->post_cl || wsgi_req->buf_pos >= wsgi_req->post_cl) {
return Qnil;
}
if (RARRAY_LEN(args) == 0) {
//uwsgi_log("reading the whole post data\n" ) ;
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
char *post_body = malloc(wsgi_req->post_cl);
if (post_body) {
//RUBY_GVL_UNLOCK
len = fread( post_body, wsgi_req->post_cl, 1, wsgi_req->async_post);
//RUBY_GVL_LOCK
chunk = rb_str_new(post_body, wsgi_req->post_cl);
free(post_body);
}
else {
uwsgi_error("malloc()");
return Qnil;
}
}
else {
chunk = rb_str_new(wsgi_req->post_buffering_buf, wsgi_req->post_cl);
}
chunk = rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, wsgi_req->post_cl-wsgi_req->buf_pos);
return chunk;
}
else if (RARRAY_LEN(args) > 0) {
chunk_size = NUM2INT(RARRAY_PTR(args)[0]);
//uwsgi_log("chunk reading of %d bytes (post_cl: %d bufsize: %d)\n", chunk_size, wsgi_req->post_cl, uwsgi.post_buffering_bufsize ) ;
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
char *post_body = malloc( chunk_size ) ;
if (post_body) {
//RUBY_GVL_UNLOCK
len = fread( post_body, chunk_size, 1, wsgi_req->async_post );
//uwsgi_log("read %d items\n", len);
//RUBY_GVL_LOCK
chunk = rb_str_new(post_body, chunk_size);
free(post_body);
}
else {
uwsgi_error("malloc()");
return Qnil;
}
if (wsgi_req->buf_pos+chunk_size > wsgi_req->post_cl) {
chunk_size = wsgi_req->post_cl-wsgi_req->buf_pos;
}
else {
if (RARRAY_LEN(args) > 1) {
rb_str_cat(RARRAY_PTR(args)[1], wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
}
chunk = rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
wsgi_req->buf_pos+=chunk_size;
wsgi_req->buf_pos+=chunk_size;
if (RARRAY_LEN(args) > 1) {
rb_str_cat(RARRAY_PTR(args)[1], wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
return RARRAY_PTR(args)[1];
}
return chunk;
return rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
}
return Qnil;
@@ -239,14 +161,7 @@ VALUE rb_uwsgi_io_rewind(VALUE obj, VALUE args) {
return Qnil;
}
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
//RUBY_GVL_LOCK
rewind(wsgi_req->async_post);
//RUBY_GVL_UNLOCK
}
else {
wsgi_req->buf_pos = 0;
}
wsgi_req->buf_pos = 0;
return Qnil;
}
@@ -269,13 +184,55 @@ VALUE require_rails(VALUE arg) {
VALUE init_rack_app(VALUE);
#ifdef RUBY19
VALUE uwsgi_ruby_fiber_yield() {
return rb_fiber_yield(0, NULL);
}
#endif
VALUE uwsgi_ruby_wait_fd_read(VALUE *class, VALUE arg1, VALUE arg2) {
VALUE uwsgi_ruby_suspend(VALUE *arg) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = NUM2INT(arg1);
int timeout = NUM2INT(arg2);
if (fd >= 0) {
async_add_fd_read(wsgi_req, fd, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_wait_fd_write(VALUE *class, VALUE arg1, VALUE arg2) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = NUM2INT(arg1);
int timeout = NUM2INT(arg2);
if (fd >= 0) {
async_add_fd_write(wsgi_req, fd, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_async_connect(VALUE *class, VALUE arg) {
int fd = uwsgi_connect(RSTRING_PTR(arg), 0, 1);
return INT2FIX(fd);
}
VALUE uwsgi_ruby_async_sleep(VALUE *class, VALUE arg) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int timeout = NUM2INT(arg);
if (timeout >= 0) {
async_add_timeout(wsgi_req, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_suspend(VALUE *class) {
struct wsgi_request *wsgi_req = current_wsgi_req();
@@ -312,19 +269,16 @@ int uwsgi_rack_init(){
ruby_init();
ruby_init_loadpath();
#endif
ruby_show_version();
ruby_script("uwsgi");
#ifdef RUBY19
uwsgi_register_loop( (char *) "fiber", fiber_loop);
#endif
VALUE rb_uwsgi_embedded = rb_define_module("UWSGI");
rb_define_module_function(rb_uwsgi_embedded, "suspend", uwsgi_ruby_suspend, 0);
#ifdef RUBY19
rb_define_module_function(rb_uwsgi_embedded, "fiber_yield", uwsgi_ruby_fiber_yield, 0);
#endif
rb_define_module_function(rb_uwsgi_embedded, "async_sleep", uwsgi_ruby_async_sleep, 1);
rb_define_module_function(rb_uwsgi_embedded, "wait_fd_read", uwsgi_ruby_wait_fd_read, 2);
rb_define_module_function(rb_uwsgi_embedded, "wait_fd_write", uwsgi_ruby_wait_fd_write, 2);
rb_define_module_function(rb_uwsgi_embedded, "async_connect", uwsgi_ruby_async_connect, 1);
if (ur.rack) {
ur.dispatcher = rb_protect(init_rack_app, rb_str_new2(ur.rack), &error);
@@ -376,14 +330,6 @@ int uwsgi_rack_init(){
rb_define_method(ur.rb_uwsgi_io_class, "read", rb_uwsgi_io_read, -2);
rb_define_method(ur.rb_uwsgi_io_class, "rewind", rb_uwsgi_io_rewind, 0);
#ifdef RUBY19
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) {
rb_gc_disable();
}
#endif
#endif
return 0;
}
@@ -398,11 +344,10 @@ VALUE send_body(VALUE obj) {
struct wsgi_request *wsgi_req = current_wsgi_req();
ssize_t len = 0;
int fd = wsgi_req->poll.fd;
//uwsgi_log("sending body\n");
if (TYPE(obj) == T_STRING) {
len = write( fd, RSTRING_PTR(obj), RSTRING_LEN(obj));
len = wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(obj), RSTRING_LEN(obj));
}
else {
uwsgi_log("UNMANAGED BODY TYPE %d\n", TYPE(obj));
@@ -428,8 +373,8 @@ VALUE send_header(VALUE obj, VALUE headers) {
struct wsgi_request *wsgi_req = current_wsgi_req();
size_t len;
int fd = wsgi_req->poll.fd;
VALUE hkey, hval;
//uwsgi_log("HEADERS %d\n", TYPE(obj));
if (TYPE(obj) == T_ARRAY) {
@@ -460,9 +405,9 @@ VALUE send_header(VALUE obj, VALUE headers) {
//uwsgi_log("header: %.*s: %.*s\n", RSTRING_LEN(hkey), RSTRING_PTR(hkey), RSTRING_LEN(hval), RSTRING_PTR(hval));
len = write( fd, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
len = wsgi_req->socket->proto_write_header( wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
wsgi_req->headers_size += len;
len = write( fd, ": ", 2);
len = wsgi_req->socket->proto_write_header( wsgi_req, ": ", 2);
wsgi_req->headers_size += len;
char *header_value = RSTRING_PTR(hval);
@@ -471,17 +416,17 @@ VALUE send_header(VALUE obj, VALUE headers) {
char *header_value_splitted = memchr(header_value, '\n', header_value_len);
if (!header_value_splitted) {
len = write( fd, header_value, header_value_len);
len = wsgi_req->socket->proto_write_header( wsgi_req, header_value, header_value_len);
wsgi_req->headers_size += len;
len = write( fd, "\r\n", 2);
len = wsgi_req->socket->proto_write_header( wsgi_req, "\r\n", 2);
wsgi_req->headers_size += len;
wsgi_req->header_cnt++;
}
else {
header_value_splitted[0] = 0;
len = write( fd, header_value, header_value_splitted-header_value);
len = wsgi_req->socket->proto_write_header( wsgi_req, header_value, header_value_splitted-header_value);
wsgi_req->headers_size += len;
len = write( fd, "\r\n", 2);
len = wsgi_req->socket->proto_write_header( wsgi_req, "\r\n", 2);
wsgi_req->headers_size += len;
wsgi_req->header_cnt++;
@@ -491,14 +436,14 @@ VALUE send_header(VALUE obj, VALUE headers) {
while(header_value_len && (header_value_splitted = memchr(header_value, '\n', header_value_len))) {
header_value_splitted[0] = 0;
len = write( fd, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
len = wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
wsgi_req->headers_size += len;
len = write( fd, ": ", 2);
len = wsgi_req->socket->proto_write( wsgi_req, ": ", 2);
wsgi_req->headers_size += len;
len = write( fd, header_value, header_value_splitted-header_value);
len = wsgi_req->socket->proto_write( wsgi_req, header_value, header_value_splitted-header_value);
wsgi_req->headers_size += len;
len = write( fd, "\r\n", 2);
len = wsgi_req->socket->proto_write( wsgi_req, "\r\n", 2);
wsgi_req->headers_size += len;
wsgi_req->header_cnt++;
@@ -517,9 +462,21 @@ clear:
return Qnil;
}
VALUE iterate_headers(VALUE headers) {
#ifdef RUBY19
return rb_block_call(headers, rb_intern("each"), 0, 0, send_header, headers );
#else
return rb_iterate(rb_each, headers, send_header, headers);
#endif
}
int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
int error;
int error = 0;
int i;
VALUE env, ret, status, headers, body;
@@ -532,13 +489,10 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
}
if (uwsgi_parse_vars(wsgi_req)) {
if (wsgi_req->status != 200) uwsgi_log("Invalid RACK request. skip.\n");
return -1;
}
//RUBY_GVL_LOCK
env = rb_hash_new();
// fill ruby hash
@@ -572,7 +526,13 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
rb_hash_aset(env, rb_str_new2("rack.run_once"), Qfalse);
VALUE dws_wr = Data_Wrap_Struct(ur.rb_uwsgi_io_class, 0, 0, wsgi_req);
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall(ur.rb_uwsgi_io_class, rb_intern("new"), 1, dws_wr ));
if (wsgi_req->async_post) {
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(fileno(wsgi_req->async_post)), rb_str_new("r",1) ));
}
else {
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall(ur.rb_uwsgi_io_class, rb_intern("new"), 1, dws_wr ));
}
rb_hash_aset(env, rb_str_new2("rack.errors"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(2), rb_str_new("w",1) ));
@@ -627,29 +587,39 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
wsgi_req->hvec[5].iov_base = (char *) "\r\n";
wsgi_req->hvec[5].iov_len = 2 ;
//RUBY_GVL_UNLOCK
if ( !(wsgi_req->headers_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, 6)) ) {
if ( !(wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, 6)) ) {
uwsgi_error("writev()");
}
//RUBY_GVL_LOCK
headers = RARRAY_PTR(ret)[1] ;
if (rb_respond_to( headers, rb_intern("each") )) {
rb_iterate( rb_each, headers, send_header, headers);
if (ur.unprotected) {
#ifdef RUBY19
rb_block_call(headers, rb_intern("each"), 0, 0, send_header, headers);
#else
rb_iterate(rb_each, headers, send_header, headers);
#endif
}
else {
rb_protect( iterate_headers, headers, &error);
if (error) {
uwsgi_ruby_exception();
rb_gc_unregister_address(&status);
rb_gc_unregister_address(&headers);
goto clear;
}
}
}
//RUBY_GVL_UNLOCK
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
if (wsgi_req->socket->proto_write(wsgi_req, "\r\n", 2) != 2) {
uwsgi_error("write()");
}
//RUBY_GVL_LOCK
body = RARRAY_PTR(ret)[2] ;
if (rb_respond_to( body, rb_intern("to_path") )) {
VALUE sendfile_path = rb_funcall( body, rb_intern("to_path"), 0);
wsgi_req->sendfile_fd = open(RSTRING_PTR(sendfile_path), O_RDONLY);
//RUBY_GVL_UNLOCK
wsgi_req->response_size = uwsgi_sendfile(wsgi_req);
if (wsgi_req->response_size > 0) {
while(wsgi_req->response_size < wsgi_req->sendfile_fd_size) {
@@ -657,7 +627,6 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
}
}
//RUBY_GVL_LOCK;
rb_gc_unregister_address(&sendfile_path);
}
@@ -691,36 +660,21 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
rb_gc_unregister_address(&body);
}
else {
internal_server_error(wsgi_req, "Invalid RACK response");
}
clear:
rb_gc_unregister_address(&ret);
rb_gc_unregister_address(&env);
if (ur.gc_freq <= 1 || ur.cycles%ur.gc_freq == 0) {
#ifdef RUBY19
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) {
if (wsgi_req->async_id == 0) {
rb_gc_enable();
rb_gc();
rb_gc_disable();
}
}
else {
#endif
#endif
//uwsgi_log("calling ruby GC\n");
rb_gc();
#ifdef RUBY19
#ifdef UWSGI_THREADING
}
#endif
#endif
}
//RUBY_GVL_UNLOCK
ur.cycles++;
@@ -761,15 +715,6 @@ void uwsgi_rack_resume(struct wsgi_request *wsgi_req) {
uwsgi_log("RESUMING RUBY\n");
}
void uwsgi_rack_enable_threads(void) {
pthread_mutex_init(&ur.gvl, NULL);
}
void uwsgi_rack_init_thread(int core_id) {
// thread initialization
}
VALUE init_rack_app( VALUE script ) {
int error;
@@ -858,11 +803,5 @@ struct uwsgi_plugin rack_plugin = {
.suspend = uwsgi_rack_suspend,
.resume = uwsgi_rack_resume,
#ifdef RUBY19
#ifdef UWSGI_THREADING
.enable_threads = uwsgi_rack_enable_threads,
.init_thread = uwsgi_rack_init_thread,
#endif
#endif
};
+2
View File
@@ -60,3 +60,5 @@ struct uwsgi_rack {
pthread_mutex_t gvl;
};
void uwsgi_ruby_exception(void);
-1
View File
@@ -17,7 +17,6 @@ GCC_LIST = ['rack_plugin']
if v[0] == '1' and v[1] == '9':
CFLAGS.append('-DRUBY19')
CFLAGS.append('-Wno-unused-parameter')
GCC_LIST.append('fiber')
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
if includedir == 'nil':
+2 -2
View File
@@ -29,10 +29,10 @@ int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
wsgi_req->uh.pktsize = uwsgi_rpc(argv[0], argc-1, argv+1, wsgi_req->buffer);
if (wsgi_req->uh.modifier2 == 0) {
wsgi_req->headers_size = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, (char *)&wsgi_req->uh, 4);
}
wsgi_req->response_size = write(wsgi_req->poll.fd, wsgi_req->buffer, wsgi_req->uh.pktsize);
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
wsgi_req->status = 0;
return 0;
+4 -3
View File
@@ -2,8 +2,10 @@ import os,sys
NAME='ruby19'
#RUBYPATH = '/opt/ruby19/bin/ruby'
RUBYPATH = '/Users/roberto/RUBY/bin/ruby'
try:
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
except:
RUBYPATH = 'ruby'
GCC_LIST = ['../rack/rack_plugin']
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
@@ -13,7 +15,6 @@ v = version.split('.')
if v[0] == '1' and v[1] == '9':
CFLAGS.append('-DRUBY19')
GCC_LIST.append('../rack/fiber')
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
if includedir == 'nil':
+107
View File
@@ -0,0 +1,107 @@
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
uint16_t proto_base_add_uwsgi_header(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
int i;
char *buffer = wsgi_req->buffer + wsgi_req->uh.pktsize;
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
char *ptr = buffer;
for (i = 0; i < keylen; i++) {
if (key[i] == '-') {
key[i] = '_';
}
else {
key[i] = toupper(key[i]);
}
}
if (uwsgi_strncmp("CONTENT_TYPE", 12, key, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) {
if (buffer + keylen + vallen + 2 + 2 + 5 >= watermark) {
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val);
return 0;
}
*ptr++ = (uint8_t) ((keylen + 5) & 0xff);
*ptr++ = (uint8_t) (((keylen + 5) >> 8) & 0xff);
memcpy(ptr, "HTTP_", 5);
ptr += 5;
memcpy(ptr, key, keylen);
ptr += keylen;
keylen += 5;
}
else {
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val);
return 0;
}
*ptr++ = (uint8_t) (keylen & 0xff);
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
memcpy(ptr, key, keylen);
ptr += keylen;
}
*ptr++ = (uint8_t) (vallen & 0xff);
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
memcpy(ptr, val, vallen);
#ifdef UWSGI_DEBUG
uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen, key, vallen, val);
#endif
return keylen + vallen + 2 + 2;
}
uint16_t proto_base_add_uwsgi_var(struct wsgi_request * wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
char *buffer = wsgi_req->buffer + wsgi_req->uh.pktsize;
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
char *ptr = buffer;
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val);
return 0;
}
*ptr++ = (uint8_t) (keylen & 0xff);
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
memcpy(ptr, key, keylen);
ptr += keylen;
*ptr++ = (uint8_t) (vallen & 0xff);
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
memcpy(ptr, val, vallen);
#ifdef UWSGI_DEBUG
uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen, key, vallen, val);
#endif
return keylen + vallen + 2 + 2;
}
int uwsgi_proto_base_accept(struct wsgi_request *wsgi_req, int fd) {
return accept(fd, (struct sockaddr *) &wsgi_req->c_addr, (socklen_t *) & wsgi_req->c_len);
}
void uwsgi_proto_base_close(struct wsgi_request *wsgi_req) {
if (wsgi_req->async_post) {
fclose(wsgi_req->async_post);
if (wsgi_req->body_as_file) {
close(wsgi_req->poll.fd);
}
}
else {
close(wsgi_req->poll.fd);
}
}
+287
View File
@@ -0,0 +1,287 @@
/* async fastcgi protocol parser */
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
#define PROTO_STATUS_RECV_HDR 0
#define PROTO_STATUS_RECV_BODY 1
int uwsgi_proto_fastcgi_parser(struct wsgi_request *wsgi_req) {
ssize_t len;
struct fcgi_record *fr;
uint16_t rs;
int j;
uint8_t octet;
uint32_t keylen, vallen;
// allocate space for a fastcgi record
if (!wsgi_req->proto_parser_buf) {
wsgi_req->proto_parser_buf = uwsgi_malloc(8 + 65536);
}
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
len = read(wsgi_req->poll.fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, 8 - wsgi_req->proto_parser_pos);
if (len <= 0) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
if (wsgi_req->proto_parser_pos >= 8) {
fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
rs = ntohs(fr->cl);
#ifdef UWSGI_DEBUG
uwsgi_log("fastcgi rs %d type %d\n", rs, fr->type);
#endif
// empty STDIN ?
if (fr->type == 5 && rs == 0) {
wsgi_req->proto_parser_status = 0;
if (wsgi_req->async_post) {
rewind(wsgi_req->async_post);
wsgi_req->body_as_file = 1;
}
free(wsgi_req->proto_parser_buf);
return UWSGI_OK;
}
wsgi_req->proto_parser_pos = 0;
if (rs == 0) {
return UWSGI_AGAIN;
}
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_BODY;
}
return UWSGI_AGAIN;
}
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_BODY) {
fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
rs = ntohs(fr->cl);
len = read(wsgi_req->poll.fd, wsgi_req->proto_parser_buf + 8 + wsgi_req->proto_parser_pos, (rs + fr->pad) - wsgi_req->proto_parser_pos);
if (len <= 0) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
if (wsgi_req->proto_parser_pos >= rs + fr->pad) {
#ifdef UWSGI_DEBUG
uwsgi_log("record parsed = type: %d size: %d padding: %d\n", fr->type, rs, fr->pad);
#endif
// params
if (fr->type == 4) {
for (j = 0; j < rs; j++) {
octet = ((uint8_t *) wsgi_req->proto_parser_buf)[8 + j];
if (octet > 127) {
if (j + 4 >= rs) {
free(wsgi_req->proto_parser_buf);
return -1;
}
memcpy(&keylen, wsgi_req->proto_parser_buf + 8 + j, 4);
keylen = ntohl(keylen) ^ 0x80000000;
j += 4;
}
else {
if (j + 1 >= rs) {
free(wsgi_req->proto_parser_buf);
return -1;
}
keylen = octet;
j++;
}
octet = ((uint8_t *) wsgi_req->proto_parser_buf)[8 + j];
if (octet > 127) {
if (j + 4 > rs) {
free(wsgi_req->proto_parser_buf);
return -1;
}
memcpy(&vallen, wsgi_req->proto_parser_buf + 8 + j, 4);
vallen = ntohl(vallen) ^ 0x80000000;
j += 4;
}
else {
if (j + 1 > rs) {
free(wsgi_req->proto_parser_buf);
return -1;
}
vallen = octet;
j++;
}
if (j + (keylen + vallen) > rs) {
free(wsgi_req->proto_parser_buf);
return -1;
}
if (keylen <= 0xffff && vallen <= 0xffff) {
#ifdef UWSGI_DEBUG
uwsgi_log("keylen %d %.*s vallen %d %.*s\n", keylen, keylen, wsgi_req->proto_parser_buf + 8 + j, vallen, vallen, wsgi_req->proto_parser_buf + 8 + j + keylen);
#endif
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, wsgi_req->proto_parser_buf + 8 + j, keylen, wsgi_req->proto_parser_buf + 8 + j + keylen, vallen);
}
j += (keylen + vallen) - 1;
}
}
// stdin
else if (fr->type == 5) {
if (!wsgi_req->async_post) {
wsgi_req->async_post = tmpfile();
if (!wsgi_req->async_post) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("tmpfile()");
return -1;
}
}
if (!fwrite(wsgi_req->proto_parser_buf + 8, rs, 1, wsgi_req->async_post)) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("fwrite()");
return -1;
}
}
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_HDR;
wsgi_req->proto_parser_pos = 0;
}
}
return UWSGI_AGAIN;
}
ssize_t uwsgi_proto_fastcgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
int i;
ssize_t len;
ssize_t ret = 0;
for (i = 0; i < (int) iov_len; i++) {
len = uwsgi_proto_fastcgi_write(wsgi_req, iovec[i].iov_base, iovec[i].iov_len);
if (len <= 0) {
return len;
}
ret += len;
}
return ret;
}
ssize_t uwsgi_proto_fastcgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return uwsgi_proto_fastcgi_writev_header(wsgi_req, iovec, iov_len);
}
ssize_t uwsgi_proto_fastcgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
struct fcgi_record fr;
ssize_t rlen;
size_t chunk_len;
char *ptr = buf;
// in fastcgi we need to not send 0 size frames
if (!len)
return 0;
fr.version = 1;
fr.type = 6;
fr.req1 = 0;
fr.req0 = 1;
fr.pad = 0;
fr.reserved = 0;
fr.cl = htons(len);
// split response in 64k chunks...
if (len <= 65535) {
rlen = write(wsgi_req->poll.fd, &fr, 8);
if (rlen <= 0) {
return rlen;
}
return write(wsgi_req->poll.fd, buf, len);
}
else {
while(len > 0) {
chunk_len = UMIN(65535, len);
fr.cl = htons(chunk_len);
rlen = write(wsgi_req->poll.fd, &fr, 8);
if (rlen <= 0) {
return rlen;
}
rlen = write(wsgi_req->poll.fd, ptr, chunk_len);
if (rlen <= 0) {
return rlen;
}
ptr += rlen;
len -= rlen;
}
return ptr-buf;
}
}
ssize_t uwsgi_proto_fastcgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return uwsgi_proto_fastcgi_write(wsgi_req, buf, len);
}
void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
if (write(wsgi_req->poll.fd, FCGI_END_REQUEST, 24) <= 0) {
uwsgi_error("write()");
}
uwsgi_proto_base_close(wsgi_req);
}
ssize_t uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req) {
ssize_t len;
struct fcgi_record fr;
char buf[65536];
size_t remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
wsgi_req->sendfile_fd_chunk = 65536;
fr.version = 1;
fr.type = 6;
fr.req1 = 0;
fr.req0 = 1;
fr.pad = 0;
fr.reserved = 0;
if (uwsgi.async > 1) {
fr.cl = htons(UMIN(remains, wsgi_req->sendfile_fd_chunk));
len = write(wsgi_req->poll.fd, &fr, 8);
if (len != 8) {
uwsgi_error("write()");
return -1;
}
len = read(wsgi_req->sendfile_fd, buf, ntohs(fr.cl));
if (len != ntohs(fr.cl)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
return write(wsgi_req->poll.fd, buf, len);
}
while (remains) {
fr.cl = htons(UMIN(remains, wsgi_req->sendfile_fd_chunk));
len = write(wsgi_req->poll.fd, &fr, 8);
if (len != 8) {
uwsgi_error("write()");
return -1;
}
len = read(wsgi_req->sendfile_fd, buf, ntohs(fr.cl));
if (len != ntohs(fr.cl)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
if (write(wsgi_req->poll.fd, buf, len) != len) {
uwsgi_error("write()");
return -1;
}
remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
}
return wsgi_req->sendfile_fd_pos;
}
+307
View File
@@ -0,0 +1,307 @@
/* async http protocol parser */
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, int hhlen) {
char *buffer = wsgi_req->buffer + wsgi_req->uh.pktsize;
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
int i;
int status = 0;
char *val = hh;
uint16_t keylen = 0, vallen = 0;
int prefix = 0;
char *ptr = buffer;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
vallen++;
}
else if (status == 2) {
vallen++;
}
}
if (!keylen)
return 0;
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
keylen += 5;
prefix = 1;
}
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
wsgi_req->post_cl = uwsgi_str_num(val, vallen);
}
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
if (prefix) {
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
}
else {
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
}
return 0;
}
*ptr++ = (uint8_t) (keylen & 0xff);
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
if (prefix) {
memcpy(ptr, "HTTP_", 5);
ptr += 5;
memcpy(ptr, hh, keylen - 5);
ptr += (keylen - 5);
}
else {
memcpy(ptr, hh, keylen);
ptr += keylen;
}
*ptr++ = (uint8_t) (vallen & 0xff);
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
memcpy(ptr, val, vallen);
#ifdef UWSGI_DEBUG
uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen - (prefix * 5), hh, vallen, val);
#endif
return 2 + keylen + 2 + vallen;
}
static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
char *ptr = wsgi_req->proto_parser_buf;
char *base = ptr;
char *query_string = NULL;
// REQUEST_METHOD
while (ptr < watermark) {
if (*ptr == ' ') {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, base, ptr - base);
ptr++;
break;
}
ptr++;
}
// REQUEST_URI / PATH_INFO / QUERY_STRING
base = ptr;
while (ptr < watermark) {
if (*ptr == '?' && !query_string) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, base, ptr - base);
query_string = ptr + 1;
}
else if (*ptr == ' ') {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, base, ptr - base);
if (!query_string) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, base, ptr - base);
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
}
else {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, query_string, ptr - query_string);
}
ptr++;
break;
}
ptr++;
}
// SERVER_PROTOCOL
base = ptr;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
return 0;
if (*(ptr + 1) != '\n')
return 0;
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, base, ptr - base);
ptr += 2;
break;
}
ptr++;
}
// SCRIPT_NAME
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0);
// SERVER_NAME
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
// SERVER_PORT
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "3031", 4);
/*
// REMOTE_ADDR
if (inet_ntop(AF_INET, &h_session->ip_addr, h_session->ip, INET_ADDRSTRLEN)) {
h_session->uh.pktsize += proto_base_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REMOTE_ADDR", 11, h_session->ip, strlen(h_session->ip));
}
else {
uwsgi_error("inet_ntop()");
}
*/
//HEADERS
base = ptr;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
return 0;
if (*(ptr + 1) != '\n')
return 0;
// multiline header ?
if (ptr + 2 < watermark) {
if (*(ptr + 2) == ' ' || *(ptr + 2) == '\t') {
ptr += 2;
continue;
}
}
wsgi_req->uh.pktsize += http_add_uwsgi_header(wsgi_req, base, ptr - base);
ptr++;
base = ptr + 1;
}
ptr++;
}
return 0;
}
int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
ssize_t len;
int j;
char *ptr;
ssize_t remains;
// make this buffer configurable
char post_buf[8192];
// first round ? this memory area will be freed by async_loop
if (!wsgi_req->proto_parser_buf) {
wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size);
}
if (wsgi_req->post_cl) {
remains = wsgi_req->post_cl - wsgi_req->proto_parser_pos;
if (remains > 0) {
remains = UMIN(remains, 8192);
len = read(wsgi_req->poll.fd, post_buf, remains);
if (len <= 0) {
uwsgi_error("read()");
fclose(wsgi_req->async_post);
return -1;
}
if (!fwrite(post_buf, len, 1, wsgi_req->async_post)) {
uwsgi_error("fwrite()");
fclose(wsgi_req->async_post);
return -1;
}
wsgi_req->proto_parser_pos += len;
if (wsgi_req->proto_parser_pos < wsgi_req->post_cl)
return UWSGI_AGAIN;
}
rewind(wsgi_req->async_post);
wsgi_req->body_as_file = 1;
return UWSGI_OK;
}
len = read(wsgi_req->poll.fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, uwsgi.buffer_size - wsgi_req->proto_parser_pos);
if (len <= 0) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("recv()");
return -1;
}
ptr = wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos;
wsgi_req->proto_parser_pos += len;
for (j = 0; j < len; j++) {
if (*ptr == '\r' && (wsgi_req->proto_parser_status == 0 || wsgi_req->proto_parser_status == 2)) {
wsgi_req->proto_parser_status++;
}
else if (*ptr == '\r') {
wsgi_req->proto_parser_status = 1;
}
else if (*ptr == '\n' && wsgi_req->proto_parser_status == 1) {
wsgi_req->proto_parser_status = 2;
}
else if (*ptr == '\n' && wsgi_req->proto_parser_status == 3) {
ptr++;
remains = len - (j + 1);
http_parse(wsgi_req, ptr);
//is there a Content_Length ?
if (wsgi_req->post_cl) {
wsgi_req->async_post = tmpfile();
if (!wsgi_req->async_post) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("tmpfile()");
return -1;
}
wsgi_req->proto_parser_pos = 0;
remains = UMIN((size_t) remains, wsgi_req->post_cl);
if (remains) {
if (!fwrite(ptr, remains, 1, wsgi_req->async_post)) {
free(wsgi_req->proto_parser_buf);
uwsgi_error("fwrite()");
fclose(wsgi_req->async_post);
return -1;
}
wsgi_req->proto_parser_pos += remains;
if (wsgi_req->proto_parser_pos >= wsgi_req->post_cl) {
free(wsgi_req->proto_parser_buf);
rewind(wsgi_req->async_post);
wsgi_req->body_as_file = 1;
return UWSGI_OK;
}
}
return UWSGI_AGAIN;
}
free(wsgi_req->proto_parser_buf);
return UWSGI_OK;
}
else {
wsgi_req->proto_parser_status = 0;
}
ptr++;
}
return UWSGI_AGAIN;
}
ssize_t uwsgi_proto_http_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return writev(wsgi_req->poll.fd, iovec, iov_len);
}
ssize_t uwsgi_proto_http_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return writev(wsgi_req->poll.fd, iovec, iov_len);
}
ssize_t uwsgi_proto_http_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
ssize_t uwsgi_proto_http_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
+131
View File
@@ -0,0 +1,131 @@
/* async uwsgi protocol parser */
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
#define PROTO_STATUS_RECV_HDR 0
#define PROTO_STATUS_RECV_VARS 1
int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) {
uint8_t *hdr_buf = (uint8_t *) & wsgi_req->uh;
ssize_t len;
struct iovec iov[1];
struct cmsghdr *cmsg;
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
if (wsgi_req->proto_parser_pos > 0) {
len = read(wsgi_req->poll.fd, hdr_buf + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos);
}
else {
iov[0].iov_base = hdr_buf;
iov[0].iov_len = 4;
wsgi_req->msg.msg_name = NULL;
wsgi_req->msg.msg_namelen = 0;
wsgi_req->msg.msg_iov = iov;
wsgi_req->msg.msg_iovlen = 1;
wsgi_req->msg.msg_control = &wsgi_req->msg_control;
wsgi_req->msg.msg_controllen = sizeof(wsgi_req->msg_control);
wsgi_req->msg.msg_flags = 0;
len = recvmsg(wsgi_req->poll.fd, &wsgi_req->msg, 0);
}
if (len <= 0) {
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
// header ready ?
if (wsgi_req->proto_parser_pos == 4) {
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_VARS;
wsgi_req->proto_parser_pos = 0;
/* big endian ? */
#ifdef __BIG_ENDIAN__
wsgi_req->uh.pktsize = uwsgi_swap16(wsgi_req->uh.pktsize);
#endif
#ifdef UWSGI_DEBUG
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", wsgi_req->uh.pktsize, wsgi_req->uh.pktsize, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2);
#endif
/* check for max buffer size */
if (wsgi_req->uh.pktsize > uwsgi.buffer_size) {
uwsgi_log("invalid request block size: %d...skip\n", wsgi_req->uh.pktsize);
return -1;
}
if (!wsgi_req->uh.pktsize)
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_VARS) {
len = read(wsgi_req->poll.fd, wsgi_req->buffer + wsgi_req->proto_parser_pos, wsgi_req->uh.pktsize - wsgi_req->proto_parser_pos);
if (len <= 0) {
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
// body ready ?
if (wsgi_req->proto_parser_pos >= wsgi_req->uh.pktsize) {
// older OSX versions make mess with CMSG_FIRSTHDR
#ifdef __APPLE__
if (!wsgi_req->msg.msg_controllen)
return UWSGI_OK;
#endif
if (uwsgi.no_fd_passing)
return UWSGI_OK;
cmsg = CMSG_FIRSTHDR(&wsgi_req->msg);
while (cmsg != NULL) {
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type && SCM_RIGHTS) {
// upgrade connection to the new socket
#ifdef UWSGI_DEBUG
uwsgi_log("upgrading fd %d to ", wsgi_req->poll.fd);
#endif
close(wsgi_req->poll.fd);
memcpy(&wsgi_req->poll.fd, CMSG_DATA(cmsg), sizeof(int));
#ifdef UWSGI_DEBUG
uwsgi_log("%d\n", wsgi_req->poll.fd);
#endif
}
cmsg = CMSG_NXTHDR(&wsgi_req->msg, cmsg);
}
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
// never here
return -1;
}
ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return writev(wsgi_req->poll.fd, iovec, iov_len);
}
ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return writev(wsgi_req->poll.fd, iovec, iov_len);
}
ssize_t uwsgi_proto_uwsgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
+124
View File
@@ -0,0 +1,124 @@
/* async uwsgi protocol parser */
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
#define PROTO_STATUS_RECV_HDR 0
#define PROTO_STATUS_RECV_VARS 1
int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) {
uint8_t *hdr_buf = (uint8_t *) & wsgi_req->uh;
ssize_t len;
struct iovec iov[1];
struct cmsghdr *cmsg;
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
if (wsgi_req->proto_parser_pos > 0) {
len = read(wsgi_req->poll.fd, hdr_buf + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos);
}
else {
iov[0].iov_base = hdr_buf;
iov[0].iov_len = 4;
wsgi_req->msg.msg_name = NULL;
wsgi_req->msg.msg_namelen = 0;
wsgi_req->msg.msg_iov = iov;
wsgi_req->msg.msg_iovlen = 1;
wsgi_req->msg.msg_control = &wsgi_req->msg_control;
wsgi_req->msg.msg_controllen = sizeof(wsgi_req->msg_control);
wsgi_req->msg.msg_flags = 0;
len = recvmsg(wsgi_req->poll.fd, &wsgi_req->msg, 0);
}
if (len <= 0) {
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
// header ready ?
if (wsgi_req->proto_parser_pos == 4) {
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_VARS;
wsgi_req->proto_parser_pos = 0;
/* big endian ? */
#ifdef __BIG_ENDIAN__
wsgi_req->uh.pktsize = uwsgi_swap16(wsgi_req->uh.pktsize);
#endif
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", wsgi_req->uh.pktsize, wsgi_req->uh.pktsize, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2);
/* check for max buffer size */
if (wsgi_req->uh.pktsize > uwsgi.buffer_size) {
uwsgi_log("invalid request block size. requested %d bytes available %d bytes...skip\n", wsgi_req->uh.pktsize, uwsgi.buffer_size);
return -1;
}
if (!wsgi_req->uh.pktsize)
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_VARS) {
len = read(wsgi_req->poll.fd, wsgi_req->buffer + wsgi_req->proto_parser_pos, wsgi_req->uh.pktsize - wsgi_req->proto_parser_pos);
if (len <= 0) {
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
// body ready ?
if (wsgi_req->proto_parser_pos >= wsgi_req->uh.pktsize) {
// older OSX versions make mess with CMSG_FIRSTHDR
#ifdef __APPLE__
if (!wsgi_req->msg.msg_controllen)
return UWSGI_OK;
#endif
cmsg = CMSG_FIRSTHDR(&wsgi_req->msg);
while (cmsg != NULL) {
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type && SCM_RIGHTS) {
// upgrade connection to the new socket
uwsgi_log("upgrading fd %d to ", wsgi_req->poll.fd);
close(wsgi_req->poll.fd);
memcpy(&wsgi_req->poll.fd, CMSG_DATA(cmsg), sizeof(int));
uwsgi_log("%d\n", wsgi_req->poll.fd);
}
cmsg = CMSG_NXTHDR(&wsgi_req->msg, cmsg);
}
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
// never here
return -1;
}
ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return writev(wsgi_req->poll.fd, iovec, iov_len);
}
ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return writev(wsgi_req->poll.fd, iovec, iov_len);
}
ssize_t uwsgi_proto_uwsgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
+481
View File
@@ -0,0 +1,481 @@
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_JSON
#include <jansson.h>
static char *uwsgi_mongrel2_json_get_string(json_t * node, const char *json_key) {
json_t *json_value = json_object_get(node, json_key);
if (json_is_string(json_value)) {
return (char *) json_string_value(json_value);
}
return NULL;
}
static uint16_t uwsgi_mongrel2_json_add(struct wsgi_request *wsgi_req, json_t * node, const char *json_key, char *key, uint16_t keylen, char **extra, size_t * extra_len) {
char *json_val;
json_t *json_value = json_object_get(node, json_key);
if (json_is_string(json_value)) {
json_val = (char *) json_string_value(json_value);
// invalid value ?
if (strlen(json_val) > 0xffff)
return 0;
if (extra) {
*extra = json_val;
*extra_len = strlen(json_val);
}
return proto_base_add_uwsgi_var(wsgi_req, key, keylen, json_val, strlen(json_val));
}
return 0;
}
static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_req) {
char *json_val;
char *query_string = NULL;
size_t query_string_len = 0;
size_t script_name_len = 0;
void *json_iter;
char *json_key;
json_t *json_value;
if ((json_val = uwsgi_mongrel2_json_get_string(root, "METHOD"))) {
if (!strcmp(json_val, "JSON")) {
return -1;
}
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val));
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) {
wsgi_req->async_post = fopen(json_val, "r");
if (!wsgi_req->async_post) {
uwsgi_error_open(json_val);
return -1;
}
}
else if (uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-start")) {
return -1;
}
wsgi_req->uh.pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "VERSION", "SERVER_PROTOCOL", 15, NULL, NULL);
wsgi_req->uh.pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "QUERY", "QUERY_STRING", 12, &query_string, &query_string_len);
if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATTERN"))) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, json_val, strlen(json_val) - 1);
script_name_len = strlen(json_val) - 1;
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATH"))) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, json_val + script_name_len, strlen(json_val + script_name_len));
if (query_string_len) {
char *request_uri = uwsgi_concat3n(json_val, strlen(json_val), "?", 1, query_string, query_string_len);
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, strlen(json_val) + 1 + query_string_len);
free(request_uri);
}
else {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, json_val, strlen(json_val));
}
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) {
char *colon = strchr(json_val, ':');
if (colon) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, strlen(colon + 1));
}
else {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
}
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "content-length"))) {
wsgi_req->post_cl = atoi(json_val);
}
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
json_iter = json_object_iter(root);
while (json_iter) {
json_key = (char *) json_object_iter_key(json_iter);
// is it a header ?
if (json_key[0] >= 97) {
json_value = json_object_iter_value(json_iter);
if (json_is_string(json_value)) {
json_val = (char *) json_string_value(json_value);
wsgi_req->uh.pktsize += proto_base_add_uwsgi_header(wsgi_req, json_key, strlen(json_key), json_val, strlen(json_val));
}
}
json_iter = json_object_iter_next(root, json_iter);
}
return 0;
}
#endif
// dumb/fake tnetstring implementation...all is a string
static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *buf, int len) {
char *ptr = buf;
char *watermark = buf + len;
char *key = NULL;
size_t keylen = 0;
char *val = NULL;
size_t vallen = 0;
uint16_t script_name_len = 0;
char *query_string = NULL;
uint16_t query_string_len = 0;
int async_upload = 0;
while (ptr < watermark) {
ptr = uwsgi_netstring(ptr, len - (ptr - buf), &key, &keylen);
if (ptr == NULL)
break;
// empty keys are not allowed
if (keylen == 0)
break;
if (ptr >= watermark)
break;
ptr = uwsgi_netstring(ptr, len - (ptr - buf), &val, &vallen);
if (ptr == NULL)
break;
if (key[0] < 97) {
if (!uwsgi_strncmp("METHOD", 6, key, keylen)) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, val, vallen);
}
else if (!uwsgi_strncmp("VERSION", 7, key, keylen)) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, val, vallen);
}
else if (!uwsgi_strncmp("QUERY", 5, key, keylen)) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, val, vallen);
query_string = val;
query_string_len = vallen;
}
else if (!uwsgi_strncmp("PATTERN", 7, key, keylen)) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, val, vallen - 1);
script_name_len = vallen - 1;
}
else if (!uwsgi_strncmp("PATH", 4, key, keylen)) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, val + script_name_len, vallen - script_name_len);
if (query_string_len) {
char *request_uri = uwsgi_concat3n(val, vallen, "?", 1, query_string, query_string_len);
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, vallen + 1 + query_string_len);
free(request_uri);
}
else {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen);
}
}
}
else {
// add header
if (!uwsgi_strncmp("host", 4, key, keylen)) {
char *colon = strchr(val, ':');
if (colon) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, (colon + 1) - val);
}
else {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
}
}
else if (!uwsgi_strncmp("content-length", 14, key, keylen)) {
wsgi_req->post_cl = uwsgi_str_num(val, vallen);
}
else if (!uwsgi_strncmp("x-mongrel2-upload-done", 22, key, keylen)) {
char *post_filename = uwsgi_concat2n(val, vallen, "", 0);
wsgi_req->async_post = fopen(post_filename, "r");
if (!wsgi_req->async_post) {
uwsgi_error_open(post_filename);
free(post_filename);
wsgi_req->do_not_log = 1;
}
async_upload += 2;
free(post_filename);
}
else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) {
async_upload += 1;
}
wsgi_req->uh.pktsize += proto_base_add_uwsgi_header(wsgi_req, key, keylen, val, vallen);
}
}
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
// reject uncomplete upload
if (async_upload == 1) {
return -1;
}
return 0;
}
int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
zmq_msg_t message;
char *req_uuid = NULL;
size_t req_uuid_len = 0;
char *req_id = NULL;
size_t req_id_len = 0;
char *req_path = NULL;
size_t req_path_len = 0;
#ifdef UWSGI_JSON
json_t *root;
json_error_t error;
#endif
char *mongrel2_req = NULL;
size_t mongrel2_req_size = 0;
int resp_id_len;
uint32_t events = 0;
char *message_ptr;
size_t message_size = 0;
char *post_data;
#ifdef ZMQ_EVENTS
size_t events_len = sizeof(uint32_t);
if (uwsgi.edge_triggered == 0) {
if (zmq_getsockopt(pthread_getspecific(uwsgi.zmq_pull), ZMQ_EVENTS, &events, &events_len) < 0) {
uwsgi_error("zmq_getsockopt()");
uwsgi.edge_triggered = 0;
return -1;
}
}
#endif
if (events & ZMQ_POLLIN || uwsgi.edge_triggered) {
wsgi_req->do_not_add_to_async_queue = 1;
wsgi_req->proto_parser_status = 0;
zmq_msg_init(&message);
if (zmq_recv(pthread_getspecific(uwsgi.zmq_pull), &message, uwsgi.zeromq_recv_flag) < 0) {
if (errno == EAGAIN) {
uwsgi.edge_triggered = 0;
}
else {
uwsgi_error("zmq_recv()");
}
zmq_msg_close(&message);
return -1;
}
uwsgi.edge_triggered = 1;
message_size = zmq_msg_size(&message);
//uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message));
if (message_size > 0xffff) {
uwsgi_log("too much big message %d\n", message_size);
zmq_msg_close(&message);
wsgi_req->do_not_log = 1;
return -1;
}
message_ptr = zmq_msg_data(&message);
// warning mongrel2_req_size will contains a bad value, but this is not a problem...
post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size);
if (post_data == NULL) {
uwsgi_log("cannot parse message (split4 phase)\n");
zmq_msg_close(&message);
wsgi_req->do_not_log = 1;
return -1;
}
// fix post_data, mongrel2_req and mongrel2_req_size
post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size);
if (post_data == NULL) {
uwsgi_log("cannot parse message (body netstring phase)\n");
zmq_msg_close(&message);
wsgi_req->do_not_log = 1;
return -1;
}
// ok ready to parse tnetstring/json data and build uwsgi request
if (mongrel2_req[mongrel2_req_size] == '}') {
if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) {
zmq_msg_close(&message);
wsgi_req->do_not_log = 1;
return -1;
}
}
else {
#ifdef UWSGI_JSON
#ifdef UWSGI_DEBUG
uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req);
#endif
// add a zero to the end of buf
mongrel2_req[mongrel2_req_size] = 0;
root = json_loads(mongrel2_req, 0, &error);
if (!root) {
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
zmq_msg_close(&message);
wsgi_req->do_not_log = 1;
return -1;
}
if (uwsgi_mongrel2_json_parse(root, wsgi_req)) {
json_decref(root);
zmq_msg_close(&message);
wsgi_req->do_not_log = 1;
return -1;
}
json_decref(root);
#else
uwsgi_log("JSON support not enabled. skip request\n");
#endif
}
// pre-build the mongrel2 response_header
wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1);
memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len);
((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' ';
resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1);
((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':';
memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len);
memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2);
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
// handle post data
if (wsgi_req->post_cl > 0 && !wsgi_req->async_post) {
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
#ifdef UWSGI_DEBUG
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
#endif
wsgi_req->async_post = tmpfile();
fwrite(message_ptr, wsgi_req->post_cl, 1, wsgi_req->async_post);
rewind(wsgi_req->async_post);
wsgi_req->body_as_file = 1;
}
}
zmq_msg_close(&message);
return 0;
}
return -1;
}
static void uwsgi_proto_zeromq_free(void *data, void *hint) {
free(data);
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
zmq_msg_t reply;
// check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos
if (!wsgi_req->proto_parser_pos)
return;
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, uwsgi_proto_zeromq_free, NULL);
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.zmq_lock);
if (zmq_send(uwsgi.zmq_pub, &reply, 0)) {
uwsgi_error("zmq_send()");
}
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock);
zmq_msg_close(&reply);
if (wsgi_req->async_post && wsgi_req->body_as_file) {
fclose(wsgi_req->async_post);
}
}
ssize_t uwsgi_proto_zeromq_writev_header(struct wsgi_request *wsgi_req, struct iovec *iovec, size_t iov_len) {
int i;
ssize_t len;
ssize_t ret = 0;
for (i = 0; i < (int) iov_len; i++) {
len = uwsgi_proto_zeromq_write(wsgi_req, iovec[i].iov_base, iovec[i].iov_len);
if (len <= 0) {
return len;
}
ret += len;
}
return ret;
}
ssize_t uwsgi_proto_zeromq_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
return uwsgi_proto_zeromq_writev_header(wsgi_req, iovec, iov_len);
}
ssize_t uwsgi_proto_zeromq_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
zmq_msg_t reply;
char *zmq_body;
if (len == 0)
return 0;
zmq_body = uwsgi_concat2n(wsgi_req->proto_parser_buf, (int) wsgi_req->proto_parser_pos, buf, (int) len);
//uwsgi_log("|%.*s|\n", (int)wsgi_req->proto_parser_pos+len, zmq_body);
zmq_msg_init_data(&reply, zmq_body, wsgi_req->proto_parser_pos + len, uwsgi_proto_zeromq_free, NULL);
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.zmq_lock);
if (zmq_send(uwsgi.zmq_pub, &reply, 0)) {
uwsgi_error("zmq_send()");
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock);
zmq_msg_close(&reply);
return -1;
}
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock);
zmq_msg_close(&reply);
return len;
}
ssize_t uwsgi_proto_zeromq_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
return uwsgi_proto_zeromq_write(wsgi_req, buf, len);
}
ssize_t uwsgi_proto_zeromq_sendfile(struct wsgi_request * wsgi_req) {
ssize_t len;
char buf[65536];
size_t remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
wsgi_req->sendfile_fd_chunk = 65536;
if (uwsgi.async > 1) {
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
return uwsgi_proto_zeromq_write(wsgi_req, buf, len);
}
while (remains) {
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
len = uwsgi_proto_zeromq_write(wsgi_req, buf, len);
remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
}
return wsgi_req->sendfile_fd_pos;
}
+85 -155
View File
@@ -339,141 +339,30 @@ ssize_t uwsgi_send_message(int fd, uint8_t modifier1, uint8_t modifier2, char *m
}
int uwsgi_parse_response(struct pollfd *upoll, int timeout, struct uwsgi_header *uh, char *buffer) {
int rlen, i;
struct msghdr msg;
struct iovec iov [1];
struct cmsghdr *cmsg;
union {
struct cmsghdr cmsg;
char control [CMSG_SPACE (sizeof (int))];
} msg_control;
int uwsgi_parse_response(struct pollfd *upoll, int timeout, struct uwsgi_header *uh, char *buffer, int (*socket_proto)(struct wsgi_request *)) {
int rlen;
int status = UWSGI_AGAIN;
if (!timeout)
timeout = 1;
/* first 4 byte header */
rlen = poll(upoll, 1, timeout * 1000);
if (rlen < 0) {
uwsgi_error("poll()");
exit(1);
}
else if (rlen == 0) {
uwsgi_log( "timeout. skip request\n");
close(upoll->fd);
return 0;
}
iov [0].iov_base = uh;
iov [0].iov_len = 4;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = &msg_control;
msg.msg_controllen = sizeof (msg_control);
msg.msg_flags = 0;
//rlen = read(upoll->fd, uh, 4);
rlen = recvmsg(upoll->fd, &msg, 0);
if (rlen > 0 && rlen < 4) {
i = rlen;
while (i < 4) {
rlen = poll(upoll, 1, timeout * 1000);
if (rlen < 0) {
uwsgi_error("poll()");
exit(1);
}
else if (rlen == 0) {
uwsgi_log( "timeout waiting for header. skip request.\n");
close(upoll->fd);
break;
}
rlen = read(upoll->fd, (char *) (uh) + i, 4 - i);
if (rlen <= 0) {
uwsgi_log( "broken header. skip request.\n");
close(upoll->fd);
break;
}
i += rlen;
}
if (i < 4) {
return 0;
}
}
else if (rlen <= 0) {
uwsgi_log( "invalid request header size: %d...skip\n", rlen);
close(upoll->fd);
return 0;
}
/* big endian ? */
#ifdef __BIG_ENDIAN__
uh->pktsize = uwsgi_swap16(uh->pktsize);
#endif
#ifdef UWSGI_DEBUG
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", uh->pktsize, uh->pktsize, uh->modifier1, uh->modifier2);
#endif
/* check for max buffer size */
if (uh->pktsize > uwsgi.buffer_size) {
uwsgi_log( "invalid request block size: %d...skip\n", uh->pktsize);
close(upoll->fd);
return 0;
}
//uwsgi_log("ready for reading %d bytes\n", wsgi_req.size);
i = 0;
while (i < uh->pktsize) {
while(status == UWSGI_AGAIN) {
rlen = poll(upoll, 1, timeout * 1000);
if (rlen < 0) {
uwsgi_error("poll()");
exit(1);
}
else if (rlen == 0) {
uwsgi_log( "timeout. skip request. (expecting %d bytes, got %d)\n", uh->pktsize, i);
close(upoll->fd);
break;
uwsgi_log( "timeout waiting for header. skip request.\n");
//close(upoll->fd);
return 0;
}
rlen = read(upoll->fd, buffer + i, uh->pktsize - i);
if (rlen <= 0) {
uwsgi_log( "broken vars. skip request.\n");
close(upoll->fd);
break;
status = socket_proto((struct wsgi_request *) uh);
if (status < 0) {
uwsgi_log("error parsing request\n");
//close(upoll->fd);
return 0;
}
i += rlen;
}
if (i < uh->pktsize) {
return 0;
}
// older OSX versions make mess with CMSG_FIRSTHDR
#ifdef __APPLE__
if (!msg.msg_controllen) return 1;
#endif
cmsg = CMSG_FIRSTHDR (&msg);
while(cmsg != NULL) {
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type && SCM_RIGHTS) {
// upgrade connection to the new socket
#ifdef UWSGI_DEBUG
uwsgi_log("upgrading fd %d to ", upoll->fd);
#endif
close(upoll->fd);
memcpy(&upoll->fd, CMSG_DATA(cmsg), sizeof(int));
#ifdef UWSGI_DEBUG
uwsgi_log("%d\n", upoll->fd);
#endif
}
cmsg = CMSG_NXTHDR (&msg, cmsg);
}
return 1;
@@ -705,28 +594,47 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
ptrbuf += strsize;
}
else {
uwsgi_log("Invalid uwsgi request. skip.\n");
uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
return -1;
}
}
else {
uwsgi_log("Invalid uwsgi request. skip.\n");
uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
return -1;
}
}
}
else {
uwsgi_log("Invalid uwsgi request. skip.\n");
uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
return -1;
}
}
if (uwsgi.post_buffering > 0 && !wsgi_req->body_as_file && !wsgi_req->async_post) {
// read to disk if post_cl > post_buffering (it will eventually do upload progress...)
if (wsgi_req->post_cl >= (size_t) uwsgi.post_buffering) {
if (!uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize)) {
wsgi_req->status = -1;
return -1;
}
wsgi_req->body_as_file = 1;
}
// on tiny post use memory
else {
if (!uwsgi_read_whole_body_in_mem(wsgi_req, wsgi_req->post_buffering_buf)) {
wsgi_req->status = -1;
return -1;
}
}
}
// check if data are available in the local cache
if (wsgi_req->cache_get_len > 0) {
uint64_t cache_value_size;
char *cache_value = uwsgi_cache_get(wsgi_req->cache_get, wsgi_req->cache_get_len, &cache_value_size);
if (cache_value && cache_value_size > 0) {
wsgi_req->response_size = write(wsgi_req->poll.fd, cache_value, cache_value_size);
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, cache_value, cache_value_size);
wsgi_req->status = -1;
return -1;
}
@@ -738,7 +646,7 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
uint64_t cache_value_size;
char *cache_value = uwsgi_cache_get(wsgi_req->uri, wsgi_req->uri_len, &cache_value_size);
if (cache_value && cache_value_size > 0) {
wsgi_req->response_size = write(wsgi_req->poll.fd, cache_value, cache_value_size);
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, cache_value, cache_value_size);
wsgi_req->status = -1;
return -1;
}
@@ -788,7 +696,7 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
// check if a file named uwsgi.check_static+env['PATH_INFO'] exists
if (uwsgi.check_static && wsgi_req->path_info_len > 1) {
if (!uwsgi_file_serve(wsgi_req, uwsgi.check_static, uwsgi.check_static_len, wsgi_req->path_info, wsgi_req->path_info_len)) {
if (!uwsgi_file_serve(wsgi_req, uwsgi.check_static, uwsgi.check_static_len, wsgi_req->path_info, wsgi_req->path_info_len, uwsgi.check_static, uwsgi.check_static_len)) {
return -1;
}
}
@@ -799,8 +707,9 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_DEBUG
uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, usm->mountpoint_len, usm->mountpoint);
#endif
if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, usm->mountpoint, usm->mountpoint_len)) {
if (!uwsgi_file_serve(wsgi_req, usm->document_root, usm->document_root_len, wsgi_req->path_info+usm->mountpoint_len, wsgi_req->path_info_len-usm->mountpoint_len)) {
if (!uwsgi_file_serve(wsgi_req, usm->document_root, usm->document_root_len, wsgi_req->path_info+usm->mountpoint_len, wsgi_req->path_info_len-usm->mountpoint_len, usm->orig_document_root, usm->orig_document_root_len)) {
return -1;
}
}
@@ -845,7 +754,7 @@ int uwsgi_ping_node(int node, struct wsgi_request *wsgi_req) {
}
uwsgi_poll.events = POLLIN;
if (!uwsgi_parse_response(&uwsgi_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) wsgi_req, wsgi_req->buffer)) {
if (!uwsgi_parse_response(&uwsgi_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) wsgi_req, wsgi_req->buffer, uwsgi_proto_uwsgi_parser)) {
return -1;
}
@@ -1117,8 +1026,8 @@ ssize_t fcgi_send_param(int fd, char *key, uint16_t keylen, char *val, uint16_t
fr.type = 4;
fr.req1 = 0;
fr.req0 = 1;
fr.cl1 = (uint8_t) ((size >> 8) & 0xff);
fr.cl0 = (uint8_t) (size &0xff);
fr.cl8.cl1 = (uint8_t) ((size >> 8) & 0xff);
fr.cl8.cl0 = (uint8_t) (size &0xff);
fr.pad = 0;
fr.reserved = 0;
@@ -1138,8 +1047,8 @@ ssize_t fcgi_send_record(int fd, uint8_t type, uint16_t size, char *buffer) {
fr.type = type;
fr.req1 = 0;
fr.req0 = 1;
fr.cl1 = (uint8_t) ((size >> 8) & 0xff);
fr.cl0 = (uint8_t) (size &0xff);
fr.cl8.cl1 = (uint8_t) ((size >> 8) & 0xff);
fr.cl8.cl0 = (uint8_t) (size &0xff);
fr.pad = 0;
fr.reserved = 0;
@@ -1159,7 +1068,6 @@ uint16_t fcgi_get_record(int fd, char *buf) {
uint16_t remains = 8;
char *ptr = (char *) &fr;
ssize_t len;
uint16_t rs;
while(remains) {
uwsgi_waitfd(fd, -1);
@@ -1169,9 +1077,7 @@ uint16_t fcgi_get_record(int fd, char *buf) {
ptr += len;
}
rs = (uint16_t) fr.cl1;
remains = ntohs(rs) + fr.pad;
remains = ntohs(fr.cl) + fr.pad;
ptr = buf;
while(remains) {
@@ -1184,7 +1090,7 @@ uint16_t fcgi_get_record(int fd, char *buf) {
if (fr.type != 6) return 0;
return ntohs(rs);
return ntohs(fr.cl);
}
@@ -1210,7 +1116,7 @@ char *uwsgi_simple_message_string(char *socket_name, uint8_t modifier1, uint8_t
upoll.events = POLLIN;
if (buffer) {
if (!uwsgi_parse_response(&upoll, timeout, &uh, buffer)) {
if (!uwsgi_parse_response(&upoll, timeout, &uh, buffer, uwsgi_proto_uwsgi_parser)) {
close(fd);
if (response_len) *response_len = 0;
return NULL;
@@ -1308,7 +1214,7 @@ int uwsgi_simple_send_string(char *socket_name, uint8_t modifier1, uint8_t modif
}
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len) {
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, char *orig_document_root, uint16_t orig_document_root_len) {
struct stat st;
char real_filename[PATH_MAX];
@@ -1335,8 +1241,17 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
if (st.st_mtime <= ims) {
wsgi_req->status = 304;
wsgi_req->headers_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, " 304 Not Modified\r\n\r\n", 21);
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, " 304 Not Modified\r\n", 19);
struct uwsgi_string_list *ah = uwsgi.additional_headers;
while(ah) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, ah->value, ah->len);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
ah = ah->next;
}
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
return 0;
}
}
@@ -1347,29 +1262,44 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
#endif
// no need to set content-type/content-length, they will be fixed by the http server/router
wsgi_req->headers_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, " 200 OK\r\n", 9);
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, " 200 OK\r\n", 9);
struct uwsgi_string_list *ah = uwsgi.additional_headers;
while(ah) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, ah->value, ah->len);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
ah = ah->next;
}
if (uwsgi.file_serve_mode == 1) {
wsgi_req->header_cnt = 2;
wsgi_req->headers_size += write(wsgi_req->poll.fd, "X-Accel-Redirect: ", 18);
wsgi_req->headers_size += write(wsgi_req->poll.fd, path_info, path_info_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "X-Accel-Redirect: ", 18);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, orig_document_root, orig_document_root_len);
if (orig_document_root[orig_document_root_len-1] != '/') {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "/", 1);
}
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, path_info, path_info_len);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
}
else if (uwsgi.file_serve_mode == 2) {
wsgi_req->header_cnt = 2;
wsgi_req->headers_size += write(wsgi_req->poll.fd, "X-Sendfile: ", 12);
wsgi_req->headers_size += write(wsgi_req->poll.fd, real_filename, strlen(real_filename));
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "X-Sendfile: ", 12);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, orig_document_root, orig_document_root_len);
if (orig_document_root[orig_document_root_len-1] != '/') {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "/", 1);
}
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, path_info, path_info_len);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
}
else {
wsgi_req->header_cnt = 1;
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
wsgi_req->sendfile_fd = open(real_filename, O_RDONLY);
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
}
+59
View File
@@ -2,6 +2,65 @@
extern struct uwsgi_server uwsgi;
void uwsgi_init_queue() {
if (!uwsgi.queue_blocksize)
uwsgi.queue_blocksize = 8192;
if (uwsgi.queue_blocksize % uwsgi.page_size != 0) {
uwsgi_log("invalid queue blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size);
exit(1);
}
uwsgi.shared->queue_pos = 0;
uwsgi.shared->queue_pull_pos = 0;
if (uwsgi.queue_store) {
uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size;
int queue_fd;
struct stat qst;
if (stat(uwsgi.queue_store, &qst)) {
uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store);
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (queue_fd >= 0) {
// fill the queue store
if (ftruncate(queue_fd, uwsgi.queue_filesize)) {
uwsgi_log("ftruncate()");
exit(1);
}
}
}
else {
if ((size_t) qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) {
uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n");
exit(1);
}
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store);
}
if (queue_fd < 0) {
uwsgi_error_open(uwsgi.queue_store);
exit(1);
}
uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
uwsgi_queue_fix();
}
else {
uwsgi.queue = mmap(NULL, uwsgi.queue_blocksize * uwsgi.queue_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
}
if (!uwsgi.queue) {
uwsgi_error("mmap()");
exit(1);
}
uwsgi.queue_lock = uwsgi_mmap_shared_rwlock();
uwsgi_rwlock_init(uwsgi.queue_lock);
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
}
char *uwsgi_queue_get(uint64_t index, uint64_t *size) {
struct uwsgi_queue_item *uqi;
+7 -1
View File
@@ -25,7 +25,13 @@ ssize_t uwsgi_sendfile(struct wsgi_request *wsgi_req) {
if (wsgi_req->sendfile_fd_size) {
if (!wsgi_req->sendfile_fd_chunk) wsgi_req->sendfile_fd_chunk = 4096;
sst = uwsgi_do_sendfile(sockfd, wsgi_req->sendfile_fd, wsgi_req->sendfile_fd_size, wsgi_req->sendfile_fd_chunk, &wsgi_req->sendfile_fd_pos, uwsgi.async);
if (wsgi_req->socket->proto_sendfile) {
sst = wsgi_req->socket->proto_sendfile(wsgi_req);
}
else {
sst = uwsgi_do_sendfile(sockfd, wsgi_req->sendfile_fd, wsgi_req->sendfile_fd_size, wsgi_req->sendfile_fd_chunk, &wsgi_req->sendfile_fd_pos, uwsgi.async);
}
}
+1 -1
View File
@@ -51,7 +51,7 @@ class uWSGIDistribution(Distribution):
setup(name='uWSGI',
version='0.9.7.2',
version=uc.uwsgi_version,
description='The uWSGI server',
author='Unbit',
author_email='info@unbit.it',
+634 -343
View File
File diff suppressed because it is too large Load Diff
+9 -5
View File
@@ -4,17 +4,17 @@
extern struct uwsgi_server uwsgi;
pid_t spooler_start() {
int i;
pid_t pid;
pid = fork();
pid_t pid = fork();
if (pid < 0) {
uwsgi_error("fork()");
exit(1);
}
else if (pid == 0) {
for (i = 0; i < uwsgi.sockets_cnt; i++) {
close(uwsgi.sockets[i].fd);
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
close(uwsgi_sock->fd);
uwsgi_sock = uwsgi_sock->next;
}
spooler();
}
@@ -126,10 +126,14 @@ void spooler() {
// asked by Marco Beri
#ifdef __HAIKU__
#ifdef UWSGI_DEBUG
uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY);
#endif
set_thread_priority(find_thread(NULL), B_LOW_PRIORITY);
#else
#ifdef UWSGI_DEBUG
uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX);
#endif
setpriority(PRIO_PROCESS, getpid(), PRIO_MAX);
#endif
+56
View File
@@ -0,0 +1,56 @@
#ifdef UWSGI_SQLITE3
#include "uwsgi.h"
#include <sqlite3.h>
extern struct uwsgi_server uwsgi;
static int uwsgi_sqlite3_config_callback(void *foo, int field_count, char **fields, char **col) {
// make a copy of the string
if (field_count >= 2) {
add_exported_option( uwsgi_strncopy(fields[0], strlen(fields[0])), uwsgi_strncopy(fields[1], strlen(fields[1])), 0);
}
return 0;
}
void uwsgi_sqlite3_config(char *file) {
sqlite3 *db;
char *err = NULL;
char *query = "SELECT * FROM uwsgi";
char *colon = uwsgi_get_last_char(file, ':');
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
query = colon+1;
}
}
uwsgi_log("[uWSGI] getting sqlite3 configuration from %s\n", file);
#ifdef sqlite3_open_v2
if (sqlite3_open_v2(file, &db, SQLITE_OPEN_READONLY, NULL)) {
#else
if (sqlite3_open(file, &db)) {
#endif
uwsgi_log("unable to open sqlite3 db: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
if (sqlite3_exec(db, query, uwsgi_sqlite3_config_callback, 0, &err)) {
uwsgi_log("sqlite3 error: %s\n", err);
sqlite3_close(db);
exit(1);
}
sqlite3_close(db);
}
#endif
+56
View File
@@ -0,0 +1,56 @@
package Responder;
sub new {
my $class = shift;
my $self = {
_env => shift,
_counter => 0,
_fd => -1,
};
bless $self, $class;
return $self;
}
sub getline {
my $self = shift;
if ($self->{_counter} > 10) {
return undef;
}
elsif ($self->{_counter} == 3) {
$self->{_counter}++;
$self->{_fd} = uwsgi::async_connect("81.174.68.52:80");
return uwsgi::wait_fd_write($self->{_fd}, 3);
}
elsif ($self->{_counter} == 4) {
$self->{_counter}++;
return "connected to http://projects.unbit.it<br/>";
}
elsif ($self->{_counter} == 7) {
$self->{_counter}++;
print "suspending the app...\n";
uwsgi::async_sleep(3);
uwsgi::suspend();
print "resumed the app\n";
return "Suspended and Resumed the app<br/>";
}
elsif ($self->{_counter} % 2 == 0) {
$self->{_counter}++;
print "sleeping...\n";
return uwsgi::async_sleep(1);
}
else {
$self->{_counter}++;
return "Hello World ".$self->{_counter}."<br/>";
}
}
sub close {
my $self = shift;
uwsgi::log("goodbye...\n");
}
1
+23
View File
@@ -0,0 +1,23 @@
sub streamer {
my $responder = shift;
my $writer = $responder->([ 200, [ 'Content-Type', 'text/html' ]]);
my @chunks = ('One', 'Two', 'Three');
foreach(@chunks) {
uwsgi::async_sleep(1);
# something like $env->{'psgix.suspend'}(); ???
uwsgi::suspend();
$writer->write($_."<br/>");
}
$writer->close;
}
my $app = sub {
my $env = shift;
return \&streamer;
};
+14 -23
View File
@@ -1,32 +1,23 @@
import uwsgi
def ciao():
uwsgi.start_response('200 OK', [ ('Content-type', 'text/plain') ])
uwsgi.send(str(22+30))
def application(env, start_response):
start_response('200 Ok', [('Content-type', 'text/html')])
if env['REQUEST_METHOD'] == 'POST':
print "getting file..."
remains = int(env['CONTENT_LENGTH'])
print remains
buf = ''
while remains > 0:
if remains < 8192:
buf = env['wsgi.input'].read(remains)
else:
buf = env['wsgi.input'].read(8192)
#print len(buf)
remains = remains - len(buf)
#print "remains",remains
print "upload ready"
yield env['CONTENT_LENGTH']
start_response('200 Ok', [('Content-type', 'text/plain')])
#for x in env['wsgi.input']:
# yield x
body = env['wsgi.input'].readline()
print body
body += env['wsgi.input'].read(100)
body += env['wsgi.input'].read(100)
body += env['wsgi.input'].read()
return body
else:
yield """
start_response('200 Ok', [('Content-type', 'text/html')])
return """
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<textarea name="pluto">
</textarea>
<input type="test" name="pippo" />
<input type="submit" value="invia" />
</form>
"""
+854 -393
View File
File diff suppressed because it is too large Load Diff
+1963 -1716
View File
File diff suppressed because it is too large Load Diff
+302 -45
View File
@@ -2,20 +2,21 @@
/* indent -i8 -br -brs -brf -l0 -npsl -nip -npcs -npsl -di1 */
#define UWSGI_VERSION "0.9.7.2"
#define UMAX16 65536
#define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
#define uwsgi_fatal_error(x) uwsgi_error(x); exit(1);
#define uwsgi_error_open(x) uwsgi_log("open(\"%s\"): %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
#define uwsgi_debug(x, ...) uwsgi_log("[uWSGI DEBUG] " x, __VA_ARGS__);
#define uwsgi_rawlog(x) if (write(2, x, strlen(x)) != strlen(x)) uwsgi_error("write()")
#define uwsgi_notify(x) if (uwsgi.notify) uwsgi.notify(x)
#define uwsgi_notify_ready() if (uwsgi.notify_ready) uwsgi.notify_ready()
#define wsgi_req_time ((wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec) - (wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec))/1000
#define ushared uwsgi.shared
#define MAX_SOCKETS 8
#define MAX_APPS 64
#define MAX_GENERIC_PLUGINS 64
#define MAX_RPC 64
@@ -67,8 +68,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <math.h>
#include <netinet/in.h>
#ifdef UWSGI_UUID
#include <uuid/uuid.h>
#endif
#ifdef __sun__
#define _XPG4_2
#define __EXTENSIONS__
@@ -88,7 +94,9 @@
#include <syslog.h>
#ifdef UWSGI_HAS_IFADDRS
#include <ifaddrs.h>
#endif
#include <dirent.h>
@@ -174,8 +182,6 @@ extern int pivot_root(const char * new_root, const char * put_old);
#define WAIT_ANY (-1)
#endif
#define MAX_PYARGV 10
#include <sys/ioctl.h>
#ifdef __linux__
@@ -198,6 +204,10 @@ extern int pivot_root(const char * new_root, const char * put_old);
#undef __EXTENSIONS__
#endif
#ifdef UWSGI_ZEROMQ
#include <zmq.h>
#endif
/* this value are taken from nginx */
#if defined(__APPLE__) || defined(__freebsd__)
#define UWSGI_LISTEN_QUEUE -1
@@ -210,12 +220,18 @@ extern int pivot_root(const char * new_root, const char * put_old);
#define uwsgi_cache_update_start(x, y, z) uwsgi_cache_set(x, y, "", 0, CACHE_FLAG_UNGETTABLE)
struct uwsgi_help_item {
char *key;
char *value;
};
struct uwsgi_config_template {
char *filename;
struct uwsgi_config_template *next;
};
struct uwsgi_static_map {
char *mountpoint;
@@ -224,9 +240,19 @@ struct uwsgi_static_map {
char *document_root;
int document_root_len;
char *orig_document_root;
int orig_document_root_len;
struct uwsgi_static_map *next;
};
struct uwsgi_string_list {
char *value;
size_t len;
struct uwsgi_string_list *next;
};
union uwsgi_sockaddr {
struct sockaddr sa;
@@ -396,6 +422,21 @@ struct uwsgi_opt {
#define LONG_ARGS_RELOAD_ON_AS 17093
#define LONG_ARGS_RELOAD_ON_RSS 17094
#define LONG_ARGS_TOUCH_RELOAD 17095
#define LONG_ARGS_EMPEROR_AMQP_VHOST 17096
#define LONG_ARGS_EMPEROR_AMQP_USERNAME 17097
#define LONG_ARGS_EMPEROR_AMQP_PASSWORD 17098
#define LONG_ARGS_PROTOCOL 17099
#define LONG_ARGS_ZEROMQ 17100
#define LONG_ARGS_INHERIT 17101
#define LONG_ARGS_VASSALS_INHERIT 17102
#define LONG_ARGS_SOCKET_PROTOCOL 17103
#define LONG_ARGS_LOG_ZEROMQ 17104
#define LONG_ARGS_PROFILER 17105
#define LONG_ARGS_SQLITE3 17106
#define LONG_ARGS_AUTO_SNAPSHOT 17107
#define LONG_ARGS_LOG_SOCKET 17108
#define LONG_ARGS_ADD_HEADER 17109
#define LONG_ARGS_IDLE 17120
#define UWSGI_OK 0
@@ -403,23 +444,6 @@ struct uwsgi_opt {
#define UWSGI_ACCEPTING 2
#define UWSGI_PAUSED 3
#define UWSGI_CLEAR_STATUS uwsgi.workers[uwsgi.mywid].status = 0
#define UWSGI_STATUS_IN_REQUEST 1 << 0
#define UWSGI_IS_IN_REQUEST uwsgi.workers[uwsgi.mywid].status & UWSGI_STATUS_IN_REQUEST
#define UWSGI_SET_IN_REQUEST uwsgi.workers[uwsgi.mywid].status |= UWSGI_STATUS_IN_REQUEST
#define UWSGI_UNSET_IN_REQUEST uwsgi.workers[uwsgi.mywid].status ^= UWSGI_STATUS_IN_REQUEST
#define UWSGI_STATUS_BLOCKING 1 << 1
#define UWSGI_IS_BLOCKING uwsgi.workers[uwsgi.mywid].status & UWSGI_STATUS_BLOCKING
#define UWSGI_SET_BLOCKING uwsgi.workers[uwsgi.mywid].status |= UWSGI_STATUS_BLOCKING
#define UWSGI_UNSET_BLOCKING uwsgi.workers[uwsgi.mywid].status ^= UWSGI_STATUS_BLOCKING
#define UWSGI_STATUS_LOCKING 1 << 2
#define UWSGI_IS_LOCKING uwsgi.workers[uwsgi.mywid].status & UWSGI_STATUS_LOCKING
#define UWSGI_SET_LOCKING uwsgi.workers[uwsgi.mywid].status |= UWSGI_STATUS_LOCKING
#define UWSGI_UNSET_LOCKING uwsgi.workers[uwsgi.mywid].status ^= UWSGI_STATUS_LOCKING
#ifdef __linux__
#include <endian.h>
#elif __sun__
@@ -479,6 +503,8 @@ struct uwsgi_loop {
void (*loop) (void);
};
struct wsgi_request;
struct uwsgi_socket {
int fd;
char *name;
@@ -487,9 +513,24 @@ struct uwsgi_socket {
int bound;
int arg;
void *ctx;
char *proto_name;
int (*proto)(struct wsgi_request *);
int (*proto_accept)(struct wsgi_request *, int);
ssize_t (*proto_write)(struct wsgi_request *, char *, size_t);
ssize_t (*proto_writev)(struct wsgi_request *, struct iovec *, size_t);
ssize_t (*proto_write_header)(struct wsgi_request *, char *, size_t);
ssize_t (*proto_writev_header)(struct wsgi_request *, struct iovec *, size_t);
ssize_t (*proto_sendfile)(struct wsgi_request *);
void (*proto_close)(struct wsgi_request *);
int edge_trigger;
int disabled;
struct uwsgi_socket *next;
};
struct wsgi_request;
struct uwsgi_server;
struct uwsgi_plugin {
@@ -509,6 +550,7 @@ struct uwsgi_plugin {
int (*request) (struct wsgi_request *);
void (*after_request) (struct wsgi_request *);
void (*init_apps) (void);
void (*fixup) (void);
int (*mount_app) (char *, char *);
int (*manage_udp) (char *, int, char *, int);
int (*manage_xml) (char *, char *);
@@ -624,6 +666,12 @@ struct wsgi_request {
//iovec
struct iovec *hvec;
struct msghdr msg;
union {
struct cmsghdr cmsg;
char control [CMSG_SPACE (sizeof (int))];
} msg_control;
struct timeval start_of_request;
struct timeval end_of_request;
@@ -690,6 +738,10 @@ struct wsgi_request {
uint16_t var_cnt;
uint16_t header_cnt;
int do_not_log;
int do_not_add_to_async_queue;
int status;
size_t response_size;
ssize_t headers_size;
@@ -711,19 +763,31 @@ struct wsgi_request {
void *async_args;
void *async_environ;
void *async_post;
void *async_input;
void *async_sendfile;
int async_force_again;
int async_plagued;
int suspended;
int *ovector;
size_t post_cl;
off_t post_pos;
char *post_buffering_buf;
uint64_t post_buffering_read;
// current socket mapped to request
struct uwsgi_socket *socket;
int body_as_file;
//for generic use
off_t buf_pos;
size_t buf_pos;
uint64_t proto_parser_pos;
int proto_parser_status;
void *proto_parser_buf;
char *buffer;
@@ -772,14 +836,38 @@ struct uwsgi_server {
int apps_cnt;
int default_app;
int autoload;
int snapshot;
int auto_snapshot;
pid_t restore_snapshot;
int respawn_workers;
unsigned int reloads;
int master_as_root;
int die_on_term;
int no_fd_passing;
time_t current_time;
uint64_t master_cycles;
int lazy;
int cheap;
int idle;
int has_emperor;
int emperor_fd;
int emperor_fd_config;
char *emperor_dir;
pid_t emperor_pid;
struct uwsgi_config_template *vassals_templates;
int loyal;
char *emperor_amqp_vhost;
char *emperor_amqp_username;
char *emperor_amqp_password;
struct uwsgi_string_list *additional_headers;
time_t master_mercy;
@@ -805,6 +893,7 @@ struct uwsgi_server {
char *uidname;
char *gidname;
char *profiler;
char *mode;
char *worker_exec;
@@ -821,6 +910,12 @@ struct uwsgi_server {
int log_master;
int log_syslog;
int log_socket;
int log_socket_fd;
union uwsgi_sockaddr *log_socket_addr;
socklen_t log_socket_size;
char *check_static;
size_t check_static_len;
int file_serve_mode;
@@ -838,6 +933,7 @@ struct uwsgi_server {
char **async_post_buf;
struct wsgi_request **async_waiting_fd_table;
struct wsgi_request **async_proto_fd_table;
struct uwsgi_async_request *async_runqueue;
struct uwsgi_async_request *async_runqueue_last;
int async_runqueue_cnt;
@@ -908,12 +1004,16 @@ struct uwsgi_server {
int harakiri_verbose;
int main_queue;
int numproc;
int async;
int async_running;
int async_queue;
int async_nevents;
int edge_triggered;
int max_vars;
int vec_size;
@@ -921,6 +1021,11 @@ struct uwsgi_server {
void *sharedareamutex;
int sharedareasize;
#ifdef UWSGI_THREADING
pthread_mutex_t six_feet_under_lock;
#endif
/* the list of workers */
struct uwsgi_worker *workers;
@@ -956,10 +1061,20 @@ struct uwsgi_server {
char *yaml;
#endif
#ifdef UWSGI_JSON
char *json;
#endif
#ifdef UWSGI_INI
char *ini;
#endif
#ifdef UWSGI_SQLITE3
char *sqlite3;
#endif
struct uwsgi_config_template *config_templates;
int single_interpreter;
struct uwsgi_shared *shared;
@@ -995,16 +1110,28 @@ struct uwsgi_server {
char *ns;
char *ns_net;
#endif
char *protocol;
int sockets_cnt;
struct uwsgi_socket sockets[MAX_SOCKETS];
// leave a slot for no-orphan mode
struct pollfd sockets_poll[9];
int signal_socket;
int shared_sockets_cnt;
struct uwsgi_socket shared_sockets[MAX_SOCKETS];
#ifdef UWSGI_ZEROMQ
char *zeromq;
char *zmq_receiver;
char *zmq_responder;
struct uwsgi_socket *zmq_socket;
void *zmq_context;
//void *zmq_pull;
void *zmq_pub;
int zeromq_recv_flag;
pthread_mutex_t zmq_lock;
pthread_key_t zmq_pull;
void *zmq_log_socket;
#endif
struct uwsgi_socket *sockets;
struct uwsgi_socket *shared_sockets;
char *map_socket[MAX_SOCKETS];
struct uwsgi_string_list *map_socket;
time_t respawn_delta;
@@ -1023,6 +1150,11 @@ struct uwsgi_server {
struct wsgi_request *(*current_wsgi_req) (void);
void (*notify) (char *);
void (*notify_ready) (void);
int notification_fd;
void *notification_object;
// usedby suspend/resume loops
void (*schedule_to_main) (struct wsgi_request *);
void (*schedule_to_req) (void);
@@ -1242,14 +1374,27 @@ struct uwsgi_core {
//uint64_t requests;
uint64_t failed_requests;
#ifdef UWSGI_THREADING
pthread_t thread_id;
#endif
//multiple ts per - core are needed only with multiple_interpreter + threads
void *ts[MAX_APPS];
int in_request;
};
struct uwsgi_snapshot {
char *name;
pid_t pid;
time_t timestamp;
};
struct uwsgi_worker {
int id;
pid_t pid;
pid_t snapshot;
uint64_t status;
time_t last_spawn;
@@ -1270,8 +1415,6 @@ struct uwsgi_worker {
uint64_t exceptions;
char sockets_mask[MAX_SOCKETS];
};
char *uwsgi_get_cwd(void);
@@ -1283,7 +1426,6 @@ void gracefully_kill(int);
void reap_them_all(int);
void kill_them_all(int);
void grace_them_all(int);
void reload_me(int);
void end_me(int);
int bind_to_unix(char *, int, int, int);
int bind_to_tcp(char *, int, char *);
@@ -1307,10 +1449,10 @@ void harakiri(void);
void stats(int);
#ifdef UWSGI_XML
void uwsgi_xml_config(struct wsgi_request *, int, char *[]);
void uwsgi_xml_config(char *, struct wsgi_request *, int, char *[]);
#endif
void internal_server_error(int, char *);
void internal_server_error(struct wsgi_request *, char *);
#ifdef UWSGI_SNMP
void manage_snmp(int, uint8_t *, int, struct sockaddr_in *);
@@ -1336,7 +1478,7 @@ uint64_t uwsgi_swap64(uint64_t);
ssize_t send_udp_message(uint8_t, char *, char *, uint16_t);
#endif
int uwsgi_parse_response(struct pollfd *, int, struct uwsgi_header *, char *);
int uwsgi_parse_response(struct pollfd *, int, struct uwsgi_header *, char *, int (*)(struct wsgi_request *));
int uwsgi_parse_vars(struct wsgi_request *);
int uwsgi_enqueue_message(char *, int, uint8_t, uint8_t, char *, int, int);
@@ -1385,9 +1527,9 @@ void nagios(void);
void uwsgi_close_request(struct wsgi_request *);
void wsgi_req_setup(struct wsgi_request *, int);
void wsgi_req_setup(struct wsgi_request *, int, struct uwsgi_socket *);
int wsgi_req_recv(struct wsgi_request *);
int wsgi_req_simple_recv(struct wsgi_request *);
int wsgi_req_async_recv(struct wsgi_request *);
int wsgi_req_accept(struct wsgi_request *);
int wsgi_req_simple_accept(struct wsgi_request *, int);
@@ -1402,7 +1544,7 @@ void uwsgi_log(const char *,...);
void uwsgi_log_verbose(const char *,...);
int uwsgi_load_plugin(int, char *, char *, int);
void *uwsgi_load_plugin(int, char *, char *, int);
int unconfigured_hook(struct wsgi_request *);
@@ -1414,6 +1556,14 @@ void uwsgi_ini_config(char *, char*[]);
void uwsgi_yaml_config(char *, char*[]);
#endif
#ifdef UWSGI_JSON
void uwsgi_json_config(char *, char*[]);
#endif
#ifdef UWSGI_SQLITE3
void uwsgi_sqlite3_config(char *);
#endif
#ifdef UWSGI_LDAP
void uwsgi_ldap_schema_dump(void);
@@ -1451,6 +1601,7 @@ int find_worker_id(pid_t);
void *simple_loop(void *);
void *zeromq_loop(void *);
int count_options(struct option *);
@@ -1516,6 +1667,7 @@ void uwsgi_rwunlock(void *);
inline void *uwsgi_malloc(size_t);
int event_queue_init(void);
void *event_queue_alloc(int);
int event_queue_add_fd_read(int, int);
@@ -1563,19 +1715,26 @@ void gateway_respawn(int);
char *uwsgi_open_and_read(char *, int *, int, char *[]);
char *uwsgi_get_last_char(char *, char);
struct uwsgi_twobytes {
uint8_t cl1;
uint8_t cl0;
} __attribute__((__packed__));
struct fcgi_record {
uint8_t version;
uint8_t type;
uint8_t req1;
uint8_t req0;
uint8_t cl1;
uint8_t cl0;
union {
uint16_t cl;
struct uwsgi_twobytes cl8;
};
uint8_t pad;
uint8_t reserved;
};
} __attribute__((__packed__));
#define FCGI_BEGIN_REQUEST "\0\1\0\0\0\0\0\0"
#define FCGI_END_REQUEST "\1\x06\0\1\0\0\0\0\1\3\0\1\0\x08\0\0\0\0\0\0\0\0\0\0"
ssize_t fcgi_send_record(int, uint8_t, uint16_t, char *);
ssize_t fcgi_send_param(int, char *, uint16_t, char *, uint16_t);
uint16_t fcgi_get_record(int, char *);
@@ -1598,6 +1757,8 @@ int is_a_number(char *);
char *uwsgi_resolve_ip(char *);
void uwsgi_init_queue(void);
void uwsgi_init_cache(void);
char *uwsgi_queue_get(uint64_t, uint64_t *);
char *uwsgi_queue_pull(uint64_t *);
int uwsgi_queue_push(char *, uint64_t);
@@ -1722,6 +1883,8 @@ int uwsgi_str3_num(char *);
int uwsgi_str4_num(char *);
#ifdef __linux__
void linux_namespace_start(void *);
void linux_namespace_jail(void);
int uwsgi_netlink_veth(char *, char *);
int uwsgi_netlink_veth_attach(char *, pid_t);
int uwsgi_netlink_ifup(char *);
@@ -1732,12 +1895,106 @@ int uwsgi_netlink_del(char *);
#endif
int uwsgi_amqp_consume_queue(int, char *, char *, char *, char *);
int uwsgi_amqp_consume_queue(int, char *, char *, char *, char *, char *, char *);
char *uwsgi_amqp_consume(int, uint64_t *, char **);
int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t, char *, uint16_t);
inline int uwsgi_starts_with(char *, int, char *, int);
#ifdef __sun__
time_t timegm(struct tm *);
#endif
int uwsgi_str_num(char *, int);
int uwsgi_proto_uwsgi_parser(struct wsgi_request *);
ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_uwsgi_write(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request *, char *, size_t);
int uwsgi_proto_http_parser(struct wsgi_request *);
ssize_t uwsgi_proto_http_writev_header(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_http_writev(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_http_write(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_proto_http_write_header(struct wsgi_request *, char *, size_t);
int uwsgi_proto_fastcgi_parser(struct wsgi_request *);
ssize_t uwsgi_proto_fastcgi_writev_header(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_fastcgi_writev(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_fastcgi_write(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_proto_fastcgi_write_header(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_proto_fastcgi_sendfile(struct wsgi_request *);
void uwsgi_proto_fastcgi_close(struct wsgi_request *);
int uwsgi_proto_base_accept(struct wsgi_request *, int);
void uwsgi_proto_base_close(struct wsgi_request *);
uint16_t proto_base_add_uwsgi_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
uint16_t proto_base_add_uwsgi_var(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
#ifdef UWSGI_ZEROMQ
void log_zeromq(char *);
int uwsgi_proto_zeromq_accept(struct wsgi_request *, int);
void uwsgi_proto_zeromq_close(struct wsgi_request *);
ssize_t uwsgi_proto_zeromq_writev_header(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_zeromq_writev(struct wsgi_request *, struct iovec *, size_t);
ssize_t uwsgi_proto_zeromq_write(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_proto_zeromq_write_header(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_proto_zeromq_sendfile(struct wsgi_request *);
int uwsgi_proto_zeromq_parser(struct wsgi_request *);
#endif
int uwsgi_num2str2(int, char *);
void uwsgi_add_socket_from_fd(struct uwsgi_socket *, int);
char *uwsgi_split3(char *, size_t, char, char **, size_t *, char **, size_t *, char **, size_t *);
char *uwsgi_split4(char *, size_t, char, char **, size_t *, char **, size_t *, char **, size_t *, char **, size_t *);
char *uwsgi_netstring(char *, size_t, char **, size_t *);
int uwsgi_get_socket_num(struct uwsgi_socket *);
struct uwsgi_socket *uwsgi_new_socket(char *);
struct uwsgi_socket *uwsgi_new_shared_socket(char *);
struct uwsgi_socket *uwsgi_del_socket(struct uwsgi_socket *);
void uwsgi_close_all_sockets(void);
struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **, char *);
void uwsgi_string_del_list(struct uwsgi_string_list **, struct uwsgi_string_list *);
void uwsgi_init_all_apps(void);
void uwsgi_socket_nb(int);
void uwsgi_destroy_request(struct wsgi_request *);
void uwsgi_systemd_init(char *);
void uwsgi_sig_pause(void);
void uwsgi_ignition(void);
void master_check_cluster_nodes(void);
int uwsgi_respawn_worker(int);
void log_socket(char *);
socklen_t socket_to_in_addr(char *, char *, struct sockaddr_in *);
socklen_t socket_to_un_addr(char *, struct sockaddr_un *);
int uwsgi_get_shared_socket_fd_by_num(int);
int uwsgi_get_shared_socket_num(struct uwsgi_socket *);
#ifdef __linux__
void uwsgi_set_cgroup(void);
#endif
void uwsgi_add_sockets_to_queue(int);
void uwsgi_del_sockets_from_queue(int);
+90 -8
View File
@@ -1,5 +1,7 @@
# uWSGI build system
uwsgi_version = '0.9.8-dev'
import os
import re
import time
@@ -23,9 +25,11 @@ GCC = os.environ.get('CC', sysconfig.get_config_var('CC'))
if not GCC:
GCC = 'gcc'
def spcall(cmd):
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,stderr=open('/dev/null','w'))
if p.wait() == 0:
if sys.version_info[0] > 2:
@@ -34,6 +38,12 @@ def spcall(cmd):
else:
return None
if uwsgi_version.endswith('-dev') and os.path.exists('%s/.hg' % os.path.dirname(os.path.abspath( __file__ ))):
try:
uwsgi_version += spcall('hg tip --template "-{rev}"')
except:
pass
def spcall2(cmd):
p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
@@ -156,11 +166,17 @@ class uConf(object):
self.config = ConfigParser.ConfigParser()
print("using profile: %s" % filename)
self.config.read(filename)
self.gcc_list = ['utils', 'protocol', 'socket', 'logging', 'master', 'emperor',
self.gcc_list = ['utils', 'protocol', 'socket', 'logging', 'master', 'master_utils', 'emperor', 'notify',
'plugins', 'lock', 'cache', 'queue', 'event', 'signal', 'rpc', 'gateway', 'loop', 'lib/rbtree', 'lib/amqp', 'rb_timers', 'uwsgi']
#if uwsgi_os == 'Linux':
# self.gcc_list.append('lib/netlink')
self.cflags = ['-O2', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split()
# add protocols
self.gcc_list.append('proto/base')
self.gcc_list.append('proto/uwsgi')
self.gcc_list.append('proto/http')
self.gcc_list.append('proto/fastcgi')
if uwsgi_os == 'Linux':
self.gcc_list.append('lib/linux_ns')
self.gcc_list.append('lib/netlink')
self.cflags = ['-DUWSGI_VERSION="\\"' + uwsgi_version + '\\""', '-O2', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split()
try:
gcc_version = str(spcall("%s -dumpversion" % GCC))
except:
@@ -175,7 +191,7 @@ class uConf(object):
self.cflags = self.cflags + [ '-Wextra', '-Wno-unused-parameter', '-Wno-missing-field-initializers' ]
self.ldflags = os.environ.get("LDFLAGS", "").split()
self.libs = ['-lpthread', '-rdynamic']
self.libs = ['-lpthread', '-lm', '-rdynamic']
if uwsgi_os == 'Linux':
self.libs.append('-ldl')
@@ -224,6 +240,9 @@ class uConf(object):
self.cflags.append('-DUWSGI_BUILD_DATE="\\"%s\\""' % time.strftime("%d %B %Y %H:%M:%S"))
kvm_list = ['FreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly']
if os.path.exists('/usr/include/ifaddrs.h') or os.path.exists('/usr/local/include/ifaddrs.h'):
self.cflags.append('-DUWSGI_HAS_IFADDRS')
if uwsgi_os == 'SunOS':
self.libs.append('-lsendfile')
self.gcc_list.append('lib/sun_fixes')
@@ -344,6 +363,12 @@ class uConf(object):
self.cflags.append('-DUWSGI_EVENT_FILEMONITOR_USE_NONE')
if self.get('malloc_implementation') != 'libc':
if self.get('malloc_implementation') == 'tcmalloc':
self.libs.append('-ltcmalloc')
if self.get('malloc_implementation') == 'jemalloc':
self.libs.append('-ljemalloc')
if self.get('embedded'):
self.cflags.append('-DUWSGI_EMBEDDED')
@@ -373,6 +398,15 @@ class uConf(object):
self.gcc_list.append('regexp')
self.cflags.append("-DUWSGI_PCRE")
has_json = False
has_uuid = False
if os.path.exists('/usr/include/uuid/uuid.h') or os.path.exists('/usr/local/include/uuid/uuid.h'):
has_uuid = True
self.cflags.append("-DUWSGI_UUID")
if os.path.exists('/usr/lib/libuuid.so') or os.path.exists('/usr/local/lib/libuuid.so'):
self.libs.append('-luuid')
if self.get('async'):
self.cflags.append("-DUWSGI_ASYNC")
self.gcc_list.append('async')
@@ -391,6 +425,33 @@ class uConf(object):
if self.get('yaml'):
self.cflags.append("-DUWSGI_YAML")
self.gcc_list.append('yaml')
if self.get('yaml_implementation') == 'libyaml':
self.cflags.append("-DUWSGI_LIBYAML")
self.libs.append('-lyaml')
if self.get('yaml_implementation') == 'auto':
if os.path.exists('/usr/include/yaml.h') or os.path.exists('/usr/local/include/yaml.h'):
self.cflags.append("-DUWSGI_LIBYAML")
self.libs.append('-lyaml')
if self.get('json'):
if self.get('json') == 'auto':
jsonconf = spcall("pkg-config --cflags jansson")
if jsonconf:
self.cflags.append(jsonconf)
self.cflags.append("-DUWSGI_JSON")
self.gcc_list.append('json')
self.libs.append(spcall("pkg-config --libs jansson"))
has_json = True
elif os.path.exists('/usr/include/jansson.h') or os.path.exists('/usr/local/include/jansson.h'):
self.cflags.append("-DUWSGI_JSON")
self.gcc_list.append('json')
self.libs.append('-ljansson')
has_json = True
else:
self.cflags.append("-DUWSGI_JSON")
self.gcc_list.append('json')
self.libs.append('-ljansson')
has_json = True
if self.get('ldap'):
if self.get('ldap') == 'auto':
@@ -403,6 +464,17 @@ class uConf(object):
self.gcc_list.append('ldap')
self.libs.append('-lldap')
if has_uuid and self.get('zeromq'):
if self.get('zeromq') == 'auto':
if os.path.exists('/usr/include/zmq.h') or os.path.exists('/usr/local/include/zmq.h'):
self.cflags.append("-DUWSGI_ZEROMQ")
self.gcc_list.append('proto/zeromq')
self.libs.append('-lzmq')
else:
self.cflags.append("-DUWSGI_ZEROMQ")
self.gcc_list.append('proto/zeromq')
self.libs.append('-lzmq')
if self.get('evdis'):
self.cflags.append("-DUWSGI_EVDIS")
self.gcc_list.append('evdis')
@@ -440,6 +512,17 @@ class uConf(object):
self.libs.append('-lexpat')
self.gcc_list.append('xmlconf')
if self.get('sqlite3'):
if self.get('sqlite3') == 'auto':
if os.path.exists('/usr/include/sqlite3.h') or os.path.exists('/usr/local/include/sqlite3.h'):
self.cflags.append("-DUWSGI_SQLITE3")
self.libs.append('-lsqlite3')
self.gcc_list.append('sqlite3')
else:
self.cflags.append("-DUWSGI_SQLITE3")
self.libs.append('-lsqlite3')
self.gcc_list.append('sqlite3')
if self.get('plugin_dir'):
self.cflags.append('-DUWSGI_PLUGIN_DIR=\\"%s\\"' % self.get('plugin_dir'))
@@ -467,11 +550,10 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
p_cflags = cflags[:]
p_ldflags = ldflags[:]
p_libs = libs[:]
p_cflags += up.CFLAGS
p_ldflags += up.LDFLAGS
p_libs += up.LIBS
p_libs = up.LIBS
p_cflags.insert(0, '-I.')
+2 -2
View File
@@ -7,8 +7,8 @@
<chdir>%v/../</chdir>
<localhost>127.0.0.1</localhost>
<socket>%(localhost):3031</socket>
<socket>/tmp/%(id).sock</socket>
<socket>%(localhost):3039</socket>
<socket>/tmp/%(id).sock2</socket>
<cpus>4</cpus>
<werkzeug>werkzeug.testapp:test_app</werkzeug>
+11
View File
@@ -0,0 +1,11 @@
{
"uwsgi": {
"http": ":8080",
"workers": 8,
"module": "werkzeug.testapp:test_app",
"master": true,
"socket": [ "/tmp/uwsgi.sock", "127.0.0.1:3031", "@foobar" ],
"pythonpath": [ "/foo", "/bar" ],
"show-config": true
}
}
+2
View File
@@ -9,6 +9,7 @@ uwsgi:
master: 1
processes: 8 # the number of processes
memory-report: 1
show-config: true
# now a psgi app via plugin
app2:
@@ -19,3 +20,4 @@ app2:
processes: 8 # the number of processes
memory-report: 1
psgi: test.psgi
show-config: true
-51
View File
@@ -1,51 +0,0 @@
// uWSGI writer
void simple_writer_init(struct wsgi_request *wsgi_req) {}
void simple_writer_end(struct wsgi_request *wsgi_req) {}
ssize_t simple_writer(struct wsgi_request *wsgi_req, char *buf, size_t len) {
return write(wsgi_req->poll.fd, buf, len);
}
void cache_writer_init(struct wsgi_request *wsgi_req) {
if (wsgi_req->cache_it) {
// lock cache write
if (uwsgi_cache_update_start(wsgi_req->uri, wsgi_req->uri_len)) {
uwsgi_log("unable to write data to uwsgi cache\n");
wsgi_req->cache_it = 0;
}
}
}
ssize_t cache_writer(struct wsgi_request *wsgi_req, char *buf, size_t len) {
if (wsgi_req->cache_it) {
// lock cache write
if (uwsgi_cache_update(wsgi_req->uri, wsgi_req->uri_len, buf, len, wsgi_req->cache_expires)) {
uwsgi_log("unable to write data to uwsgi cache\n");
uwsgi_cache_del(sgi_req->uri, wsgi_req->uri_len);
}
// unlock cache
}
return write(wsgi_req->poll.fd, buf, len);
}
void cache_writer_end(struct wsgi_request *wsgi_req) {
if (wsgi_req->cache_it) {
// finish cache update (lock write it)
uwsgi_cache_update_finalize(wsgi_req->uri, wsgi_req->uri_len);
}
}
void memcached_writer_init(struct wsgi_request *wsgi_req) {
//open connection to memcached and create entry
}
void memcached_writer_end(struct wsgi_request *wsgi_req) {
// close connection with memcached
}
ssize_t memcached_writer(struct wsgi_request *wsgi_req, char *buf, size_t len) {
}
+12 -6
View File
@@ -9,7 +9,7 @@ extern struct uwsgi_server uwsgi;
#include <libxml/parser.h>
#include <libxml/tree.h>
void uwsgi_xml_config(struct wsgi_request *wsgi_req, int app_tag, char *magic_table[]) {
void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, int app_tag, char *magic_table[]) {
xmlDoc *doc = NULL;
xmlNode *element = NULL;
xmlNode *node = NULL;
@@ -26,7 +26,13 @@ void uwsgi_xml_config(struct wsgi_request *wsgi_req, int app_tag, char *magic_ta
char *xml_content;
int xml_size = 0;
colon = uwsgi_get_last_char(uwsgi.xml_config, ':');
if (!uwsgi_startswith(filename, "http://", 7)) {
colon = uwsgi_get_last_char(filename, '/');
colon = uwsgi_get_last_char(colon, ':');
}
else {
colon = uwsgi_get_last_char(filename, ':');
}
if (colon) {
colon[0] = 0;
colon++;
@@ -37,16 +43,16 @@ void uwsgi_xml_config(struct wsgi_request *wsgi_req, int app_tag, char *magic_ta
uwsgi_log( "[uWSGI] using xml uwsgi id: %s\n", colon);
}
xml_content = uwsgi_open_and_read(uwsgi.xml_config, &xml_size, 0, magic_table);
xml_content = uwsgi_open_and_read(filename, &xml_size, 0, magic_table);
doc = xmlReadMemory(xml_content, xml_size, uwsgi.xml_config, NULL, 0);
doc = xmlReadMemory(xml_content, xml_size, filename, NULL, 0);
if (doc == NULL) {
uwsgi_log( "[uWSGI] could not parse file %s.\n", uwsgi.xml_config);
uwsgi_log( "[uWSGI] could not parse file %s.\n", filename);
exit(1);
}
if (!app_tag) {
uwsgi_log( "[uWSGI] parsing config file %s\n", uwsgi.xml_config);
uwsgi_log( "[uWSGI] parsing config file %s\n", filename);
}
element = xmlDocGetRootElement(doc);
+86 -10
View File
@@ -4,6 +4,8 @@
extern struct uwsgi_server uwsgi;
#ifndef UWSGI_LIBYAML
/*
yaml file must be read ALL into memory.
This memory must not be freed for all the server lifecycle
@@ -83,28 +85,31 @@ char *yaml_get_line(char *yaml, off_t size) {
return NULL;
}
#else
#include <yaml.h>
#endif
void uwsgi_yaml_config(char *file, char *magic_table[]) {
int len = 0;
char *yaml;
int depth;
int current_depth = 0;
int in_uwsgi_section = 0;
char *yaml_line;
char *section = "";
char *key;
char *val;
int lines = 1;
char *key = NULL;
char *val = NULL;
char *section_asked = "uwsgi";
char *colon;
colon = uwsgi_get_last_char(file, ':');
if (!uwsgi_startswith(file, "http://", 7)) {
colon = uwsgi_get_last_char(file, '/');
colon = uwsgi_get_last_char(colon, ':');
}
else {
colon = uwsgi_get_last_char(file, ':');
}
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
@@ -116,6 +121,76 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
yaml = uwsgi_open_and_read(file, &len, 1, magic_table);
#ifdef UWSGI_LIBYAML
yaml_parser_t parser;
yaml_token_t token;
int status = 0;
int parsing = 1;
if(!yaml_parser_initialize(&parser)) {
uwsgi_log("unable to initialize YAML parser (libyaml)\n");
exit(1);
}
yaml_parser_set_input_string(&parser, (const unsigned char *)yaml, (size_t) len-1);
while(parsing) {
yaml_parser_scan(&parser, &token);
switch(token.type) {
case YAML_STREAM_END_TOKEN:
parsing = 0;
break;
case YAML_KEY_TOKEN:
status = 1;
break;
case YAML_VALUE_TOKEN:
status = 2;
break;
case YAML_BLOCK_MAPPING_START_TOKEN:
if (!in_uwsgi_section) {
if (key) {
if (!strcmp(section_asked, key)) {
in_uwsgi_section = 1;
}
}
}
break;
case YAML_BLOCK_END_TOKEN:
if (in_uwsgi_section) {
parsing = 0;
break;
}
break;
case YAML_SCALAR_TOKEN:
if (status == 1) {
key = (char *) token.data.scalar.value;
}
else if (status == 2) {
val = (char *) token.data.scalar.value;
if (key && val && in_uwsgi_section) {
add_exported_option(key, val, 0);
}
status = 0;
}
else {
uwsgi_log("unsupported YAML token in %s block\n", section_asked);
parsing = 0;
break;
}
break;
default:
status = 0;
}
}
#else
int depth;
int current_depth = 0;
int lines = 1;
char *yaml_line;
char *section = "";
while(len) {
yaml_line = yaml_get_line(yaml, len);
if (yaml_line == NULL) {
@@ -177,6 +252,7 @@ next:
yaml += (yaml_line - yaml);
}
#endif
}