Compare commits

...
241 Commits
Author SHA1 Message Date
Unbit 0f397eeb55 fixed #305 2013-06-05 11:14:47 +02:00
Unbit bf929398a9 updated gemspec for 1.9.12 2013-06-05 09:19:57 +02:00
Unbit 4f8a0f753e added router_hash and extended support for memcached and redis 2013-06-05 06:26:39 +02:00
Unbit 7db5da9566 fixed support for newer cygwin 2013-06-04 17:13:18 +02:00
Unbit 4d1389805c added redis router code 2013-06-04 13:20:47 +02:00
Unbit ee87e2b946 memcached and redis routers are now builtin by default 2013-06-04 13:07:51 +02:00
Unbit 6356d78768 completed memcachedstore 2013-06-04 12:04:42 +02:00
Unbit afdf7e740e prepare for memcachedstore 2013-06-04 11:40:19 +02:00
Unbit 51ce3ddf78 added offloading to memcached internal router 2013-06-04 11:18:02 +02:00
Unbit 192186056e added pipe offload engine 2013-06-04 10:34:19 +02:00
Unbit 336a7febd7 prepate for 1.9.12 2013-06-03 15:35:17 +02:00
Unbit 63e73d1b73 added --touch-signal 2013-06-03 11:15:39 +02:00
Unbit a02ab9a723 automatically search for 'application' method in jwsgi 2013-06-03 06:33:48 +02:00
Unbit 95f15ab9dd added a note for python logger 2013-06-02 19:20:35 +02:00
Unbit 5d0ea0066a fixed fastcgi body read 2013-06-02 12:52:13 +02:00
Unbit 9ff6b2da9b improved tmp file generation and first implementation of offload transformation 2013-06-02 11:12:28 +02:00
Roberta Giordano 6ac7e27847 added seek() support to jvm input 2013-06-01 19:53:29 +02:00
Roberta Giordano 4ed1c5e747 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-06-01 19:42:29 +02:00
Roberta Giordano bae3bc096f added readLine featute to jvm input 2013-06-01 19:42:11 +02:00
unbit 9d73683de2 Merge pull request #298 from prymitive/csfix
try to escape json
2013-06-01 08:15:19 -07:00
Roberta Giordano f5fec0ab71 added support for jvm list and uwsgi.opt 2013-06-01 16:32:39 +02:00
Łukasz Mierzwa 9909ab10c4 try to escape json 2013-06-01 15:53:35 +02:00
Roberta Giordano 65cff01fee implemented non-static JWSGI apps 2013-06-01 12:20:19 +02:00
unbit 10190a3012 Merge pull request #301 from jimfunk/master
Fix signed/unsigned comparison in emperor_amqp plugin
2013-05-31 21:56:23 -07:00
James Oakley 79ab696f4e Fix signed/unsigned comparison 2013-05-31 13:24:49 -07:00
Unbit cb603682e4 updated gemspec for the new release 2013-05-26 08:08:32 +02:00
Unbit c986a06bf7 more api functions in the uwsgi pypy module, it is enough for 1.9.11 2013-05-26 07:24:57 +02:00
Unbit e2843a6cee fixed static cache paths 2013-05-25 21:03:59 +02:00
Unbit ea1f239807 added memory offload 2013-05-25 20:01:26 +02:00
Unbit 8d7618146a fixed X-Sendfile + gzip 2013-05-25 18:07:41 +02:00
Unbit eb9e419bb0 fixed GC problem with pypy callback 2013-05-25 08:26:52 +02:00
Unbit f98f71ac26 added rbtimer and rpc/call to pypy 2013-05-25 08:09:09 +02:00
Unbit 03baaaebcb only import gevent.select in chat example 2013-05-24 20:41:51 +02:00
Unbit cbca954508 added tests/websockets_chat.py 2013-05-24 20:37:53 +02:00
Unbit 22ba6cc406 added uwsgi.lock/unlock to pypy and fixed --pypy-wsgi-file 2013-05-24 18:10:29 +02:00
Unbit 6bd172acb4 added preinit_apps hook in pypy 2013-05-24 06:59:13 +02:00
unbit 818ba4416f Merge pull request #295 from prymitive/cron_harakiri_fix
send sigkill to whole process group on cron harakiri
2013-05-23 06:50:45 -07:00
Łukasz Mierzwa adff12841c fixed harakiri for cron2 2013-05-23 15:40:02 +02:00
Łukasz Mierzwa 480c306591 send sigkill to whole process group on cron harakiri 2013-05-23 14:52:38 +02:00
unbit cbd1481cb7 Merge pull request #294 from prymitive/cron2
--cron2 option
2013-05-23 04:51:36 -07:00
Łukasz Mierzwa d1c1871222 --cron2 option 2013-05-23 13:44:13 +02:00
Unbit 15a94b8fb0 fixed a typo 2013-05-23 12:10:28 +02:00
unbit 66be54e6a7 Merge pull request #293 from prymitive/cron_stats
cron harakiri and stats
2013-05-23 03:46:24 -07:00
Łukasz Mierzwa 62c85cc2eb cron harakiri and stats 2013-05-23 12:25:02 +02:00
Unbit 1ae05a9ebc avoid loading pypy when python is already loaded 2013-05-23 12:02:35 +02:00
unbit 3457c70f30 Merge pull request #292 from prymitive/unique_crons
unique crons, fixes #227
2013-05-23 02:28:48 -07:00
Łukasz Mierzwa c1ec9126da unique crons, fixes #227 2013-05-23 11:09:56 +02:00
Unbit 398da2fac7 added 'harakiri' routing action 2013-05-23 08:52:19 +02:00
Unbit 47f33d6346 added --print-sym 2013-05-23 08:46:01 +02:00
Unbit 2cad82d537 removed support for SLOW pypy cpyext 2013-05-23 07:48:19 +02:00
Unbit 8d06d78537 preliminary support for GNU HURD 2013-05-23 07:43:01 +00:00
Unbit b61be000de added support for non-file object in pypy wsgi.file_wrapper 2013-05-23 07:03:41 +02:00
Unbit 9ca6de6e7a fixed #291 2013-05-23 06:51:59 +02:00
unbit 5c03c25e96 Merge pull request #237 from prymitive/cgroup_perms
allow setting cgroup dir mode
2013-05-22 05:23:42 -07:00
Roberta Giordano 23843163ad right fix for pipeline requests 2013-05-22 07:41:18 +02:00
Roberta Giordano 8b07fbbedc honour read() method if original file_wrapper object is not a file 2013-05-22 07:16:34 +02:00
Unbit 5bf55220d4 fixed python3 stdout/stderr line buffering 2013-05-21 14:19:33 +02:00
Unbit 0e1de3d6e8 added __name__ and sys.argv[0] in pypy setup script 2013-05-21 00:37:02 +02:00
Unbit 3a7ba3675b better sanity check for http requests 2013-05-20 23:44:05 +02:00
Unbit 5c0deb5bdb correctly handle pep333 exc_info in pypy 2013-05-20 23:31:14 +02:00
Unbit 50dcbc2b01 improved sendfile() on pypy 2013-05-20 23:21:08 +02:00
Unbit 90d72f7843 completed pep3333 vars for pypy 2013-05-20 21:35:02 +02:00
Unbit 90ee59c70d try to automatically set pypy home during compilation 2013-05-20 21:05:41 +02:00
Unbit 59eda11c1b Merge branch 'master' of https://github.com/unbit/uwsgi 2013-05-20 18:58:21 +02:00
Unbit 78684a424f support for http keepalive for request with body 2013-05-20 14:27:50 +02:00
unbit 4a936dda6e Merge pull request #289 from edevil/DropInvalid
Drop obvious invalid requests.
2013-05-20 03:04:14 -07:00
Andre Cruz 094d4b99a4 Drop obvious invalid requests. 2013-05-20 10:44:35 +01:00
Unbit 382268308e improved PYTHONPATH management 2013-05-19 23:40:49 +02:00
Unbit 97315d27b9 added osx support to pypy plugin 2013-05-19 23:33:49 +02:00
Unbit 26ae573b72 added cache_get,cache_update and cache_del to pypy 2013-05-19 22:40:47 +02:00
Unbit 803c44d783 added pypy management of .wsgi files and pythonpath manipulation 2013-05-19 22:33:42 +02:00
Unbit 90f3f1037a fixed a leak in uwsgi_get_app_id 2013-05-19 12:01:04 +02:00
Unbit ce39a751d9 improved uwsgi_get_app_id 2013-05-19 12:00:12 +02:00
unbit ceebf7d32d Merge pull request #288 from alex/pypy-cleanups
Some cleanups for the PyPy plugin:
2013-05-18 22:54:53 -07:00
Unbit 8da59bf0ac better __main__ setup in pypy 2013-05-19 07:52:31 +02:00
Unbit d25979502a better auto-detection of pypy paths 2013-05-19 07:45:21 +02:00
Unbit 549bc3bf9f added --pypy-eval --pypy-eval-post-fork --pypy-eval-exec --pypy-eval-exec-post-fork 2013-05-19 07:17:22 +02:00
Alex Gaynor 22b2f325e0 removed a method with a nonsense implementation 2013-05-18 22:09:24 -07:00
Alex Gaynor 6615d1b90c Catch a more precise error 2013-05-18 22:06:36 -07:00
Alex Gaynor 8f045c4254 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-05-18 22:06:04 -07:00
Alex Gaynor a4434349e5 whoops, a few small fixse 2013-05-18 22:03:55 -07:00
Unbit 01272be25f automatically detect pypy in setup.py 2013-05-19 07:02:05 +02:00
Alex Gaynor be0beed403 Some cleanups for the PyPy plugin:
a) pep8 and such
b) Made classes be newstyle
c) Made the classes be created once, not once per request
2013-05-18 21:59:37 -07:00
Unbit 453d2abed5 another micro optimization for pypy 2013-05-19 06:52:01 +02:00
Unbit 57e9ccbef0 added uwsgi.opt to pypy 2013-05-19 06:33:57 +02:00
Unbit 989124772b added wsgi.file_wrapper and improved import in pypy 2013-05-19 06:20:02 +02:00
Unbit 72400e4b91 completed wsgi.input for pypy 2013-05-19 05:33:53 +02:00
Unbit 900cba29a7 fixed python3 pyargv 2013-05-19 04:55:52 +02:00
Unbit f177a65c1e added uwsgi.add_file_monitor to pypy 2013-05-18 20:08:50 +02:00
Unbit b6baf9016d Merge branch 'master' of github.com:unbit/uwsgi 2013-05-18 20:02:37 +02:00
Unbit 86ac6e8044 implemented uwsgi.add_timer for pypy 2013-05-18 20:01:18 +02:00
unbit 66d8fb95db Merge pull request #286 from alex/patch-1
Fixed a clear typo.
2013-05-18 10:55:50 -07:00
Unbit 22da8d9ba2 optimized pypy environ helper 2013-05-18 19:45:18 +02:00
Alex Gaynor 819e9c1b16 Fixed a clear typo.
Only call writer once when the result of a WSGI application is a string.
2013-05-18 11:23:01 -06:00
Unbit dd4b2e8bc2 fixed a typo 2013-05-18 18:29:16 +02:00
Unbit e2f7ac2017 added --mule-msg-size 2013-05-18 18:28:50 +02:00
Unbit 31b5cf6926 fixed mule_msg 2013-05-18 17:52:23 +02:00
Unbit 25fe3035c2 fixed SCRIPT_NAME handling in python 2013-05-18 17:27:51 +02:00
Unbit 0cf56823cd added uwsgi.cache_get to pypy 2013-05-18 15:45:53 +02:00
Unbit c2f36968c3 trying to understand why multirheading is flaky on pypy 2013-05-18 12:17:43 +02:00
Unbit a508c7f53e added signal handling to pypy 2013-05-18 09:59:06 +02:00
Unbit 48de68031d more pypy implementations 2013-05-18 09:20:55 +02:00
Unbit 81ef85af82 added xmlrpc wrapper 2013-05-17 16:42:45 +02:00
Unbit 16b65d7dbe uwsgi RPC http wrapper 2013-05-17 15:45:43 +02:00
Unbit 5a98e6511b prepare for pypy multithreading 2013-05-17 14:28:42 +02:00
unbit 2418f08e22 Update README 2013-05-16 23:31:23 +03:00
Unbit 80a821bc20 updated pypy README 2013-05-16 18:09:36 +02:00
Unbit 378f78bd87 removed uwsgi.py 2013-05-16 18:03:35 +02:00
Unbit f010591e19 more WSGI vars 2013-05-16 17:58:15 +02:00
Unbit 5274abdcca fixed pypy environ 2013-05-16 17:30:29 +02:00
Unbit 48f9e8c5c8 improved PyPy plugin 2013-05-16 16:29:13 +02:00
unbit 5c02117fde Merge pull request #285 from fijal/master
A sketch for a PyPy plugin
2013-05-15 05:21:57 -07:00
Maciej Fijalkowski bc56a188f8 Add a copyright info 2013-05-15 14:18:47 +02:00
Maciej Fijalkowski b6df1b22ab flush the pypy debug file 2013-05-14 23:55:27 +02:00
Maciej Fijalkowski 0fbf2dd5bb Progress - now example wsgi runs 2013-05-14 23:32:05 +02:00
Unbit 38c126d11a fixed file action status 2013-05-14 16:49:22 +02:00
Unbit 7dff602e5e try to fix retry engine 2013-05-14 16:43:44 +02:00
Maciej Fijalkowski e401f32815 This was indeed temporary 2013-05-14 15:19:04 +02:00
Maciej Fijalkowski 12e94b70a7 Merge github.com:fijal/uwsgi 2013-05-14 15:06:48 +02:00
Maciej Fijalkowski 884de3959c initial checkin of pypy plugin 2013-05-14 15:04:17 +02:00
Unbit fe12325e50 fixed goto and pc in error and final routing 2013-05-14 12:19:17 +02:00
Unbit bea86f3f79 fixed a typo 2013-05-13 18:55:48 +02:00
unbit 7a5f3667da Merge pull request #280 from xrmx/warn-ini
core: print a warning if the configuration section can't be read
2013-05-13 07:35:20 -07:00
Riccardo Magliocchetti 0813788c98 core: print a warning if the configuration section can't be read
Fixes #278
2013-05-13 16:21:30 +02:00
Unbit b1ca73e7f0 added file-next action 2013-05-13 07:33:05 +02:00
Unbit ebf9e9b1a3 added ignore_body flag 2013-05-13 07:19:12 +02:00
Unbit b0abab7a1d fixed #277 2013-05-12 22:57:07 +02:00
Unbit 995bb493df preliminary implementation of error routing 2013-05-12 22:48:10 +02:00
Unbit 1b2375fc84 added error routes 2013-05-12 18:02:33 +02:00
Unbit b7315bcb5a added "file" routing action 2013-05-12 17:36:40 +02:00
Unbit 2c9ebdaa69 updated gemspec for 1.9.10 2013-05-11 17:12:00 +02:00
Unbit fbd9e5b4d7 goroutines support must be completely rewritten :( 2013-05-11 16:57:41 +02:00
unbit b9a3425b6d Merge pull request #276 from prymitive/build_fixes
better check for default value, this allows using false or empty string ...
2013-05-11 02:53:56 -07:00
Łukasz Mierzwa d4742c611b better check for default value, this allows using false or empty string as defaults 2013-05-11 11:43:29 +02:00
Unbit c645a590aa added goroutine reference to gccgo 2013-05-11 08:43:46 +02:00
Unbit 275a7fe63f added --go-args 2013-05-11 08:26:02 +02:00
unbit 0ff16d8312 Merge pull request #275 from prymitive/df
fixed legion-smart-attach-daemon2
2013-05-10 14:21:42 -07:00
Łukasz Mierzwa 1cb31d6c7e fixed legion-smart-attach-daemon2 2013-05-10 20:51:39 +02:00
Unbit 8a6eb553df fixed attach-daemon 2013-05-10 17:20:44 +02:00
Unbit 946af8b9ee added errorlimiter.ini example config 2013-05-10 15:15:51 +02:00
Unbit 098a1f647e added final routes or running rules at the end of the request 2013-05-10 15:08:33 +02:00
Unbit c9681dc430 Merge branch 'master' of github.com:unbit/uwsgi 2013-05-10 08:18:33 +02:00
Unbit ff0b8b2d53 fixed #274 2013-05-10 08:17:54 +02:00
unbit 75f520d43a Merge pull request #255 from prymitive/airbrake_fixes
few airbrake fixes
2013-05-09 11:52:29 -07:00
Unbit 65209748ba completed the first phase of the gccgo plugin 2013-05-09 19:55:27 +02:00
Unbit cd604ef07b extended the build system to support .o files and added preliminary gccgo plugin 2013-05-09 18:38:53 +02:00
Łukasz Mierzwa 51da8bc531 * report more data in airbrake plugin
* preserve text version of backtrace (there might be multiple alarm handlers for any segfault)
* fix reload errors
2013-05-09 15:44:29 +02:00
Unbit 2374ba12bd better file descriptor management for alarm threads 2013-05-09 15:17:57 +02:00
Unbit 0a75aaec25 added the uwsgi_takeover commodity function 2013-05-09 13:53:22 +02:00
Unbit a8c286ae83 prepare for gccgo integration 2013-05-09 11:43:01 +02:00
Unbit 9cbdfc7764 updated gemspec for 1.9.9 2013-05-08 17:48:41 +02:00
Unbit cb1423436f fixed radius-next 2013-05-08 16:30:32 +02:00
Unbit 2fb391795a added symcall-post-fork 2013-05-08 13:29:21 +02:00
Unbit 9ec20f2d8f allows cache math from the routing subsystem 2013-05-08 11:00:23 +02:00
Unbit 9323ca5136 added cache math api to python 2013-05-08 10:34:34 +02:00
Unbit 978e6072ab prepare for math operations in cache 2013-05-08 09:41:24 +02:00
Unbit d0e3869d54 fixed go arguments on osx 2013-05-07 16:35:34 +02:00
unbit 15c7e956f2 Merge pull request #270 from prymitive/numleaks
2 small memory leaks valgrind complains about
2013-05-07 07:01:11 -07:00
Łukasz Mierzwa ed61545ec7 2 small memory leaks valgrind complains about 2013-05-07 15:54:35 +02:00
Unbit 1aac5becdc added --touch-exec 2013-05-07 15:14:09 +02:00
Unbit 4bca26debc added the radius plugin 2013-05-07 14:38:44 +02:00
Unbit d6eecd1637 report gateway harakiri 2013-05-07 13:41:40 +02:00
unbit 00e7620d2e Merge pull request #269 from prymitive/legion_daemons
legion daemons
2013-05-07 03:36:25 -07:00
Łukasz Mierzwa d657283aad legion daemons 2013-05-07 12:09:26 +02:00
Unbit 70a879ea94 added incache routing condition 2013-05-07 11:56:18 +02:00
Unbit 591ee22472 fixed support for go 1.1rc2 2013-05-07 11:11:25 +02:00
Unbit 956b05d39d Merge branch 'master' of github.com:unbit/uwsgi 2013-05-07 10:02:00 +02:00
Roberto De Ioris 5bdad6d4cb support for go 1.1 on osx 2013-05-07 04:36:05 +02:00
unbit 29a6ac6ed7 Merge pull request #267 from prymitive/log_retries
log retry count on router error
2013-05-06 09:16:07 -07:00
Łukasz Mierzwa 8f7f091e9b log retry count on router error 2013-05-06 16:20:04 +02:00
Unbit 63dfe7628b added uwsgi_connect_udp 2013-05-06 15:22:13 +02:00
Unbit ce507e7851 try to fix multithread + dynamic mode 2013-05-04 15:44:44 +02:00
Unbit a9cd76173e added default app for psgi 2013-05-04 15:41:12 +02:00
Unbit 44f8ffb434 another fix in spnego 2013-05-04 15:27:40 +02:00
Unbit 28c395f111 it looks like both MIT krb5 and heimdal leaks memory... 2013-05-04 15:14:17 +02:00
Unbit 39df68c38e better next support for spnego 2013-05-04 13:49:32 +02:00
Unbit b33ca9225a improved route-if regexp to store vectors 2013-05-04 13:36:09 +02:00
Unbit bd137afecf fixed thread bug with routing regexp vectors 2013-05-04 12:39:08 +02:00
Roberta Giordano a3b9bed8c2 fixed spnego build 2013-05-04 08:37:55 +02:00
Unbit 0a157739bc Merge branch 'master' of github.com:unbit/uwsgi 2013-05-04 08:11:37 +02:00
Unbit c46b08ad5e completed spnego plugin 2013-05-04 08:11:19 +02:00
unbit 754e6193a4 Merge pull request #265 from ttreptow/master
Fix mule farm initialization
2013-05-03 12:03:26 -07:00
Tim Treptow 56b49fe2dd fix mule farm initialization 2013-05-03 09:40:10 -07:00
Unbit 36a7215f94 added setscriptname and donotlog routing actions 2013-05-03 17:49:06 +02:00
Unbit 702247affd spnego plugin is almost ready 2013-05-03 17:44:21 +02:00
Unbit e752b1f8e5 added Graham credits 2013-05-03 10:21:15 +02:00
Unbit 920eee36e3 fixed a wrong cast in gevent plugin 2013-05-02 17:28:06 +02:00
unbit a5070a5d98 Merge pull request #262 from edevil/master
Call atexit hook after all requests are done, or immediately if there are no requests
2013-05-02 08:24:57 -07:00
Unbit ccb5aefa61 do not use the stack on ldapauth filter generation 2013-05-02 16:50:55 +02:00
Unbit 378b08e37c fixed a memory leak in ldapauth 2013-05-02 16:48:04 +02:00
Unbit 5763483c91 avoid using deprecated apis in the ldap plugin 2013-05-02 15:54:45 +02:00
Andre Cruz 559f8ee095 Call atexit hook when we want to graceful reload and there are no requests being served. Otherwise call it when the last request finishes. 2013-05-02 14:36:50 +01:00
Unbit 4382ef360c Merge branch 'master' of github.com:unbit/uwsgi 2013-05-02 15:12:07 +02:00
Unbit 0cb576cf1a added ldap to all buildconf 2013-05-02 15:11:57 +02:00
unbit dee4d047b4 Merge pull request #261 from prymitive/ldapauth1
remove useless reconnect
2013-05-02 06:11:25 -07:00
Łukasz Mierzwa 2520cc7bb9 remove useless reconnect 2013-05-02 12:24:11 +02:00
unbit 192c31efe0 Merge pull request #257 from prymitive/router_ldapauth
router_ldapauth plugin with simple bind support
2013-05-02 02:54:23 -07:00
Łukasz Mierzwa a1d8ebc2d2 router_ldapauth plugin with simple bind support 2013-05-02 11:47:31 +02:00
Unbit 14a9de2147 spnego authentication is still broken 2013-05-02 10:17:28 +02:00
Unbit a760a9a3f1 ported the xslt plugin to the new api 2013-05-02 10:04:04 +02:00
Unbit efd14e1c7a added cookie-based authentication test 2013-05-02 09:34:31 +02:00
Unbit 6019c46cee removed the GOON routing return value 2013-05-02 08:45:37 +02:00
Unbit ec6acfbc1c improved transformation system 2013-05-01 19:36:13 +02:00
Unbit e925dbaad6 other gzip improvements 2013-05-01 12:04:41 +02:00
Unbit 8321adf0bc completed chunked transformation 2013-05-01 10:21:35 +02:00
Unbit e1c5e9e874 prepare for gzip streaming 2013-05-01 10:05:39 +02:00
Unbit 0aec581714 prepare for streaming transformations 2013-05-01 09:56:56 +02:00
Unbit b77b8623d1 added a simple dumper for REPORT method 2013-04-30 18:49:58 +02:00
Unbit 5ab986d6d9 send only requested webdav props 2013-04-30 11:41:16 +02:00
Unbit 09b8332236 prepare for caldav support 2013-04-29 21:42:46 +02:00
Unbit d05345abc0 added current-user-privilege-set 2013-04-29 15:06:37 +02:00
Unbit 804c369f0d toward programmable webdav, carddav support ensured 2013-04-29 14:42:04 +02:00
Roberta Giordano 8f67fc886c added support for OSX xattr in WebDAV plugin 2013-04-28 11:37:20 +02:00
Roberta Giordano ca3b1a9b30 support for OSX in the webdav plugin 2013-04-28 11:24:07 +02:00
Unbit 63c1dbb3ed windows-webdav compatibility fix 2013-04-28 11:16:44 +02:00
Unbit 9a424dfe29 prepare for webdav locking 2013-04-28 10:07:36 +02:00
Unbit 0a6eb596bb completed PROPPATCH 2013-04-28 09:46:10 +02:00
Unbit 34452376db added PROPFIND + xattr in the webdav plugin 2013-04-28 08:31:47 +02:00
Unbit 53a90a59c5 added xattr plugin 2013-04-27 19:01:09 +02:00
Unbit ec491ebd83 added the WebDAV plugin (beta) 2013-04-27 18:24:21 +02:00
Unbit cdc41c305e improved url encoding api 2013-04-27 11:45:48 +02:00
Unbit 6cf67b399c new api functions for http headers 2013-04-27 09:10:11 +02:00
unbit dc3c56bccc Merge pull request #253 from prymitive/alarm_airbrake_plugin
airbrake plugin
2013-04-26 07:55:23 -07:00
Łukasz Mierzwa 4657f2039a airbrake plugin 2013-04-26 16:29:18 +02:00
Unbit b0082fbd0d added --alarm-segfault 2013-04-26 15:09:04 +02:00
Unbit ede1b4df11 fixed initial flush 2013-04-26 08:36:41 +02:00
unbit d78a3d1f8a Merge pull request #247 from prymitive/cache_sync_fix
fixed cache sync parsing
2013-04-25 05:44:08 -07:00
Unbit 6152555f26 another fix in python async mode 2013-04-25 14:43:40 +02:00
Unbit bbad505044 fixed python async mode with the improved api 2013-04-25 14:28:38 +02:00
Łukasz Mierzwa 11c5429184 fixed cache sync parsing - uwsgi_hooked_parse() was getting invalid data lenght 2013-04-25 14:28:18 +02:00
Unbit 4e865c4525 fixed stackless + threads 2013-04-25 14:03:40 +02:00
Unbit 2fa785a539 improved fiber support 2013-04-25 13:51:05 +02:00
Unbit 296a8449c9 improved stackless plugin 2013-04-25 13:46:30 +02:00
Unbit f20213ff10 various async/green mode improvements and fixes 2013-04-25 11:33:45 +02:00
Unbit 8a7067ee24 added routing support to coroae and fixed backtrace-depth 2013-04-25 09:09:46 +02:00
Unbit a3024e9f5a refactored async mode 2013-04-25 08:57:58 +02:00
Unbit 86e651f5e7 call gevent atexit hook before destroying uwsgi-related greenlets 2013-04-25 07:09:39 +02:00
unbit 409710b2b1 Merge pull request #245 from prymitive/dont_count_tx_on_pings
don't increment tx counter on requests that should not be accounted
2013-04-24 04:27:27 -07:00
Łukasz Mierzwa 14a406a276 don't increment tx counter on requests that should not be accounted (ping plugin requests) 2013-04-24 10:57:05 +02:00
Unbit 28a283b1c1 added uwsgi.atexit management to gevent 2013-04-23 21:20:42 +02:00
Łukasz Mierzwa 7c4caef5e7 allow setting cgroup dir mode 2013-04-18 13:13:15 +02:00
116 changed files with 8302 additions and 844 deletions
+2
View File
@@ -2,6 +2,8 @@
*.py[co]
*.class
*.jar
*~
*.so
/uwsgi
/uwsgibuild.*
+1 -1
View File
@@ -1,3 +1,3 @@
[uwsgi]
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap
inherit = base
+1 -1
View File
@@ -16,7 +16,7 @@ plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash
as_shared_library = false
locking = auto
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin =
inherit = base
+116 -79
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;
}
@@ -61,13 +82,18 @@ 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 = uwsgi_malloc(sizeof(struct uwsgi_async_request));
// 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;
@@ -83,8 +109,6 @@ static void runqueue_push(struct wsgi_request *wsgi_req) {
uwsgi.async_runqueue_last->next = uar;
}
uwsgi.async_runqueue_last = uar;
uwsgi.async_runqueue_cnt++;
}
struct wsgi_request *find_first_available_wsgi_req() {
@@ -100,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 (;;) {
@@ -118,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;
}
@@ -148,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;
@@ -205,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;
@@ -249,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() {
@@ -259,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;
@@ -268,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;
@@ -295,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 {
@@ -325,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) {
@@ -348,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++;
@@ -361,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);
}
@@ -377,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
@@ -399,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) {
@@ -408,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;
}
+86 -5
View File
@@ -194,9 +194,15 @@ static void uwsgi_cache_load_files(struct uwsgi_cache *uc) {
if (!uwsgi_cache_set2(uc, key, key_len, value, len, 0, 0)) {
uwsgi_log("[cache] stored \"%.*s\" in \"%s\"\n", key_len, key, uc->name);
}
else {
uwsgi_log("[cache-error] unable to store \"%.*s\" in \"%s\"\n", key_len, key, uc->name);
}
uwsgi_rwunlock(uc->lock);
free(value);
}
else {
uwsgi_log("[cache-error] unable to read file \"%.*s\"\n", key_len, key);
}
next:
usl = usl->next;
}
@@ -416,6 +422,24 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
return NULL;
}
int64_t uwsgi_cache_num2(struct uwsgi_cache *uc, char *key, uint16_t keylen) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
if (index) {
struct uwsgi_cache_item *uci = cache_item(index);
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
return 0;
uci->hits++;
uc->hits++;
int64_t *num = (int64_t *) (uc->data + (uci->first_block * uc->blocksize));
return *num;
}
uc->miss++;
return 0;
}
char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize, uint64_t *expires) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
@@ -543,6 +567,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
if (vallen > uc->max_item_size) return -1;
if ((flags & UWSGI_CACHE_FLAG_MATH) && vallen != 8) return -1;
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) {
@@ -602,7 +628,33 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uci->hits = 0;
uci->flags = flags;
memcpy(uci->key, key, keylen);
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
}
// ok math operations here
else {
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
*num = uc->math_initial;
int64_t *delta = (int64_t *) val;
if (flags & UWSGI_CACHE_FLAG_INC) {
*num += *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DEC) {
*num -= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_MUL) {
*num *= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DIV) {
if (*delta == 0) {
*num = 0;
}
else {
*num /= *delta;
}
}
}
// set this as late as possibile (to reduce races risk)
@@ -634,7 +686,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
}
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
uci = cache_item(index);
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
now = uwsgi_now();
expires += now;
uci->expires = expires;
@@ -661,7 +713,30 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
// unmark the old blocks
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
}
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
}
else {
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
int64_t *delta = (int64_t *) val;
if (flags & UWSGI_CACHE_FLAG_INC) {
*num += *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DEC) {
*num -= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_MUL) {
*num *= *delta;
}
else if (flags & UWSGI_CACHE_FLAG_DIV) {
if (*delta == 0) {
*num = 0;
}
else {
*num /= *delta;
}
}
}
uci->valsize = vallen;
ret = 0;
}
@@ -968,6 +1043,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_udp_servers = NULL;
char *c_bitmap = NULL;
char *c_use_last_modified = NULL;
char *c_math_initial = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"name", &c_name,
@@ -994,6 +1070,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"udpserver", &c_udp_servers,
"bitmap", &c_bitmap,
"lastmod", &c_use_last_modified,
"math_initial", &c_math_initial,
NULL)) {
uwsgi_log("unable to parse cache definition\n");
exit(1);
@@ -1018,7 +1095,6 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
// defaults
uc->blocks = uc->max_items;
uc->blocksize = UMAX16;
uc->max_item_size = uc->blocksize;
uc->keysize = 2048;
uc->hashsize = UMAX16;
uc->hash = uwsgi_hash_algo_get("djb33x");
@@ -1026,6 +1102,9 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
// customize
if (c_blocksize) uc->blocksize = uwsgi_n64(c_blocksize);
if (!uc->blocksize) { uwsgi_log("invalid cache blocksize for \"%s\"\n", uc->name); exit(1); }
// set the true max size of an item
uc->max_item_size = uc->blocksize;
if (c_blocks) uc->blocks = uwsgi_n64(c_blocks);
if (!uc->blocks) { uwsgi_log("invalid cache blocks for \"%s\"\n", uc->name); exit(1); }
if (c_hash) uc->hash = uwsgi_hash_algo_get(c_hash);
@@ -1040,6 +1119,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
}
if (c_use_last_modified) uc->use_last_modified = 1;
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
uc->store_sync = uwsgi.cache_store_sync;
if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); }
@@ -1737,7 +1818,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);
+160 -12
View File
@@ -27,13 +27,22 @@ struct uwsgi_cron *uwsgi_cron_add(char *crontab) {
exit(1);
}
uc->command = crontab + i;
uc->pid = -1;
return uc;
}
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
uwsgi_cron_add(value);
}
void uwsgi_opt_add_unique_cron(char *opt, char *value, void *foobar) {
struct uwsgi_cron *uc = uwsgi_cron_add(value);
uc->unique = 1;
}
#ifdef UWSGI_SSL
void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) {
char *space = strchr(value, ' ');
@@ -45,9 +54,140 @@ void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) {
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
uc->legion = legion;
}
void uwsgi_opt_add_unique_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;
uc->unique = 1;
}
#endif
void uwsgi_opt_add_cron2(char *opt, char *value, void *foobar) {
char *c_minute = NULL;
char *c_hour = NULL;
char *c_day = NULL;
char *c_month = NULL;
char *c_week = NULL;
char *c_unique = NULL;
char *c_harakiri = NULL;
char *c_legion = NULL;
char *c_command = value;
char *space = strchr(value, ' ');
if (space) {
if (uwsgi_str_contains(value, space - value, '=')) {
// --cron2 key=val command
*space = 0;
c_command = space + 1;
}
// no point in parsing key=val list if there is none
if (uwsgi_kvlist_parse(value, strlen(value), ',', '=',
"minute", &c_minute,
"hour", &c_hour,
"day", &c_day,
"month", &c_month,
"week", &c_week,
"unique", &c_unique,
"harakiri", &c_harakiri,
"legion", &c_legion,
NULL)) {
uwsgi_log("unable to parse cron definition: %s\n", value);
exit(1);
}
}
else {
if (uwsgi_str_contains(value, strlen(value), '=')) {
// --cron2 key=val
uwsgi_log("unable to parse cron definition: %s\n", value);
exit(1);
}
}
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));
uc->command = c_command;
if (!uc->command) {
uwsgi_log("[uwsgi-cron] invalid command in cron definition: %s\n", value);
exit(1);
}
// defaults
uc->minute = -1;
uc->hour = -1;
uc->day = -1;
uc->month = -1;
uc->week = -1;
uc->unique = 0;
uc->mercy = 0;
uc->harakiri = 0;
uc->pid = -1;
#ifdef UWSGI_SSL
uc->legion = c_legion;
#endif
if (c_minute)
uc->minute = atoi(c_minute);
if (c_hour)
uc->hour = atoi(c_hour);
if (c_day)
uc->day = atoi(c_day);
if (c_month)
uc->month = atoi(c_month);
if (c_week)
uc->week = atoi(c_week);
if (c_unique)
uc->unique = atoi(c_unique);
if (c_harakiri) {
if (atoi(c_harakiri)) {
// harakiri > 0
uc->mercy = atoi(c_harakiri);
}
else {
// harakiri == 0
uc->mercy = -1;
}
}
else if (uwsgi.cron_harakiri) {
uc->harakiri = uwsgi.cron_harakiri;
}
}
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
if (!uwsgi.master_process)
@@ -134,15 +274,16 @@ void uwsgi_manage_command_cron(time_t now) {
#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;
}
if (!uwsgi_legion_i_am_the_lord(current_cron->legion))
goto next;
}
#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);
// skip unique crons that are still running
if (current_cron->unique && current_cron->pid >= 0)
goto next;
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 ?
@@ -153,20 +294,27 @@ void uwsgi_manage_command_cron(time_t now) {
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);
}
pid_t pid = uwsgi_run_command(current_cron->command, NULL, -1);
if (pid >= 0) {
current_cron->pid = pid;
current_cron->started_at = now;
uwsgi_log_verbose("[uwsgi-cron] running \"%s\" (pid %d)\n", current_cron->command, current_cron->pid);
if (current_cron->mercy) {
//uwsgi_cron->mercy can be negative to inform master that harakiri should be disabled for this cron
if (current_cron->mercy > 0)
current_cron->harakiri = now + current_cron->mercy;
}
else if (uwsgi.cron_harakiri)
current_cron->harakiri = now + uwsgi.cron_harakiri;
}
}
}
current_cron->last_job = now;
}
}
next:
current_cron = current_cron->next;
}
}
+98 -8
View File
@@ -1,4 +1,4 @@
#include "../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -42,6 +42,31 @@ void uwsgi_daemons_smart_check() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
#ifdef UWSGI_SSL
if (ud->legion) {
if (uwsgi_legion_i_am_the_lord(ud->legion)) {
// lord, spawn if not running
if (ud->pid <= 0) {
uwsgi_spawn_daemon(ud);
}
}
else {
// not lord, kill daemon if running
if (ud->pid > 0) {
if (!kill(ud->pid, 0)) {
uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid);
kill(-ud->pid, SIGTERM);
}
else {
// pid already died
ud->pid = -1;
}
}
ud = ud->next;
continue;
}
}
#endif
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
@@ -70,12 +95,13 @@ void uwsgi_daemons_smart_check() {
}
}
// this function is called when a dumb daemon dies and we do not wat to respawn it
// this function is called when a dumb daemon dies and we do not want to respawn it
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
ud->pid = -1;
return -1;
}
ud = ud->next;
@@ -87,6 +113,15 @@ int uwsgi_daemon_check_pid_death(pid_t diedpid) {
int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
#ifdef UWSGI_SSL
if (ud->pid == diedpid && ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
// part of legion but not lord, don't respawn
ud->pid = -1;
uwsgi_log("uwsgi-daemons] legion \"%s\" daemon \"%s\" (pid: %d) annihilated\n", ud->legion, ud->command, (int) diedpid);
ud = ud->next;
continue;
}
#endif
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_spawn_daemon(ud);
return 1;
@@ -133,6 +168,20 @@ void uwsgi_daemons_spawn_all() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (!ud->registered) {
#ifdef UWSGI_SSL
if (ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
// part of legion, register but don't spawn it yet
if (ud->pidfile) {
ud->pid = uwsgi_check_pidfile(ud->pidfile);
if (ud->pid > 0)
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
}
ud->registered = 1;
ud = ud->next;
continue;
}
#endif
ud->registered = 1;
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
@@ -146,7 +195,6 @@ void uwsgi_daemons_spawn_all() {
else {
uwsgi_spawn_daemon(ud);
}
ud->registered = 1;
}
ud = ud->next;
}
@@ -156,8 +204,29 @@ void uwsgi_daemons_spawn_all() {
void uwsgi_detach_daemons() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0 && !ud->pidfile)
kill(-ud->pid, SIGKILL);
#ifdef UWSGI_SSL
// stop any legion daemon, doesn't matter if dumb or smart
if (ud->pid > 0 && (ud->legion || !ud->pidfile)) {
#else
// stop only dumb daemons
if (ud->pid > 0 && !ud->pidfile) {
#endif
uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command);
// try to gracefully stop daemon, kill it if it won't die
// if mercy is not set than wait up to 3 seconds
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
while (!kill(ud->pid, 0)) {
kill(-ud->pid, SIGTERM);
sleep(1);
if (uwsgi_now() >= timeout) {
uwsgi_log("[uwsgi-daemons] daemon did not died in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
kill(-ud->pid, SIGKILL);
break;
}
}
// unregister daemon to prevent it from being respawned
ud->registered = 0;
}
ud = ud->next;
}
}
@@ -165,6 +234,9 @@ void uwsgi_detach_daemons() {
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
// skip unregistered daemons
if (!ud->registered) return;
int devnull = -1;
int throttle = 0;
@@ -261,11 +333,26 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
char *pidfile = NULL;
int daemonize = 0;
int freq = 10;
char *space = NULL;
char *command = uwsgi_str(value);
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2")) {
char *space = strchr(command, ' ');
#ifdef UWSGI_SSL
char *legion = NULL;
if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) {
space = strchr(command, ' ');
if (!space) {
uwsgi_log("invalid legion daemon syntax: %s\n", command);
exit(1);
}
*space = 0;
legion = command;
command = space+1;
}
#endif
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) {
space = strchr(command, ' ');
if (!space) {
uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command);
exit(1);
@@ -279,7 +366,7 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
freq = atoi(comma + 1);
}
command = space + 1;
if (!strcmp(opt, "smart-attach-daemon2")) {
if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) {
daemonize = 1;
}
}
@@ -308,6 +395,9 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi_ud->last_spawn = 0;
uwsgi_ud->daemonize = daemonize;
uwsgi_ud->pidfile = pidfile;
#ifdef UWSGI_SSL
uwsgi_ud->legion = legion;
#endif
uwsgi.daemons_cnt++;
+17
View File
@@ -376,7 +376,11 @@ void *event_queue_alloc(int nevents) {
int event_queue_interesting_fd(void *events, int id) {
port_event_t *pe = (port_event_t *) events;
#ifdef PORT_SOURCE_FILE
if (pe[id].portev_source == PORT_SOURCE_FILE || pe[id].portev_source == PORT_SOURCE_TIMER) {
#else
if (pe[id].portev_source == PORT_SOURCE_TIMER) {
#endif
return (long) pe[id].portev_user;
}
@@ -464,7 +468,11 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
}
#ifdef PORT_SOURCE_FILE
if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) {
#else
if (pe.portev_source == PORT_SOURCE_TIMER) {
#endif
*interesting_fd = (long) pe.portev_user;
}
else {
@@ -972,6 +980,7 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
#endif
#ifdef UWSGI_EVENT_FILEMONITOR_USE_PORT
#ifdef PORT_SOURCE_FILE
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
struct file_obj fo;
@@ -1032,6 +1041,14 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
}
#else
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
return -1;
}
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
return NULL;
}
#endif
#endif
+3 -1
View File
@@ -18,7 +18,9 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
}
}
char *fullname = uwsgi_concat3(name, " ", uwsgi_num2str(num));
char *str = uwsgi_num2str(num);
char *fullname = uwsgi_concat3(name, " ", str);
free(str);
ug = &ushared->gateways[ushared->gateways_cnt];
ug->pid = 0;
+6
View File
@@ -91,6 +91,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
char *section_asked = "uwsgi";
char *colon;
int got_section = 0;
if (uwsgi_check_scheme(file)) {
@@ -147,6 +148,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
val = ini_get_key(key);
if (!strcmp(section, section_asked)) {
got_section = 1;
ini_rstrip(key);
val = ini_lstrip(val);
ini_rstrip(val);
@@ -161,6 +163,10 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
}
if (!got_section) {
uwsgi_log("*** WARNING: Can't find section \"%s\" in INI configuration file %s ***\n", section_asked, file);
}
if (colon) {
colon[0] = ':';
}
+10
View File
@@ -161,6 +161,10 @@ void uwsgi_init_default() {
uwsgi.empty = "";
#ifdef __linux__
uwsgi.cgroup_dir_mode = "0700";
#endif
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
@@ -347,6 +351,12 @@ void uwsgi_setup_workers() {
// allocate signal table
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
#ifdef UWSGI_ROUTING
uwsgi_fixup_routes(uwsgi.routes);
uwsgi_fixup_routes(uwsgi.error_routes);
uwsgi_fixup_routes(uwsgi.final_routes);
#endif
}
pid_t uwsgi_daemonize2() {
+13 -3
View File
@@ -659,7 +659,9 @@ ready:
// application generic lock
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
for (i = 0; i < uwsgi.locks + 1; i++) {
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i)));
char *num = uwsgi_num2str(i);
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", num));
free(num);
}
// event queue lock (mitigate same event on multiple queues)
@@ -762,10 +764,18 @@ nextlock:
}
void uwsgi_user_lock(int lock_num) {
int uwsgi_user_lock(int lock_num) {
if (lock_num < 0 || lock_num > uwsgi.locks) {
return -1;
}
uwsgi_lock(uwsgi.user_lock[lock_num]);
return 0;
}
void uwsgi_user_unlock(int lock_num) {
int uwsgi_user_unlock(int lock_num) {
if (lock_num < 0 || lock_num > uwsgi.locks) {
return -1;
}
uwsgi_unlock(uwsgi.user_lock[lock_num]);
return 0;
}
+41
View File
@@ -473,6 +473,30 @@ 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);
// update signal touches
usl = uwsgi.touch_signal;
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_signal);
// setup cheaper algos (can be stacked)
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
@@ -694,6 +718,7 @@ int master_loop(char **argv, char **environ) {
uwsgi_master_check_gateways_deadline();
uwsgi_master_check_mules_deadline();
uwsgi_master_check_spoolers_deadline();
uwsgi_master_check_crons_deadline();
#ifdef __linux__
#ifdef MADV_MERGEABLE
@@ -748,6 +773,20 @@ 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);
}
}
touched = uwsgi_check_touches(uwsgi.touch_signal);
if (touched) {
uint8_t signum = atoi(touched);
uwsgi_route_signal(signum);
uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum);
}
}
continue;
@@ -769,6 +808,7 @@ int master_loop(char **argv, char **environ) {
if (uwsgi_master_check_mules_death(diedpid)) continue;
if (uwsgi_master_check_gateways_death(diedpid)) continue;
if (uwsgi_master_check_daemons_death(diedpid)) continue;
if (uwsgi_master_check_cron_death(diedpid)) continue;
}
@@ -833,6 +873,7 @@ next:
// ok, if we are reloading or dying, just continue the master loop
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) {
if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now();
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now()-uwsgi.workers[thewid].cursed_at));
uwsgi.workers[thewid].cursed_at = 0;
continue;
+27
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;
@@ -276,3 +277,29 @@ int uwsgi_worker_is_busy(int wid) {
}
return 0;
}
int uwsgi_master_check_cron_death(int diedpid) {
struct uwsgi_cron *uc = uwsgi.crons;
while (uc) {
if (uc->pid == (pid_t) diedpid) {
uwsgi_log("[uwsgi-cron] command \"%s\" running with pid %d exited after %d second(s)\n", uc->command, uc->pid, uwsgi_now() - uc->started_at);
uc->pid = -1;
uc->started_at = 0;
return -1;
}
uc = uc->next;
}
return 0;
}
void uwsgi_master_check_crons_deadline() {
struct uwsgi_cron *uc = uwsgi.crons;
while (uc) {
if (uc->pid >= 0 && uc->harakiri > 0 && uc->harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON CRON \"%s\" (pid: %d) ***\n", uc->command, uc->pid);
kill(-uc->pid, SIGKILL);
}
uc = uc->next;
}
}
+80 -3
View File
@@ -388,6 +388,12 @@ void uwsgi_reload(char **argv) {
}
}
if (uwsgi.alarm_thread) {
if (i == uwsgi.alarm_thread->queue) continue;
if (i == uwsgi.alarm_thread->pipe[0]) continue;
if (i == uwsgi.alarm_thread->pipe[1]) continue;
}
if (uwsgi.log_master) {
if (uwsgi.original_log_fd > -1) {
if (i == uwsgi.original_log_fd) {
@@ -690,11 +696,20 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
while (ud) {
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keyval_comma(us, "cmd", ud->command))
// allocate 2x the size of original command
// in case we need to escape all chars
char *cmd = uwsgi_malloc(strlen(ud->command)*2);
escape_json(ud->command, strlen(ud->command), cmd);
if (uwsgi_stats_keyval_comma(us, "cmd", cmd)) {
free(cmd);
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) ud->pid))
}
free(cmd);
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;
@@ -1073,6 +1088,68 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
}
struct uwsgi_cron *ucron = uwsgi.crons;
if (ucron) {
if (uwsgi_stats_comma(us))
goto end;
if (uwsgi_stats_key(us, "crons"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
while (ucron) {
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keyslong_comma(us, "minute", (long long) ucron->minute))
goto end;
if (uwsgi_stats_keyslong_comma(us, "hour", (long long) ucron->hour))
goto end;
if (uwsgi_stats_keyslong_comma(us, "day", (long long) ucron->day))
goto end;
if (uwsgi_stats_keyslong_comma(us, "month", (long long) ucron->month))
goto end;
if (uwsgi_stats_keyslong_comma(us, "week", (long long) ucron->week))
goto end;
char *cmd = uwsgi_malloc(strlen(ucron->command)*2);
escape_json(ucron->command, strlen(ucron->command), cmd);
if (uwsgi_stats_keyval_comma(us, "command", cmd)) {
free(cmd);
goto end;
}
free(cmd);
if (uwsgi_stats_keylong_comma(us, "unique", (unsigned long long) ucron->unique))
goto end;
#ifdef UWSGI_SSL
if (uwsgi_stats_keyval_comma(us, "legion", ucron->legion ? ucron->legion : ""))
goto end;
#endif
if (uwsgi_stats_keyslong_comma(us, "pid", (long long) ucron->pid))
goto end;
if (uwsgi_stats_keylong(us, "started_at", (unsigned long long) ucron->started_at))
goto end;
if (uwsgi_stats_object_close(us))
goto end;
ucron = ucron->next;
if (ucron) {
if (uwsgi_stats_comma(us))
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end;
}
#ifdef UWSGI_SSL
struct uwsgi_legion *legion = NULL;
if (uwsgi.legions) {
+23 -17
View File
@@ -77,19 +77,8 @@ void uwsgi_mule(int id) {
}
}
uwsgi_mule_run();
if (uwsgi.mules[id - 1].patch) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->mule) {
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
// never here ?
end_me(1);
}
}
}
}
uwsgi_mule_handler();
}
else if (pid > 0) {
uwsgi.mules[id - 1].id = id;
@@ -98,6 +87,23 @@ void uwsgi_mule(int id) {
}
}
void uwsgi_mule_run() {
int id = uwsgi.muleid;
int i;
if (uwsgi.mules[id - 1].patch) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->mule) {
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
// never here ?
end_me(1);
}
}
}
}
uwsgi_mule_handler();
}
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
struct uwsgi_mule_farm *umf = farm->mules;
@@ -410,12 +416,12 @@ void uwsgi_setup_mules_and_farms() {
uwsgi.mules = (struct uwsgi_mule *) uwsgi_calloc_shared(sizeof(struct uwsgi_mule) * uwsgi.mules_cnt);
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
create_signal_pipe(uwsgi.shared->mule_queue_pipe);
create_msg_pipe(uwsgi.shared->mule_queue_pipe, uwsgi.mule_msg_size);
for (i = 0; i < uwsgi.mules_cnt; i++) {
// create the socket pipe
create_signal_pipe(uwsgi.mules[i].signal_pipe);
create_signal_pipe(uwsgi.mules[i].queue_pipe);
create_msg_pipe(uwsgi.mules[i].queue_pipe, uwsgi.mule_msg_size);
uwsgi.mules[i].id = i + 1;
@@ -441,11 +447,11 @@ 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);
create_signal_pipe(uwsgi.farms[i].queue_pipe);
create_msg_pipe(uwsgi.farms[i].queue_pipe, uwsgi.mule_msg_size);
char *p = strtok(mules_list, ",");
while (p != NULL) {
@@ -462,7 +468,7 @@ void uwsgi_setup_mules_and_farms() {
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
farm_name = farm_name->next;
free(farm_value);
}
}
+150 -1
View File
@@ -58,6 +58,39 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
return 0;
}
/*
pipe offload engine:
fd -> the file descriptor to read from
len -> amount of data to transfer
*/
static int u_offload_pipe_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
if (uor->fd < 0 || !uor->len) {
return -1;
}
return 0;
}
/*
memory offload engine:
buf -> pointer to the memory to transfer (memory is freed at the end)
len -> amount of data to transfer
*/
static int u_offload_memory_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
if (!uor->buf || !uor->len) {
return -1;
}
return 0;
}
/*
transfer offload engine:
@@ -66,7 +99,7 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
*/
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
static int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
if (!uor->name) {
return -1;
@@ -240,6 +273,39 @@ struct uwsgi_thread *uwsgi_offload_thread_start() {
return uwsgi_thread_new(uwsgi_offload_loop);
}
/*
offload memory transfer
uor->len -> the size of the memory chunk
uor->buf -> the memory to transfer
uor->written -> written bytes
status: none
*/
static int u_offload_memory_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
if (fd == -1) {
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
return 0;
}
ssize_t rlen = write(uor->s, uor->buf + uor->written, uor->len - uor->written);
if (rlen > 0) {
uor->written += rlen;
if (uor->written >= uor->len) {
return -1;
}
return 0;
}
else if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("u_offload_memory_do()");
}
return -1;
}
/*
the offload task starts after having acquired the file fd
@@ -293,6 +359,71 @@ static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
}
/*
pipe offloading
status:
0 -> waiting for data on fd
1 -> waiting for write to s
*/
static int u_offload_pipe_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
ssize_t rlen;
// setup
if (fd == -1) {
event_queue_add_fd_read(ut->queue, uor->fd);
return 0;
}
switch(uor->status) {
// read event from fd
case 0:
if (!uor->buf) {
uor->buf = uwsgi_malloc(4096);
}
rlen = read(uor->fd, uor->buf, 4096);
if (rlen > 0) {
uor->to_write = rlen;
uor->pos = 0;
if (event_queue_del_fd(ut->queue, uor->fd, event_queue_read())) return -1;
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
uor->status = 1;
return 0;
}
if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("u_offload_pipe_do() -> read()");
}
return -1;
// write event on s
case 1:
rlen = write(uor->s, uor->buf + uor->pos, uor->to_write);
if (rlen > 0) {
uor->to_write -= rlen;
uor->pos += rlen;
if (uor->to_write == 0) {
if (event_queue_del_fd(ut->queue, uor->s, event_queue_write())) return -1;
if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1;
uor->status = 0;
}
return 0;
}
else if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("u_offload_pipe_do() -> write()");
}
return -1;
default:
break;
}
return -1;
}
/*
the offload task starts soon after the call to connect()
@@ -490,6 +621,8 @@ struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*pre
void uwsgi_offload_engines_register_all() {
uwsgi.offload_engine_sendfile = uwsgi_offload_register_engine("sendfile", u_offload_sendfile_prepare, u_offload_sendfile_do);
uwsgi.offload_engine_transfer = uwsgi_offload_register_engine("transfer", u_offload_transfer_prepare, u_offload_transfer_do);
uwsgi.offload_engine_memory = uwsgi_offload_register_engine("memory", u_offload_memory_prepare, u_offload_memory_do);
uwsgi.offload_engine_pipe = uwsgi_offload_register_engine("pipe", u_offload_pipe_prepare, u_offload_pipe_do);
}
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
@@ -507,3 +640,19 @@ int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname
uor.ubuf = ubuf;
return uwsgi_offload_run(wsgi_req, &uor, NULL);
}
int uwsgi_offload_request_memory_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
struct uwsgi_offload_request uor;
uwsgi_offload_setup(uwsgi.offload_engine_memory, &uor, wsgi_req, 1);
uor.buf = buf;
uor.len = len;
return uwsgi_offload_run(wsgi_req, &uor, NULL);
}
int uwsgi_offload_request_pipe_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
struct uwsgi_offload_request uor;
uwsgi_offload_setup(uwsgi.offload_engine_pipe, &uor, wsgi_req, 1);
uor.fd = fd;
uor.len = len;
return uwsgi_offload_run(wsgi_req, &uor, NULL);
}
+2 -2
View File
@@ -478,9 +478,9 @@ int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
int upload_progress_fd = -1;
char *upload_progress_filename = NULL;
wsgi_req->post_file = tmpfile();
wsgi_req->post_file = uwsgi_tmpfile();
if (!wsgi_req->post_file) {
uwsgi_error("uwsgi_postbuffer_do_in_disk()/tmpfile()");
uwsgi_error("uwsgi_postbuffer_do_in_disk()/uwsgi_tmpfile()");
return -1;
}
+336 -78
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,28 +150,50 @@ error:
return NULL;
}
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
static void uwsgi_routing_reset_memory(struct wsgi_request *wsgi_req, struct uwsgi_route *routes) {
// free dynamic memory structures
if (routes->if_func) {
routes->ovn[wsgi_req->async_id] = 0;
if (routes->ovector[wsgi_req->async_id]) {
free(routes->ovector[wsgi_req->async_id]);
routes->ovector[wsgi_req->async_id] = NULL;
}
if (routes->condition_ub[wsgi_req->async_id]) {
uwsgi_buffer_destroy(routes->condition_ub[wsgi_req->async_id]);
routes->condition_ub[wsgi_req->async_id] = NULL;
}
}
}
int uwsgi_apply_routes_do(struct uwsgi_route *routes, struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
struct uwsgi_route *routes = uwsgi.routes;
void *goon_func = NULL;
int n = -1;
char *orig_subject = subject;
uint16_t orig_subject_len = subject_len;
uint32_t *r_goto = &wsgi_req->route_goto;
uint32_t *r_pc = &wsgi_req->route_pc;
if (routes == uwsgi.error_routes) {
r_goto = &wsgi_req->error_route_goto;
r_pc = &wsgi_req->error_route_pc;
}
else if (routes == uwsgi.final_routes) {
r_goto = &wsgi_req->final_route_goto;
r_pc = &wsgi_req->final_route_pc;
}
while (routes) {
if (routes->label) goto next;
if (wsgi_req->route_goto > 0 && wsgi_req->route_pc < wsgi_req->route_goto) {
if (*r_goto > 0 && *r_pc < *r_goto) {
goto next;
}
if (goon_func && goon_func == routes->func) {
goto next;
}
goon_func = NULL;
wsgi_req->route_goto = 0;
*r_goto = 0;
if (!routes->if_func) {
// could be a "run"
@@ -181,23 +207,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 +237,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 +247,6 @@ run:
return ret;
}
if (ret == UWSGI_ROUTE_GOON) {
goon_func = routes->func;
}
if (ret == -1) {
return UWSGI_ROUTE_BREAK;
}
@@ -229,7 +255,7 @@ next:
subject = orig_subject;
subject_len = orig_subject_len;
routes = routes->next;
if (routes) wsgi_req->route_pc++;
if (routes) *r_pc = *r_pc+1;
}
return UWSGI_ROUTE_CONTINUE;
@@ -253,9 +279,34 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
return UWSGI_ROUTE_CONTINUE;
}
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
return uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0);
}
void uwsgi_apply_final_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.final_routes) return;
// avoid loops
if (wsgi_req->is_routing) return;
wsgi_req->is_final_routing = 1;
uwsgi_apply_routes_do(uwsgi.final_routes, wsgi_req, NULL, 0);
}
int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.error_routes) return 0;
// do not forget to check it !!!
if (wsgi_req->is_error_routing) return 0;
wsgi_req->is_error_routing = 1;
return uwsgi_apply_routes_do(uwsgi.error_routes, wsgi_req, NULL, 0);
}
static void *uwsgi_route_get_condition_func(char *name) {
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
while(urc) {
@@ -267,11 +318,25 @@ static void *uwsgi_route_get_condition_func(char *name) {
return NULL;
}
static int uwsgi_route_condition_status(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
if (wsgi_req->status == ur->if_status) {
return 1;
}
return 0;
}
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
char *space = NULL;
char *command = NULL;
struct uwsgi_route *old_ur = NULL,*ur = uwsgi.routes;
struct uwsgi_route *old_ur = NULL, *ur = uwsgi.routes;
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
ur = uwsgi.final_routes;
}
else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) {
ur = uwsgi.error_routes;
}
uint64_t pos = 0;
while(ur) {
old_ur = ur;
@@ -283,7 +348,15 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
old_ur->next = ur;
}
else {
uwsgi.routes = ur;
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
uwsgi.final_routes = ur;
}
else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) {
uwsgi.error_routes = ur;
}
else {
uwsgi.routes = ur;
}
}
ur->pos = pos;
@@ -295,14 +368,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 +384,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,12 +396,17 @@ 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);
}
}
else if (!strcmp(foobar, "status")) {
ur->if_status = atoi(ur->orig_route);
foobar = ur->orig_route;
ur->if_func = uwsgi_route_condition_status;
}
else if (!strcmp(foobar, "http_host")) {
ur->subject = offsetof(struct wsgi_request, host);
@@ -365,18 +443,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 +461,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 +472,31 @@ done:
exit(1);
}
void uwsgi_fixup_routes(struct uwsgi_route *ur) {
while(ur) {
// prepare the main pointers
ur->ovn = uwsgi_calloc(sizeof(int) * uwsgi.cores);
ur->ovector = uwsgi_calloc(sizeof(int *) * uwsgi.cores);
ur->condition_ub = uwsgi_calloc( sizeof(struct uwsgi_buffer *) * uwsgi.cores);
// fill them if needed... (this is an optimization for route with a static subject)
if (ur->subject && ur->subject_len) {
if (uwsgi_regexp_build(ur->orig_route, &ur->pattern, &ur->pattern_extra)) {
exit(1);
}
int i;
for(i=0;i<uwsgi.cores;i++) {
ur->ovn[i] = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
if (ur->ovn[i] > 0) {
ur->ovector[i] = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn[i] + 1)));
}
}
}
ur = ur->next;
}
}
int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args) {
struct uwsgi_route *ur = NULL;
struct uwsgi_router *r = uwsgi.routers;
@@ -476,30 +558,36 @@ 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;
// harakiri router
static int uwsgi_router_harakiri_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
if (route->custom > 0) {
set_user_harakiri(route->custom);
}
return UWSGI_ROUTE_CONTINUE;
}
static int uwsgi_router_goon(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_goon_func;
static int uwsgi_router_harakiri(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_harakiri_func;
ur->custom = atoi(arg);
return 0;
}
// flush response
static int transform_flush(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **foobar, void *data) {
wsgi_req->flush = 1;
return uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
return 0;
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_flush_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
// if there are no transformations defined, set the flush right now
if (!wsgi_req->transformations) {
wsgi_req->flush = 1;
}
else {
// otherwise push it in the chain
uwsgi_add_transformation(wsgi_req, transform_flush, NULL);
}
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) {
@@ -507,6 +595,28 @@ static int uwsgi_router_flush(struct uwsgi_route *ur, char *arg) {
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) {
@@ -528,6 +638,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) {
@@ -566,25 +686,37 @@ static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_ro
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint32_t *r_goto = &wsgi_req->route_goto;
uint32_t *r_pc = &wsgi_req->route_pc;
// find the label
struct uwsgi_route *routes = uwsgi.routes;
if (wsgi_req->is_error_routing) {
routes = uwsgi.error_routes;
r_goto = &wsgi_req->error_route_goto;
r_pc = &wsgi_req->error_route_pc;
}
else if (wsgi_req->is_final_routing) {
routes = uwsgi.final_routes;
r_goto = &wsgi_req->final_route_goto;
r_pc = &wsgi_req->final_route_pc;
}
while(routes) {
if (!routes->label) goto next;
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
wsgi_req->route_goto = routes->pos;
*r_goto = routes->pos;
goto found;
}
next:
routes = routes->next;
}
wsgi_req->route_goto = ur->custom;
*r_goto = ur->custom;
found:
uwsgi_buffer_destroy(ub);
if (wsgi_req->route_goto <= wsgi_req->route_pc) {
wsgi_req->route_goto = 0;
if (*r_goto <= *r_pc) {
*r_goto = 0;
uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
return UWSGI_ROUTE_BREAK;
}
@@ -733,6 +865,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);
@@ -881,21 +1069,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);
@@ -905,7 +1097,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);
@@ -1125,7 +1316,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);
@@ -1184,6 +1375,19 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
ret = uwsgi_num2str(uwsgi.mypid);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) {
ret = uwsgi_malloc(37);
uwsgi_uuid(ret);
*vallen = 36;
}
else if (!uwsgi_strncmp(key, keylen, "status", 6)) {
ret = uwsgi_num2str(wsgi_req->status);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "rtime", 5)) {
ret = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
*vallen = strlen(ret);
}
return ret;
}
@@ -1200,6 +1404,19 @@ static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint
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;
@@ -1280,8 +1497,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);
@@ -1293,12 +1510,17 @@ 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_router("harakiri", uwsgi_router_harakiri);
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
@@ -1336,6 +1558,8 @@ void uwsgi_register_embedded_routers() {
urv->need_free = 1;
urv = uwsgi_register_route_var("time", uwsgi_route_var_time);
urv->need_free = 1;
urv = uwsgi_register_route_var("httptime", uwsgi_route_var_httptime);
urv->need_free = 1;
#ifdef UWSGI_MATHEVAL
urv = uwsgi_register_route_var("math", uwsgi_route_var_math);
urv->need_free = 1;
@@ -1397,7 +1621,7 @@ struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*f
void uwsgi_routing_dump() {
struct uwsgi_route *routes = uwsgi.routes;
if (!routes) return;
if (!routes) goto next;
uwsgi_log("*** dumping internal routing table ***\n");
while(routes) {
if (routes->label) {
@@ -1412,5 +1636,39 @@ void uwsgi_routing_dump() {
routes = routes->next;
}
uwsgi_log("*** end of the internal routing table ***\n");
next:
routes = uwsgi.error_routes;
if (!routes) goto next2;
uwsgi_log("*** dumping internal error routing table ***\n");
while(routes) {
if (routes->label) {
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
}
else if (!routes->subject_str && !routes->if_func) {
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
}
else {
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
}
routes = routes->next;
}
uwsgi_log("*** end of the internal error routing table ***\n");
next2:
routes = uwsgi.final_routes;
if (!routes) return;
uwsgi_log("*** dumping internal final routing table ***\n");
while(routes) {
if (routes->label) {
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
}
else if (!routes->subject_str && !routes->if_func) {
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
}
else {
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
}
routes = routes->next;
}
uwsgi_log("*** end of the internal final routing table ***\n");
}
#endif
+36
View File
@@ -37,3 +37,39 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
#endif
}
/*
simple non blocking sendfile implementation
(generally used as fallback)
*/
int uwsgi_simple_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
wsgi_req->write_pos = 0;
for(;;) {
int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
if (ret < 0) {
if (!uwsgi.ignore_write_errors) {
uwsgi_error("uwsgi_simple_sendfile()");
}
wsgi_req->write_errors++;
return -1;
}
if (ret == UWSGI_OK) {
break;
}
ret = uwsgi_wait_write_req(wsgi_req);
if (ret < 0) {
wsgi_req->write_errors++;
return -1;
}
if (ret == 0) {
uwsgi_log("uwsgi_simple_sendfile() TIMEOUT !!!\n");
wsgi_req->write_errors++;
return -1;
}
}
return 0;
}
+4 -1
View File
@@ -99,7 +99,10 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
struct uwsgi_signal_entry *use = NULL;
if (!uwsgi.master_process) return -1;
if (!uwsgi.master_process) {
uwsgi_log("you cannot register signals without a master\n");
return -1;
}
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
uwsgi_log("only the master and the workers can register signal handlers\n");
+72 -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, '*');
@@ -1508,6 +1552,9 @@ void uwsgi_setup_shared_sockets() {
shared_sock->fd = bind_to_unix(shared_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
shared_sock->family = AF_UNIX;
uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
if (uwsgi.chown_socket) {
uwsgi_chown(shared_sock->name, uwsgi.chown_socket);
}
}
else {
#ifdef AF_INET6
+21 -15
View File
@@ -122,21 +122,7 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
}
}
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->spooler_init) {
uwsgi.p[i]->spooler_init();
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->spooler_init) {
uwsgi.gp[i]->spooler_init();
}
}
spooler(uspool);
uwsgi_spooler_run();
}
else if (pid > 0) {
uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid);
@@ -145,6 +131,26 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
return pid;
}
void uwsgi_spooler_run() {
int i;
struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler;
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->spooler_init) {
uwsgi.p[i]->spooler_init();
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->spooler_init) {
uwsgi.gp[i]->spooler_init();
}
}
spooler(uspool);
}
void destroy_spool(char *dir, char *file) {
if (chdir(dir)) {
+13 -2
View File
@@ -1,5 +1,7 @@
#include "../uwsgi.h"
#include <uwsgi.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
extern struct uwsgi_server uwsgi;
/*
@@ -412,8 +414,9 @@ char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
}
char *uwsgi_ssl_rand(size_t len) {
unsigned char *buf = uwsgi_calloc(len+1);
unsigned char *buf = uwsgi_calloc(len);
if (RAND_bytes(buf, len) <= 0) {
free(buf);
return NULL;
}
return (char *) buf;
@@ -427,6 +430,14 @@ char *uwsgi_sha1(char *src, size_t len, char *dst) {
return dst;
}
char *uwsgi_md5(char *src, size_t len, char *dst) {
MD5_CTX md5;
MD5_Init(&md5);
MD5_Update(&md5, src, len);
MD5_Final((unsigned char *)dst, &md5);
return dst;
}
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
SHA_CTX sha;
SHA1_Init(&sha);
+12 -11
View File
@@ -2,9 +2,9 @@
extern struct uwsgi_server uwsgi;
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t filename_len, struct stat *st) {
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st) {
// check for filename size
if (filename_len + 4 > PATH_MAX) return 0;
if (*filename_len + 4 > PATH_MAX) return 0;
// check for supported encodings
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
@@ -14,7 +14,7 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
// check for dirs/prefix
struct uwsgi_string_list *usl = uwsgi.static_gzip_dir;
while(usl) {
if (!uwsgi_starts_with(filename, filename_len, usl->value, usl->len)) {
if (!uwsgi_starts_with(filename, *filename_len, usl->value, usl->len)) {
goto gzip;
}
usl = usl->next;
@@ -23,7 +23,7 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
// check for ext/suffix
usl = uwsgi.static_gzip_ext;
while(usl) {
if (!uwsgi_strncmp(filename + (filename_len - usl->len), usl->len, usl->value, usl->len)) {
if (!uwsgi_strncmp(filename + (*filename_len - usl->len), usl->len, usl->value, usl->len)) {
goto gzip;
}
usl = usl->next;
@@ -33,7 +33,7 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
// check for regexp
struct uwsgi_regexp_list *url = uwsgi.static_gzip;
while(url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, filename_len) >= 0) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, *filename_len) >= 0) {
goto gzip;
}
url = url->next;
@@ -43,12 +43,12 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
gzip:
memcpy(filename + filename_len, ".gz\0", 4);
filename_len += 3;
memcpy(filename + *filename_len, ".gz\0", 4);
*filename_len += 3;
if (stat(filename, st)) {
filename_len -= 3;
filename[filename_len] = 0;
*filename_len -= 3;
filename[*filename_len] = 0;
return 0;
}
@@ -445,7 +445,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
// 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 (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);
@@ -579,6 +579,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
if (item && item_len > 0 && item_len <= PATH_MAX) {
memcpy(real_filename, item, item_len);
real_filename_len = item_len;
real_filename[real_filename_len] = 0;
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
goto found;
}
@@ -644,7 +645,7 @@ safe:
#ifdef UWSGI_ROUTING
// before sending the file, we need to check if some rule applies
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
return 0;
}
wsgi_req->routes_applied = 1;
+120 -23
View File
@@ -4,10 +4,11 @@
uWSGI transformations
responses can be buffered in the wsgi_request structure (instead of being sent to the client)
Before closing the request, the transformations are applied in chain to the response buffer
each body chunk is passed (in chain) to every transformation
Finally the resulting buffer is sent to the client
some of them supports streaming, other requires buffering
at the end of the request the "final chain" is called (and the whole chain freed)
Transformations (if required) could completely swallow already set headers
@@ -15,42 +16,143 @@
extern struct uwsgi_server uwsgi;
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req) {
int ret = 0;
// -1 error, 0 = no buffer, send the body, 1 = buffer
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *buf, size_t len) {
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
struct uwsgi_transformation *ut = wsgi_req->transformations;
char *t_buf = buf;
size_t t_len = len;
uint8_t flushed = 0;
while(ut) {
struct uwsgi_buffer *new_ub = NULL;
if (ut->func(wsgi_req, wsgi_req->response_buffer, &new_ub, ut->data)) {
ret = -1;
goto end;
// allocate the buffer (if needed)
if (!ut->chunk) {
ut->chunk = uwsgi_buffer_new(t_len);
}
if (new_ub) {
uwsgi_buffer_destroy(wsgi_req->response_buffer);
wsgi_req->response_buffer = new_ub;
// skip final transformations before appending data
if (ut->is_final) goto next;
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
return -1;
}
// if the transformation cannot stream, continue buffering (the func will be called at the end)
if (!ut->can_stream) return 1;
ut->round++;
if (ut->func(wsgi_req, ut)) {
return -1;
}
if (ut->flushed) flushed = 1;
t_buf = ut->chunk->buf;
t_len = ut->chunk->pos;
// we reset the buffer, so we do not waste memory
ut->chunk->pos = 0;
next:
ut = ut->next;
}
end:
ut = wsgi_req->transformations;
// if we are here we can tell the writer to send the body to the client
// no buffering please
if (!flushed) {
wsgi_req->transformed_chunk = t_buf;
wsgi_req->transformed_chunk_len = t_len;
}
return 0;
}
/*
run all the remaining (or buffered) transformations
*/
int uwsgi_apply_final_transformations(struct wsgi_request *wsgi_req) {
struct uwsgi_transformation *ut = wsgi_req->transformations;
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
char *t_buf = NULL;
size_t t_len = 0;
uint8_t flushed = 0;
int found_nostream = 0;
while(ut) {
if (!found_nostream) {
if (!ut->can_stream) {
found_nostream = 1;
}
else {
t_buf = ut->chunk->buf;
t_len = ut->chunk->pos;
goto next;
}
}
if (!ut->chunk) {
if (t_len > 0) {
ut->chunk = uwsgi_buffer_new(t_len);
}
else {
ut->chunk = uwsgi_buffer_new(uwsgi.page_size);
}
}
if (t_len > 0) {
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
return -1;
}
}
// run the transformation
ut->round++;
if (ut->func(wsgi_req, ut)) {
return -1;
}
if (ut->flushed) flushed = 1;
t_buf = ut->chunk->buf;
t_len = ut->chunk->pos;
next:
ut = ut->next;
}
// if we are here, all of the transformations are applied
if (!flushed) {
wsgi_req->transformed_chunk = t_buf;
wsgi_req->transformed_chunk_len = t_len;
}
return 0;
}
void uwsgi_free_transformations(struct wsgi_request *wsgi_req) {
struct uwsgi_transformation *ut = wsgi_req->transformations;
while(ut) {
struct uwsgi_transformation *current_ut = ut;
if (current_ut->chunk) {
uwsgi_buffer_destroy(current_ut->chunk);
}
if (current_ut->ub) {
uwsgi_buffer_destroy(current_ut->ub);
}
if (current_ut->fd > -1) {
close(current_ut->fd);
}
ut = ut->next;
free(current_ut);
}
return ret;
}
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_buffer *, struct uwsgi_buffer **, void *), void *data) {
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *data) {
struct uwsgi_transformation *old_ut = NULL, *ut = wsgi_req->transformations;
while(ut) {
old_ut = ut;
ut = ut->next;
}
ut = uwsgi_malloc(sizeof(struct uwsgi_transformation));
ut = uwsgi_calloc(sizeof(struct uwsgi_transformation));
ut->func = func;
ut->next = NULL;
ut->fd = -1;
ut->data = data;
if (old_ut) {
@@ -60,10 +162,5 @@ struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_
wsgi_req->transformations = ut;
}
// start buffering
if (!wsgi_req->response_buffer) {
wsgi_req->response_buffer = uwsgi_buffer_new(uwsgi.page_size);
}
return ut;
}
+182 -57
View File
@@ -206,14 +206,20 @@ void uwsgi_set_cgroup() {
usl = uwsgi.cgroup;
while (usl) {
if (mkdir(usl->value, 0700)) {
uwsgi_log("using Linux cgroup %s\n", usl->value);
int mode = strtol(uwsgi.cgroup_dir_mode, 0, 8);
if (mkdir(usl->value, mode)) {
if (errno != EEXIST) {
uwsgi_error("mkdir()");
exit(1);
}
if (chmod(usl->value, mode)) {
uwsgi_error("chmod()");
exit(1);
}
uwsgi_log("using Linux cgroup %s with mode %o\n", usl->value, mode);
}
else {
uwsgi_log("created Linux cgroup %s\n", usl->value);
uwsgi_log("created Linux cgroup %s with mode %o\n", usl->value, mode);
}
cgroup_taskfile = uwsgi_concat2(usl->value, "/tasks");
@@ -574,23 +580,14 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
int tmp_id;
uint64_t tmp_rt, rss = 0, vsz = 0;
// flush the response buf (if any)
if (wsgi_req->response_buffer) {
// send the body only if transformations are successfull
struct uwsgi_buffer *ub = wsgi_req->response_buffer;
if (uwsgi_apply_transformations(wsgi_req) == 0) {
// the response_buffer could be changed by translations
ub = wsgi_req->response_buffer;
// force true write (take flushing into account)
wsgi_req->response_buffer = NULL;
if (wsgi_req->response_size == 0) {
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
// apply transformations
if (wsgi_req->transformations) {
if (uwsgi_apply_final_transformations(wsgi_req) == 0) {
if (wsgi_req->transformed_chunk && wsgi_req->transformed_chunk_len > 0) {
uwsgi_response_write_body_do(wsgi_req, wsgi_req->transformed_chunk, wsgi_req->transformed_chunk_len);
}
}
else {
wsgi_req->write_errors++;
}
uwsgi_buffer_destroy(ub);
uwsgi_free_transformations(wsgi_req);
}
// check if headers should be sent
@@ -616,6 +613,20 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uwsgi.workers[uwsgi.mywid].rss_size = rss;
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
// this is used for MAX_REQUESTS
uwsgi.workers[uwsgi.mywid].delta_requests++;
}
#ifdef UWSGI_ROUTING
// apply final routes after accounting
uwsgi_apply_final_routes(wsgi_req);
#endif
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
@@ -638,15 +649,6 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
free(wsgi_req->proto_parser_buf);
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
// this is used for MAX_REQUESTS
uwsgi.workers[uwsgi.mywid].delta_requests++;
}
// after_request hook
if (uwsgi.p[wsgi_req->uh->modifier1]->after_request)
uwsgi.p[wsgi_req->uh->modifier1]->after_request(wsgi_req);
@@ -666,12 +668,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
@@ -1148,7 +1152,7 @@ int uwsgi_get_app_id(struct wsgi_request *wsgi_req, char *key, uint16_t key_len,
char *app_name = key;
uint16_t app_name_len = key_len;
if (!app_name && wsgi_req) {
if (app_name_len == 0 && wsgi_req) {
app_name = wsgi_req->appid;
app_name_len = wsgi_req->appid_len;
if (app_name_len == 0) {
@@ -1210,11 +1214,7 @@ int uwsgi_get_app_id(struct wsgi_request *wsgi_req, char *key, uint16_t key_len,
}
}
if (!uwsgi.no_default_app) {
if (free_appname) free(app_name);
return uwsgi.default_app;
}
if (free_appname) free(app_name);
return -1;
}
@@ -1810,18 +1810,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);
@@ -1830,6 +1833,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);
@@ -2223,6 +2232,7 @@ struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **list,
uwsgi_string->next = NULL;
uwsgi_string->custom = 0;
uwsgi_string->custom2 = 0;
uwsgi_string->custom_ptr = NULL;
return uwsgi_string;
}
@@ -3055,6 +3065,36 @@ void escape_shell_arg(char *src, size_t len, char *dst) {
*ptr++ = 0;
}
void escape_json(char *src, size_t len, char *dst) {
size_t i;
char *ptr = dst;
for (i = 0; i < len; i++) {
if (src[i] == '\t') {
*ptr++ = '\\';
*ptr++ = 't';
}
else if (src[i] == '\n') {
*ptr++ = '\\';
*ptr++ = 'n';
}
else if (src[i] == '\r') {
*ptr++ = '\\';
*ptr++ = 'r';
}
else if (src[i] == '"') {
*ptr++ = '\\';
*ptr++ = '"';
}
else {
*ptr++ = src[i];
}
}
*ptr++ = 0;
}
void http_url_decode(char *buf, uint16_t * len, char *dst) {
uint16_t i;
@@ -3100,6 +3140,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
*/
@@ -3143,6 +3184,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;
}
@@ -3162,7 +3207,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);
@@ -3177,14 +3222,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;
}
@@ -3206,14 +3251,22 @@ char *uwsgi_chomp(char *str) {
return str;
}
char *uwsgi_tmpname(char *base, char *id) {
char *template = uwsgi_concat3(base, "/", id);
if (mkstemp(template) < 0) {
free(template);
return NULL;
int uwsgi_tmpfd() {
char *tmpdir = getenv("TMPDIR");
if (!tmpdir) {
tmpdir = "/tmp";
}
char *template = uwsgi_concat2(tmpdir, "/uwsgiXXXXXX");
int fd = mkstemp(template);
unlink(template);
free(template);
return fd;
}
return template;
FILE *uwsgi_tmpfile() {
int fd = uwsgi_tmpfd();
if (fd < 0) return NULL;
return fdopen(fd, "w+");
}
int uwsgi_file_to_string_list(char *filename, struct uwsgi_string_list **list) {
@@ -3907,3 +3960,75 @@ char *uwsgi_str_to_hex(char *src, size_t slen) {
}
return dst;
}
// dst has to be 3 times buf size (USE IT ONLY FOR PATH_INFO !!!)
void http_url_encode(char *buf, uint16_t *len, char *dst) {
uint16_t i;
char *ptr = dst;
for(i=0;i<*len;i++) {
if ((buf[i] >= 'A' && buf[i] <= 'Z') ||
(buf[i] >= 'a' && buf[i] <= 'z') ||
(buf[i] >= '0' && buf[i] <= '9') ||
buf[i] == '-' || buf[i] == '_' || buf[i] == '.' || buf[i] == '~' || buf[i] == '/' ) {
*ptr++= buf[i];
}
else {
char *h = uwsgi_hex_table[(int) buf[i]];
*ptr++= '%';
*ptr++= h[0];
*ptr++= h[1];
}
}
*len = ptr-dst;
}
void uwsgi_takeover() {
if (uwsgi.i_am_a_spooler) {
uwsgi_spooler_run();
}
else if (uwsgi.muleid) {
uwsgi_mule_run();
}
else {
uwsgi_worker_run();
}
}
// create a message pipe
void create_msg_pipe(int *fd, int bufsize) {
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd)) {
#else
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fd)) {
#endif
uwsgi_error("create_msg_pipe()/socketpair()");
exit(1);
}
uwsgi_socket_nb(fd[0]);
uwsgi_socket_nb(fd[1]);
if (bufsize) {
if (setsockopt(fd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int))) {
uwsgi_error("create_msg_pipe()/setsockopt()");
}
if (setsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int))) {
uwsgi_error("create_msg_pipe()/setsockopt()");
}
if (setsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int))) {
uwsgi_error("create_msg_pipe()/setsockopt()");
}
if (setsockopt(fd[1], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int))) {
uwsgi_error("create_msg_pipe()/setsockopt()");
}
}
}
char *uwsgi_binary_path() {
return uwsgi.binary_path ? uwsgi.binary_path : "uwsgi";
}
+101 -17
View File
@@ -65,7 +65,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"no-harakiri-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"no-harakiri-after-req-hook", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"backtrace-depth", no_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
{"backtrace-depth", required_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
{"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MULE_HARAKIRI, 0},
#ifdef UWSGI_XML
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
@@ -206,6 +206,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"help", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
{"usage", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
{"print-sym", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
{"print-symbol", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
{"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_REAPER, 0},
{"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MAX_REQUESTS, 0},
{"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 60)", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MIN_WORKER_LIFETIME, 0},
@@ -258,6 +261,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"mule", optional_argument, 0, "add a mule", uwsgi_opt_add_mule, NULL, UWSGI_OPT_MASTER},
{"mules", required_argument, 0, "add the specified number of mules", uwsgi_opt_add_mules, NULL, UWSGI_OPT_MASTER},
{"farm", required_argument, 0, "add a mule farm", uwsgi_opt_add_farm, NULL, UWSGI_OPT_MASTER},
{"mule-msg-size", optional_argument, 0, "set mule message buffer size", uwsgi_opt_set_int, &uwsgi.mule_msg_size, UWSGI_OPT_MASTER},
{"signal", required_argument, 0, "send a uwsgi signal to a server", uwsgi_opt_signal, NULL, UWSGI_OPT_IMMEDIATE},
{"signal-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0},
@@ -344,6 +348,8 @@ 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},
{"touch-signal", required_argument, 0, "signal when the specified file is modified/touched (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.touch_signal, 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},
@@ -413,7 +419,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"ssl-verbose", no_argument, 0, "be verbose about SSL errors", uwsgi_opt_true, &uwsgi.ssl_verbose, 0},
// force master, as ssl sessions caching initialize locking early
{"ssl-sessions-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
{"ssl-session-use-cache", no_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_true, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
{"ssl-session-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
{"ssl-sessions-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0},
{"ssl-session-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0},
{"sni", required_argument, 0, "add an SNI-governed SSL context", uwsgi_opt_sni, NULL, 0},
@@ -457,6 +463,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
{"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
#ifdef UWSGI_PCRE
{"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
@@ -528,6 +536,37 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0},
{"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0},
{"final-route", required_argument, 0, "add a final route", uwsgi_opt_add_route, "path_info", 0},
{"final-route-status", required_argument, 0, "add a final route for the specified status", uwsgi_opt_add_route, "status", 0},
{"final-route-host", required_argument, 0, "add a final route based on Host header", uwsgi_opt_add_route, "http_host", 0},
{"final-route-uri", required_argument, 0, "add a final route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
{"final-route-qs", required_argument, 0, "add a final route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
{"final-route-remote-addr", required_argument, 0, "add a final route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
{"final-route-user-agent", required_argument, 0, "add a final route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
{"final-route-remote-user", required_argument, 0, "add a final route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
{"final-route-referer", required_argument, 0, "add a final route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
{"final-route-label", required_argument, 0, "add a final routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
{"final-route-if", required_argument, 0, "add a final route based on condition", uwsgi_opt_add_route, "if", 0},
{"final-route-if-not", required_argument, 0, "add a final route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"final-route-run", required_argument, 0, "always run the specified final route action", uwsgi_opt_add_route, "run", 0},
{"error-route", required_argument, 0, "add an error route", uwsgi_opt_add_route, "path_info", 0},
{"error-route-status", required_argument, 0, "add an error route for the specified status", uwsgi_opt_add_route, "status", 0},
{"error-route-host", required_argument, 0, "add an error route based on Host header", uwsgi_opt_add_route, "http_host", 0},
{"error-route-uri", required_argument, 0, "add an error route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
{"error-route-qs", required_argument, 0, "add an error route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
{"error-route-remote-addr", required_argument, 0, "add an error route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
{"error-route-user-agent", required_argument, 0, "add an error route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
{"error-route-remote-user", required_argument, 0, "add an error route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
{"error-route-referer", required_argument, 0, "add an error route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
{"error-route-label", required_argument, 0, "add an error routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
{"error-route-if", required_argument, 0, "add an error route based on condition", uwsgi_opt_add_route, "if", 0},
{"error-route-if-not", required_argument, 0, "add an error route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"error-route-run", required_argument, 0, "always run the specified error route action", uwsgi_opt_add_route, "run", 0},
{"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
{"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
#endif
@@ -601,6 +640,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
#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},
{"cgroup-dir-mode", required_argument, 0, "set permission for cgroup directory (default is 700)", uwsgi_opt_set_str, &uwsgi.cgroup_dir_mode, 0},
{"namespace", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0},
{"namespace-keep-mount", required_argument, 0, "keep the specified mountpoint in your namespace", uwsgi_opt_add_string_list, &uwsgi.ns_keep_mount, 0},
{"ns", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0},
@@ -617,9 +657,14 @@ 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},
{"cron2", required_argument, 0, "add a cron task (key=val syntax)", uwsgi_opt_add_cron2, NULL, UWSGI_OPT_MASTER},
{"unique-cron", required_argument, 0, "add a unique cron task", uwsgi_opt_add_unique_cron, NULL, UWSGI_OPT_MASTER},
{"cron-harakiri", required_argument, 0, "set the maximum time (in seconds) we wait for cron command to complete", uwsgi_opt_set_int, &uwsgi.cron_harakiri, 0},
#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},
{"unique-legion-cron", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER},
{"unique-cron-legion", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_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},
@@ -628,6 +673,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion-attach-daemon", required_argument, 0, "same as --attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"legion-smart-attach-daemon", required_argument, 0, "same as --smart-attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"legion-smart-attach-daemon2", required_argument, 0, "same as --smart-attach-daemon2 but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
#endif
{"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
@@ -1447,15 +1497,28 @@ void uwsgi_backtrace(int depth) {
bt_strings = backtrace_symbols(btrace, bt_size);
uwsgi_log("*** backtrace of %d ***\n", (int) getpid());
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
uwsgi_buffer_append(ub, "*** backtrace of ",17);
uwsgi_buffer_num64(ub, (int64_t) getpid());
uwsgi_buffer_append(ub, " ***\n", 5);
for (i = 0; i < bt_size; i++) {
uwsgi_log("%s\n", bt_strings[i]);
uwsgi_buffer_append(ub, bt_strings[i], strlen(bt_strings[i]));
uwsgi_buffer_append(ub, "\n", 1);
}
free(btrace);
uwsgi_log("*** end of backtrace ***\n");
uwsgi_buffer_append(ub, "*** end of backtrace ***\n", 25);
uwsgi_log("%.*s", ub->pos, ub->buf);
struct uwsgi_string_list *usl = uwsgi.alarm_segfault;
while(usl) {
uwsgi_alarm_trigger(usl->value, ub->buf, ub->pos);
usl = usl->next;
}
uwsgi_buffer_destroy(ub);
#endif
}
@@ -2202,18 +2265,9 @@ int uwsgi_start(void *v_argv) {
}
}
uwsgi_log("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
uwsgi.async_waiting_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_waiting_fd_table) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi.async_waiting_fd_table, 0, sizeof(struct wsgi_request *) * uwsgi.max_fd);
uwsgi.async_proto_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_proto_fd_table) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi.async_proto_fd_table, 0, sizeof(struct wsgi_request *) * uwsgi.max_fd);
// optimization, this array maps file descriptor to requests
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
}
#ifdef UWSGI_DEBUG
@@ -2778,6 +2832,16 @@ next2:
}
}
uwsgi_worker_run();
// never here
_exit(0);
}
void uwsgi_worker_run() {
int i;
if (uwsgi.lazy || uwsgi.lazy_apps) {
uwsgi_init_all_apps();
}
@@ -4042,3 +4106,23 @@ void uwsgi_opt_extract(char *opt, char *address, void *foobar) {
};
exit(0);
}
void uwsgi_print_sym(char *opt, char *symbol, void *foobar) {
char *sym = dlsym(RTLD_DEFAULT, symbol);
if (sym) {
uwsgi_log("%s", sym);
exit(0);
}
char *symbol_start = uwsgi_concat2(symbol, "_start");
char *symbol_end = uwsgi_concat2(symbol, "_end");
char *sym_s = dlsym(RTLD_DEFAULT, symbol_start);
char *sym_e = dlsym(RTLD_DEFAULT, symbol_end);
if (sym_s && sym_e) {
uwsgi_log("%.*s", sym_e - sym_s, sym_s);
}
exit(0);
}
+122 -28
View File
@@ -23,6 +23,28 @@ int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) {
return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len);
}
int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) {
// 30+1
char d[31];
int len = uwsgi_http_date((time_t) t, d);
if (!len) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len);
}
int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) {
// 30+1
char lm[31];
int len = uwsgi_http_date((time_t) t, lm);
if (!len) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len);
}
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
char buf[6+(sizeof(UMAX64_STR)*3)+4];
if (end == 0) {
@@ -54,7 +76,19 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
// reset the buffer (could be useful for rollbacks...)
wsgi_req->headers->pos = 0;
// reset headers count
wsgi_req->header_cnt = 0;
struct uwsgi_buffer *hh = NULL;
wsgi_req->status = uwsgi_str3_num(status);
#ifdef UWSGI_ROUTING
// apply error routes
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_error_routing = 0;
#endif
if (status_len <= 4) {
char *new_sc = NULL;
size_t new_sc_len = 0;
@@ -77,7 +111,6 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
if (!hh) {wsgi_req->write_errors++; return -1;}
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
uwsgi_buffer_destroy(hh);
wsgi_req->status = uwsgi_str3_num(status);
return 0;
error:
uwsgi_buffer_destroy(hh);
@@ -86,6 +119,24 @@ error:
}
//each protocol has its header generator
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
if (!wsgi_req->headers) {
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
wsgi_req->headers->limit = UMAX16;
}
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
if (!hh) { wsgi_req->write_errors++ ; return -1;}
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
wsgi_req->header_cnt++;
uwsgi_buffer_destroy(hh);
return 0;
error:
uwsgi_buffer_destroy(hh);
wsgi_req->write_errors++;
return -1;
}
int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
@@ -105,21 +156,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) {
@@ -175,9 +219,29 @@ int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
if (wsgi_req->write_errors) return -1;
if (wsgi_req->ignore_body) return UWSGI_OK;
// do not commit headers until a response_buffer is available (take in account flushing)
if ((wsgi_req->flush || !wsgi_req->response_buffer) && !wsgi_req->headers_sent) {
// if the transformation chain returns 1, we are in buffering mode
if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
if (t_ret == 0) {
buf = wsgi_req->transformed_chunk;
len = wsgi_req->transformed_chunk_len;
// reset transformation
wsgi_req->transformed_chunk = NULL;
wsgi_req->transformed_chunk_len = 0;
goto write;
}
if (t_ret == 1) {
return UWSGI_OK;
}
wsgi_req->write_errors++;
return -1;
}
write:
// send headers if not already sent
if (!wsgi_req->headers_sent) {
int ret = uwsgi_response_write_headers_do(wsgi_req);
if (ret == UWSGI_OK) goto sendbody;
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
@@ -189,15 +253,6 @@ sendbody:
if (len == 0) return UWSGI_OK;
if (wsgi_req->response_buffer) {
if (uwsgi_buffer_append(wsgi_req->response_buffer, buf, len)) {
wsgi_req->write_errors++;
return -1;
}
if (!wsgi_req->flush)
return UWSGI_OK;
}
for(;;) {
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
if (ret < 0) {
@@ -227,8 +282,10 @@ sendbody:
}
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
return uwsgi_response_sendfile_do_can_close(wsgi_req, fd, pos, len, 1);
}
int can_close = 1;
int uwsgi_response_sendfile_do_can_close(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len, int can_close) {
if (fd == wsgi_req->sendfile_fd) can_close = 0;
@@ -237,6 +294,11 @@ int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos
return -1;
}
if (wsgi_req->ignore_body) {
if (can_close) close(fd);
return UWSGI_OK;
}
if (!wsgi_req->headers_sent) {
int ret = uwsgi_response_write_headers_do(wsgi_req);
if (ret == UWSGI_OK) goto sendfile;
@@ -251,7 +313,7 @@ sendfile:
if (len == 0) {
struct stat st;
if (fstat(fd, &st)) {
uwsgi_error("fstat()");
uwsgi_error("uwsgi_response_sendfile_do()/fstat()");
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
@@ -346,3 +408,35 @@ int uwsgi_simple_wait_write_hook(int fd, int timeout) {
return ret;
}
/*
simplified write to client
(generally used as fallback)
*/
int uwsgi_simple_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
wsgi_req->write_pos = 0;
for(;;) {
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
if (ret < 0) {
if (!uwsgi.ignore_write_errors) {
uwsgi_error("uwsgi_simple_write()");
}
wsgi_req->write_errors++;
return -1;
}
if (ret == UWSGI_OK) {
break;
}
ret = uwsgi_wait_write_req(wsgi_req);
if (ret < 0) { wsgi_req->write_errors++; return -1;}
if (ret == 0) {
uwsgi_log("uwsgi_simple_write() TIMEOUT !!!\n");
wsgi_req->write_errors++;
return -1;
}
}
return 0;
}
+29 -1
View File
@@ -1,6 +1,11 @@
#include <uwsgi.h>
static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
char *uwsgi_gzip_chunk(z_stream *z, uint32_t *crc32, char *buf, size_t len, size_t *dlen) {
uwsgi_crc32(crc32, buf, len);
return uwsgi_deflate(z, buf, len, dlen);
}
struct uwsgi_buffer *uwsgi_gzip(char *buf, size_t len) {
z_stream z;
@@ -49,6 +54,29 @@ int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
return 0;
}
int uwsgi_gzip_prepare(z_stream *z, char *dict, size_t dict_len, uint32_t *crc32) {
uwsgi_crc32(crc32, NULL, 0);
if (uwsgi_deflate_init(z, NULL, 0)) return -1;
return 0;
}
// fix and free a gzip stream
int uwsgi_gzip_fix(z_stream *z, uint32_t crc32, struct uwsgi_buffer *ub, size_t len) {
size_t dlen0 = 0;
char *gzipped0 = uwsgi_deflate(z, NULL, 0, &dlen0);
if (!gzipped0) goto end;
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
free(gzipped0);
if (uwsgi_buffer_u32le(ub, crc32)) goto end;
if (uwsgi_buffer_u32le(ub, len)) goto end;
deflateEnd(z);
return 0;
end:
if (gzipped0) free(gzipped0);
deflateEnd(z);
return -1;
}
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
+294
View File
@@ -0,0 +1,294 @@
#include <uwsgi.h>
#include <libxml/parser.h>
#include <curl/curl.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_airbrake_config {
int first;
char *arg;
char *apikey;
char *env;
};
struct uwsgi_airbrake_opt {
char *name;
CURLoption option;
void (*func)(CURL *, CURLoption, char *, struct uwsgi_airbrake_config*);
};
static void uwsgi_airbrake_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL);
}
static void uwsgi_airbrake_int(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
curl_easy_setopt(curl, option, atoi(arg));
}
static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
uacc->apikey = arg;
}
static void uwsgi_airbrake_set_env(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
uacc->env = arg;
}
static struct uwsgi_airbrake_opt uaco[] = {
{"url", CURLOPT_URL, NULL},
{"apikey", 0, uwsgi_airbrake_set_apikey},
{"env", 0, uwsgi_airbrake_set_env},
{"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl},
{"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int},
{"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int},
{NULL, 0, NULL},
};
static void uwsgi_airbrake_setopt(CURL *curl, char *opt, struct uwsgi_airbrake_config *uacc) {
struct uwsgi_airbrake_opt *o = uaco;
char *equal = strchr(opt,'=');
if (!equal) {
if (!uacc->first) {
curl_easy_setopt(curl, CURLOPT_URL, opt);
uacc->first = 1;
}
return;
}
uacc->first = 1;
*equal = 0;
while(o->name) {
if (!strcmp(o->name, opt)) {
if (o->func) {
o->func(curl, o->option, equal+1, uacc);
}
else {
curl_easy_setopt(curl, o->option, equal+1);
}
goto end;
}
o++;
}
end:
*equal = '=';
}
char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) {
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
xmlChar *xmlbuff;
int buffersize;
xmlDocPtr doc = NULL;
xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL;
char *msg = NULL;
doc = xmlNewDoc(BAD_CAST "1.0");
notice_node = xmlNewNode(NULL, BAD_CAST "notice");
xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3");
xmlDocSetRootElement(doc, notice_node);
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey);
node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL);
xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI");
xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION);
xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi");
// request env
node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL);
node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL);
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version");
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version");
struct utsname uuts;
#ifdef __sun__
if (uname(&uuts) < 0) {
#else
if (uname(&uuts)) {
#endif
uwsgi_error("uname()");
}
else {
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname");
char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version);
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version");
free(os_version);
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine");
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename");
}
// end request env
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
if (uacc->env) {
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env);
}
else {
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
}
errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL);
xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError");
node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL);
char *ctx = NULL;
char *text = uwsgi_str(ut->buf);
char *p = strtok_r(text, "\n", &ctx);
while (p) {
// skip log messages
if (!uwsgi_startswith(p, "***", 3))
goto next;
// backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555]
// we take binary/lib as filename
// and extract method name from remaining string
char *n = strchr(p, '(');
if (n) {
*n = 0;
char *pls = strchr(n+1, '+');
if (pls) {
*pls = 0;
}
if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) {
goto next;
}
else if (!strcmp("uwsgi_fpe", n+1)) {
msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p);
goto next;
}
if (!msg) {
if (strlen(n+1)) {
msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p);
}
else {
// method name might be missing
msg = uwsgi_concat2("uWSGI segfault in ", p);
}
}
// skip empty lines
if (!p)
goto next;
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
if ((n+1)[0] == ')') {
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()");
}
else {
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST n+1);
}
xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p);
//xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
}
next:
p = strtok_r(NULL, "\n", &ctx);
}
xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg);
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
xmlFreeDoc(doc);
xmlCleanupParser();
xmlMemoryDump();
free(msg);
free(text);
return (char *) xmlbuff;
}
static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
int interesting_fd;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
CURL *curl = curl_easy_init();
// ARGH !!!
if (!curl) return;
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
char *opts = uwsgi_str(uacc->arg);
// fill curl options
char *ctx = NULL;
char *p = strtok_r(opts, ";", &ctx);
while(p) {
uwsgi_airbrake_setopt(curl, uwsgi_str(p), uacc);
p = strtok_r(NULL, ";", &ctx);
}
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret < 0) return;
if (ret == 0) continue;
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
ut->pos = 0;
ut->len = (size_t) rlen;
ut->custom0 = 0;
char *notice = uwsgi_format_airbrake_backtrace(ut);
curl_slist_append(expect, "Accept: */*");
curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice));
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
free(notice);
}
}
static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_airbrake_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config));
uacc->arg = uai->arg;
ut->data = uacc;
}
static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
ut->rlen = write(ut->pipe[0], msg, len);
}
static void uwsgi_airbrake_load(void) {
uwsgi_register_alarm("airbrake", uwsgi_airbrake_init, uwsgi_airbrake_func);
}
struct uwsgi_plugin airbrake_plugin = {
.name = "airbrake",
.on_load = uwsgi_airbrake_load,
};
+9
View File
@@ -0,0 +1,9 @@
from uwsgiconfig import spcall
NAME='airbrake'
CFLAGS = [spcall('xml2-config --cflags')]
LDFLAGS = []
LIBS = ['-lcurl', spcall('xml2-config --libs')]
GCC_LIST = ['airbrake_plugin']
+3 -2
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include <curl/curl.h>
extern struct uwsgi_server uwsgi;
@@ -168,7 +168,8 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret <= 0) continue;
if (ret < 0) return;
if (ret == 0) continue;
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
+3 -3
View File
@@ -214,7 +214,7 @@ static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len)
// "Status: NNN"
if (header_size >= 11) {
if (!strncasecmp("Status: ", key, 8)) {
uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8);
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
status_sent = 1;
key = NULL;
value = NULL;
@@ -229,13 +229,13 @@ static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len)
// Location: X
if (header_size >= 11) {
if (!strncasecmp("Location: ", key, 10)) {
uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9);
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
status_sent = 1;
}
}
if (status_sent == 0) {
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
status_sent = 1;
}
}
+2 -7
View File
@@ -44,10 +44,6 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
peers->in = uwsgi_buffer_new(uwsgi.page_size);
// add timeout
peers->timeout = cr_add_timeout(cs->corerouter, peers);
// check retry
if (cs->retry) {
peers->can_retry = 1;
}
peers->prev = old_peers;
if (old_peers) {
@@ -293,18 +289,17 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
#endif
}
if (peer->failed) {
if (peer->soopt) {
if (!ucr->quiet)
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\": %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, strerror(peer->soopt));
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt));
}
else if (peer->timed_out) {
if (peer->instance_address_len > 0) {
if (peer->connecting) {
if (!ucr->quiet)
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\": timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address);
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries);
}
}
}
+7 -2
View File
@@ -154,9 +154,14 @@ XS(XS_coroae_accept_request) {
request:
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
goto end;
}
#endif
for(;;) {
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
if (wsgi_req->async_status <= UWSGI_OK) {
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req)) {
goto end;
}
wsgi_req->switches++;
+2 -1
View File
@@ -453,7 +453,8 @@ static int amqp_wait_connection_tune(int fd) {
static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) {
char *ptr = (char *) fh;
ssize_t len = 0, rlen;
size_t len = 0;
ssize_t rlen;
while(len < 7) {
rlen = recv(fd, ptr, 7-len, 0);
+5
View File
@@ -172,6 +172,9 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
cr_peer_connected(peer, "fr_instance_connected()");
// we are connected, we cannot retry anymore
peer->can_retry = 0;
// fix modifiers
peer->in->buf[0] = peer->session->main_peer->modifier1;
peer->in->buf[3] = peer->session->main_peer->modifier2;
@@ -217,6 +220,8 @@ static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
if (new_peer->instance_address_len == 0)
return -1;
new_peer->can_retry = 1;
cr_connect(new_peer, fr_instance_connected);
}
+19 -7
View File
@@ -16,8 +16,7 @@ struct uwsgi_option fiber_options[] = {
VALUE uwsgi_fiber_request() {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
async_schedule_to_req_green();
return Qnil;
}
@@ -32,30 +31,43 @@ VALUE rb_fiber_schedule_to_req() {
rb_fiber_resume(ufiber.fib[id], 0, NULL);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
return Qnil;
}
static void fiber_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
int error = 0;
rb_protect(rb_fiber_schedule_to_req, 0, &error);
// call it in the main core
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
if (error) {
rack_plugin.exception_log(NULL);
rb_gc_unregister_address(&ufiber.fib[id]);
uwsgi.wsgi_req->async_status = UWSGI_OK;
}
}
static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
rb_fiber_yield(0, NULL);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
}
+196
View File
@@ -0,0 +1,196 @@
#include <uwsgi.h>
/*
Soon before official Go 1.1, we understand supporting Go in a fork() heavy
environment was not blessed by the Go community.
Instead of completely dropping support for Go, we studied how the gccgo project works and we
decided it was a better approach for uWSGI.
This new plugin works by initializing a new "go runtime" after each fork().
The runtime calls the Go main function (developed by the user), and pass the whole
uWSGI control to it.
the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically
manages mules, spoolers and workers)
As well as before each core maps to a goroutine mapped to a real pthread. (goroutines called
from your apps are native goroutines)
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_plugin gccgo_plugin;
struct uwsgi_gccgo{
struct uwsgi_string_list *libs;
char *args;
} ugccgo;
/*
static void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
// set loop engine
uwsgi.loop = "goroutines";
}
*/
struct uwsgi_option uwsgi_gccgo_options[] = {
{"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
{"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
{"go-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
{"gccgo-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
// {"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
// no_split_stack is the key to avoid crashing !!!
void* runtime_m(void) __attribute__ ((noinline, no_split_stack));
void runtime_check(void);
void runtime_args(int, char **);
void runtime_osinit(void);
void runtime_schedinit(void);
void *__go_go(void *, void *);
void runtime_main(void);
void runtime_mstart(void *);
extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler");
extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env");
extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd");
extern void uwsgigo_run_core(int) __asm__ ("go.uwsgi.RunCore");
extern void uwsgigo_signal_handler(void *, uint8_t) __asm__ ("go.uwsgi.SignalHandler");
//extern void uwsgigo_loop(void) __asm__ ("go.uwsgi.Loop");
static void mainstart(void *arg __attribute__((unused))) {
runtime_main();
}
void uwsgigo_main_main(void) __asm__ ("main.main");
void uwsgigo_main_init(void) __asm__ ("__go_init_main");
void (*uwsgigo_hook_init)(void);
void (*uwsgigo_hook_main)(void);
void uwsgigo_main_init(void) {
uwsgigo_hook_init();
}
void uwsgigo_main_main(void) {
uwsgigo_hook_main();
}
int uwsgi_gccgo_helper_request_body_read(struct wsgi_request *wsgi_req, char *p, uint64_t len) {
ssize_t rlen = 0;
char *buf = uwsgi_request_body_read(wsgi_req, len, &rlen);
if (buf == uwsgi.empty) {
return 0;
}
else if (buf == NULL) {
return -1;
}
memcpy(p, buf, rlen);
return (int) rlen;
}
int uwsgi_gccgo_helper_register_signal(uint8_t signum, char *receiver, void *handler) {
return uwsgi_register_signal(signum, receiver, handler, gccgo_plugin.modifier1);
}
static void uwsgi_gccgo_initialize() {
struct uwsgi_string_list *usl = ugccgo.libs;
while(usl) {
void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
uwsgi_log("unable to open go shared library: %s\n", dlerror());
exit(1);
}
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
uwsgigo_hook_init = dlsym(handle, "__go_init_main");
uwsgigo_hook_main = dlsym(handle, "main.main");
usl = usl->next;
}
if (!uwsgigo_hook_init || !uwsgigo_hook_main) {
return;
}
// Go runtime initialization
int argc = 0;
if (ugccgo.args) {
char *argv_list = uwsgi_str(ugccgo.args);
char *p = strtok(argv_list, " ");
while(p) {
argc++;
p = strtok(NULL, " ");
}
free(argv_list);
}
runtime_check();
if (argc > 0) {
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 1));
char *argv_list = uwsgi_str(ugccgo.args);
char *p = strtok(argv_list, " ");
int n = 0;
while(p) {
argv[n] = p;
n++;
p = strtok(NULL, " ");
}
runtime_args(argc, argv);
}
else {
char *argv[2] = {0,0};
runtime_args(0, argv);
}
runtime_osinit();
runtime_schedinit();
__go_go(mainstart, NULL);
runtime_mstart(runtime_m());
// never here
}
static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
/* Standard GO request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log("Empty GO request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
wsgi_req->async_environ = uwsgigo_env(wsgi_req);
int i;
for(i=0;i<wsgi_req->var_cnt;i++) {
uwsgigo_env_add(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
i++;
}
uwsgigo_request(wsgi_req->async_environ, wsgi_req);
return UWSGI_OK;
}
static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_gccgo_signal_handler(uint8_t signum, void *handler) {
uwsgigo_signal_handler(handler, signum);
return 0;
}
struct uwsgi_plugin gccgo_plugin = {
.name = "gccgo",
.modifier1 = 11,
.options = uwsgi_gccgo_options,
//.on_load = uwsgi_gccgo_on_load,
.request = uwsgi_gccgo_request,
.after_request = uwsgi_gccgo_after_request,
.post_fork = uwsgi_gccgo_initialize,
.signal_handler = uwsgi_gccgo_signal_handler,
};
+118
View File
@@ -0,0 +1,118 @@
package uwsgi
import (
"strings"
"net/http"
"net/http/cgi"
"io"
)
//extern uwsgi_takeover
func uwsgi_takeover()
//extern uwsgi_response_write_body_do
func uwsgi_response_write_body_do(*interface{}, *byte, uint64) int
//extern uwsgi_response_prepare_headers_int
func uwsgi_response_prepare_headers_int(*interface{}, int) int
//extern uwsgi_response_add_header
func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int
//extern uwsgi_gccgo_helper_request_body_read
func uwsgi_request_body_read(*interface{}, *byte, uint64) int
//extern uwsgi_gccgo_helper_register_signal
func uwsgi_register_signal(uint8, *byte, func(uint8)) int
var uwsgi_signals_gc [256]func(uint8)
func Env(wsgi_req *interface{}) *map[string]string {
var env map[string]string
env = make(map[string]string)
return &env
}
func EnvAdd(env *map[string]string, k *[65536]byte, kl uint16, v *[65536]byte, vl uint16) {
(*env)[ string((*k)[0:kl]) ] = string((*v)[0:vl])
}
type ResponseWriter struct {
r *http.Request
wsgi_req *interface{}
headers http.Header
wroteHeader bool
}
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
uwsgi_response_write_body_do(w.wsgi_req, &p[0], uint64(len(p)))
return len(p), err
}
func (w *ResponseWriter) WriteHeader(status int) {
uwsgi_response_prepare_headers_int(w.wsgi_req, status )
if w.headers.Get("Content-Type") == "" {
w.headers.Set("Content-Type", "text/html; charset=utf-8")
}
for k := range w.headers {
for _, v := range w.headers[k] {
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
v = strings.TrimSpace(v)
kb := []byte(k)
vb := []byte(v)
uwsgi_response_add_header(w.wsgi_req, &kb[0], uint16(len(k)), &vb[0], uint16(len(v)))
}
}
w.wroteHeader = true
}
func (w *ResponseWriter) Header() http.Header {
return w.headers
}
type BodyReader struct {
wsgi_req *interface{}
}
// there is no close in request body
func (br *BodyReader) Close() error {
return nil
}
func (br *BodyReader) Read(p []byte) (n int, err error) {
var rlen int = uwsgi_request_body_read(br.wsgi_req, &p[0], uint64(len(p)))
if (rlen == 0) {
err = io.EOF;
return 0, err
} else if (rlen == -1) {
err = io.ErrUnexpectedEOF
return 0, err
}
return rlen, err
}
func RequestHandler(env *map[string]string, wsgi_req *interface{}) {
httpReq, err := cgi.RequestFromMap(*env)
if err == nil {
httpReq.Body = &BodyReader{wsgi_req}
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
http.DefaultServeMux.ServeHTTP(&w, httpReq)
}
}
func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool {
var b []byte = []byte(receiver)
if (uwsgi_register_signal(signum, &b[0], handler) < 0) {
return false
}
uwsgi_signals_gc[signum] = handler
return true
}
func SignalHandler(handler func(uint8), signum uint8) {
handler(signum)
}
func Run() {
uwsgi_takeover()
}
+34 -4
View File
@@ -29,7 +29,7 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL);
PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL);
@@ -54,7 +54,16 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
if (running_cores > 0) {
uwsgi_log_verbose("waiting for %d running requests on worker %d (pid: %d)...\n", running_cores, uwsgi.mywid, uwsgi.mypid);
}
} else {
// no need to worry about freeing memory
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
if (ae) {
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
}
Py_INCREF(Py_None);
return Py_None;
@@ -242,8 +251,7 @@ request:
#endif
for(;;) {
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
if (wsgi_req->async_status <= UWSGI_OK) {
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
goto end;
}
wsgi_req->switches++;
@@ -259,6 +267,28 @@ end2:
uwsgi_close_request(wsgi_req);
free_req_queue;
if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) {
int running_cores = 0;
int i;
for(i=0;i<uwsgi.async;i++) {
if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) {
running_cores++;
}
}
if (running_cores == 0) {
// no need to worry about freeing memory
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
if (ae) {
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
}
}
Py_INCREF(Py_None);
return Py_None;
+8 -6
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -48,9 +48,6 @@ static int uwsgi_go_init() {
uwsgi_log("Go version \"%s\" initialized\n", uwsgi_go_helper_version_c());
// call PostInit()
uwsgi_go_helper_post_init_c();
return 0;
}
@@ -80,9 +77,7 @@ static int uwsgi_go_request(struct wsgi_request *wsgi_req) {
}
static void uwsgi_go_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_go_signal_handler(uint8_t signum, void *handler) {
@@ -101,11 +96,18 @@ static void uwsgi_go_on_load() {
uwsgi_register_loop("goroutines", goroutines_loop);
}
static void uwsgi_go_call_init_hook() {
if (uwsgi_go_helper_post_init_c) {
uwsgi_go_helper_post_init_c();
}
}
struct uwsgi_plugin go_plugin = {
.name = "go",
.modifier1 = 11,
.request = uwsgi_go_request,
.after_request = uwsgi_go_after_request,
.preinit_apps = uwsgi_go_call_init_hook,
.post_fork = uwsgi_go_post_fork,
.init = uwsgi_go_init,
.signal_handler = uwsgi_go_signal_handler,
+2 -2
View File
@@ -411,10 +411,10 @@ func uwsgi_go_helper_run_core(core_id int) {
the main function, running the uWSGI server via libuwsgi.so
*/
func Run() {
argc := len(os.Args)
argc := len(os.Args) + 1
argv := C.uwsgi_go_helper_create_argv(C.int(argc))
for i, s := range os.Args {
C.uwsgi_go_helper_set_argv(argv, C.int(i), C.CString(s))
}
C.uwsgi_init(C.int(argc), argv, nil)
C.uwsgi_init(C.int(argc-1), argv, nil)
}
+46 -21
View File
@@ -2,6 +2,7 @@
#include <greenlet/greenlet.h>
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
struct ugreenlet {
int enabled;
@@ -10,15 +11,22 @@ struct ugreenlet {
PyGreenlet **gl;
} ugl;
struct uwsgi_option greenlet_options[] = {
static struct uwsgi_option greenlet_options[] = {
{"greenlet", no_argument, 0, "enable greenlet as suspend engine", uwsgi_opt_true, &ugl.enabled, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
};
PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
static void gil_greenlet_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
static void gil_greenlet_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
async_schedule_to_req_green();
Py_DECREF(ugl.gl[uwsgi.wsgi_req->async_id]);
@@ -28,45 +36,66 @@ PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
PyMethodDef uwsgi_greenlet_request_method[] = {{"uwsgi_greenlet_request", py_uwsgi_greenlet_request, METH_VARARGS, ""}};
static inline void greenlet_schedule_to_req() {
static void greenlet_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// ensure gil
UWSGI_GET_GIL
if (!uwsgi.wsgi_req->suspended) {
ugl.gl[id] = PyGreenlet_New(ugl.callable, NULL);
uwsgi.wsgi_req->suspended = 1;
}
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
}
static inline void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
// ensure gil
UWSGI_GET_GIL
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyGreenlet_Switch(ugl.main, NULL, NULL);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
}
static int greenlet_init() {
return 0;
}
static void greenlet_init_apps(void) {
if (!ugl.enabled) {
return;
}
if (!ugl.enabled) return;
if (uwsgi.async <= 1) {
uwsgi_log("the greenlet loop engine requires async mode\n");
uwsgi_log("the greenlet suspend engine requires async mode\n");
exit(1);
}
if (uwsgi.has_threads) {
up.gil_get = gil_greenlet_get;
up.gil_release = gil_greenlet_release;
}
// blindy call it as the stackless gil engine is already set
UWSGI_GET_GIL
PyGreenlet_Import();
@@ -77,15 +106,11 @@ static void greenlet_init_apps(void) {
uwsgi.schedule_to_main = greenlet_schedule_to_main;
uwsgi.schedule_to_req = greenlet_schedule_to_req;
return;
}
struct uwsgi_plugin greenlet_plugin = {
.name = "greenlet",
.init = greenlet_init,
.init_apps = greenlet_init_apps,
.options = greenlet_options,
};
+34 -3
View File
@@ -121,7 +121,6 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
hr->content_length = uwsgi_str_num(val, vallen);
hr->session.can_keepalive = 0;
}
// in the future we could support chunked requests...
@@ -183,19 +182,28 @@ int http_headers_parse(struct corerouter_peer *peer) {
peer->out_pos = 0;
struct uwsgi_buffer *out = peer->out;
int found = 0;
// REQUEST_METHOD
while (ptr < watermark) {
if (*ptr == ' ') {
if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1;
ptr++;
found = 1;
break;
}
else if (*ptr == '\r' || *ptr == '\n') break;
ptr++;
}
// ensure we have a method
if (!found) {
return -1;
}
// REQUEST_URI / PATH_INFO / QUERY_STRING
base = ptr;
found = 0;
while (ptr < watermark) {
if (*ptr == '?' && !query_string) {
// PATH_INFO must be url-decoded !!!
@@ -221,13 +229,20 @@ int http_headers_parse(struct corerouter_peer *peer) {
if (uwsgi_buffer_append_keyval(out, "QUERY_STRING", 12, query_string, ptr - query_string)) return -1;
}
ptr++;
found = 1;
break;
}
ptr++;
}
// ensure we have a URI
if (!found) {
return -1;
}
// SERVER_PROTOCOL
base = ptr;
found = 0;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
@@ -239,11 +254,17 @@ int http_headers_parse(struct corerouter_peer *peer) {
hr->session.can_keepalive = 1;
}
ptr += 2;
found = 1;
break;
}
ptr++;
}
// ensure we have a protocol
if (!found) {
return -1;
}
// SCRIPT_NAME
if (uwsgi_buffer_append_keyval(out, "SCRIPT_NAME", 11, "", 0)) return -1;
@@ -459,6 +480,8 @@ ssize_t hr_instance_read(struct corerouter_peer *peer) {
struct http_session *hr = (struct http_session *) peer->session;
ssize_t len = cr_read(peer, "hr_instance_read()");
if (!len) {
// disable keepalive on unread body
if (hr->content_length) hr->session.can_keepalive = 0;
if (hr->session.can_keepalive) {
peer->session->main_peer->disabled = 0;
hr->rnrn = 0;
@@ -575,9 +598,16 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
if (main_peer->in->pos > hr->content_length) {
main_peer->in->pos = hr->content_length;
hr->content_length = 0;
// on pipeline attempt, disable keepalive
hr->session.can_keepalive = 0;
}
else {
hr->content_length -= main_peer->in->pos;
if (hr->content_length == 0) {
main_peer->disabled = 1;
// stop reading from the client
if (uwsgi_cr_set_hooks(main_peer, NULL, NULL)) return -1;
}
}
}
}
@@ -649,10 +679,11 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
if (hr->remains > 0) {
hr->session.can_keepalive = 0;
if (hr->content_length < hr->remains) {
hr->remains = hr->content_length;
hr->content_length = 0;
// we need to avoid problems with pipelined requests
hr->session.can_keepalive = 0;
}
else {
hr->content_length -= hr->remains;
@@ -660,7 +691,7 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
if (uwsgi_buffer_append(new_peer->out, main_peer->in->buf + hr->headers_size + 1, hr->remains)) return -1;
}
if (hr->session.can_keepalive) {
if (hr->session.can_keepalive && hr->content_length == 0) {
main_peer->disabled = 1;
// stop reading from the client
if (uwsgi_cr_set_hooks(main_peer, NULL, NULL)) return -1;
+5
View File
@@ -25,6 +25,7 @@ struct uwsgi_jvm {
jclass input_stream_class;
jclass file_class;
jclass hashmap_class;
jclass list_class;
jclass set_class;
jclass iterator_class;
@@ -63,6 +64,10 @@ jmethodID uwsgi_jvm_get_static_method_id_quiet(jclass, char *, char *);
jobject uwsgi_jvm_str(char *, size_t);
jobject uwsgi_jvm_hashmap(void);
int uwsgi_jvm_hashmap_put(jobject, jobject, jobject);
int uwsgi_jvm_hashmap_has(jobject, jobject);
jobject uwsgi_jvm_list(void);
int uwsgi_jvm_list_add(jobject, jobject);
jobject uwsgi_jvm_call_object(jobject, jmethodID, ...);
jobject uwsgi_jvm_call_object_static(jclass, jmethodID, ...);
+120
View File
@@ -215,15 +215,42 @@ JNIEXPORT jint JNICALL uwsgi_jvm_request_body_read_bytearray(JNIEnv *env, jobjec
return rlen;
}
JNIEXPORT jint JNICALL uwsgi_jvm_request_body_readline_bytearray(JNIEnv *env, jobject o, jobject b) {
struct wsgi_request *wsgi_req = current_wsgi_req();
ssize_t rlen = 0;
size_t len = uwsgi_jvm_array_len(b);
char *chunk = uwsgi_request_body_readline(wsgi_req, len, &rlen);
if (!chunk) {
uwsgi_jvm_throw_io("error reading request body");
return -1;
}
if (chunk == uwsgi.empty) {
return -1;
}
char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, b, JNI_FALSE);
if (!buf) return -1;
memcpy(buf, chunk, rlen);
(*ujvm_env)->ReleaseByteArrayElements(ujvm_env, b, (jbyte *) buf, 0);
return rlen;
}
JNIEXPORT jint JNICALL uwsgi_jvm_request_body_available(JNIEnv *env, jobject o) {
struct wsgi_request *wsgi_req = current_wsgi_req();
return (jint) (wsgi_req->post_cl - wsgi_req->post_pos);
}
JNIEXPORT void JNICALL uwsgi_jvm_request_body_seek(JNIEnv *env, jobject o, jint pos) {
struct wsgi_request *wsgi_req = current_wsgi_req();
uwsgi_request_body_seek(wsgi_req, pos);
}
static JNINativeMethod uwsgi_jvm_request_body_methods[] = {
{"read", "()I", (void *) &uwsgi_jvm_request_body_read},
{"read", "([B)I", (void *) &uwsgi_jvm_request_body_read_bytearray},
{"readLine", "([B)I", (void *) &uwsgi_jvm_request_body_readline_bytearray},
{"available", "()I", (void *) &uwsgi_jvm_request_body_available},
{"seek", "(I)V", (void *) &uwsgi_jvm_request_body_seek},
};
static struct uwsgi_option uwsgi_jvm_options[] = {
@@ -684,6 +711,23 @@ void uwsgi_jvm_local_unref(jobject obj) {
(*ujvm_env)->DeleteLocalRef(ujvm_env, obj);
}
jobject uwsgi_jvm_list() {
// optimization
static jmethodID mid = 0;
if (!mid) {
mid = uwsgi_jvm_get_method_id(ujvm.list_class, "<init>", "()V");
if (!mid) return NULL;
}
jobject ll = (*ujvm_env)->NewObject(ujvm_env, ujvm.list_class, mid);
if (uwsgi_jvm_exception()) {
return NULL;
}
return ll;
}
jobject uwsgi_jvm_hashmap() {
// optimization
static jmethodID mid = 0;
@@ -712,6 +756,18 @@ int uwsgi_jvm_hashmap_put(jobject hm, jobject key, jobject value) {
return uwsgi_jvm_call(hm, mid, key, value);
}
int uwsgi_jvm_list_add(jobject ll, jobject value) {
// optimization
static jmethodID mid = 0;
if (!mid) {
mid = uwsgi_jvm_get_method_id(ujvm.list_class, "add", "(Ljava/lang/Object;)Z");
if (!mid) return -1;
}
return uwsgi_jvm_call(ll, mid, value);
}
jobject uwsgi_jvm_hashmap_get(jobject hm, jobject key) {
// optimization
static jmethodID mid = 0;
@@ -724,6 +780,21 @@ jobject uwsgi_jvm_hashmap_get(jobject hm, jobject key) {
return uwsgi_jvm_call_object(hm, mid, key);
}
int uwsgi_jvm_hashmap_has(jobject hm, jobject key) {
// optimization
static jmethodID mid = 0;
if (!mid) {
mid = uwsgi_jvm_get_method_id(ujvm.hashmap_class, "containsKey", "(Ljava/lang/Object;)Z");
if (!mid) return 0;
}
if (uwsgi_jvm_call_bool(hm, mid, key)) {
return 1;
}
return 0;
}
jobject uwsgi_jvm_iterator(jobject set) {
// optimization
static jmethodID mid = 0;
@@ -1010,6 +1081,9 @@ static void uwsgi_jvm_create(void) {
ujvm.hashmap_class = uwsgi_jvm_class("java/util/HashMap");
if (!ujvm.hashmap_class) exit(1);
ujvm.list_class = uwsgi_jvm_class("java/util/ArrayList");
if (!ujvm.list_class) exit(1);
ujvm.set_class = uwsgi_jvm_class("java/util/Set");
if (!ujvm.set_class) exit(1);
@@ -1026,6 +1100,52 @@ static void uwsgi_jvm_create(void) {
if (!uwsgi_class) {
exit(1);
}
/*
start filling uwsgi.opt
*/
jfieldID opt_fid = (*ujvm_env)->GetStaticFieldID(ujvm_env, uwsgi_class, "opt", "Ljava/util/HashMap;");
if (uwsgi_jvm_exception()) {
exit(1);
}
jobject opt_hm = uwsgi_jvm_hashmap();
int j;
for (j = 0; j < uwsgi.exported_opts_cnt; j++) {
jstring j_opt_key = uwsgi_jvm_str(uwsgi.exported_opts[j]->key, 0);
if (uwsgi_jvm_hashmap_has(opt_hm, (jobject) j_opt_key)) {
jobject j_opt_value = uwsgi_jvm_hashmap_get(opt_hm, (jobject) j_opt_key);
if (uwsgi_jvm_object_is_instance(j_opt_value, ujvm.list_class)) {
if (uwsgi.exported_opts[j]->value == NULL) {
uwsgi_jvm_list_add(j_opt_value, (jobject) 1);
}
else {
uwsgi_jvm_list_add(j_opt_value, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
}
}
else {
jobject ll = uwsgi_jvm_list();
uwsgi_jvm_list_add(ll, j_opt_value);
if (uwsgi.exported_opts[j]->value == NULL) {
uwsgi_jvm_list_add(ll, (jobject) 1);
}
else {
uwsgi_jvm_list_add(ll, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
}
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, ll);
}
}
else {
if (uwsgi.exported_opts[j]->value == NULL) {
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, (jobject) 1);
}
else {
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
}
}
}
(*ujvm_env)->SetStaticObjectField(ujvm_env, uwsgi_class, opt_fid, opt_hm);
(*ujvm_env)->RegisterNatives(ujvm_env, uwsgi_class, uwsgi_jvm_api_methods, sizeof(uwsgi_jvm_api_methods)/sizeof(uwsgi_jvm_api_methods[0]));
if (uwsgi_jvm_exception()) {
exit(1);
+5
View File
@@ -1,11 +1,16 @@
import java.io.*;
import java.util.*;
public class uwsgi {
static HashMap<String,Object> opt;
public static class RequestBody extends InputStream {
public native int read();
public native int read(byte[] b);
public native int readLine(byte[] b);
public native int available();
public native void seek(int pos);
}
public interface SignalHandler {
+33 -10
View File
@@ -9,6 +9,7 @@ struct uwsgi_jwsgi {
char *app;
jmethodID app_mid;
jclass app_class;
jobject app_instance;
} ujwsgi;
static struct uwsgi_option uwsgi_jwsgi_options[] = {
@@ -20,7 +21,16 @@ static int uwsgi_jwsgi_add_request_item(jobject hm, char *key, uint16_t key_len,
jobject j_key = uwsgi_jvm_str(key, key_len);
if (!j_key) return -1;
jobject j_value = uwsgi_jvm_str(value, value_len);
jobject j_value = NULL;
// avoid clobbering vars
if (value_len > 0) {
j_value = uwsgi_jvm_str(value, value_len);
}
else {
char *tmp = uwsgi_str("");
j_value = uwsgi_jvm_str(tmp, 0);
free(tmp);
}
if (!j_value) {
uwsgi_jvm_local_unref(j_value);
return -1;
@@ -72,7 +82,12 @@ static int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) {
if (uwsgi_jwsgi_add_request_input(hm, "jwsgi.input", 11)) goto end;
response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm);
if (!ujwsgi.app_instance) {
response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm);
}
else {
response = uwsgi_jvm_call_object(ujwsgi.app_instance, ujwsgi.app_mid, hm);
}
if (!response) goto end;
if (uwsgi_jvm_array_len(response) != 3) {
@@ -135,23 +150,31 @@ static int uwsgi_jwsgi_setup() {
char *app = uwsgi_str(ujwsgi.app);
char *method = "application";
char *colon = strchr(app, ':');
if (!colon) {
uwsgi_log("invalid JWSGI app definition, must be class:method\n");
exit(1);
if (colon) {
*colon = 0;
method = colon + 1;
}
*colon = 0;
ujwsgi.app_class = uwsgi_jvm_class(app);
if (!ujwsgi.app_class) {
exit(1);
}
ujwsgi.app_mid = uwsgi_jvm_get_static_method_id(ujwsgi.app_class, colon+1, "(Ljava/util/HashMap;)[Ljava/lang/Object;");
if (!ujwsgi.app_mid) {
exit(1);
ujwsgi.app_mid = uwsgi_jvm_get_static_method_id_quiet(ujwsgi.app_class, method, "(Ljava/util/HashMap;)[Ljava/lang/Object;");
if (uwsgi_jvm_exception() || !ujwsgi.app_mid) {
jmethodID mid = uwsgi_jvm_get_method_id(ujwsgi.app_class, "<init>", "()V");
if (uwsgi_jvm_exception() || !mid) exit(1);
ujwsgi.app_instance = (*ujvm_env)->NewObject(ujvm_env, ujwsgi.app_class, mid);
if (uwsgi_jvm_exception() || !ujwsgi.app_instance) {
exit(1);
}
ujwsgi.app_mid = uwsgi_jvm_get_method_id(ujwsgi.app_class, method, "(Ljava/util/HashMap;)[Ljava/lang/Object;");
if (uwsgi_jvm_exception() || !ujwsgi.app_mid) {
exit(1);
}
}
uwsgi_log("JWSGI app \"%s\" loaded\n", ujwsgi.app);
+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,
};
+1 -1
View File
@@ -547,7 +547,7 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
pthread_mutex_lock(&umono.lock_loader);
}
// check if the mean time, something changed
// check if in the mean time, something changed
wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1);
if (wsgi_req->app_id == -1) {
+21 -10
View File
@@ -394,33 +394,44 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
return -1;
}
if (wsgi_req->dynamic) {
if (uwsgi.threads > 1) {
pthread_mutex_lock(&uperl.lock_loader);
}
}
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) {
if (uwsgi.threads > 1) {
pthread_mutex_lock(&uperl.lock_loader);
}
if (wsgi_req->script_len > 0) {
wsgi_req->app_id = init_psgi_app(wsgi_req, wsgi_req->script, wsgi_req->script_len, NULL);
}
else if (wsgi_req->file_len > 0) {
wsgi_req->app_id = init_psgi_app(wsgi_req, wsgi_req->file, wsgi_req->file_len, NULL);
}
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&uperl.lock_loader);
}
}
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
if (uwsgi_apps[uwsgi.default_app].modifier1 == psgi_plugin.modifier1) {
wsgi_req->app_id = uwsgi.default_app;
}
}
}
if (wsgi_req->dynamic) {
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&uperl.lock_loader);
}
}
if (wsgi_req->app_id == -1) {
uwsgi_500(wsgi_req);
uwsgi_log("--- unable to find perl application ---\n");
// nothing to clear/free
return UWSGI_OK;
}
}
struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id];
wi->requests++;
@@ -712,7 +723,7 @@ static uint16_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t a
STRLEN rlen;
SV *response = POPs;
char *value = SvPV(response, rlen );
ret = UMIN(UMAX16, rlen);
ret = UMIN(UMAX16-1, rlen);
memcpy(buffer, value, ret);
}
+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;
}
}
+30
View File
@@ -0,0 +1,30 @@
This is a bit convoluted, but you run it (so far) this way:
You have to compile PyPy with strange options. I'll explain them below.
In the pypy checkout, run:
./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone
Options:
-Ojit - standard PyPy build with JIT
--shared - as expected, creates a .so
--gcrootfinder - on linux, the default rootfinder is asmgcc which has trouble
with position independent code. This option is not needed
on OS X or windows.
If for some strange/dangerous/wrong reason your uWSGI binary is linked with cpython you could have name collisions
with pypy cpyext. In such crazy case you can remove cpyext support with:
./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone --withoutmod-cpyext
By default the pypy uWSGI plugin will load the libpypy-c.so library. You should have it in the LD_LIBRARY_PATH, otherwise you can set its path
with --pypy-lib option (pass an absolute path to it)
You have to specify the pypy home too, you can use the --pypy-home option or the PYPY_HOME var
PYPY_HOME=/home/user/pypy/lib_pypy uwsgi --pypy-lib /opt/pypy/libpypy-c.so --http-socket :9090 --pypy-wsgi werkzeug.testapp:test_app
The funny part about the uWSGI pypy plugin is that it is mainly written in python. The pypy_setup.py script is linked to the plugin, but you can override
it with the --pypy-setup option
+360
View File
@@ -0,0 +1,360 @@
/*******************************************************************
This is the C part of the PyPy plugin (with the main logic being in
Python, see pypy_setup.py).
Idea and initial implementation by Maciej Fijalkowski
*******************************************************************/
#include <uwsgi.h>
struct uwsgi_pypy {
void *handler;
char *lib;
char *setup;
char *home;
char *wsgi;
char *wsgi_file;
struct uwsgi_string_list *eval;
struct uwsgi_string_list *eval_post_fork;
struct uwsgi_string_list *exec;
struct uwsgi_string_list *exec_post_fork;
struct uwsgi_string_list *pp;
} upypy;
// the functions exposed by libpypy-c
char *(*rpython_startup_code)(void);
int (*pypy_setup_home)(char *, int);
int (*pypy_execute_source)(char *);
void (*pypy_thread_attach)(void);
void (*pypy_init_threads)(void);
// the hooks you can override with pypy
void (*uwsgi_pypy_hook_loader)(char *);
void (*uwsgi_pypy_hook_file_loader)(char *);
void (*uwsgi_pypy_hook_pythonpath)(char *);
void (*uwsgi_pypy_hook_request)(void *, int);
void (*uwsgi_pypy_post_fork_hook)(void);
extern struct uwsgi_server uwsgi;
struct uwsgi_plugin pypy_plugin;
int uwsgi_pypy_helper_masterpid() {
if (uwsgi.master_process) {
return uwsgi.workers[0].pid;
}
return 0;
}
int uwsgi_pypy_helper_worker_id() {
return uwsgi.mywid;
}
int uwsgi_pypy_helper_mule_id() {
return uwsgi.muleid;
}
void uwsgi_pypy_helper_signal(int signum) {
uwsgi_signal_send(uwsgi.signal_socket, signum);
}
struct uwsgi_opt **uwsgi_pypy_helper_opts(int *n) {
*n = uwsgi.exported_opts_cnt;
return uwsgi.exported_opts;
}
char *uwsgi_pypy_helper_version() {
return UWSGI_VERSION;
}
int uwsgi_pypy_helper_register_signal(int signum, char *kind, void *handler) {
return uwsgi_register_signal(signum, kind, handler, pypy_plugin.modifier1);
}
int uwsgi_pypy_helper_register_rpc(char *name, int argc, void *func) {
return uwsgi_register_rpc(name, &pypy_plugin, argc, func);
}
struct iovec *uwsgi_pypy_helper_environ(struct wsgi_request *wsgi_req, uint16_t *len) {
*len = wsgi_req->var_cnt;
return wsgi_req->hvec;
}
static int uwsgi_pypy_init() {
size_t rlen = 0;
char *buffer = NULL;
void *is_cpython_loaded = dlsym(RTLD_DEFAULT, "Py_Initialize");
if (is_cpython_loaded) {
uwsgi_log("!!! Loading both PyPy and CPython in the same process IS PURE EVIL AND IT IS NOT SUPPORTED !!!\n");
exit(1);
}
if (upypy.lib) {
upypy.handler = dlopen(upypy.lib, RTLD_NOW | RTLD_GLOBAL);
}
else {
if (upypy.home) {
#ifdef __APPLE__
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib");
#else
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so");
#endif
if (uwsgi_file_exists(libpath)) {
upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL);
}
free(libpath);
}
// fallback to standard library search path
if (!upypy.handler) {
#ifdef __APPLE__
upypy.handler = dlopen("libpypy-c.dylib", RTLD_NOW | RTLD_GLOBAL);
#else
upypy.handler = dlopen("libpypy-c.so", RTLD_NOW | RTLD_GLOBAL);
#endif
}
}
if (!upypy.handler) {
uwsgi_log("unable to load pypy library: %s\n", dlerror());
exit(1);
}
rpython_startup_code = dlsym(upypy.handler, "rpython_startup_code");
if (!rpython_startup_code) {
uwsgi_log("unable to find rpython_startup_code() symbol\n");
exit(1);
}
pypy_setup_home = dlsym(upypy.handler, "pypy_setup_home");
if (!pypy_setup_home) {
uwsgi_log("unable to find pypy_setup_home() symbol\n");
exit(1);
}
pypy_execute_source = dlsym(upypy.handler, "pypy_execute_source");
if (!pypy_execute_source) {
uwsgi_log("unable to find pypy_execute_source() symbol\n");
exit(1);
}
pypy_thread_attach = dlsym(upypy.handler, "pypy_thread_attach");
if (!pypy_thread_attach) {
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_thread_attach, multithreading will not work !!!\n");
}
pypy_init_threads = dlsym(upypy.handler, "pypy_init_threads");
if (!pypy_init_threads) {
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_init_threads, multithreading will not work !!!\n");
}
rpython_startup_code();
if (!upypy.home) {
upypy.home = getenv("PYPY_HOME");
if (!upypy.home) {
uwsgi_log("you have to specify a pypy home with --pypy-home\n");
exit(1);
}
}
if (pypy_setup_home(upypy.home, 0)) {
char *retry = uwsgi_concat2(upypy.home, "/lib_pypy");
if (uwsgi_is_dir(retry)) {
// this time we use debug
if (!pypy_setup_home(retry, 1)) {
free(retry);
goto ready;
}
}
uwsgi_log("unable to set pypy home to \"%s\"\n", upypy.home);
exit(1);
}
ready:
if (upypy.setup) {
buffer = uwsgi_open_and_read(upypy.setup, &rlen, 1, NULL);
}
else {
char *start = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_start");
char *end = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_end");
if (start && end) {
buffer = uwsgi_concat2n(start, end-start, "", 0);
}
}
if (!buffer) {
uwsgi_log("you have to load a pypy setup file with --pypy-setup\n");
exit(1);
}
if (pypy_execute_source(buffer)) {
exit(1);
}
free(buffer);
// add items to the pythonpath
struct uwsgi_string_list *usl = upypy.pp;
while(usl) {
if (uwsgi_pypy_hook_pythonpath) {
uwsgi_pypy_hook_pythonpath(usl->value);
}
usl = usl->next;
}
return 0;
}
static void uwsgi_pypy_preinit_apps() {
struct uwsgi_string_list *usl = upypy.eval;
while(usl) {
if (pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
}
usl = upypy.exec;
while(usl) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (pypy_execute_source(buffer)) {
exit(1);
}
free(buffer);
usl = usl->next;
}
}
static int uwsgi_pypy_request(struct wsgi_request *wsgi_req) {
/* Standard WSGI request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty pypy request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
if (uwsgi_pypy_hook_request) {
uwsgi_pypy_hook_request(wsgi_req, wsgi_req->async_id);
}
return UWSGI_OK;
}
static void uwsgi_pypy_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static void uwsgi_pypy_init_apps() {
if (uwsgi_pypy_hook_loader && upypy.wsgi) {
uwsgi_pypy_hook_loader(upypy.wsgi);
}
if (uwsgi_pypy_hook_file_loader && upypy.wsgi_file) {
uwsgi_pypy_hook_file_loader(upypy.wsgi_file);
}
}
/*
static void uwsgi_pypy_atexit() {
if (pypy_debug_file)
fflush(pypy_debug_file);
}
*/
static struct uwsgi_option uwsgi_pypy_options[] = {
{"pypy-lib", required_argument, 0, "set the path/name of the pypy library", uwsgi_opt_set_str, &upypy.lib, 0},
{"pypy-setup", required_argument, 0, "set the path of the python setup script", uwsgi_opt_set_str, &upypy.setup, 0},
{"pypy-home", required_argument, 0, "set the home of pypy library", uwsgi_opt_set_str, &upypy.home, 0},
{"pypy-wsgi", required_argument, 0, "load a WSGI module", uwsgi_opt_set_str, &upypy.wsgi, 0},
{"pypy-wsgi-file", required_argument, 0, "load a WSGI/mod_wsgi file", uwsgi_opt_set_str, &upypy.wsgi_file, 0},
{"pypy-eval", required_argument, 0, "evaluate pypy code before fork()", uwsgi_opt_add_string_list, &upypy.eval, 0},
{"pypy-eval-post-fork", required_argument, 0, "evaluate pypy code soon after fork()", uwsgi_opt_add_string_list, &upypy.eval_post_fork, 0},
{"pypy-exec", required_argument, 0, "execute pypy code from file before fork()", uwsgi_opt_add_string_list, &upypy.exec, 0},
{"pypy-exec-post-fork", required_argument, 0, "execute pypy code from file soon after fork()", uwsgi_opt_add_string_list, &upypy.exec_post_fork, 0},
{"pypy-pp", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0},
{"pypy-python-path", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0},
{"pypy-pythonpath", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static void uwsgi_pypy_enable_threads() {
if (pypy_init_threads) {
pypy_init_threads();
}
}
static void uwsgi_pypy_init_thread() {
if (pypy_thread_attach) {
pypy_thread_attach();
}
}
static int uwsgi_pypy_signal_handler(uint8_t sig, void *handler) {
void (*pypy_func)(int) = (void(*)(int)) handler;
pypy_func(sig);
return 0;
}
static uint16_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
int iargvs[UMAX8];
int i;
int (*pypy_func)(int, char **, int*, char *) = (int (*)(int, char **, int*, char *)) func;
// we convert 16bit to int
for(i=0;i<argc;i++) {
iargvs[i] = (int) argvs[i];
}
return pypy_func(argc, argv, iargvs, buffer);
}
static void uwsgi_pypy_post_fork() {
struct uwsgi_string_list *usl = upypy.eval_post_fork;
while(usl) {
if (pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
}
usl = upypy.exec_post_fork;
while(usl) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (pypy_execute_source(buffer)) {
exit(1);
}
free(buffer);
usl = usl->next;
}
if (uwsgi_pypy_post_fork_hook) {
uwsgi_pypy_post_fork_hook();
}
}
static void uwsgi_pypy_onload() {
#ifdef UWSGI_PYPY_HOME
upypy.home = UWSGI_PYPY_HOME;
#endif
}
struct uwsgi_plugin pypy_plugin = {
.name = "pypy",
.modifier1 = 0,
.on_load = uwsgi_pypy_onload,
.init = uwsgi_pypy_init,
.request = uwsgi_pypy_request,
.after_request = uwsgi_pypy_after_request,
.options = uwsgi_pypy_options,
.preinit_apps = uwsgi_pypy_preinit_apps,
.init_apps = uwsgi_pypy_init_apps,
.init_thread = uwsgi_pypy_init_thread,
.signal_handler = uwsgi_pypy_signal_handler,
.enable_threads = uwsgi_pypy_enable_threads,
.rpc = uwsgi_pypy_rpc,
.post_fork = uwsgi_pypy_post_fork,
};
+463
View File
@@ -0,0 +1,463 @@
import sys
import os
sys.path.insert(0, '.')
sys.path.extend(os.environ.get('PYTHONPATH','').split(os.pathsep))
import imp
import traceback
__name__ = '__main__'
mainmodule = type(sys)('__main__')
sys.modules['__main__'] = mainmodule
import cffi
# this is a list holding object we do not want to be freed (like callback and handlers)
uwsgi_gc = []
defines = '''
void free(void *);
void (*uwsgi_pypy_hook_loader)(char *);
void (*uwsgi_pypy_hook_file_loader)(char *);
void (*uwsgi_pypy_hook_pythonpath)(char *);
void (*uwsgi_pypy_hook_request)(void *, int);
void (*uwsgi_pypy_post_fork_hook)(void);
struct iovec {
char *iov_base;
uint64_t iov_len;
};
struct uwsgi_opt {
char *key;
char *value;
int configured;
};
char *uwsgi_binary_path();
void uwsgi_set_processname(char *);
void uwsgi_alarm_trigger(char *, char *, uint64_t);
int uwsgi_signal_registered(uint8_t);
int uwsgi_response_write_body_do(void *, char *, uint64_t);
int uwsgi_response_sendfile_do_can_close(void *, int, uint64_t, uint64_t, int);
int uwsgi_response_prepare_headers(void *, char *, uint16_t);
int uwsgi_response_add_header(void *, char *, uint16_t, char *, uint16_t);
char *uwsgi_request_body_read(void *, uint64_t, int64_t *);
char *uwsgi_request_body_readline(void *, uint64_t, int64_t *);
struct iovec *uwsgi_pypy_helper_environ(void *, uint16_t *);
char *uwsgi_pypy_helper_version();
int uwsgi_pypy_helper_register_signal(int, char *, void *);
int uwsgi_pypy_helper_register_rpc(char *, int, void *);
void uwsgi_pypy_helper_signal(int);
struct uwsgi_opt** uwsgi_pypy_helper_opts(int *);
int uwsgi_pypy_helper_masterpid();
int uwsgi_pypy_helper_worker_id();
int uwsgi_pypy_helper_mule_id();
char *uwsgi_cache_magic_get(char *, uint64_t, uint64_t *, uint64_t *, char *);
int uwsgi_cache_magic_set(char *, uint64_t, char *, uint64_t, uint64_t, uint64_t, char *);
int uwsgi_cache_magic_del(char *, uint64_t, char *);
int uwsgi_add_timer(uint8_t, int);
int uwsgi_add_rb_timer(uint8_t, int, int);
int uwsgi_add_file_monitor(uint8_t, char *);
char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint16_t *);
int uwsgi_signal_add_cron(uint8_t, int, int, int, int, int);
int uwsgi_user_lock(int);
int uwsgi_user_unlock(int);
'''
ffi = cffi.FFI()
ffi.cdef(defines)
lib = ffi.verify(defines)
libc = ffi.dlopen(None)
"""
this is a global object point the the WSGI callable
it sucks, i will fix it in the near future...
"""
wsgi_application = None
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
"""
load a wsgi module
"""
@ffi.callback("void(char *)")
def uwsgi_pypy_loader(module):
global wsgi_application
m = ffi.string(module)
c = 'application'
if ':' in m:
m, c = m.split(':')
if '.' in m:
mod = __import__(m, None, None, '*')
else:
mod = __import__(m)
wsgi_application = getattr(mod, c)
"""
load a mod_wsgi compliant .wsgi file
"""
@ffi.callback("void(char *)")
def uwsgi_pypy_file_loader(filename):
global wsgi_application
w = ffi.string(filename)
c = 'application'
mod = imp.load_source('uwsgi_file_wsgi', w)
wsgi_application = getattr(mod, c)
"""
.post_fork_hokk
"""
@ffi.callback("void()")
def uwsgi_pypy_post_fork_hook():
import uwsgi
if hasattr(uwsgi, 'post_fork_hook'):
uwsgi.post_fork_hook()
"""
add an item to the pythonpath
"""
@ffi.callback("void(char *)")
def uwsgi_pypy_pythonpath(item):
path = ffi.string(item)
sys.path.append(path)
print "added %s to pythonpath" % path
"""
class implementing wsgi.file_wrapper
"""
class WSGIfilewrapper(object):
def __init__(self, wsgi_req, f, chunksize=0):
self.wsgi_req = wsgi_req
self.f = f
self.chunksize = chunksize
if hasattr(f, 'close'):
self.close = f.close
def __iter__(self):
return self
def sendfile(self):
if hasattr(self.f, 'fileno'):
lib.uwsgi_response_sendfile_do_can_close(self.wsgi_req, self.f.fileno(), 0, 0, 0)
elif hasattr(self.f, 'read'):
if self.chunksize == 0:
chunk = self.f.read()
if len(chunk) > 0:
lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk))
return
while True:
chunk = self.f.read(self.chunksize)
if chunk is None or len(chunk) == 0:
break
lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk))
"""
class implementing wsgi.input
"""
class WSGIinput(object):
def __init__(self, wsgi_req):
self.wsgi_req = wsgi_req
def read(self, size=0):
rlen = ffi.new('int64_t*')
chunk = lib.uwsgi_request_body_read(self.wsgi_req, size, rlen)
if chunk != ffi.NULL:
return ffi.string(chunk, rlen[0])
if rlen[0] < 0:
raise IOError("error reading wsgi.input")
raise IOError("error waiting for wsgi.input")
def getline(self, hint=0):
rlen = ffi.new('int64_t*')
chunk = lib.uwsgi_request_body_readline(self.wsgi_req, hint, rlen)
if chunk != ffi.NULL:
return ffi.string(chunk, rlen[0])
if rlen[0] < 0:
raise IOError("error reading line from wsgi.input")
raise IOError("error waiting for line on wsgi.input")
def readline(self, hint=0):
return self.getline(hint)
def readlines(self, hint=0):
lines = []
while True:
chunk = self.getline(hint)
if len(chunk) == 0:
break
lines.append(chunk)
return lines
def __iter__(self):
return self
def __next__(self):
chunk = self.getline()
if len(chunk) == 0:
raise StopIteration
return chunk
"""
the WSGI request handler
"""
@ffi.callback("void(void *, int)")
def uwsgi_pypy_wsgi_handler(wsgi_req, core):
global wsgi_application
def writer(data):
lib.uwsgi_response_write_body_do(wsgi_req, ffi.new("char[]", data), len(data))
def start_response(status, headers, exc_info=None):
if exc_info:
traceback.print_exception(*exc_info)
lib.uwsgi_response_prepare_headers(wsgi_req, ffi.new("char[]", status), len(status))
for hh in headers:
lib.uwsgi_response_add_header(wsgi_req, ffi.new("char[]", hh[0]), len(hh[0]), ffi.new("char[]", hh[1]), len(hh[1]))
return writer
environ = {}
nv = ffi.new("uint16_t*")
iov = lib.uwsgi_pypy_helper_environ(wsgi_req, nv)
for i in range(0, nv[0], 2):
environ[ffi.string(iov[i].iov_base, iov[i].iov_len)] = ffi.string(iov[i+1].iov_base, iov[i+1].iov_len)
environ['wsgi.version'] = (1, 0)
scheme = 'http'
if 'HTTPS' in environ:
if environ['HTTPS'] in ('on', 'ON', 'On', '1', 'true', 'TRUE', 'True'):
scheme = 'https'
environ['wsgi.url_scheme'] = environ.get('UWSGI_SCHEME', scheme)
environ['wsgi.input'] = WSGIinput(wsgi_req)
environ['wsgi.errors'] = sys.stderr
environ['wsgi.run_once'] = False
environ['wsgi.file_wrapper'] = lambda f, chunksize=0: WSGIfilewrapper(wsgi_req, f, chunksize)
environ['wsgi.multithread'] = True
environ['wsgi.multiprocess'] = True
environ['uwsgi.core'] = core
response = wsgi_application(environ, start_response)
if type(response) is str:
writer(response)
else:
try:
if isinstance(response, WSGIfilewrapper):
response.sendfile()
else:
for chunk in response:
if isinstance(chunk, WSGIfilewrapper):
try:
chunk.sendfile()
finally:
chunk.close()
else:
writer(chunk)
finally:
if hasattr(response, 'close'):
response.close()
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
lib.uwsgi_pypy_hook_pythonpath = uwsgi_pypy_pythonpath
lib.uwsgi_pypy_hook_request = uwsgi_pypy_wsgi_handler
lib.uwsgi_pypy_post_fork_hook = uwsgi_pypy_post_fork_hook
"""
Here we define the "uwsgi" virtual module
"""
uwsgi = imp.new_module('uwsgi')
sys.modules['uwsgi'] = uwsgi
uwsgi.version = ffi.string(lib.uwsgi_pypy_helper_version())
def uwsgi_pypy_uwsgi_register_signal(signum, kind, handler):
cb = ffi.callback('void(int)', handler)
uwsgi_gc.append(cb)
if lib.uwsgi_pypy_helper_register_signal(signum, ffi.new("char[]", kind), cb) < 0:
raise Exception("unable to register signal %d" % signum)
uwsgi.register_signal = uwsgi_pypy_uwsgi_register_signal
class uwsgi_pypy_RPC(object):
def __init__(self, func):
self.func = func
def __call__(self, argc, argv, argvs, buf):
pargs = []
for i in range(0, argc):
pargs.append(ffi.string(argv[i], argvs[i]))
response = self.func(*pargs)
if len(response) > 0 and len(response) <= 65535:
dst = ffi.buffer(buf, 65536)
dst[:len(response)] = response
return len(response)
def uwsgi_pypy_uwsgi_register_rpc(name, func, argc=0):
rpc_func = uwsgi_pypy_RPC(func)
cb = ffi.callback("int(int, char*[], int[], char*)", rpc_func)
uwsgi_gc.append(cb)
if lib.uwsgi_pypy_helper_register_rpc(ffi.new("char[]", name), argc, cb) < 0:
raise Exception("unable to register rpc func %s" % name)
uwsgi.register_rpc = uwsgi_pypy_uwsgi_register_rpc
def uwsgi_pypy_rpc(node, func, *args):
argc = 0
argv = ffi.new('char*[256]')
argvs = ffi.new('uint16_t[256]')
rsize = ffi.new('uint16_t*')
for arg in args:
if argc >= 255:
raise Exception('invalid number of rpc arguments')
if len(arg) >= 65535:
raise Exception('invalid rpc argument size (must be < 65535)')
argv[argc] = ffi.new('char[]', arg)
argvs[argc] = len(arg)
argc += 1
if node:
c_node = ffi.new("char[]", node)
else:
c_node = ffi.NULL
response = lib.uwsgi_do_rpc(c_node, ffi.new("char[]",func), argc, argv, argvs, rsize)
if response:
ret = ffi.string(response, rsize[0])
lib.free(response)
return ret
return None
uwsgi.rpc = uwsgi_pypy_rpc
def uwsgi_pypy_call(func, *args):
node = None
if '@' in func:
(func, node) = func.split('@')
return uwsgi_pypy_rpc(node, func, *args)
uwsgi.call = uwsgi_pypy_call
def uwsgi_pypy_uwsgi_signal(signum):
lib.uwsgi_pypy_helper_signal(signum)
uwsgi.signal = uwsgi_pypy_uwsgi_signal
def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL):
vallen = ffi.new('uint64_t*')
value = lib.uwsgi_cache_magic_get(key, len(key), vallen, ffi.NULL, cache)
if value == ffi.NULL:
return None
ret = ffi.string(value, vallen[0])
libc.free(value)
return ret
uwsgi.cache_get = uwsgi_pypy_uwsgi_cache_get
def uwsgi_pypy_uwsgi_cache_set(key, value, expires=0, cache=ffi.NULL):
if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 0, cache) < 0:
raise Exception('unable to store item in the cache')
uwsgi.cache_set = uwsgi_pypy_uwsgi_cache_set
def uwsgi_pypy_uwsgi_cache_update(key, value, expires=0, cache=ffi.NULL):
if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 1 << 1, cache) < 0:
raise Exception('unable to store item in the cache')
uwsgi.cache_update = uwsgi_pypy_uwsgi_cache_update
def uwsgi_pypy_uwsgi_cache_del(key, cache=ffi.NULL):
if lib.uwsgi_cache_magic_del(key, len(key), cache) < 0:
raise Exception('unable to delete item from the cache')
uwsgi.cache_del = uwsgi_pypy_uwsgi_cache_del
def uwsgi_pypy_uwsgi_add_timer(signum, secs):
if lib.uwsgi_add_timer(signum, secs) < 0:
raise Exception("unable to register timer")
uwsgi.add_timer = uwsgi_pypy_uwsgi_add_timer
def uwsgi_pypy_uwsgi_add_rb_timer(signum, secs):
if lib.uwsgi_add_rb_timer(signum, secs, 0) < 0:
raise Exception("unable to register redblack timer")
uwsgi.add_rb_timer = uwsgi_pypy_uwsgi_add_rb_timer
def uwsgi_pypy_uwsgi_add_file_monitor(signum, filename):
if lib.uwsgi_add_file_monitor(signum, ffi.new("char[]", filename)) < 0:
raise Exception("unable to register file monitor")
uwsgi.add_file_monitor = uwsgi_pypy_uwsgi_add_file_monitor
def uwsgi_pypy_lock(num):
if lib.uwsgi_user_lock(num) < 0:
raise Exception("invalid lock")
uwsgi.lock = uwsgi_pypy_lock
def uwsgi_pypy_unlock(num):
if lib.uwsgi_user_unlock(num) < 0:
raise Exception("invalid lock")
uwsgi.unlock = uwsgi_pypy_unlock
def uwsgi_pypy_masterpid():
return lib.uwsgi_pypy_helper_masterpid()
uwsgi.masterpid = uwsgi_pypy_masterpid
def uwsgi_pypy_worker_id():
return lib.uwsgi_pypy_helper_worker_id()
uwsgi.worker_id = uwsgi_pypy_worker_id
def uwsgi_pypy_mule_id():
return lib.uwsgi_pypy_helper_mule_id()
uwsgi.mule_id = uwsgi_pypy_mule_id
def uwsgi_pypy_signal_registered(signum):
if lib.uwsgi_signal_registered(signum) > 0:
return True
return False
uwsgi.signal_registered = uwsgi_pypy_signal_registered
def uwsgi_pypy_alarm(alarm, msg):
lib.uwsgi_alarm_trigger(ffi.new('char[]', alarm), ffi.new('char[]', msg), len(msg))
uwsgi.alarm = uwsgi_pypy_alarm
def uwsgi_pypy_setprocname(name):
lib.uwsgi_set_processname(ffi.new('char[]',name))
uwsgi.setprocname = uwsgi_pypy_setprocname
def uwsgi_pypy_add_cron(signum, minute, hour, day, month, week):
if lib.uwsgi_signal_add_cron(signum, minute, hour, day, month, week) < 0:
raise Exception("unable to register cron")
return True
uwsgi.add_cron = uwsgi_pypy_add_cron
"""
populate uwsgi.opt
"""
uwsgi.opt = {}
n_opts = ffi.new('int*')
u_opts = lib.uwsgi_pypy_helper_opts(n_opts)
for i in range(0, n_opts[0]):
k = ffi.string(u_opts[i].key)
if u_opts[i].value == ffi.NULL:
v = True
else:
v = ffi.string(u_opts[i].value)
if k in uwsgi.opt:
if type(uwsgi.opt[k]) is list:
uwsgi.opt[k].append(v)
else:
uwsgi.opt[k] = [uwsgi.opt[k], v]
else:
uwsgi.opt[k] = v
print "Initialized PyPy with Python", sys.version
print "PyPy Home:", sys.prefix
+10 -11
View File
@@ -1,13 +1,12 @@
import os,sys
from distutils import sysconfig
NAME='pypy'
GCC_LIST = ['../python/python_plugin', '../python/pyutils', '../python/pyloader', '../python/wsgi_handlers', '../python/wsgi_headers', '../python/wsgi_subhandler',
'../python/web3_subhandler', '../python/pump_subhandler','../python/gil', '../python/uwsgi_pymodule', '../python/profiler', '../python/symimporter']
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
CFLAGS.append('-DUWSGI_PYPY')
LIBS = ['-lpypy-c']
LDFLAGS = []
LIBS = []
GCC_LIST = ['pypy_plugin']
BINARY_LIST = [ ('uwsgi_pypy_setup','pypy_setup.py')]
CFLAGS = []
try:
import __pypy__
import sys
CFLAGS.append('-DUWSGI_PYPY_HOME="\\"%s\\""' % sys.prefix)
except:
pass
+2 -2
View File
@@ -5,7 +5,7 @@ extern struct uwsgi_python up;
void gil_real_get() {
//uwsgi_log("LOCK %d\n", uwsgi.mywid);
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
#if !defined(PYTHREE)
PyEval_AcquireLock();
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_gil_key));
#else
@@ -17,7 +17,7 @@ void gil_real_get() {
void gil_real_release() {
//uwsgi_log("UNLOCK %d\n", uwsgi.mywid);
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
#if !defined(PYTHREE)
pthread_setspecific(up.upt_gil_key, (void *) PyThreadState_Swap(NULL));
PyEval_ReleaseLock();
#else
-4
View File
@@ -15,7 +15,6 @@ int PyFrame_GetLineNumber(PyFrameObject *frame) {
int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
#ifndef UWSGI_PYPY
static uint64_t last_ts = 0;
uint64_t now = uwsgi_micros();
uint64_t delta = 0;
@@ -42,14 +41,12 @@ int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, Py
PyEval_GetFuncName(arg), frame->f_code->co_argcount, frame->f_code->co_stacksize);
break;
}
#endif
return 0;
}
int uwsgi_python_tracer(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
#ifndef UWSGI_PYPY
static uint64_t last_ts = 0;
uint64_t now = uwsgi_micros();
uint64_t delta = 0;
@@ -64,7 +61,6 @@ int uwsgi_python_tracer(PyObject *obj, PyFrameObject *frame, int what, PyObject
last_ts = now;
uwsgi_log("[uWSGI Python profiler %llu] file %s line %d: %s argc:%d\n", (unsigned long long)delta, PyString_AsString(frame->f_code->co_filename), PyFrame_GetLineNumber(frame), PyString_AsString(frame->f_code->co_name), frame->f_code->co_argcount);
}
#endif
return 0;
}
-5
View File
@@ -672,10 +672,6 @@ PyObject *uwsgi_paste_loader(void *arg1) {
PyObject *uwsgi_eval_loader(void *arg1) {
#ifdef UWSGI_PYPY
uwsgi_log("the eval loader is currently not supported under PyPy !!!\n");
return NULL;
#else
char *code = (char *) arg1;
PyObject *wsgi_eval_module, *wsgi_eval_callable = NULL;
@@ -731,7 +727,6 @@ PyObject *uwsgi_eval_loader(void *arg1) {
}
return wsgi_eval_callable;
#endif
}
+20 -45
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;
@@ -44,11 +52,7 @@ void uwsgi_opt_pyrun(char *opt, char *value, void *foobar) {
}
void uwsgi_opt_pyver(char *opt, char *foo, void *bar) {
#ifndef UWSGI_PYPY
const char *version = Py_GetVersion();
#else
const char *version = PYPY_VERSION;
#endif
const char *space = strchr(version, ' ');
if (space) {
fprintf(stdout, "%.*s\n", (int) (space-version), version);
@@ -128,9 +132,7 @@ struct uwsgi_option uwsgi_python_options[] = {
{"ini-paste-logged", required_argument, 0, "load a paste.deploy config file containing uwsgi section (load loggers too)", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
{"reload-os-env", no_argument, 0, "force reload of os.environ at each request", uwsgi_opt_true, &up.reload_os_env, 0},
#ifndef __CYGWIN__
#ifndef UWSGI_PYPY
{"no-site", no_argument, 0, "do not import site module", uwsgi_opt_true, &Py_NoSiteFlag, 0},
#endif
#endif
{"pyshell", optional_argument, 0, "run an interactive python shell in the uWSGI environment", uwsgi_opt_pyshell, NULL, 0},
{"pyshell-oneshot", optional_argument, 0, "run an interactive python shell in the uWSGI environment (one-shot variant)", uwsgi_opt_pyshell, NULL, 0},
@@ -139,9 +141,8 @@ struct uwsgi_option uwsgi_python_options[] = {
{"py", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
{"pyrun", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
#ifndef UWSGI_PYPY
{"py-tracebacker", required_argument, 0, "enable the uWSGI python tracebacker", uwsgi_opt_set_str, &up.tracebacker, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
#endif
{"py-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
{"py-autoreload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
{"python-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
@@ -175,7 +176,6 @@ PyMethodDef uwsgi_write_method[] = { {"uwsgi_write", py_uwsgi_write, METH_VARARG
int uwsgi_python_init() {
#ifndef UWSGI_PYPY
char *pyversion = strchr(Py_GetVersion(), '\n');
if (!pyversion) {
uwsgi_log_initial("Python version: %s\n", Py_GetVersion());
@@ -183,9 +183,6 @@ int uwsgi_python_init() {
else {
uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
}
#else
uwsgi_log_initial("PyPy version: %s\n", PYPY_VERSION);
#endif
if (up.home != NULL) {
#ifdef PYTHREE
@@ -237,9 +234,7 @@ pep405:
#endif
#ifndef UWSGI_PYPY
Py_OptimizeFlag = up.optimize;
#endif
Py_Initialize();
@@ -278,9 +273,6 @@ void uwsgi_python_reset_random_seed() {
random_seed = PyDict_GetItemString(random_dict, "seed");
if (random_seed) {
PyObject *random_args = PyTuple_New(1);
#ifdef UWSGI_PYPY
Py_INCREF(Py_None);
#endif
// pass no args
PyTuple_SetItem(random_args, 0, Py_None);
PyEval_CallObject(random_seed, random_args);
@@ -367,13 +359,11 @@ void uwsgi_python_post_fork() {
pthread_t par_tid;
pthread_create(&par_tid, NULL, uwsgi_python_autoreloader_thread, NULL);
}
#ifndef UWSGI_PYPY
if (up.tracebacker) {
// spawn the tracebacker thread
pthread_t ptb_tid;
pthread_create(&ptb_tid, NULL, uwsgi_python_tracebacker_thread, NULL);
}
#endif
}
UWSGI_RELEASE_GIL
@@ -382,10 +372,6 @@ UWSGI_RELEASE_GIL
PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) {
#ifdef UWSGI_PYPY
uwsgi_log("import by filename is currently not supported on PyPy !!!\n");
return NULL;
#else
FILE *pyfile;
struct _node *py_file_node = NULL;
PyObject *py_compiled_node, *py_file_module;
@@ -471,7 +457,6 @@ PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) {
Py_DECREF(py_compiled_node);
return py_file_module;
#endif
}
@@ -492,7 +477,11 @@ void init_uwsgi_vars() {
#ifdef PYTHREE
// fix stdout and stderr
PyObject *new_stdprint = PyFile_NewStdPrinter(2);
#ifdef HAS_NO_ERRORS_IN_PyFile_FromFd
PyObject *new_stdprint = PyFile_FromFd(2, NULL, "w", _IOLBF, NULL, NULL, 0);
#else
PyObject *new_stdprint = PyFile_FromFd(2, NULL, "w", _IOLBF, NULL, NULL, NULL, 0);
#endif
PyDict_SetItemString(pysys_dict, "stdout", new_stdprint);
PyDict_SetItemString(pysys_dict, "__stdout__", new_stdprint);
PyDict_SetItemString(pysys_dict, "stderr", new_stdprint);
@@ -1059,13 +1048,11 @@ void uwsgi_python_init_apps() {
UWSGI_GET_GIL;
}
#ifndef UWSGI_PYPY
// prepare for stack suspend/resume
if (uwsgi.async > 1) {
up.current_recursion_depth = uwsgi_malloc(sizeof(int)*uwsgi.async);
up.current_frame = uwsgi_malloc(sizeof(struct _frame)*uwsgi.async);
}
#endif
// setup app loaders
up.loaders[LOADER_DYN] = uwsgi_dyn_loader;
@@ -1152,7 +1139,6 @@ next:
init_uwsgi_app(LOADER_UWSGI, up.wsgi_lite, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI_LITE);
}
#ifndef UWSGI_PYPY
if (uwsgi.profiler) {
if (!strcmp(uwsgi.profiler, "pycall")) {
PyEval_SetProfile(uwsgi_python_profiler_call, NULL);
@@ -1161,7 +1147,6 @@ next:
PyEval_SetTrace(uwsgi_python_tracer, NULL);
}
}
#endif
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
@@ -1417,7 +1402,6 @@ void *uwsgi_python_autoreloader_thread(void *foobar) {
return NULL;
}
#ifndef UWSGI_PYPY
void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
PyGILState_STATE pgst = PyGILState_Ensure();
@@ -1434,7 +1418,6 @@ void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
}
}
#endif
char *uwsgi_python_code_string(char *id, char *code, char *function, char *key, uint16_t keylen) {
@@ -1629,7 +1612,6 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
return -1;
}
#ifndef UWSGI_PYPY
void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
PyGILState_STATE pgst = PyGILState_Ensure();
@@ -1646,7 +1628,6 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
}
}
#endif
void uwsgi_python_fixup() {
// set hacky modifier 30
@@ -1660,7 +1641,6 @@ void uwsgi_python_hijack(void) {
// the pyshell will be execute only in the first worker
#ifndef UWSGI_PYPY
FILE *pyfile;
if (up.pyrun) {
uwsgi.workers[uwsgi.mywid].hijacked = 1;
@@ -1674,7 +1654,6 @@ void uwsgi_python_hijack(void) {
// could be never executed
exit(0);
}
#endif
if (up.pyshell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) {
uwsgi.workers[uwsgi.mywid].hijacked = 0;
@@ -1700,9 +1679,7 @@ void uwsgi_python_hijack(void) {
else {
PyImport_ImportModule("readline");
#ifndef UWSGI_PYPY
ret = PyRun_InteractiveLoop(stdin, "uwsgi");
#endif
}
if (up.pyshell_oneshot) {
exit(UWSGI_DE_HIJACKED_CODE);
@@ -1779,7 +1756,12 @@ void uwsgi_python_harakiri(int wid) {
}
}
/*
# you can use this logger to offload logging to python
# be sure to configure it to not log to stderr otherwise you will generate a loop
import logging
logging.basicConfig(filename='/tmp/pippo.log')
*/
ssize_t uwsgi_python_logger(struct uwsgi_logger *ul, char *message, size_t len) {
if (!Py_IsInitialized()) return -1;
@@ -1822,13 +1804,8 @@ void uwsgi_python_on_load() {
uwsgi_register_logger("python", uwsgi_python_logger);
}
#ifndef UWSGI_PYPY
struct uwsgi_plugin python_plugin = {
.name = "python",
#else
struct uwsgi_plugin pypy_plugin = {
.name = "pypy",
#endif
.alias = "python",
.modifier1 = 0,
.init = uwsgi_python_init,
@@ -1850,10 +1827,8 @@ struct uwsgi_plugin pypy_plugin = {
.magic = uwsgi_python_magic,
#ifndef UWSGI_PYPY
.suspend = uwsgi_python_suspend,
.resume = uwsgi_python_resume,
#endif
.harakiri = uwsgi_python_harakiri,
+5 -4
View File
@@ -10,14 +10,14 @@ int manage_python_response(struct wsgi_request *wsgi_req) {
char *uwsgi_python_get_exception_type(PyObject *exc) {
char *class_name = NULL;
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
#if !defined(PYTHREE)
if (PyClass_Check(exc)) {
class_name = PyString_AsString( ((PyClassObject*)(exc))->cl_name );
}
else {
#endif
class_name = (char *) ((PyTypeObject*)exc)->tp_name;
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
#if !defined(PYTHREE)
}
#endif
@@ -301,8 +301,9 @@ void init_pyargv() {
#endif
if (*ap != '\0') {
#ifdef PYTHREE
mbstowcs( wcargv + strlen(ap), ap, strlen(ap));
up.py_argv[up.argc] = wcargv + strlen(ap);
mbstowcs( wcargv, ap, strlen(ap));
up.py_argv[up.argc] = wcargv;
wcargv += strlen(ap) + 1;
#else
up.py_argv[up.argc] = ap;
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "uwsgi_python.h"
#ifndef UWSGI_PYPY
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
@@ -806,5 +804,3 @@ int uwsgi_init_symbol_import() {
return 0;
}
#endif
+132 -2
View File
@@ -2555,7 +2555,7 @@ PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) {
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#s#|is:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) {
if (!PyArg_ParseTuple(args, "s#s#|ls:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) {
return NULL;
}
@@ -2582,7 +2582,7 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#s#|is:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) {
if (!PyArg_ParseTuple(args, "s#s#|ls:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) {
return NULL;
}
@@ -2599,6 +2599,106 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_cache_inc(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 1;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_inc", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_INC, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_dec(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 1;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_dec", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DEC, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_mul(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 2;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_mul", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_MUL, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_div(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *remote = NULL;
int64_t value = 2;
uint64_t expires = 0;
if (!PyArg_ParseTuple(args, "s#|lls:cache_div", &key, &keylen, &value, &expires, &remote)) {
return NULL;
}
UWSGI_RELEASE_GIL
if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DIV, remote)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) {
@@ -2940,6 +3040,31 @@ PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_cache_num(PyObject * self, PyObject * args) {
char *key;
Py_ssize_t keylen = 0;
char *cache = NULL;
if (!PyArg_ParseTuple(args, "s#|s:cache_num", &key, &keylen, &cache)) {
return NULL;
}
uint64_t vallen = 0;
UWSGI_RELEASE_GIL
char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache);
UWSGI_GET_GIL
if (value && vallen == 8) {
int64_t *num = (int64_t *) value;
PyObject *ret = PyLong_FromLong(*num);
free(value);
return ret;
}
return PyLong_FromLong(0);
}
static PyMethodDef uwsgi_cache_methods[] = {
{"cache_get", py_uwsgi_cache_get, METH_VARARGS, ""},
{"cache_set", py_uwsgi_cache_set, METH_VARARGS, ""},
@@ -2947,6 +3072,11 @@ static PyMethodDef uwsgi_cache_methods[] = {
{"cache_del", py_uwsgi_cache_del, METH_VARARGS, ""},
{"cache_exists", py_uwsgi_cache_exists, METH_VARARGS, ""},
{"cache_clear", py_uwsgi_cache_clear, METH_VARARGS, ""},
{"cache_inc", py_uwsgi_cache_inc, METH_VARARGS, ""},
{"cache_dec", py_uwsgi_cache_dec, METH_VARARGS, ""},
{"cache_mul", py_uwsgi_cache_mul, METH_VARARGS, ""},
{"cache_div", py_uwsgi_cache_div, METH_VARARGS, ""},
{"cache_num", py_uwsgi_cache_num, METH_VARARGS, ""},
{NULL, NULL},
};
+4
View File
@@ -22,6 +22,10 @@
#define HAS_NOT_PyFrame_GetLineNumber
#endif
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0
#define HAS_NO_ERRORS_IN_PyFile_FromFd
#endif
#if PY_MAJOR_VERSION > 2
#define PYTHREE
#endif
-4
View File
@@ -14,10 +14,6 @@ NAME='python'
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'web3_subhandler', 'pump_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter', 'tracebacker']
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
if 'pypy_version_info' in sys.__dict__:
CFLAGS.append('-DUWSGI_PYPY')
LDFLAGS = []
if not 'UWSGI_PYTHON_NOLIB' in os.environ:
+28 -10
View File
@@ -2,6 +2,7 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern struct uwsgi_plugin python_plugin;
PyObject *uwsgi_Input_iter(PyObject *self) {
@@ -293,8 +294,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
struct uwsgi_app *wi;
if (wsgi_req->async_status == UWSGI_AGAIN) {
if (wsgi_req->async_force_again) {
wi = &uwsgi_apps[wsgi_req->app_id];
wsgi_req->async_force_again = 0;
UWSGI_GET_GIL
// get rid of timeout
if (wsgi_req->async_timed_out) {
@@ -315,6 +317,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
int ret = manage_python_response(wsgi_req);
if (ret == UWSGI_OK) goto end;
UWSGI_RELEASE_GIL
if (ret == UWSGI_AGAIN) {
wsgi_req->async_force_again = 1;
}
return ret;
}
@@ -328,13 +333,15 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
return -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);
}
if (wsgi_req->dynamic) {
// this part must be heavy locked in threaded modes
if (uwsgi.threads > 1) {
pthread_mutex_lock(&up.lock_pyloaders);
}
}
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, python_plugin.modifier1)) == -1) {
if (wsgi_req->dynamic) {
UWSGI_GET_GIL
if (uwsgi.single_interpreter) {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
@@ -343,12 +350,22 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL, PYTHON_APP_TYPE_WSGI);
}
UWSGI_RELEASE_GIL
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
}
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
if (uwsgi_apps[uwsgi.default_app].modifier1 == python_plugin.modifier1) {
wsgi_req->app_id = uwsgi.default_app;
}
}
}
if (wsgi_req->dynamic) {
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
}
if (wsgi_req->app_id == -1) {
uwsgi_500(wsgi_req);
uwsgi_log("--- no python application found, check your startup logs for errors ---\n");
@@ -388,6 +405,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
while (wi->response_subhandler(wsgi_req) != UWSGI_OK) {
if (uwsgi.async > 1) {
UWSGI_RELEASE_GIL
wsgi_req->async_force_again = 1;
return UWSGI_AGAIN;
}
else {
+2 -1
View File
@@ -80,7 +80,7 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
Py_DECREF(zero);
#endif
return PyErr_Format(PyExc_TypeError, "unable to set HTTP status line");
goto end;
}
#ifdef PYTHREE
@@ -193,6 +193,7 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
UWSGI_GET_GIL
}
end:
Py_INCREF(up.wsgi_writeout);
return up.wsgi_writeout;
}
+59 -8
View File
@@ -4,6 +4,44 @@ extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern PyTypeObject uwsgi_InputType;
/*
this is a hack for supporting non-file object passed to wsgi.file_wrapper
*/
static void uwsgi_python_consume_file_wrapper_read(struct wsgi_request *wsgi_req, PyObject *pychunk) {
PyObject *read_method_args = NULL;
PyObject *read_method = PyObject_GetAttrString(pychunk, "read");
if (wsgi_req->sendfile_fd_chunk > 0) {
read_method_args = PyTuple_New(1);
PyTuple_SetItem(read_method_args, 0, PyInt_FromLong(wsgi_req->sendfile_fd_chunk));
}
else {
read_method_args = PyTuple_New(0);
}
for(;;) {
PyObject *read_method_output = PyEval_CallObject(read_method, read_method_args);
if (PyErr_Occurred()) {
uwsgi_manage_exception(wsgi_req, 0);
break;
}
if (!read_method_output) break;
if (PyString_Check(read_method_output)) {
char *content = PyString_AsString(read_method_output);
size_t content_len = PyString_Size(read_method_output);
if (content_len == 0) {
Py_DECREF(read_method_output);
break;
}
UWSGI_RELEASE_GIL
uwsgi_response_write_body_do(wsgi_req, content, content_len);
UWSGI_GET_GIL
}
Py_DECREF(read_method_output);
if (wsgi_req->sendfile_fd_chunk == 0) break;
}
Py_DECREF(read_method_args);
Py_DECREF(read_method);
}
void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
@@ -143,10 +181,16 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
}
if (wsgi_req->sendfile_obj == wsgi_req->async_result && wsgi_req->sendfile_fd != -1) {
UWSGI_RELEASE_GIL
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
UWSGI_GET_GIL
if (wsgi_req->sendfile_obj == wsgi_req->async_result) {
if (wsgi_req->sendfile_fd >= 0) {
UWSGI_RELEASE_GIL
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
UWSGI_GET_GIL
}
// we do not have an iterable, check for read() method
else if (PyObject_HasAttrString((PyObject *)wsgi_req->async_result, "read")) {
uwsgi_python_consume_file_wrapper_read(wsgi_req, (PyObject *)wsgi_req->async_result);
}
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
}
@@ -190,10 +234,17 @@ exception:
}
}
else if (wsgi_req->sendfile_obj == pychunk && wsgi_req->sendfile_fd != -1) {
UWSGI_RELEASE_GIL
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
UWSGI_GET_GIL
else if (wsgi_req->sendfile_obj == pychunk) {
if (wsgi_req->sendfile_fd >= 0) {
UWSGI_RELEASE_GIL
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
UWSGI_GET_GIL
}
// we do not have an iterable, check for read() method
else if (PyObject_HasAttrString(pychunk, "read")) {
uwsgi_python_consume_file_wrapper_read(wsgi_req, pychunk);
}
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
Py_DECREF(pychunk);
+5 -6
View File
@@ -888,7 +888,9 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
status = rb_obj_as_string(RARRAY_PTR(ret)[0]);
// get the status code
uwsgi_response_prepare_headers(wsgi_req, RSTRING_PTR(status), RSTRING_LEN(status));
if (uwsgi_response_prepare_headers(wsgi_req, RSTRING_PTR(status), RSTRING_LEN(status))) {
goto clear;
}
headers = RARRAY_PTR(ret)[1] ;
if (rb_respond_to( headers, rb_intern("each") )) {
@@ -957,18 +959,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 ) {
+3
View File
@@ -163,6 +163,8 @@ static ssize_t rr_instance_connected(struct corerouter_peer *peer) {
struct rawrouter_session *rr = (struct rawrouter_session *) cs;
cr_peer_connected(peer, "rr_instance_connected()");
peer->can_retry = 0;
if (rr->xclient) {
cr_reset_hooks_and_read(peer, rr_xclient_read);
return 1;
@@ -251,6 +253,7 @@ static int rawrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_ga
return -1;
}
peer->can_retry = 1;
cr_connect(peer, rr_instance_connected);
return 0;
}
+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 = {
+346 -4
View File
@@ -23,9 +23,17 @@ struct uwsgi_router_cache_conf {
char *key;
size_t key_len;
char *var;
size_t var_len;
char *value;
size_t value_len;
// use mime types ?
char *mime;
char *as_num;
#ifdef UWSGI_ZLIB
char *gzip;
size_t gzip_len;
@@ -41,6 +49,14 @@ struct uwsgi_router_cache_conf {
char *expires_str;
uint64_t expires;
int64_t default_num;
uint64_t flags;
char *status_str;
int status;
char *no_offload;
};
// this is allocated for each transformation
@@ -50,15 +66,22 @@ struct uwsgi_transformation_cache_conf {
struct uwsgi_buffer *cache_it_gzip;
#endif
int status;
struct uwsgi_buffer *value;
struct uwsgi_buffer *cache_it_to;
uint64_t cache_it_expires;
};
static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
struct uwsgi_transformation_cache_conf *utcc = (struct uwsgi_transformation_cache_conf *) data;
static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_cache_conf *utcc = (struct uwsgi_transformation_cache_conf *) ut->data;
struct uwsgi_buffer *ub = ut->chunk;
// force value
if (utcc->value) {
ub = utcc->value;
}
// store only successfull response
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
if (wsgi_req->write_errors == 0 && (wsgi_req->status == 200 || (utcc->status && wsgi_req->status == utcc->status)) && ub->pos > 0) {
if (utcc->cache_it) {
uwsgi_cache_magic_set(utcc->cache_it->buf, utcc->cache_it->pos, ub->buf, ub->pos, utcc->cache_it_expires,
UWSGI_CACHE_FLAG_UPDATE, utcc->cache_it_to ? utcc->cache_it_to->buf : NULL);
@@ -81,6 +104,7 @@ static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_buffer *u
if (utcc->cache_it_gzip) uwsgi_buffer_destroy(utcc->cache_it_gzip);
#endif
if (utcc->cache_it_to) uwsgi_buffer_destroy(utcc->cache_it_to);
if (utcc->value) uwsgi_buffer_destroy(utcc->value);
free(utcc);
return 0;
}
@@ -104,6 +128,13 @@ static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct
if (!utcc->cache_it_to) goto error;
}
if (urcc->value) {
utcc->value = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
if (!utcc->value) goto error;
}
utcc->status = urcc->status;
#ifdef UWSGI_ZLIB
if (urcc->gzip) {
utcc->cache_it_gzip = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->gzip, urcc->gzip_len);
@@ -159,6 +190,13 @@ static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_
if (uwsgi_response_add_expires(wsgi_req, expires)) goto error;
}
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
if (wsgi_req->socket->can_offload && !ur->custom && !urcc->no_offload) {
if (!uwsgi_offload_request_memory_do(wsgi_req, value, valsize)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
return UWSGI_ROUTE_BREAK;
}
}
uwsgi_response_write_body_do(wsgi_req, value, valsize);
free(value);
if (ur->custom)
@@ -172,6 +210,102 @@ error:
return UWSGI_ROUTE_BREAK;
}
// place a cache value in a request var
static int uwsgi_routing_func_cachevar(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, NULL, urcc->name);
uwsgi_buffer_destroy(ub);
if (value) {
if (urcc->as_num) {
char *tmp = value;
if (valsize == 8) {
int64_t *num = (int64_t *) value;
value = uwsgi_64bit2str(*num);
}
else {
value = uwsgi_64bit2str(0);
}
free(tmp);
}
if (!uwsgi_req_append(wsgi_req, urcc->var, urcc->var_len, value, valsize)) {
free(value);
return UWSGI_ROUTE_BREAK;
}
free(value);
}
return UWSGI_ROUTE_NEXT;
}
// set a cache item
static int uwsgi_routing_func_cacheset(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
if (!ub_val) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
if (uwsgi_cache_magic_set(ub->buf, ub->pos, ub_val->buf, ub_val->pos, urcc->expires, 0, urcc->name)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_val);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_val);
return UWSGI_ROUTE_NEXT;
}
// cacheinc/cachedec/cachemul/cachediv
static int uwsgi_routing_func_cachemath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
int64_t num = urcc->default_num;
if (urcc->value) {
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len);
if (!ub_val) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
num = strtol(ub_val->buf, NULL, 10);
uwsgi_buffer_destroy(ub_val);
}
if (uwsgi_cache_magic_set(ub->buf, ub->pos, (char *) &num, 8, urcc->expires, urcc->flags, urcc->name)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cache_store;
ur->data = args;
@@ -183,6 +317,9 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
"gzip", &urcc->gzip,
#endif
"name", &urcc->name,
"value", &urcc->value,
"status", &urcc->status_str,
"code", &urcc->status_str,
"expires", &urcc->expires_str, NULL)) {
uwsgi_log("invalid cachestore route syntax: %s\n", args);
goto error;
@@ -211,6 +348,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:
@@ -232,6 +377,7 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
"content_encoding", &urcc->content_encoding,
"mime", &urcc->mime,
"name", &urcc->name,
"no_offload", &urcc->no_offload,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
@@ -264,11 +410,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 = {
+146
View File
@@ -0,0 +1,146 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
extern struct uwsgi_server uwsgi;
/*
by Unbit
syntax:
route = /^foobar1(.*)/ hash:key=foo$1poo,algo=murmur2,var=MYHASH,items=node1;node2;node3
*/
struct uwsgi_router_hash_conf {
char *key;
size_t key_len;
char *var;
size_t var_len;
char *algo;
char *items;
size_t items_len;
};
static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_hash_conf *urhc = (struct uwsgi_router_hash_conf *) ur->data2;
struct uwsgi_hash_algo *uha = uwsgi_hash_algo_get(urhc->algo);
if (!uha) {
uwsgi_log("[uwsgi-hash-router] unable to find hash algo \"%s\"\n", urhc->algo);
return UWSGI_ROUTE_BREAK;
}
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, urhc->key, urhc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint32_t h = uha->func(ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
// now count the number of items
uint32_t items = 1;
size_t i, ilen = urhc->items_len;
for(i=0;i<ilen;i++) {
if (urhc->items[i] == ';') items++;
}
// skip last semicolon
if (urhc->items[ilen-1] == ';') items--;
uint32_t hashed_result = h % items;
uint32_t found = 0;
char *value = urhc->items;
uint16_t vallen = 0;
for(i=0;i<ilen;i++) {
if (!value) {
value = urhc->items + i;
}
if (urhc->items[i] == ';') {
if (found == hashed_result) {
vallen = (urhc->items+i) - value;
break;
}
value = NULL;
found++;
}
}
if (vallen == 0) {
// first item
if (hashed_result == 0) {
value = urhc->items;
vallen = urhc->items_len;
}
// last item
else {
vallen = (urhc->items + urhc->items_len) - value;
}
}
if (!vallen) {
uwsgi_log("[uwsgi-hash-router] BUG !!! unable to hash items\n");
return UWSGI_ROUTE_BREAK;
}
if (!uwsgi_req_append(wsgi_req, urhc->var, urhc->var_len, value, vallen)) {
uwsgi_log("[uwsgi-hash-router] unable to append hash var to the request\n");
return UWSGI_ROUTE_BREAK;
}
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_hash(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_hash;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_hash_conf *urhc = uwsgi_calloc(sizeof(struct uwsgi_router_hash_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urhc->key,
"var", &urhc->var,
"algo", &urhc->algo,
"items", &urhc->items,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urhc->key || !urhc->var || !urhc->items) {
uwsgi_log("invalid route syntax: you need to specify a hash key, a var and a set of items\n");
exit(1);
}
urhc->key_len = strlen(urhc->key);
urhc->var_len = strlen(urhc->var);
urhc->items_len = strlen(urhc->items);
if (!urhc->algo) urhc->algo = "djb33x";
ur->data2 = urhc;
return 0;
}
static void router_hash_register() {
uwsgi_register_router("hash", uwsgi_router_hash);
}
struct uwsgi_plugin router_hash_plugin = {
.name = "router_hash",
.on_load = router_hash_register,
};
#else
struct uwsgi_plugin router_hash_plugin = {
.name = "router_hash",
};
#endif
+6
View File
@@ -0,0 +1,6 @@
NAME='router_hash'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['router_hash']
+174 -33
View File
@@ -1,20 +1,24 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
#define MEMCACHED_BUFSIZE 8192
extern struct uwsgi_server uwsgi;
/*
memcached internal router
memcached internal router and transformation
route = /^foobar1(.*)/ memcached:addr=127.0.0.1:11211,key=foo$1poo,type=body
route = /^foobar1(.*)/ memcached:addr=127.0.0.1:11211,key=foo$1poo
route = /^foobar1(.*)/ memcachedstore:addr=127.0.0.1:11211,key=foo$1poo
*/
struct uwsgi_router_memcached_conf {
char *addr;
size_t addr_len;
char *key;
size_t key_len;
@@ -22,12 +26,19 @@ struct uwsgi_router_memcached_conf {
char *content_type;
size_t content_type_len;
// 0 -> full, 1 -> body
char *type;
int type_num;
char *no_offload;
char *expires;
};
// this is allocated for each transformation
struct uwsgi_transformation_memcached_conf {
struct uwsgi_buffer *addr;
struct uwsgi_buffer *key;
char *expires;
};
static size_t memcached_firstline_parse(char *buf, size_t len) {
// check for "VALUE x 0 0"
if (len < 11) return 0;
@@ -48,6 +59,86 @@ static size_t memcached_firstline_parse(char *buf, size_t len) {
}
}
// store an item in memcached
static void memcached_store(char *addr, struct uwsgi_buffer *key, struct uwsgi_buffer *value, char *expires) {
int timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
int fd = uwsgi_connect(addr, 0, 1);
if (fd < 0) return;
// wait for connection
int ret = uwsgi.wait_write_hook(fd, timeout);
if (ret <= 0) goto end;
// build the request
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_append(ub, "set ", 4)) goto end2;
if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2;
if (uwsgi_buffer_append(ub, " 0 " , 3)) goto end2;
if (uwsgi_buffer_append(ub, expires, strlen(expires))) goto end2;
if (uwsgi_buffer_append(ub, " " , 1)) goto end2;
if (uwsgi_buffer_num64(ub, value->pos)) goto end2;
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2;
if (uwsgi_write_true_nb(fd, value->buf, value->pos, timeout)) goto end2;
if (uwsgi_write_true_nb(fd, "\r\n", 2, timeout)) goto end2;
// we are not interested in command result... (ugly but it works)
end2:
uwsgi_buffer_destroy(ub);
end:
close(fd);
}
static int transform_memcached(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_memcached_conf *utmc = (struct uwsgi_transformation_memcached_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) {
memcached_store(utmc->addr->buf, utmc->key, ub, utmc->expires);
}
// free resources
uwsgi_buffer_destroy(utmc->key);
uwsgi_buffer_destroy(utmc->addr);
free(utmc);
return 0;
}
// be tolerant on errors
static int uwsgi_routing_func_memcached_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_memcached_conf *urmc = (struct uwsgi_router_memcached_conf *) ur->data2;
struct uwsgi_transformation_memcached_conf *utmc = uwsgi_calloc(sizeof(struct uwsgi_transformation_memcached_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);
utmc->key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len);
if (!utmc->key) goto error;
utmc->addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->addr, urmc->addr_len);
if (!utmc->addr) goto error;
utmc->expires = urmc->expires;
uwsgi_add_transformation(wsgi_req, transform_memcached, utmc);
return UWSGI_ROUTE_NEXT;
error:
if (utmc->key) uwsgi_buffer_destroy(utmc->key);
if (utmc->addr) uwsgi_buffer_destroy(utmc->addr);
free(utmc);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
// this is the buffer for the memcached response
char buf[MEMCACHED_BUFSIZE];
@@ -62,13 +153,24 @@ static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uw
struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len);
if (!ub_key) return UWSGI_ROUTE_BREAK;
int fd = uwsgi_connect(urmc->addr, 0, 1);
if (fd < 0) { uwsgi_buffer_destroy(ub_key) ; goto end; }
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->addr, urmc->addr_len);
if (!ub_addr) {
uwsgi_buffer_destroy(ub_key);
return UWSGI_ROUTE_BREAK;
}
int fd = uwsgi_connect(ub_addr->buf, 0, 1);
if (fd < 0) {
uwsgi_buffer_destroy(ub_key);
uwsgi_buffer_destroy(ub_addr);
goto end;
}
// wait for connection;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) {
uwsgi_buffer_destroy(ub_key) ;
uwsgi_buffer_destroy(ub_addr);
close(fd);
goto end;
}
@@ -77,11 +179,13 @@ static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uw
char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2);
if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub_key);
uwsgi_buffer_destroy(ub_addr);
free(cmd);
close(fd);
goto end;
}
uwsgi_buffer_destroy(ub_key);
uwsgi_buffer_destroy(ub_addr);
free(cmd);
// ok, start reading the response...
@@ -130,26 +234,34 @@ read:
goto end;
}
if (urmc->type_num == 1) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { close(fd); goto end; }
if (uwsgi_response_add_content_type(wsgi_req, urmc->content_type, urmc->content_type_len)) { close(fd); goto end; }
if (uwsgi_response_add_content_length(wsgi_req, response_size)) { close(fd); goto end; }
}
// from now on, every error will trigger a BREAK...
// send headers
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urmc->content_type, urmc->content_type_len)) goto error;
if (uwsgi_response_add_content_length(wsgi_req, response_size)) goto error;
// the first chunk could already contains part of the body
size_t remains = pos-(found+2);
if (remains >= response_size) {
uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size);
close(fd);
goto end;
goto done;
}
// send what we have
if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) {
close(fd);
goto end;
}
if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) goto error;
// and now start reading til the output is consumed
response_size -= remains;
// try to offload via the pipe engine
if (wsgi_req->socket->can_offload && !ur->custom && !urmc->no_offload) {
if (!uwsgi_offload_request_pipe_do(wsgi_req, fd, response_size)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
return UWSGI_ROUTE_BREAK;
}
}
while(response_size > 0) {
ssize_t len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size));
if (len > 0) goto write;
@@ -165,23 +277,22 @@ wait2:
}
goto error;
write:
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) {
goto error;
}
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) goto error;
response_size -= len;
}
done:
close(fd);
if (ur->custom)
return UWSGI_ROUTE_NEXT;
return UWSGI_ROUTE_BREAK;
error:
close(fd);
return UWSGI_ROUTE_BREAK;
end:
if (ur->custom)
return UWSGI_ROUTE_NEXT;
return UWSGI_ROUTE_BREAK;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_memcached(struct uwsgi_route *ur, char *args) {
@@ -193,27 +304,23 @@ static int uwsgi_router_memcached(struct uwsgi_route *ur, char *args) {
"addr", &urmc->addr,
"key", &urmc->key,
"content_type", &urmc->content_type,
"type", &urmc->type, NULL)) {
"no_offload", &urmc->no_offload,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urmc->key || !urmc->addr) {
uwsgi_log("invalid route syntax: you need to specify a memcached address and key pattern\n");
exit(1);
return -1;
}
urmc->key_len = strlen(urmc->key);
urmc->addr_len = strlen(urmc->addr);
if (!urmc->type) urmc->type = "full";
if (!urmc->content_type) urmc->content_type = "text/html";
urmc->content_type_len = strlen(urmc->content_type);
if (!strcmp(urmc->type, "body")) {
urmc->type_num = 1;
}
ur->data2 = urmc;
return 0;
}
@@ -224,12 +331,46 @@ static int uwsgi_router_memcached_continue(struct uwsgi_route *ur, char *args) {
return 0;
}
static int uwsgi_router_memcached_store(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_memcached_store;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_memcached_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_memcached_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"addr", &urmc->addr,
"key", &urmc->key,
"expires", &urmc->expires, NULL)) {
uwsgi_log("invalid memcachedstore route syntax: %s\n", args);
return -1;
}
if (!urmc->key || !urmc->addr) {
uwsgi_log("invalid memcachedstore route syntax: you need to specify an address and a key\n");
return -1;
}
urmc->key_len = strlen(urmc->key);
urmc->addr_len = strlen(urmc->addr);
if (!urmc->expires) urmc->expires = "0";
ur->data2 = urmc;
return 0;
}
static void router_memcached_register() {
uwsgi_register_router("memcached", uwsgi_router_memcached);
uwsgi_register_router("memcached-continue", uwsgi_router_memcached_continue);
uwsgi_register_router("memcachedstore", uwsgi_router_memcached_store);
uwsgi_register_router("memcached-store", uwsgi_router_memcached_store);
}
#endif
struct uwsgi_plugin router_memcached_plugin = {
.name = "router_memcached",
#ifdef UWSGI_ROUTING
.on_load = router_memcached_register,
#endif
};
+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']
+374
View File
@@ -0,0 +1,374 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
#define REDIS_BUFSIZE 8192
extern struct uwsgi_server uwsgi;
/*
redis internal router and transformation
route = /^foobar1(.*)/ redis:addr=127.0.0.1:11211,key=foo$1poo
route = /^foobar1(.*)/ redisstore:addr=127.0.0.1:11211,key=foo$1poo
*/
struct uwsgi_router_redis_conf {
char *addr;
size_t addr_len;
char *key;
size_t key_len;
char *content_type;
size_t content_type_len;
char *no_offload;
char *expires;
};
// this is allocated for each transformation
struct uwsgi_transformation_redis_conf {
struct uwsgi_buffer *addr;
struct uwsgi_buffer *key;
char *expires;
};
static size_t redis_firstline_parse(char *buf, size_t len) {
// check for "$0"
if (len < 2) return 0;
if (buf[0] != '$') return 0;
if (buf[1] == '-') return 0;
return uwsgi_str_num(buf + 1, len - 1);
}
// store an item in redis
static void redis_store(char *addr, struct uwsgi_buffer *key, struct uwsgi_buffer *value, char *expires) {
int timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
int fd = uwsgi_connect(addr, 0, 1);
if (fd < 0) return;
// wait for connection
int ret = uwsgi.wait_write_hook(fd, timeout);
if (ret <= 0) goto end;
// build the request
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_append(ub, "*3\r\n$3\r\nSET\r\n$", 14)) goto end2;
if (uwsgi_buffer_num64(ub, key->pos)) goto end2;
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2;
if (uwsgi_buffer_append(ub, "\r\n$" , 3)) goto end2;
if (uwsgi_buffer_num64(ub, value->pos)) goto end2;
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2;
if (uwsgi_write_true_nb(fd, value->buf, value->pos, timeout)) goto end2;
ub->pos = 0;
if (strcmp(expires, "0")) {
if (uwsgi_buffer_append(ub, "\r\n*3\r\n$6\r\nEXPIRE\r\n$" , 19)) goto end2;
if (uwsgi_buffer_num64(ub, key->pos)) goto end2;
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2;
if (uwsgi_buffer_append(ub, "\r\n$" , 3)) goto end2;
if (uwsgi_buffer_num64(ub, strlen(expires))) goto end2;
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
if (uwsgi_buffer_append(ub, expires, strlen(expires))) goto end2;
}
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2;
// we are not interested in command result... (ugly but it works)
end2:
uwsgi_buffer_destroy(ub);
end:
close(fd);
}
static int transform_redis(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_redis_conf *utrc = (struct uwsgi_transformation_redis_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) {
redis_store(utrc->addr->buf, utrc->key, ub, utrc->expires);
}
// free resources
uwsgi_buffer_destroy(utrc->key);
uwsgi_buffer_destroy(utrc->addr);
free(utrc);
return 0;
}
// be tolerant on errors
static int uwsgi_routing_func_redis_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_redis_conf *urrc = (struct uwsgi_router_redis_conf *) ur->data2;
struct uwsgi_transformation_redis_conf *utrc = uwsgi_calloc(sizeof(struct uwsgi_transformation_redis_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);
utrc->key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->key, urrc->key_len);
if (!utrc->key) goto error;
utrc->addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->addr, urrc->addr_len);
if (!utrc->addr) goto error;
utrc->expires = urrc->expires;
uwsgi_add_transformation(wsgi_req, transform_redis, utrc);
return UWSGI_ROUTE_NEXT;
error:
if (utrc->key) uwsgi_buffer_destroy(utrc->key);
if (utrc->addr) uwsgi_buffer_destroy(utrc->addr);
free(utrc);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_routing_func_redis(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
// this is the buffer for the redis response
char buf[REDIS_BUFSIZE];
size_t i;
char last_char = 0;
struct uwsgi_router_redis_conf *urrc = (struct uwsgi_router_redis_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_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->key, urrc->key_len);
if (!ub_key) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->addr, urrc->addr_len);
if (!ub_addr) {
uwsgi_buffer_destroy(ub_key);
return UWSGI_ROUTE_BREAK;
}
int fd = uwsgi_connect(ub_addr->buf, 0, 1);
if (fd < 0) {
uwsgi_buffer_destroy(ub_key);
uwsgi_buffer_destroy(ub_addr);
goto end;
}
// wait for connection;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) {
uwsgi_buffer_destroy(ub_key) ;
uwsgi_buffer_destroy(ub_addr);
close(fd);
goto end;
}
// build the request and send it
char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2);
if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub_key);
uwsgi_buffer_destroy(ub_addr);
free(cmd);
close(fd);
goto end;
}
uwsgi_buffer_destroy(ub_key);
uwsgi_buffer_destroy(ub_addr);
free(cmd);
// ok, start reading the response...
// first we need to get a full line;
size_t found = 0;
size_t pos = 0;
for(;;) {
ssize_t len = read(fd, buf + pos, REDIS_BUFSIZE - pos);
if (len > 0) {
pos += len;
goto read;
}
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait;
}
close(fd);
goto end;
wait:
ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
// when we have a chunk try to read the first line
if (ret > 0) {
len = read(fd, buf + pos, REDIS_BUFSIZE - pos);
if (len > 0) {
pos += len;
goto read;
}
}
close(fd);
goto end;
read:
for(i=0;i<pos;i++) {
if (last_char == '\r' && buf[i] == '\n') {
found = i-1;
break;
}
last_char = buf[i];
}
if (found) break;
}
// ok parse the first line
size_t response_size = redis_firstline_parse(buf, found);
if (response_size == 0) {
close(fd);
goto end;
}
// from now on, every error will trigger a BREAK...
// send headers
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urrc->content_type, urrc->content_type_len)) goto error;
if (uwsgi_response_add_content_length(wsgi_req, response_size)) goto error;
// the first chunk could already contains part of the body
size_t remains = pos-(found+2);
if (remains >= response_size) {
uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size);
goto done;
}
// send what we have
if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) goto error;
// and now start reading til the output is consumed
response_size -= remains;
// try to offload via the pipe engine
if (wsgi_req->socket->can_offload && !ur->custom && !urrc->no_offload) {
if (!uwsgi_offload_request_pipe_do(wsgi_req, fd, response_size)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
return UWSGI_ROUTE_BREAK;
}
}
while(response_size > 0) {
ssize_t len = read(fd, buf, UMIN(REDIS_BUFSIZE, response_size));
if (len > 0) goto write;
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait2;
}
goto error;
wait2:
ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret > 0) {
len = read(fd, buf, UMIN(REDIS_BUFSIZE, response_size));
if (len > 0) goto write;
}
goto error;
write:
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) goto error;
response_size -= len;
}
done:
close(fd);
if (ur->custom)
return UWSGI_ROUTE_NEXT;
return UWSGI_ROUTE_BREAK;
error:
close(fd);
return UWSGI_ROUTE_BREAK;
end:
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_redis(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_redis;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_redis_conf *urrc = uwsgi_calloc(sizeof(struct uwsgi_router_redis_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"addr", &urrc->addr,
"key", &urrc->key,
"content_type", &urrc->content_type,
"no_offload", &urrc->no_offload,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urrc->key || !urrc->addr) {
uwsgi_log("invalid route syntax: you need to specify a redis address and key pattern\n");
return -1;
}
urrc->key_len = strlen(urrc->key);
urrc->addr_len = strlen(urrc->addr);
if (!urrc->content_type) urrc->content_type = "text/html";
urrc->content_type_len = strlen(urrc->content_type);
ur->data2 = urrc;
return 0;
}
static int uwsgi_router_redis_continue(struct uwsgi_route *ur, char *args) {
uwsgi_router_redis(ur, args);
ur->custom = 1;
return 0;
}
static int uwsgi_router_redis_store(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_redis_store;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_redis_conf *urrc = uwsgi_calloc(sizeof(struct uwsgi_router_redis_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"addr", &urrc->addr,
"key", &urrc->key,
"expires", &urrc->expires, NULL)) {
uwsgi_log("invalid redisstore route syntax: %s\n", args);
return -1;
}
if (!urrc->key || !urrc->addr) {
uwsgi_log("invalid redisstore route syntax: you need to specify an address and a key\n");
return -1;
}
urrc->key_len = strlen(urrc->key);
urrc->addr_len = strlen(urrc->addr);
if (!urrc->expires) urrc->expires = "0";
ur->data2 = urrc;
return 0;
}
static void router_redis_register() {
uwsgi_register_router("redis", uwsgi_router_redis);
uwsgi_register_router("redis-continue", uwsgi_router_redis_continue);
uwsgi_register_router("redisstore", uwsgi_router_redis_store);
uwsgi_register_router("redis-store", uwsgi_router_redis_store);
}
#endif
struct uwsgi_plugin router_redis_plugin = {
.name = "router_redis",
#ifdef UWSGI_ROUTING
.on_load = router_redis_register,
#endif
};
+6
View File
@@ -0,0 +1,6 @@
NAME='router_redis'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['router_redis']
+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']
+121 -2
View File
@@ -1,9 +1,23 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
extern struct uwsgi_server uwsgi;
struct uwsgi_router_file_conf {
char *filename;
size_t filename_len;
char *status;
size_t status_len;
char *content_type;
size_t content_type_len;
char *mime;
};
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -17,8 +31,71 @@ int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route
return UWSGI_ROUTE_BREAK;
}
int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
char buf[32768];
struct stat st;
int ret = UWSGI_ROUTE_BREAK;
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_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, urfc->filename, urfc->filename_len);
if (!ub) return UWSGI_ROUTE_BREAK;
int fd = open(ub->buf, O_RDONLY);
if (fd < 0) {
if (ur->custom)
ret = UWSGI_ROUTE_NEXT;
goto end;
}
if (fstat(fd, &st)) {
goto end2;
}
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
}
uwsgi_buffer_destroy(ub_s);
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
if (urfc->mime) {
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
if (mime_type) {
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
}
else {
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
}
else {
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
size_t remains = st.st_size;
while(remains) {
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
if (rlen <= 0) goto end2;
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end2;
remains -= rlen;
}
end2:
close(fd);
end:
uwsgi_buffer_destroy(ub);
return ret;
}
static int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_static;
ur->data = args;
@@ -26,10 +103,52 @@ int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
return 0;
}
static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_file;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_file_conf *urfc = uwsgi_calloc(sizeof(struct uwsgi_router_file_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"filename", &urfc->filename,
"status", &urfc->status,
"content_type", &urfc->content_type,
"mime", &urfc->mime,
NULL)) {
uwsgi_log("invalid file route syntax: %s\n", args);
return -1;
}
if (!urfc->filename) {
uwsgi_log("you have to specifify a filename for the \"file\" router\n");
return -1;
}
urfc->filename_len = strlen(urfc->filename);
if (!urfc->content_type) {
urfc->content_type = "text/html";
}
urfc->content_type_len = strlen(urfc->content_type);
if (!urfc->status) {
urfc->status = "200 OK";
}
urfc->status_len = strlen(urfc->status);
ur->data2 = urfc;
return 0;
}
static int uwsgi_router_file_next(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
return uwsgi_router_file(ur, args);
}
static void router_static_register(void) {
uwsgi_register_router("static", uwsgi_router_static);
uwsgi_register_router("file", uwsgi_router_file);
uwsgi_register_router("file-next", uwsgi_router_file_next);
}
struct uwsgi_plugin router_static_plugin = {
+197 -3
View File
@@ -1,7 +1,125 @@
#include <uwsgi.h>
#ifdef UWSGI_XML_LIBXML2
#include <libxml/parser.h>
#include <libxml/tree.h>
#endif
extern struct uwsgi_server uwsgi;
/*
rpc-HTTP interface.
modifier2 changes the parsser behaviours:
0 -> return uwsgi header + rpc response
1 -> return raw rpc response
2 -> split PATH_INFO to get func name and args and return as HTTP response with content_type as application/binary or Accept request header (if different from *)
3 -> set xmlrpc wrapper (requires libxml2)
4 -> set jsonrpc wrapper (requires libjansson)
*/
#ifdef UWSGI_XML_LIBXML2
// raise error on non-string args
static int uwsgi_rpc_xmlrpc_string(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) {
xmlNode *node;
for (node = element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (strcmp((char *) node->name, "string")) {
return -1;
}
if (!node->children) return -1;
if (!node->children->content) return -1;
*argc+=1;
argv[*argc] = (char *) node->children->content;
argvs[*argc] = strlen(argv[*argc]);
}
}
return 0;
}
static int uwsgi_rpc_xmlrpc_value(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) {
xmlNode *node;
for (node = element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (!strcmp((char *) node->name, "value")) {
if (uwsgi_rpc_xmlrpc_string(node, argv, argvs, argc)) {
return -1;
}
}
}
}
return 0;
}
static int uwsgi_rpc_xmlrpc_args(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) {
xmlNode *node;
for (node = element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (!strcmp((char *) node->name, "param")) {
if (uwsgi_rpc_xmlrpc_value(node, argv, argvs, argc)) {
return -1;
}
}
}
}
return 0;
}
static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **argv, uint16_t *argvs, uint8_t *argc, char *response_buf) {
char *method = NULL;
xmlNode *element = xmlDocGetRootElement(doc);
if (!element) return -1;
if (strcmp((char *) element->name, "methodCall")) return -1;
*argc = 0;
xmlNode *node;
for (node = element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (!strcmp((char *) node->name, "methodName") && node->children) {
method = (char *) node->children->content;
}
else if (!strcmp((char *) node->name, "params")) {
if (uwsgi_rpc_xmlrpc_args(node, argv, argvs, argc)) return -1;
}
}
}
if (!method) return -1;
wsgi_req->uh->pktsize = uwsgi_rpc(method, *argc, argv+1, argvs+1, response_buf);
if (!wsgi_req->uh->pktsize) return -1;
if (wsgi_req->uh->pktsize == UMAX16-1) return -1;
// add final NULL byte
response_buf[wsgi_req->uh->pktsize] = 0;
xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0");
xmlNode *m_response = xmlNewNode(NULL, BAD_CAST "methodResponse");
xmlDocSetRootElement(rdoc, m_response);
xmlNode *x_params = xmlNewChild(m_response, NULL, BAD_CAST "params", NULL);
xmlNode *x_param = xmlNewChild(x_params, NULL, BAD_CAST "param", NULL);
xmlNode *x_value = xmlNewChild(x_param, NULL, BAD_CAST "value", NULL);
xmlNewTextChild(x_value, NULL, BAD_CAST "string", BAD_CAST response_buf);
xmlChar *xmlbuf;
int xlen = 0;
xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1);
uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6);
uwsgi_response_add_content_length(wsgi_req, xlen);
uwsgi_response_add_content_type(wsgi_req, "application/xml", 15);
uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen);
xmlFreeDoc(rdoc);
xmlFree(xmlbuf);
return 0;
}
#endif
static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
@@ -20,6 +138,82 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
return -1;
}
if (wsgi_req->uh->modifier2 == 2) {
if (uwsgi_parse_vars(wsgi_req)) {
uwsgi_log("Invalid RPC request. skip.\n");
return -1;
}
if (wsgi_req->path_info_len == 0) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
char *args = NULL;
if (wsgi_req->path_info[0] == '/') {
args = uwsgi_concat2n(wsgi_req->path_info+1, wsgi_req->path_info_len-1, "", 0);
}
else {
args = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
}
argc = 0;
argv[0] = strtok(args, "/");
if (!argv[0]) {
free(args);
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
char *p = strtok(NULL, "/");
while(p) {
argc++;
argv[argc] = p;
argvs[argc] = strlen(p);
p = strtok(NULL, "/");
}
wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, response_buf);
free(args);
if (!wsgi_req->uh->pktsize) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return 1;
if (uwsgi_response_add_content_length(wsgi_req, wsgi_req->uh->pktsize)) return -1;
uint16_t ctype_len = 0;
char *ctype = uwsgi_get_var(wsgi_req, "HTTP_ACCEPT", 11, &ctype_len);
if (ctype && strcmp(ctype, "*/*") && strcmp(ctype, "*")) {
if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) return -1;
}
else {
if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) return -1;
}
goto sendbody;
}
#ifdef UWSGI_XML_LIBXML2
if (wsgi_req->uh->modifier2 == 3) {
if (wsgi_req->post_cl == 0) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len);
xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0);
if (!doc) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, response_buf);
xmlFreeDoc(doc);
if (ret) {
uwsgi_500(wsgi_req);
}
return UWSGI_OK;
}
#endif
if (uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) {
uwsgi_log("Invalid RPC request. skip.\n");
return -1;
@@ -34,6 +228,9 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
return -1;
}
}
sendbody:
// write the response
uwsgi_response_write_body_do(wsgi_req, response_buf, wsgi_req->uh->pktsize);
@@ -247,9 +444,6 @@ static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsg
else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
ret = UWSGI_ROUTE_CONTINUE;
}
else if (!uwsgi_strncmp(response, size, "goon", 4 )) {
ret = UWSGI_ROUTE_GOON;
}
else if (!uwsgi_starts_with(response, size, "break", 5 )) {
ret = UWSGI_ROUTE_BREAK;
if (size > 6) {
+2
View File
@@ -193,6 +193,7 @@ static ssize_t sr_instance_read(struct corerouter_peer *peer) {
// the instance is connected now we cannot retry connections
static ssize_t sr_instance_connected(struct corerouter_peer *peer) {
cr_peer_connected(peer, "sr_instance_connected()");
peer->can_retry = 0;
// set the output buffer as the main_peer output one
peer->out = peer->session->main_peer->in;
peer->out_pos = 0;
@@ -307,6 +308,7 @@ static ssize_t sr_read(struct corerouter_peer *main_peer) {
return -1;
}
peer->can_retry = 1;
cr_connect(peer, sr_instance_connected);
return 1;
}
+50 -20
View File
@@ -2,6 +2,7 @@
#include <stackless_api.h>
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
struct ustackless {
int enabled;
@@ -9,16 +10,22 @@ struct ustackless {
PyTaskletObject **sl;
} usl;
struct uwsgi_option stackless_options[] = {
static void gil_stackless_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
static void gil_stackless_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static struct uwsgi_option stackless_options[] = {
{"stackless", no_argument, 0, "use stackless as suspend engine", uwsgi_opt_true, &usl.enabled, 0},
{ 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0 }
};
PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
static PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
async_schedule_to_req_green();
Py_DECREF(usl.sl[uwsgi.wsgi_req->async_id]);
Py_INCREF(Py_None);
@@ -27,9 +34,13 @@ PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
PyMethodDef uwsgi_stackless_request_method[] = {{"uwsgi_stackless_request", py_uwsgi_stackless_request, METH_VARARGS, ""}};
static inline static void stackless_schedule_to_req() {
static void stackless_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// ensure gil
UWSGI_GET_GIL
if (!uwsgi.wsgi_req->suspended) {
usl.sl[id] = PyTasklet_New(NULL, usl.callable);
@@ -39,46 +50,65 @@ static inline static void stackless_schedule_to_req() {
uwsgi.wsgi_req->suspended = 1;
}
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
PyTasklet_Run(usl.sl[id]);
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
}
// call it in the main core
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
}
static inline static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
// ensure gil
UWSGI_GET_GIL
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyStackless_Schedule(Py_None, 1);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
}
int stackless_init() {
return 0;
}
static void stackless_init_apps(void) {
void stackless_init_apps(void) {
if (!usl.enabled) return;
if (!usl.enabled) {
return;
if (uwsgi.async <= 1) {
uwsgi_log("the stackless suspend engine requires async mode\n");
exit(1);
}
if (uwsgi.has_threads) {
up.gil_get = gil_stackless_get;
up.gil_release = gil_stackless_release;
}
// blindy call it as the stackless gil engine is already set
UWSGI_GET_GIL
usl.sl = uwsgi_malloc( sizeof(PyTaskletObject *) * uwsgi.async );
usl.callable = PyCFunction_New(uwsgi_stackless_request_method, NULL);
Py_INCREF(usl.callable);
uwsgi_log("enabled stackless engine\n");
uwsgi.schedule_to_main = stackless_schedule_to_main;
uwsgi.schedule_to_req = stackless_schedule_to_req;
return;
}
struct uwsgi_plugin stackless_plugin = {
.name = "stackless",
.init = stackless_init,
.init_apps = stackless_init_apps,
.options = stackless_options,
};
+17
View File
@@ -7,6 +7,7 @@ struct uwsgi_symcall {
int (*symcall_function)(struct wsgi_request *);
struct uwsgi_string_list *rpc;
struct uwsgi_string_list *post_fork;
} usym;
struct uwsgi_plugin symcall_plugin;
@@ -14,6 +15,7 @@ struct uwsgi_plugin symcall_plugin;
static struct uwsgi_option uwsgi_symcall_options[] = {
{"symcall", required_argument, 0, "load the specified C symbol as the symcall request handler", uwsgi_opt_set_str, &usym.symcall_function_name, 0},
{"symcall-register-rpc", required_argument, 0, "load the specified C symbol as an RPC function (syntax: name function)", uwsgi_opt_add_string_list, &usym.rpc, 0},
{"symcall-post-fork", required_argument, 0, "call the specified C symbol after each fork()", uwsgi_opt_add_string_list, &usym.post_fork, 0},
{0, 0, 0, 0},
};
@@ -66,6 +68,20 @@ static uint16_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_
return casted_func(argc, argv, argvs, buffer);
}
static void uwsgi_symcall_post_fork() {
void (*func)(void);
struct uwsgi_string_list *usl = usym.post_fork;
while(usl) {
func = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", usl->value);
exit(1);
}
func();
usl = usl->next;
}
}
struct uwsgi_plugin symcall_plugin = {
.name = "symcall",
@@ -75,6 +91,7 @@ struct uwsgi_plugin symcall_plugin = {
.request = uwsgi_symcall_request,
.after_request = uwsgi_symcall_after_request,
.rpc = uwsgi_symcall_rpc,
.post_fork = uwsgi_symcall_post_fork,
};
+58
View File
@@ -0,0 +1,58 @@
#include <uwsgi.h>
#if defined(UWSGI_ROUTING)
/*
transfer-encoding is added to the headers
*/
static int transform_chunked(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_buffer *ub = ut->chunk;
if (ut->is_final) {
if (uwsgi_buffer_append(ub, "0\r\n\r\n", 5)) return -1;
return 0;
}
if (ut->round == 1) {
// do not check for errors !!!
uwsgi_response_add_header(wsgi_req, "Transfer-Encoding", 17, "chunked", 7);
}
if (ub->pos > 0) {
if (uwsgi_buffer_insert_chunked(ub, 0, ub->pos)) return -1;
if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1;
}
return 0;
}
static int uwsgi_routing_func_chunked(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL);
ut->can_stream = 1;
// add a "final" transformation to add the trailing chunk
ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL);
ut->is_final = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_chunked(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_chunked;
return 0;
}
static void router_chunked_register(void) {
uwsgi_register_router("chunked", uwsgi_router_chunked);
}
struct uwsgi_plugin transformation_chunked_plugin = {
.name = "transformation_chunked",
.on_load = router_chunked_register,
};
#else
struct uwsgi_plugin transformation_chunked_plugin = {
.name = "transformation_chunked",
};
#endif
@@ -0,0 +1,6 @@
NAME='transformation_chunked'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['chunked']
+47 -12
View File
@@ -4,27 +4,62 @@
/*
gzip transformations reset your headers !!!
gzip transformations add content-encoding to your headers and changes the final size !!!
remember to re-add the content type via routing rules
remember to fix the content_length (or use chunked encoding) !!!
*/
static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
struct uwsgi_buffer *gzipped = uwsgi_gzip(ub->buf, ub->pos);
if (!gzipped) {
return -1;
struct uwsgi_transformation_gzip {
z_stream z;
uint32_t crc32;
size_t len;
uint8_t header;
};
extern char gzheader[];
static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_gzip *utgz = (struct uwsgi_transformation_gzip *) ut->data;
struct uwsgi_buffer *ub = ut->chunk;
if (ut->is_final) {
if (uwsgi_gzip_fix(&utgz->z, utgz->crc32, ub, utgz->len)) {
free(utgz);
return -1;
}
free(utgz);
return 0;
}
// use this new buffer
*new = gzipped;
if (uwsgi_response_prepare_headers_int(wsgi_req, wsgi_req->status)) return -1;
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
if (uwsgi_response_add_content_length(wsgi_req, gzipped->pos)) return -1;
size_t dlen = 0;
char *gzipped = uwsgi_gzip_chunk(&utgz->z, &utgz->crc32, ub->buf, ub->pos, &dlen);
if (!gzipped) return -1;
utgz->len += ub->pos;
uwsgi_buffer_map(ub, gzipped, dlen);
if (!utgz->header) {
// do not check for errors !!!
uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4);
utgz->header = 1;
if (uwsgi_buffer_insert(ub, 0, gzheader, 10)) {
return -1;
}
}
return 0;
}
static int uwsgi_routing_func_gzip(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
uwsgi_add_transformation(wsgi_req, transform_gzip, NULL);
struct uwsgi_transformation_gzip *utgz = uwsgi_calloc(sizeof(struct uwsgi_transformation_gzip));
if (uwsgi_gzip_prepare(&utgz->z, NULL, 0, &utgz->crc32)) {
free(utgz);
return UWSGI_ROUTE_BREAK;
}
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
ut->can_stream = 1;
// this is the trasformation clearing the memory
ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
ut->is_final = 1;
return UWSGI_ROUTE_NEXT;
}
+138
View File
@@ -0,0 +1,138 @@
#include <uwsgi.h>
#if defined(UWSGI_ROUTING)
/*
offload transformation
each chunk is buffered to the transformation custom buffer
if the buffer grows higher than the specified limit, the response will be buffered to disk
on final the memory (or the tmpfile) will be offloaded
even if we are talking about buffering, this is a streaming transformation
as we need to hold control on memory usage
"offload" MUST BE the last transformation in the chain. Hellish things will happen otherwise...
*/
static int transform_offload(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
if (ut->is_final) {
struct uwsgi_transformation *orig_ut = (struct uwsgi_transformation *) ut->data;
// sendfile offload
if (orig_ut->fd > -1) {
if (!uwsgi_offload_request_sendfile_do(wsgi_req, orig_ut->fd, orig_ut->len)) {
// the fd will be closed by the offload engine
orig_ut->fd = -1;
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->response_size += orig_ut->len;
return 0;
}
// fallback to non-offloaded write
if (uwsgi_simple_sendfile(wsgi_req, orig_ut->fd, 0, orig_ut->len)) {
return -1;
}
wsgi_req->response_size += orig_ut->len;
return 0;
}
// memory offload
if (orig_ut->ub) {
if (!uwsgi_offload_request_memory_do(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) {
// memory will be freed by the offload engine
orig_ut->ub->buf = NULL;
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->response_size += orig_ut->ub->pos;
return 0;
}
// fallback to non-offloaded write
if (uwsgi_simple_write(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) {
return -1;
}
wsgi_req->response_size += orig_ut->ub->pos;
return -1;
}
return 0;
}
// check if we need to start buffering to disk
if (ut->fd == -1 && ut->len + ut->chunk->pos > ut->custom64) {
ut->fd = uwsgi_tmpfd();
if (ut->fd < 0) return -1;
// save already buffered data
if (ut->ub) {
ssize_t wlen = write(ut->fd, ut->ub->buf, ut->ub->pos);
if (wlen != (ssize_t) ut->ub->pos) {
uwsgi_error("transform_offload/write()");
return -1;
}
}
}
// if fd > -1, append to file
if (ut->fd > -1) {
ssize_t wlen = write(ut->fd, ut->chunk->buf, ut->chunk->pos);
if (wlen != (ssize_t) ut->chunk->pos) {
uwsgi_error("transform_offload/write()");
return -1;
}
ut->len += wlen;
goto done;
}
// buffer to memory
if (!ut->ub) {
ut->ub = uwsgi_buffer_new(ut->chunk->pos);
}
// append the chunk to the custom buffer
if (uwsgi_buffer_append(ut->ub, ut->chunk->buf, ut->chunk->pos)) return -1;
ut->len += ut->chunk->pos;
done:
// reset the chunk !!!
ut->chunk->pos = 0;
return 0;
}
static int uwsgi_routing_func_offload(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
if (!wsgi_req->socket->can_offload) {
uwsgi_log("unable to use the offload transformation without offload threads !!!\n");
return UWSGI_ROUTE_BREAK;
}
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_offload, NULL);
ut->can_stream = 1;
ut->custom64 = ur->custom;
// add a "final" transformation to add the trailing chunk
ut = uwsgi_add_transformation(wsgi_req, transform_offload, ut);
ut->is_final = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_offload(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_offload;
if (args[0] == 0) {
// 1 MB limit
ur->custom = 1024 * 1024;
}
else {
ur->custom = strtoul(args, NULL, 10);
}
return 0;
}
static void router_offload_register(void) {
uwsgi_register_router("offload", uwsgi_router_offload);
}
struct uwsgi_plugin transformation_offload_plugin = {
.name = "transformation_offload",
.on_load = router_offload_register,
};
#else
struct uwsgi_plugin transformation_offload_plugin = {
.name = "transformation_offload",
};
#endif
@@ -0,0 +1,6 @@
NAME='transformation_offload'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['offload']
+6 -3
View File
@@ -20,13 +20,15 @@ struct uwsgi_transformation_tofile_conf {
struct uwsgi_buffer *filename;
};
static int transform_tofile(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **new, void *data) {
struct uwsgi_transformation_tofile_conf *uttc = (struct uwsgi_transformation_tofile_conf *) data;
static int transform_tofile(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_transformation_tofile_conf *uttc = (struct uwsgi_transformation_tofile_conf *) ut->data;
struct uwsgi_buffer *ub = ut->chunk;
// store only successfull response
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
if (uttc->filename) {
int fd = open(uttc->filename->buf, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
int fd = open(uttc->filename->buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (fd < 0) {
uwsgi_error_open(uttc->filename->buf);
goto end;
@@ -56,6 +58,7 @@ end:
// free resources
if (uttc->filename) uwsgi_buffer_destroy(uttc->filename);
free(uttc);
// reset the buffer
return 0;
}
+5 -4
View File
@@ -1,15 +1,16 @@
#include <uwsgi.h>
static int transform_toupper(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub, struct uwsgi_buffer **foobar, void *data) {
static int transform_toupper(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
size_t i;
for(i=0;i<ub->pos;i++) {
ub->buf[i] = toupper((int) ub->buf[i]);
for(i=0;i<ut->chunk->pos;i++) {
ut->chunk->buf[i] = toupper((int) ut->chunk->buf[i]);
}
return 0;
}
static int uwsgi_routing_func_toupper(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
uwsgi_add_transformation(wsgi_req, transform_toupper, NULL);
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_toupper, NULL);
ut->can_stream = 1;
return UWSGI_ROUTE_NEXT;
}
+15 -25
View File
@@ -21,47 +21,35 @@ struct uwsgi_ugreen {
extern struct uwsgi_server uwsgi;
struct uwsgi_option ugreen_options[] = {
{"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 1},
static struct uwsgi_option ugreen_options[] = {
{"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 0},
{"ugreen-stacksize", required_argument, 0, "set ugreen stack size in pages", uwsgi_opt_set_int, &ug.stackpages, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
};
void u_green_request() {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
// end of the request
uwsgi.wsgi_req->async_status = UWSGI_OK;
uwsgi.wsgi_req->suspended = 0;
return;
}
#endif
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->suspended = 0;
}
static void u_green_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1;
// first round ?
if (!uwsgi.wsgi_req->suspended) {
ug.contexts[id].uc_link = &ug.main;
makecontext(&ug.contexts[id], u_green_request, 0);
makecontext(&ug.contexts[id], async_schedule_to_req_green, 0);
uwsgi.wsgi_req->suspended = 1;
}
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->suspend(NULL);
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
// save the main stack and switch to the core
swapcontext(&ug.main, &ug.contexts[id] );
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->resume) {
uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->resume(NULL);
}
if (uwsgi.wsgi_req->suspended) {
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
// call it in the main core
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
}
@@ -72,7 +60,9 @@ static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
// back to main
swapcontext(&ug.contexts[wsgi_req->async_id], &ug.main);
// back to core
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
@@ -82,7 +72,7 @@ static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) {
}
int u_green_init() {
static int u_green_init() {
static int i;
+8
View File
@@ -0,0 +1,8 @@
import os
NAME='webdav'
CFLAGS = os.popen('xml2-config --cflags').read().rstrip().split()
LDFLAGS = []
LIBS = os.popen('xml2-config --libs').read().rstrip().split()
GCC_LIST = ['webdav']
File diff suppressed because it is too large Load Diff

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