Compare commits

..
180 Commits
Author SHA1 Message Date
Unbit 9cbdfc7764 updated gemspec for 1.9.9 2013-05-08 17:48:41 +02:00
Unbit cb1423436f fixed radius-next 2013-05-08 16:30:32 +02:00
Unbit 2fb391795a added symcall-post-fork 2013-05-08 13:29:21 +02:00
Unbit 9ec20f2d8f allows cache math from the routing subsystem 2013-05-08 11:00:23 +02:00
Unbit 9323ca5136 added cache math api to python 2013-05-08 10:34:34 +02:00
Unbit 978e6072ab prepare for math operations in cache 2013-05-08 09:41:24 +02:00
Unbit d0e3869d54 fixed go arguments on osx 2013-05-07 16:35:34 +02:00
unbit 15c7e956f2 Merge pull request #270 from prymitive/numleaks
2 small memory leaks valgrind complains about
2013-05-07 07:01:11 -07:00
Łukasz Mierzwa ed61545ec7 2 small memory leaks valgrind complains about 2013-05-07 15:54:35 +02:00
Unbit 1aac5becdc added --touch-exec 2013-05-07 15:14:09 +02:00
Unbit 4bca26debc added the radius plugin 2013-05-07 14:38:44 +02:00
Unbit d6eecd1637 report gateway harakiri 2013-05-07 13:41:40 +02:00
unbit 00e7620d2e Merge pull request #269 from prymitive/legion_daemons
legion daemons
2013-05-07 03:36:25 -07:00
Łukasz Mierzwa d657283aad legion daemons 2013-05-07 12:09:26 +02:00
Unbit 70a879ea94 added incache routing condition 2013-05-07 11:56:18 +02:00
Unbit 591ee22472 fixed support for go 1.1rc2 2013-05-07 11:11:25 +02:00
Unbit 956b05d39d Merge branch 'master' of github.com:unbit/uwsgi 2013-05-07 10:02:00 +02:00
Roberto De Ioris 5bdad6d4cb support for go 1.1 on osx 2013-05-07 04:36:05 +02:00
unbit 29a6ac6ed7 Merge pull request #267 from prymitive/log_retries
log retry count on router error
2013-05-06 09:16:07 -07:00
Łukasz Mierzwa 8f7f091e9b log retry count on router error 2013-05-06 16:20:04 +02:00
Unbit 63dfe7628b added uwsgi_connect_udp 2013-05-06 15:22:13 +02:00
Unbit ce507e7851 try to fix multithread + dynamic mode 2013-05-04 15:44:44 +02:00
Unbit a9cd76173e added default app for psgi 2013-05-04 15:41:12 +02:00
Unbit 44f8ffb434 another fix in spnego 2013-05-04 15:27:40 +02:00
Unbit 28c395f111 it looks like both MIT krb5 and heimdal leaks memory... 2013-05-04 15:14:17 +02:00
Unbit 39df68c38e better next support for spnego 2013-05-04 13:49:32 +02:00
Unbit b33ca9225a improved route-if regexp to store vectors 2013-05-04 13:36:09 +02:00
Unbit bd137afecf fixed thread bug with routing regexp vectors 2013-05-04 12:39:08 +02:00
Roberta Giordano a3b9bed8c2 fixed spnego build 2013-05-04 08:37:55 +02:00
Unbit 0a157739bc Merge branch 'master' of github.com:unbit/uwsgi 2013-05-04 08:11:37 +02:00
Unbit c46b08ad5e completed spnego plugin 2013-05-04 08:11:19 +02:00
unbit 754e6193a4 Merge pull request #265 from ttreptow/master
Fix mule farm initialization
2013-05-03 12:03:26 -07:00
Tim Treptow 56b49fe2dd fix mule farm initialization 2013-05-03 09:40:10 -07:00
Unbit 36a7215f94 added setscriptname and donotlog routing actions 2013-05-03 17:49:06 +02:00
Unbit 702247affd spnego plugin is almost ready 2013-05-03 17:44:21 +02:00
Unbit e752b1f8e5 added Graham credits 2013-05-03 10:21:15 +02:00
Unbit 920eee36e3 fixed a wrong cast in gevent plugin 2013-05-02 17:28:06 +02:00
unbit a5070a5d98 Merge pull request #262 from edevil/master
Call atexit hook after all requests are done, or immediately if there are no requests
2013-05-02 08:24:57 -07:00
Unbit ccb5aefa61 do not use the stack on ldapauth filter generation 2013-05-02 16:50:55 +02:00
Unbit 378b08e37c fixed a memory leak in ldapauth 2013-05-02 16:48:04 +02:00
Unbit 5763483c91 avoid using deprecated apis in the ldap plugin 2013-05-02 15:54:45 +02:00
Andre Cruz 559f8ee095 Call atexit hook when we want to graceful reload and there are no requests being served. Otherwise call it when the last request finishes. 2013-05-02 14:36:50 +01:00
Unbit 4382ef360c Merge branch 'master' of github.com:unbit/uwsgi 2013-05-02 15:12:07 +02:00
Unbit 0cb576cf1a added ldap to all buildconf 2013-05-02 15:11:57 +02:00
unbit dee4d047b4 Merge pull request #261 from prymitive/ldapauth1
remove useless reconnect
2013-05-02 06:11:25 -07:00
Łukasz Mierzwa 2520cc7bb9 remove useless reconnect 2013-05-02 12:24:11 +02:00
unbit 192c31efe0 Merge pull request #257 from prymitive/router_ldapauth
router_ldapauth plugin with simple bind support
2013-05-02 02:54:23 -07:00
Łukasz Mierzwa a1d8ebc2d2 router_ldapauth plugin with simple bind support 2013-05-02 11:47:31 +02:00
Unbit 14a9de2147 spnego authentication is still broken 2013-05-02 10:17:28 +02:00
Unbit a760a9a3f1 ported the xslt plugin to the new api 2013-05-02 10:04:04 +02:00
Unbit efd14e1c7a added cookie-based authentication test 2013-05-02 09:34:31 +02:00
Unbit 6019c46cee removed the GOON routing return value 2013-05-02 08:45:37 +02:00
Unbit ec6acfbc1c improved transformation system 2013-05-01 19:36:13 +02:00
Unbit e925dbaad6 other gzip improvements 2013-05-01 12:04:41 +02:00
Unbit 8321adf0bc completed chunked transformation 2013-05-01 10:21:35 +02:00
Unbit e1c5e9e874 prepare for gzip streaming 2013-05-01 10:05:39 +02:00
Unbit 0aec581714 prepare for streaming transformations 2013-05-01 09:56:56 +02:00
Unbit b77b8623d1 added a simple dumper for REPORT method 2013-04-30 18:49:58 +02:00
Unbit 5ab986d6d9 send only requested webdav props 2013-04-30 11:41:16 +02:00
Unbit 09b8332236 prepare for caldav support 2013-04-29 21:42:46 +02:00
Unbit d05345abc0 added current-user-privilege-set 2013-04-29 15:06:37 +02:00
Unbit 804c369f0d toward programmable webdav, carddav support ensured 2013-04-29 14:42:04 +02:00
Roberta Giordano 8f67fc886c added support for OSX xattr in WebDAV plugin 2013-04-28 11:37:20 +02:00
Roberta Giordano ca3b1a9b30 support for OSX in the webdav plugin 2013-04-28 11:24:07 +02:00
Unbit 63c1dbb3ed windows-webdav compatibility fix 2013-04-28 11:16:44 +02:00
Unbit 9a424dfe29 prepare for webdav locking 2013-04-28 10:07:36 +02:00
Unbit 0a6eb596bb completed PROPPATCH 2013-04-28 09:46:10 +02:00
Unbit 34452376db added PROPFIND + xattr in the webdav plugin 2013-04-28 08:31:47 +02:00
Unbit 53a90a59c5 added xattr plugin 2013-04-27 19:01:09 +02:00
Unbit ec491ebd83 added the WebDAV plugin (beta) 2013-04-27 18:24:21 +02:00
Unbit cdc41c305e improved url encoding api 2013-04-27 11:45:48 +02:00
Unbit 6cf67b399c new api functions for http headers 2013-04-27 09:10:11 +02:00
unbit dc3c56bccc Merge pull request #253 from prymitive/alarm_airbrake_plugin
airbrake plugin
2013-04-26 07:55:23 -07:00
Łukasz Mierzwa 4657f2039a airbrake plugin 2013-04-26 16:29:18 +02:00
Unbit b0082fbd0d added --alarm-segfault 2013-04-26 15:09:04 +02:00
Unbit ede1b4df11 fixed initial flush 2013-04-26 08:36:41 +02:00
unbit d78a3d1f8a Merge pull request #247 from prymitive/cache_sync_fix
fixed cache sync parsing
2013-04-25 05:44:08 -07:00
Unbit 6152555f26 another fix in python async mode 2013-04-25 14:43:40 +02:00
Unbit bbad505044 fixed python async mode with the improved api 2013-04-25 14:28:38 +02:00
Łukasz Mierzwa 11c5429184 fixed cache sync parsing - uwsgi_hooked_parse() was getting invalid data lenght 2013-04-25 14:28:18 +02:00
Unbit 4e865c4525 fixed stackless + threads 2013-04-25 14:03:40 +02:00
Unbit 2fa785a539 improved fiber support 2013-04-25 13:51:05 +02:00
Unbit 296a8449c9 improved stackless plugin 2013-04-25 13:46:30 +02:00
Unbit f20213ff10 various async/green mode improvements and fixes 2013-04-25 11:33:45 +02:00
Unbit 8a7067ee24 added routing support to coroae and fixed backtrace-depth 2013-04-25 09:09:46 +02:00
Unbit a3024e9f5a refactored async mode 2013-04-25 08:57:58 +02:00
Unbit 86e651f5e7 call gevent atexit hook before destroying uwsgi-related greenlets 2013-04-25 07:09:39 +02:00
unbit 409710b2b1 Merge pull request #245 from prymitive/dont_count_tx_on_pings
don't increment tx counter on requests that should not be accounted
2013-04-24 04:27:27 -07:00
Łukasz Mierzwa 14a406a276 don't increment tx counter on requests that should not be accounted (ping plugin requests) 2013-04-24 10:57:05 +02:00
Unbit 28a283b1c1 added uwsgi.atexit management to gevent 2013-04-23 21:20:42 +02:00
Unbit ccf298a148 updated gemspec 2013-04-23 14:29:45 +02:00
Unbit 914b600af4 prepare for 1.9.8 2013-04-23 14:27:47 +02:00
Unbit 4944994667 fixed #244 2013-04-23 14:27:08 +02:00
Unbit 3a487578a5 remove annoying logline in async mode 2013-04-23 10:10:13 +02:00
Unbit 39eeccb16a refactored async runqueue management 2013-04-23 10:02:36 +02:00
Roberta Giordano 32acd3b9d1 added the flush instruction 2013-04-23 07:07:53 +02:00
Roberta Giordano c57baae477 mime route var has to take variables 2013-04-23 06:46:47 +02:00
Unbit 4a6ed633b9 added hex and base64 routing vars 2013-04-22 16:36:46 +02:00
Unbit 2ab1845547 prepare gemspec for 1.9.7 2013-04-22 15:36:13 +02:00
Unbit f4d2e1f20c added UWSGI_EMBED_PLUGINS 2013-04-22 12:37:31 +02:00
Unbit 81dca1f690 better lock-engine auto-detection 2013-04-22 12:23:59 +02:00
Unbit 2b331fd68f fixed ipcsem removal on reload 2013-04-22 12:16:39 +02:00
Unbit cc77e4dba7 ported gridfs to the new uwsgi_get_app_id function 2013-04-22 10:33:52 +02:00
Unbit 620a13a308 added toxslt transformation 2013-04-22 10:08:56 +02:00
Unbit 42d4ba09d7 refactored uwsgi_get_app_id 2013-04-22 09:43:20 +02:00
Unbit ca071fa52f removed cherokee nginx and lighttpd directories 2013-04-22 08:07:26 +02:00
Unbit d38e5dec7b added uwsgi::register_rpc to perl 2013-04-22 08:05:20 +02:00
Unbit e5db38f7c0 kqueue timer for OpenBSD, NetBSD and DragonFlyBSD 2013-04-22 09:07:19 +02:00
Unbit 68a29730c0 transformation_gzip and transformation_tofile are part of the default build profile 2013-04-22 06:57:29 +02:00
Unbit 5c33c4d341 fixed fd leak in sendfile on error 2013-04-22 06:25:50 +02:00
Unbit a1d6270089 another static gzip refactoring 2013-04-21 20:48:08 +02:00
unbit 1968175b00 Merge pull request #240 from toofishes/static-gz-length
Fix Content-Length header when serving gzipped content
2013-04-21 11:38:18 -07:00
Dan McGee cf1e2aeeba Fix Content-Length header when serving gzipped content
The refactor in a56003d8 to support the Range header broke compliance
with the HTTP spec. When we find a gzipped resource to serve up, ensure
we use the correct Content-Length of the compressed file, not the
original one.
2013-04-21 13:16:33 -05:00
Unbit 199b0b9f57 resources allocated by transformations are correctly freed 2013-04-21 10:22:33 +02:00
Unbit 87a0daa465 ported gzip and toupper to the new transformation api 2013-04-21 10:17:37 +02:00
Unbit c2af90b58f cachestore response is buffered 2013-04-21 10:09:02 +02:00
Unbit 62f01453af refactored cachestore to use transformation api 2013-04-21 10:07:48 +02:00
Unbit 375d6ee331 allows non-request plugin to register rpc functions 2013-04-21 09:43:45 +02:00
Unbit 222ca2915b symcall has been improved and added to the dfault build profile 2013-04-20 19:22:50 +02:00
Unbit 5ca848f9fe more robust subscription propagation using non blocking sockets 2013-04-20 15:17:43 +02:00
Unbit 68d878ff6b added arbiters to the Legion subsystem 2013-04-20 14:20:32 +02:00
Unbit 782a7b418a added mime route var 2013-04-20 13:56:10 +02:00
Unbit 724d7854ad allows transformation to rewrite headers 2013-04-20 13:51:48 +02:00
Unbit f8e64d17e8 added safe-fd concept and --alarm-fd 2013-04-20 13:24:36 +02:00
Unbit 3b40799000 more robust error checking for cgroups and support for writing proc files on the fly 2013-04-20 10:49:42 +02:00
Roberta Giordano 709964ca92 raise an exception with python3 if the headers are not encodable in latin1 2013-04-20 08:08:53 +02:00
Unbit d2cdedc610 maintain headers sent as the last resort even in buffered mode 2013-04-18 22:09:05 +02:00
Unbit b7d0730343 fixed another typo 2013-04-18 18:06:07 +02:00
Unbit 30b4ea7d49 added transformation_gzip 2013-04-18 18:05:01 +02:00
Unbit 546dadbd06 fixed some typo 2013-04-18 17:59:24 +02:00
Unbit 76edf902de added trasnformations 2013-04-18 17:56:13 +02:00
Unbit 068024134c added --load-file-in-cache-gzip 2013-04-17 16:08:27 +02:00
Unbit 538ab57b6e extend magic cache api to export the expires value (if available) 2013-04-16 18:56:25 +02:00
Unbit fd6d9148f3 filter more headers in proxy mode 2013-04-16 18:00:30 +02:00
Unbit f033f59755 fixed gzip caching 2013-04-16 17:51:50 +02:00
Unbit 7168c6dd69 improved caching 2013-04-16 17:46:36 +02:00
Unbit f121d41c2f added proxyhttp and proxyuwsgi 2013-04-16 17:11:32 +02:00
Unbit e56e774eac Merge branch 'master' of github.com:unbit/uwsgi 2013-04-16 10:17:29 +02:00
Unbit 6d9b0918a3 do not skip atexit hooks on end_me when run by the master 2013-04-16 10:17:11 +02:00
unbit d445418611 Merge pull request #229 from prymitive/cb_in_base
add cheaper_busyness plugin to default build profile
2013-04-16 01:12:52 -07:00
Unbit 6d15a51c9a added --skip-atexit 2013-04-16 10:12:22 +02:00
unbit 42a615efdd Merge pull request #231 from prymitive/legion_lock
add missing locks to legion_cache_fetch plugin
2013-04-15 10:32:01 -07:00
Łukasz Mierzwa 54cd1f79a6 add missing locks to legion_cache_fetch plugin 2013-04-15 19:15:54 +02:00
Unbit 8ed8f46374 fixed some minor-bug dected by cppcheck 2013-04-15 13:45:46 +02:00
Unbit dd3a2996a4 fixed leak in cache gzip 2013-04-15 13:22:26 +02:00
Unbit bf1f90a96a added the ability to store cache items in gzip 2013-04-15 12:36:27 +02:00
Unbit 2d6200231a added content_encoding to routing cache 2013-04-15 11:28:54 +02:00
Unbit 032cd23304 added --legion-mcast shortcut 2013-04-14 18:12:57 +02:00
Łukasz Mierzwa de4c0a9e1c add cheaper_busyness plugin to default build profile 2013-04-14 12:28:49 +02:00
Unbit e33f8e8920 compile the remote spooler plugin by default 2013-04-14 09:39:46 +02:00
Unbit 22615c7921 correctly support default cache in ssl session scaling 2013-04-14 08:23:48 +02:00
Unbit 9d8809c580 added the curl_cron plugin 2013-04-13 10:04:21 +02:00
Unbit 96b92c98ff refactored cron to allows better plugins integration 2013-04-13 09:22:22 +02:00
unbit 07939acecd Merge pull request #228 from prymitive/cache_last_modified
store cache last modification time if enabled, fixes #224
2013-04-13 00:08:10 -07:00
Łukasz Mierzwa 30abcb2563 store cache last modification time if enabled, fixes #224 2013-04-12 22:11:25 +02:00
Unbit 35ce8f2b8d do not spawn the excpetion thread handler if no exception handler has been loaded 2013-04-12 08:12:15 +02:00
Unbit d6453eab38 improved cache usage in corerouters 2013-04-11 20:25:18 +02:00
Unbit e0964d07ea ported router_http improvements to router_uwsgi 2013-04-11 17:59:49 +02:00
Unbit fc359f1956 better to set status to 202 for offloaded requests 2013-04-11 17:39:20 +02:00
Unbit 322261d65d Merge branch 'master' of github.com:unbit/uwsgi 2013-04-11 17:26:42 +02:00
Unbit bd1163c439 fixed websocket proxy 2013-04-11 17:24:44 +02:00
unbit e203a8c706 Merge pull request #226 from prymitive/legion_log_fixes
remove unnecessary new lines in legion logs
2013-04-11 05:54:16 -07:00
unbit 6a1ba2af74 Merge pull request #225 from prymitive/cron_interval_fix
execute cron tasks with 60 second resolution, instead of 61 seconds
2013-04-11 05:37:00 -07:00
Łukasz Mierzwa 22569e64df remove unnecessary new lines in legion logs 2013-04-11 14:33:38 +02:00
Łukasz Mierzwa dcafe41cde execute cron tasks with 60 second resolution, instead of 61 seconds 2013-04-11 14:09:49 +02:00
Unbit dd2adc08a3 fixed teajs support 2013-04-11 12:25:06 +02:00
Unbit d7534d2673 improve post_buffering management in http internal router 2013-04-11 12:20:32 +02:00
Unbit 0a59920025 honour http protocol in http internal router 2013-04-11 11:47:14 +02:00
Unbit 77602a8de4 improved websockets detection 2013-04-11 11:30:15 +02:00
Unbit 65b3fde97c added --legion-cron 2013-04-11 09:37:22 +02:00
unbit b690148452 Merge pull request #223 from prymitive/lcf_fixes
free values on old sync node list
2013-04-10 22:52:55 -07:00
Łukasz Mierzwa 4c7bc9ada6 free list value before we free list itself 2013-04-10 22:12:06 +02:00
Unbit 432651489f let's start with 1.9.7 2013-04-10 19:04:12 +02:00
unbit 82aa232a37 Merge pull request #221 from prymitive/legion_cache_plugin2
plugin for fetching cache dump from any node after joining legion
2013-04-10 09:32:41 -07:00
Unbit 19b13bf7a7 fixed offloading and more metric analysis 2013-04-10 18:21:28 +02:00
Łukasz Mierzwa f7e25d807d Merge remote branch 'upstream/master' into legion_cache_plugin2 2013-04-10 15:57:04 +02:00
unbit cf05316b95 Merge pull request #210 from prymitive/cron_refactoring
move crontab entry parsing to separate function
2013-04-10 06:40:30 -07:00
Łukasz Mierzwa 001c4386b5 move crontab entry parsing to separate function 2013-04-10 15:37:10 +02:00
Łukasz Mierzwa 572527f8cb plugin for fetching cache dump from any node after joining legion 2013-04-10 13:28:03 +02:00
Unbit b4252beda6 updated gemspec 2013-04-09 19:05:26 +02:00
110 changed files with 6232 additions and 4000 deletions
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap
inherit = base
+1 -1
View File
@@ -16,7 +16,7 @@ plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked
as_shared_library = false
locking = auto
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin =
inherit = base
-1
View File
@@ -1 +0,0 @@
the uwsgi handler is included in the official Cherokee distribution
+139 -10
View File
@@ -11,6 +11,29 @@ void uwsgi_alarm_func_signal(struct uwsgi_alarm_instance *uai, char *msg, size_t
uwsgi_route_signal(uai->data8);
}
// simply log an alarm
void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
}
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
if (msg[len-1] != '\n') {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s\n", len, msg);
}
}
else {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s", len, msg);
}
}
}
// run a command on alarm
void uwsgi_alarm_init_cmd(struct uwsgi_alarm_instance *uai) {
uai->data_ptr = uai->arg;
@@ -86,6 +109,7 @@ void uwsgi_register_embedded_alarms() {
uwsgi_register_alarm("signal", uwsgi_alarm_init_signal, uwsgi_alarm_func_signal);
uwsgi_register_alarm("cmd", uwsgi_alarm_init_cmd, uwsgi_alarm_func_cmd);
uwsgi_register_alarm("mule", uwsgi_alarm_init_mule, uwsgi_alarm_func_mule);
uwsgi_register_alarm("log", uwsgi_alarm_init_log, uwsgi_alarm_func_log);
}
static int uwsgi_alarm_add(char *name, char *plugin, char *arg) {
@@ -189,21 +213,54 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
#endif
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
// add uwsgi_alarm_fd;
struct uwsgi_alarm_fd *uafd = uwsgi.alarm_fds;
while(uafd) {
event_queue_add_fd_read(ut->queue, uafd->fd);
uafd = uafd->next;
}
char *buf = uwsgi_malloc(uwsgi.alarm_msg_size + sizeof(long));
for (;;) {
int interesting_fd = -1;
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret > 0) {
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
if (len > (ssize_t)(sizeof(long) + 1)) {
size_t msg_size = len - sizeof(long);
char *msg = buf + sizeof(long);
long ptr = 0;
memcpy(&ptr, buf, sizeof(long));
struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr;
if (!uai)
break;
uwsgi_alarm_run(uai, msg, msg_size);
if (interesting_fd == ut->pipe[1]) {
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
if (len > (ssize_t)(sizeof(long) + 1)) {
size_t msg_size = len - sizeof(long);
char *msg = buf + sizeof(long);
long ptr = 0;
memcpy(&ptr, buf, sizeof(long));
struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr;
if (!uai)
break;
uwsgi_alarm_run(uai, msg, msg_size);
}
}
// check for alarm_fd
else {
uafd = uwsgi.alarm_fds;
int fd_read = 0;
while(uafd) {
if (interesting_fd == uafd->fd) {
if (fd_read) goto raise;
size_t remains = uafd->buf_len;
while(remains) {
ssize_t len = read(uafd->fd, uafd->buf + (uafd->buf_len-remains), remains);
if (len <= 0) {
uwsgi_error("[uwsgi-alarm-fd]/read()");
uwsgi_log("[uwsgi-alarm-fd] i will stop monitoring fd %d\n", uafd->fd);
event_queue_del_fd(ut->queue, uafd->fd, event_queue_read());
break;
}
remains-=len;
}
fd_read = 1;
raise:
uwsgi_alarm_run(uafd->alarm, uafd->msg, uafd->msg_len);
}
uafd = uafd->next;
}
}
}
}
@@ -243,6 +300,37 @@ void uwsgi_alarms_init() {
if (!uwsgi.alarm_instances) return;
// map alarm file descriptors
usl = uwsgi.alarm_fd_list;
while(usl) {
char *space0 = strchr(usl->value, ' ');
if (!space0) {
uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value);
exit(1);
}
*space0 = 0;
size_t buf_len = 1;
char *space1 = strchr(space0+1, ' ');
if (!space1) {
uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value);
exit(1);
}
char *colon = strchr(space0+1, ':');
if (colon) {
buf_len = strtoul(colon+1, NULL, 10);
*colon = 0;
}
int fd = atoi(space0+1);
uwsgi_add_alarm_fd(fd, usl->value, buf_len, space1+1, strlen(space1+1));
*space0 = ' ';
*space1 = ' ';
if (colon) {
*colon = ':';
}
usl = usl->next;
}
#ifdef UWSGI_PCRE
// then map log-alarm
usl = uwsgi.alarm_logs_list;
@@ -340,3 +428,44 @@ void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
}
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
struct uwsgi_alarm_fd *old_uafd = NULL, *uafd = uwsgi.alarm_fds;
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm);
if (!uai) {
uwsgi_log("unable to find alarm \"%s\"\n", alarm);
exit(1);
}
if (!buf_len) buf_len = 1;
while(uafd) {
// check if an equal alarm has been added
if (uafd->fd == fd && uafd->alarm == uai) {
return uafd;
}
old_uafd = uafd;
uafd = uafd->next;
}
uafd = uwsgi_calloc(sizeof(struct uwsgi_alarm_fd));
uafd->fd = fd;
uafd->buf = uwsgi_malloc(buf_len);
uafd->buf_len = buf_len;
uafd->msg = msg;
uafd->msg_len = msg_len;
uafd->alarm = uai;
if (!old_uafd) {
uwsgi.alarm_fds = uafd;
}
else {
old_uafd->next = uafd;
}
// avoid the fd to be closed
uwsgi_add_safe_fd(fd);
uwsgi_log("[uwsgi-alarm] added fd %d\n", fd);
return uafd;
}
+126 -94
View File
@@ -2,6 +2,24 @@
extern struct uwsgi_server uwsgi;
/*
This is a general purpose async loop engine (it expects a coroutine based approach)
You can see it as an hub holding the following structures:
1) the runqueue, cores ready to be run are appended in this list
2) the fd list, this is a list of monitored file descriptors, a core can wait for all the file descriptors it needs
3) the timeout value, if set the current core will timeout aftert he specified number of seconds (unless an event cancel it)
IMPORTANT: this is not a callback based engine !!!
*/
// this is called whenever a new connection is ready, but there are no cores to handle it
void uwsgi_async_queue_is_full(time_t now) {
if (now > uwsgi.async_queue_is_full) {
uwsgi_log_verbose("[DANGER] async queue is full !!!\n");
@@ -22,12 +40,15 @@ void uwsgi_async_init() {
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
// a stack of unused cores
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
// fill it with default values
for (i = 0; i < uwsgi.async; i++) {
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
}
// the first available core is the last one
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
}
@@ -52,7 +73,7 @@ static void runqueue_remove(struct uwsgi_async_request *u_request) {
child->prev = parent;
}
if (parent == NULL) {
if (u_request == uwsgi.async_runqueue) {
uwsgi.async_runqueue = child;
}
@@ -61,33 +82,33 @@ static void runqueue_remove(struct uwsgi_async_request *u_request) {
}
free(u_request);
uwsgi.async_runqueue_cnt--;
}
static void runqueue_push(struct wsgi_request *wsgi_req) {
struct uwsgi_async_request *uar;
// do not push the same request in the runqueue
struct uwsgi_async_request *uar = uwsgi.async_runqueue;
while(uar) {
if (uar->wsgi_req == wsgi_req) return;
uar = uar->next;
}
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
uar->prev = NULL;
uar->next = NULL;
uar->wsgi_req = wsgi_req;
if (uwsgi.async_runqueue == NULL) {
// empty runqueue, create a new one
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
uwsgi.async_runqueue->next = NULL;
uwsgi.async_runqueue->prev = NULL;
uwsgi.async_runqueue->wsgi_req = wsgi_req;
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
uwsgi.async_runqueue = uar;
}
else {
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
uar->prev = uwsgi.async_runqueue_last;
uar->next = NULL;
uar->wsgi_req = wsgi_req;
uwsgi.async_runqueue_last->next = uar;
uwsgi.async_runqueue_last = uar;
uar->prev = uwsgi.async_runqueue_last;
}
uwsgi.async_runqueue_cnt++;
if (uwsgi.async_runqueue_last) {
uwsgi.async_runqueue_last->next = uar;
}
uwsgi.async_runqueue_last = uar;
}
struct wsgi_request *find_first_available_wsgi_req() {
@@ -103,11 +124,28 @@ struct wsgi_request *find_first_available_wsgi_req() {
return wsgi_req;
}
void async_reset_request(struct wsgi_request *wsgi_req) {
if (wsgi_req->async_timeout) {
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout);
free(wsgi_req->async_timeout);
wsgi_req->async_timeout = NULL;
}
struct uwsgi_async_fd *uaf = wsgi_req->waiting_fds;
while (uaf) {
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
struct uwsgi_async_fd *current_uaf = uaf;
uaf = current_uaf->next;
free(current_uaf);
}
wsgi_req->waiting_fds = NULL;
}
static void async_expire_timeouts(uint64_t now) {
struct wsgi_request *wsgi_req;
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
struct uwsgi_rb_timer *urbt;
for (;;) {
@@ -121,20 +159,9 @@ static void async_expire_timeouts(uint64_t now) {
wsgi_req = (struct wsgi_request *) urbt->data;
// timeout expired
wsgi_req->async_timed_out = 1;
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout);
free(wsgi_req->async_timeout);
wsgi_req->async_timeout = NULL;
uaf = wsgi_req->waiting_fds;
// remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready)
while (uaf) {
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
current_uaf = uaf;
uaf = current_uaf->next;
free(current_uaf);
}
wsgi_req->waiting_fds = NULL;
// put th request in the runqueue
// reset teh request
async_reset_request(wsgi_req);
// push it in the runqueue
runqueue_push(wsgi_req);
continue;
}
@@ -151,7 +178,7 @@ int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
if (fd < 0)
return -1;
// find first slot
// find last slot
while (uad) {
last_uad = uad;
uad = uad->next;
@@ -208,7 +235,7 @@ int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
if (fd < 0)
return -1;
// find first slot
// find last slot
while (uad) {
last_uad = uad;
uad = uad->next;
@@ -252,7 +279,49 @@ static int async_wait_fd_write(int fd, int timeout) {
}
void async_schedule_to_req(void) {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
goto end;
}
// a trick to avoid calling routes again
uwsgi.wsgi_req->is_routing = 1;
#endif
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
goto end;
}
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(uwsgi.wsgi_req);
}
return;
end:
async_reset_request(uwsgi.wsgi_req);
uwsgi_close_request(uwsgi.wsgi_req);
uwsgi.wsgi_req->async_status = UWSGI_OK;
}
void async_schedule_to_req_green(void) {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
goto end;
}
#endif
for(;;) {
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
break;
}
uwsgi.wsgi_req->switches++;
// switch after each yield
uwsgi.schedule_to_main(uwsgi.wsgi_req);
}
#ifdef UWSGI_ROUTING
end:
#endif
async_reset_request(uwsgi.wsgi_req);
uwsgi_close_request(uwsgi.wsgi_req);
uwsgi.wsgi_req->async_status = UWSGI_OK;
}
void async_loop() {
@@ -262,7 +331,6 @@ void async_loop() {
exit(1);
}
struct uwsgi_async_fd *tmp_uaf;
int interesting_fd, i;
struct uwsgi_rb_timer *min_timeout;
int timeout;
@@ -271,13 +339,12 @@ void async_loop() {
uint64_t now;
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
struct uwsgi_async_request *current_request = NULL;
void *events = event_queue_alloc(64);
struct uwsgi_socket *uwsgi_sock;
uwsgi.async_runqueue = NULL;
uwsgi.async_runqueue_cnt = 0;
uwsgi.wait_write_hook = async_wait_fd_write;
uwsgi.wait_read_hook = async_wait_fd_read;
@@ -298,7 +365,7 @@ void async_loop() {
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
now = (uint64_t) uwsgi_now();
if (uwsgi.async_runqueue_cnt) {
if (uwsgi.async_runqueue) {
timeout = 0;
}
else {
@@ -328,16 +395,15 @@ void async_loop() {
// manage events
interesting_fd = event_queue_interesting_fd(events, i);
// signals are executed in the main stack... in the future we could have dedicated stacks for them
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
continue;
}
is_a_new_connection = 0;
// new request coming in ?
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -351,6 +417,7 @@ void async_loop() {
break;
}
// on error re-insert the request in the queue
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock);
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
uwsgi.async_queue_unused_ptr++;
@@ -364,6 +431,9 @@ void async_loop() {
break;
}
// by default the core is in UWSGI_AGAIN mode
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
// some protocol (like zeromq) do not need additional parsing, just push it in the runqueue
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
runqueue_push(uwsgi.wsgi_req);
}
@@ -380,9 +450,7 @@ void async_loop() {
if (uwsgi.wsgi_req) {
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
// reset timeout
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
async_reset_request(uwsgi.wsgi_req);
// parsing complete
if (!proto_parser_status) {
// remove fd from event poll and fd proto table
@@ -393,8 +461,6 @@ void async_loop() {
continue;
}
else if (proto_parser_status < 0) {
if (proto_parser_status == -1)
uwsgi_log("error parsing request\n");
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
close(interesting_fd);
continue;
@@ -404,7 +470,7 @@ void async_loop() {
continue;
}
// app event
// app-registered event
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
// unknown fd, remove it (for safety)
if (uwsgi.wsgi_req == NULL) {
@@ -413,79 +479,45 @@ void async_loop() {
}
// remove all the fd monitors and timeout
while (uwsgi.wsgi_req->waiting_fds) {
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
free(tmp_uaf);
}
uwsgi.wsgi_req->waiting_fds = NULL;
if (uwsgi.wsgi_req->async_timeout) {
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
}
async_reset_request(uwsgi.wsgi_req);
uwsgi.wsgi_req->async_ready_fd = 1;
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
// put the request in the runqueue again
runqueue_push(uwsgi.wsgi_req);
// avoid managing other enqueued events...
break;
}
}
// event queue managed, give cpu to runqueue
if (!current_request)
current_request = uwsgi.async_runqueue;
if (uwsgi.async_runqueue_cnt) {
// event queue managed, give cpu to runqueue
current_request = uwsgi.async_runqueue;
while(current_request) {
// current_request could be nulled on error/end of request
struct uwsgi_async_request *next_request = current_request->next;
uwsgi.wsgi_req = current_request->wsgi_req;
uwsgi.schedule_to_req();
uwsgi.wsgi_req->switches++;
next_async_request = current_request->next;
// request ended ?
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
// remove all the monitored fds and timeout
while (uwsgi.wsgi_req->waiting_fds) {
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
free(tmp_uaf);
}
uwsgi.wsgi_req->waiting_fds = NULL;
if (uwsgi.wsgi_req->async_timeout) {
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
}
// remove from the list
// remove from the runqueue
runqueue_remove(current_request);
uwsgi_close_request(uwsgi.wsgi_req);
// push wsgi_request in the unused stack
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
}
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
// remove this request from suspended list
// remove this request from the runqueue
runqueue_remove(current_request);
}
current_request = next_async_request;
current_request = next_request;
}
}
}
+8
View File
@@ -354,3 +354,11 @@ struct uwsgi_buffer *uwsgi_buffer_from_file(char *filename) {
return ub;
}
void uwsgi_buffer_map(struct uwsgi_buffer *ub, char *buf, size_t len) {
if (ub->buf) {
free(ub->buf);
}
ub->buf = buf;
ub->pos = len;
ub->len = len;
}
+163 -16
View File
@@ -156,14 +156,14 @@ static void cache_send_udp_command(struct uwsgi_cache *, char *, uint16_t, char
static void cache_sync_hook(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
struct uwsgi_cache *uc = (struct uwsgi_cache *) data;
if (!uwsgi_strncmp(k, kl, "items", 5)) {
size_t num = uwsgi_str_num(v, vl);
size_t num = uwsgi_str_num(v, vl);
if (num != uc->max_items) {
uwsgi_log("[cache-sync] invalid cache size, expected %llu received %llu\n", (unsigned long long) uc->max_items, (unsigned long long) num);
exit(1);
}
}
if (!uwsgi_strncmp(k, kl, "blocksize", 9)) {
size_t num = uwsgi_str_num(v, vl);
size_t num = uwsgi_str_num(v, vl);
if (num != uc->blocksize) {
uwsgi_log("[cache-sync] invalid cache block size, expected %llu received %llu\n", (unsigned long long) uc->blocksize, (unsigned long long) num);
exit(1);
@@ -200,6 +200,40 @@ static void uwsgi_cache_load_files(struct uwsgi_cache *uc) {
next:
usl = usl->next;
}
#ifdef UWSGI_ZLIB
usl = uwsgi.load_file_in_cache_gzip;
while(usl) {
size_t len = 0;
char *value = NULL;
char *key = usl->value;
uint16_t key_len = usl->len;
char *space = strchr(usl->value, ' ');
if (space) {
// need to skip ?
if (uwsgi_strncmp(uc->name, uc->name_len, usl->value, space-usl->value)) {
goto next2;
}
key = space+1;
key_len = usl->len - ((space-usl->value)+1);
}
value = uwsgi_open_and_read(key, &len, 0, NULL);
if (value) {
struct uwsgi_buffer *gzipped = uwsgi_gzip(value, len);
if (gzipped) {
uwsgi_wlock(uc->lock);
if (!uwsgi_cache_set2(uc, key, key_len, gzipped->buf, gzipped->len, 0, 0)) {
uwsgi_log("[cache-gzip] stored \"%.*s\" in \"%s\"\n", key_len, key, uc->name);
}
uwsgi_rwunlock(uc->lock);
uwsgi_buffer_destroy(gzipped);
}
free(value);
}
next2:
usl = usl->next;
}
#endif
}
@@ -382,6 +416,46 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
return NULL;
}
int64_t uwsgi_cache_num2(struct uwsgi_cache *uc, char *key, uint16_t keylen) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
if (index) {
struct uwsgi_cache_item *uci = cache_item(index);
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
return 0;
uci->hits++;
uc->hits++;
int64_t *num = (int64_t *) (uc->data + (uci->first_block * uc->blocksize));
return *num;
}
uc->miss++;
return 0;
}
char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize, uint64_t *expires) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
if (index) {
struct uwsgi_cache_item *uci = cache_item(index);
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
return NULL;
*valsize = uci->valsize;
if (expires)
*expires = uci->expires;
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
}
uc->miss++;
return NULL;
}
int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t index, uint16_t flags) {
struct uwsgi_cache_item *uci;
@@ -427,6 +501,10 @@ int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_
uci->expires = 0;
uc->n_items--;
if (uc->use_last_modified) {
uc->last_modified_at = uwsgi_now();
}
}
if (uc->nodes && ret == 0 && !(flags & UWSGI_CACHE_FLAG_LOCAL)) {
@@ -473,6 +551,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uint8_t rollback_mode = 0;
int ret = -1;
time_t now = 0;
if (!keylen || !vallen)
return -1;
@@ -482,6 +561,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
if (vallen > uc->max_item_size) return -1;
if ((flags & UWSGI_CACHE_FLAG_MATH) && vallen != 8) return -1;
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) {
@@ -518,13 +599,13 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uc->unused_blocks_stack_ptr++;
}
else if (rollback_mode == 2) {
uc->first_available_block--;
uc->first_available_block--;
}
goto end;
}
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize teh scan
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
@@ -532,14 +613,42 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
}
}
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE))
expires += uwsgi_now();
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
}
uci->expires = expires;
uci->hash = uc->hash->func(key, keylen);
uci->hits = 0;
uci->flags = flags;
memcpy(uci->key, key, keylen);
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
}
// ok math operations here
else {
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
*num = uc->math_initial;
int64_t *delta = (int64_t *) val;
if (flags & UWSGI_CACHE_FLAG_INC) {
*num += *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DEC) {
*num -= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_MUL) {
*num *= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DIV) {
if (*delta == 0) {
*num = 0;
}
else {
*num /= *delta;
}
}
}
// set this as late as possibile (to reduce races risk)
@@ -571,8 +680,9 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
}
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
uci = cache_item(index);
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
expires += uwsgi_now();
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
now = uwsgi_now();
expires += now;
uci->expires = expires;
}
if (uc->blocks_bitmap) {
@@ -597,11 +707,38 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
// unmark the old blocks
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
}
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
}
else {
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
int64_t *delta = (int64_t *) val;
if (flags & UWSGI_CACHE_FLAG_INC) {
*num += *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DEC) {
*num -= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_MUL) {
*num *= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DIV) {
if (*delta == 0) {
*num = 0;
}
else {
*num /= *delta;
}
}
}
uci->valsize = vallen;
ret = 0;
}
if (uc->use_last_modified) {
uc->last_modified_at = (now ? now : uwsgi_now());
}
if (uc->nodes && ret == 0 && !(flags & UWSGI_CACHE_FLAG_LOCAL)) {
cache_send_udp_command(uc, key, keylen, val, vallen, expires, 10);
}
@@ -879,6 +1016,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
uc->nodes = uwsgi.cache_udp_node;
uc->udp_servers = uwsgi.cache_udp_server;
uc->store_sync = uwsgi.cache_store_sync;
uc->use_last_modified = (uint8_t) uwsgi.cache_use_last_modified;
if (uwsgi.cache_sync) {
uwsgi_string_new_list(&uc->sync_nodes, uwsgi.cache_sync);
@@ -898,6 +1036,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_sync = NULL;
char *c_udp_servers = NULL;
char *c_bitmap = NULL;
char *c_use_last_modified = NULL;
char *c_math_initial = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"name", &c_name,
@@ -923,6 +1063,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"udpservers", &c_udp_servers,
"udpserver", &c_udp_servers,
"bitmap", &c_bitmap,
"lastmod", &c_use_last_modified,
"math_initial", &c_math_initial,
NULL)) {
uwsgi_log("unable to parse cache definition\n");
exit(1);
@@ -967,6 +1109,9 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
uc->use_blocks_bitmap = 1;
uc->max_item_size = uc->blocksize * uc->blocks;
}
if (c_use_last_modified) uc->use_last_modified = 1;
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
uc->store_sync = uwsgi.cache_store_sync;
if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); }
@@ -1233,7 +1378,7 @@ static int cache_magic_send_and_manage(int fd, struct uwsgi_buffer *ub, char *st
return 0;
}
char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char *cache) {
char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64_t *expires, char *cache) {
struct uwsgi_cache_magic_context ucmc;
struct uwsgi_cache *uc = NULL;
char *cache_server = NULL;
@@ -1258,7 +1403,7 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char *
// we have a local cache !!!
if (uc) {
uwsgi_rlock(uc->lock);
char *value = uwsgi_cache_get2(uc, key, keylen, vallen);
char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires);
if (!value) {
uwsgi_rwunlock(uc->lock);
return NULL;
@@ -1328,6 +1473,9 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char *
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
*vallen = ucmc.size;
if (expires) {
*expires = ucmc.expires;
}
return value;
}
@@ -1625,7 +1773,6 @@ int uwsgi_cache_magic_clear(char *cache) {
void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
struct uwsgi_string_list *usl = uc->sync_nodes;
usl = uc->sync_nodes;
while(usl) {
uwsgi_log("[cache-sync] getting cache dump from %s ...\n", usl->value);
int fd = uwsgi_connect(usl->value, 0, 0);
@@ -1663,7 +1810,7 @@ void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
goto next;
}
uwsgi_hooked_parse(ub->buf, ub->pos, cache_sync_hook, uc);
uwsgi_hooked_parse(ub->buf, rlen, cache_sync_hook, uc);
if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
+172
View File
@@ -0,0 +1,172 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_cron *uwsgi_cron_add(char *crontab) {
int i;
struct uwsgi_cron *old_uc, *uc = uwsgi.crons;
if (!uc) {
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
uwsgi.crons = uc;
}
else {
old_uc = uc;
while (uc->next) {
uc = uc->next;
old_uc = uc;
}
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
uc = old_uc->next;
}
memset(uc, 0, sizeof(struct uwsgi_cron));
if (sscanf(crontab, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) {
uwsgi_log("invalid cron syntax\n");
exit(1);
}
uc->command = crontab + i;
return uc;
}
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
uwsgi_cron_add(value);
}
#ifdef UWSGI_SSL
void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) {
char *space = strchr(value, ' ');
if (!space) {
uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt);
exit(1);
}
char *legion = uwsgi_concat2n(value, space-value, "", 0);
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
uc->legion = legion;
}
#endif
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
if (!uwsgi.master_process)
return -1;
uwsgi_lock(uwsgi.cron_table_lock);
if (ushared->cron_cnt < MAX_CRONS) {
ushared->cron[ushared->cron_cnt].sig = sig;
ushared->cron[ushared->cron_cnt].minute = minute;
ushared->cron[ushared->cron_cnt].hour = hour;
ushared->cron[ushared->cron_cnt].day = day;
ushared->cron[ushared->cron_cnt].month = month;
ushared->cron[ushared->cron_cnt].week = week;
ushared->cron_cnt++;
}
else {
uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS);
uwsgi_unlock(uwsgi.cron_table_lock);
return -1;
}
uwsgi_unlock(uwsgi.cron_table_lock);
return 0;
}
void uwsgi_manage_signal_cron(time_t now) {
struct tm *uwsgi_cron_delta;
int i;
uwsgi_cron_delta = localtime(&now);
if (uwsgi_cron_delta) {
// fix month
uwsgi_cron_delta->tm_mon++;
uwsgi_lock(uwsgi.cron_table_lock);
for (i = 0; i < ushared->cron_cnt; i++) {
struct uwsgi_cron *ucron = &ushared->cron[i];
int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, ucron->minute, ucron->hour, ucron->day, ucron->month, ucron->week);
if (run_task == 1) {
// date match, signal it ?
if (now - ucron->last_job >= 60) {
uwsgi_route_signal(ucron->sig);
ucron->last_job = now;
}
}
}
uwsgi_unlock(uwsgi.cron_table_lock);
}
else {
uwsgi_error("localtime()");
}
}
void uwsgi_manage_command_cron(time_t now) {
struct tm *uwsgi_cron_delta;
struct uwsgi_cron *current_cron = uwsgi.crons;
uwsgi_cron_delta = localtime(&now);
if (!uwsgi_cron_delta) {
uwsgi_error("uwsgi_manage_command_cron()/localtime()");
return;
}
// fix month
uwsgi_cron_delta->tm_mon++;
while (current_cron) {
#ifdef UWSGI_SSL
// check for legion cron
if (current_cron->legion) {
if (!uwsgi_legion_i_am_the_lord(current_cron->legion)) {
current_cron = current_cron->next;
continue;
}
}
#endif
int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, current_cron->minute, current_cron->hour, current_cron->day, current_cron->month, current_cron->week);
if (run_task == 1) {
// date match, run command ?
if (now - current_cron->last_job >= 60) {
//call command
if (current_cron->command) {
if (current_cron->func) {
current_cron->func(current_cron, now);
}
else {
if (uwsgi_run_command(current_cron->command, NULL, -1) >= 0) {
uwsgi_log_verbose("[uwsgi-cron] running %s\n", current_cron->command);
}
}
}
current_cron->last_job = now;
}
}
current_cron = current_cron->next;
}
}
+96 -6
View File
@@ -1,4 +1,4 @@
#include "../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -42,6 +42,31 @@ void uwsgi_daemons_smart_check() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
#ifdef UWSGI_SSL
if (ud->legion) {
if (uwsgi_legion_i_am_the_lord(ud->legion)) {
// lord, spawn if not running
if (ud->pid <= 0) {
uwsgi_spawn_daemon(ud);
}
}
else {
// not lord, kill daemon if running
if (ud->pid > 0) {
if (!kill(ud->pid, 0)) {
uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid);
kill(-ud->pid, SIGTERM);
}
else {
// pid already died
ud->pid = -1;
}
}
ud = ud->next;
continue;
}
}
#endif
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
@@ -70,12 +95,13 @@ void uwsgi_daemons_smart_check() {
}
}
// this function is called when a dumb daemon dies and we do not wat to respawn it
// this function is called when a dumb daemon dies and we do not want to respawn it
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
ud->pid = -1;
return -1;
}
ud = ud->next;
@@ -87,6 +113,15 @@ int uwsgi_daemon_check_pid_death(pid_t diedpid) {
int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
#ifdef UWSGI_SSL
if (ud->pid == diedpid && ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
// part of legion but not lord, don't respawn
ud->pid = -1;
uwsgi_log("uwsgi-daemons] legion \"%s\" daemon \"%s\" (pid: %d) annihilated\n", ud->legion, ud->command, (int) diedpid);
ud = ud->next;
continue;
}
#endif
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_spawn_daemon(ud);
return 1;
@@ -133,6 +168,19 @@ void uwsgi_daemons_spawn_all() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (!ud->registered) {
#ifdef UWSGI_SSL
if (ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
// part of legion, register but don't spawn it yet
if (ud->pidfile) {
ud->pid = uwsgi_check_pidfile(ud->pidfile);
if (ud->pid > 0)
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
}
ud->registered = 1;
ud = ud->next;
continue;
}
#endif
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
@@ -156,8 +204,29 @@ void uwsgi_daemons_spawn_all() {
void uwsgi_detach_daemons() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0 && !ud->pidfile)
kill(-ud->pid, SIGKILL);
#ifdef UWSGI_SSL
// stop any legion daemon, doesn't matter if dumb or smart
if (ud->pid > 0 && (ud->legion || !ud->pidfile)) {
#else
// stop only dumb daemons
if (ud->pid > 0 && !ud->pidfile) {
#endif
uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command);
// try to gracefully stop daemon, kill it if it won't die
// if mercy is not set than wait up to 3 seconds
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
while (!kill(ud->pid, 0)) {
kill(-ud->pid, SIGTERM);
sleep(1);
if (uwsgi_now() >= timeout) {
uwsgi_log("[uwsgi-daemons] daemon did not died in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
kill(-ud->pid, SIGKILL);
break;
}
}
// unregister daemon to prevent it from being respawned
ud->registered = 0;
}
ud = ud->next;
}
}
@@ -165,6 +234,9 @@ void uwsgi_detach_daemons() {
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
// skip unregistered daemons
if (!ud->registered) return;
int devnull = -1;
int throttle = 0;
@@ -261,11 +333,26 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
char *pidfile = NULL;
int daemonize = 0;
int freq = 10;
char *space = NULL;
char *command = uwsgi_str(value);
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2")) {
char *space = strchr(command, ' ');
#ifdef UWSGI_SSL
char *legion = NULL;
if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) {
space = strchr(command, ' ');
if (!space) {
uwsgi_log("invalid legion daemon syntax: %s\n", command);
exit(1);
}
*space = 0;
legion = command;
command = space+1;
}
#endif
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) {
space = strchr(command, ' ');
if (!space) {
uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command);
exit(1);
@@ -308,6 +395,9 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi_ud->last_spawn = 0;
uwsgi_ud->daemonize = daemonize;
uwsgi_ud->pidfile = pidfile;
#ifdef UWSGI_SSL
uwsgi_ud->legion = legion;
#endif
uwsgi.daemons_cnt++;
+3 -3
View File
@@ -322,7 +322,7 @@ void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) {
if (do_exit) goto check_catch;
if (wsgi_req && uwsgi.exception_handlers_instance) {
if (uwsgi.exception_handlers_instance) {
struct uwsgi_buffer *ehi = uwsgi_exception_handler_object(wsgi_req);
if (ehi) {
uwsgi_exception_run_handlers(ehi);
@@ -442,7 +442,7 @@ static void uwsgi_exception_handler_thread_loop(struct uwsgi_thread *ut) {
int interesting_fd = -1;
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret > 0) {
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
ssize_t len = read(ut->pipe[1], buf, uwsgi.exception_handler_msg_size + sizeof(long));
if (len > (ssize_t)(sizeof(long) + 1)) {
size_t msg_size = len - sizeof(long);
char *msg = buf + sizeof(long);
@@ -488,7 +488,7 @@ void uwsgi_exception_setup_handlers() {
}
void uwsgi_exceptions_handler_thread_start() {
if (!uwsgi.exception_handlers_instance) return;
// start the exception_handler_thread
uwsgi.exception_handler_thread = uwsgi_thread_new(uwsgi_exception_handler_thread_loop);
if (!uwsgi.exception_handler_thread) {
+10 -1
View File
@@ -18,7 +18,9 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
}
}
char *fullname = uwsgi_concat3(name, " ", uwsgi_num2str(num));
char *str = uwsgi_num2str(num);
char *fullname = uwsgi_concat3(name, " ", str);
free(str);
ug = &ushared->gateways[ushared->gateways_cnt];
ug->pid = 0;
@@ -28,10 +30,17 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
ug->fullname = fullname;
ug->data = data;
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ug->internal_subscription_pipe)) {
#else
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) {
#endif
uwsgi_error("socketpair()");
}
uwsgi_socket_nb(ug->internal_subscription_pipe[0]);
uwsgi_socket_nb(ug->internal_subscription_pipe[1]);
if (!uwsgi.master_process)
gateway_respawn(ushared->gateways_cnt);
+4
View File
@@ -347,6 +347,10 @@ void uwsgi_setup_workers() {
// allocate signal table
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
#ifdef UWSGI_ROUTING
uwsgi_fixup_routes();
#endif
}
pid_t uwsgi_daemonize2() {
+75 -3
View File
@@ -955,6 +955,8 @@ readok2:
int uwsgi_proxy_nb(struct wsgi_request *wsgi_req, char *addr, struct uwsgi_buffer *ub, size_t remains, int timeout) {
struct uwsgi_buffer *headers = NULL;
int fd = uwsgi_connect(addr, 0, 1);
if (fd < 0) {
return -1;
@@ -988,21 +990,91 @@ int uwsgi_proxy_nb(struct wsgi_request *wsgi_req, char *addr, struct uwsgi_buffe
}
// read the response
headers = uwsgi_buffer_new(8192);
// max 64k headers
ub->limit = UMAX16;
for(;;) {
char buf[8192];
ssize_t rlen = uwsgi_read_true_nb(fd, buf, 8192, timeout);
if (rlen > 0) {
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
break;
}
if (headers) {
if (uwsgi_buffer_append(headers, buf, rlen)) {
goto end;
}
// check if we have a full HTTP response
if (uwsgi_is_full_http(headers)) {
int ret = uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos);
if (ret) continue;
uwsgi_buffer_destroy(headers);
headers = NULL;
}
}
else {
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
break;
}
}
continue;
}
break;
}
if (headers) uwsgi_buffer_destroy(headers);
close(fd);
return 0;
end:
if (headers) uwsgi_buffer_destroy(headers);
close(fd);
return -1;
}
void uwsgi_file_write_do(struct uwsgi_string_list *usl) {
struct uwsgi_string_list *fl = usl;
while(fl) {
char *equal = strchr(fl->value, '=');
if (equal) {
*equal = 0;
FILE *f = fopen(fl->value, "w");
if (!f) {
uwsgi_error_open("uwsgi_file_write_do()");
exit(1);
}
uwsgi_log("writing \"%s\" to \"%s\" ...\n", equal+1, fl->value);
if (fprintf(f, "%s\n", equal+1) <= 0 || ferror(f) || fclose(f)) {
uwsgi_error("uwsgi_file_write_do()");
exit(1);
}
}
else {
uwsgi_log("unable to write empty value for \"%s\"\n", fl->value);
exit(1);
}
*equal = '=';
fl = fl->next;
}
}
int uwsgi_fd_is_safe(int fd) {
int i;
for(i=0;i<uwsgi.safe_fds_cnt;i++) {
if (uwsgi.safe_fds[i] == fd) {
return 1;
}
}
return 0;
}
void uwsgi_add_safe_fd(int fd) {
// check if the fd is already safe
if (uwsgi_fd_is_safe(fd)) return;
size_t len = sizeof(int) * (uwsgi.safe_fds_cnt+1);
int *tmp = realloc(uwsgi.safe_fds, len);
if (!tmp) {
uwsgi_error("uwsgi_add_safe_fd()/realloc()");
exit(1);
}
uwsgi.safe_fds = tmp;
uwsgi.safe_fds[uwsgi.safe_fds_cnt] = fd;
uwsgi.safe_fds_cnt++;
}
+47 -10
View File
@@ -206,7 +206,7 @@ static void legions_check_nodes() {
if (now - node->last_seen > uwsgi.legion_tolerance) {
struct uwsgi_legion_node *tmp_node = node;
node = node->next;
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s left Legion %s\n", tmp_node->name_len, tmp_node->name, tmp_node->valor, 36, tmp_node->uuid, legion->legion);
uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s left Legion %s\n", tmp_node->valor > 0 ? "node" : "arbiter", tmp_node->name_len, tmp_node->name, tmp_node->valor, 36, tmp_node->uuid, legion->legion);
uwsgi_wlock(legion->lock);
uwsgi_legion_remove_node(legion, tmp_node);
uwsgi_rwunlock(legion->lock);
@@ -232,12 +232,12 @@ struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *);
static void legions_report_quorum(struct uwsgi_legion *ul, uint64_t best_valor, char *best_uuid, int votes) {
struct uwsgi_legion_node *nodes = ul->nodes_head;
uwsgi_log("\n[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu votes: %d) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum, votes);
uwsgi_log("[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu votes: %d) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum, votes);
while (nodes) {
uwsgi_log("[uwsgi-legion-node] node: %.*s valor: %llu uuid: %.*s last_seen: %d vote_valor: %llu vote_uuid: %.*s\n", nodes->name_len, nodes->name, nodes->valor, 36, nodes->uuid, nodes->last_seen, nodes->lord_valor, 36, nodes->lord_uuid);
uwsgi_log("[uwsgi-legion-node] %s: %.*s valor: %llu uuid: %.*s last_seen: %d vote_valor: %llu vote_uuid: %.*s\n", nodes->valor > 0 ? "node" : "arbiter", nodes->name_len, nodes->name, nodes->valor, 36, nodes->uuid, nodes->last_seen, nodes->lord_valor, 36, nodes->lord_uuid);
nodes = nodes->next;
}
uwsgi_log("[uwsgi-legion] --- END OF QUORUM REPORT ---\n\n");
uwsgi_log("[uwsgi-legion] --- END OF QUORUM REPORT ---\n");
}
uint64_t uwsgi_legion_checksum(struct uwsgi_legion *ul) {
@@ -273,12 +273,17 @@ static void legions_check_nodes_step2() {
best_valor = node->valor;
memcpy(best_uuid, node->uuid, 36);
}
else {
// go on if i am not an arbiter
else if (ul->valor > 0) {
// no potential Lord is available, i will propose myself
best_valor = ul->valor;
memcpy(best_uuid, ul->uuid, 36);
i_am_the_best = 1;
}
else {
// empty lord
memset(best_uuid, 0, 36);
}
// calculate the checksum
uint64_t new_checksum = uwsgi_legion_checksum(ul);
@@ -357,9 +362,9 @@ static void legions_check_nodes_step2() {
if (ul->i_am_the_lord) {
uwsgi_log("[uwsgi-legion] a new Lord (valor: %llu uuid: %.*s) raised for Legion %s...\n", ul->lord_valor, 36, ul->lord_uuid, ul->legion);
if (ul->lord_scroll_len > 0) {
uwsgi_log("*********** The New Lord Scroll ***********\n\n");
uwsgi_log("*********** The New Lord Scroll ***********\n");
uwsgi_log("%.*s\n", ul->lord_scroll_len, ul->lord_scroll);
uwsgi_log("\n*********** End of the New Lord Scroll ***********\n\n");
uwsgi_log("*********** End of the New Lord Scroll ***********\n");
}
// no more lord, trigger unlord hooks
struct uwsgi_string_list *usl = ul->unlord_hooks;
@@ -376,6 +381,20 @@ static void legions_check_nodes_step2() {
}
else if (votes > 0 && votes < ul->quorum && (uwsgi_now() - ul->last_warning >= 60)) {
uwsgi_log("[uwsgi-legion] no quorum: only %d vote(s) for Legion %s, %d needed to elect a Lord\n", votes, ul->legion, ul->quorum);
// no more quorum, leave the Lord state
if (ul->i_am_the_lord) {
uwsgi_log("[uwsgi-legion] i cannot be The Lord of The Legion %s without a quorum ...\n", ul->legion);
// no more lord, trigger unlord hooks
struct uwsgi_string_list *usl = ul->unlord_hooks;
while (usl) {
int ret = uwsgi_legion_action_call("unlord", ul, usl);
if (ret) {
uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret);
}
usl = usl->next;
}
ul->i_am_the_lord = 0;
}
ul->last_warning = uwsgi_now();
}
@@ -395,6 +414,8 @@ struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *ul) {
struct uwsgi_legion_node *nodes = ul->nodes_head;
while (nodes) {
// skip arbiters
if (nodes->valor == 0) goto next;
if (nodes->valor > best_valor) {
best_node = nodes;
best_valor = nodes->valor;
@@ -407,11 +428,12 @@ struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *ul) {
memcpy(best_uuid, nodes->uuid, 36);
}
}
next:
nodes = nodes->next;
}
// first round ?
if (ul->lord_valor == 0) {
// first round ? (skip first round if arbiter)
if (ul->valor > 0 && ul->lord_valor == 0) {
ul->changed = 1;
}
else if (best_valor != ul->lord_valor) {
@@ -578,7 +600,7 @@ static void *legion_loop(void *foobar) {
// we are still locked (and safe), let's rebuild the scrolls list
legion_rebuild_scrolls(ul);
uwsgi_rwunlock(ul->lock);
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->valor > 0 ? "node" : "arbiter", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
// trigger node_joined hooks
struct uwsgi_string_list *usl = ul->node_joined_hooks;
while (usl) {
@@ -775,6 +797,21 @@ err:
return -1;
}
void uwsgi_opt_legion_mcast(char *opt, char *value, void *foobar) {
uwsgi_opt_legion(opt, value, foobar);
char *legion = uwsgi_str(value);
char *space = strchr(legion, ' ');
// over engineering
if (!space) exit(1);
*space = 0;
struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
if (!ul) {
uwsgi_log("unknown legion: %s\n", legion);
exit(1);
}
uwsgi_legion_register_node(ul, uwsgi_str(ul->addr));
}
void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) {
char *legion = uwsgi_str(value);
+3 -3
View File
@@ -474,8 +474,6 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
#define UWSGI_LOCK_ENGINE_NAME "ipcsem"
#define UWSGI_IPCSEM_ATEXIT 1
#endif
struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
@@ -661,7 +659,9 @@ ready:
// application generic lock
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
for (i = 0; i < uwsgi.locks + 1; i++) {
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i)));
char *num = uwsgi_num2str(i);
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", num));
free(num);
}
// event queue lock (mitigate same event on multiple queues)
+20
View File
@@ -473,6 +473,18 @@ int master_loop(char **argv, char **environ) {
uwsgi_check_touches(uwsgi.touch_chain_reload);
uwsgi_check_touches(uwsgi.touch_workers_reload);
uwsgi_check_touches(uwsgi.touch_gracefully_stop);
// update exec touches
struct uwsgi_string_list *usl = uwsgi.touch_exec;
while(usl) {
char *space = strchr(usl->value, ' ');
if (space) {
*space = 0;
usl->len = strlen(usl->value);
usl->custom_ptr = space + 1;
}
usl = usl->next;
}
uwsgi_check_touches(uwsgi.touch_exec);
// setup cheaper algos (can be stacked)
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
@@ -748,6 +760,14 @@ int master_loop(char **argv, char **environ) {
uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched);
}
}
// be sure to run it as the last touch check
touched = uwsgi_check_touches(uwsgi.touch_exec);
if (touched) {
if (uwsgi_run_command( touched , NULL, -1) >= 0) {
uwsgi_log_verbose("[uwsgi-touch-exec] running %s\n", touched);
}
}
}
continue;
+1
View File
@@ -177,6 +177,7 @@ void uwsgi_master_check_gateways_deadline() {
if (ushared->gateways_harakiri[i] > 0) {
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
if (ushared->gateways[i].pid > 0) {
uwsgi_log("*** HARAKIRI ON GATEWAY %s %d (pid: %d) ***\n", ushared->gateways[i].name, ushared->gateways[i].num, ushared->gateways[i].pid);
kill(ushared->gateways[i].pid, SIGKILL);
}
ushared->gateways_harakiri[i] = 0;
+71 -175
View File
@@ -351,6 +351,9 @@ void uwsgi_reload(char **argv) {
/* check fd table (a module can obviosly open some fd on initialization...) */
uwsgi_log("closing all non-uwsgi socket fds > 2 (max_fd = %d)...\n", (int) uwsgi.max_fd);
for (i = 3; i < (int) uwsgi.max_fd; i++) {
if (uwsgi_fd_is_safe(i)) continue;
int found = 0;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
@@ -413,6 +416,13 @@ void uwsgi_reload(char **argv) {
#endif
}
#ifndef UWSGI_IPCSEM_ATEXIT
// free ipc semaphores if in use
if (uwsgi.lock_engine && !strcmp(uwsgi.lock_engine, "ipcsem")) {
uwsgi_ipcsem_clear();
}
#endif
uwsgi_log("running %s\n", uwsgi.binary_path);
uwsgi_flush_logs();
argv[0] = uwsgi.binary_path;
@@ -630,178 +640,6 @@ int uwsgi_respawn_worker(int wid) {
return 0;
}
void uwsgi_manage_signal_cron(time_t now) {
struct tm *uwsgi_cron_delta;
int i;
uwsgi_cron_delta = localtime(&now);
if (uwsgi_cron_delta) {
// fix month
uwsgi_cron_delta->tm_mon++;
uwsgi_lock(uwsgi.cron_table_lock);
for (i = 0; i < ushared->cron_cnt; i++) {
struct uwsgi_cron *ucron = &ushared->cron[i];
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
uc_minute = ucron->minute;
uc_hour = ucron->hour;
uc_day = ucron->day;
uc_month = ucron->month;
uc_week = ucron->week;
// negative values as interval -1 = * , -5 = */5
if (ucron->minute < 0) {
if ((uwsgi_cron_delta->tm_min % abs(ucron->minute)) == 0) {
uc_minute = uwsgi_cron_delta->tm_min;
}
}
if (ucron->hour < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(ucron->hour)) == 0) {
uc_hour = uwsgi_cron_delta->tm_hour;
}
}
if (ucron->month < 0) {
if ((uwsgi_cron_delta->tm_mon % abs(ucron->month)) == 0) {
uc_month = uwsgi_cron_delta->tm_mon;
}
}
if (ucron->day < 0) {
if ((uwsgi_cron_delta->tm_mday % abs(ucron->day)) == 0) {
uc_day = uwsgi_cron_delta->tm_mday;
}
}
if (ucron->week < 0) {
if ((uwsgi_cron_delta->tm_wday % abs(ucron->week)) == 0) {
uc_week = uwsgi_cron_delta->tm_wday;
}
}
int run_task = 0;
// mday and wday are ORed
if (ucron->day >= 0 && ucron->week >= 0) {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
run_task = 1;
}
}
else {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
run_task = 1;
}
}
if (run_task == 1) {
// date match, signal it ?
if (now - ucron->last_job > 60) {
uwsgi_route_signal(ucron->sig);
ucron->last_job = now;
}
}
}
uwsgi_unlock(uwsgi.cron_table_lock);
}
else {
uwsgi_error("localtime()");
}
}
void uwsgi_manage_command_cron(time_t now) {
struct tm *uwsgi_cron_delta;
struct uwsgi_cron *current_cron = uwsgi.crons;
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
uwsgi_cron_delta = localtime(&now);
if (!uwsgi_cron_delta) {
uwsgi_error("localtime()");
return;
}
// fix month
uwsgi_cron_delta->tm_mon++;
while (current_cron) {
uc_minute = current_cron->minute;
uc_hour = current_cron->hour;
uc_day = current_cron->day;
uc_month = current_cron->month;
uc_week = current_cron->week;
// negative values as interval -1 = * , -5 = */5
if (current_cron->minute < 0) {
if ((uwsgi_cron_delta->tm_min % abs(current_cron->minute)) == 0) {
uc_minute = uwsgi_cron_delta->tm_min;
}
}
if (current_cron->hour < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(current_cron->hour)) == 0) {
uc_hour = uwsgi_cron_delta->tm_hour;
}
}
if (current_cron->month < 0) {
if ((uwsgi_cron_delta->tm_mon % abs(current_cron->month)) == 0) {
uc_month = uwsgi_cron_delta->tm_mon;
}
}
if (current_cron->day < 0) {
if ((uwsgi_cron_delta->tm_mday % abs(current_cron->day)) == 0) {
uc_day = uwsgi_cron_delta->tm_mday;
}
}
if (current_cron->week < 0) {
if ((uwsgi_cron_delta->tm_wday % abs(current_cron->week)) == 0) {
uc_week = uwsgi_cron_delta->tm_wday;
}
}
int run_task = 0;
// mday and wday are ORed
if (current_cron->day >= 0 && current_cron->week >= 0) {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
run_task = 1;
}
}
else {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
run_task = 1;
}
}
if (run_task == 1) {
// date match, run command ?
if (now - current_cron->last_job > 60) {
//call command
if (current_cron->command) {
if (uwsgi_run_command(current_cron->command, NULL, -1) >= 0) {
uwsgi_log_verbose("[uWSGI-cron] running %s\n", current_cron->command);
}
}
current_cron->last_job = now;
}
}
current_cron = current_cron->next;
}
}
struct uwsgi_stats *uwsgi_master_generate_stats() {
int i;
@@ -854,9 +692,9 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
if (uwsgi_stats_keyval_comma(us, "cmd", ud->command))
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) ud->pid))
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) (ud->pid < 0) ? 0 : ud->pid))
goto end;
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) (ud->respawns - 1)))
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) ud->respawns ? 0 : ud->respawns))
goto end;
if (uwsgi_stats_object_close(us))
goto end;
@@ -940,7 +778,10 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keylong_comma(us, "miss", (unsigned long long) uc->miss))
goto end;
if (uwsgi_stats_keylong(us, "full", (unsigned long long) uc->full))
if (uwsgi_stats_keylong_comma(us, "full", (unsigned long long) uc->full))
goto end;
if (uwsgi_stats_keylong(us, "last_modified_at", (unsigned long long) uc->last_modified_at))
goto end;
if (uwsgi_stats_object_close(us))
@@ -1485,3 +1326,58 @@ void uwsgi_master_fix_request_counters() {
uwsgi.workers[0].requests = total_counter;
}
int uwsgi_cron_task_needs_execution(struct tm *uwsgi_cron_delta, int minute, int hour, int day, int month, int week) {
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
uc_minute = minute;
uc_hour = hour;
uc_day = day;
uc_month = month;
uc_week = week;
// negative values as interval -1 = * , -5 = */5
if (minute < 0) {
if ((uwsgi_cron_delta->tm_min % abs(minute)) == 0) {
uc_minute = uwsgi_cron_delta->tm_min;
}
}
if (hour < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(hour)) == 0) {
uc_hour = uwsgi_cron_delta->tm_hour;
}
}
if (month < 0) {
if ((uwsgi_cron_delta->tm_mon % abs(month)) == 0) {
uc_month = uwsgi_cron_delta->tm_mon;
}
}
if (day < 0) {
if ((uwsgi_cron_delta->tm_mday % abs(day)) == 0) {
uc_day = uwsgi_cron_delta->tm_mday;
}
}
if (week < 0) {
if ((uwsgi_cron_delta->tm_wday % abs(week)) == 0) {
uc_week = uwsgi_cron_delta->tm_wday;
}
}
int run_task = 0;
// mday and wday are ORed
if (day >= 0 && week >= 0) {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
run_task = 1;
}
}
else {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
run_task = 1;
}
}
return run_task;
}
+29 -3
View File
@@ -77,9 +77,14 @@ struct uwsgi_metric {
// ABSOLUTE/COUNTER/GAUGE
uint8_t type;
// the value of the metric
int64_t value;
// MANUAL/PTR/FUNC/FILE
uint8_t collect_way
// this could be taken from a file storage and must laways be added to value when reporting (default 0)
int64_t initial_value;
// the value of the metric (point to a shared memory area)
*int64_t value;
// a custom blob you can attach to a metric
void *custom;
@@ -110,3 +115,24 @@ void uwsgi_metric_loop() {
// every second scan the whole metrics tree
time_t now = uwsgi_now();
}
int64_t uwsgi_metric_get(char *name, char *oid) {
struct uwsgi_metric *um = NULL;
if (name) {
um = uwsgi_metric_find_by_name(name);
}
else if (oid) {
um = uwsgi_metric_find_by_oid(oid);
}
if (!um) return 0;
//
switch(um->collect_way) {
case UWSGI_METRIC_MANUAL:
return um->initial_value+*um->value;
case UWSGI_METRIC_PTR:
return um->initial_value+*um->ptr;
case UWSGI_METRIC_FUNC:
case UWSGI_METRIC_FILE:
}
}
+2 -2
View File
@@ -441,7 +441,7 @@ void uwsgi_setup_mules_and_farms() {
mules_list++;
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
free(farm_value);
// create the socket pipe
create_signal_pipe(uwsgi.farms[i].signal_pipe);
@@ -462,7 +462,7 @@ void uwsgi_setup_mules_and_farms() {
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
farm_name = farm_name->next;
free(farm_value);
}
}
+1 -1
View File
@@ -72,7 +72,7 @@ int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offlo
return -1;
}
uor->fd = uwsgi_connect(uor->ubuf->buf, 0, 1);
uor->fd = uwsgi_connect(uor->name, 0, 1);
if (uor->fd < 0) {
uwsgi_error("u_offload_transfer_prepare()/connect()");
return -1;
+2 -2
View File
@@ -739,7 +739,7 @@ next:
// 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_magic_get(wsgi_req->cache_get, wsgi_req->cache_get_len, &cache_value_size, NULL);
char *cache_value = uwsgi_cache_magic_get(wsgi_req->cache_get, wsgi_req->cache_get_len, &cache_value_size, NULL, NULL);
if (cache_value && cache_value_size > 0) {
uwsgi_response_write_body_do(wsgi_req, cache_value, cache_value_size);
free(cache_value);
@@ -750,7 +750,7 @@ next:
if (uwsgi.check_cache && wsgi_req->uri_len && wsgi_req->method_len == 3 && wsgi_req->method[0] == 'G' && wsgi_req->method[1] == 'E' && wsgi_req->method[2] == 'T') {
uint64_t cache_value_size;
char *cache_value = uwsgi_cache_magic_get(wsgi_req->uri, wsgi_req->uri_len, &cache_value_size, NULL);
char *cache_value = uwsgi_cache_magic_get(wsgi_req->uri, wsgi_req->uri_len, &cache_value_size, NULL, NULL);
if (cache_value && cache_value_size > 0) {
uwsgi_response_write_body_do(wsgi_req, cache_value, cache_value_size);
free(cache_value);
+269 -53
View File
@@ -45,9 +45,13 @@ struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, stru
char *pass1 = data;
size_t pass1_len = data_len;
if (ur->condition_ub[wsgi_req->async_id] && ur->ovn[wsgi_req->async_id] > 0) {
pass1 = uwsgi_regexp_apply_ovec(ur->condition_ub[wsgi_req->async_id]->buf, ur->condition_ub[wsgi_req->async_id]->pos, data, data_len, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id]);
pass1_len = strlen(pass1);
}
// cannot fail
if (subject) {
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector, ur->ovn);
else if (subject) {
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id]);
pass1_len = strlen(pass1);
}
@@ -146,10 +150,25 @@ error:
return NULL;
}
static void uwsgi_routing_reset_memory(struct wsgi_request *wsgi_req, struct uwsgi_route *routes) {
// free dynamic memory structures
if (routes->if_func) {
routes->ovn[wsgi_req->async_id] = 0;
if (routes->ovector[wsgi_req->async_id]) {
free(routes->ovector[wsgi_req->async_id]);
routes->ovector[wsgi_req->async_id] = NULL;
}
if (routes->condition_ub[wsgi_req->async_id]) {
uwsgi_buffer_destroy(routes->condition_ub[wsgi_req->async_id]);
routes->condition_ub[wsgi_req->async_id] = NULL;
}
}
}
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
struct uwsgi_route *routes = uwsgi.routes;
void *goon_func = NULL;
int n = -1;
char *orig_subject = subject;
@@ -163,10 +182,6 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
goto next;
}
if (goon_func && goon_func == routes->func) {
goto next;
}
goon_func = NULL;
wsgi_req->route_goto = 0;
if (!routes->if_func) {
@@ -181,23 +196,26 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
subject = *subject2 ;
subject_len = *subject_len2;
}
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector, routes->ovn);
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector[wsgi_req->async_id], routes->ovn[wsgi_req->async_id]);
}
else {
int ret = routes->if_func(wsgi_req, routes);
// error
if (ret < 0) {
uwsgi_routing_reset_memory(wsgi_req, routes);
return UWSGI_ROUTE_BREAK;
}
// true
if (!routes->if_negate) {
if (ret == 0) {
uwsgi_routing_reset_memory(wsgi_req, routes);
goto next;
}
n = ret;
}
else {
if (ret > 0) {
uwsgi_routing_reset_memory(wsgi_req, routes);
goto next;
}
n = 1;
@@ -208,6 +226,7 @@ run:
if (n >= 0) {
wsgi_req->is_routing = 1;
int ret = routes->func(wsgi_req, routes);
uwsgi_routing_reset_memory(wsgi_req, routes);
wsgi_req->is_routing = 0;
if (ret == UWSGI_ROUTE_BREAK) {
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
@@ -217,10 +236,6 @@ run:
return ret;
}
if (ret == UWSGI_ROUTE_GOON) {
goon_func = routes->func;
}
if (ret == -1) {
return UWSGI_ROUTE_BREAK;
}
@@ -295,14 +310,14 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
return;
}
char *route = uwsgi_str(value);
ur->orig_route = uwsgi_str(value);
if (!strcmp(foobar, "run")) {
command = route;
command = ur->orig_route;
goto done;
}
space = strchr(route, ' ');
space = strchr(ur->orig_route, ' ');
if (!space) {
uwsgi_log("invalid route syntax\n");
exit(1);
@@ -311,7 +326,7 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
*space = 0;
if (!strcmp(foobar, "if") || !strcmp(foobar, "if-not")) {
char *colon = strchr(route, ':');
char *colon = strchr(ur->orig_route, ':');
if (!colon) {
uwsgi_log("invalid route condition syntax\n");
exit(1);
@@ -323,9 +338,9 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
}
foobar = colon+1;
ur->if_func = uwsgi_route_get_condition_func(route);
ur->if_func = uwsgi_route_get_condition_func(ur->orig_route);
if (!ur->if_func) {
uwsgi_log("unable to find \"%s\" route condition\n", route);
uwsgi_log("unable to find \"%s\" route condition\n", ur->orig_route);
exit(1);
}
}
@@ -365,18 +380,7 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
ur->subject_str = foobar;
ur->subject_str_len = strlen(ur->subject_str);
ur->regexp = route;
if (ur->subject && ur->subject_len) {
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
exit(1);
}
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
if (ur->ovn > 0) {
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
}
}
ur->regexp = ur->orig_route;
command = space + 1;
done:
@@ -394,16 +398,6 @@ done:
while (r) {
if (!strcmp(r->name, command)) {
if (r->func(ur, colon + 1) == 0) {
// apply is_last
struct uwsgi_route *last_ur = ur;
ur = uwsgi.routes;
while (ur) {
if (ur->func == last_ur->func) {
ur->is_last = 0;
}
ur = ur->next;
}
last_ur->is_last = 1;
return;
}
break;
@@ -415,6 +409,32 @@ done:
exit(1);
}
void uwsgi_fixup_routes() {
struct uwsgi_route *ur = uwsgi.routes;
while(ur) {
// prepare the main pointers
ur->ovn = uwsgi_calloc(sizeof(int) * uwsgi.cores);
ur->ovector = uwsgi_calloc(sizeof(int *) * uwsgi.cores);
ur->condition_ub = uwsgi_calloc( sizeof(struct uwsgi_buffer *) * uwsgi.cores);
// fill them if needed... (this is an optimization for route with a static subject)
if (ur->subject && ur->subject_len) {
if (uwsgi_regexp_build(ur->orig_route, &ur->pattern, &ur->pattern_extra)) {
exit(1);
}
int i;
for(i=0;i<uwsgi.cores;i++) {
ur->ovn[i] = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
if (ur->ovn[i] > 0) {
ur->ovector[i] = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn[i] + 1)));
}
}
}
ur = ur->next;
}
}
int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args) {
struct uwsgi_route *ur = NULL;
struct uwsgi_router *r = uwsgi.routers;
@@ -476,14 +496,49 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
return 0;
}
// goon route
static int uwsgi_router_goon_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
return UWSGI_ROUTE_GOON;
// flush response
static int transform_flush(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
// avoid loops !!!
if (ut->chunk->pos == 0) return 0;
wsgi_req->transformed_chunk = ut->chunk->buf;
wsgi_req->transformed_chunk_len = ut->chunk->pos;
int ret = uwsgi_response_write_body_do(wsgi_req, ut->chunk->buf, ut->chunk->pos);
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
ut->flushed = 1;
return ret;
}
static int uwsgi_router_goon(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_goon_func;
static int uwsgi_router_flush_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_flush, NULL);
ut->can_stream = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_flush(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_flush_func;
return 0;
}
// fix content length
static int transform_fixcl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
wsgi_req->write_errors++;
return -1;
}
// do not check for errors !!!
uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
return 0;
}
static int uwsgi_router_fixcl_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_add_transformation(wsgi_req, transform_fixcl, NULL);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_fixcl_func;
return 0;
}
// log route
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -506,6 +561,16 @@ static int uwsgi_router_log(struct uwsgi_route *ur, char *arg) {
return 0;
}
// do not log !!!
static int uwsgi_router_donotlog_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->do_not_log = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_donotlog(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_donotlog_func;
return 0;
}
// logvar route
static int uwsgi_router_logvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -711,6 +776,62 @@ static int uwsgi_router_setapp(struct uwsgi_route *ur, char *arg) {
return 0;
}
// setscriptname route
static int uwsgi_router_setscriptname_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
char *ptr = uwsgi_req_append(wsgi_req, "SCRIPT_NAME", 11, ub->buf, ub->pos);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->script_name = ptr;
wsgi_req->script_name_len = ub->pos;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setscriptname(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setscriptname_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setuser route
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint16_t user_len = ub->pos;
// stop at the first colon (useful for various tricks)
char *colon = memchr(ub->buf, ':', ub->pos);
if (colon) {
user_len = colon - ub->buf;
}
char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, ub->buf, user_len);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->remote_user = ptr;
wsgi_req->remote_user_len = ub->pos;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setuser(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setuser_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// sethome route
static int uwsgi_router_sethome_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -859,21 +980,25 @@ static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uw
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
ur->condition_ub[wsgi_req->async_id] = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ur->condition_ub[wsgi_req->async_id]) return -1;
pcre *pattern;
pcre_extra *pattern_extra;
char *re = uwsgi_concat2n(semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str), "", 0);
if (uwsgi_regexp_build(re, &pattern, &pattern_extra)) {
free(re);
uwsgi_buffer_destroy(ub);
return -1;
}
free(re);
if (uwsgi_regexp_match(pattern, pattern_extra, ub->buf, ub->pos) >= 0) {
uwsgi_buffer_destroy(ub);
// a condition has no initialized vectors, let's create them
ur->ovn[wsgi_req->async_id] = uwsgi_regexp_ovector(pattern, pattern_extra);
if (ur->ovn[wsgi_req->async_id] > 0) {
ur->ovector[wsgi_req->async_id] = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn[wsgi_req->async_id] + 1)));
}
if (uwsgi_regexp_match_ovec(pattern, pattern_extra, ur->condition_ub[wsgi_req->async_id]->buf, ur->condition_ub[wsgi_req->async_id]->pos, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id] ) >= 0) {
pcre_free(pattern);
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_free_study(pattern_extra);
@@ -883,7 +1008,6 @@ static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uw
return 1;
}
uwsgi_buffer_destroy(ub);
pcre_free(pattern);
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_free_study(pattern_extra);
@@ -1067,6 +1191,29 @@ static int uwsgi_route_condition_startswith(struct wsgi_request *wsgi_req, struc
return 0;
}
static int uwsgi_route_condition_contains(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if(uwsgi_contains_n(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
@@ -1080,7 +1227,7 @@ static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct
return -1;
}
if (ub2->pos < ub->pos) goto zero;
if (ub2->pos > ub->pos) goto zero;
if(!uwsgi_strncmp(ub->buf + (ub->pos - ub2->pos), ub2->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
@@ -1139,10 +1286,41 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
ret = uwsgi_num2str(uwsgi.mypid);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) {
ret = uwsgi_malloc(37);
uwsgi_uuid(ret);
*vallen = 36;
}
return ret;
}
static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
uint16_t var_vallen = 0;
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
if (var_value) {
size_t mime_type_len = 0;
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
if (ret) *vallen = mime_type_len;
}
return ret;
}
static char *uwsgi_route_var_httptime(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
// 30+1
char *ht = uwsgi_calloc(31);
size_t t = uwsgi_str_num(key, keylen);
int len = uwsgi_http_date(uwsgi_now() + t, ht);
if (len == 0) {
free(ht);
return NULL;
}
*vallen = len;
return ht;
}
static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
if (!uwsgi_strncmp(key, keylen, "unix", 4)) {
@@ -1152,6 +1330,29 @@ static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint
return ret;
}
static char *uwsgi_route_var_base64(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
uint16_t var_vallen = 0;
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
if (var_value) {
size_t b64_len = 0;
ret = uwsgi_base64_encode(var_value, var_vallen, &b64_len);
*vallen = b64_len;
}
return ret;
}
static char *uwsgi_route_var_hex(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
uint16_t var_vallen = 0;
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
if (var_value) {
ret = uwsgi_str_to_hex(var_value, var_vallen);
*vallen = var_vallen*2;
}
return ret;
}
#ifdef UWSGI_MATHEVAL
static char *uwsgi_route_var_math(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
@@ -1199,8 +1400,8 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("continue", uwsgi_router_continue);
uwsgi_register_router("last", uwsgi_router_continue);
uwsgi_register_router("break", uwsgi_router_break);
uwsgi_register_router("goon", uwsgi_router_goon);
uwsgi_register_router("log", uwsgi_router_log);
uwsgi_register_router("donotlog", uwsgi_router_donotlog);
uwsgi_register_router("logvar", uwsgi_router_logvar);
uwsgi_register_router("goto", uwsgi_router_goto);
uwsgi_register_router("addvar", uwsgi_router_addvar);
@@ -1212,11 +1413,16 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
uwsgi_register_router("chdir", uwsgi_router_chdir);
uwsgi_register_router("setapp", uwsgi_router_setapp);
uwsgi_register_router("setuser", uwsgi_router_setuser);
uwsgi_register_router("sethome", uwsgi_router_sethome);
uwsgi_register_router("setfile", uwsgi_router_setfile);
uwsgi_register_router("setscriptname", uwsgi_router_setscriptname);
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
uwsgi_register_router("alarm", uwsgi_router_alarm);
uwsgi_register_router("flush", uwsgi_router_flush);
uwsgi_register_router("fixcl", uwsgi_router_fixcl);
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
@@ -1238,6 +1444,8 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_route_condition(">=", uwsgi_route_condition_higherequal);
uwsgi_register_route_condition("islowerequal", uwsgi_route_condition_lowerequal);
uwsgi_register_route_condition("<=", uwsgi_route_condition_lowerequal);
uwsgi_register_route_condition("contains", uwsgi_route_condition_contains);
uwsgi_register_route_condition("contain", uwsgi_route_condition_contains);
#ifdef UWSGI_SSL
uwsgi_register_route_condition("lord", uwsgi_route_condition_lord);
#endif
@@ -1246,14 +1454,22 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_route_var("cookie", uwsgi_get_cookie);
uwsgi_register_route_var("qs", uwsgi_get_qs);
uwsgi_register_route_var("mime", uwsgi_route_var_mime);
struct uwsgi_route_var *urv = uwsgi_register_route_var("uwsgi", uwsgi_route_var_uwsgi);
urv->need_free = 1;
urv = uwsgi_register_route_var("time", uwsgi_route_var_time);
urv->need_free = 1;
urv = uwsgi_register_route_var("httptime", uwsgi_route_var_httptime);
urv->need_free = 1;
#ifdef UWSGI_MATHEVAL
urv = uwsgi_register_route_var("math", uwsgi_route_var_math);
urv->need_free = 1;
#endif
urv = uwsgi_register_route_var("base64", uwsgi_route_var_base64);
urv->need_free = 1;
urv = uwsgi_register_route_var("hex", uwsgi_route_var_hex);
urv->need_free = 1;
}
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
+5 -5
View File
@@ -1,8 +1,8 @@
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func) {
int uwsgi_register_rpc(char *name, struct uwsgi_plugin *plugin, uint8_t args, void *func) {
struct uwsgi_rpc *urpc;
int ret = -1;
@@ -30,7 +30,7 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
uwsgi.shared->rpc_count[uwsgi.mywid]++;
already:
memcpy(urpc->name, name, strlen(name));
urpc->modifier1 = modifier1;
urpc->plugin = plugin;
urpc->args = args;
urpc->func = func;
urpc->shared = uwsgi.mywid == 0 ? 1 : 0;
@@ -77,8 +77,8 @@ uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], cha
}
if (urpc) {
if (uwsgi.p[urpc->modifier1]->rpc) {
ret = uwsgi.p[urpc->modifier1]->rpc(urpc->func, argc, argv, argvs, output);
if (urpc->plugin->rpc) {
ret = urpc->plugin->rpc(urpc->func, argc, argv, argvs, output);
}
}
+3
View File
@@ -106,6 +106,9 @@ void uwsgi_setup_inherited_sockets() {
//now close all the unbound fd
for (j = 3; j < (int) uwsgi.max_fd; j++) {
int useless = 1;
if (uwsgi_fd_is_safe(j)) continue;
if (uwsgi.has_emperor) {
if (j == uwsgi.emperor_fd)
continue;
-57
View File
@@ -203,63 +203,6 @@ int uwsgi_add_timer(uint8_t sig, int secs) {
}
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
int i;
struct uwsgi_cron *old_uc, *uc = uwsgi.crons;
if (!uc) {
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
uwsgi.crons = uc;
}
else {
old_uc = uc;
while (uc->next) {
uc = uc->next;
old_uc = uc;
}
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
uc = old_uc->next;
}
memset(uc, 0, sizeof(struct uwsgi_cron));
if (sscanf(value, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) {
uwsgi_log("invalid cron syntax\n");
exit(1);
}
uc->command = value + i;
}
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
if (!uwsgi.master_process)
return -1;
uwsgi_lock(uwsgi.cron_table_lock);
if (ushared->cron_cnt < MAX_CRONS) {
ushared->cron[ushared->cron_cnt].sig = sig;
ushared->cron[ushared->cron_cnt].minute = minute;
ushared->cron[ushared->cron_cnt].hour = hour;
ushared->cron[ushared->cron_cnt].day = day;
ushared->cron[ushared->cron_cnt].month = month;
ushared->cron[ushared->cron_cnt].week = week;
ushared->cron_cnt++;
}
else {
uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS);
uwsgi_unlock(uwsgi.cron_table_lock);
return -1;
}
uwsgi_unlock(uwsgi.cron_table_lock);
return 0;
}
int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) {
if (!uwsgi.master_process)
+69 -25
View File
@@ -2,6 +2,10 @@
extern struct uwsgi_server uwsgi;
static int connect_to_unix(char *, int, int);
static int connect_to_tcp(char *, int, int, int);
static int connect_to_udp(char *, int);
static int uwsgi_socket_strcmp(char *sock1, char *sock2) {
size_t sock1_len = strlen(sock1);
size_t sock2_len = strlen(sock2);
@@ -312,36 +316,46 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
}
static int uwsgi_connect_do(char *socket_name, int timeout, int async) {
char *tcp_port = strchr(socket_name, ':');
if (tcp_port) {
tcp_port[0] = 0;
tcp_port++;
return connect_to_tcp(socket_name, atoi(tcp_port), timeout, async);
}
return connect_to_unix(socket_name, timeout, async);
}
int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) {
int fd;
char *zeroed_socket_name = uwsgi_concat2n(socket_name, len, "", 0);
fd = uwsgi_connect(zeroed_socket_name, timeout, async);
int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async);
free(zeroed_socket_name);
return fd;
}
int uwsgi_connect(char *socket_name, int timeout, int async) {
int ret;
char *tcp_port = strchr(socket_name, ':');
if (tcp_port) {
tcp_port[0] = 0;
tcp_port++;
ret = connect_to_tcp(socket_name, atoi(tcp_port), timeout, async);
// reset the socket name
tcp_port--;
tcp_port[0] = ':';
return ret;
}
return connect_to_unix(socket_name, timeout, async);
char *zeroed_socket_name = uwsgi_str(socket_name);
int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async);
free(zeroed_socket_name);
return fd;
}
int connect_to_unix(char *socket_name, int timeout, int async) {
int uwsgi_connect_udp(char *socket_name) {
int fd = -1;
char *zeroed_socket_name = uwsgi_str(socket_name);
char *udp_port = strchr(zeroed_socket_name, ':');
if (!udp_port) goto end;
*udp_port = 0;
udp_port++;
fd = connect_to_udp(zeroed_socket_name, atoi(udp_port));
end:
free(zeroed_socket_name);
return fd;
}
static int connect_to_unix(char *socket_name, int timeout, int async) {
struct pollfd uwsgi_poll;
struct sockaddr_un uws_addr;
@@ -386,7 +400,7 @@ int connect_to_unix(char *socket_name, int timeout, int async) {
}
int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
static int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
struct pollfd uwsgi_poll;
struct sockaddr_in uws_addr;
@@ -403,15 +417,13 @@ int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
uws_addr.sin_addr.s_addr = inet_addr(socket_name);
}
socket_name[strlen(socket_name)] = ':';
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
#else
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0);
#endif
if (uwsgi_poll.fd < 0) {
uwsgi_error("socket()");
uwsgi_error("connect_to_tcp()/socket()");
return -1;
}
@@ -427,6 +439,38 @@ int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
}
static int connect_to_udp(char *socket_name, int port) {
struct sockaddr_in uws_addr;
memset(&uws_addr, 0, sizeof(struct sockaddr_in));
uws_addr.sin_family = AF_INET;
uws_addr.sin_port = htons(port);
if (socket_name[0] == 0) {
uws_addr.sin_addr.s_addr = INADDR_ANY;
}
else {
uws_addr.sin_addr.s_addr = inet_addr(socket_name);
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
uwsgi_error("connect_to_udp()/socket()");
return -1;
}
if (connect(fd, (const struct sockaddr *) &uws_addr, sizeof(struct sockaddr_in))) {
close(fd);
return -1;
}
return fd;
}
char *generate_socket_name(char *socket_name) {
char *asterisk = strchr(socket_name, '*');
+21 -4
View File
@@ -1,5 +1,7 @@
#include "../uwsgi.h"
#include <uwsgi.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
extern struct uwsgi_server uwsgi;
/*
@@ -252,8 +254,14 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
if (!uwsgi.ssl_sessions_cache) {
uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
exit(1);
// check for default cache
if (!strcmp(uwsgi.ssl_sessions_use_cache, "true") && uwsgi.caches) {
uwsgi.ssl_sessions_cache = uwsgi.caches;
}
else {
uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
exit(1);
}
}
if (!uwsgi.ssl_sessions_cache->max_items) {
@@ -406,8 +414,9 @@ char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
}
char *uwsgi_ssl_rand(size_t len) {
unsigned char *buf = uwsgi_calloc(len+1);
unsigned char *buf = uwsgi_calloc(len);
if (RAND_bytes(buf, len) <= 0) {
free(buf);
return NULL;
}
return (char *) buf;
@@ -421,6 +430,14 @@ char *uwsgi_sha1(char *src, size_t len, char *dst) {
return dst;
}
char *uwsgi_md5(char *src, size_t len, char *dst) {
MD5_CTX md5;
MD5_Init(&md5);
MD5_Update(&md5, src, len);
MD5_Final((unsigned char *)dst, &md5);
return dst;
}
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
SHA_CTX sha;
SHA1_Init(&sha);
+31 -23
View File
@@ -55,7 +55,7 @@ gzip:
return 1;
}
static int set_http_date(time_t t, char *dst) {
int uwsgi_http_date(time_t t, char *dst) {
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static char *months[] = {
@@ -179,7 +179,7 @@ int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int m
while (udd) {
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
int size = uwsgi_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -192,7 +192,7 @@ int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int m
while (udd) {
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
int size = uwsgi_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -215,7 +215,7 @@ int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filenam
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
int size = uwsgi_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -228,7 +228,7 @@ int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filenam
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
int size = uwsgi_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -250,7 +250,7 @@ int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st)
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
int size = uwsgi_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -263,7 +263,7 @@ int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st)
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
int size = uwsgi_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -285,7 +285,7 @@ int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
int size = uwsgi_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -298,7 +298,7 @@ int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
int size = uwsgi_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
@@ -333,6 +333,10 @@ char *uwsgi_get_mime_type(char *name, int namelen, size_t *size) {
if (!ext)
return NULL;
if (uwsgi.threads > 1)
pthread_mutex_lock(&uwsgi.lock_static);
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
while (udd) {
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
@@ -361,11 +365,16 @@ char *uwsgi_get_mime_type(char *name, int namelen, size_t *size) {
}
}
*size = udd->vallen;
if (uwsgi.threads > 1)
pthread_mutex_unlock(&uwsgi.lock_static);
return udd->value;
}
udd = udd->next;
}
if (uwsgi.threads > 1)
pthread_mutex_unlock(&uwsgi.lock_static);
return NULL;
}
@@ -431,14 +440,12 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
size_t mime_type_size = 0;
char http_last_modified[49];
if (uwsgi.threads > 1)
pthread_mutex_lock(&uwsgi.lock_static);
int use_gzip = 0;
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&uwsgi.lock_static);
// here we need to choose if we want the gzip variant;
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) use_gzip = 1;
if (wsgi_req->if_modified_since_len) {
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
@@ -451,6 +458,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif
size_t fsize = st->st_size;
if (wsgi_req->range_to) {
fsize = wsgi_req->range_to - wsgi_req->range_from;
@@ -462,7 +470,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
// reset in case of inconsistent size
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
fsize = 0 ;
fsize = 0;
}
else {
fsize -= wsgi_req->range_from;
@@ -483,6 +491,10 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
uwsgi_add_expires_uri(wsgi_req, st);
#endif
if (use_gzip) {
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
}
// Content-Type (if available)
if (mime_type_size > 0 && mime_type) {
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
@@ -497,29 +509,25 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
if (uwsgi.file_serve_mode == 1) {
if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
// this is the final header (\r\n added)
int size = set_http_date(st->st_mtime, http_last_modified);
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
}
// apache
else if (uwsgi.file_serve_mode == 2) {
if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
// this is the final header (\r\n added)
int size = set_http_date(st->st_mtime, http_last_modified);
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
}
// raw
else {
// here we need to choose if we want the gzip variant;
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
}
// set Content-Length (to fsize NOT st->st_size)
if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
// here use teh original size !!!
// here use the original size !!!
if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
}
int size = set_http_date(st->st_mtime, http_last_modified);
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
// if it is a HEAD request just skip transfer
+163
View File
@@ -0,0 +1,163 @@
#include <uwsgi.h>
/*
uWSGI transformations
each body chunk is passed (in chain) to every transformation
some of them supports streaming, other requires buffering
at the end of the request the "final chain" is called (and the whole chain freed)
Transformations (if required) could completely swallow already set headers
*/
extern struct uwsgi_server uwsgi;
// -1 error, 0 = no buffer, send the body, 1 = buffer
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *buf, size_t len) {
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
struct uwsgi_transformation *ut = wsgi_req->transformations;
char *t_buf = buf;
size_t t_len = len;
uint8_t flushed = 0;
while(ut) {
// allocate the buffer (if needed)
if (!ut->chunk) {
ut->chunk = uwsgi_buffer_new(t_len);
}
// skip final transformations before appending data
if (ut->is_final) goto next;
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
return -1;
}
// if the transformation cannot stream, continue buffering (the func will be called at the end)
if (!ut->can_stream) return 1;
ut->round++;
if (ut->func(wsgi_req, ut)) {
return -1;
}
if (ut->flushed) flushed = 1;
t_buf = ut->chunk->buf;
t_len = ut->chunk->pos;
// we reset the buffer, so we do not waste memory
ut->chunk->pos = 0;
next:
ut = ut->next;
}
// if we are here we can tell the writer to send the body to the client
// no buffering please
if (!flushed) {
wsgi_req->transformed_chunk = t_buf;
wsgi_req->transformed_chunk_len = t_len;
}
return 0;
}
/*
run all the remaining (or buffered) transformations
*/
int uwsgi_apply_final_transformations(struct wsgi_request *wsgi_req) {
struct uwsgi_transformation *ut = wsgi_req->transformations;
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
char *t_buf = NULL;
size_t t_len = 0;
uint8_t flushed = 0;
int found_nostream = 0;
while(ut) {
if (!found_nostream) {
if (!ut->can_stream) {
found_nostream = 1;
}
else {
t_buf = ut->chunk->buf;
t_len = ut->chunk->pos;
goto next;
}
}
if (!ut->chunk) {
if (t_len > 0) {
ut->chunk = uwsgi_buffer_new(t_len);
}
else {
ut->chunk = uwsgi_buffer_new(uwsgi.page_size);
}
}
if (t_len > 0) {
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
return -1;
}
}
// run the transformation
ut->round++;
if (ut->func(wsgi_req, ut)) {
return -1;
}
if (ut->flushed) flushed = 1;
t_buf = ut->chunk->buf;
t_len = ut->chunk->pos;
next:
ut = ut->next;
}
// if we are here, all of the transformations are applied
if (!flushed) {
wsgi_req->transformed_chunk = t_buf;
wsgi_req->transformed_chunk_len = t_len;
}
return 0;
}
void uwsgi_free_transformations(struct wsgi_request *wsgi_req) {
struct uwsgi_transformation *ut = wsgi_req->transformations;
while(ut) {
struct uwsgi_transformation *current_ut = ut;
if (current_ut->chunk) {
uwsgi_buffer_destroy(current_ut->chunk);
}
ut = ut->next;
free(current_ut);
}
}
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *data) {
struct uwsgi_transformation *old_ut = NULL, *ut = wsgi_req->transformations;
while(ut) {
old_ut = ut;
ut = ut->next;
}
ut = uwsgi_malloc(sizeof(struct uwsgi_transformation));
ut->func = func;
ut->is_final = 0;
ut->next = NULL;
ut->chunk = NULL;
ut->can_stream = 0;
ut->data = data;
if (old_ut) {
old_ut->next = ut;
}
else {
wsgi_req->transformations = ut;
}
return ut;
}
+136 -48
View File
@@ -222,12 +222,11 @@ void uwsgi_set_cgroup() {
uwsgi_error_open(cgroup_taskfile);
exit(1);
}
if (fprintf(cgroup, "%d", (int) getpid()) <= 0) {
uwsgi_log("could not set cgroup\n");
if (fprintf(cgroup, "%d\n", (int) getpid()) <= 0 || ferror(cgroup) || fclose(cgroup)) {
uwsgi_error("could not set cgroup");
exit(1);
}
uwsgi_log("assigned process %d to cgroup %s\n", (int) getpid(), cgroup_taskfile);
fclose(cgroup);
free(cgroup_taskfile);
@@ -248,11 +247,10 @@ void uwsgi_set_cgroup() {
cgroup_taskfile = uwsgi_concat3(usl->value, "/", uslo->value);
cgroup = fopen(cgroup_taskfile, "w");
if (cgroup) {
if (fprintf(cgroup, "%s\n", cgroup_opt) < 0) {
if (fprintf(cgroup, "%s\n", cgroup_opt) <= 0 || ferror(cgroup) || fclose(cgroup)) {
uwsgi_log("could not set cgroup option %s to %s\n", uslo->value, cgroup_opt);
exit(1);
}
fclose(cgroup);
uwsgi_log("set %s to %s\n", cgroup_opt, cgroup_taskfile);
}
free(cgroup_taskfile);
@@ -576,6 +574,16 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
int tmp_id;
uint64_t tmp_rt, rss = 0, vsz = 0;
// apply transformations
if (wsgi_req->transformations) {
if (uwsgi_apply_final_transformations(wsgi_req) == 0) {
if (wsgi_req->transformed_chunk && wsgi_req->transformed_chunk_len > 0) {
uwsgi_response_write_body_do(wsgi_req, wsgi_req->transformed_chunk, wsgi_req->transformed_chunk_len);
}
}
uwsgi_free_transformations(wsgi_req);
}
// check if headers should be sent
if (wsgi_req->headers) {
if (!wsgi_req->headers_sent && !wsgi_req->headers_size && !wsgi_req->response_size) {
@@ -599,7 +607,6 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uwsgi.workers[uwsgi.mywid].rss_size = rss;
}
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
@@ -622,25 +629,6 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
free(wsgi_req->proto_parser_buf);
}
// do we need to store the response in the cache
if (wsgi_req->cache_it) {
// only response with a body and a status code of 200 can be cached (TODO allows it to be configurable)
if (wsgi_req->cached_response && wsgi_req->status == 200 && wsgi_req->response_size > 0) {
uwsgi_cache_magic_set(wsgi_req->cache_it->buf, wsgi_req->cache_it->pos,
wsgi_req->cached_response->buf, wsgi_req->cached_response->pos, wsgi_req->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, wsgi_req->cache_it_to ? wsgi_req->cache_it_to->buf : NULL);
}
uwsgi_buffer_destroy(wsgi_req->cache_it);
}
if (wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it_to);
}
if (wsgi_req->cached_response) {
uwsgi_buffer_destroy(wsgi_req->cached_response);
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
@@ -669,12 +657,14 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
set_user_harakiri(0);
}
// this is racy in multithread mode
if (wsgi_req->response_size > 0) {
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->response_size;
}
if (wsgi_req->headers_size > 0) {
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->headers_size;
if (!wsgi_req->do_not_account) {
// this is racy in multithread mode
if (wsgi_req->response_size > 0) {
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->response_size;
}
if (wsgi_req->headers_size > 0) {
uwsgi.workers[uwsgi.mywid].tx += wsgi_req->headers_size;
}
}
// defunct process reaper
@@ -1141,11 +1131,36 @@ void parse_sys_envs(char **envs) {
}
// get the application id
int uwsgi_get_app_id(char *app_name, int app_name_len, int modifier1) {
int uwsgi_get_app_id(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, int modifier1) {
int i;
struct stat st;
int found;
int free_appname = 0;
char *app_name = key;
uint16_t app_name_len = key_len;
if (!app_name && wsgi_req) {
app_name = wsgi_req->appid;
app_name_len = wsgi_req->appid_len;
if (app_name_len == 0) {
if (!uwsgi.ignore_script_name) {
app_name = wsgi_req->script_name;
app_name_len = wsgi_req->script_name_len;
}
if (uwsgi.vhost) {
app_name = uwsgi_concat3n(wsgi_req->host, wsgi_req->host_len, "|",1, wsgi_req->script_name, wsgi_req->script_name_len);
app_name_len = wsgi_req->host_len + 1 + wsgi_req->script_name_len;
#ifdef UWSGI_DEBUG
uwsgi_debug("VirtualHost KEY=%.*s\n", wsgi_req->appid_len, wsgi_req->appid);
#endif
free_appname = 1;
}
}
}
for (i = 0; i < uwsgi_apps_cnt; i++) {
// reset check
@@ -1177,14 +1192,19 @@ int uwsgi_get_app_id(char *app_name, int app_name_len, int modifier1) {
}
}
}
if (modifier1 == -1)
if (modifier1 == -1) {
if (free_appname) free(app_name);
return i;
if (modifier1 == uwsgi_apps[i].modifier1)
}
if (modifier1 == uwsgi_apps[i].modifier1) {
if (free_appname) free(app_name);
return i;
}
}
}
if (!uwsgi.no_default_app) {
if (free_appname) free(app_name);
return uwsgi.default_app;
}
@@ -1783,18 +1803,21 @@ void init_magic_table(char *magic_table[]) {
}
char *uwsgi_get_last_char(char *what, char c) {
int i;
char *ptr = NULL;
for (i = 0; i < (int) strlen(what); i++) {
if (what[i] == c) {
ptr = what + i;
}
size_t len = strlen(what);
while(len--) {
if (what[len] == c) return what + len;
}
return ptr;
return NULL;
}
char *uwsgi_get_last_charn(char *what, size_t len, char c) {
while(len--) {
if (what[len] == c) return what + len;
}
return NULL;
}
char *uwsgi_num2str(int num) {
char *str = uwsgi_malloc(11);
@@ -1803,6 +1826,12 @@ char *uwsgi_num2str(int num) {
return str;
}
char *uwsgi_64bit2str(int64_t num) {
char *str = uwsgi_malloc(sizeof(MAX64_STR)+1);
snprintf(str, sizeof(MAX64_STR)+1, "%lld", (long long) num);
return str;
}
int uwsgi_num2str2(int num, char *ptr) {
return snprintf(ptr, 11, "%d", num);
@@ -3073,6 +3102,7 @@ void http_url_decode(char *buf, uint16_t * len, char *dst) {
}
/*
we scan the table in reverse, as updated values are at the end
*/
@@ -3116,6 +3146,10 @@ struct uwsgi_app *uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int
}
}
if ((mountpoint_len == 0 || (mountpoint_len =- 1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
uwsgi.default_app = id;
}
return wi;
}
@@ -3135,7 +3169,7 @@ char *uwsgi_check_touches(struct uwsgi_string_list *touch_list) {
uwsgi_log("[uwsgi-check-touches] File %s was removed\n", touch->value);
#endif
touch->custom2 = 1;
return touch->value;
return touch->custom_ptr ? touch->custom_ptr : touch->value;
}
else if (!touch->custom && !touch->custom2) {
uwsgi_log("unable to stat() %s, events will be triggered as soon as the file is created\n", touch->value);
@@ -3150,14 +3184,14 @@ char *uwsgi_check_touches(struct uwsgi_string_list *touch_list) {
#endif
touch->custom = (uint64_t) tr_st.st_mtime;
touch->custom2 = 0;
return touch->value;
return touch->custom_ptr ? touch->custom_ptr : touch->value;
}
else if (touch->custom && (uint64_t) tr_st.st_mtime > touch->custom) {
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-check-touches] modification detected on %s: %llu -> %llu\n", touch->value, (unsigned long long) touch->custom, (unsigned long long) tr_st.st_mtime);
#endif
touch->custom = (uint64_t) tr_st.st_mtime;
return touch->value;
return touch->custom_ptr ? touch->custom_ptr : touch->value;
}
touch->custom = (uint64_t) tr_st.st_mtime;
}
@@ -3236,10 +3270,9 @@ void uwsgi_write_pidfile(char *pidfile_name) {
uwsgi_error_open(pidfile_name);
exit(1);
}
if (fprintf(pidfile, "%d\n", (int) getpid()) < 0) {
if (fprintf(pidfile, "%d\n", (int) getpid()) <= 0 || ferror(pidfile) || fclose(pidfile)) {
uwsgi_log("could not write pidfile.\n");
}
fclose(pidfile);
}
char *uwsgi_expand_path(char *dir, int dir_len, char *ptr) {
@@ -3851,3 +3884,58 @@ char *uwsgi_get_header(struct wsgi_request *wsgi_req, char *hh, uint16_t len, ui
return value;
}
static char *uwsgi_hex_table[] = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF",
};
char *uwsgi_str_to_hex(char *src, size_t slen) {
char *dst = uwsgi_malloc(slen*2);
char *ptr = dst;
size_t i;
for(i=0;i<slen;i++) {
memcpy(ptr, uwsgi_hex_table[ (int) src[i] ], 2);
ptr+=2;
}
return dst;
}
// dst has to be 3 times buf size (USE IT ONLY FOR PATH_INFO !!!)
void http_url_encode(char *buf, uint16_t *len, char *dst) {
uint16_t i;
char *ptr = dst;
for(i=0;i<*len;i++) {
if ((buf[i] >= 'A' && buf[i] <= 'Z') ||
(buf[i] >= 'a' && buf[i] <= 'z') ||
(buf[i] >= '0' && buf[i] <= '9') ||
buf[i] == '-' || buf[i] == '_' || buf[i] == '.' || buf[i] == '~' || buf[i] == '/' ) {
*ptr++= buf[i];
}
else {
char *h = uwsgi_hex_table[(int) buf[i]];
*ptr++= '%';
*ptr++= h[0];
*ptr++= h[1];
}
}
*len = ptr-dst;
}
+68 -19
View File
@@ -24,6 +24,7 @@
#include <uwsgi.h>
struct uwsgi_server uwsgi;
pid_t masterpid;
#if defined(__APPLE__) && defined(UWSGI_AS_SHARED_LIBRARY)
#include <crt_externs.h>
@@ -64,7 +65,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"no-harakiri-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"no-harakiri-after-req-hook", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"backtrace-depth", no_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
{"backtrace-depth", required_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
{"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MULE_HARAKIRI, 0},
#ifdef UWSGI_XML
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
@@ -73,6 +74,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE},
{"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0},
{"skip-atexit", no_argument, 0, "skip atexit hooks (ignored by the master)", uwsgi_opt_true, &uwsgi.skip_atexit, 0},
{"set", required_argument, 'S', "set a custom placeholder", uwsgi_opt_set_placeholder, NULL, UWSGI_OPT_IMMEDIATE},
{"get", required_argument, 0, "print the specified option value and exit", uwsgi_opt_add_string_list, &uwsgi.get_list, UWSGI_OPT_NO_INITIAL},
@@ -216,6 +218,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"ftok", required_argument, 0, "set the ipcsem key via ftok() for avoiding duplicates", uwsgi_opt_set_str, &uwsgi.ftok, 0},
{"sharedarea", required_argument, 'A', "create a raw shared memory area of specified pages", uwsgi_opt_set_int, &uwsgi.sharedareasize, 0},
{"safe-fd", no_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0},
{"fd-safe", no_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0},
{"cache", required_argument, 0, "create a shared cache containing given elements", uwsgi_opt_set_64bit, &uwsgi.cache_max_items, 0},
{"cache-blocksize", required_argument, 0, "set cache blocksize", uwsgi_opt_set_64bit, &uwsgi.cache_blocksize, 0},
{"cache-store", required_argument, 0, "enable persistent cache to disk", uwsgi_opt_set_str, &uwsgi.cache_store, UWSGI_OPT_MASTER},
@@ -226,8 +231,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"cache-udp-server", required_argument, 0, "bind the cache udp server (used only for set/update/delete) to the specified socket", uwsgi_opt_add_string_list, &uwsgi.cache_udp_server, UWSGI_OPT_MASTER},
{"cache-udp-node", required_argument, 0, "send cache update/deletion to the specified cache udp server", uwsgi_opt_add_string_list, &uwsgi.cache_udp_node, UWSGI_OPT_MASTER},
{"cache-sync", required_argument, 0, "copy the whole content of another uWSGI cache server on server startup", uwsgi_opt_set_str, &uwsgi.cache_sync, 0},
{"cache-use-last-modified", no_argument, 0, "update last_modified_at timestamp on every cache item modification (default is disabled)", uwsgi_opt_true, &uwsgi.cache_use_last_modified, 0},
{"load-file-in-cache", required_argument, 0, "load a static file in the cache", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache, 0},
#ifdef UWSGI_ZLIB
{"load-file-in-cache-gzip", required_argument, 0, "load a static file in the cache with gzip compression", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache_gzip, 0},
#endif
{"cache2", required_argument, 0, "create a new generation shared cache (keyval syntax)", uwsgi_opt_add_string_list, &uwsgi.cache2, 0},
@@ -335,6 +344,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"touch-chain-reload", required_argument, 0, "trigger chain reload if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_chain_reload, UWSGI_OPT_MASTER},
{"touch-logrotate", required_argument, 0, "trigger logrotation if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logrotate, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"touch-logreopen", required_argument, 0, "trigger log reopen if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logreopen, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"touch-exec", required_argument, 0, "run command when the specified file is modified/touched (syntax: file command)", uwsgi_opt_add_string_list, &uwsgi.touch_exec, UWSGI_OPT_MASTER},
{"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal mamagement", uwsgi_opt_true, &uwsgi.propagate_touch, 0},
{"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0},
{"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0},
@@ -370,6 +380,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
#ifdef UWSGI_SSL
{"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER},
{"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER},
{"legion-node", required_argument, 0, "add a node to a legion", uwsgi_opt_legion_node, NULL, UWSGI_OPT_MASTER},
{"legion-freq", required_argument, 0, "set the frequency of legion packets", uwsgi_opt_set_int, &uwsgi.legion_freq, UWSGI_OPT_MASTER},
{"legion-tolerance", required_argument, 0, "set the tolerance of legion subsystem", uwsgi_opt_set_int, &uwsgi.legion_tolerance, UWSGI_OPT_MASTER},
@@ -446,6 +457,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
#endif
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
{"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
#ifdef UWSGI_PCRE
{"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
@@ -586,6 +600,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0},
{"unenv", required_argument, 0, "unset environment variable", uwsgi_opt_unset_env, NULL, 0},
{"vacuum", no_argument, 0, "try to remove all of the generated file/sockets", uwsgi_opt_true, &uwsgi.vacuum, 0},
{"file-write", required_argument, 0, "write the specified content to the specified file (syntax: file=value) before privileges drop", uwsgi_opt_add_string_list, &uwsgi.file_write_list, 0},
#ifdef __linux__
{"cgroup", required_argument, 0, "put the processes in the specified cgroup", uwsgi_opt_add_string_list, &uwsgi.cgroup, 0},
{"cgroup-opt", required_argument, 0, "set value in specified cgroup option", uwsgi_opt_add_string_list, &uwsgi.cgroup_opt, 0},
@@ -605,6 +620,10 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"zerg-server", required_argument, 0, "enable the zerg server on the specified UNIX socket", uwsgi_opt_set_str, &uwsgi.zerg_server, UWSGI_OPT_MASTER},
{"cron", required_argument, 0, "add a cron task", uwsgi_opt_add_cron, NULL, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion-cron", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER},
{"cron-legion", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER},
#endif
{"loop", required_argument, 0, "select the uWSGI loop engine", uwsgi_opt_set_str, &uwsgi.loop, 0},
{"loop-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
{"loops-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
@@ -612,6 +631,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion-attach-daemon", required_argument, 0, "same as --attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"legion-smart-attach-daemon", required_argument, 0, "same as --smart-attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"legion-smart-attach-daemon2", required_argument, 0, "same as --smart-attach-daemon2 but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
#endif
{"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
@@ -944,6 +968,10 @@ void gracefully_kill(int signum) {
}
void end_me(int signum) {
if (getpid() != masterpid && uwsgi.skip_atexit) {
_exit(UWSGI_END_CODE);
// never here
}
exit(UWSGI_END_CODE);
}
@@ -1200,7 +1228,6 @@ void what_i_am_doing() {
}
pid_t masterpid;
int unconfigured_hook(struct wsgi_request *wsgi_req) {
uwsgi_log("-- unavailable modifier requested: %d --\n", wsgi_req->uh->modifier1);
@@ -1428,15 +1455,28 @@ void uwsgi_backtrace(int depth) {
bt_strings = backtrace_symbols(btrace, bt_size);
uwsgi_log("*** backtrace of %d ***\n", (int) getpid());
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
uwsgi_buffer_append(ub, "*** backtrace of ",17);
uwsgi_buffer_num64(ub, (int64_t) getpid());
uwsgi_buffer_append(ub, " ***\n", 5);
for (i = 0; i < bt_size; i++) {
uwsgi_log("%s\n", bt_strings[i]);
uwsgi_buffer_append(ub, bt_strings[i], strlen(bt_strings[i]));
uwsgi_buffer_append(ub, "\n", 1);
}
free(btrace);
uwsgi_log("*** end of backtrace ***\n");
uwsgi_buffer_append(ub, "*** end of backtrace ***\n", 25);
uwsgi_log("%.*s", ub->pos, ub->buf);
struct uwsgi_string_list *usl = uwsgi.alarm_segfault;
while(usl) {
uwsgi_alarm_trigger(usl->value, ub->buf, ub->pos);
usl = usl->next;
}
uwsgi_buffer_destroy(ub);
#endif
}
@@ -2048,6 +2088,8 @@ int uwsgi_start(void *v_argv) {
}
#endif
uwsgi_file_write_do(uwsgi.file_write_list);
if (!uwsgi.master_as_root && !uwsgi.chown_socket) {
uwsgi_as_root();
}
@@ -2181,18 +2223,9 @@ int uwsgi_start(void *v_argv) {
}
}
uwsgi_log("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
uwsgi.async_waiting_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_waiting_fd_table) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi.async_waiting_fd_table, 0, sizeof(struct wsgi_request *) * uwsgi.max_fd);
uwsgi.async_proto_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_proto_fd_table) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi.async_proto_fd_table, 0, sizeof(struct wsgi_request *) * uwsgi.max_fd);
// optimization, this array maps file descriptor to requests
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
}
#ifdef UWSGI_DEBUG
@@ -2352,7 +2385,8 @@ int uwsgi_start(void *v_argv) {
!uwsgi.udp_socket &&
!uwsgi.emperor &&
!uwsgi.command_mode &&
!uwsgi.daemons_cnt
!uwsgi.daemons_cnt &&
!uwsgi.crons
#ifdef UWSGI_SSL
&& !uwsgi.legions
#endif
@@ -2415,7 +2449,14 @@ unsafe:
if (uwsgi.crons) {
struct uwsgi_cron *ucron = uwsgi.crons;
while (ucron) {
uwsgi_log("command \"%s\" registered as uWSGI-cron task\n", ucron->command);
#ifdef UWSGI_SSL
if (ucron->legion) {
uwsgi_log("[uwsgi-cron] command \"%s\" registered as cron task for legion \"%s\"\n", ucron->command, ucron->legion);
ucron = ucron->next;
continue;
}
#endif
uwsgi_log("[uwsgi-cron] command \"%s\" registered as cron task\n", ucron->command);
ucron = ucron->next;
}
}
@@ -3244,6 +3285,14 @@ void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) {
uwsgi_log("immediate uid: %d\n", (int) uid);
}
void uwsgi_opt_safe_fd(char *opt, char *value, void *foobar) {
int fd = atoi(value);
if (fd < 0) {
uwsgi_log("invalid file descriptor: %d\n", fd);
exit(1);
}
uwsgi_add_safe_fd(fd);
}
void uwsgi_opt_set_int(char *opt, char *value, void *key) {
int *ptr = (int *) key;
+94 -29
View File
@@ -12,6 +12,39 @@ int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
}
int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) {
// 30+1
char expires[31];
int len = uwsgi_http_date((time_t) t, expires);
if (!len) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len);
}
int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) {
// 30+1
char d[31];
int len = uwsgi_http_date((time_t) t, d);
if (!len) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len);
}
int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) {
// 30+1
char lm[31];
int len = uwsgi_http_date((time_t) t, lm);
if (!len) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len);
}
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
char buf[6+(sizeof(UMAX64_STR)*3)+4];
if (end == 0) {
@@ -25,6 +58,12 @@ int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t sta
return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret);
}
int uwsgi_response_prepare_headers_int(struct wsgi_request *wsgi_req, int status) {
char status_str[11];
uwsgi_num2str2(status, status_str);
return uwsgi_response_prepare_headers(wsgi_req, status_str, 3);
}
// status could be NNN or NNN message
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
@@ -69,6 +108,24 @@ error:
}
//each protocol has its header generator
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
if (!wsgi_req->headers) {
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
wsgi_req->headers->limit = UMAX16;
}
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
if (!hh) { wsgi_req->write_errors++ ; return -1;}
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
wsgi_req->header_cnt++;
uwsgi_buffer_destroy(hh);
return 0;
error:
uwsgi_buffer_destroy(hh);
wsgi_req->write_errors++;
return -1;
}
int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
@@ -88,21 +145,14 @@ int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t
rh = rh->next;
}
if (!wsgi_req->headers) {
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
wsgi_req->headers->limit = UMAX16;
}
return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
}
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
if (!hh) { wsgi_req->write_errors++ ; return -1;}
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
wsgi_req->header_cnt++;
uwsgi_buffer_destroy(hh);
return 0;
error:
uwsgi_buffer_destroy(hh);
wsgi_req->write_errors++;
return -1;
int uwsgi_response_add_header_force(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
}
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
@@ -159,6 +209,26 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
if (wsgi_req->write_errors) return -1;
// if the transformation chain returns 1, we are in buffering mode
if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
if (t_ret == 0) {
buf = wsgi_req->transformed_chunk;
len = wsgi_req->transformed_chunk_len;
// reset transformation
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
goto write;
}
if (t_ret == 1) {
return UWSGI_OK;
}
wsgi_req->write_errors++;
return -1;
}
write:
// send headers if not already sent
if (!wsgi_req->headers_sent) {
int ret = uwsgi_response_write_headers_do(wsgi_req);
if (ret == UWSGI_OK) goto sendbody;
@@ -170,7 +240,7 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
sendbody:
if (len == 0) return UWSGI_OK;
for(;;) {
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
if (ret < 0) {
@@ -196,18 +266,6 @@ sendbody:
// reset for the next write
wsgi_req->write_pos = 0;
// now we need to check if the chunk must be stored
if (wsgi_req->cache_it) {
if (!wsgi_req->cached_response) {
wsgi_req->cached_response = uwsgi_buffer_new(len);
}
// if we are unable to append the buffer, we just stop caching it
if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
}
return UWSGI_OK;
}
@@ -217,7 +275,10 @@ int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos
if (fd == wsgi_req->sendfile_fd) can_close = 0;
if (wsgi_req->write_errors) return -1;
if (wsgi_req->write_errors) {
if (can_close) close(fd);
return -1;
}
if (!wsgi_req->headers_sent) {
int ret = uwsgi_response_write_headers_do(wsgi_req);
@@ -238,7 +299,10 @@ sendfile:
if (can_close) close(fd);
return -1;
}
if (pos >= (size_t)st.st_size) return UWSGI_OK;
if (pos >= (size_t)st.st_size) {
if (can_close) close(fd);
return UWSGI_OK;
}
len = st.st_size;
}
@@ -290,6 +354,7 @@ sendfile:
if (ret == 0) {
uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
}
}
+60
View File
@@ -1,5 +1,42 @@
#include <uwsgi.h>
char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
char *uwsgi_gzip_chunk(z_stream *z, uint32_t *crc32, char *buf, size_t len, size_t *dlen) {
uwsgi_crc32(crc32, buf, len);
return uwsgi_deflate(z, buf, len, dlen);
}
struct uwsgi_buffer *uwsgi_gzip(char *buf, size_t len) {
z_stream z;
struct uwsgi_buffer *ub = NULL;
uint32_t gzip_crc32 = 0;
char *gzipped = NULL;
char *gzipped0 = NULL;
size_t dlen = 0;
size_t dlen0 = 0;
uwsgi_crc32(&gzip_crc32, NULL, 0);
if (uwsgi_deflate_init(&z, NULL, 0)) return NULL;
uwsgi_crc32(&gzip_crc32, buf, len);
gzipped = uwsgi_deflate(&z, buf, len, &dlen);
if (!gzipped) goto end;
gzipped0 = uwsgi_deflate(&z, NULL, 0, &dlen0);
if (!gzipped0) goto end;
ub = uwsgi_buffer_new(10 + dlen + dlen0 + 8);
if (uwsgi_buffer_append(ub, gzheader, 10)) goto end;
if (uwsgi_buffer_append(ub, gzipped, dlen)) goto end;
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
if (uwsgi_buffer_u32le(ub, gzip_crc32)) goto end;
if (uwsgi_buffer_u32le(ub, len)) goto end;
end:
if (gzipped) free(gzipped);
if (gzipped0) free(gzipped0);
deflateEnd(&z);
return ub;
}
int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
z->zalloc = Z_NULL;
@@ -17,6 +54,29 @@ int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
return 0;
}
int uwsgi_gzip_prepare(z_stream *z, char *dict, size_t dict_len, uint32_t *crc32) {
uwsgi_crc32(crc32, NULL, 0);
if (uwsgi_deflate_init(z, NULL, 0)) return -1;
return 0;
}
// fix and free a gzip stream
int uwsgi_gzip_fix(z_stream *z, uint32_t crc32, struct uwsgi_buffer *ub, size_t len) {
size_t dlen0 = 0;
char *gzipped0 = uwsgi_deflate(z, NULL, 0, &dlen0);
if (!gzipped0) goto end;
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
free(gzipped0);
if (uwsgi_buffer_u32le(ub, crc32)) goto end;
if (uwsgi_buffer_u32le(ub, len)) goto end;
deflateEnd(z);
return 0;
end:
if (gzipped0) free(gzipped0);
deflateEnd(z);
return -1;
}
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
-1356
View File
File diff suppressed because it is too large Load Diff
-3
View File
@@ -1,3 +0,0 @@
ngx_addon_name=ngx_http_uwsgi_module
HTTP_MODULES="$HTTP_MODULES ngx_http_uwsgi_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_uwsgi_module.c"
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
+267
View File
@@ -0,0 +1,267 @@
#include <uwsgi.h>
#include <libxml/parser.h>
#include <curl/curl.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_airbrake_config {
int first;
char *arg;
char *apikey;
};
struct uwsgi_airbrake_opt {
char *name;
CURLoption option;
void (*func)(CURL *, CURLoption, char *, struct uwsgi_airbrake_config*);
};
static void uwsgi_airbrake_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL);
}
static void uwsgi_airbrake_int(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
curl_easy_setopt(curl, option, atoi(arg));
}
static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
uacc->apikey = arg;
}
static struct uwsgi_airbrake_opt uaco[] = {
{"url", CURLOPT_URL, NULL},
{"apikey", 0, uwsgi_airbrake_set_apikey},
{"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl},
{"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int},
{"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int},
{NULL, 0, NULL},
};
static void uwsgi_airbrake_setopt(CURL *curl, char *opt, struct uwsgi_airbrake_config *uacc) {
struct uwsgi_airbrake_opt *o = uaco;
char *equal = strchr(opt,'=');
if (!equal) {
if (!uacc->first) {
curl_easy_setopt(curl, CURLOPT_URL, opt);
uacc->first = 1;
}
return;
}
uacc->first = 1;
*equal = 0;
while(o->name) {
if (!strcmp(o->name, opt)) {
if (o->func) {
o->func(curl, o->option, equal+1, uacc);
}
else {
curl_easy_setopt(curl, o->option, equal+1);
}
goto end;
}
o++;
}
end:
*equal = '=';
}
static size_t uwsgi_airbrake_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
size_t full_size = size * nmemb;
size_t remains = ut->len - ut->pos;
if (remains == 0) return 0;
if (ut->custom0 == 0) {
size_t newline = 0;
size_t required = 1;
char *addr = ptr;
if (required > full_size) goto skip;
skip:
if (newline > 0) {
*addr = '\n';
}
ut->custom0 = 1;
return required;
}
if (full_size < remains) {
remains = full_size;
}
memcpy(ptr, ut->buf + ut->pos, remains);
ut->pos += remains;
return remains;
}
static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apikey) {
xmlChar *xmlbuff;
int buffersize;
xmlDocPtr doc = NULL;
xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL;
char *msg = uwsgi_str("uWSGI segfault");
doc = xmlNewDoc(BAD_CAST "1.0");
notice_node = xmlNewNode(NULL, BAD_CAST "notice");
xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3");
xmlDocSetRootElement(doc, notice_node);
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST apikey);
node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL);
xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI");
xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION);
xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi");
errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL);
xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError");
node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL);
char *p = strtok(ut->buf, "\n");
int i = 0;
while (p) {
// skip log messages
if (!uwsgi_startswith(p, "***", 3))
goto next;
i++;
// skip last 2 backtrace lines, real bt starts after them
if (i <= 2) {
goto next;
}
// backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555]
// we take binary/lib as filename
// and extract method name from remaining string
char *n = strchr(p, '(');
if (n) {
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
*n = 0;
char *pls = strchr(n+1, '+');
if (pls) {
*pls = 0;
}
if (i == 3) {
free(msg);
if (strlen(n+1)) {
msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p);
}
else {
// method name might be missing
msg = uwsgi_concat2("uWSGI segfault in ", p);
}
}
if ((n+1)[0] == ')') {
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()");
}
else {
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST n+1);
}
xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p);
xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
}
next:
p = strtok(NULL, "\n");
}
xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg);
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
xmlFreeDoc(doc);
xmlCleanupParser();
xmlMemoryDump();
free(ut->buf);
free(msg);
ut->buf = (char *) xmlbuff;
ut->len = strlen(ut->buf);
}
static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
int interesting_fd;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
CURL *curl = curl_easy_init();
// ARGH !!!
if (!curl) return;
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_airbrake_read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
char *opts = uwsgi_str(uacc->arg);
// fill curl options
char *ctx = NULL;
char *p = strtok_r(opts, ";", &ctx);
while(p) {
uwsgi_airbrake_setopt(curl, uwsgi_str(p), uacc);
p = strtok_r(NULL, ";", &ctx);
}
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret <= 0) continue;
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
ut->pos = 0;
ut->len = (size_t) rlen;
ut->custom0 = 0;
uwsgi_format_airbrake_backtrace(ut, uacc->apikey);
curl_slist_append(expect, "Accept: */*");
curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ut->buf);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, ut->len);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
}
}
static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_airbrake_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config));
uacc->arg = uai->arg;
ut->data = uacc;
}
static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
ut->rlen = write(ut->pipe[0], msg, len);
}
static void uwsgi_airbrake_load(void) {
uwsgi_register_alarm("airbrake", uwsgi_airbrake_init, uwsgi_airbrake_func);
}
struct uwsgi_plugin airbrake_plugin = {
.name = "airbrake",
.on_load = uwsgi_airbrake_load,
};
+9
View File
@@ -0,0 +1,9 @@
from uwsgiconfig import spcall
NAME='airbrake'
CFLAGS = [spcall('xml2-config --cflags')]
LDFLAGS = []
LIBS = ['-lcurl', spcall('xml2-config --libs')]
GCC_LIST = ['airbrake_plugin']
+9 -5
View File
@@ -40,7 +40,7 @@ static void cache_simple_command(char *key, uint16_t keylen, char *val, uint16_t
if (vallen > 0) {
if (!uwsgi_strncmp(key, keylen, "key", 3)) {
uint64_t vallen = 0;
char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL);
char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL, NULL);
if (value) {
uwsgi_response_write_body_do(wsgi_req, value, vallen);
free(value);
@@ -49,7 +49,7 @@ static void cache_simple_command(char *key, uint16_t keylen, char *val, uint16_t
}
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
uint64_t vallen = 0;
char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL);
char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL, NULL);
if (value) {
uwsgi_response_write_body_do(wsgi_req, value, vallen);
free(value);
@@ -77,8 +77,9 @@ static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cac
// cache get
if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "get", 3)) {
uint64_t vallen = 0;
uint64_t expires = 0;
uwsgi_rlock(uc->lock);
char *value = uwsgi_cache_get2(uc, ucmc->key, ucmc->key_len, &vallen);
char *value = uwsgi_cache_get3(uc, ucmc->key, ucmc->key_len, &vallen, &expires);
if (!value) {
uwsgi_rwunlock(uc->lock);
return;
@@ -88,6 +89,9 @@ static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cac
ub->pos = 4;
if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error;
if (uwsgi_buffer_append_keynum(ub, "size", 4, vallen)) goto error;
if (expires) {
if (uwsgi_buffer_append_keynum(ub, "expires", 7, expires)) goto error;
}
if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error;
if (uwsgi_buffer_append(ub, value, vallen)) goto error;
// unlock !!!
@@ -205,7 +209,7 @@ static int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
case 0:
// get
if (wsgi_req->uh->pktsize > 0) {
value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL);
value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL, NULL);
if (value) {
wsgi_req->uh->pktsize = vallen;
if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ; return -1;}
@@ -242,7 +246,7 @@ static int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
case 5:
// get (uwsgi + stream)
if (wsgi_req->uh->pktsize > 0) {
value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL);
value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL, NULL);
if (value) {
wsgi_req->uh->pktsize = 0;
wsgi_req->uh->modifier2 = 1;
+6 -6
View File
@@ -293,18 +293,17 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
#endif
}
if (peer->failed) {
if (peer->soopt) {
if (!ucr->quiet)
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\": %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, strerror(peer->soopt));
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt));
}
else if (peer->timed_out) {
if (peer->instance_address_len > 0) {
if (peer->connecting) {
if (!ucr->quiet)
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\": timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address);
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries);
}
}
}
@@ -701,7 +700,8 @@ void uwsgi_corerouter_loop(int id, void *data) {
if (ucr->use_cache) {
ucr->cache = uwsgi_cache_by_name(ucr->use_cache);
if (!ucr->cache) {
uwsgi_log("unable to find cache \"%s\"\n", ucr->use_cache);
uwsgi_log("!!! unable to find cache \"%s\" !!!\n", ucr->use_cache);
exit(1);
}
ucr->mapper = uwsgi_cr_map_use_cache;
}
@@ -899,7 +899,7 @@ int uwsgi_corerouter_init(struct uwsgi_corerouter *ucr) {
if (ucr->has_sockets) {
if (ucr->use_cache && !uwsgi.cache_max_items) {
if (ucr->use_cache && !uwsgi.caches) {
uwsgi_log("you need to create a uwsgi cache to use the %s (add --cache <n>)\n", ucr->name);
exit(1);
}
@@ -945,7 +945,7 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
int client_fd = accept(ucr->cr_stats_server, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd < 0) {
uwsgi_error("accept()");
uwsgi_error("corerouter_send_stats()/accept()");
return;
}
+1 -1
View File
@@ -173,7 +173,7 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
continue;
if (!strcmp(ushared->gateways[i].name, ucr->name)) {
if (send(ushared->gateways[i].internal_subscription_pipe[0], bbuf, len, 0) != len) {
uwsgi_error("send()");
uwsgi_error("uwsgi_corerouter_manage_subscription()/send()");
}
}
}
+8 -3
View File
@@ -154,9 +154,14 @@ XS(XS_coroae_accept_request) {
request:
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
goto end;
}
#endif
for(;;) {
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
if (wsgi_req->async_status <= UWSGI_OK) {
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req)) {
goto end;
}
wsgi_req->switches++;
@@ -171,7 +176,7 @@ end:
}
XS(XS_coroae_sighandler) {
int sigfd = (int) XSANY.any_ptr;
int sigfd = (long) XSANY.any_ptr;
uwsgi_receive_signal(sigfd, "worker", uwsgi.mywid);
}
+58
View File
@@ -0,0 +1,58 @@
#include <uwsgi.h>
#include <curl/curl.h>
extern struct uwsgi_server uwsgi;
static void curl_cron_func(struct uwsgi_cron *uc, time_t now) {
CURL *curl = curl_easy_init();
// ARGH !!!
if (!curl) return;
curl_easy_setopt(curl, CURLOPT_URL, uc->command);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
// use 1 minute as the cron resolution
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);
uwsgi_log("[uwsgi-curl-cron] requesting %s\n", uc->command);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log("[uwsgi-curl-cron] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
static void uwsgi_opt_add_cron_curl(char *opt, char *value, void *foobar) {
struct uwsgi_cron *uc = uwsgi_cron_add(value);
uc->func = curl_cron_func;
}
#ifdef UWSGI_SSL
static void uwsgi_opt_add_legion_cron_curl(char *opt, char *value, void *foobar) {
char *space = strchr(value, ' ');
if (!space) {
uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt);
exit(1);
}
char *legion = uwsgi_concat2n(value, space-value, "", 0);
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
uc->legion = legion;
uc->func = curl_cron_func;
}
#endif
static struct uwsgi_option curl_cron_options[] = {
{"curl-cron", required_argument, 0, "add a cron task invoking the specified url via CURL", uwsgi_opt_add_cron_curl, NULL, UWSGI_OPT_MASTER},
{"cron-curl", required_argument, 0, "add a cron task invoking the specified url via CURL", uwsgi_opt_add_cron_curl, NULL, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion-curl-cron", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER},
{"legion-cron-curl", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER},
{"curl-cron-legion", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER},
{"cron-curl-legion", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER},
#endif
{ 0, 0, 0, 0, 0, 0, 0},
};
struct uwsgi_plugin curl_cron_plugin = {
.name = "curl_cron",
.options = curl_cron_options,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='curl_cron'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lcurl']
GCC_LIST = ['curl_cron']
+19 -7
View File
@@ -16,8 +16,7 @@ struct uwsgi_option fiber_options[] = {
VALUE uwsgi_fiber_request() {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
async_schedule_to_req_green();
return Qnil;
}
@@ -32,30 +31,43 @@ VALUE rb_fiber_schedule_to_req() {
rb_fiber_resume(ufiber.fib[id], 0, NULL);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
return Qnil;
}
static void fiber_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
int error = 0;
rb_protect(rb_fiber_schedule_to_req, 0, &error);
// call it in the main core
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
if (error) {
rack_plugin.exception_log(NULL);
rb_gc_unregister_address(&ufiber.fib[id]);
uwsgi.wsgi_req->async_status = UWSGI_OK;
}
}
static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
rb_fiber_yield(0, NULL);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
}
+34 -4
View File
@@ -29,7 +29,7 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL);
PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL);
@@ -54,7 +54,16 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
if (running_cores > 0) {
uwsgi_log_verbose("waiting for %d running requests on worker %d (pid: %d)...\n", running_cores, uwsgi.mywid, uwsgi.mypid);
}
} else {
// no need to worry about freeing memory
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
if (ae) {
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
}
Py_INCREF(Py_None);
return Py_None;
@@ -242,8 +251,7 @@ request:
#endif
for(;;) {
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
if (wsgi_req->async_status <= UWSGI_OK) {
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
goto end;
}
wsgi_req->switches++;
@@ -259,6 +267,28 @@ end2:
uwsgi_close_request(wsgi_req);
free_req_queue;
if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) {
int running_cores = 0;
int i;
for(i=0;i<uwsgi.async;i++) {
if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) {
running_cores++;
}
}
if (running_cores == 0) {
// no need to worry about freeing memory
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
if (ae) {
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
}
}
Py_INCREF(Py_None);
return Py_None;
+8 -6
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -48,9 +48,6 @@ static int uwsgi_go_init() {
uwsgi_log("Go version \"%s\" initialized\n", uwsgi_go_helper_version_c());
// call PostInit()
uwsgi_go_helper_post_init_c();
return 0;
}
@@ -80,9 +77,7 @@ static int uwsgi_go_request(struct wsgi_request *wsgi_req) {
}
static void uwsgi_go_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_go_signal_handler(uint8_t signum, void *handler) {
@@ -101,11 +96,18 @@ static void uwsgi_go_on_load() {
uwsgi_register_loop("goroutines", goroutines_loop);
}
static void uwsgi_go_call_init_hook() {
if (uwsgi_go_helper_post_init_c) {
uwsgi_go_helper_post_init_c();
}
}
struct uwsgi_plugin go_plugin = {
.name = "go",
.modifier1 = 11,
.request = uwsgi_go_request,
.after_request = uwsgi_go_after_request,
.preinit_apps = uwsgi_go_call_init_hook,
.post_fork = uwsgi_go_post_fork,
.init = uwsgi_go_init,
.signal_handler = uwsgi_go_signal_handler,
+3 -3
View File
@@ -150,7 +150,7 @@ func CacheGet(key string, cache string) []byte {
var p []byte
c_value := C.uwsgi_cache_magic_get(k, C.uint16_t(kl), &vl, c)
c_value := C.uwsgi_cache_magic_get(k, C.uint16_t(kl), &vl, (*C.uint64_t)(nil), c)
if c_value != nil {
p = C.GoBytes((unsafe.Pointer)(c_value), C.int(vl))
@@ -411,10 +411,10 @@ func uwsgi_go_helper_run_core(core_id int) {
the main function, running the uWSGI server via libuwsgi.so
*/
func Run() {
argc := len(os.Args)
argc := len(os.Args) + 1
argv := C.uwsgi_go_helper_create_argv(C.int(argc))
for i, s := range os.Args {
C.uwsgi_go_helper_set_argv(argv, C.int(i), C.CString(s))
}
C.uwsgi_init(C.int(argc), argv, nil)
C.uwsgi_init(C.int(argc-1), argv, nil)
}
+46 -21
View File
@@ -2,6 +2,7 @@
#include <greenlet/greenlet.h>
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
struct ugreenlet {
int enabled;
@@ -10,15 +11,22 @@ struct ugreenlet {
PyGreenlet **gl;
} ugl;
struct uwsgi_option greenlet_options[] = {
static struct uwsgi_option greenlet_options[] = {
{"greenlet", no_argument, 0, "enable greenlet as suspend engine", uwsgi_opt_true, &ugl.enabled, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
};
PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
static void gil_greenlet_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
static void gil_greenlet_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
async_schedule_to_req_green();
Py_DECREF(ugl.gl[uwsgi.wsgi_req->async_id]);
@@ -28,45 +36,66 @@ PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
PyMethodDef uwsgi_greenlet_request_method[] = {{"uwsgi_greenlet_request", py_uwsgi_greenlet_request, METH_VARARGS, ""}};
static inline void greenlet_schedule_to_req() {
static void greenlet_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// ensure gil
UWSGI_GET_GIL
if (!uwsgi.wsgi_req->suspended) {
ugl.gl[id] = PyGreenlet_New(ugl.callable, NULL);
uwsgi.wsgi_req->suspended = 1;
}
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
}
static inline void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
// ensure gil
UWSGI_GET_GIL
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyGreenlet_Switch(ugl.main, NULL, NULL);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
}
static int greenlet_init() {
return 0;
}
static void greenlet_init_apps(void) {
if (!ugl.enabled) {
return;
}
if (!ugl.enabled) return;
if (uwsgi.async <= 1) {
uwsgi_log("the greenlet loop engine requires async mode\n");
uwsgi_log("the greenlet suspend engine requires async mode\n");
exit(1);
}
if (uwsgi.has_threads) {
up.gil_get = gil_greenlet_get;
up.gil_release = gil_greenlet_release;
}
// blindy call it as the stackless gil engine is already set
UWSGI_GET_GIL
PyGreenlet_Import();
@@ -77,15 +106,11 @@ static void greenlet_init_apps(void) {
uwsgi.schedule_to_main = greenlet_schedule_to_main;
uwsgi.schedule_to_req = greenlet_schedule_to_req;
return;
}
struct uwsgi_plugin greenlet_plugin = {
.name = "greenlet",
.init = greenlet_init,
.init_apps = greenlet_init_apps,
.options = greenlet_options,
};
+4 -8
View File
@@ -197,14 +197,7 @@ extern "C" int uwsgi_gridfs_request(struct wsgi_request *wsgi_req) {
return -1;
}
if (wsgi_req->appid_len == 0) {
if (!uwsgi.ignore_script_name) {
wsgi_req->appid = wsgi_req->script_name;
wsgi_req->appid_len = wsgi_req->script_name_len;
}
}
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, gridfs_plugin.modifier1);
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, gridfs_plugin.modifier1);
if (ugridfs.debug) {
uwsgi_log("[uwsgi-gridfs-debug] app_id = %d\n", wsgi_req->app_id);
}
@@ -238,6 +231,9 @@ extern "C" int uwsgi_gridfs_request(struct wsgi_request *wsgi_req) {
extern "C" void uwsgi_gridfs_mount() {
if (!uwsgi.skip_atexit) {
uwsgi_log("*** WARNING libmongoclient could have a bug with atexit() hooks, if you get segfault on end/reload, add --skip-atexit ***\n");
}
struct uwsgi_string_list *usl = ugridfs.mountpoints;
while(usl) {
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
+13 -8
View File
@@ -90,31 +90,35 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
if (!keylen)
return -1;
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
}
else if (hr->websockets) {
if (hr->websockets) {
if (!uwsgi_strncmp("UPGRADE", 7, hh, keylen)) {
if (!uwsgi_strnicmp(val, vallen, "websocket", 9)) {
hr->websockets++;
}
goto done;
}
else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) {
if (!uwsgi_strnicmp(val, vallen, "Upgrade", 7)) {
hr->websockets++;
}
goto done;
}
else if (!uwsgi_strncmp("SEC_WEBSOCKET_VERSION", 21, hh, keylen)) {
hr->websockets++;
hr->websockets++;
goto done;
}
else if (!uwsgi_strncmp("SEC_WEBSOCKET_KEY", 17, hh, keylen)) {
hr->websocket_key = val;
hr->websocket_key_len = vallen;
goto done;
}
}
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
}
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
hr->content_length = uwsgi_str_num(val, vallen);
hr->session.can_keepalive = 0;
@@ -139,12 +143,13 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
}
#endif
done:
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
keylen += 5;
prefix = 1;
}
if (uwsgi_buffer_u16le(out, keylen)) return -1;
if (prefix) {
+3 -3
View File
@@ -41,7 +41,7 @@ JNIEXPORT void JNICALL uwsgi_jvm_api_register_signal(JNIEnv *env, jclass c, jint
JNIEXPORT void JNICALL uwsgi_jvm_api_register_rpc(JNIEnv *env, jclass c, jstring name, jobject func) {
// no need to release it
char *n = uwsgi_jvm_str2c(name);
if (uwsgi_register_rpc(n, jvm_plugin.modifier1, 0, uwsgi_jvm_ref(func))) {
if (uwsgi_register_rpc(n, &jvm_plugin, 0, uwsgi_jvm_ref(func))) {
uwsgi_jvm_throw("unable to register rpc function");
}
}
@@ -79,7 +79,7 @@ JNIEXPORT jobject JNICALL uwsgi_jvm_api_cache_get(JNIEnv *env, jclass c, jstring
size_t keylen = uwsgi_jvm_strlen(jkey);
char *key = uwsgi_jvm_str2c(jkey);
uint64_t vallen = 0;
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL);
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, NULL);
uwsgi_jvm_release_chars(jkey, key);
if (value) {
jobject o = uwsgi_jvm_bytearray(value, vallen);
@@ -99,7 +99,7 @@ JNIEXPORT jobject JNICALL uwsgi_jvm_api_cache_get_name(JNIEnv *env, jclass c, js
char *key = uwsgi_jvm_str2c(jkey);
char *cache = uwsgi_jvm_str2c(jcache);
uint64_t vallen = 0;
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, cache);
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache);
uwsgi_jvm_release_chars(jkey, key);
uwsgi_jvm_release_chars(jcache, cache);
if (value) {
+278 -1
View File
@@ -1,5 +1,13 @@
#include <uwsgi.h>
/*
Authors:
Roberto De Ioris <roberto@unbit.it> - general LDAP support, reading uWSGI configuration from LDAP servers
Łukasz Mierzwa <l.mierzwa@gmail.com> - LDAP auth router support
*/
extern struct uwsgi_server uwsgi;
#include <ldap.h>
@@ -366,7 +374,276 @@ static void uwsgi_ldap_config(char *url) {
}
#ifdef UWSGI_ROUTING
struct uwsgi_ldapauth_config {
char *url;
LDAPURLDesc *ldap_url;
char *binddn;
char *bindpw;
char *basedn;
char *filter;
char *login_attr;
int loglevel;
};
static uint16_t ldap_passwd_check(struct uwsgi_ldapauth_config *ulc, char *auth) {
char *colon = strchr(auth, ':');
if (!colon) return 0;
int ret;
uint16_t ulen = 0;
LDAP *ldp;
int desired_version = LDAP_VERSION3;
#if LDAP_API_VERSION >= 3000
if ((ret = ldap_initialize(&ldp, ulc->url)) != LDAP_SUCCESS) {
uwsgi_log("[router-ldapauth] can't connect to LDAP server at %s\n", ulc->url);
return 0;
}
#else
if ((ldp = ldap_init(ulc->ldap_url->lud_host, ulc->ldap_url->lud_port)) == NULL) {
uwsgi_log("[router-ldapauth] can't connect to LDAP server at %s\n", ulc->url);
return 0;
}
#endif
if ((ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) {
uwsgi_log("[router-ldapauth] LDAP protocol version mismatch: %s\n", ldap_err2string(ret));
goto close;
}
// first bind if needed
if (ulc->binddn && ulc->bindpw) {
#if LDAP_API_VERSION >= 3000
struct berval bval;
bval.bv_val = ulc->bindpw;
bval.bv_len = strlen(bval.bv_val);
if ((ret = ldap_sasl_bind_s(ldp, ulc->binddn, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL)) != LDAP_OPT_SUCCESS) {
#else
if ((ret = ldap_bind_s(ldp, ulc->binddn, ulc->bindpw, LDAP_AUTH_SIMPLE)) != LDAP_OPT_SUCCESS) {
#endif
uwsgi_log("[router-ldapauth] can't bind as user '%s' to '%s': %s\n", ulc->binddn, ulc->url, ldap_err2string(ret));
goto close;
}
}
// search for user
char *userdn = NULL;
LDAPMessage *msg, *entry;
// use the minimal amount of memory
char *filter = uwsgi_malloc( strlen(ulc->login_attr) + (colon-auth) + strlen(ulc->filter) + 7);
if (snprintf(filter, 1024, "(&(%s=%.*s)%s)", ulc->login_attr, (int) (colon-auth), auth, ulc->filter) <= 0) {
free(filter);
uwsgi_error("ldap_passwd_check()/sprintfn(filter)");
goto close;
}
if ((ret = ldap_search_ext_s(ldp, ulc->basedn, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS) {
free(filter);
uwsgi_log("[router-ldapauth] search error on '%s': %s\n", ulc->url, ldap_err2string(ret));
goto close;
}
else {
free(filter);
entry = ldap_first_entry(ldp, msg);
while (entry) {
struct berval **vals = ldap_get_values_len(ldp, entry, ulc->login_attr);
if (!uwsgi_strncmp(auth, colon-auth, vals[0]->bv_val, vals[0]->bv_len)) {
userdn = ldap_get_dn(ldp, entry);
free(vals);
break;
}
free(vals);
entry = ldap_next_entry(ldp, entry);
}
ldap_msgfree(msg);
}
if (userdn) {
// user found in ldap, try to bind
#if LDAP_API_VERSION >= 3000
struct berval bval;
bval.bv_val = colon+1;
bval.bv_len = strlen(bval.bv_val);
if ((ret = ldap_sasl_bind_s(ldp, userdn, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL)) != LDAP_OPT_SUCCESS) {
#else
if ((ret = ldap_bind_s(ldp, userdn, colon+1, LDAP_AUTH_SIMPLE)) != LDAP_OPT_SUCCESS) {
#endif
if (ulc->loglevel)
uwsgi_log("[router-ldapauth] can't bind as user '%s' to '%s': %s\n", userdn, ulc->url, ldap_err2string(ret));
}
else {
if (ulc->loglevel > 1)
uwsgi_log("[router-ldapauth] successful bind as user '%s' to '%s'\n", userdn, ulc->url);
ulen = colon-auth;
}
ldap_memfree(userdn);
}
else if (ulc->loglevel) {
uwsgi_log("router-ldapauth] user '%.*s' not found in LDAP server at '%s'\n", colon-auth, auth, ulc->url);
}
close:
if ((ret = ldap_unbind_ext_s(ldp, NULL, NULL)) != LDAP_OPT_SUCCESS) {
uwsgi_log("[router-ldapauth] LDAP unbind error: %s\n", ldap_err2string(ret));
}
return ulen;
}
int uwsgi_routing_func_ldapauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
// skip if already authenticated
if (wsgi_req->remote_user_len > 0) {
return UWSGI_ROUTE_NEXT;
}
if (wsgi_req->authorization_len > 7 && ur->data2) {
if (strncmp(wsgi_req->authorization, "Basic ", 6))
goto forbidden;
size_t auth_len = 0;
char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len);
if (auth) {
if (!ur->custom) {
uint16_t ulen = ldap_passwd_check(ur->data2, auth);
if (ulen > 0) {
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen);
if (wsgi_req->remote_user)
wsgi_req->remote_user_len = ulen;
}
else if (ur->data3_len == 0) {
free(auth);
goto forbidden;
}
}
free(auth);
return UWSGI_ROUTE_NEXT;
}
}
forbidden:
if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1);
int ret = uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
free(realm);
if (ret) goto end;
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
end:
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_ldapauth(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_ldapauth;
char *comma = strchr(args, ',');
if (!comma) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
*comma = 0;
ur->data = args;
ur->data_len = strlen(args);
char *url = NULL;
char *binddn = NULL;
char *bindpw = NULL;
char *basedn = NULL;
char *filter = NULL;
char *attr = NULL;
char *loglevel = NULL;
if (uwsgi_kvlist_parse(comma+1, strlen(comma+1), ';', '=',
"url", &url,
"binddn", &binddn,
"bindpw", &bindpw,
"basedn", &basedn,
"filter", &filter,
"attr", &attr,
"loglevel", &loglevel,
NULL)) {
uwsgi_log("[router-ldapauth] unable to parse options: %s\n", comma+1);
exit(1);
}
else {
struct uwsgi_ldapauth_config *ulc = uwsgi_malloc(sizeof(struct uwsgi_ldapauth_config));
if (!basedn) {
uwsgi_log("[router-ldapauth] missing LDAP base dn (basedn option) on line: %s\n", comma+1);
exit(1);
}
else {
ulc->basedn = basedn;
}
if (!url) {
uwsgi_log("[router-ldapauth] missing LDAP server url (url option) on line: %s\n", comma+1);
exit(1);
}
else {
if (!ldap_is_ldap_url(url)) {
uwsgi_log("[router-ldapauth] invalid LDAP url: %s\n", url);
exit(1);
}
if (ldap_url_parse(url, &ulc->ldap_url) != LDAP_SUCCESS) {
uwsgi_log("[router-ldapauth] unable to parse LDAP url: %s\n", url);
exit(1);
}
}
if (!filter) {
ulc->filter = uwsgi_str("(objectClass=*)");
}
else {
ulc->filter = filter;
}
if (!attr) {
ulc->login_attr = uwsgi_str("uid");
}
else {
ulc->login_attr = attr;
}
ulc->url = url;
ulc->binddn = binddn;
ulc->bindpw = bindpw;
if (loglevel) {
ulc->loglevel = atoi(loglevel);
}
else {
ulc->loglevel = 0;
}
ur->data2 = ulc;
}
return 0;
}
static int uwsgi_router_ldapauth_next(struct uwsgi_route *ur, char *args) {
ur->data3_len = 1;
return uwsgi_router_ldapauth(ur, args);
}
#endif
void uwsgi_ldap_register(void) {
#ifdef UWSGI_ROUTING
uwsgi_register_router("ldapauth", uwsgi_router_ldapauth);
uwsgi_register_router("ldapauth-next", uwsgi_router_ldapauth_next);
#endif
}
struct uwsgi_plugin ldap_plugin = {
.name = "ldap",
.options = uwsgi_ldap_options,
.options = uwsgi_ldap_options,
.on_load = uwsgi_ldap_register,
};
@@ -0,0 +1,71 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
static int legion_action_cache_fetch_from_legion(struct uwsgi_legion *ul, char *arg) {
uwsgi_log("[legion-cache-fetch] getting cache '%s' dump from legion '%s' nodes\n", arg, ul->legion);
struct uwsgi_cache *uc = uwsgi_cache_by_name(arg);
if (!uc) {
uwsgi_log("[legion-cache-fetch] cannot sync, cache '%s' not found\n", arg);
return 1;
}
struct uwsgi_string_list *dump_from_nodes = NULL;
uwsgi_rlock(ul->lock);
struct uwsgi_legion_node *legion_nodes = ul->nodes_head;
while (legion_nodes) {
char *dump_socket = NULL;
if (uwsgi_kvlist_parse(legion_nodes->scroll, legion_nodes->scroll_len, ',', '=',
"dump-socket", &dump_socket,
NULL)) {
uwsgi_log("[legion-cache-fetch] cannot sync from %.*s, cache socket address not found in legion scroll: %.*s\n",
legion_nodes->name_len, legion_nodes->name, legion_nodes->scroll_len, legion_nodes->scroll);
}
else {
if (dump_socket) {
uwsgi_string_new_list(&dump_from_nodes, dump_socket);
}
else {
uwsgi_log("[legion-cache-fetch] cannot sync from %.*s, cache socket address not found in legion scroll: %.*s\n",
legion_nodes->name_len, legion_nodes->name, legion_nodes->scroll_len, legion_nodes->scroll);
}
}
legion_nodes = legion_nodes->next;
}
// update uc->sync_nodes list
struct uwsgi_string_list *usl = uc->sync_nodes;
struct uwsgi_string_list *next;
while (usl) {
next = usl->next;
free(usl->value);
free(usl);
usl = next;
}
uwsgi_rwunlock(ul->lock);
uwsgi_rlock(uc->lock);
uc->sync_nodes = dump_from_nodes;
uwsgi_rwunlock(uc->lock);
// call sync
uwsgi_cache_sync_from_nodes(uc);
return 0;
}
static void legion_cache_register() {
uwsgi_legion_action_register("legion-cache-fetch", legion_action_cache_fetch_from_legion);
}
struct uwsgi_plugin legion_cache_fetch_plugin = {
.name = "legion_cache_fetch",
.on_load = legion_cache_register,
};
@@ -0,0 +1,8 @@
NAME = 'legion_cache_fetch'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['legion_cache_fetch']
+5 -3
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include <lua.h>
#include <lualib.h>
@@ -13,6 +13,8 @@ struct uwsgi_lua {
struct uwsgi_string_list *load;
} ulua;
struct uwsgi_plugin lua_plugin;
#define lca(L, n) ulua_check_args(L, __FUNCTION__, n)
static void uwsgi_opt_luashell(char *opt, char *value, void *foobar) {
@@ -88,7 +90,7 @@ static int uwsgi_api_register_rpc(lua_State *L) {
uwsgi_log("registered function %d in Lua global table\n", func);
lfunc = func;
if (uwsgi_register_rpc((char *)name, 6, 0, (void *) lfunc)) {
if (uwsgi_register_rpc((char *)name, &lua_plugin, 0, (void *) lfunc)) {
lua_pushnil(L);
}
else {
@@ -276,7 +278,7 @@ static int uwsgi_api_cache_get(lua_State *L) {
if (argc > 1) {
cache = lua_tolstring(L, 2, NULL);
}
value = uwsgi_cache_magic_get((char *)key, keylen, &valsize, (char *)cache);
value = uwsgi_cache_magic_get((char *)key, keylen, &valsize, NULL, (char *)cache);
if (value) {
lua_pushlstring(L, value, valsize);
free(value);
+3 -3
View File
@@ -267,7 +267,7 @@ static MonoArray *uwsgi_mono_method_api_CacheGet(MonoString *key, MonoString *ca
c_cache = mono_string_to_utf8(cache);
}
uint64_t vallen = 0 ;
char *value = uwsgi_cache_magic_get(c_key, c_keylen, &vallen, c_cache);
char *value = uwsgi_cache_magic_get(c_key, c_keylen, &vallen, NULL, c_cache);
if (value) {
MonoArray *ret = mono_array_new(mono_domain_get(), umono.byte_class, vallen);
char *buf = mono_array_addr(ret, char, 0);
@@ -540,7 +540,7 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
key_len = 0;
}
wsgi_req->app_id = uwsgi_get_app_id(key, key_len, mono_plugin.modifier1);
wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1);
// if it is -1, try to load a dynamic app
if (wsgi_req->app_id == -1) {
if (uwsgi.threads > 1) {
@@ -548,7 +548,7 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
}
// check if the mean time, something changed
wsgi_req->app_id = uwsgi_get_app_id(key, key_len, mono_plugin.modifier1);
wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1);
if (wsgi_req->app_id == -1) {
wsgi_req->app_id = uwsgi_mono_create_app(key, key_len, key, key_len, 0);
+1 -1
View File
@@ -309,7 +309,7 @@ PHP_FUNCTION(uwsgi_cache_get) {
RETURN_NULL();
}
char *value = uwsgi_cache_magic_get(key, keylen, &valsize, cache);
char *value = uwsgi_cache_magic_get(key, keylen, &valsize, NULL, cache);
if (value) {
char *ret = estrndup(value, valsize);
free(value);
+1 -1
View File
@@ -17,7 +17,7 @@ try:
except:
pass
CFLAGS = [os.popen(PHPPATH + ' --includes').read().rstrip(), '-Wno-error=sign-compare']
CFLAGS = [os.popen(PHPPATH + ' --includes').read().rstrip(), '-Wno-sign-compare']
LDFLAGS = os.popen(PHPPATH + ' --ldflags').read().rstrip().split()
if ld_run_path:
+38 -2
View File
@@ -394,7 +394,7 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
return -1;
}
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, psgi_plugin.modifier1);
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, psgi_plugin.modifier1);
// if it is -1, try to load a dynamic app
if (wsgi_req->app_id == -1) {
if (wsgi_req->dynamic) {
@@ -621,7 +621,7 @@ void uwsgi_perl_enable_threads(void) {
#endif
}
int uwsgi_perl_signal_handler(uint8_t sig, void *handler) {
static int uwsgi_perl_signal_handler(uint8_t sig, void *handler) {
int ret = 0;
@@ -688,6 +688,41 @@ realstuff:
}
}
static uint16_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
int i;
uint16_t ret = 0;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
for(i=0;i<argc;i++) {
XPUSHs( sv_2mortal(newSVpv(argv[i], argvs[i])));
}
PUTBACK;
call_sv( SvRV((SV*)func), G_SCALAR | G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV));
}
else {
STRLEN rlen;
SV *response = POPs;
char *value = SvPV(response, rlen );
ret = UMIN(UMAX16, rlen);
memcpy(buffer, value, ret);
}
PUTBACK;
FREETMPS;
LEAVE;
return ret;
}
struct uwsgi_plugin psgi_plugin = {
.name = "psgi",
@@ -700,6 +735,7 @@ struct uwsgi_plugin psgi_plugin = {
.init_thread = uwsgi_perl_init_thread,
.signal_handler = uwsgi_perl_signal_handler,
.rpc = uwsgi_perl_rpc,
.mule = uwsgi_perl_mule,
+3 -4
View File
@@ -11,7 +11,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
char *chitem, *chitem2;
SV **harakiri;
if (wsgi_req->async_status == UWSGI_AGAIN) {
if (wsgi_req->async_force_again) {
wsgi_req->async_force_again = 0;
@@ -53,7 +53,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
return UWSGI_OK;
}
SvREFCNT_dec(chunk);
wsgi_req->async_force_again = 1;
return UWSGI_AGAIN;
}
@@ -141,7 +141,6 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
chitem = SvPV( chunk, hlen);
if (uwsgi.async > 1 && wsgi_req->async_force_again) {
SvREFCNT_dec(chunk);
wsgi_req->async_status = UWSGI_AGAIN;
wsgi_req->async_placeholder = (SV *) *hitem;
return UWSGI_AGAIN;
}
@@ -157,8 +156,8 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
}
SvREFCNT_dec(chunk);
if (uwsgi.async > 1) {
wsgi_req->async_status = UWSGI_AGAIN;
wsgi_req->async_placeholder = (SV *) *hitem;
wsgi_req->async_force_again = 1;
return UWSGI_AGAIN;
}
}
+17 -1
View File
@@ -136,7 +136,7 @@ XS(XS_cache_get) {
cache = SvPV_nolen(ST(1));
}
char *value = uwsgi_cache_magic_get(key, (uint16_t) keylen, &vallen, cache);
char *value = uwsgi_cache_magic_get(key, (uint16_t) keylen, &vallen, NULL, cache);
if (value) {
ST(0) = newSVpv(value, vallen);
free(value);
@@ -233,6 +233,21 @@ XS(XS_register_signal) {
}
XS(XS_register_rpc) {
dXSARGS;
psgi_check_args(2);
char *name = SvPV_nolen(ST(0));
if (uwsgi_register_rpc(name, &psgi_plugin, 0, (void *) newRV_inc(ST(1)))) {
XSRETURN_NO;
}
XSRETURN_YES;
}
XS(XS_postfork) {
dXSARGS;
@@ -519,6 +534,7 @@ void init_perl_embedded_module() {
psgi_xs(suspend);
psgi_xs(signal);
psgi_xs(register_signal);
psgi_xs(register_rpc);
psgi_xs(signal_wait);
#ifdef UWSGI_SSL
psgi_xs(i_am_the_lord);
+1 -1
View File
@@ -86,7 +86,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
time_t now = uwsgi_now();
if (uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, -1) != -1) {
if (uwsgi_get_app_id(NULL, wsgi_req->appid, wsgi_req->appid_len, -1) != -1) {
uwsgi_log( "mountpoint %.*s already configured. skip.\n", wsgi_req->appid_len, wsgi_req->appid);
return -1;
}
+8
View File
@@ -1,5 +1,13 @@
#include "uwsgi_python.h"
/*
This is the official python plugin, the one with the modifier1 mapped to 0
Since uWSGI 1.0 it is heavily based on Graham Dumpleton mod_wsgi (for Apache)
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_python up;
+135 -4
View File
@@ -2,6 +2,7 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern struct uwsgi_plugin python_plugin;
PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
@@ -394,7 +395,7 @@ PyObject *py_uwsgi_register_rpc(PyObject * self, PyObject * args) {
}
if (uwsgi_register_rpc(name, 0, argc, func)) {
if (uwsgi_register_rpc(name, &python_plugin, argc, func)) {
return PyErr_Format(PyExc_ValueError, "unable to register rpc function");
}
@@ -2554,7 +2555,7 @@ PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) {
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#s#|is:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) {
if (!PyArg_ParseTuple(args, "s#s#|ls:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) {
return NULL;
}
@@ -2581,7 +2582,7 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#s#|is:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) {
if (!PyArg_ParseTuple(args, "s#s#|ls:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) {
return NULL;
}
@@ -2598,6 +2599,106 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_cache_inc(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 1;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_inc", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_INC, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_dec(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 1;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_dec", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DEC, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_mul(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 2;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_mul", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_MUL, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_div(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 2;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_div", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DIV, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) {
@@ -2925,7 +3026,7 @@ PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) {
uint64_t vallen = 0;
UWSGI_RELEASE_GIL
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, cache);
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache);
UWSGI_GET_GIL
if (value) {
// in python 3.x we return bytes
@@ -2939,6 +3040,31 @@ PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_cache_num(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *cache = NULL;
if (!PyArg_ParseTuple(args, "s#|s:cache_num", &key, &keylen, &cache)) {
return NULL;
}
uint64_t vallen = 0;
UWSGI_RELEASE_GIL
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache);
UWSGI_GET_GIL
if (value && vallen == 8) {
int64_t *num = (int64_t *) value;
PyObject *ret = PyLong_FromLong(*num);
free(value);
return ret;
}
return PyLong_FromLong(0);
}
static PyMethodDef uwsgi_cache_methods[] = {
{"cache_get", py_uwsgi_cache_get, METH_VARARGS, ""},
{"cache_set", py_uwsgi_cache_set, METH_VARARGS, ""},
@@ -2946,6 +3072,11 @@ static PyMethodDef uwsgi_cache_methods[] = {
{"cache_del", py_uwsgi_cache_del, METH_VARARGS, ""},
{"cache_exists", py_uwsgi_cache_exists, METH_VARARGS, ""},
{"cache_clear", py_uwsgi_cache_clear, METH_VARARGS, ""},
{"cache_inc", py_uwsgi_cache_inc, METH_VARARGS, ""},
{"cache_dec", py_uwsgi_cache_dec, METH_VARARGS, ""},
{"cache_mul", py_uwsgi_cache_mul, METH_VARARGS, ""},
{"cache_div", py_uwsgi_cache_div, METH_VARARGS, ""},
{"cache_num", py_uwsgi_cache_num, METH_VARARGS, ""},
{NULL, NULL},
};
+16 -33
View File
@@ -293,10 +293,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
struct uwsgi_app *wi;
int free_appid = 0;
if (wsgi_req->async_status == UWSGI_AGAIN) {
if (wsgi_req->async_force_again) {
wi = &uwsgi_apps[wsgi_req->app_id];
wsgi_req->async_force_again = 0;
UWSGI_GET_GIL
// get rid of timeout
if (wsgi_req->async_timed_out) {
@@ -317,6 +316,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
int ret = manage_python_response(wsgi_req);
if (ret == UWSGI_OK) goto end;
UWSGI_RELEASE_GIL
if (ret == UWSGI_AGAIN) {
wsgi_req->async_force_again = 1;
}
return ret;
}
@@ -330,34 +332,15 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
return -1;
}
if (wsgi_req->appid_len == 0) {
if (!uwsgi.ignore_script_name) {
wsgi_req->appid = wsgi_req->script_name;
wsgi_req->appid_len = wsgi_req->script_name_len;
}
if (uwsgi.vhost) {
wsgi_req->appid = uwsgi_concat3n(wsgi_req->host, wsgi_req->host_len, "|",1, wsgi_req->script_name, wsgi_req->script_name_len);
wsgi_req->appid_len = wsgi_req->host_len + 1 + wsgi_req->script_name_len;
#ifdef UWSGI_DEBUG
uwsgi_debug("VirtualHost KEY=%.*s\n", wsgi_req->appid_len, wsgi_req->appid);
#endif
free_appid = 1;
}
if (wsgi_req->dynamic) {
// this part must be heavy locked in threaded modes
if (uwsgi.threads > 1) {
pthread_mutex_lock(&up.lock_pyloaders);
}
}
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
wsgi_req->app_id = uwsgi.default_app;
if (uwsgi.no_default_app) {
wsgi_req->app_id = -1;
}
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
if (wsgi_req->dynamic) {
// this part must be heavy locked in threaded modes
if (uwsgi.threads > 1) {
pthread_mutex_lock(&up.lock_pyloaders);
}
UWSGI_GET_GIL
if (uwsgi.single_interpreter) {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
@@ -366,14 +349,13 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL, PYTHON_APP_TYPE_WSGI);
}
UWSGI_RELEASE_GIL
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
}
}
if (free_appid) {
free(wsgi_req->appid);
if (wsgi_req->dynamic) {
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
}
if (wsgi_req->app_id == -1) {
@@ -415,6 +397,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
while (wi->response_subhandler(wsgi_req) != UWSGI_OK) {
if (uwsgi.async > 1) {
UWSGI_RELEASE_GIL
wsgi_req->async_force_again = 1;
return UWSGI_AGAIN;
}
else {
+9
View File
@@ -62,6 +62,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
PyObject *zero2 = NULL;
if (self != Py_None) {
zero = PyUnicode_AsASCIIString(head);
if (!zero) {
return PyErr_Format(PyExc_TypeError, "http status string must be encodable in latin1");
}
status_line = PyBytes_AsString(zero);
status_line_len = PyBytes_Size(zero);
}
@@ -133,6 +136,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
zero = PyUnicode_AsASCIIString(h_key);
if (!zero) {
return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1");
}
k = PyBytes_AsString(zero);
kl = PyBytes_Size(zero);
}
@@ -148,6 +154,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
zero2 = PyUnicode_AsASCIIString(h_value);
if (!zero2) {
return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1");
}
v = PyBytes_AsString(zero2);
vl = PyBytes_Size(zero2);
}
+2 -2
View File
@@ -463,7 +463,7 @@ VALUE rack_uwsgi_cache_get(int argc, VALUE *argv, VALUE *class) {
}
uint64_t vallen = 0;;
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, cache);
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache);
if (value) {
VALUE res = rb_str_new(value, vallen);
free(value);
@@ -774,7 +774,7 @@ VALUE uwsgi_ruby_register_rpc(int argc, VALUE *argv, VALUE *class) {
void *func = (void *) argv[1];
if (uwsgi_register_rpc(name, rack_plugin.modifier1, rb_argc, func)) {
if (uwsgi_register_rpc(name, &rack_plugin, rb_argc, func)) {
clear:
rb_raise(rb_eRuntimeError, "unable to register rpc function");
return Qnil;
+2 -5
View File
@@ -957,18 +957,15 @@ clear:
}
void uwsgi_rack_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
void uwsgi_rack_suspend(struct wsgi_request *wsgi_req) {
uwsgi_log("SUSPENDING RUBY\n");
//uwsgi_log("SUSPENDING RUBY\n");
}
void uwsgi_rack_resume(struct wsgi_request *wsgi_req) {
uwsgi_log("RESUMING RUBY\n");
//uwsgi_log("RESUMING RUBY\n");
}
VALUE init_rack_app( VALUE script ) {
+31 -24
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
@@ -60,7 +60,13 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
return 0;
}
int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
static int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
// skip if already authenticated
if (wsgi_req->remote_user_len > 0) {
return UWSGI_ROUTE_NEXT;
}
if (wsgi_req->authorization_len > 7 && ur->data2_len > 0) {
if (strncmp(wsgi_req->authorization, "Basic ", 6))
@@ -74,28 +80,32 @@ int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_rou
uint16_t ulen = htpasswd_check(ur->data2, auth);
if (ulen > 0) {
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen);
if (wsgi_req->remote_user)
wsgi_req->remote_user_len = ulen;
if (!wsgi_req->remote_user) {
free(auth);
goto forbidden;
}
wsgi_req->remote_user_len = ulen;
}
else if (ur->data3_len == 0) {
free(auth);
if (ur->data3_len > 0)
return UWSGI_ROUTE_CONTINUE;
return UWSGI_ROUTE_GOON;
goto forbidden;
}
}
else {
if (!uwsgi_strncmp(auth, auth_len, ur->data2, ur->data2_len)) {
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ur->custom);
if (wsgi_req->remote_user)
wsgi_req->remote_user_len = ur->custom;
if (!wsgi_req->remote_user) {
free(auth);
goto forbidden;
}
wsgi_req->remote_user_len = ur->custom;
}
else if (ur->data3_len == 0) {
free(auth);
if (ur->data3_len > 0)
return UWSGI_ROUTE_CONTINUE;
return UWSGI_ROUTE_GOON;
goto forbidden;
}
}
free(auth);
if (ur->is_last)
goto forbidden;
return UWSGI_ROUTE_NEXT;
}
}
@@ -103,16 +113,16 @@ int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_rou
forbidden:
if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1);
int ret = uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
// no need to check for errors
uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
free(realm);
if (ret) goto end;
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
end:
return UWSGI_ROUTE_BREAK;
}
#ifndef __linux__
void router_basicauth_init_lock() {
static void router_basicauth_init_lock() {
pthread_mutex_init(&ur_basicauth_crypt_mutex, NULL);
}
#endif
@@ -147,17 +157,14 @@ static int uwsgi_router_basicauth(struct uwsgi_route *ur, char *args) {
return 0;
}
static int uwsgi_router_basicauth_last(struct uwsgi_route *ur, char *args) {
uwsgi_router_basicauth(ur, args);
static int uwsgi_router_basicauth_next(struct uwsgi_route *ur, char *args) {
ur->data3_len = 1;
return 0;
return uwsgi_router_basicauth(ur, args);
}
void router_basicauth_register(void) {
static void router_basicauth_register(void) {
uwsgi_register_router("basicauth", uwsgi_router_basicauth);
uwsgi_register_router("basicauth-last", uwsgi_router_basicauth_last);
uwsgi_register_router("basicauth-next", uwsgi_router_basicauth_next);
}
struct uwsgi_plugin router_basicauth_plugin = {
+445 -23
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
@@ -23,54 +23,143 @@ struct uwsgi_router_cache_conf {
char *key;
size_t key_len;
char *var;
size_t var_len;
char *value;
size_t value_len;
// use mime types ?
char *mime;
char *as_num;
#ifdef UWSGI_ZLIB
char *gzip;
size_t gzip_len;
#endif
char *content_type;
size_t content_type_len;
char *content_encoding;
size_t content_encoding_len;
struct uwsgi_cache *cache;
char *expires_str;
uint64_t expires;
int64_t default_num;
uint64_t flags;
char *status_str;
int status;
};
// this is allocated for each transformation
struct uwsgi_transformation_cache_conf {
struct uwsgi_buffer *cache_it;
#ifdef UWSGI_ZLIB
struct uwsgi_buffer *cache_it_gzip;
#endif
int status;
struct uwsgi_buffer *value;
struct uwsgi_buffer *cache_it_to;
uint64_t cache_it_expires;
};
static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_cache_conf *utcc = (struct uwsgi_transformation_cache_conf *) ut->data;
struct uwsgi_buffer *ub = ut->chunk;
// force value
if (utcc->value) {
ub = utcc->value;
}
// store only successfull response
if (wsgi_req->write_errors == 0 && (wsgi_req->status == 200 || (utcc->status && wsgi_req->status == utcc->status)) && ub->pos > 0) {
if (utcc->cache_it) {
uwsgi_cache_magic_set(utcc->cache_it->buf, utcc->cache_it->pos, ub->buf, ub->pos, utcc->cache_it_expires,
UWSGI_CACHE_FLAG_UPDATE, utcc->cache_it_to ? utcc->cache_it_to->buf : NULL);
#ifdef UWSGI_ZLIB
if (utcc->cache_it_gzip) {
struct uwsgi_buffer *gzipped = uwsgi_gzip(ub->buf, ub->pos);
if (gzipped) {
uwsgi_cache_magic_set(utcc->cache_it_gzip->buf, utcc->cache_it_gzip->pos, gzipped->buf, gzipped->pos, utcc->cache_it_expires,
UWSGI_CACHE_FLAG_UPDATE, utcc->cache_it_to ? utcc->cache_it_to->buf : NULL);
uwsgi_buffer_destroy(gzipped);
}
}
#endif
}
}
// free resources
if (utcc->cache_it) uwsgi_buffer_destroy(utcc->cache_it);
#ifdef UWSGI_ZLIB
if (utcc->cache_it_gzip) uwsgi_buffer_destroy(utcc->cache_it_gzip);
#endif
if (utcc->cache_it_to) uwsgi_buffer_destroy(utcc->cache_it_to);
if (utcc->value) uwsgi_buffer_destroy(utcc->value);
free(utcc);
return 0;
}
// be tolerant on errors
static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
// overwrite previous run
if (wsgi_req->cache_it) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
if (wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it_to);
wsgi_req->cache_it_to = NULL;
}
struct uwsgi_transformation_cache_conf *utcc = uwsgi_calloc(sizeof(struct uwsgi_transformation_cache_conf));
// build key and name
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
wsgi_req->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!wsgi_req->cache_it) return UWSGI_ROUTE_NEXT;
utcc->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!utcc->cache_it) goto error;
if (urcc->name) {
wsgi_req->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len);
if (!wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
utcc->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len);
if (!utcc->cache_it_to) goto error;
}
wsgi_req->cache_it_expires = urcc->expires;
if (urcc->value) {
utcc->value = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
if (!utcc->value) goto error;
}
utcc->status = urcc->status;
#ifdef UWSGI_ZLIB
if (urcc->gzip) {
utcc->cache_it_gzip = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->gzip, urcc->gzip_len);
if (!utcc->cache_it_gzip) goto error;
}
#endif
utcc->cache_it_expires = urcc->expires;
uwsgi_add_transformation(wsgi_req, transform_cache, utcc);
return UWSGI_ROUTE_NEXT;
error:
if (utcc->cache_it) uwsgi_buffer_destroy(utcc->cache_it);
#ifdef UWSGI_ZLIB
if (utcc->cache_it_gzip) uwsgi_buffer_destroy(utcc->cache_it_gzip);
#endif
if (utcc->cache_it_to) uwsgi_buffer_destroy(utcc->cache_it_to);
free(utcc);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
char *mime_type = NULL;
size_t mime_type_len = 0;
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -79,11 +168,26 @@ static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_
if (!ub) return UWSGI_ROUTE_BREAK;
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, urcc->name);
uint64_t expires = 0;
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, &expires, urcc->name);
if (urcc->mime && value) {
mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
}
uwsgi_buffer_destroy(ub);
if (value) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
if (mime_type) {
uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len);
}
else {
if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
}
if (urcc->content_encoding_len) {
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, urcc->content_encoding, urcc->content_encoding_len)) goto error;
}
if (expires) {
if (uwsgi_response_add_expires(wsgi_req, expires)) goto error;
}
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
uwsgi_response_write_body_do(wsgi_req, value, valsize);
free(value);
@@ -98,6 +202,102 @@ error:
return UWSGI_ROUTE_BREAK;
}
// place a cache value in a request var
static int uwsgi_routing_func_cachevar(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, NULL, urcc->name);
uwsgi_buffer_destroy(ub);
if (value) {
if (urcc->as_num) {
char *tmp = value;
if (valsize == 8) {
int64_t *num = (int64_t *) value;
value = uwsgi_64bit2str(*num);
}
else {
value = uwsgi_64bit2str(0);
}
free(tmp);
}
if (!uwsgi_req_append(wsgi_req, urcc->var, urcc->var_len, value, valsize)) {
free(value);
return UWSGI_ROUTE_BREAK;
}
free(value);
}
return UWSGI_ROUTE_NEXT;
}
// set a cache item
static int uwsgi_routing_func_cacheset(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
if (!ub_val) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
if (uwsgi_cache_magic_set(ub->buf, ub->pos, ub_val->buf, ub_val->pos, urcc->expires, 0, urcc->name)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_val);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_val);
return UWSGI_ROUTE_NEXT;
}
// cacheinc/cachedec/cachemul/cachediv
static int uwsgi_routing_func_cachemath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
int64_t num = urcc->default_num;
if (urcc->value) {
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
if (!ub_val) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
num = strtol(ub_val->buf, NULL, 10);
uwsgi_buffer_destroy(ub_val);
}
if (uwsgi_cache_magic_set(ub->buf, ub->pos, (char *) &num, 8, urcc->expires, urcc->flags, urcc->name)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cache_store;
ur->data = args;
@@ -105,7 +305,13 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
#ifdef UWSGI_ZLIB
"gzip", &urcc->gzip,
#endif
"name", &urcc->name,
"value", &urcc->value,
"status", &urcc->status_str,
"code", &urcc->status_str,
"expires", &urcc->expires_str, NULL)) {
uwsgi_log("invalid cachestore route syntax: %s\n", args);
goto error;
@@ -115,6 +321,12 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
urcc->key_len = strlen(urcc->key);
}
#ifdef UWSGI_ZLIB
if (urcc->gzip) {
urcc->gzip_len = strlen(urcc->gzip);
}
#endif
if (urcc->name) {
urcc->name_len = strlen(urcc->name);
}
@@ -128,6 +340,14 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
}
if (urcc->value) {
urcc->value_len = strlen(urcc->value);
}
if (urcc->status_str) {
urcc->status = atoi(urcc->status_str);
}
ur->data2 = urcc;
return 0;
error:
@@ -146,6 +366,8 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"content_type", &urcc->content_type,
"content_encoding", &urcc->content_encoding,
"mime", &urcc->mime,
"name", &urcc->name,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
@@ -165,6 +387,10 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
urcc->content_type_len = strlen(urcc->content_type);
if (urcc->content_encoding) {
urcc->content_encoding_len = strlen(urcc->content_encoding);
}
ur->data2 = urcc;
return 0;
}
@@ -175,11 +401,207 @@ static int uwsgi_router_cache_continue(struct uwsgi_route *ur, char *args) {
return 0;
}
static struct uwsgi_router_cache_conf *uwsgi_router_cachemath(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cachemath;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"value", &urcc->value,
"name", &urcc->name,
"expires", &urcc->expires_str, NULL)) {
uwsgi_log("invalid cachemath route syntax: %s\n", args);
goto error;
}
if (urcc->key) {
urcc->key_len = strlen(urcc->key);
}
if (urcc->value) {
urcc->value_len = strlen(urcc->value);
}
if (urcc->name) {
urcc->name_len = strlen(urcc->name);
}
if (!urcc->key) {
uwsgi_log("invalid cachemath route syntax: you need to specify a cache key\n");
goto error;
}
if (urcc->expires_str) {
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
}
urcc->flags = UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE;
ur->data2 = urcc;
return urcc;
error:
if (urcc->key) free(urcc->key);
if (urcc->name) free(urcc->name);
if (urcc->value) free(urcc->value);
if (urcc->expires_str) free(urcc->expires_str);
free(urcc);
return NULL;
}
static int uwsgi_router_cacheinc(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
if (!urcc) return -1;
urcc->default_num = 1;
urcc->flags |= UWSGI_CACHE_FLAG_INC;
return 0;
}
static int uwsgi_router_cachedec(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
if (!urcc) return -1;
urcc->default_num = 1;
urcc->flags |= UWSGI_CACHE_FLAG_DEC;
return 0;
}
static int uwsgi_router_cachemul(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
if (!urcc) return -1;
urcc->default_num = 2;
urcc->flags |= UWSGI_CACHE_FLAG_MUL;
return 0;
}
static int uwsgi_router_cachediv(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args);
if (!urcc) return -1;
urcc->default_num = 2;
urcc->flags |= UWSGI_CACHE_FLAG_DIV;
return 0;
}
static int uwsgi_router_cacheset(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cacheset;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"value", &urcc->value,
"name", &urcc->name,
"expires", &urcc->expires_str, NULL)) {
uwsgi_log("invalid cacheset route syntax: %s\n", args);
goto error;
}
if (urcc->key) {
urcc->key_len = strlen(urcc->key);
}
if (urcc->value) {
urcc->value_len = strlen(urcc->value);
}
if (urcc->name) {
urcc->name_len = strlen(urcc->name);
}
if (!urcc->key || !urcc->value) {
uwsgi_log("invalid cacheset route syntax: you need to specify a cache key and a value\n");
goto error;
}
if (urcc->expires_str) {
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
}
ur->data2 = urcc;
return 0;
error:
if (urcc->key) free(urcc->key);
if (urcc->name) free(urcc->name);
if (urcc->value) free(urcc->value);
if (urcc->expires_str) free(urcc->expires_str);
free(urcc);
return -1;
}
static int uwsgi_router_cachevar(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cachevar;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"var", &urcc->var,
"name", &urcc->name,
"num", &urcc->as_num,
"as_num", &urcc->as_num,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (urcc->key) {
urcc->key_len = strlen(urcc->key);
}
if (urcc->var) {
urcc->var_len = strlen(urcc->var);
}
if (!urcc->key || !urcc->var) {
uwsgi_log("invalid route syntax: you need to specify a cache key and a request var\n");
exit(1);
}
ur->data2 = urcc;
return 0;
}
static int uwsgi_route_condition_incache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = 0;
char *key = NULL;
size_t key_len = 0;
char *name = NULL;
if (uwsgi_kvlist_parse(ur->subject_str, ur->subject_str_len, ',', '=',
"key", &key,
"name", &name,
NULL)) {
return 0;
}
if (!key) goto end;
key_len = strlen(key);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, key, key_len);
if (!ub) goto end;
ret = uwsgi_cache_magic_exists(ub->buf, ub->pos, name);
uwsgi_buffer_destroy(ub);
end:
if (key) free(key);
if (name) free(name);
return ret;
}
static void router_cache_register() {
uwsgi_register_router("cache", uwsgi_router_cache);
uwsgi_register_router("cache-continue", uwsgi_router_cache_continue);
uwsgi_register_router("cachevar", uwsgi_router_cachevar);
uwsgi_register_router("cacheset", uwsgi_router_cacheset);
uwsgi_register_router("cachestore", uwsgi_router_cache_store);
uwsgi_register_router("cache-store", uwsgi_router_cache_store);
uwsgi_register_route_condition("incache", uwsgi_route_condition_incache);
uwsgi_register_router("cacheinc", uwsgi_router_cacheinc);
uwsgi_register_router("cachedec", uwsgi_router_cachedec);
uwsgi_register_router("cachemul", uwsgi_router_cachemul);
uwsgi_register_router("cachediv", uwsgi_router_cachediv);
}
struct uwsgi_plugin router_cache_plugin = {
+17 -1
View File
@@ -36,6 +36,7 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
// append remaining body...
if (wsgi_req->proto_parser_remains > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
uwsgi_buffer_destroy(ub);
uwsgi_log("unable to generate http request for %s\n", addr);
return UWSGI_ROUTE_NEXT;
}
@@ -43,9 +44,18 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
}
// ok now if have offload threads, directly use them
if (wsgi_req->socket->can_offload) {
if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
// append buffered body
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
uwsgi_buffer_destroy(ub);
uwsgi_log("unable to generate http request for %s\n", addr);
return UWSGI_ROUTE_NEXT;
}
}
if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
return UWSGI_ROUTE_BREAK;
}
}
@@ -82,10 +92,16 @@ static int uwsgi_router_http(struct uwsgi_route *ur, char *args) {
return 0;
}
static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
return uwsgi_router_http(ur, args);
}
static void router_http_register(void) {
uwsgi_register_router("http", uwsgi_router_http);
uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp);
}
struct uwsgi_plugin router_http_plugin = {
+235
View File
@@ -0,0 +1,235 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_radius_conf {
char *realm;
uint16_t realm_len;
char *server;
char *secret;
uint16_t secret_len;
char *nas_port_str;
uint32_t nas_port;
char *nas_address_str;
uint32_t nas_address;
};
static uint16_t uwsgi_radius_auth(struct uwsgi_radius_conf *urc, char *auth, size_t auth_len) {
static uint8_t packet_identifier = 0;
char access_request[4096];
char hash[4096];
// md5 result
char md5_hash[16];
size_t i;
char *password = memchr(auth, ':', auth_len);
if (!password) return 0;
char *username = auth;
uint16_t username_len = password - auth;
password++;
uint16_t password_len = auth_len - (username_len+1);
int fd = uwsgi_connect_udp(urc->server);
if (fd < 0) return 0;
uwsgi_socket_nb(fd);
// start generating authenticator
char authenticator[16];
for(i=0;i<16;i++) authenticator[i] = rand();
// generate the User-Password attribute
char *md5 = authenticator;
// step 1 pad to 16 bytes boundary
size_t pwd16_len = password_len + (16 - (password_len % 16));
if (pwd16_len > 128) return 0;
// compute the whole packet size
uint16_t access_request_len = 4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 6;
memset(access_request, 0, access_request_len);
if (access_request_len > 4096) return 0;
char *pwd16_buf = access_request + (access_request_len - (pwd16_len + 6 + 6));
memcpy(pwd16_buf, password, password_len);
// allocate a buffer for the hash
if (urc->secret_len + 16 > 4096) return 0;
memcpy(hash, urc->secret, urc->secret_len);
for(i=0;i<pwd16_len;i+=16) {
// append the last md5 to the hash (after the secret)
memcpy(hash + urc->secret_len, md5, 16);
// calculate its md5
if (!uwsgi_md5(hash, urc->secret_len + 16, md5_hash)) {
goto end;
}
size_t j;
// set md5 to the new result
md5 = &pwd16_buf[i];
// xor the result (we use the authenticator as destination buffer)
for(j=0;j<16;j++) {
md5[j] = md5_hash[j] ^ md5[j];
}
}
// complete the packet
packet_identifier++;
access_request[0] = 1;
access_request[1] = packet_identifier;
access_request[2] = (uint8_t) ((access_request_len >> 8) & 0xff);
access_request[3] = (uint8_t) (access_request_len & 0xff);
memcpy(access_request + 4, authenticator, 16);
access_request[4 + 16] = 1;
access_request[4 + 16 + 1] = username_len + 2;
memcpy(access_request + (4 + 16 + 2), username, username_len);
access_request[4 + 16 + 2 + username_len] = 2;
access_request[4 + 16 + 2 + username_len + 1] = pwd16_len + 2;
// add nas port
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len] = 5;
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 1] = 6;
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 2] = (uint8_t) ((urc->nas_port >> 24) & 0xff);
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 3] = (uint8_t) ((urc->nas_port >> 16) & 0xff);
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 4] = (uint8_t) ((urc->nas_port >> 8) & 0xff);
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 5] = (uint8_t) (urc->nas_port & 0xff);
// add nas address
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6] = 4;
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 1] = 6;
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 2] = (uint8_t) ((urc->nas_address >> 24) & 0xff);
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 3] = (uint8_t) ((urc->nas_address >> 16) & 0xff);
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 4] = (uint8_t) ((urc->nas_address >> 8) & 0xff);
access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 5] = (uint8_t) (urc->nas_address & 0xff);
if (write(fd, access_request, access_request_len) != access_request_len) {
goto end;
}
// now wait for the response
int ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) goto end;
ssize_t rlen = read(fd, access_request, access_request_len);
// we need at least 4 + 16
if (rlen >= 20) {
char response_authenticator[16];
if (access_request[1] != packet_identifier) goto end;
if (rlen + urc->secret_len > 4096) goto end;
// get the authenticator
memcpy(response_authenticator, access_request+4, 16);
// append the secret
memcpy(access_request+rlen, urc->secret, urc->secret_len);
// change the authenticator
memcpy(access_request+4, authenticator, 16);
// compute the md5
if (!uwsgi_md5(access_request, rlen + urc->secret_len, md5_hash)) {
goto end;
}
if (memcmp(md5_hash, response_authenticator, 16)) goto end;
// Access-Accept
if (access_request[0] == 2) {
close(fd);
return username_len;
}
}
end:
close(fd);
return 0;
}
static int uwsgi_routing_func_radius(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_radius_conf *urc = (struct uwsgi_radius_conf *) ur->data2;
// skip if already authenticated
if (wsgi_req->remote_user_len > 0) {
return UWSGI_ROUTE_NEXT;
}
if (wsgi_req->authorization_len > 7) {
if (strncmp(wsgi_req->authorization, "Basic ", 6))
goto forbidden;
size_t auth_len = 0;
char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len);
if (auth) {
uint16_t rlen = uwsgi_radius_auth(urc, auth, auth_len);
if (rlen > 0) {
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, rlen);
free(auth);
if (!wsgi_req->remote_user) goto forbidden;
wsgi_req->remote_user_len = rlen;
return UWSGI_ROUTE_NEXT;
}
free(auth);
if (ur->custom) return UWSGI_ROUTE_NEXT;
}
}
forbidden:
if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
char *realm = uwsgi_concat3n("Basic realm=\"", 13, urc->realm, urc->realm_len, "\"", 1);
// no need to check for errors
uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + urc->realm_len + 1);
free(realm);
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
end:
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_radius(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_radius;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_radius_conf *urc = uwsgi_calloc(sizeof(struct uwsgi_radius_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"realm", &urc->realm,
"server", &urc->server,
"secret", &urc->secret,
"nas_port", &urc->nas_port_str,
"nas_address", &urc->nas_address_str,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urc->realm || !urc->server || !urc->secret) {
uwsgi_log("invalid radius route syntax: you need to specify a realm a server and a secret\n");
exit(1);
}
urc->realm_len = strlen(urc->realm);
urc->secret_len = strlen(urc->secret);
if (urc->nas_port_str) {
urc->nas_port = strtoul(urc->nas_port_str, NULL, 10);
}
if (!urc->nas_address_str) {
urc->nas_address_str = uwsgi.hostname;
}
struct hostent *he = gethostbyname(urc->nas_address_str);
if (he) {
if (he->h_addr_list[0]) {
memcpy(&urc->nas_address, he->h_addr_list[0], 4);
urc->nas_address = htonl(urc->nas_address);
}
}
ur->data2 = urc;
return 0;
}
static int uwsgi_router_radius_next(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
return uwsgi_router_radius(ur, args);
}
static void router_radius_register(void) {
uwsgi_register_router("radius", uwsgi_router_radius);
uwsgi_register_router("radius-next", uwsgi_router_radius_next);
}
struct uwsgi_plugin router_radius_plugin = {
.name = "router_radius",
.on_load = router_radius_register,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='router_radius'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['radius']
+107 -74
View File
@@ -1,13 +1,19 @@
#include "../../uwsgi.h"
#ifdef UWSGI_ROUTING
#include <uwsgi.h>
#include <gssapi/gssapi.h>
extern struct uwsgi_server uwsgi;
/*
At the first request (without authentication) uWSGI sends back a token
The client resend-the request with its token
Following requests could need a new token or are simply accepted
*/
// log errors...
static void uwsgi_spnego_err(OM_uint32 err_maj, OM_uint32 err_min) {
static void uwsgi_spnego_err(const char *func, OM_uint32 err_maj, OM_uint32 err_min) {
OM_uint32 ret;
OM_uint32 min_stat;
@@ -21,11 +27,9 @@ static void uwsgi_spnego_err(OM_uint32 err_maj, OM_uint32 err_min) {
&msg_ctx,
&status_string);
if (GSS_ERROR(ret)) {
return;
}
if (GSS_ERROR(ret)) return;
uwsgi_log("[uwsgi-spnego] error: %.*s\n", status_string.length, status_string.value);
uwsgi_log("[uwsgi-spnego] %s() error (major): %.*s\n", func, status_string.length, status_string.value);
gss_release_buffer(&min_stat, &status_string);
@@ -36,73 +40,138 @@ static void uwsgi_spnego_err(OM_uint32 err_maj, OM_uint32 err_min) {
&msg_ctx,
&status_string);
if (GSS_ERROR(ret)) {
return;
if (GSS_ERROR(ret)) return;
if (status_string.length > 0) {
uwsgi_log("[uwsgi-spnego] %s() error (minor): %.*s\n",func, status_string.length, status_string.value);
}
if (status_string.value) {
gss_release_buffer(&min_stat, &status_string);
}
uwsgi_log("[uwsgi-spnego] error: %.*s\n", status_string.length, status_string.value);
gss_release_buffer(&min_stat, &status_string);
}
static char *uwsgi_spnego_new_token(struct wsgi_request *wsgi_req, gss_cred_id_t cred, char *token_buf, size_t token_buf_len, size_t *b64_len) {
static char *uwsgi_spnego_new_token(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *token_buf, size_t token_buf_len, size_t *b64_len) {
char *b64 = NULL;
OM_uint32 ret;
OM_uint32 min_ret;
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
gss_name_t client_name = GSS_C_NO_NAME;
gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
struct uwsgi_buffer *ub = NULL;
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
if (ur->data_len) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) goto end;
service.value = ub->buf;
service.length = ub->pos;
}
gss_name_t server_name = GSS_C_NO_NAME;
gss_name_t client_name = GSS_C_NO_NAME;
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
token.value = token_buf;
token.length = token_buf_len;
if (service.length == 0) {
service.value = "HTTP";
service.length = 4;
}
ret = gss_import_name(&min_ret, &service, GSS_C_NT_HOSTBASED_SERVICE, &server_name);
if (GSS_ERROR(ret)) {
uwsgi_spnego_err("gss_import_name", ret, min_ret);
goto end;
}
ret = gss_acquire_cred(&min_ret, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL, NULL);
if (GSS_ERROR(ret)) {
uwsgi_spnego_err("gss_acquire_cred", ret, min_ret);
goto end;
}
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
ret = gss_accept_sec_context(&min_ret, &context, cred, &token, GSS_C_NO_CHANNEL_BINDINGS, &client_name, NULL, &output, NULL, NULL, NULL);
if (GSS_ERROR(ret)) {
uwsgi_spnego_err(ret, min_ret);
uwsgi_spnego_err("gss_accept_sec_context", ret, min_ret);
if (output.value) {
gss_release_buffer(&min_ret, &output);
}
goto end;
}
if (output.length) {
b64 = uwsgi_base64_encode(output.value, output.length, b64_len);
gss_release_buffer(&min_ret, &output);
if (output.value) {
gss_release_buffer(&min_ret, &output);
}
if (!b64) {
goto end;
}
ret = gss_display_name(&min_ret, client_name, &output, NULL);
if (GSS_ERROR(ret)) {
uwsgi_spnego_err(ret, min_ret);
uwsgi_spnego_err("gss_display_name", ret, min_ret);
if (output.value) {
gss_release_buffer(&min_ret, &output);
}
free(b64);
b64 = NULL;
goto end;
}
wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, output.value, output.length);
if (!wsgi_req->remote_user) {
if (output.value) {
gss_release_buffer(&min_ret, &output);
}
free(b64);
b64 = NULL;
goto end;
}
wsgi_req->remote_user_len = output.length;
gss_release_buffer(&min_ret, &output);
if (output.value) {
gss_release_buffer(&min_ret, &output);
}
if (!wsgi_req->remote_user) {
wsgi_req->remote_user_len = 0;
uwsgi_spnego_err(ret, min_ret);
free(b64);
b64 = NULL;
goto end;
}
}
end:
if (context != GSS_C_NO_CONTEXT) {
gss_delete_sec_context(&min_ret, &context, GSS_C_NO_BUFFER);
if (server_name != GSS_C_NO_NAME) {
gss_release_name(&min_ret, &server_name);
}
if (client_name != GSS_C_NO_NAME) {
gss_release_name(&min_ret, &client_name);
}
if (cred != GSS_C_NO_CREDENTIAL) {
gss_release_cred(&min_ret, &cred);
}
if (context != GSS_C_NO_CONTEXT) {
gss_delete_sec_context(&min_ret, &context, GSS_C_NO_BUFFER);
}
if (ub) {
uwsgi_buffer_destroy(ub);
}
return b64;
}
@@ -111,7 +180,6 @@ static int uwsgi_routing_func_spnego(struct wsgi_request *wsgi_req, struct uwsgi
char *negotiate = NULL;
size_t negotiate_len = 0;
struct uwsgi_buffer *ub = NULL;
size_t b64_len = 0;
// check for "Negotiate " string at least
@@ -120,19 +188,18 @@ static int uwsgi_routing_func_spnego(struct wsgi_request *wsgi_req, struct uwsgi
goto forbidden;
char *token = uwsgi_base64_decode(wsgi_req->authorization+10, wsgi_req->authorization_len-10, &b64_len);
if (token && b64_len) {
negotiate = uwsgi_spnego_new_token(wsgi_req, ur->data2, token, b64_len, &negotiate_len);
if (token) {
negotiate = uwsgi_spnego_new_token(wsgi_req, ur, token, b64_len, &negotiate_len);
free(token);
if (negotiate) {
char *auth_header = uwsgi_concat2n("WWW-Authenticate: Negotiate ", 28, negotiate, negotiate_len);
free(negotiate);
uwsgi_additional_header_add(wsgi_req, auth_header, negotiate_len + 28);
free(auth_header);
if (ur->custom)
return UWSGI_ROUTE_CONTINUE;
return UWSGI_ROUTE_GOON;
return UWSGI_ROUTE_NEXT;
}
if (ur->custom) return UWSGI_ROUTE_NEXT;
}
}
@@ -151,8 +218,9 @@ forbidden:
if (uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, "Negotiate", 9)) goto end;
}
uwsgi_response_write_body(wsgi_req, "Unauthorized", 12);
uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
end:
if (ur->custom) return UWSGI_ROUTE_NEXT;
return UWSGI_ROUTE_BREAK;
}
@@ -161,60 +229,25 @@ end:
static int uwsgi_router_spnego(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_spnego;
OM_uint32 ret;
OM_uint32 min_ret;
gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
service.value = args;
service.length = strlen(args);
if (service.length == 0) {
service.value = "HTTP";
service.length = 4;
ur->data = args ;
if (args) {
ur->data_len = strlen(args);
}
gss_name_t server_name = GSS_C_NO_NAME;
ret = gss_import_name(&min_ret, &service, GSS_C_NT_HOSTBASED_SERVICE, &server_name);
if (GSS_ERROR(ret)) {
uwsgi_spnego_err(ret, min_ret);
exit(1);
}
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
ret = gss_acquire_cred(&min_ret, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL, NULL);
if (GSS_ERROR(ret)) {
uwsgi_spnego_err(ret, min_ret);
exit(1);
}
ur->data2 = cred;
return 0;
}
static int uwsgi_router_spnego_last(struct uwsgi_route *ur, char *args) {
uwsgi_router_spnego(ur, args);
static int uwsgi_router_spnego_next(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
return 0;
return uwsgi_router_spnego(ur, args);
}
static void router_spnego_register(void) {
uwsgi_register_router("spnego", uwsgi_router_spnego);
uwsgi_register_router("spnego-last", uwsgi_router_spnego_last);
uwsgi_register_router("spnego-next", uwsgi_router_spnego_next);
}
struct uwsgi_plugin router_spnego_plugin = {
.name = "router_spnego",
.on_load = router_spnego_register,
};
#else
struct uwsgi_plugin router_spnego_plugin = {
.name = "router_spnego",
};
#endif
+2 -2
View File
@@ -1,8 +1,8 @@
import os
NAME='router_spnego'
CFLAGS = []
CFLAGS = os.popen('krb5-config --cflags gssapi').read().rstrip().split()
LDFLAGS = []
LIBS = ['-L' + os.popen('krb5-config --libs gssapi').read().rstrip()]
LIBS = os.popen('krb5-config --libs gssapi').read().rstrip().split()
GCC_LIST = ['router_spnego']
+13 -1
View File
@@ -58,9 +58,16 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
}
// ok now if have offload threads, directly use them
if (wsgi_req->socket->can_offload) {
if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
// append buffered body
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
goto end;
}
}
if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
return UWSGI_ROUTE_BREAK;
}
}
@@ -140,10 +147,15 @@ static int uwsgi_router_uwsgi(struct uwsgi_route *ur, char *args) {
return -1;
}
static int uwsgi_router_proxyuwsgi(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
return uwsgi_router_uwsgi(ur, args);
}
static void router_uwsgi_register(void) {
uwsgi_register_router("uwsgi", uwsgi_router_uwsgi);
uwsgi_register_router("proxyuwsgi", uwsgi_router_proxyuwsgi);
}
struct uwsgi_plugin router_uwsgi_plugin = {
-3
View File
@@ -247,9 +247,6 @@ static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsg
else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
ret = UWSGI_ROUTE_CONTINUE;
}
else if (!uwsgi_strncmp(response, size, "goon", 4 )) {
ret = UWSGI_ROUTE_GOON;
}
else if (!uwsgi_starts_with(response, size, "break", 5 )) {
ret = UWSGI_ROUTE_BREAK;
if (size > 6) {
+1 -1
View File
@@ -36,7 +36,7 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
uwsgi_log("disconnected client, remove spool file.\n");
/* client disconnect, remove spool file */
if (unlink(spool_filename)) {
uwsgi_error("unlink()");
uwsgi_error("uwsgi_request_spooler()/unlink()");
uwsgi_log("something horrible happened !!! check your spooler ASAP !!!\n");
exit(1);
}
+1 -1
View File
@@ -444,7 +444,7 @@ static struct uwsgi_buffer *ssi_cmd_cache(struct wsgi_request *wsgi_req, struct
}
uint64_t rlen = 0;
char *value = uwsgi_cache_magic_get(var, var_len, &rlen, cache_name);
char *value = uwsgi_cache_magic_get(var, var_len, &rlen, NULL, cache_name);
if (cache_name) free(cache_name);
struct uwsgi_buffer *ub = NULL;
if (value) {
+50 -20
View File
@@ -2,6 +2,7 @@
#include <stackless_api.h>
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
struct ustackless {
int enabled;
@@ -9,16 +10,22 @@ struct ustackless {
PyTaskletObject **sl;
} usl;
struct uwsgi_option stackless_options[] = {
static void gil_stackless_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
static void gil_stackless_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static struct uwsgi_option stackless_options[] = {
{"stackless", no_argument, 0, "use stackless as suspend engine", uwsgi_opt_true, &usl.enabled, 0},
{ 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0 }
};
PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
static PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
async_schedule_to_req_green();
Py_DECREF(usl.sl[uwsgi.wsgi_req->async_id]);
Py_INCREF(Py_None);
@@ -27,9 +34,13 @@ PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
PyMethodDef uwsgi_stackless_request_method[] = {{"uwsgi_stackless_request", py_uwsgi_stackless_request, METH_VARARGS, ""}};
static inline static void stackless_schedule_to_req() {
static void stackless_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// ensure gil
UWSGI_GET_GIL
if (!uwsgi.wsgi_req->suspended) {
usl.sl[id] = PyTasklet_New(NULL, usl.callable);
@@ -39,46 +50,65 @@ static inline static void stackless_schedule_to_req() {
uwsgi.wsgi_req->suspended = 1;
}
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
PyTasklet_Run(usl.sl[id]);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
// call it in the main core
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
}
static inline static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
// ensure gil
UWSGI_GET_GIL
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyStackless_Schedule(Py_None, 1);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
}
int stackless_init() {
return 0;
}
static void stackless_init_apps(void) {
void stackless_init_apps(void) {
if (!usl.enabled) return;
if (!usl.enabled) {
return;
if (uwsgi.async <= 1) {
uwsgi_log("the stackless suspend engine requires async mode\n");
exit(1);
}
if (uwsgi.has_threads) {
up.gil_get = gil_stackless_get;
up.gil_release = gil_stackless_release;
}
// blindy call it as the stackless gil engine is already set
UWSGI_GET_GIL
usl.sl = uwsgi_malloc( sizeof(PyTaskletObject *) * uwsgi.async );
usl.callable = PyCFunction_New(uwsgi_stackless_request_method, NULL);
Py_INCREF(usl.callable);
uwsgi_log("enabled stackless engine\n");
uwsgi.schedule_to_main = stackless_schedule_to_main;
uwsgi.schedule_to_req = stackless_schedule_to_req;
return;
}
struct uwsgi_plugin stackless_plugin = {
.name = "stackless",
.init = stackless_init,
.init_apps = stackless_init_apps,
.options = stackless_options,
};
+77 -13
View File
@@ -1,33 +1,97 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int (*symcall_function)(struct wsgi_request *);
int uwsgi_symcall_init(){
symcall_function = dlsym(RTLD_DEFAULT, "pypy_uwsgi_request");
uwsgi_log("symcall function ptr: %p\n", symcall_function);
return 0;
struct uwsgi_symcall {
char *symcall_function_name;
int (*symcall_function)(struct wsgi_request *);
struct uwsgi_string_list *rpc;
struct uwsgi_string_list *post_fork;
} usym;
struct uwsgi_plugin symcall_plugin;
static struct uwsgi_option uwsgi_symcall_options[] = {
{"symcall", required_argument, 0, "load the specified C symbol as the symcall request handler", uwsgi_opt_set_str, &usym.symcall_function_name, 0},
{"symcall-register-rpc", required_argument, 0, "load the specified C symbol as an RPC function (syntax: name function)", uwsgi_opt_add_string_list, &usym.rpc, 0},
{"symcall-post-fork", required_argument, 0, "call the specified C symbol after each fork()", uwsgi_opt_add_string_list, &usym.post_fork, 0},
{0, 0, 0, 0},
};
static void uwsgi_symcall_init(){
if (usym.symcall_function_name) {
usym.symcall_function = dlsym(RTLD_DEFAULT, usym.symcall_function_name);
if (!usym.symcall_function) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", usym.symcall_function_name);
exit(1);
}
uwsgi_log("symcall function ptr: %p\n", usym.symcall_function);
}
struct uwsgi_string_list *usl = usym.rpc;
while(usl) {
char *space = strchr(usl->value, ' ');
if (!space) {
uwsgi_log("invalid symcall RPC syntax, must be: rpcname symbol\n");
exit(1);
}
*space = 0;
void *func = dlsym(RTLD_DEFAULT, space+1);
if (!func) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", space+1);
exit(1);
}
if (uwsgi_register_rpc(usl->value, &symcall_plugin, 0, func)) {
uwsgi_log("unable to register rpc function");
exit(1);
}
*space = ' ';
usl = usl->next;
}
}
int uwsgi_symcall_request(struct wsgi_request *wsgi_req) {
return symcall_function(wsgi_req);
static int uwsgi_symcall_request(struct wsgi_request *wsgi_req) {
if (usym.symcall_function) {
return usym.symcall_function(wsgi_req);
}
return UWSGI_OK;
}
void uwsgi_symcall_after_request(struct wsgi_request *wsgi_req) {
// TODO
static void uwsgi_symcall_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static uint16_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
uint16_t (*casted_func)(uint8_t, char **, uint16_t *, char *) = (uint16_t (*)(uint8_t, char **, uint16_t *, char *)) func;
return casted_func(argc, argv, argvs, buffer);
}
static void uwsgi_symcall_post_fork() {
void (*func)(void);
struct uwsgi_string_list *usl = usym.post_fork;
while(usl) {
func = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", usl->value);
exit(1);
}
func();
usl = usl->next;
}
}
struct uwsgi_plugin symcall_plugin = {
.name = "symcall",
.modifier1 = 18,
.init = uwsgi_symcall_init,
.options = uwsgi_symcall_options,
.init_apps = uwsgi_symcall_init,
.request = uwsgi_symcall_request,
.after_request = uwsgi_symcall_after_request,
.rpc = uwsgi_symcall_rpc,
.post_fork = uwsgi_symcall_post_fork,
};
+58
View File
@@ -0,0 +1,58 @@
#include <uwsgi.h>
#if defined(UWSGI_ROUTING)
/*
transfer-encoding is added to the headers
*/
static int transform_chunked(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_buffer *ub = ut->chunk;
if (ut->is_final) {
if (uwsgi_buffer_append(ub, "0\r\n\r\n", 5)) return -1;
return 0;
}
if (ut->round == 1) {
// do not check for errors !!!
uwsgi_response_add_header(wsgi_req, "Transfer-Encoding", 17, "chunked", 7);
}
if (ub->pos > 0) {
if (uwsgi_buffer_insert_chunked(ub, 0, ub->pos)) return -1;
if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1;
}
return 0;
}
static int uwsgi_routing_func_chunked(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL);
ut->can_stream = 1;
// add a "final" transformation to add the trailing chunk
ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL);
ut->is_final = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_chunked(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_chunked;
return 0;
}
static void router_chunked_register(void) {
uwsgi_register_router("chunked", uwsgi_router_chunked);
}
struct uwsgi_plugin transformation_chunked_plugin = {
.name = "transformation_chunked",
.on_load = router_chunked_register,
};
#else
struct uwsgi_plugin transformation_chunked_plugin = {
.name = "transformation_chunked",
};
#endif
@@ -0,0 +1,6 @@
NAME='transformation_chunked'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['chunked']
+83
View File
@@ -0,0 +1,83 @@
#include <uwsgi.h>
#if defined(UWSGI_ROUTING) && defined(UWSGI_ZLIB)
/*
gzip transformations add content-encoding to your headers and changes the final size !!!
remember to fix the content_length (or use chunked encoding) !!!
*/
struct uwsgi_transformation_gzip {
z_stream z;
uint32_t crc32;
size_t len;
uint8_t header;
};
extern char gzheader[];
static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_gzip *utgz = (struct uwsgi_transformation_gzip *) ut->data;
struct uwsgi_buffer *ub = ut->chunk;
if (ut->is_final) {
if (uwsgi_gzip_fix(&utgz->z, utgz->crc32, ub, utgz->len)) {
free(utgz);
return -1;
}
free(utgz);
return 0;
}
size_t dlen = 0;
char *gzipped = uwsgi_gzip_chunk(&utgz->z, &utgz->crc32, ub->buf, ub->pos, &dlen);
if (!gzipped) return -1;
utgz->len += ub->pos;
uwsgi_buffer_map(ub, gzipped, dlen);
if (!utgz->header) {
// do not check for errors !!!
uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4);
utgz->header = 1;
if (uwsgi_buffer_insert(ub, 0, gzheader, 10)) {
return -1;
}
}
return 0;
}
static int uwsgi_routing_func_gzip(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_transformation_gzip *utgz = uwsgi_calloc(sizeof(struct uwsgi_transformation_gzip));
if (uwsgi_gzip_prepare(&utgz->z, NULL, 0, &utgz->crc32)) {
free(utgz);
return UWSGI_ROUTE_BREAK;
}
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
ut->can_stream = 1;
// this is the trasformation clearing the memory
ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
ut->is_final = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_gzip(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_gzip;
return 0;
}
static void router_gzip_register(void) {
uwsgi_register_router("gzip", uwsgi_router_gzip);
}
struct uwsgi_plugin transformation_gzip_plugin = {
.name = "transformation_gzip",
.on_load = router_gzip_register,
};
#else
struct uwsgi_plugin transformation_gzip_plugin = {
.name = "transformation_gzip",
};
#endif
@@ -0,0 +1,6 @@
NAME='transformation_gzip'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['gzip']
+128
View File
@@ -0,0 +1,128 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
extern struct uwsgi_server uwsgi;
struct uwsgi_router_tofile_conf {
// the name of the file
char *filename;
size_t filename_len;
// the mode of the file
char *mode;
size_t mode_len;
};
// this is allocated for each transformation
struct uwsgi_transformation_tofile_conf {
struct uwsgi_buffer *filename;
};
static int transform_tofile(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_tofile_conf *uttc = (struct uwsgi_transformation_tofile_conf *) ut->data;
struct uwsgi_buffer *ub = ut->chunk;
// store only successfull response
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
if (uttc->filename) {
int fd = open(uttc->filename->buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (fd < 0) {
uwsgi_error_open(uttc->filename->buf);
goto end;
}
// lock the file
if (uwsgi_fcntl_lock(fd)) {
close(fd);
goto end;
}
// write to it
size_t remains = ub->pos;
while(remains) {
ssize_t rlen = write(fd, ub->buf + (ub->pos - remains), remains);
if (rlen <= 0) {
uwsgi_error("transform_tofile()/write()");
unlink(uttc->filename->buf);
break;
}
remains -= rlen;
}
// unlock/close
close(fd);
}
}
end:
// free resources
if (uttc->filename) uwsgi_buffer_destroy(uttc->filename);
free(uttc);
// reset the buffer
return 0;
}
// be tolerant on errors
static int uwsgi_routing_func_tofile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_tofile_conf *urtc = (struct uwsgi_router_tofile_conf *) ur->data2;
struct uwsgi_transformation_tofile_conf *uttc = uwsgi_calloc(sizeof(struct uwsgi_transformation_tofile_conf));
// build key and name
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uttc->filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urtc->filename, urtc->filename_len);
if (!uttc->filename) goto error;
uwsgi_add_transformation(wsgi_req, transform_tofile, uttc);
return UWSGI_ROUTE_NEXT;
error:
if (uttc->filename) uwsgi_buffer_destroy(uttc->filename);
free(uttc);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_tofile(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_tofile;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_tofile_conf *urtc = uwsgi_calloc(sizeof(struct uwsgi_router_tofile_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"filename", &urtc->filename,
"name", &urtc->filename,
"mode", &urtc->mode, NULL)) {
uwsgi_log("invalid tofile route syntax: %s\n", args);
goto error;
}
if (!urtc->filename) {
uwsgi_log("invalid tofile route syntax, you need to specify a filename\n");
goto error;
}
urtc->filename_len = strlen(urtc->filename);
ur->data2 = urtc;
return 0;
error:
if (urtc->filename) free(urtc->filename);
free(urtc);
return -1;
}
static void router_tofile_register() {
uwsgi_register_router("tofile", uwsgi_router_tofile);
uwsgi_register_router("to-file", uwsgi_router_tofile);
}
struct uwsgi_plugin transformation_tofile_plugin = {
.name = "transformation_tofile",
.on_load = router_tofile_register,
};
#else
struct uwsgi_plugin transformation_tofile_plugin = {
.name = "transformation_tofile",
};
#endif
@@ -0,0 +1,6 @@
NAME='transformation_tofile'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['tofile']
+29
View File
@@ -0,0 +1,29 @@
#include <uwsgi.h>
static int transform_toupper(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
size_t i;
for(i=0;i<ut->chunk->pos;i++) {
ut->chunk->buf[i] = toupper((int) ut->chunk->buf[i]);
}
return 0;
}
static int uwsgi_routing_func_toupper(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_toupper, NULL);
ut->can_stream = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_toupper(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_toupper;
return 0;
}
static void router_toupper_register(void) {
uwsgi_register_router("toupper", uwsgi_router_toupper);
}
struct uwsgi_plugin transformation_toupper_plugin = {
.name = "transformation_toupper",
.on_load = router_toupper_register,
};
@@ -0,0 +1,6 @@
NAME='transformation_toupper'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['toupper']
+15 -25
View File
@@ -21,47 +21,35 @@ struct uwsgi_ugreen {
extern struct uwsgi_server uwsgi;
struct uwsgi_option ugreen_options[] = {
{"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 1},
static struct uwsgi_option ugreen_options[] = {
{"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 0},
{"ugreen-stacksize", required_argument, 0, "set ugreen stack size in pages", uwsgi_opt_set_int, &ug.stackpages, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
};
void u_green_request() {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
// end of the request
uwsgi.wsgi_req->async_status = UWSGI_OK;
uwsgi.wsgi_req->suspended = 0;
return;
}
#endif
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
}
static void u_green_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// first round ?
if (!uwsgi.wsgi_req->suspended) {
ug.contexts[id].uc_link = &ug.main;
makecontext(&ug.contexts[id], u_green_request, 0);
makecontext(&ug.contexts[id], async_schedule_to_req_green, 0);
uwsgi.wsgi_req->suspended = 1;
}
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->suspend(NULL);
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
// save the main stack and switch to the core
swapcontext(&ug.main, &ug.contexts[id] );
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->resume) {
uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->resume(NULL);
}
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
// call it in the main core
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
}
@@ -72,7 +60,9 @@ static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
// back to main
swapcontext(&ug.contexts[wsgi_req->async_id], &ug.main);
// back to core
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
@@ -82,7 +72,7 @@ static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) {
}
int u_green_init() {
static int u_green_init() {
static int i;
+2 -2
View File
@@ -41,6 +41,7 @@ static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments &
}
return v8::Undefined();
}
TeaJS_uWSGI app;
#else
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments &);
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require_do(char *);
@@ -49,11 +50,10 @@ static v8::Handle < v8::Value > uwsgi_v8_commonjs_require_do(char *);
extern struct uwsgi_v8 uv8;
extern struct uwsgi_server uwsgi;
TeaJS_uWSGI app;
v8::Persistent<v8::Context> uwsgi_v8_setup_context() {
#ifdef UWSGI_V8_TEAJS
v8::HandleScope handle_scope;
#ifdef UWSGI_V8_TEAJS
try {
app.init();
app.getContext()->Global()->Set(v8::String::New("require"), v8::FunctionTemplate::New(uwsgi_v8_commonjs_require)->GetFunction());
+2 -1
View File
@@ -85,7 +85,7 @@ static v8::Handle<v8::Value> uwsgi_v8_api_register_rpc(const v8::Arguments& args
uvrt->func[core_id] = func;
// we can safely call register_rpc here as it will check for already registered funcs
if (uwsgi_register_rpc(*name, v8_plugin.modifier1, j_argc, uvrt)) {
if (uwsgi_register_rpc(*name, &v8_plugin, j_argc, uvrt)) {
uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name);
return v8::Undefined();
}
@@ -179,6 +179,7 @@ extern "C" int uwsgi_v8_init(){
pthread_key_create(&uv8.current_core, NULL);
pthread_setspecific(uv8.current_core, (void *) 0);
uv8.contexts[0] = uwsgi_v8_new_isolate(0);
return 0;
+8
View File
@@ -0,0 +1,8 @@
import os
NAME='webdav'
CFLAGS = os.popen('xml2-config --cflags').read().rstrip().split()
LDFLAGS = []
LIBS = os.popen('xml2-config --libs').read().rstrip().split()
GCC_LIST = ['webdav']
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
NAME='xattr'
CFLAGS=[]
LDFLAGS=[]
LIBS=[]
GCC_LIST = ['xattr']
+82
View File
@@ -0,0 +1,82 @@
#include <uwsgi.h>
/*
xattr-related plugin
exposes two routing vars:
file is a var, key is a string
${xattr[PATH_INFO:user.uwsgi.webdav.foobar]}
file is a var, key is a var
${xattr2[PATH_INFO:MYKEY]}
*/
#ifdef __linux__
#include <attr/xattr.h>
#endif
static char *uwsgi_route_var_xattr(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *colon = memchr(key, ':', keylen);
if (!colon) return NULL;
uint16_t var_vallen = 0;
char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen);
if (var_value) {
char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0);
char *name = uwsgi_concat2n(colon+1, (keylen-1) - (colon-key), "", 0);
ssize_t rlen = getxattr(filename, name, NULL, 0);
if (rlen > 0) {
char *value = uwsgi_calloc(rlen);
getxattr(filename, name, value, rlen);
*vallen = rlen;
free(filename);
free(name);
return value;
}
free(filename);
free(name);
}
return NULL;
}
static char *uwsgi_route_var_xattr2(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *colon = memchr(key, ':', keylen);
if (!colon) return NULL;
uint16_t var_vallen = 0;
char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen);
if (var_value) {
uint16_t var2_vallen = 0;
char *var2_value = uwsgi_get_var(wsgi_req, colon+1, (keylen-1) - (colon-key), &var2_vallen);
if (var2_value) {
char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0);
char *name = uwsgi_concat2n(var2_value, var2_vallen, "", 0);
ssize_t rlen = getxattr(filename, name, NULL, 0);
if (rlen > 0) {
char *value = uwsgi_calloc(rlen);
getxattr(filename, name, value, rlen);
*vallen = rlen;
free(filename);
free(name);
return value;
}
free(filename);
free(name);
}
}
return NULL;
}
static void register_route_vars_xattr() {
struct uwsgi_route_var *urv = uwsgi_register_route_var("xattr", uwsgi_route_var_xattr);
urv->need_free = 1;
urv = uwsgi_register_route_var("xattr2", uwsgi_route_var_xattr2);
urv->need_free = 1;
}
struct uwsgi_plugin xattr_plugin = {
.name = "xattr",
.on_load = register_route_vars_xattr,
};

Some files were not shown because too many files have changed in this diff Show More