Compare commits

...
802 Commits
Author SHA1 Message Date
Unbit 807060706f prepare for 1.9.2 2013-03-26 20:05:33 +01:00
Unbit a317f88d3c added the cache command to the ssi plugin 2013-03-26 20:03:37 +01:00
Unbit e17a7f0701 fixed a typo 2013-03-26 19:53:32 +01:00
Unbit db325eb9fe fixed readline() + post_buffering 2013-03-26 17:54:42 +01:00
Unbit b41a4c8c3b fixed python3 headers management 2013-03-26 16:45:57 +01:00
Unbit 73b4d11d18 added ssi router 2013-03-26 15:38:45 +01:00
Unbit 8162b87287 beta quality ssi plugin 2013-03-26 15:19:23 +01:00
Unbit 70e9e4f3ee added printenv 2013-03-26 12:24:17 +01:00
Unbit e61ae376b3 other improvements in the ssi plugin 2013-03-26 11:48:51 +01:00
Unbit 2d57b0e926 added preliminary ssi support 2013-03-26 11:33:00 +01:00
Unbit ae683af07a completed the geoip plugin [2] 2013-03-26 07:11:27 +01:00
Unbit 3c4f6a9171 completed the geoip plugin 2013-03-26 07:05:02 +01:00
Unbit 39986e546c fixed GeoIP plugin 2013-03-26 06:47:18 +01:00
Unbit 2e81a80f7b added preliminary geoip plugin 2013-03-25 19:11:20 +01:00
Unbit fcb3aa38c8 allows freeing route vars 2013-03-25 18:15:29 +01:00
Unbit 00a38d8ec5 fixed routing vars management 2013-03-25 18:10:41 +01:00
Unbit 07a0ab4227 pluggable routing vars 2013-03-25 18:05:57 +01:00
Unbit d4a9a2c543 fixed exceptions in the fiber plugin 2013-03-25 17:46:29 +01:00
Unbit 2b523fc60d added query string management functions 2013-03-25 10:21:20 +01:00
Unbit 0c26928236 added cookie management and --route-run 2013-03-25 09:56:53 +01:00
Unbit 8401e56a22 added 'empty' internal routing condition 2013-03-25 09:04:30 +01:00
Unbit 5109f9ae0b back to libxml2 default 2013-03-25 08:47:22 +01:00
Unbit c9bc06669a .ini file can backreference themselves 2013-03-25 08:47:00 +01:00
unbit a83fb2672c Merge pull request #189 from xtfxme/enhance/189-dashful-endif-endfor
Routing table appear to go nuts when used within a FOR loop
2013-03-24 23:18:50 -07:00
C Anthony Risinger 8f9ecb44d9 [#189] endfor/endif => end-for/end-if ...i know i'm not alone 2013-03-24 15:45:04 -05:00
Unbit bfcc09a8de prepare for cookie management in internal routing 2013-03-24 21:05:21 +01:00
Unbit f8a8c997db removed cache type in routing instruction 2013-03-24 20:30:56 +01:00
Unbit 132b996f30 added cachestore routing instruction 2013-03-24 19:43:41 +01:00
Unbit 12f970cdfb prepare for routing-governed caching 2013-03-24 19:24:13 +01:00
Unbit 9afa963225 prepare for gem 1.9.1 2013-03-24 11:39:44 +01:00
Unbit ed368d0d51 fixed signal copy on write 2013-03-24 10:30:01 +01:00
Unbit 21f21d34ba fixed legion scrolls api 2013-03-24 09:52:16 +01:00
Unbit f37823c809 completed --emperor-on-demand-dir 2013-03-23 10:34:36 +01:00
Unbit 6eaefcff5e added build profile for ubuntu ppa 2013-03-23 06:15:55 +01:00
Unbit 79235c1cc3 another memory report fix for Unbit 2013-03-23 04:41:58 +01:00
Unbit 29135f014b Unbit fixes 2013-03-23 04:11:33 +01:00
Unbit 13c998fb8d added uwsgi_main.c 2013-03-23 03:56:56 +01:00
Unbit 71bfd0d636 prepare for uWSGI 1.9.1 2013-03-23 03:52:19 +01:00
Unbit 51e99e0f5a removed UWSGI_INI 2013-03-23 03:15:33 +01:00
Unbit 66e7beefc4 fixed rack exceptions management 2013-03-22 19:53:47 +01:00
Unbit f2b10c35b7 fixed build without pcre 2013-03-22 11:15:13 +01:00
Unbit e951eba96c improved emperor on demand mode 2013-03-22 14:56:49 +01:00
Unbit 9fe18da7a3 added startswith endswith and regexp/re routing instructions 2013-03-22 10:14:34 +01:00
Unbit a14fdead14 added rpc router instruction 2013-03-22 09:26:11 +01:00
Unbit 9a671a4991 added %V magic var (contains UWSGI_VERSION) 2013-03-21 17:18:41 +01:00
Unbit 8f5e7b124a added --emperor-on-demand-exec 2013-03-21 16:55:23 +01:00
Unbit 5f7464d015 implemented --emperor-on-demand-ext 2013-03-21 16:42:24 +01:00
Unbit 238dd6c1d0 added a commodity mongodb plugin for system without mongoclient shared library 2013-03-21 15:18:09 +01:00
Roberta Giordano 82e4e54edc removed some unbit useless definition 2013-03-21 07:59:45 +01:00
Unbit 9946cbb9da added 'equal' routing func 2013-03-21 06:54:36 +01:00
Unbit 2474adb23a completed routing cache instruction 2013-03-21 06:31:26 +01:00
Unbit f40757bb67 free carbon_address memory 2013-03-21 06:19:31 +01:00
unbit bc29479930 Merge pull request #188 from prymitive/carbon_resolve_hostnames
allow connecting to carbon server using hostname resolved on every cycle...
2013-03-20 22:04:50 -07:00
Łukasz Mierzwa 4ec78edaa3 allow connecting to carbon server using hostname resolved on every cycle, fixes #186 2013-03-20 21:47:56 +01:00
Unbit aa0271158d allows build profiles to be stored on http/https/ftp 2013-03-20 19:44:46 +01:00
Unbit c0aa5bfe17 added the crypto logger 2013-03-20 16:22:40 +01:00
Unbit 3f8e6a8cc8 completed xslt plugin 2013-03-19 17:53:12 +01:00
Unbit ef0316fc2e Merge branch 'master' of github.com:unbit/uwsgi 2013-03-19 15:18:33 +01:00
Unbit 7274efab15 added xslt plugin 2013-03-19 15:18:03 +01:00
Unbit e44b62b6b2 on demand vassals 2013-03-18 15:42:34 +01:00
Unbit 31c041d435 added --exec-post-app 2013-03-18 13:32:09 +01:00
Unbit 35f47371ed first part of uwsgi_legion_scrolls() function api 2013-03-18 13:22:10 +01:00
unbit c5412e1620 Merge pull request #185 from guokr/master
Supporting JVM/Ring installing in Virtualenv
2013-03-18 03:09:03 -07:00
Mingli a9b4c52811 supporting virtualenv 2013-03-18 17:53:04 +08:00
Roberto De Ioris 5ce40b6ac8 fixed --req-logger after reload 2013-03-18 09:19:25 +01:00
Unbit b93dcbf46f removed download_url from setup.py 2013-03-17 08:10:12 +01:00
Unbit 8051a2bc98 prepare for 1.9 release 2013-03-17 07:15:24 +01:00
Unbit 78d8b221fc added --gevent-monkey-patch 2013-03-17 07:14:54 +01:00
Unbit d51cada284 second (and last i hope) part of mongrel2 support refactoring 2013-03-16 18:24:25 +01:00
Unbit 389eef9e88 first part of mongrel2 support refactoring 2013-03-16 18:02:11 +01:00
Unbit 270fb0c50d avoid routing loop 2013-03-16 16:48:26 +01:00
Unbit e7e9dfee88 fixed DragonFlyBSD support 2013-03-16 15:45:49 +01:00
Unbit 3bafae276d improved binary detection path on cygwin 2013-03-16 12:33:00 +01:00
Unbit cfebe2927d fixed lazy mode 2013-03-15 13:47:29 +01:00
Unbit 1d4294a845 added some comment for the statsd plugin 2013-03-15 11:34:19 +01:00
Unbit 12cfdd9864 added stats_pusher_statsd plugin 2013-03-15 11:32:08 +01:00
Unbit add930c517 fixed uuid support in cygwin 2013-03-15 07:31:41 +01:00
Unbit 32972978be added java support for cygwin 2013-03-13 17:50:56 +01:00
Unbit c8bad3550e added proper locking to windows 2013-03-13 15:51:14 +01:00
Unbit ecc55d789d added proper-locking to poll event mode 2013-03-13 15:03:30 +01:00
Unbit 88555e2c20 improved poll() support 2013-03-13 14:33:38 +01:00
Unbit ec2bfcd302 allows building router basicauth on cygwin 2013-03-13 11:14:32 +01:00
Unbit f1f81ed4c4 fixed python3 build 2013-03-13 11:00:05 +01:00
Unbit 87933cca26 another series of cygwin fixes 2013-03-13 10:51:33 +01:00
Unbit 2dcd8624a2 psgi support for windows 2013-03-13 10:12:24 +01:00
Unbit 7fcef76bbe experimental windows/cygwin support 2013-03-13 09:44:32 +01:00
Unbit 2a5c4e938d fixed requets overwrite in PATH_INFO rewrite (fixed typo) 2013-03-12 15:57:44 +01:00
Unbit 274eae27ef fixed requets overwrite in PATH_INFO rewrite 2013-03-12 15:56:30 +01:00
Unbit 207220bc50 fixed #180 2013-03-12 11:45:03 +01:00
Unbit fb8c4439c7 the whole ring test suite passes 2013-03-12 11:15:45 +01:00
Roberto De Ioris 894be9c41e let the /sequence ring test pass 2013-03-12 09:42:13 +01:00
unbit 0a4bff8963 Merge pull request #182 from guokr/master
Ring plugin tests
2013-03-12 00:27:11 -07:00
Mingli d515f3e279 add tests for ring plugin 2013-03-12 14:47:51 +08:00
Roberto De Ioris e8aa0e1e26 fixed a typecasting 2013-03-11 20:51:08 +01:00
Unbit 46a8aae908 added CacheGet to mono 2013-03-11 16:10:39 +01:00
Unbit a9f90464e6 fixed routing condition bug 2013-03-11 12:44:22 +01:00
Unbit 4bcdba2334 removed Changelog, we maintain them online 2013-03-11 12:16:44 +01:00
Unbit 64a8f3464a fixed routing goto 2013-03-11 10:37:10 +01:00
Unbit e640bd6f9b completed legion scroll 2013-03-11 09:44:50 +01:00
Unbit 71a6726bcf finally removed --app and static-offload-to-thread 2013-03-11 07:13:05 +01:00
Unbit fe13774b4b internal routing optimization 2013-03-11 07:05:58 +01:00
Unbit ecc3a5e8e2 another routing fix 2013-03-11 06:46:52 +01:00
Unbit dd1881576a removed grunt support 2013-03-10 22:22:16 +01:00
Unbit 322a2d2365 improved routing + static management 2013-03-10 21:30:54 +01:00
Unbit a76d7a1c66 first part of legion scroll implementation 2013-03-10 17:55:58 +01:00
Unbit 5631dcabf8 fixed --static-index when methods different from GET/HEAD are in place 2013-03-10 12:05:25 +01:00
Unbit 3f731e2577 Merge branch 'master' of github.com:unbit/uwsgi 2013-03-10 08:55:05 +01:00
Unbit 7a1b7f299b added --whitelist and --blacklist context 2013-03-10 08:54:45 +01:00
unbit 322673215e Merge pull request #178 from xrmx/coverity-buildconf
Add build profile for coverity scan
2013-03-09 15:28:44 -08:00
Riccardo Magliocchetti b58a0c4969 Add build profile for coverity scan
Add all the language plugins i can actually compile on my machine
so that we have a bit more plugin coverage instead of the plain make.
31 more bugs reported by Coverity scan.
2013-03-09 18:32:15 +01:00
Unbit c5fe8c6d30 reverted flock fd anti-leak 2013-03-09 18:13:18 +01:00
Unbit 7f54f5075d fixed a leak in routing api 2013-03-09 18:10:23 +01:00
unbit 95d4cea3bb Merge pull request #177 from xrmx/coverity10
More issues reported by Coverity
2013-03-09 09:03:55 -08:00
Riccardo Magliocchetti d6ff3ac018 core/legion: fix memory leak in wsgi_opt_legion_quorum
Reported by Coverity as CID #971024.
2013-03-09 17:04:57 +01:00
Riccardo Magliocchetti 1f4099c874 core/mule: fix a memory leak in uwsgi_setup_mules_and_farms
Reported by Coverity as CID #971028.
2013-03-09 17:01:18 +01:00
Riccardo Magliocchetti 8cd298de34 core/protocol: fix leak in send_udp_message
By moving the allocation after some early returns in case of error.

Reported by Coverity as CID #971033.
2013-03-09 16:52:20 +01:00
Riccardo Magliocchetti 851df33977 core/queue: close queue store after mmap()
Reported by Coverity as CID #971035.
2013-03-09 16:49:58 +01:00
Riccardo Magliocchetti 17f3f3d9a0 core/stats: fix memory leak in uwsgi_stats_pusher_setup
Reported by Coverity as CID #971039.
2013-03-09 16:46:49 +01:00
Riccardo Magliocchetti 4273489e42 core/uwsgi: fix memory leak in signal_pidfile
Reportd by Coverity as CID #971046.
2013-03-09 16:37:19 +01:00
Riccardo Magliocchetti 57077ac68c core/uwsgi: don't leak fd in flock related function
Reported by Coverity as CID #971047, #971048.
2013-03-09 16:34:32 +01:00
Riccardo Magliocchetti 45f61435a1 core: fix a couple of leaks in uwsgi_opt_load_dl
Reported by Coverity as CID #971049, #971050.
2013-03-09 16:27:57 +01:00
Riccardo Magliocchetti 28153af4ad plugin/python: fix leak in uwsgi_file_loader
Reported by Coverity as CID #971055.
2013-03-09 16:21:16 +01:00
Riccardo Magliocchetti 341cfd90b6 plugin/python: fix a leak in symimporter_load_module
Reported by Coverity as CID #971058.
2013-03-09 16:17:18 +01:00
Riccardo Magliocchetti 82342577a4 plugins/zergpool: fix a couple of memory leaks in add_zergpool_socket
Reported by Coverity as CID #971071, #971070.
2013-03-09 16:02:04 +01:00
Riccardo Magliocchetti 9d735fdbea plugins/python: don't copy router_name in py_uwsgi_route
No need to create a news string since uwsgi_route_api_func use it
for just a strcmp.

Reported by Coverity as CID #989251.
2013-03-09 15:50:02 +01:00
Unbit 1775526b89 improved asp.net support 2013-03-09 15:11:42 +01:00
Unbit c84f205c74 improved mono build 2013-03-09 12:56:40 +01:00
Unbit 591faabc00 fixed spooler plugin 2013-03-09 11:48:56 +01:00
Unbit e945003d07 fixed jwsgi plugin name 2013-03-09 11:27:25 +01:00
Unbit 26c6ec4283 fixed admin and echo plugins 2013-03-09 11:03:46 +01:00
Unbit b64884961d removed unused functions 2013-03-09 09:24:15 +01:00
Unbit 619e853a19 cache sync is working again 2013-03-09 06:34:48 +01:00
Unbit 050908a65e added a test for clojure rpc 2013-03-08 21:11:28 +01:00
Unbit bcb1e623d9 implemented uwsgi.rpc jvm function [test] 2013-03-08 20:59:05 +01:00
Unbit 57105c1bc7 implemented uwsgi.rpc jvm function 2013-03-08 20:58:52 +01:00
Unbit 8bb5b8a9f3 removed old java test 2013-03-08 20:30:26 +01:00
Unbit fba0d196ff fixed php body read 2013-03-08 20:23:09 +01:00
Unbit e29c50c9a5 prepare for JVM uwsgi.rpc() api function 2013-03-08 20:02:21 +01:00
Unbit 4ad9c8d034 fixed default cache set 2013-03-08 20:00:25 +01:00
Unbit 059b4c6ba3 ported cache magic api to go 2013-03-08 19:35:27 +01:00
Unbit 3ab96621db ported magic cache api to lua 2013-03-08 19:06:36 +01:00
Unbit 9bbe148112 ported magic cache api to php 2013-03-08 18:51:31 +01:00
Unbit e32de9b892 ported magic cache api to ruby 2013-03-08 18:12:12 +01:00
Unbit dea7f0fbb8 ported the new magic cache api to perl/psgi 2013-03-08 17:39:55 +01:00
Unbit a684bc6124 completed magic cache clear 2013-03-08 17:21:08 +01:00
Unbit 849ba0856f implemented cache magic exists and del 2013-03-08 17:04:36 +01:00
Unbit f728e277e2 fixed the cache router 2013-03-08 16:40:59 +01:00
Unbit d11fed3511 prepare for exists del and clear 2013-03-08 16:32:46 +01:00
Unbit f3b1acc55e completed cache magic update 2013-03-08 16:26:16 +01:00
Unbit 61722a7876 other improvements in the cache api 2013-03-08 16:16:49 +01:00
Unbit e418a35159 added cache check for max item size 2013-03-08 14:18:49 +01:00
Unbit cd29b033f0 reimplementation of the cache networking protocol to be fully non-blocking 2013-03-08 13:45:27 +01:00
Unbit f3f191558a removed the threaded cache server, it has been superseeded by the new async architecture 2013-03-08 11:29:56 +01:00
Unbit c728471b94 another update to the cache magic api 2013-03-08 11:23:26 +01:00
Unbit 4383578795 prepare for magic cache functions 2013-03-08 10:04:13 +01:00
Unbit b2f127a798 do not start the alarm thread if not needed 2013-03-08 09:19:40 +01:00
Unbit f8212f9e4b fixed alarm subsystem and added uwsgi.alarm to the JVM 2013-03-08 09:18:20 +01:00
Unbit 5e70986bc9 added JVM cache_get and lock/unlock 2013-03-08 08:12:51 +01:00
Unbit d61dff3c26 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-03-08 06:42:04 +01:00
Unbit 2b2da8b7f4 fixed #172 2013-03-08 06:41:46 +01:00
unbit 827b142577 Merge pull request #175 from gber/master
Add optional logging to notfound plugin
2013-03-07 10:40:26 -08:00
Guido Berhoerster d753e1aeef add option for enabling logging in notfound plugin 2013-03-07 19:27:13 +01:00
Unbit 8f7e5fc1bc fixed cache_update for lua 2013-03-07 13:23:24 +01:00
Unbit 650c251236 Merge branch 'master' of github.com:unbit/uwsgi 2013-03-07 13:14:51 +01:00
Unbit 3acb67bd2a try again semop() on interrupt 2013-03-07 13:14:31 +01:00
unbit f9f0eb45e5 Merge pull request #174 from kunkku/lua
Lua binding for cache update function
2013-03-07 01:52:39 -08:00
Kaarle Ritvanen fe0c1a4bb3 Lua binding for cache update function 2013-03-07 09:17:58 +00:00
Unbit eb90b773fa ported JWSGI to the new stable api and refactored ring plugin 2013-03-07 07:01:28 +01:00
Unbit 4f9369aa3a fork() friendly signal management 2013-03-06 20:16:09 +01:00
Unbit 2ae323feee better broodlord num computation 2013-03-06 19:55:20 +01:00
Unbit 56a79ae09c improved broodlord mode [2] 2013-03-06 19:11:49 +01:00
Unbit 48f6d5a240 improved broodlord mode 2013-03-06 19:05:38 +01:00
Unbit 49f717b616 fork() safe rpc subsystem 2013-03-06 18:21:39 +01:00
Unbit 77bae96c34 the ring support is complete 2013-03-06 16:09:06 +01:00
Unbit cbbaa24d6e completetd uwsgi.RequestBody jvm implementation 2013-03-06 14:44:49 +01:00
Unbit 37010c04ca implemented read() method for jvm input stream 2013-03-06 14:26:52 +01:00
Unbit 5902749f9d started implementing jvm body input stream 2013-03-06 13:51:42 +01:00
Unbit b1db1ae651 maintain python2.4 and centos5 compatibility 2013-03-06 13:24:51 +01:00
Unbit d96e394947 implemented ring content-length 2013-03-06 12:25:09 +01:00
Unbit 89891c80ae added ssl error clear even in the ssl router 2013-03-06 11:43:09 +01:00
Unbit edabc3cc6e fixed jvm build on python3 2013-03-06 11:15:16 +01:00
Unbit 9d4300d514 call ERR_clear_error after each https session close 2013-03-06 10:35:32 +01:00
Unbit af1eac9fcc correctly report REMOTE_ADDR and REMOTE_PORT in the fastrouter 2013-03-06 08:55:04 +01:00
Unbit fd50b1e054 allows loading custom classes 2013-03-05 19:23:17 +01:00
Unbit 1239e740ab better jvm class loading 2013-03-05 18:37:20 +01:00
Unbit f6535488e5 more tolerant ring support 2013-03-05 18:00:42 +01:00
Unbit c1c4dd01d2 ring + input_stream completed 2013-03-05 14:01:22 +01:00
Unbit 5cc9c8405a completed uwsgi_jvm_consume_input_stream 2013-03-05 13:56:30 +01:00
Unbit 990028697b Merge branch 'master' of github.com:unbit/uwsgi 2013-03-05 13:44:37 +01:00
Unbit 666c7c5b3f improved OSX jvm auto-detection 2013-03-05 13:40:35 +01:00
Unbit 1ccf9335dd prepare for managing InputStream 2013-03-05 07:58:01 +01:00
Unbit f90bb6b53c better iSeq detection in ring 2013-03-05 07:20:38 +01:00
Unbit 0ad74e282c better jvm paths detection 2013-03-04 21:40:47 +01:00
Unbit 34d6c0ad16 added some doc on top of the ring plugin 2013-03-04 21:36:06 +01:00
Unbit 4ceeb3b789 added more request item to the ring request map 2013-03-04 21:24:45 +01:00
Unbit 259c6c493f huge amount of jvm memory leak fixes 2013-03-04 21:18:59 +01:00
Unbit a3dd2e6efd added support ring clojure.io.file response 2013-03-04 16:50:37 +01:00
Unbit af3860dbd7 completed status and headers management for the ring plugin 2013-03-04 15:43:52 +01:00
Unbit 980b4f3c9a fixed type in yaml/ini parsers 2013-03-04 14:09:13 +01:00
Unbit efa0e0b27b added jvm api for iterations 2013-03-04 14:07:52 +01:00
Unbit d8d60e9a24 signals can now be registered even by non-fork friendly plugins 2013-03-04 06:48:25 +01:00
Unbit 6f5a521692 ported post_build hooks to the new build system 2013-03-04 06:14:22 +01:00
Unbit 522cbfe855 Merge branch 'master' of github.com:unbit/uwsgi 2013-03-04 06:11:27 +01:00
Unbit ed4425ee86 prepare for clojure/ring support 2013-03-04 06:11:07 +01:00
Unbit cb271e9a05 use exec/execfile instead of import in the build system 2013-03-04 06:10:28 +01:00
unbit 621cb99684 Merge pull request #170 from xrmx/coverity9
A few more coverity fixes
2013-03-03 13:46:35 -08:00
unbit 8600060d79 Merge pull request #169 from xrmx/coverity8
More issues reported by Coverity
2013-03-03 13:46:03 -08:00
Riccardo Magliocchetti 511a0aca0b plugins/http: remove self assignment
Also while at it cleanup the handling of the if branch around
the ifdefery.

Reported by Coverity as CID #970999.
2013-03-03 19:51:40 +01:00
Riccardo Magliocchetti 0b0a0ccce1 core/yaml: use size_t for buffer lenght in yaml_get_line
As the only user pass a size_t value and they have different
storage size.

Reported by Coverity as CID #970987.
2013-03-03 19:47:45 +01:00
Riccardo Magliocchetti e4e346772a core/ini: change ini_get_line size type
The only user of ini_get_line uses a size_t as size. Since off_t
and size_t have different storage size just switch ini_get_line
to size_t.

Reported by Coverity as CID #970984.
2013-03-03 19:44:30 +01:00
Riccardo Magliocchetti f102ef64da core/static: Add missing break in switch
Reported by Coverity as CID #970990.
2013-03-03 19:37:49 +01:00
Riccardo Magliocchetti 192c73d53d plugins/router_http: Fix copy and paste bug in uwsgi_routing_func_http
Don't redeclare ub_url since it is already there.

Reported by Coverity as CID #989243, #989252.
2013-03-03 19:29:50 +01:00
Riccardo Magliocchetti 07bd3f5df0 core/exception: avoid null pointer dereference in uwsgi_exception_run_handlers
If wsgi_req is NULL and uwsgi.reload_on_exception is True

Reported by Coverity as CID #989244.
2013-03-03 19:06:59 +01:00
Riccardo Magliocchetti eae00a5c77 core/subscription: fix wrong check in uwsgi_subscribe2
It looks like both s2_server and s2_key are mandatory in
uwsgi_send_subscription so fail if any of them is missing not both.

Reported by coverity as CID #989245.
2013-03-03 18:56:46 +01:00
Riccardo Magliocchetti 133dff6b76 core/alarm: fix memory leak in uwsgi_alarm_thread_loop
Rpoerted by Coverity as CID #989247.
2013-03-03 18:51:46 +01:00
Riccardo Magliocchetti cf634e11a9 core/exceptions: fix leak in uwsgi_exception_handler_thread_loop
Reported by Coverity as CID #989248.
2013-03-03 18:48:59 +01:00
Riccardo Magliocchetti 18dfd10b71 core/exceptions: fix memory leak in wsgi_exception_setup_handlers
Reported by Coverity as CID #989249.
2013-03-03 18:44:33 +01:00
Unbit 54b4189ab9 added uwsgi.java as the base for JVM request plugins 2013-03-03 18:43:22 +01:00
Riccardo Magliocchetti 7e58d78bfe proto/base: fix copy and paste bug in uwsgi_proto_base_cgi_prepare_headers
Reported by Coverity as CID #989253
2013-03-03 18:36:03 +01:00
Unbit 6497c93e3e completeted JVM multithread support 2013-03-03 15:38:01 +01:00
Unbit 27d637a9b2 report useful initialization message for the jvm 2013-03-03 14:40:09 +01:00
Unbit 296f9304ba Merge branch 'master' of github.com:unbit/uwsgi 2013-03-03 14:28:35 +01:00
Unbit a04420e5ef fixed jvm multiple args rpc 2013-03-03 14:28:09 +01:00
Unbit 2e4bc3dc6b allows mixing shared RPC with unshared 2013-03-03 13:56:38 +01:00
Unbit 773d853bb4 the RPC subsystem is no more dependent on cow 2013-03-03 13:28:06 +01:00
Unbit 92e06b1078 another series of improvements for the jvm 2013-03-03 12:36:35 +01:00
Unbit 1e6dd22fd8 prepare for new generation JVM plugin 2013-03-02 21:22:20 +01:00
unbit e5eba6be46 Merge pull request #168 from prymitive/ignore_nagios_requests
don't count ping requests
2013-03-02 11:24:11 -08:00
Łukasz Mierzwa 456729f6e2 don't count ping requests 2013-03-02 20:12:52 +01:00
Unbit 5f191b6e7f allows building the ruby plugin on heroku [3] 2013-03-02 16:16:54 +01:00
Unbit 7435235502 allows building the ruby plugin on heroku [2] 2013-03-02 16:14:32 +01:00
Unbit 764af285d3 allows building the ruby plugin on heroku 2013-03-02 16:09:59 +01:00
Unbit 3ed597368d completetd gemspec 2013-03-02 14:59:34 +01:00
Unbit 2119e06e38 allows building uwsgi as a gem 2013-03-02 14:34:09 +01:00
Unbit 0770fd8815 better error reporting on failed uploads 2013-03-02 13:59:22 +01:00
Unbit 6a94d1f91c fixed base64 decoding 2013-03-01 14:58:51 +01:00
Unbit f53c79cce7 Merge branch 'master' of github.com:unbit/uwsgi 2013-03-01 14:44:35 +01:00
Unbit a2e4c6e272 added isexec route condition 2013-03-01 14:44:15 +01:00
unbit ce898614a0 Merge pull request #165 from prymitive/carbon_hostname
add option for dot replacement in carbon hostname
2013-03-01 05:37:13 -08:00
Łukasz Mierzwa 0676c5e6a8 add option for dot replacement in carbon hostname 2013-03-01 14:13:48 +01:00
Unbit 1469e68a33 added --route-if and --route-if-not 2013-03-01 12:39:39 +01:00
Unbit f4ad33976d added --if-plugin and --if-not-plugin 2013-03-01 11:20:38 +01:00
Unbit c8e12a6be3 better to avoid RegisterSignal in Mono 2013-03-01 11:10:21 +01:00
Unbit 48af1b28d4 Mono RegisterSignal implementation 2013-03-01 09:43:33 +01:00
Unbit b8c115a127 better dummy plugin 2013-03-01 08:26:55 +01:00
Unbit c009ab82f5 sadly Mono is not fork() friendly 2013-03-01 08:19:44 +01:00
Unbit b0c421ff4b fixed Mono domains handling 2013-02-28 20:20:04 +01:00
Unbit a39ac59757 refactored cgi plugin 2013-02-28 14:42:43 +01:00
Unbit d3792cba72 fixed php build without pcre 2013-02-28 14:16:04 +01:00
Unbit 4aa17c40fc allows building without ssl 2013-02-28 14:08:15 +01:00
Unbit 38b1f52723 fixed static-index and apply_fast routes 2013-02-28 12:14:59 +01:00
Unbit 30e50df5d4 better header in mono plugin 2013-02-28 00:20:19 +01:00
Roberto De Ioris 22d9a2b831 fixed OpenBSD support 2013-02-28 10:02:56 +01:00
Unbit 6bccb62799 added for-glob 2013-02-27 23:48:56 +01:00
Unbit acd1215524 added asp.net dynamic applications 2013-02-27 23:36:01 +01:00
Unbit 4381e816ae fixed cache_del2 2013-02-27 23:00:50 +01:00
Unbit 5760338445 multi-app mode for mono 2013-02-27 09:19:50 +01:00
Unbit e517bcea7c implemented Mono send file from handle 2013-02-27 08:30:14 +01:00
Unbit b6bdafa669 another round of Mono methods implementation 2013-02-27 06:52:53 +01:00
Unbit 5bd10a99fb report unavailable lock engine 2013-02-27 04:28:11 +01:00
Unbit b8dfd1be85 fixed pthread locking ifdef bug 2013-02-27 04:10:20 +01:00
Unbit 3c810e5ca8 updated carbon plugin 2013-02-27 01:15:56 +01:00
Unbit 61a1ca4ca4 initialize alarm and exception thread ONLY in the master 2013-02-26 19:29:29 +01:00
Unbit a71d9953a1 fixed sign bug 2013-02-26 17:46:47 +01:00
Unbit b20fbf5fe8 re-added uwsgi.route() 2013-02-26 06:38:34 +01:00
Unbit c73490fc80 prepare for --mono-key 2013-02-26 02:09:38 +01:00
Unbit da6b052bef added --mono-gc-freq 2013-02-26 01:34:45 +01:00
Unbit 08ea52164c fixed BSD support for Mono 2013-02-26 09:58:17 +01:00
Unbit 4de3d534a8 first public release of the new Mono/ASP.NET plugin 2013-02-26 01:09:09 +01:00
Unbit 7be55d71a8 improved mono build system 2013-02-25 23:14:43 +01:00
Unbit 6e24730025 fixed mime type with static-index 2013-02-25 23:10:29 +01:00
Unbit 513380d5c9 first version of the new mono plugin 2013-02-25 17:50:19 +01:00
Unbit 2f474b2af4 added support for ruby 2 2013-02-25 07:33:05 +01:00
Unbit a062ef2ac2 added rb tmier in the PSGI plugin 2013-02-24 09:45:39 +01:00
Unbit b82566268a completeted the CoroAE plugin, added timers to the PSGI plugin 2013-02-24 09:41:33 +01:00
Unbit 8d16ce28b9 avoid async queue full log storming 2013-02-24 07:55:46 +01:00
Unbit 2a9835649e added --tcp-nodelay 2013-02-23 15:50:34 +01:00
unbit 9912ab6afb Merge pull request #157 from xrmx/coverity7
More issues reported by Coverity
2013-02-23 06:25:04 -08:00
Unbit 94f18e3508 allows --attach-daemon without workers 2013-02-23 14:45:20 +01:00
Unbit 25c812e4aa fixed --http-socket url decoding 2013-02-23 13:46:31 +01:00
Unbit bddf8fe5c9 completed --perl-arg and --perl-args 2013-02-23 13:24:59 +01:00
Unbit fbabb14c61 another heroku check [5] 2013-02-23 13:03:48 +01:00
Unbit fd62e2ebb7 another heroku check [4] 2013-02-23 12:59:13 +01:00
Unbit e96c43970d another heroku check [3] 2013-02-23 12:54:00 +01:00
Unbit 99eda6d084 another heroku check [2] 2013-02-23 12:51:20 +01:00
Unbit 91b2cc7570 another heroku check 2013-02-23 12:47:06 +01:00
Unbit 0ff6277f28 prepare for perl args 2013-02-23 12:46:14 +01:00
Unbit dee99b6535 try to understand how heroku installed python [9] 2013-02-23 11:57:48 +01:00
Unbit 39260ebac0 try to understand how heroku installed python [8] 2013-02-23 11:53:47 +01:00
Unbit ac3ec1781e try to understand how heroku installed python [7] 2013-02-23 11:46:33 +01:00
Unbit e8925ac7b7 try to understand how heroku installed python [6] 2013-02-23 11:42:55 +01:00
Unbit 2877a5a05d try to understand how heroku installed python [5] 2013-02-23 11:40:50 +01:00
Unbit 9e3bfd261a try to understand how heroku installed python [5] 2013-02-23 11:38:34 +01:00
Unbit 636cd261e0 try to understand how heroku installed python [4] 2013-02-23 11:26:21 +01:00
Unbit 5fff6467a8 try to understand how heroku installed python [4] 2013-02-23 11:24:42 +01:00
Unbit 647c972ffe try to understand how heroku installed python [3] 2013-02-23 11:21:12 +01:00
Unbit ed9ac16c78 try to understand how heroku installed python [2] 2013-02-23 11:14:01 +01:00
Unbit 4f1b610459 try to understand how heroku installed python 2013-02-23 11:11:25 +01:00
Unbit a68b9b9fa6 attempt to better build on non-share-library configs 2013-02-23 11:08:41 +01:00
Unbit cd8e9f62b2 fixed GIL in new body reading system 2013-02-23 08:28:27 +01:00
Unbit f3ee043246 fixed a refcnt bug in psgi plugin 2013-02-23 08:26:57 +01:00
Riccardo Magliocchetti 949fdb5f86 core/cache: fix memory leak
Reported by Coverity as CID #981514.
2013-02-22 08:42:49 +01:00
Riccardo Magliocchetti d1c8a02151 core/io: check realloc() return value
Reported by Coverity as CID #981513.
2013-02-22 08:42:33 +01:00
Riccardo Magliocchetti 7c0f002239 core/emperor: fix memory leak on error path
Reported by Coverity as CID #971011.
2013-02-22 08:15:55 +01:00
Riccardo Magliocchetti 4d236b9b74 core/cache: close() mmapped cache store
The file will actually get closed when unmapped but we should
remove our reference to it.

Reported by Coverity scan as CID #971009.
2013-02-22 07:54:51 +01:00
Riccardo Magliocchetti 8d39eabf9d core/alarm: fix memory leak
Reported by Coverity scan as CID #971007.
2013-02-22 07:49:42 +01:00
unbit 591cec9a2c Merge pull request #156 from prymitive/fix_travis
Make travis fail is test request had errors
2013-02-20 05:46:31 -08:00
Łukasz Mierzwa 057d0bc250 add -f switch to curl options so that it will exit with non-zero return code if request fails 2013-02-20 13:38:38 +01:00
Unbit 252731544b it is too early to automatically build the router_memcached plugin 2013-02-20 11:42:33 +01:00
Unbit cdb901c091 another series of routing porting to the new api 2013-02-20 11:41:30 +01:00
Unbit 00c5a77554 new routing translator functions 2013-02-20 11:33:33 +01:00
Unbit 0e5f8acde5 goto label can be build from regexp 2013-02-20 07:57:46 +01:00
Unbit d2ae982329 improved routing label 2013-02-20 06:51:38 +01:00
Unbit 5307de6974 added uwsgi_buffer json escaper 2013-02-19 19:09:27 +01:00
Unbit dc2f9f405d added redirect-301 internal router instruction 2013-02-19 12:39:42 +01:00
Unbit e610682b31 added exception_log plugin 2013-02-19 12:34:43 +01:00
Unbit 34b6bc5378 preliminary support for exception handlers 2013-02-19 10:59:48 +01:00
Unbit 3d171f52b3 report client address and client port on corerouter errors 2013-02-19 09:01:41 +01:00
Unbit cfa4d2a3ad added ipv6 in corerouters 2013-02-19 08:19:47 +01:00
Unbit 12bf2cd3af fixed exception management in python mules and improved uwsgidecorators 2013-02-19 07:11:45 +01:00
Unbit 5089123e5a prepare for ipv6 support in corerouters 2013-02-18 18:21:57 +01:00
Unbit 4d53d3a16a added more logvars 2013-02-18 13:05:43 +01:00
Unbit 941dd70e3b added additional infos in the exceptions catcher 2013-02-17 16:24:36 +01:00
Unbit 609b5aeb0a porte the ruby/rack plugin to the new exception api 2013-02-17 16:18:12 +01:00
Unbit 8e6b810df8 fixed lua plugin 2013-02-17 14:27:32 +01:00
Unbit f31186a0f9 completetd first part of the new exceptions framework 2013-02-17 14:26:31 +01:00
Unbit b5a6da5448 refactored catch_exceptions 2013-02-17 11:22:09 +01:00
Unbit 0a9b5f05b0 prepare for advanced exception management 2013-02-17 10:12:49 +01:00
Unbit 7c8ae1737a fixed reports in xmpp alarm 2013-02-17 09:33:03 +01:00
Unbit 0e502172c9 added websockets tolerance 2013-02-16 13:31:01 +01:00
Unbit 0dd2a34e22 improved websockets support 2013-02-16 13:13:04 +01:00
Unbit f4b8f3e49d fixed a stupid bug in websocket ruby example 2013-02-16 10:23:04 +01:00
Unbit 9610ec72ab openindiana fixes 2013-02-15 22:24:35 +01:00
Unbit 32bf82552e added SCGI support 2013-02-15 19:08:28 +01:00
Unbit d15f1a9e36 prepare for SCGI support 2013-02-15 17:53:06 +01:00
Unbit 5e02bc3c84 UWSGI_ALARM is no more required 2013-02-15 12:26:45 +01:00
Unbit d397036e29 improved the alarm subsystem 2013-02-15 12:17:29 +01:00
Unbit c92fde03b9 various micro-optmizations in async, caching and static file serving 2013-02-15 08:11:33 +01:00
Unbit e1598af32f fiber requiers async mode 2013-02-14 20:53:13 +01:00
Unbit fbfab14224 improved fiber support 2013-02-14 20:49:26 +01:00
Unbit 8ff56a694a added --http-socket-modifier1 and --http-socket-modifier2 2013-02-14 20:10:56 +01:00
Unbit 639f26ff26 improved fastcgi support 2013-02-14 20:08:35 +01:00
Unbit 7d8a2968d5 first part of the fastcgi porting to the new api 2013-02-14 17:30:23 +01:00
Unbit f70c7c1e17 report worker id during gevent requests waiting 2013-02-14 12:13:33 +01:00
Unbit a89eb5d8cb report go version on startup 2013-02-14 12:11:49 +01:00
Unbit 4c9d30cc1b ported Go to the new api 2013-02-14 11:34:33 +01:00
Unbit fd7d4fc944 greatly improved chain reload in gevent mode 2013-02-14 10:12:24 +01:00
Unbit 7106301d86 report write_errors in core statistics 2013-02-14 09:27:04 +01:00
Unbit f046d47eb2 worker's busy value is now dinamically computed 2013-02-14 09:17:59 +01:00
Unbit 0b8b6346be ported router_uwsgi to the new api 2013-02-13 16:20:40 +01:00
Unbit 104c8a8b90 fixed routing + ugreen 2013-02-13 12:23:46 +01:00
Unbit f25ab0fdd2 more improvements on the non-blocking api 2013-02-13 12:07:07 +01:00
Unbit bb789d1ac0 fixed cheaper 2013-02-13 08:56:43 +01:00
Unbit e94315ca75 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-02-12 18:12:17 +01:00
unbit dd2e07122a Merge pull request #151 from xrmx/ipleak
core: don't leak ip in uwsgi_open_and_read()
2013-02-12 10:19:52 -08:00
Unbit 375d446bf0 mules and gateways are correctly managed 2013-02-12 19:18:54 +01:00
Unbit 46eafeaa58 graceful reload is working again 2013-02-12 18:47:53 +01:00
Unbit 79dccaac9c first big (really bug) master refactoring 2013-02-12 18:42:36 +01:00
Unbit cdf05dcef2 make older compilers happy 2013-02-12 18:12:04 +01:00
unbit 7d8aa98766 Merge pull request #155 from prymitive/carbon_requests_fix
fixed carbon requests metric
2013-02-11 22:14:24 -08:00
Łukasz Mierzwa 115470837e fixed carbon requests metric 2013-02-11 20:51:58 +01:00
Unbit c226feaeca added --touch-chain-reload 2013-02-11 20:10:43 +01:00
Unbit 669c14ac71 fixed subscription reference count 2013-02-11 20:03:52 +01:00
Unbit 1c5347ac90 added router_memcached plugin 2013-02-11 18:57:58 +01:00
Unbit 83ce30a51e added an heavy test for new caching system 2013-02-11 16:57:03 +01:00
Unbit f75a637ef6 implemented cache bitmap blocks unmarking 2013-02-11 14:50:55 +01:00
Unbit 48d749f11b prepare for unmarking function 2013-02-11 14:20:10 +01:00
unbit 3f041350a2 Update README 2013-02-11 14:11:36 +01:00
Unbit 39613d466a other improvements for bitmap based caching 2013-02-11 14:09:40 +01:00
Unbit 3c32980fe3 forget to reset SIGCHLD to SIG_DFL 2013-02-10 20:13:32 +01:00
Unbit a1fbed315f reset sigmask on startup 2013-02-10 19:51:36 +01:00
Unbit c0083c5801 first commit for bitmap based cache 2013-02-10 12:11:47 +01:00
Unbit f86404f03f fixed FreeBSD sendfile 2013-02-09 18:16:37 +01:00
unbit 602f0385cb Merge pull request #153 from prymitive/cheaper_zero_fix
additional validation of the --cheaper value at startup
2013-02-09 07:22:34 -08:00
Łukasz Mierzwa c32da58a7c additional validation of the --cheaper value at startup 2013-02-09 14:15:35 +01:00
Riccardo Magliocchetti d64a734292 core: don't leak ip in uwsgi_open_and_read()
While at it convert malloc() to uwsgi_malloc() to cleanup error
handling.

Reported by Coverity Scan as CID #971018.
2013-02-09 12:49:35 +01:00
Unbit 65c047dca1 added timebomb concept and improved gevent reloading 2013-02-09 07:55:12 +01:00
Unbit 73b1887287 fixed #34 2013-02-08 21:06:42 +01:00
Unbit 8d41a77baa coro and gevent improvements 2013-02-08 07:01:04 +01:00
Unbit 0692bf45da fixed a stupid bug in protocol parser 2013-02-07 21:09:22 +01:00
Unbit 9d5d439191 rpc subsystem is now async/greenthreads friendly 2013-02-07 18:31:44 +01:00
Unbit 9f15345183 prepare dor async-friendly rpc 2013-02-07 17:23:59 +01:00
Unbit 7d84413038 added a note on cheap string 2013-02-07 16:49:42 +01:00
Unbit ecd4b9bc36 added notes for the new caching plugin 2013-02-07 16:15:26 +01:00
Unbit 47d66ab368 ported cache store system to the new api 2013-02-07 16:01:15 +01:00
Unbit 54227db3e4 cache syncing is working again 2013-02-07 15:42:14 +01:00
Unbit aecd9a7703 ported udp cache server to the new api 2013-02-07 15:33:01 +01:00
Unbit dd0551bf68 ported the cache sync client system to the new api 2013-02-07 15:21:32 +01:00
Unbit d649853a51 ported cache udp nodes to the new api 2013-02-07 15:12:58 +01:00
Unbit 05ad7bf07e fixed suspend when harakiri is in place 2013-02-07 14:10:13 +01:00
Unbit f29ac2117f refactored mod_proxy_uwsgi 2013-02-07 13:35:43 +01:00
Unbit 91be1f8929 really apply PATH_INFO fix in mod_proxy_uwsgi 2013-02-07 11:43:59 +01:00
Unbit 1e9c8c47bb add copyright notes in mod_proxy_uwsgi and correctly decode PATH_INFO/SCRIPT_NAME 2013-02-07 10:05:15 +01:00
Unbit 63c8ce3bf8 updated mod_uwsgi copyright notes 2013-02-07 09:43:01 +01:00
Unbit d13b58869d fiber fixes 2013-02-04 11:23:47 +01:00
Unbit 49740e99fb Merge branch 'master' of github.com:unbit/uwsgi 2013-02-04 11:02:43 +01:00
unbit 09b136ed2c Merge pull request #149 from prymitive/alarm_curl
ifdefed stuff only available in newer curl releases
2013-02-05 03:30:59 -08:00
Łukasz Mierzwa 5be46f0cb3 ifdefed stuff only available in newer curl releases 2013-02-05 11:50:06 +01:00
Unbit e5094e7efa ruby/rack websockets support 2013-02-04 11:02:24 +01:00
Unbit 60580a0195 prepare for ruby websockets + fibers support 2013-02-04 08:55:19 +01:00
Unbit 0a73039cfc improved ugreen support and cgi integration 2013-02-04 04:56:13 +01:00
Unbit 94aed13978 simplified --http-websockets 2013-02-03 20:52:42 +01:00
Unbit 9679645354 Coro::AnyEvent + websockets is working 2013-02-03 20:38:30 +01:00
Unbit 0c1a25b8a6 coroae fixes 2013-02-03 17:03:59 +01:00
Unbit 4a3c1e537b zmq need a bit more work... 2013-02-03 15:58:29 +01:00
Unbit c355c93f12 ported ping plugin to the new api 2013-02-03 14:17:39 +01:00
Unbit 5552e87087 generalized offload subsystem 2013-02-03 14:14:00 +01:00
Roberta Giordano 67544158d9 osx fixes 2013-02-04 13:08:16 +01:00
Unbit f117f404fc fixed a regression with sendfile() 2013-02-03 10:57:13 +01:00
Unbit d4130dbc4b first round of protocol parsers optimizations
preliminary api for language-independent body read

another step

completed body read language independent implementation

ported gevent to the new read/write api

ported websockets to the new read/write api

removed channels subsystem

removed channels subsystem

ported lua to the new read/write api

fixed post-buffering

readline is still broken

improved request body readline

very difficult test for readline()/read() combo passed

other improvements in postbuffering/read/readline

ported --http-socket to the new api

added X-Forwarded-SSL management

removed old api

more refactoring

ported the RACK plugin to the new api

ported psgi plugin to the new api

defintely removed clustering

simpified ifdel hell

simpified ifdef hell

removed useless configuration options
2013-02-03 10:38:13 +01:00
Unbit e50a7c518f improved alarm_xmpp plugin 2013-01-31 09:56:20 +01:00
Unbit 874b994e66 added --static-gzip-* options 2013-01-31 07:49:19 +01:00
Unbit cc93687476 better support for robust mutexes 2013-01-30 18:31:15 +01:00
Unbit e354f3b37a fixed PTHREAD_PRIO_INHERIT 2013-01-30 18:07:24 +01:00
Unbit d204e75c1c added --thunder-lock 2013-01-30 17:59:00 +01:00
Unbit 8c0e77b737 fixed SERVER_PORT in routers when shared sockets are in place 2013-01-30 16:31:11 +01:00
Unbit 70f12c4407 fixed backlog reporting on 32bit 2013-01-30 14:06:09 +01:00
Unbit ac78830a90 offloading by default, if available 2013-01-30 13:22:02 +01:00
Unbit 534f78acb3 improved sendfile management 2013-01-30 12:51:13 +01:00
Unbit 443c2c5a29 better route/sendfile/offload logging 2013-01-30 12:24:38 +01:00
Unbit feca5abc53 announce only spdy3 2013-01-30 08:30:33 +01:00
unbit c643c3069c Merge pull request #143 from xrmx/coverity6
Fix some leaks reported by Coverity scan
2013-01-30 10:57:36 -08:00
unbit 1cffe0dfe6 Merge pull request #142 from prymitive/router_delta
add last_request attribute to subscription node, it will hold the number...
2013-01-30 09:45:07 -08:00
Łukasz Mierzwa 3761709ec4 add last_request attribute to subscription node, it will hold the number of requests since last subscription ping
use node->last_requests instead of absolute request counter in (w)lrc
2013-01-30 18:32:06 +01:00
Riccardo Magliocchetti 956f54033c plugins/http: fixup some leaks in spdy
Reported by Coverity as CID #971245, #971246.
2013-01-30 18:05:42 +01:00
Riccardo Magliocchetti 7afd4e39eb proto/zeromq: Don't leak ub on write error in uwsgi_proto_zeromq_writev_header
Reported by Coverity as CID #971247.
2013-01-30 17:43:45 +01:00
Unbit 76866a05ba fixed realloc() usare in core/io.c as spotted by cppcheck [2] 2013-01-29 16:31:48 +01:00
Unbit 74eeee48ae fixed realloc() usare in core/io.c as spotted by cppcheck 2013-01-29 16:28:45 +01:00
Unbit 3babcbe2bb added --route-referer 2013-01-29 12:07:56 +01:00
Unbit 1a50463ed9 --sslrouter and --sslrouter2 to be more aligned with --https 2013-01-29 10:57:30 +01:00
Unbit a88244a700 fixed --sslrouter-sni 2013-01-29 10:51:04 +01:00
Unbit 7cf4cc788c added --sni-dir 2013-01-29 09:44:20 +01:00
Unbit 990e7241e6 added the sslrouter and various corerouters micro-optimizations 2013-01-29 09:08:41 +01:00
unbit 40d69f90d9 Merge pull request #141 from xrmx/coverity5
Check return value of library call Coverity issues
2013-01-28 13:52:56 -08:00
Unbit 194f4897e3 new rbtree implementation 2013-01-28 22:22:29 +01:00
Riccardo Magliocchetti d56e35651b core/cluster: log sendto() error
Reported by Coverity as CID #970958.
2013-01-28 19:41:41 +01:00
Riccardo Magliocchetti 58314c2800 core: log when sendmsg fails
Reported by Coverity as CID #970962, #970963.
2013-01-28 18:41:08 +01:00
Riccardo Magliocchetti 0af894df06 core: log when fcntl() fails
Reported by Coverity as CID #970967, #970966.
2013-01-28 18:37:28 +01:00
Riccardo Magliocchetti 9bfcec2999 lib/linux_ns: check mkdir() return value
Fail earlier if we can't create the dirs we need.
Reported by Coverity as CID #970969.
2013-01-28 18:31:15 +01:00
Unbit 65c513bec2 when the emperor has a master, allows it to respawn the dead emperor 2013-01-28 16:35:12 +01:00
Unbit ec3a95dafb fixed request log routing 2013-01-28 10:59:26 +01:00
Unbit 8386d7829d fixed fastrouter read body hook 2013-01-28 10:45:27 +01:00
Unbit bb9c3e0d6c logformat can now create apache compatible logs 2013-01-28 09:42:11 +01:00
Unbit bc5b71a5ec Merge branch 'master' of https://github.com/unbit/uwsgi 2013-01-28 09:34:22 +01:00
Unbit 2cdf1b7265 fill empty logvars 2013-01-28 09:34:09 +01:00
unbit 162c861e74 Merge pull request #137 from prymitive/reload_mercy_for_cheaped
reload/cheap mercy for invidual workers
2013-01-28 00:19:55 -08:00
unbit edb9c5f982 Merge pull request #138 from prymitive/php_new_cache
fixed php plugin to use new cache api
2013-01-28 00:01:22 -08:00
Łukasz Mierzwa c88be57dd9 refactored php plugin to use new cache api 2013-01-28 00:44:41 +01:00
Łukasz Mierzwa c1682f4ee4 reload/cheap mercy for invidual workers 2013-01-27 23:19:50 +01:00
Unbit 799ac9310f after years we can finally differentiate between stderr and request logging 2013-01-27 17:59:23 +01:00
unbit 2540e739c7 Merge pull request #136 from xrmx/coverity4
More issues reported by Coverity
2013-01-27 04:54:54 -08:00
Riccardo Magliocchetti 43ee6a305f plugin/python: fix some leaks on error paths in symimporter
Reported by Coverity as CID #971059, #971060.
2013-01-27 12:36:54 +01:00
Riccardo Magliocchetti 0cb2e6852b plugins/python: fix tracebaker resource leaks on import error
Reported by Coverity as CID #971061, #971062, #971063.
2013-01-27 12:19:45 +01:00
Riccardo Magliocchetti a559e9ea63 plugins/python: fix a couple of memory leaks
Reported by Coverity as CID #971065, #971066.
2013-01-27 12:10:19 +01:00
Riccardo Magliocchetti 89dfa7976a core/socket: fix a couple of memory leaks
Reported by Coverity as CID #971053, #971054.
2013-01-27 11:54:48 +01:00
Unbit 56a8d44cb0 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-01-27 11:37:41 +01:00
Unbit 7fc644d1a8 fixed uwsgi_cache_create definition 2013-01-27 11:37:23 +01:00
Riccardo Magliocchetti 74d6bac54b plugins/python: check return value of PyType_Ready in init_uwsgi_embedded_module
Reported by Coverity as CID #970972.
2013-01-27 10:33:17 +01:00
Riccardo Magliocchetti 5647aff995 plugins/python: remove double assignment to same variable
Which coverity reports as undefined behaviour in CID #970978.
2013-01-27 10:22:31 +01:00
Riccardo Magliocchetti cf67363164 core: prefer strncpy over strcpy in emperor
Coverity reports a possible buffer overrun which is not possible
at the momento because the only caller of uwsgi_emperor_blacklist_add
use another fixed buffer of the same size as te one we are writing
to. Still better safe than sorry. Reported as CID #971078.
2013-01-27 10:17:01 +01:00
Roberta Giordano 1bdec68fb7 added uagent to logvars 2013-01-27 09:34:55 +01:00
Unbit 5698955384 added ltime logformat 2013-01-27 08:59:05 +01:00
unbit 732466e4e4 Merge pull request #133 from xrmx/coverity3
Fix "argument cannot be negative" errors reported by Coverity
2013-01-26 22:21:44 -08:00
unbit 23165a1587 Merge pull request #132 from xrmx/coverity2a
More issues reported by Coverity
2013-01-26 22:20:15 -08:00
unbit d9a8e071e2 Merge pull request #131 from xrmx/coverity
Fix some issues spotted by coverity scan
2013-01-26 22:18:03 -08:00
Riccardo Magliocchetti e106a6ef61 plugins/python: check uwsgi_connect return code in uwsgi_python_harakiri
Reported by Coverity as CID #970996.
2013-01-26 21:23:17 +01:00
Riccardo Magliocchetti 297bd429a9 core: check return of uwsgi_connect in uwsgi_opt_connect_and_read
Reported by Coverity as CID #970995.
2013-01-26 21:18:55 +01:00
Riccardo Magliocchetti 838bdd27a6 core: check return of getgroups()
When we pass 0 as size to getgroups() the number of additional
groups is return. If it returns error or 0 don't even try to
poke for additional groups.

Reported by Coverity as CID #970944.
2013-01-26 21:10:33 +01:00
Riccardo Magliocchetti f50e179100 core: don't call dup2 on negative fd after open() error
Also call close() only if open was succesful.
Reported by Coverity as CID #970991.
2013-01-26 21:00:11 +01:00
Riccardo Magliocchetti c6ddaf6b8d core: add missing legion mutex unlock on error path
Reported by Coverity as CID #970988.
2013-01-26 19:45:46 +01:00
Riccardo Magliocchetti cbc06f92d0 core: add missing unlock in wsgi_req_accept
Reported by Coverity as CID #970989.
2013-01-26 19:29:46 +01:00
Riccardo Magliocchetti 386fac2421 core: fix copy & paste bug in uwsgi_manage_command_cron
It looks like tm_hour is used where tm_mon was intended.
Reported by Coverity as CID #970975.
2013-01-26 19:18:15 +01:00
Riccardo Magliocchetti 3138d0b6c3 plugins/carbon: add missing call to va_end()
Reported by Coverity as CID #971091.
2013-01-26 19:14:52 +01:00
Riccardo Magliocchetti 135a5a505c lib/linux_ns.c: fix some possible null pointer dereferences
In case we cannot open /self/proc/mounts or it is malformed.
Spotted by Coverity, CID #971002, #971003.
2013-01-26 19:06:49 +01:00
Riccardo Magliocchetti 1b47a8932e plugins/cache: fix resource leak
Reported by Coverity, CID #971053.
2013-01-26 18:44:08 +01:00
Riccardo Magliocchetti 01e4d07fb8 plugins/corerouter: use correct goto label
After cwd has been allocated we should exit through end0.
Spotted by Coverity, CID #971054.
2013-01-26 18:39:37 +01:00
Riccardo Magliocchetti ec1bfdeb2a plugins/router_http: fix leak if connection to host fails
Fix Coverity CID #971069.
2013-01-26 18:29:36 +01:00
Riccardo Magliocchetti ac3d617037 core: remove spurious call to dlsym
Fix use after free reported by Coverity, CID #971090
2013-01-26 18:13:11 +01:00
Roberta Giordano 253805daa6 added rsize,hsize and cl logvars, added logvar: routing instruction 2013-01-26 17:25:18 +01:00
unbit 63e4964808 Merge pull request #130 from prymitive/busyness_ifdef_fix
better backlog ifdef in cheaper_busyness
2013-01-26 05:41:00 -08:00
Łukasz Mierzwa 57962d2e6e better backlog ifdef in cheaper_busyness 2013-01-26 14:08:29 +01:00
unbit f81ea8e898 Merge pull request #109 from prymitive/busyness_backlog
spawn new workers if backlog is > 0 for some time
2013-01-26 05:04:24 -08:00
Łukasz Mierzwa 821af5d763 spawn new workers if backlog is > 0 for some time 2013-01-26 13:59:42 +01:00
unbit 2e923aaf9e Merge pull request #128 from prymitive/rsyslog_fixes
split messages > 995 bytes into chunks in rsyslog plugin
2013-01-26 03:46:12 -08:00
Łukasz Mierzwa 15b12983e1 * add buf to uwsgi_logger struct and use it when logger needs buffering (rsyslog + graylog2)
* allow to split big syslog messages into chunks
* allow to set maximum syslog packet size (some syslog deamons support that)
2013-01-26 12:37:23 +01:00
unbit 15f0f8d294 Merge pull request #125 from prymitive/worker_lifetime
new options to control worker minimum and maximum lifetime
2013-01-26 03:29:34 -08:00
unbit c6658fca72 Merge pull request #129 from prymitive/named_cache_stats
don't free lock name of a named cache
2013-01-26 03:22:13 -08:00
Łukasz Mierzwa 5bbc7ee673 don't free lock name of a named cache 2013-01-26 11:56:16 +01:00
Unbit 37927c6f5d ported sweepers to the new api and added more statistics 2013-01-26 07:43:12 +01:00
Unbit 1a6ee9a775 added --emperor-procname 2013-01-26 04:11:07 +01:00
Unbit d42649d80b implemented SPDYv3 WINDOW UPDATE 2013-01-25 18:58:11 +01:00
Unbit 2acd338429 SPDY improvements 2013-01-25 17:38:42 +01:00
Unbit 7adcb19d1a fixed --http-to-https 2013-01-25 12:51:26 +01:00
Unbit a2f776b487 fixed rawrouter allocation bug 2013-01-25 11:00:29 +01:00
Unbit 941ae2b5e3 better non-blocking support for protocols 2013-01-25 10:38:10 +01:00
Unbit e88d4bbb79 improved expect-continue management 2013-01-25 09:41:39 +01:00
Unbit db352999b8 --check-cache takes an optional parameter (the cache name) 2013-01-24 20:43:15 +01:00
Unbit 744fed60b9 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-01-24 20:41:00 +01:00
Unbit df85a8e6a9 added uwsgi_cache_safe_get2() commodity function 2013-01-24 20:40:43 +01:00
unbit 7ba7fd55d0 Merge pull request #126 from prymitive/master_init_fix
One more fix is needed for master branch
2013-01-24 11:32:47 -08:00
Łukasz Mierzwa 6fd2176b3e fixed new cache typo 2013-01-24 20:25:11 +01:00
Unbit 271ac33193 fixed a regression caused by new caching system 2013-01-24 20:20:14 +01:00
Unbit 8d33491211 added magix gzipper in http corerouter and added sessions counter in corerouters 2013-01-24 19:31:50 +01:00
Unbit 13a42599ea corerouters --*-use-cache option can take an optional cache name 2013-01-24 10:24:46 +01:00
Unbit cb8878dc81 --ssl-sessions-use-cache can take the cache name as parameter 2013-01-24 10:03:07 +01:00
Unbit 5e561c0d1e --cache2 is ready 2013-01-24 09:02:53 +01:00
Unbit fbfe58948b prepare for the --cache2 option 2013-01-23 20:38:55 +01:00
Unbit e839a9eb89 ported psgi and rack plugin to the new caching api 2013-01-23 20:32:52 +01:00
Unbit b90779aecf improved the caching subsystem to allows dynamic key 2013-01-23 20:16:49 +01:00
Unbit 2447f819cb first commit of the new caching infrastructure 2013-01-23 16:15:43 +01:00
Roberto De Ioris 6f956c6965 fixed gzip encoding 2013-01-22 18:28:40 +01:00
Roberto De Ioris 729fdd22c4 preliminary support for uWSGI-Encoding magic header 2013-01-21 19:24:27 +01:00
Łukasz Mierzwa 7b59668386 new options to control worker minimum and maximum lifetime 2013-01-21 16:44:43 +01:00
Roberto De Ioris 1e5739f8ea added core/strings.c 2013-01-21 16:41:33 +01:00
Roberto De Ioris 3ef7e9aee3 added --rem-header support 2013-01-21 16:13:20 +01:00
Roberto De Ioris 4854b3cbcf fixed rack plugin 2013-01-21 14:55:35 +01:00
Roberto De Ioris 5273dbba90 maintain after_hook test in welcome.py 2013-01-21 14:53:40 +01:00
Roberto De Ioris b59f3b254f fixed buf in python uwsgi.workers() 2013-01-21 14:50:27 +01:00
Roberto De Ioris dda6bb2a5f dump request vars in stats (if possibile and safe) 2013-01-21 14:24:42 +01:00
Roberto De Ioris 0daff2cfe2 multithread corner case fixes 2013-01-21 12:12:36 +01:00
Roberto De Ioris 61ee03a99e improved http keepalive 2013-01-21 10:15:26 +01:00
Roberto De Ioris 06b6704be3 tempoarily disable fastcgi support to continue building with clang 2013-01-21 09:07:15 +01:00
Roberto De Ioris ab2a8c90cd fixed http router 2013-01-20 20:51:48 +01:00
unbit 21ada10805 Merge pull request #123 from prymitive/busyness_backlog_fixes
Better backlog messages in cheaper_busyness
2013-01-20 10:22:51 -08:00
Łukasz Mierzwa 3d8467506a better log messages when backlog is over limit but we already started max number of workers 2013-01-20 18:52:27 +01:00
Roberto De Ioris 8f996bb68d fixed go plugin 2013-01-20 18:04:06 +01:00
Roberto De Ioris 9f55579b87 added support for automatic status codes 2013-01-20 17:29:03 +01:00
Roberto De Ioris 215e514385 tiny fixes in the psgi plugin 2013-01-20 17:06:29 +01:00
Roberto De Ioris 77bd73d597 psgi plugin improvements 2013-01-20 16:25:39 +01:00
Roberto De Ioris 3642198acd added gevent.h 2013-01-20 16:01:39 +01:00
Roberto De Ioris 810a1463d5 started porting the gevent plugin to the new api 2013-01-20 16:00:11 +01:00
Roberto De Ioris d3dfdbb0ba refactoring [2] 2013-01-20 15:34:24 +01:00
Roberto De Ioris f71f76c6e6 refactoring 2013-01-20 15:20:35 +01:00
Roberto De Ioris 287a8c8a24 improved notfound plugin 2013-01-20 14:46:39 +01:00
Roberto De Ioris 70d9dab5ef avoid wasting resources on failed writes... 2013-01-20 14:45:40 +01:00
Roberto De Ioris c9987aa721 ported http-socket to the new api 2013-01-20 14:35:06 +01:00
Roberto De Ioris 874e8b5621 completed port of the python plugin to the new writing api 2013-01-20 14:17:54 +01:00
Roberto De Ioris 4b3b3f9200 need to fix go support 2013-01-20 13:14:34 +01:00
Roberto De Ioris 994209ffb0 another bunch of portings 2013-01-20 13:08:10 +01:00
Roberto De Ioris 4cd5643c8f ported lua to the new api 2013-01-20 13:01:23 +01:00
Roberto De Ioris b7e2eaad0f ported the example plugin 2013-01-20 12:52:58 +01:00
Roberto De Ioris 71a5e8b768 ported php to the new api 2013-01-20 12:46:52 +01:00
Roberto De Ioris 6044af9e7a ported the cgi plugin to the new write api 2013-01-20 12:36:17 +01:00
Roberto De Ioris 4e2178ffab another WSGI optimization 2013-01-20 11:41:43 +01:00
Roberto De Ioris 37e153d5de need to find a way to better manage write errors... 2013-01-20 10:32:02 +01:00
Roberto De Ioris e1316153be another series of porting 2013-01-19 21:42:05 +01:00
Roberto De Ioris 876f775698 solid sendfile for the new api 2013-01-19 20:59:53 +01:00
Roberto De Ioris 2bd714c610 new writer api 2013-01-19 19:06:06 +01:00
Roberto De Ioris 1b0c5bea6c another destructive commit 2013-01-19 16:53:31 +01:00
Roberto De Ioris 1f8cadb15d psgi plugin was badly broken in async mode when threads are enabled 2013-01-19 13:23:12 +01:00
unbit 83d24bee99 Merge pull request #121 from prymitive/carbon_root
[carbon] allow setting empty carbon root node
2013-01-18 14:15:00 -08:00
Roberto De Ioris 297111f2b6 non-working prototype for Coro::AnyEvent loop engine 2013-01-18 21:50:21 +01:00
Łukasz Mierzwa 0f354cbf2c allow setting empty carbon root node 2013-01-18 21:39:14 +01:00
unbit 1303efb2a4 Merge pull request #120 from prymitive/carbon_fixes
push memory metrics only if --memory-report is enabled
2013-01-18 07:45:51 -08:00
Łukasz Mierzwa 234b09b17c push memory metrics only if --memory-report is enabled & fixed total harakiri counter to include cheaper workers 2013-01-18 16:38:56 +01:00
Roberto De Ioris fe4f621d79 added --http-auto-chunked 2013-01-18 14:51:16 +01:00
Roberto De Ioris 3f83e91fb2 added uwsgi_buffer_insert() 2013-01-18 09:57:19 +01:00
Roberto De Ioris 9aebb6c564 working --http-keepalive implementation 2013-01-17 17:13:13 +01:00
Roberto De Ioris c7da6b2d45 removed a useless log 2013-01-16 19:34:14 +01:00
Roberto De Ioris bbf35be595 fixed mule management 2013-01-16 16:58:30 +01:00
Roberto De Ioris 419875e6cf fixed unix signal usage in mules and spooler 2013-01-16 16:47:46 +01:00
Roberto De Ioris aa36a2ce5f Merge branch 'master' of https://github.com/unbit/uwsgi 2013-01-16 16:25:27 +01:00
Roberto De Ioris 4c669b17ef fixed http-socket body storage leak 2013-01-16 16:25:06 +01:00
unbit abb4c9b6da Merge pull request #119 from prymitive/carbon_namespace
allow setting root node in carbon stats
2013-01-16 05:54:32 -08:00
Roberto De Ioris fe244e16d9 Merge branch 'master' of https://github.com/unbit/uwsgi 2013-01-16 14:47:32 +01:00
Roberto De Ioris 499202e84f added uwsgi::postfork and uwsgi::atexit 2013-01-16 14:47:14 +01:00
Łukasz Mierzwa e33b56890f allow setting root node in carbon stats 2013-01-16 14:37:24 +01:00
unbit 63275e9ec7 Merge pull request #118 from prymitive/carbon_busyness_fixes
carbon - detect stuck workers
2013-01-16 05:24:31 -08:00
Łukasz Mierzwa c182f30e8d carbon - detect cases were no request is completed but worker was busy and set busyness to 100% 2013-01-16 14:13:11 +01:00
unbit e365211cd0 Merge pull request #117 from prymitive/busyness_fixes
cheaper busyness -  detecting stuck workers
2013-01-16 03:28:59 -08:00
unbit 4838baf01a Merge pull request #116 from nwalker/master
another size_t fix
2013-01-16 03:26:16 -08:00
Łukasz Mierzwa 7db8636da5 cheaper busyness - detect cases were no request is completed but worker was busy 2013-01-16 12:09:40 +01:00
Alex Bubnoff 74d84be587 yet another size_t fix 2013-01-16 15:45:57 +07:00
Roberto De Ioris 8dd74ced5d Merge branch 'master' of github.com:unbit/uwsgi 2013-01-14 16:41:07 +01:00
Roberto De Ioris 9cb97dd62d php-fallback 2013-01-14 16:40:43 +01:00
Roberto De Ioris cd91830d65 fixed websockets test 2013-01-14 15:17:21 +01:00
unbit 1cefceba10 Merge pull request #113 from prymitive/core_logs
fixed init log
2013-01-13 06:32:41 -08:00
Łukasz Mierzwa afc2e7dbe2 fixed init log 2013-01-13 15:21:43 +01:00
unbit b1a9d2d497 Update tests/websockets.py 2013-01-13 13:11:37 +01:00
Roberto De Ioris ee129f02bc support for websockets over https 2013-01-13 12:46:03 +01:00
Roberto De Ioris 7ac4282047 synchrnous websockets + channels implementation 2013-01-13 10:53:11 +01:00
Roberto De Ioris 50fe00d142 gevent-friendly channel hook 2013-01-13 09:32:58 +01:00
Roberto De Ioris 6dab462296 first workign channel commit 2013-01-13 09:06:28 +01:00
Roberto De Ioris d614eabeac fixed websocket on older compilers 2013-01-13 05:24:42 +01:00
Roberto De Ioris 7da87bdf9d added --load-file-in-cache 2013-01-12 20:00:43 +01:00
Roberto De Ioris cf682773fb various int->size_t fixes 2013-01-12 19:50:49 +01:00
Roberto De Ioris 78a05ef9e8 use size_t instead of int in io functions 2013-01-12 19:22:51 +01:00
Roberto De Ioris 17d9b5f58d improved cache router added send and send-crnl route instruction 2013-01-12 19:02:40 +01:00
Roberto De Ioris 385458b291 fixed gevent leak 2013-01-12 17:17:30 +01:00
Roberta Giordano 7a80ee49be osx fixes 2013-01-11 14:44:21 +01:00
Roberto De Ioris e31d0a8693 websocket gevent hooks 2013-01-11 14:40:23 +01:00
Roberto De Ioris 9d43d6c9d4 removed some debug info 2013-01-11 11:57:42 +01:00
Roberto De Ioris b03008d1a6 spdy ping/pong 2013-01-11 11:46:32 +01:00
Roberto De Ioris 94c29a396a added new files 2013-01-11 10:22:12 +01:00
Roberto De Ioris bba8e503c1 fixed spdy/http memory cooperation 2013-01-11 08:04:46 +01:00
Roberto De Ioris 9c2e9e42f9 ported https to the new api 2013-01-11 07:40:21 +01:00
Roberto De Ioris 82d5e0ead8 Merge branch 'master' of github.com:unbit/uwsgi 2013-01-10 22:15:38 +01:00
Roberto De Ioris 3d9a20953e allows building on debian etch 4 2013-01-10 22:11:51 +01:00
Roberto De Ioris 1004ad0edc added 'signal' internal router instruction 2013-01-10 19:43:22 +01:00
Roberto De Ioris 688a227886 preliminary Websockets and SPDY support, highly optimized corerouters 2013-01-10 19:28:21 +01:00
unbit 7541195a5f Merge pull request #111 from xtfxme/defect/sec-sub
defect/sec-sub: Incorrect offset + length used for pkt encryption
2013-01-07 04:36:39 -08:00
C Anthony Risinger db24fa7bd4 defect/sec-sub: Incorrect offset + length used for pkt encryption
Off-by-four bug included the (uninitialized) uwsgi protocol header as part of
the signed packet during encryption, but *not* decryption, effectively preventing successful subscriptions; omit the header from both sides.
2013-01-07 06:24:39 -06:00
Roberto De Ioris 339c49f560 fixed remote_user in spnego plugin 2013-01-05 18:01:32 +01:00
Roberto De Ioris 8dd943542e added a route rule for remote_user 2013-01-05 17:49:27 +01:00
Roberto De Ioris 0f156fc25e fixed spnego on auth errors 2013-01-05 17:45:16 +01:00
Roberto De Ioris 8f7e65c467 added spnego/kerberos router 2013-01-05 17:21:21 +01:00
Roberto De Ioris 08b2437146 added base64 functions 2013-01-05 17:19:23 +01:00
Roberto De Ioris 912098c4c1 added --legion-skew-tolerance 2013-01-05 12:14:41 +01:00
Roberto De Ioris 3d3b21afc9 improved break routing instruction and first round of uwsgi protocol parsing optimizations 2013-01-05 11:46:11 +01:00
Roberto De Ioris 3cd7a1163d added addheader routing instruction 2013-01-05 09:35:47 +01:00
Roberto De Ioris e335c611a3 added addvar routing instruction 2013-01-05 09:06:29 +01:00
Roberto De Ioris 3409ce86e7 added --perl-version 2013-01-05 08:38:07 +01:00
Roberto De Ioris 02a9d37c32 added --python-version 2013-01-05 08:33:00 +01:00
Roberto De Ioris 121124c3cd implemented advanced login in internal routing subsystem 2013-01-04 21:15:26 +01:00
Roberto De Ioris c6440ffa2d fixed broodlord mode stats 2013-01-04 20:41:00 +01:00
Roberto De Ioris 6bab2b2318 refactored routing 2013-01-04 20:25:31 +01:00
Roberto De Ioris 7ae7b3d715 added 'static' internal router 2013-01-03 10:38:13 +01:00
Roberto De Ioris 2a2c650bec improved routing subsystem with the GOON return code 2013-01-03 10:13:38 +01:00
Roberto De Ioris ed69d78a9b export HTTP_AUTHORIZARION in mod_proxy_uwsgi 2013-01-02 17:38:03 +01:00
Roberto De Ioris 50c2fde29e fixed cheaper-initial startup message 2013-01-02 16:41:48 +01:00
unbit 96b35a3fff Merge pull request #98 from nwalker/master
Broken pyerl build
2013-01-02 00:17:47 -08:00
unbit 09a5ffeffb Merge pull request #107 from kunkku/lua-lock
Lua bindings for lock/unlock functions
2013-01-02 00:15:03 -08:00
Kaarle Ritvanen e4642e5e56 Lua bindings for lock/unlock functions 2013-01-01 15:11:46 +02:00
Roberto De Ioris 8236233489 legion subsystem does not require workers 2013-01-01 11:46:19 +01:00
Roberto De Ioris 5bfad8a1c5 added check key to the subscribe2 new generation subscriber 2013-01-01 09:56:19 +01:00
Roberto De Ioris c0dcbb7bac refactored subscriptions 2012-12-31 13:00:05 +01:00
Roberto De Ioris 808216fbd2 rewritten subscription packet generation uwsgi uwsgi_buffer struct 2012-12-31 11:40:06 +01:00
Roberto De Ioris f9a91fad63 added --static-cache-paths <seconds> 2012-12-31 11:14:53 +01:00
Roberto De Ioris 7956bebb25 added --static-safe 2012-12-31 10:51:17 +01:00
Roberto De Ioris 30633b2c9f refactored static support 2012-12-31 10:33:11 +01:00
Roberto De Ioris c713c1013c exported uwsgi_legion_i_am_the_lord() api function 2012-12-31 10:16:38 +01:00
Roberto De Ioris becdd27467 fixed locing in legion stats 2012-12-31 09:59:59 +01:00
Roberto De Ioris 2216aafcf1 take checksum in account to recognize quorum changes 2012-12-31 09:23:04 +01:00
unbit 7b3859b484 Update core/master_utils.c 2012-12-30 19:08:05 +01:00
unbit b1ab162bd2 Merge pull request #104 from prymitive/legion_stats
basic legion stats
2012-12-30 10:05:19 -08:00
unbit a0dbcee7d5 Merge pull request #103 from prymitive/legion_quorum_warning
[legion] periodic warnings when no quorum is reached
2012-12-30 10:01:59 -08:00
unbit 5312a8a0f6 Merge pull request #102 from prymitive/travis_update
fixed travis tests after latests cleanups
2012-12-30 10:00:55 -08:00
Łukasz Mierzwa 9e9b28a9cd fixed travis tests after latests cleanups 2012-12-30 15:51:39 +01:00
Łukasz Mierzwa 572298e63d periodic warnings when no quorum is reached 2012-12-30 15:48:47 +01:00
Łukasz Mierzwa 32a47c91b7 basic legion stats 2012-12-30 15:47:43 +01:00
Roberto De Ioris 556905048e legions now supports nodes with the same valor, uuid will be the diff 2012-12-30 12:46:09 +01:00
Roberto De Ioris 219d77fc17 fixed uuid compare 2012-12-30 12:41:21 +01:00
Roberto De Ioris e34371a974 debug quorum 2012-12-30 12:29:17 +01:00
Roberto De Ioris c5099b6d38 faster uwsgi_uuid_cmp() 2012-12-30 12:17:22 +01:00
Roberto De Ioris d535c22723 do not rely on uuid_compare() [2] 2012-12-30 12:14:50 +01:00
Roberto De Ioris fa68d2cae3 do not rely on uuid_compare() 2012-12-30 12:13:11 +01:00
Roberto De Ioris 5a754e66fe implemented uuid compare for legion and added a warning for system not using libuuid 2012-12-30 11:55:50 +01:00
Roberto De Ioris 83f9920705 improved mod_proxy_uwsgi 2012-12-30 11:04:43 +01:00
Roberto De Ioris f3dd60d683 fixed socket naming 2012-12-30 08:52:43 +01:00
Roberto De Ioris e25e671104 removed excessive debugging info in legion 2012-12-30 08:34:21 +01:00
Roberto De Ioris c3b101baf4 improve legion reliability 2012-12-29 20:26:59 +01:00
Roberto De Ioris b60c9b24b3 added 'signal' and 'log' Lord action 2012-12-29 20:21:03 +01:00
Roberto De Ioris 8aba421a87 fixed iv usage 2012-12-29 20:08:58 +01:00
Roberto De Ioris 15c0b5f5e9 implemented iv for legion 2012-12-29 20:03:00 +01:00
Roberto De Ioris f6271b1893 fixed quorum math 2012-12-29 19:39:10 +01:00
Roberto De Ioris 374317cffd completed voting subsystem for legions 2012-12-29 19:13:43 +01:00
Roberto De Ioris 6f7b158942 report checksum in quorum 2012-12-29 18:45:51 +01:00
Roberto De Ioris 310eb53a37 added checksum and unix time check in legion packets 2012-12-29 18:44:58 +01:00
Roberto De Ioris badeafef59 reports quorum status at every legion changes 2012-12-29 18:18:39 +01:00
Roberto De Ioris 35557de982 improvements in the legion subsystem 2012-12-29 17:52:38 +01:00
Roberto De Ioris b0a7501212 first attempt of legion quorum implementation [step 2] 2012-12-29 17:36:36 +01:00
Roberto De Ioris f45db5456e first attempt of legion quorum implementation 2012-12-29 17:29:25 +01:00
Roberto De Ioris 2b58c79611 add uuid to legion packets 2012-12-29 16:11:19 +01:00
Roberto De Ioris b7499f22f5 do not report error if /proc file system is not mounted 2012-12-29 15:37:53 +01:00
Roberto De Ioris d55a5e1b8c added --cache-sync for initial synchronization with remote caches 2012-12-28 21:24:28 +01:00
Roberto De Ioris e4ec5b000e refactored utils.c and created io.c 2012-12-28 21:10:06 +01:00
Roberto De Ioris dd983135c6 another cleanup [2] 2012-12-28 14:33:12 +01:00
Roberto De Ioris 09fe2960b5 another cleanup 2012-12-28 14:32:27 +01:00
Roberto De Ioris cf5794e22c moved uwsgirouter*.py to examples 2012-12-28 14:31:29 +01:00
Alex Bubnoff 2f2876fe6b fixed build error of pyerl plugin 2012-12-24 17:36:04 +07:00
unbit 1f1008c415 Update CONTRIBUTORS 2012-12-24 10:46:26 +01:00
unbit c02a936b61 Merge pull request #97 from guokr/master
Fix the memory leak of jvm and jwsgi plugins
2012-12-24 00:04:20 -08:00
Mingli d28cdaabb3 release chars 2012-12-24 11:33:21 +08:00
Mingli ec78213819 fix compiler error 2012-12-24 11:06:27 +08:00
Mingli 2a2303e37f remove local ref in jvm and fix indent 2012-12-24 10:19:37 +08:00
Mingli 90bc859222 Merge remote-tracking branch 'upstream/master' 2012-12-24 10:00:52 +08:00
Mingli a3be8d36fe frame scoping in jwsgi 2012-12-24 09:57:35 +08:00
Roberto De Ioris de3e70c61f skel for storage subsystem 2012-12-22 10:12:59 +01:00
Roberto De Ioris c3bba30af5 improved listen_queue management in freebsd 2012-12-21 12:07:30 +01:00
Roberto De Ioris 35566a8533 start refactoring tcp_info usage 2012-12-21 11:50:05 +01:00
Roberto De Ioris dda86dbc9c fixed a https/corerouter corner-case bug 2012-12-21 11:30:46 +01:00
Roberto De Ioris 5f971812d1 set HTTPS to on when behind stud 2012-12-21 08:59:25 +01:00
Giovanni Scala 17c8fff794 fixed --php-app-bypass 2012-12-20 20:44:25 +01:00
Giovanni Scala e4d5ca9209 added --php-app-bypass 2012-12-20 20:42:27 +01:00
Roberto De Ioris 8536bc349a added --http-stud-prefix 2012-12-19 18:37:13 +01:00
Roberto De Ioris e4b34921e1 report pos in failed uploads 2012-12-16 12:56:55 +01:00
Roberto De Ioris f966ef8e69 fixed computation of post data 2012-12-16 12:17:06 +01:00
Roberto De Ioris df8efa31dd more debug for https 2012-12-16 10:57:56 +01:00
Roberto De Ioris ee6aff6665 added additional uwgsi-gevent error report 2012-12-15 20:34:25 +01:00
Roberto De Ioris 5f2abf9949 fixed uwsgi_str_num for 32bit 2012-12-15 14:30:22 +01:00
unbit ee9b4a70d4 Merge pull request #86 from scottkmaxwell/master
1.4.3 wouldn't build on my Mac due to a too-strict cast in the Yaml plug-in.
2012-12-13 22:48:40 -08:00
Roberto De Ioris d5632f7715 fixed net offloading and http internal router 2012-12-13 15:25:45 +01:00
Roberto De Ioris efd10599a6 oops alarm_xmpp should not be build by default 2012-12-13 11:06:23 +01:00
Roberto De Ioris f0a846927e allows embedding .cc and .m files 2012-12-13 11:03:17 +01:00
Scott Maxwell 5e876e4adc Loosen up cast so we can build on Mac
Cast to (const unsigned char*) caused error building on OS X Mountain Lion
2012-12-12 09:51:30 -08:00
Roberto De Ioris d968e9f39e dup2() returns < 0 on error 2012-12-12 15:02:37 +01:00
unbit 54fa0ab19f Merge pull request #84 from prymitive/travis_buildconf
travis buildconf
2012-12-11 21:52:05 -08:00
Łukasz Mierzwa d63a570230 travis buildconf 2012-12-11 22:32:23 +01:00
Roberto De Ioris 98e9822150 removed garbage from old versions 2012-12-10 17:37:13 +01:00
unbit 6a9809b301 Merge pull request #82 from prymitive/cheaper_initial
check if --cheaper-initial is valid
2012-12-10 08:07:54 -08:00
Łukasz Mierzwa 47590a2b0d check if --cheaper-initial is valid 2012-12-10 17:01:15 +01:00
Roberto De Ioris 1447ae01bd improved uwsgi_run_command 2012-12-10 15:10:52 +01:00
Roberto De Ioris d24ad0e61c close fds for external processes 2012-12-10 14:45:01 +01:00
Roberto De Ioris 0a0b27ad4c added offload-thread alias 2012-12-07 13:39:39 +01:00
Roberto De Ioris 504151b695 improved stdin management in cron 2012-12-07 12:40:29 +01:00
Roberto De Ioris 813074b010 fixed emperor 2012-12-07 12:06:49 +01:00
Roberto De Ioris 01cbcbad47 django dir will be in a dedicated repository 2012-12-07 11:39:15 +01:00
Roberto De Ioris 20b0dc0d1e removed uwsgicc, it should be on a separate repository 2012-12-07 11:33:50 +01:00
root 6e6dd65cef updated Changelog for 1.5 2012-12-07 11:30:17 +01:00
root e77f1d5069 %z is not portable 2012-12-07 11:25:14 +01:00
root 41af8e54bb fixed FIXME for #79 2012-12-07 11:18:33 +01:00
unbit d598a10013 Merge pull request #79 from prymitive/log_format_fixes
few log format fixes
2012-12-07 02:16:18 -08:00
root 9af9cd09f9 --not-alarm-log is the only condition that need to break 2012-12-07 11:13:44 +01:00
root b358c46413 added support for negative regexp in alarm-log 2012-12-07 10:58:58 +01:00
root 45ffa98b5e added preliminary support for TCP_FASTOPEN 2012-12-07 10:33:39 +01:00
root f458877e53 improved emperor reloading 2012-12-07 09:04:32 +01:00
root 544e598dcb improved emperor custom config management 2012-12-07 07:58:48 +01:00
root 360a94691d added --get for shell scripting 2012-12-06 14:51:34 +01:00
unbit a297b9b981 Merge pull request #78 from prymitive/cheaper_busyness_logging
fixed log format in cheaper_busyness
2012-12-06 05:28:05 -08:00
Łukasz Mierzwa 7bb424622c few log format fixes 2012-12-06 13:55:43 +01:00
Łukasz Mierzwa 0d382a846a fixed log format in cheaper_busyness 2012-12-06 12:44:37 +01:00
root e82430369e added --legion-death 2012-12-06 11:23:45 +01:00
unbit 647e1e0826 Merge pull request #77 from prymitive/x_forwarded_for
use client address if X-Forwarded-For is missing
2012-12-06 02:00:53 -08:00
Łukasz Mierzwa b5802b4793 fallback to REMOTE_ADDR if HTTP_X_FORWARDED_FOR is missing but --log-x-forwarded-for was used 2012-12-06 10:51:59 +01:00
root af5dbda00d fixed unlord 2012-12-06 10:35:11 +01:00
root 4b889c90bf completed legion subsystem, added cmd legion_action 2012-12-06 10:24:32 +01:00
unbit 1313841dd3 Merge pull request #76 from prymitive/carbon_newline
missing new line in carbon plugin logs
2012-12-05 23:56:34 -08:00
Łukasz Mierzwa b09c343627 missing new line in carbon plugin logs 2012-12-05 22:33:08 +01:00
root ca97c0653f added newline to legion log 2012-12-05 21:03:47 +01:00
Roberto De Ioris 76edb7374e support for zeromq3 in emperor_zeromq 2012-12-04 12:55:55 +01:00
Roberto De Ioris c8f53b9296 report name and pid for upcoming Lord 2012-12-04 12:44:02 +01:00
Roberto De Ioris 55a190312a a note about iv for encryption 2012-12-04 12:37:32 +01:00
Roberto De Ioris 7ebbac0dd8 completed legion management and logic 2012-12-04 12:35:17 +01:00
Roberto De Ioris 1662f58a09 added first lord check 2012-12-03 19:44:39 +01:00
Roberto De Ioris ac5ca4a002 added legion decrypter 2012-12-03 19:42:13 +01:00
Roberto De Ioris ebadaa73a8 bind to legion address 2012-12-03 18:09:28 +01:00
Roberto De Ioris 55fdc9d847 initialize encrypt/decrypt contexts for legions 2012-12-03 17:39:03 +01:00
Roberto De Ioris a409a82736 Merge branch 'master' of github.com:unbit/uwsgi 2012-12-03 15:58:18 +01:00
Roberto De Ioris 58e3b7166c added core/ssl.c for ssl utilities (moved from core/utils.c) and prepare for legion support 2012-12-03 15:57:54 +01:00
unbit cac413f725 Update core/legion.c 2012-12-03 09:43:45 +01:00
Roberto De Ioris 73e3938d9a added legions subsystem introduction 2012-12-03 09:41:54 +01:00
Roberto De Ioris 985114b7bd fixed #66 2012-12-01 15:44:52 +01:00
Roberto De Ioris fb4a594add SNI support 2012-12-01 15:34:28 +01:00
Roberto De Ioris 5d8f91c1ed added zeromq imperial monitor 2012-11-30 18:33:46 +01:00
Roberto De Ioris 759a9d4439 added emperor:// to the supported schemes, improved vassals config handling 2012-11-30 18:23:27 +01:00
unbit 25b29df65e core: make smart-attach-daemon smart enough
Avoid call storming of pidfile check that leads to multiple daemons
running instead of one. Fix #65.
2012-11-28 20:57:06 +01:00
unbit 9f396466bd Merge pull request #64 from prymitive/touch_logrotate
fixed --touch-logrotate after my patch
2012-11-27 12:07:24 -08:00
Łukasz Mierzwa c79b36a59d fixed --touch-logrotate after my patch 2012-11-27 20:47:55 +01:00
unbit de33a4a5a3 Merge pull request #61 from prymitive/touch_reload
enhanced file touch checker
2012-11-27 04:04:19 -08:00
Roberto De Ioris 88e108cacc fixed #20 2012-11-27 13:02:59 +01:00
unbit 163d71c5b8 Merge pull request #62 from xrmx/cpucount
uwsgiconfig: permit to override CPUCOUNT with environment variable
2012-11-27 03:37:59 -08:00
Riccardo Magliocchetti 936d4b19a5 uwsgiconfig: permit to override CPUCOUNT with environment variable
CPUCOUNT=X make

will force X cores instead of the autodetected ones
2012-11-27 12:23:06 +01:00
Łukasz Mierzwa 93cbd60f11 enhanced file touch checker 2012-11-27 11:54:13 +01:00
Roberto De Ioris 850cbea236 added --http-session-context 2012-11-25 21:21:08 +01:00
Roberto De Ioris 3ceda8993a removed some debug 2012-11-25 19:04:37 +01:00
Roberto De Ioris ccad290b78 added cache full counter 2012-11-25 18:51:01 +01:00
Roberto De Ioris 66d28aa958 added cache stats 2012-11-25 18:43:37 +01:00
Roberto De Ioris 3717b8cd13 implemented udp cache del 2012-11-25 17:48:18 +01:00
Roberto De Ioris 6e5fc85e54 uwsgi_cache_del now takes flags 2012-11-25 17:29:41 +01:00
Roberto De Ioris a3bbfde884 refactored cache threads 2012-11-25 17:22:44 +01:00
Roberto De Ioris fd86c6cafa implemented expires in cache udp server 2012-11-25 16:42:40 +01:00
Roberto De Ioris cb87f8f6d6 implemented udp cache update 2012-11-25 16:02:05 +01:00
Roberto De Ioris 4ccd20eb23 pre-build cache udp nodes addresses 2012-11-25 14:09:25 +01:00
Roberto De Ioris 9ced8f9bdd skeleton for --cache-udp-server and --cache-udp-node 2012-11-25 13:07:34 +01:00
Roberto De Ioris 4eb174e9cb first implementation of ssl sessions store in the shared cache 2012-11-25 10:46:58 +01:00
Roberto De Ioris 598250d469 added --php-var 2012-11-24 11:22:01 +01:00
Roberto De Ioris 6cc3faf14d improved QUERY_STRING management in router_rewrite 2012-11-24 11:14:44 +01:00
Roberto De Ioris 8864f3c53c fixed corner-case ssl body reading 2012-11-24 09:52:24 +01:00
unbit 49dd3366fc Merge pull request #60 from prymitive/travisci
removed python2.5 from build
2012-11-23 05:26:04 -08:00
Łukasz Mierzwa 5d253ab00f removed python2.5 2012-11-23 14:20:03 +01:00
Roberto De Ioris 25db778f32 Revert "uClibc compatibility for core"
This reverts commit c2d2f13bfb.
2012-11-23 10:10:26 +01:00
unbit 35fbd85fad Merge pull request #59 from kunkku/uclibc
uClibc compatibility for core
2012-11-23 00:26:00 -08:00
Kaarle Ritvanen c2d2f13bfb uClibc compatibility for core 2012-11-23 08:45:24 +02:00
Roberto De Ioris 7add254781 fixed typo in the php plugin 2012-11-22 16:38:22 +01:00
Giovanni Scala 970d899986 honour QSA style in php-app-qs 2012-11-22 07:39:01 +01:00
Giovanni Scala d719ed6a3b added php-app-qs 2012-11-22 06:26:36 +01:00
Giovanni Scala 7fcc8ba6ac fixed sendfile offload with bigger files 2012-11-22 05:28:56 +01:00
Roberto De Ioris 70e1bda986 refactored rewrite plugin 2012-11-21 18:01:39 +01:00
Roberto De Ioris 32789e62a5 fixed PATH_TRANSLATED in cgi and improved var appending 2012-11-21 17:54:47 +01:00
Roberto De Ioris 6297ed0455 do not crash on non-existent config files 2012-11-21 07:48:06 +01:00
unbit 1cbabf6296 Merge pull request #56 from xtfxme/feature/extract
feature/extract: dump the specified address to stdout and exit
2012-11-20 07:56:33 -08:00
C Anthony Risinger e7f694cdc5 feature/extract: dump the specified address to stdout and exit
similar to `--connect-and-read` except for file-like addresses; allows such
things as:

```
$ uwsgi --extract data://0
$ uwsgi --extract sym://embedded_json
$ uwsgi --extract http://me.local/config.xml
$ uwsgi --extract section://rootfs.tar.gz
$ uwsgi --ini exec://"uwsgi --extract section://rootfs.tar.gz | \
        tar xz && cat rootfs/config.ini"
```

...the latter of which embeds/extracts a complete rootfs for immediate use!
combined with embedded configs + declare-options, one can construct a self-
extracting -- single-file -- app that managed it's own plugins, configs,
databases, shared libs, [...]
2012-11-20 09:48:29 -06:00
Unbit 5f93d93cc1 added x magic var 2012-11-19 09:35:22 +01:00
Unbit 15fa7a9c09 improved section detection 2012-11-19 09:16:29 +01:00
Roberto De Ioris 2e9e5af686 added perl signal_wait and mule handler 2012-11-17 12:12:43 +00:00
Roberto De Ioris 54c1055f15 Merge branch 'master' of github.com:unbit/uwsgi 2012-11-16 19:58:05 +00:00
Roberto De Ioris 114d71af8d implemented register_signal in the psgi plugin 2012-11-16 19:57:54 +00:00
unbit 757c3e7d95 Merge pull request #52 from prymitive/travisci
More advanced travis config
2012-11-15 05:19:04 -08:00
unbit 0233f3e712 Merge pull request #54 from kunkku/lua-async
Support asynchronous requests in Lua plugin
2012-11-15 05:18:05 -08:00
Kaarle Ritvanen e23a7bfd80 support asynchronous requests in Lua plugin 2012-11-15 14:18:45 +02:00
Roberto De Ioris 6c67d205b8 fixed magic_table management 2012-11-15 10:01:24 +01:00
Łukasz Mierzwa aaaae5a602 * travis config with plugins for multiple python and ruby versions
* basic script with tests for each python and rack plugin
2012-11-13 21:27:15 +01:00
Roberto De Ioris 5ddd773680 fixed #51 2012-11-13 04:36:45 +01:00
Roberto De Ioris 34bb5de3aa fixed static_maps 2012-11-12 14:42:44 +01:00
Roberto De Ioris e23094e820 clear uwsgi_thread structure on setup 2012-11-12 14:11:15 +01:00
Roberto De Ioris 8d53e4aa54 fixed offload threading when the numbr of ocres is higher than 1 2012-11-12 13:49:10 +01:00
Roberto De Ioris ca1666789d Merge branch 'master' of github.com:unbit/uwsgi 2012-11-12 13:13:26 +01:00
Roberto De Ioris 211ed5c71c corerouter NOT courerouter 2012-11-12 13:09:06 +01:00
unbit 9f6a88d9d7 Merge pull request #48 from prymitive/travis
minimal travis.yml file
2012-11-12 03:35:38 -08:00
Roberto De Ioris 3d483f22ca 'wsgi' option is an alias for 'module' not 'wsgi-file' 2012-11-12 11:57:02 +01:00
Roberto De Ioris a6bbb0cfa4 starting 1.5 development cycle 2012-11-12 11:37:51 +01:00
Łukasz Mierzwa e6c9e53f14 minimal travis.yml file 2012-11-12 10:52:42 +01:00
286 changed files with 30085 additions and 17638 deletions
+4
View File
@@ -1,5 +1,9 @@
*.o
*.py[co]
*.class
*.jar
/uwsgi
/uwsgibuild.*
/t/ring/target
+44
View File
@@ -0,0 +1,44 @@
language: c
compiler:
- gcc
- clang
script:
- echo -e "\n\n>>> Building uWSGI binary"
- /usr/bin/python uwsgiconfig.py --build travis
- echo -e "\n\n>>> Building python26 plugin"
- /usr/bin/python2.6 -V
- /usr/bin/python2.6 uwsgiconfig.py --plugin plugins/python base python26
- echo -e "\n\n>>> Building python27 plugin"
- /usr/bin/python2.7 -V
- /usr/bin/python2.7 uwsgiconfig.py --plugin plugins/python base python27
- echo -e "\n\n>>> Building python31 plugin"
- /usr/bin/python3.1 -V
- /usr/bin/python3.1 uwsgiconfig.py --plugin plugins/python base python31
- echo -e "\n\n>>> Building python32 plugin"
- /usr/bin/python3.2 -V
- /usr/bin/python3.2 uwsgiconfig.py --plugin plugins/python base python32
- echo -e "\n\n>>> Building python33 plugin"
- /usr/bin/python3.3 -V
- /usr/bin/python3.3 uwsgiconfig.py --plugin plugins/python base python33
- echo -e "\n\n>>> Building rack 1.8.7 plugin"
- /usr/bin/ruby1.8 -v
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.8 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack187
- echo -e "\n\n>>> Building rack 1.9.1 plugin"
- /usr/bin/ruby1.9.1 -v
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.9.1 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack191
- echo -e "\n\n>>> Building cgi plugin"
- /usr/bin/python uwsgiconfig.py --plugin plugins/cgi base
- echo -e "\n\n>>> Building dummy plugin"
- /usr/bin/python uwsgiconfig.py --plugin plugins/dummy base
- echo -e "\n\n>>> Building done, starting tests"
- ./tests/travis.sh
before_install:
- sudo add-apt-repository -y ppa:fkrull/deadsnakes
- sudo apt-get update -qq
- sudo apt-get install -qqyf python2.6-dev python2.7-dev python3.1-dev python3.2-dev python3.3-dev rubygems1.8 ruby1.8-dev ruby1.9.1-dev
- sudo apt-get install -qqyf libxml2-dev libpcre3-dev libcap2-dev
- sudo apt-get install -qqyf curl
+1
View File
@@ -21,3 +21,4 @@ Roy Marples
Aarni Koskela
C Anthony Risinger
Stephen Pierce
Mingli Yuan
-670
View File
@@ -1,670 +0,0 @@
*** current ***
* 1.4
- gevent improvements
- improved http/https router and fastrouter
- Go official support
- a new set of infos are exported to the stats system
- improved systemd support
- log filtering and routing
- improved tracebacker
- offload transfer for static files, and network transfers
- matheval support
- plugins can be written in Obj-C
- smart attach daemon
- added support for PEP 405 virtualenvs
- rawrouter with xclient support
- internal routing plugin for cache
*** semptember 2012 ***
* 1.3
- python tracebacker
- user-governed harakiri
- simplified external plugin development
- Linux namespace mountpoint improvements
- secured subscription system
- merged routers codebase (fastrouter, http, rawrouter)
- https support in the http router
- config report at the end of uWSGI build process
- improved subscription system (multicast and unix socket)
- custom options
- graceful reloads on shared sockets
- configurable log-master buffer size
- extreme-optimizations for the stats subsystem
- redislog and mongodblog plugins
- added python logger
- mongodb and postgres imperial monitors
- implemented psgix.logger and psgix.cleanup
- full rack spec compliance
- preliminary ipv6 support
- gevent graceful reloads
- support for multiple loggers and logformat
- lazy-apps to load apps after fork() but without changing reloading subsystem
- emperor heartbeat subsystem
- cheaper busyness plugin
- pluggable clock sources
- added router_rewrite and router_http plugins
- external spoolers
- support for section:// and fd:// loaders
- alarm subsystem (with curl and xmpp plugins)
*** april 2012 ***
* 1.2 [20120430]
- PyPy support
- Improved gevent support with threads
- Python auto-reload subsystem
- added --spooler-max-tasks
- pthread robust mutexes support in Linux and Solaris
- posix semaphores support in FreeBSD9
- thread-safe ctime() reporting
- interval support in cron subsystem
- improved syslog support
- better management of disconnected clients
- static files serving improvements
- another set of multithreading optimizations
- minor fixes in the Rack plugin
- Upstart socket-activation support
*** march 2012 ***
* 1.1 [20120317]
- new options parser subsystem
- improved php support
- multiple spooler with multiprocessing
- segmentation fault and floating point exceptions manager
- never-swap option
- zergpool plugin
- perl/psgi multiple interpreters support
- deadlock detector
- pluggable cheaper algos
- new internal routing susbsystem
- preliminary support for config logic
- log rotation infrastructure
- support for paste loggers
- threading improvements
- plugins can now mapped to specific modifiers
- <app> tag is deprecated (use mount option)
- report startup time for apps
- reintroduced expat support
- reintroduced remote spooler plugin
- various fastrouter optimizations
- added ruby rvm support
*** december 2011 ***
* 1.0 [20111230]
- adaptive process spawning (--cheaper option)
- new control options --stop, --reload, --suspend, --resume, --pause
- stats framework
- new subscription system
- support for mime types in static file serving
- posix capablities support
- uWSGI mules and farms
- support for multiple --touch-reload options
- new logging subsystem
- new custom locking subsystem
- process name handling
- better (and faster) HTTP parser
- perl and python threading improvements
- new plugins: rrdtool, carbon, cgi, php
- various improvements in the Rack/ruby plugin
- Linux KSM support
- refactored ping and nagios plugins
- support for signals in lazy mode
- optimized static-file serving
- support for linux unshare()
*** august 2011 ***
* 0.9.9 [20110829]
- various spooler improvements
- upload progress optimizations and fixes
- new emperor mode: Tyrant
- allows multiple --ini options
- better binary path detection
- gevent loop engine support
- resolve domain names in socket logging
- snmp fixes and reintroduction of the snmp-api
- fixed grunt mode
- you can specify build profile via env var UWSGI_PROFILE
- reintroduction of string-based multiapp
- new option --emperor-throttle
- improved queue and sharedarea subsystems
- uWSGI can now be built as a shared library
- new api attribute: uwsgi.magic_table
- improved apache2 module
- new option --pyshell
- allow threads in gateways
- fastrouter improvements
- the application list is now shared and exported to the api
- allows setting the thread stack size
- UWSGI_APPID for better multiapp hosting
- better reloading in lazy mode
- native pump support
- various rack fixes
- support for attaching binary data in the executable
- new option --set
- extreme-optimized http protocol parser
- WSGI handler optimizations
*** july 2011 ***
* 0.9.8.3 [20110723]
- implemented uwsgi.SymZipImporter to load embedded zip files
- OSX Lion is officially supported
- fixed xinetd support (example file added in contrib)
- suppot for systemd socket activation
- added --freebind option (Linux only)
* 0.9.8.2 [20110719]
- fixed an ini and yaml parsing bug spotted by Raffaele Colace
- spooler has been extremely improved
- new option --chown-socket
- added uwsgidecorators for elegant uwsgi api access from python
- the rack plugin is now stable
- support for embedding config and generic files in the server binary
- high-performance cache-server
- accept() is now locked on all threads in the same workers
- preliminary implementation of hooks in emperor
- support for C++ in server core
- tcp port auto-bind
- implemented workers, workerN and spooler signal target
- prefork/multithread uwsgi.signal_wait() implementation
- export uwsgi.node in WSGI vars
- new option --import (python plugin)
- support for unlimited number of Linux cgroups
- broodlord mode
*** june 2011 ***
* 0.9.8.1 [20110625]
- the build system has been improved
- various threading fixes
- fix python GIL status after reload
- new option --propagate-touch
- fixed uwsgi.sendfile
- fixed readline() support in wsgi.input
- fixed dynamic touch reload
- new option --logto2
- export %c in config files
- fixed libyaml support
- support passing modifiers in subscription system
- reset random seed in spooler
- subscribe from a list in a text file
- allow binding on port 0 (auto-assignment)
- reset random seed on grunt
- fix vhost mode for empty hostname
- fixed python3+virtualenv support
- tasks are now allowed to chdir() in spooler
- better zeromq+clustering support
- clustering has been refactored
- fixed rpc
- report correct worker id in cheap mode
- fixed a fd-leak in attach-daemon
- use setsid() in attach-daemon
- zerg mode
- added psgix.harakiri
- allows magic vars in sqlite3 config db
- added UWSGI_FASTROUTER_KEY var
- slowdown async-queue-is-full messages
- new option --cron
- --vassals-start-hook and --vassals-stop-hook
- the proxy plugin has been removed
* 0.9.8 [20110605]
- support for --callable in virtualhosting mode
- a NetBSD fix
- abstract unix socket can be prefixed with \0 (nginx-style)
- add /lib to the linker in sun-like systems
- a mercy mode of 5 seconds is enabled by default on SIGINT/SIGQUIT
* 0.9.8-rc4 [20110602]
- fixed REMOTE_ADDR when --protocol=http
- official support for OpenIndiana
- added a welcome.py test script
- new api attribute uwsgi.version_info
- improved the admin plugin
- two new management flag for backlog queue monitoring
- fixed uwsgi_log for bigger loglines
- new option --early-emperor to allows out-of-jail emperors
- emperor can now spawn other emperors (sub-emperors)
- fixed idle mode in single-process
- fixed solaris iovec
*** may 2011 ***
* 0.9.8-rc3 [20110530]
- snapshotting support
- fixed python 3.x spooler
- improvements for grunt processes
- better abstract unix socket
- --log-socket allows logging to generic DGRAM sockets
- a bunch of solaris fixes
- new option --no-fd-passing for fastrouter
- --fastrouter-subscription-slot to set the number of slot in subscription server
- unlimited shared sockets
- fixed netlink compilation
- auto-reconnect on emperor+amqp server disconnection
- various emperor fixes
- unlimited fastrouter sockets
- better cgroup support
- --add-header option allow adding of custom HTTP response headers
- cheap and idle operational modes
* 0.9.8-rc2 [20110521]
- new option --die-on-term
- fixed touch reload
- a couple of optimizations for wsgi.input
- systemd integration
* 0.9.8-rc1 [20110514]
- massive code cleanup and refactoring
- added vassals loyalty concept
- fixed virtualhosting with dynamic virtualenv
- fixed reloading on grand-central-dispatch-enabled OSX
- improved PSGI support with uGreen and async support
- improved Rack support with complete fiber+async in ruby 1.9
- support for JSON config files
- native multi-protocol support (added fastcgi and http)
- Mongrel2 support
- support for templates in vassals
- various threading fixes
- gcc-4.6 support
- support for logging via zeromq
- support for configuration passed via pipe/stdin
- pythonpath entries are now unlimited
- socket entries are unlimited
- pythonpath can be a glob
- lazy mode added
- new language-independent profiling subsystem
- support for configuration stored in a sqlite3 db
- allow workers to survive to syslogd death (when --log-syslog is used)
- fix traceback in Python 3.x
- support for uwsgi signals in threads
- plugin autoloading
- graceful reloading for threads
- new wsgi.input object
- support for alternative allocators (tcmalloc and jemalloc)
*** april 2011 ***
* 0.9.7.2 [20110406]
- new option --touch-reload <file> to reload the stack on <file> modification
--static-map <mountpoint=documentroot> allows to serve static files
- fixed --post-limit management
- disallow empty socket names
- implemented exception_info WSGI support
- new options --reload-on-as <n> and --reload-on-rss <n> allows
to recycle workers when their memory usage is higher than <n> MB
- fixed syslog support (use --log-syslog[=facility] to enable it)
- improved plugin loading system
- added support for RabbitMQ as event dispatcher for the Emperor
- fixed FreeBSD memory report
- PSGI plugin can be compiled without ithreads
- various Emperor fixes
- fixed a regression with setgroups()
- support for shared sockets (used in jails within network namespaces)
*** march 2011 ***
* 0.9.7.1 [20110326]
- fixed python stackless support
- added persistence for queue
- forbid daemonizing in vassal mode
- modifier1 30 is available again
- allow python modules to be mapped/aliased via http
- added --pidfile2 and --logfile-chown
- added UWSGI_CACHE_GET dynamic variable
- 304/If-Modified-Since support for --check-static
- option --check-cache for integrated caching
- option --map-socket to assign specific workers to socket
- fixed unix fd passing on older OSX versions
- fixed post-buffering without pep3333-input
- fixed python threading without uwsgi cores
- support for Linux network namespace
- build with sys.abiflags if necessary
* 0.9.7 [20110317]
- fixed psgi compilation on GNU systems
- improved --pep3333-input
- better error reporting on failed open/fopen
- fixed uGreen
- added greenlet support
- various solaris fixes
- new help system
- updated async support
- fixed uwsgi.cache_get in python
* 0.9.7-rc3 [20110312]
- added support for persistent cache (--cache-store <filename>)
- less verbose file monitoring
- fixed a race condition in emperor startup
- fixed erlang empty list encoding
- improved snmp support
- fixed cache modifier 111 for 3 and 4
- preliminary cpu-affinity support (Linux only)
- fixed ldap support
- auto-configure ldap compilation
- added --allowed-modifiers (allow only a subset of modifiers)
- fixed a bug with getopt_long
* 0.9.7-rc2 [20110309]
- added cron-like interface to signal framework
- improved Linux namespaces support
- fixed multithreading + --max-requests
- added support for reference in configuration files
* 0.9.7-rc1 [20110307]
- export %v in emperor mode
- fixed signal race condition in server reload
- fixed http router post handling bug
- added uwsgi.erlang_register_process in pyerl plugin
- fixed unix socket inherit
- fixed linux namespace support in recent kernel/gcc
- ported threading to python 3.2
- add build date to uWSGI startup info
- do not allow clustering without defining a socket
- kill all the gateways/daemons on startup errors
- fixed vacuum after chdir()
- fixed gateways reload
- re-added support for OpenBSD and NetBSD
- fixed post-buffering in python
- use erlang binary for python string
- fixed memory leak in pyerl plugin
- removed broken log rotation (post-poned)
- fixed no_argument options in ini and yaml parsing
* 0.9.7-beta1 [20110301]
- fully modular re-design
- advanced build system with presets
- threading support
- emperor mode for massive auto-hosting
- caching subsystem
- message queue (even stacked) support
- improved server reloading system
- support for Linux Cgroups and Namespaces
- integrated upload progress
- Clustering infrastructure via multicast, broadcast or subscriptions
- support for attaching/monitoring external apps to the master process
- improved virtualhosting mode
- extremely improved Python support with better usage of multiple interpreters
- improved multiple apps support
- Production ready, evented HTTP router/proxy/load-balancer
- Production ready, evented uwsgi router/proxy/load-balancer
- new Erlang stack
- Internal signal subsystem
- support for RubyOnRails and Rack apps
- A huge series of fixes and optimizations
*** february 2011 ***
* 0.9.6.8 [20110207]
- fixed a bug when using --limit-as
- fixed a erlang buffer initialization
- added --ignore-sigpipe
- added --master-as-root
*** january 2011 ***
* 0.9.6.7 [20110130]
- a huge amount of async optimizations and fixes
- --logdate takes an optional strftime-like value
- follow $PATH on reloading
- uwsgi.core is exported in WSGI env
- uwsgi.log() respect for --logdate
- initial banner respect for --logdate
- fixed --post-buffering
- default listen backlog queue is now 100
- Python 3 support is no more marked as experimental
- Python 3.2 support
- new option --chroot-reload will force a reload of the uWSGI stack after a chroot
- fixed a typo in INI parsing
*** december 2010 ***
* 0.9.6.6 [20101230]
- support for YAML configuration files
- backported python module aliasing from 0.9.7-dev
- better apache2 module (support for SetEnv directive, fixed REQUEST_URI and improved connection handling)
- uwsgi.post_fork_hook implementation (to execute function after fork()) (thanks George Kollias)
- option --gid calls setgroups() after setgid() (thanks Jorge Cardona)
- fixed uGreen compilation (and uGreen is now built by default)
- fixed timeout and thundering herd problem in async modes (many thanks to Test157 for giving us a good async-test-app)
- disable TCP_INFO in older Linux kernels (thanks Bo Shi)
- enable TCP_INFO in FreeBSD (limited usage due to FreeBSD kernel support)
- fixed static virtualhosting mode using xml files (thanks Guido Notari of Link I.T. spa)
- new option --close-on-exec (thanks Jean-Baptiste Quenot)
- use HTTP_HOST var (and fallback to SERVER_NAME) in virtual hosting mode
- fixed a buffer overflow in automatic socket_name allocation (spotted by Riccardo Magliocchetti)
- Official support for Nexenta
*** september 2010 ***
* 0.9.6.5 [20100929]
- PEP 3333 support
- fix --pythonpath with --wsgi-file
- x-wsgiorg.uwsgi.version renamed to uwsgi.version
* 0.9.6.4 [20100925]
- fix a stupid bug in conditional logging backport
* 0.9.6.3 [20100925]
- fix a buffer overflow in .ini parsing (it throws a glibc error on malloc)
- backport of conditional logging from 0.9.7-dev
- backport of backlog queue monitor from 0.9.7-dev (only Linux)
* 0.9.6.2 [20100915]
- fix a regression in virtual hosting mode
- fix pythonpath usage in --ini and --ini-paste
- new uwsgi packet var: UWSGI_CHDIR
* 0.9.6.1 [20100912]
- print the request uri during SIGPIPE or HARAKIRI
- added SIGUSR2 support (it will print the current running request, if available)
- protocol parsing optimization
- fixed --logto support
- new --eval option allows inline definition of WSGI script
- support for defining WSGI script in xml using CDATA
- allow --pp as --pythonpath shortcut
- various spooler optimizations and fixes
- added -O2 optimization by default
- added uwsgi.is_a_reload commodity function
- .ini file support fix
- SNMP agent fix
- support for subprocesses generated by master
- fix a regression in SCRIPT_NAME handling
- Haiku official support
- gcc 2.95 support
- dynamic app management optimizations
- export x-wsgiorg.uwsgi.version in WSGI env
*** august 2010 ***
* 0.9.6 [20100829]
- better handling of SCRIPT_NAME
- vacuum option for deleting unix sockets and pidfiles after usage
- advanced XML configuration
- new configuration systems: INI files and LDAP
- embedded HTTP server for development/testing
- better signal handling
- PSGI plugin improved
- usability fixes and new commodities options for root startup
- grunt processes (detached workers)
- preliminary integrated virtualhosting mode
- new option catch-exceptions can redirect python exceptions to your browser
- logging improvements (--logto and --logdate options)
- Full PEP 333 compliant usage of wsgi.file_wrapper
- re-initialize random seed after every fork() [security fix]
- fix Spooler's usage of stdin
- export WSGI environment in uwsgi.env (for doing evil things)
- logsize tracking (uwsgi.logsize) for future embedded log rotation
*** july 2010 ***
* 0.9.5.4 [20100706]
*** june 2010 ***
* 0.9.5.3 [20100628]
- fixed linux x86_64 compilation (sorry)
* 0.9.5.2 [20100626] *
- fixed a request parsing bug
- applied debian fixes
- fixed multiple interpreter sys.argv
- improved --chmod-socket
- fixed uid 0 SIGHUP
- updated nginx and apache modules
- updated PSGI, lua and example plugin
- fixed --pyargv with python 3.x
- improved plugin build system
*** may 2010 ***
* 0.9.5.1 [20100519] *
- fixed paste support
- added a new modifier (22)
- full support for configuration via environment variables
- nginx_string option in nginx module
- fix for harakiri without master
- backported unladen swallow support for 0.9.6-dev
- fixed address space limit detection via getrlimit()
- http body buffering implementation
- added --prio option (to set priority)
- added --post-limit to limit the size of uploads
- added --logto option to allow udp logging without daemonizing
- applied Gentoo's packagers fixes for build system
* 0.9.5 [20100501] *
- hook based request/modifier management
- plugin support via dlopen
- on-the-fly management flag
- integrated proxy
- logging via udp
- improved spooler for cron-like apps
- async support
- green thread platform (uGreen) on top of the async mode
- transparent Erlang integration
- embedded snmp agent
- nagios mode
- improved python 3.x support
- improved xml configuration
- new build system
- address space usage limiting
- lot of portability fixes
- lot of optimizations and code refactoring
*** april 2010 ***
* Fourth Maintenance release [20100427] *
- backported non-yielding app optimization from 0.9.5
- backported udp logging from 0.9.5
- backported uwsgi_error() from 0.9.5 (no more dumb perror())
- fix a rare (but possible) segmentation fault
- added --version
- updated apache2 module
*** march 2010 ***
* Third Maintenance release [20100310] *
- fix sendfile on 64bit
- include setup.py
*** february 2010 ***
* Maintenance release *
- better support for NetBSD
- threading fix for FreeBSD
- sendfile portability fixes
- new makefiles
- example app for testing static file serving
- fixes for ROCK_SOLID mode
*** january 2010 ***
- Integrated Spooler
- better error management
- long options
- clustering functions
- experimental lighttpd module
- official support for OpenBSD and OpenSolaris
- FastFuncs
- new functions for embedded module
- reliable harakiri
- better Makefiles
- python threads support in master process
- proper timeout handling in apache2 module
- endianess fixes all over the place
- paste support
- Django app for managing and monitoring the uWSGI server
- options for changin uid/gid and chrooting when run by root
- lot of bugfixes and optimizations
*** 20091129 Version 0.9.3 ***
- Nginx 0.7.x module
- configuration via python module
- support (non-standard) for Python 3.x
- Twisted client resource adapter
- graceful restart of worker processes and hot-plug substitution/upgrade of the uWSGI server
- shared memory area to share data between workers/processes
- Tomcat handler
- support for virtualenv
- tons of bugfixes and optimizations
*** 20090829 Version 0.9.2 ***
- TCP support
- configurable internal timeout (socket/poll)
- Cherokee handler
- code refactoring
- Makefiles
- customizable harakiri handler (put an harakiri(environ, start_response) function in your wsgi script)
- limit requests per worker
- a lot of bugfix and optimizations
+1 -1
View File
@@ -1,3 +1,3 @@
surprise i am empty !
Look in the online documentation on http://projects.unbit.it/uwsgi/
Look in the online documentation on https://uwsgi-docs.readthedocs.org/en/latest/
+69 -45
View File
@@ -1,3 +1,38 @@
/*
*** mod_proxy_uwsgi ***
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
To build:
apxs2 -i -c mod_proxy_uwsgi.c
To use:
LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so
ProxyPass / uwsgi://127.0.0.1:3031/
Docs:
http://uwsgi-docs.readthedocs.org/en/latest/Apache.html#mod-proxy-uwsgi
*/
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_strings.h"
@@ -101,10 +136,26 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
ap_add_common_vars(r);
ap_add_cgi_vars(r);
// this is not a security problem (in Linux) as uWSGI destroy the env memory area readable in /proc
// and generally if you host untrusted apps in your server and allows them to read others uid /proc/<pid>
// files you have higher problems...
const char *auth = apr_table_get(r->headers_in, "Authorization");
if (auth) {
apr_table_setn(r->subprocess_env, "HTTP_AUTHORIZATION", auth);
}
const char *script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME");
const char *path_info = apr_table_get(r->subprocess_env, "PATH_INFO");
if (script_name && path_info) {
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
if (strcmp(path_info, "/")) {
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
}
else {
if (!strcmp(script_name, "/")) {
apr_table_set(r->subprocess_env, "SCRIPT_NAME", "");
}
}
}
env_table = apr_table_elts(r->subprocess_env);
@@ -135,7 +186,7 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
buf[0] = 0;
buf[1] = (uint8_t) (pktsize & 0xff);
buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
buf[0] = 0;
buf[3] = 0;
return uwsgi_send(conn, buf, headerlen, r);
}
@@ -166,28 +217,6 @@ static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
return OK;
}
static
apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,
int fold, int *writen)
{
char *tmp_s = s;
apr_status_t rv;
apr_size_t len;
rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);
apr_brigade_cleanup(bb);
if (rv == APR_SUCCESS) {
*writen = (int) len;
} else if (rv == APR_ENOSPC) {
*writen = n;
} else {
*writen = -1;
}
return rv;
}
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
{
@@ -207,11 +236,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
if (len == 0) {
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
}
len = ap_getline(buffer, sizeof(buffer), rp, 1);
if (len <= 0) {
// oops
@@ -220,25 +245,11 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
backend->worker->s->read += len;
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*") || len >= sizeof(buffer)-1) {
// oops
return HTTP_INTERNAL_SERVER_ERROR;
}
int major, minor;
major = buffer[5] - '0';
minor = buffer[7] - '0';
/* If not an HTTP/1 message or
* if the status line was > 8192 bytes
*/
if ((major != 1) || (len >= sizeof(buffer)-1)) {
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_pstrcat(r->pool, "Corrupt status line returned by remote "
"server: ", buffer, NULL));
}
char keepchar = buffer[12];
buffer[12] = '\0';
r->status = atoi(&buffer[9]);
@@ -326,7 +337,20 @@ static int uwsgi_handler(request_rec *r, proxy_worker *worker,
}
// ADD PATH_INFO
apr_table_add(r->subprocess_env, "PATH_INFO", url+strlen(worker->name));
size_t w_len = strlen(worker->name);
char *u_path_info = r->filename + 6 + w_len;
int delta = 0;
if (u_path_info[0] != '/') {
delta = 1;
}
int decode_status = ap_unescape_url(url+w_len-delta);
if (decode_status) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"unable to decode uri: %s",
url+w_len-delta);
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_table_add(r->subprocess_env, "PATH_INFO", url+w_len-delta);
/* Create space for state information */
+1 -1
View File
@@ -2,7 +2,7 @@
*** uWSGI/mod_uwsgi ***
Copyright 2009-2012 Unbit S.a.s. <info@unbit.it>
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
cmd = File.expand_path "#{File.dirname(__FILE__)}/../ext/uwsgi/uwsgi.ruby"
exec(cmd, *ARGV)
-1
View File
@@ -1 +0,0 @@
object file for embedded files will be put here
+1 -12
View File
@@ -1,24 +1,13 @@
[uwsgi]
xml = auto
ini = true
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
snmp = true
spooler = true
embedded = true
ssl = auto
udp = true
multicast = true
threading = true
minterpreters = true
async = true
ldap = auto
pcre = auto
routing = auto
alarm = auto
ipv6 = false
debug = false
unbit = false
xml_implementation = libxml2
@@ -29,7 +18,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
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
as_shared_library = false
locking = auto
+4
View File
@@ -0,0 +1,4 @@
[uwsgi]
# pypy,jvm,ring,jwsgi
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,mono,pyerl,go
inherit = base
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = jvm,jwsgi
inherit = base
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = mono
inherit = base
+34
View File
@@ -0,0 +1,34 @@
[uwsgi]
xml = true
yaml = true
json = true
sqlite3 = true
zeromq = true
ssl = true
ldap = true
pcre = true
routing = true
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = libyaml
malloc_implementation = libc
extras =
plugins =
bin_name = /usr/lib/libuwsgi.so
append_version = ubuntu
plugin_dir = /usr/lib/uwsgi
embedded_plugins =
as_shared_library = true
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
+6
View File
@@ -0,0 +1,6 @@
[uwsgi]
main_plugin = python,gevent
inherit = base
plugins = jvm,ring
plugin_dir = .
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = jvm,ring
inherit = base
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin =
inherit = base
+13 -13
View File
@@ -1,34 +1,34 @@
[uwsgi]
xml = true
ini = true
yaml = true
json = false
sqlite3 = false
zeromq = false
snmp = false
spooler = true
embedded = true
udp = true
multicast = false
threading = true
minterpreters = true
async = true
ldap = true
ssl = true
ldap = false
pcre = true
routing = true
alarm = true
debug = false
unbit = true
xml_implementation = expat
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
bin_name = /opt/unbit/bin/uwsgi
bin_name = /opt/unbit/uwsgi19/lib/libuwsgi.so
append_version = unbit
plugin_dir = /opt/unbit/uwsgi_plugins
plugin_dir = /opt/unbit/uwsgi19/plugins
embedded_plugins =
as_shared_library = true
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
-1
View File
@@ -1,6 +1,5 @@
[uwsgi]
inherit = unbit
json = false
embedded_plugins = python
bin_name = ../bin/uwsgi
plugin_dir = ../bin/uwsgi_plugins
+4 -1
View File
@@ -1,12 +1,15 @@
use POSIX;
use IO::Socket::INET;
use IO::Socket::INET6;
use IO::Socket::UNIX;
my $s = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 1717, Proto => 'tcp', Reuse => 1);
my $s2 = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 3022, Proto => 'tcp', Reuse => 1);
my $s3 = IO::Socket::INET6->new(LocalAddr => '::', LocalPort => 3017, Proto => 'tcp', Reuse => 1);
my $s4 = IO::Socket::UNIX->new(Local => '/tmp/u.sock', Listen => 1);
dup2($s->fileno, 17);
dup2($s2->fileno, 22);
dup2($s3->fileno, 30);
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30';
dup2($s4->fileno, 0);
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30','--stats',':5001';
+24
View File
@@ -0,0 +1,24 @@
require 'socket'
require 'openssl'
secret = 'ciaociao'
iv = ''
address = '127.0.0.1'
port = 1717
algo = 'bf-cbc'
s = UDPSocket.new
s.bind(address, port)
cipher = OpenSSL::Cipher.new(algo)
cipher.decrypt
cipher.key = secret + ("\0" * (cipher.key_len - secret.length))
cipher.iv = iv + ("0" * (cipher.iv_len - iv.length))
loop do
msg, sender = s.recvfrom(8192)
cipher.reset
begin
puts cipher.update(msg) + cipher.final
rescue
end
end
View File
+77 -4
View File
@@ -136,7 +136,8 @@ static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) {
}
static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
#ifdef UWSGI_PCRE
static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
struct uwsgi_alarm_log *old_ual = NULL, *ual = uwsgi.alarm_logs;
while (ual) {
@@ -148,6 +149,7 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
if (uwsgi_regexp_build(regexp, &ual->pattern, &ual->pattern_extra)) {
return -1;
}
ual->negate = negate;
if (old_ual) {
old_ual->next = ual;
@@ -161,8 +163,10 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
char *p = strtok(list, ",");
while (p) {
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
if (!uai)
if (!uai) {
free(list);
return -1;
}
struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms;
while (uall) {
old_uall = uall;
@@ -179,12 +183,38 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
}
p = strtok(NULL, ",");
}
free(list);
return 0;
}
#endif
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
char *buf = uwsgi_malloc(uwsgi.alarm_msg_size + sizeof(long));
for (;;) {
int interesting_fd = -1;
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret > 0) {
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
if (len > (ssize_t)(sizeof(long) + 1)) {
size_t msg_size = len - sizeof(long);
char *msg = buf + sizeof(long);
long ptr = 0;
memcpy(&ptr, buf, sizeof(long));
struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr;
if (!uai)
break;
uwsgi_alarm_run(uai, msg, msg_size);
}
}
}
free(buf);
}
// initialize alarms, instances and log regexps
void uwsgi_alarms_init() {
if (!uwsgi.master_process) return;
// first of all, create instance of alarms
struct uwsgi_string_list *usl = uwsgi.alarm_list;
while (usl) {
@@ -211,6 +241,9 @@ void uwsgi_alarms_init() {
usl = usl->next;
}
if (!uwsgi.alarm_instances) return;
#ifdef UWSGI_PCRE
// then map log-alarm
usl = uwsgi.alarm_logs_list;
while (usl) {
@@ -223,15 +256,27 @@ void uwsgi_alarms_init() {
*space = 0;
char *regexp = space + 1;
// here the log-alarm is created
if (uwsgi_alarm_log_add(line, regexp)) {
if (uwsgi_alarm_log_add(line, regexp, usl->custom)) {
uwsgi_log("invalid log-alarm: %s\n", usl->value);
exit(1);
}
usl = usl->next;
}
#endif
}
void uwsgi_alarm_thread_start() {
if (!uwsgi.alarm_instances) return;
// start the alarm_thread
uwsgi.alarm_thread = uwsgi_thread_new(uwsgi_alarm_thread_loop);
if (!uwsgi.alarm_thread) {
uwsgi_log("unable to spawn alarm thread\n");
exit(1);
}
}
#ifdef UWSGI_PCRE
// check if a log should raise an alarm
void uwsgi_alarm_log_check(char *msg, size_t len) {
if (!uwsgi_strncmp(msg, len, "[uwsgi-alarm", 12))
@@ -239,11 +284,17 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
struct uwsgi_alarm_log *ual = uwsgi.alarm_logs;
while (ual) {
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
uwsgi_alarm_log_run(ual, msg, len);
if (!ual->negate) {
uwsgi_alarm_log_run(ual, msg, len);
}
else {
break;
}
}
ual = ual->next;
}
}
#endif
// call the alarm func
void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
@@ -259,6 +310,7 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
uai->last_msg_size = len;
}
#ifdef UWSGI_PCRE
// call the alarms mapped to a log line
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
struct uwsgi_alarm_ll *uall = ual->alarms;
@@ -267,3 +319,24 @@ void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
uall = uall->next;
}
}
#endif
// this is the api function workers,mules and whatever you want can call from code
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
if (!uwsgi.alarm_thread) return;
if (len > uwsgi.alarm_msg_size) return;
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
if (!uai) return;
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
}
+72 -43
View File
@@ -1,7 +1,14 @@
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
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");
uwsgi.async_queue_is_full = now;
}
}
void uwsgi_async_init() {
int i;
@@ -33,7 +40,7 @@ struct wsgi_request *find_wsgi_req_by_fd(int fd) {
return uwsgi.async_waiting_fd_table[fd];
}
void runqueue_remove(struct uwsgi_async_request *u_request) {
static void runqueue_remove(struct uwsgi_async_request *u_request) {
struct uwsgi_async_request *parent = u_request->prev;
struct uwsgi_async_request *child = u_request->next;
@@ -58,7 +65,7 @@ void runqueue_remove(struct uwsgi_async_request *u_request) {
uwsgi.async_runqueue_cnt--;
}
void runqueue_push(struct wsgi_request *wsgi_req) {
static void runqueue_push(struct wsgi_request *wsgi_req) {
struct uwsgi_async_request *uar;
@@ -96,26 +103,25 @@ struct wsgi_request *find_first_available_wsgi_req() {
return wsgi_req;
}
void async_expire_timeouts() {
static void async_expire_timeouts(uint64_t now) {
struct wsgi_request *wsgi_req;
time_t current_time = uwsgi_now();
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
struct uwsgi_rb_timer *urbt;
for (;;) {
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL);
if (urbt == NULL)
return;
if (urbt->key <= current_time) {
if (urbt->value <= now) {
wsgi_req = (struct wsgi_request *) urbt->data;
// timeout expired
wsgi_req->async_timed_out = 1;
rb_erase(&wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
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;
@@ -138,12 +144,12 @@ void async_expire_timeouts() {
}
void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
if (fd < 0)
return;
return -1;
// find first slot
while (uad) {
@@ -168,8 +174,23 @@ void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
async_add_timeout(wsgi_req, timeout);
}
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
event_queue_add_fd_read(uwsgi.async_queue, fd);
wsgi_req->async_force_again = 1;
return event_queue_add_fd_read(uwsgi.async_queue, fd);
}
static int async_wait_fd_read(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (async_add_fd_read(wsgi_req, fd, timeout)) {
return -1;
}
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
if (wsgi_req->async_timed_out) {
wsgi_req->async_timed_out = 0;
return 0;
}
return 1;
}
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
@@ -180,12 +201,12 @@ void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
}
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
if (fd < 0)
return;
return -1;
// find first slot
while (uad) {
@@ -211,12 +232,27 @@ void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
}
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
event_queue_add_fd_write(uwsgi.async_queue, fd);
wsgi_req->async_force_again = 1;
return event_queue_add_fd_write(uwsgi.async_queue, fd);
}
static int async_wait_fd_write(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (async_add_fd_write(wsgi_req, fd, timeout)) {
return -1;
}
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
if (wsgi_req->async_timed_out) {
wsgi_req->async_timed_out = 0;
return 0;
}
return 1;
}
void async_schedule_to_req(void) {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
}
void async_loop() {
@@ -233,7 +269,7 @@ void async_loop() {
int is_a_new_connection;
int proto_parser_status;
time_t now, last_now = 0;
uint64_t now;
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
@@ -243,6 +279,9 @@ void async_loop() {
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;
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket);
@@ -252,20 +291,22 @@ void async_loop() {
if (!uwsgi.schedule_to_req)
uwsgi.schedule_to_req = async_schedule_to_req;
if (!uwsgi.schedule_to_main) {
uwsgi_log("*** WARNING *** async mode without coroutine/greenthread engine loaded !!!\n");
}
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
now = (uint64_t) uwsgi_now();
if (uwsgi.async_runqueue_cnt) {
timeout = 0;
}
else {
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
if (uwsgi.async_runqueue_cnt) {
timeout = 0;
}
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL);
if (min_timeout) {
timeout = min_timeout->key - uwsgi_now();
timeout = min_timeout->value - now;
if (timeout <= 0) {
async_expire_timeouts();
async_expire_timeouts(now);
timeout = 0;
}
}
@@ -276,9 +317,10 @@ void async_loop() {
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
now = (uint64_t) uwsgi_now();
// timeout ???
if (uwsgi.async_nevents == 0) {
async_expire_timeouts();
async_expire_timeouts(now);
}
@@ -305,11 +347,7 @@ void async_loop() {
uwsgi.wsgi_req = find_first_available_wsgi_req();
if (uwsgi.wsgi_req == NULL) {
now = uwsgi_now();
if (now > last_now) {
uwsgi_log("async queue is full !!!\n");
last_now = now;
}
uwsgi_async_queue_is_full((time_t)now);
break;
}
@@ -319,18 +357,6 @@ void async_loop() {
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
// on linux we do not need to reset the socket to blocking state
#ifndef __linux__
/* re-set blocking socket */
int arg = uwsgi_sock->arg;
arg &= (~O_NONBLOCK);
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) {
uwsgi_error("fcntl()");
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
#endif
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
uwsgi.async_queue_unused_ptr++;
@@ -354,13 +380,14 @@ void async_loop() {
if (uwsgi.wsgi_req) {
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
// reset timeout
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
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;
// parsing complete
if (!proto_parser_status) {
// remove fd from event poll and fd proto table
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
// put request in the runqueue
runqueue_push(uwsgi.wsgi_req);
continue;
@@ -395,7 +422,7 @@ void async_loop() {
}
uwsgi.wsgi_req->waiting_fds = NULL;
if (uwsgi.wsgi_req->async_timeout) {
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
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;
}
@@ -405,6 +432,8 @@ void async_loop() {
// put the request in the runqueue again
runqueue_push(uwsgi.wsgi_req);
// avoid managing other enqueued events...
break;
}
}
@@ -432,7 +461,7 @@ void async_loop() {
}
uwsgi.wsgi_req->waiting_fds = NULL;
if (uwsgi.wsgi_req->async_timeout) {
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
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;
}
+240
View File
@@ -48,6 +48,50 @@ int uwsgi_buffer_ensure(struct uwsgi_buffer *ub, size_t len) {
return 0;
}
int uwsgi_buffer_insert(struct uwsgi_buffer *ub, size_t pos, char *buf, size_t len) {
size_t to_move = (ub->pos-pos);
if (uwsgi_buffer_ensure(ub, len)) return -1;
memmove(ub->buf+pos+len, ub->buf+pos, to_move);
memcpy(ub->buf+pos, buf, len);
ub->pos += len;
return 0;
}
int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *ub, size_t pos, size_t len) {
// 0xFFFFFFFFFFFFFFFF\r\n\0
char chunked[19];
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
if (ret <= 0 || ret > 19) {
return -1;
}
return uwsgi_buffer_insert(ub, pos, chunked, ret);
}
int uwsgi_buffer_append_chunked(struct uwsgi_buffer *ub, size_t len) {
// 0xFFFFFFFFFFFFFFFF\r\n\0
char chunked[19];
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
if (ret <= 0 || ret > 19) {
return -1;
}
return uwsgi_buffer_append(ub, chunked, ret);
}
int uwsgi_buffer_decapitate(struct uwsgi_buffer *ub, size_t len) {
if (len > ub->pos) return -1;
memmove(ub->buf, ub->buf + len, ub->pos-len);
ub->pos = ub->pos-len;
return 0;
}
int uwsgi_buffer_byte(struct uwsgi_buffer *ub, char byte) {
return uwsgi_buffer_append(ub, &byte, 1);
}
int uwsgi_buffer_u8(struct uwsgi_buffer *ub, uint8_t u8) {
return uwsgi_buffer_append(ub, (char *) &u8, 1);
}
int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
@@ -77,12 +121,173 @@ int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
return 0;
}
int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
// need to escape \ and "
size_t i;
for(i=0;i<len;i++) {
if (buf[i] == '"') {
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
}
else if (buf[i] == '\\') {
if (uwsgi_buffer_append(ub, "\\\\", 2)) return -1;
}
else {
if (uwsgi_buffer_append(ub, buf+i, 1)) return -1;
}
}
return 0;
}
int uwsgi_buffer_u16le(struct uwsgi_buffer *ub, uint16_t num) {
uint8_t buf[2];
buf[0] = (uint8_t) (num & 0xff);
buf[1] = (uint8_t) ((num >> 8) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 2);
}
int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) {
uint8_t buf[2];
buf[1] = (uint8_t) (num & 0xff);
buf[0] = (uint8_t) ((num >> 8) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 2);
}
int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) {
uint8_t buf[3];
buf[2] = (uint8_t) (num & 0xff);
buf[1] = (uint8_t) ((num >> 8) & 0xff);
buf[0] = (uint8_t) ((num >> 16) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 3);
}
int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) {
uint8_t buf[4];
buf[3] = (uint8_t) (num & 0xff);
buf[2] = (uint8_t) ((num >> 8) & 0xff);
buf[1] = (uint8_t) ((num >> 16) & 0xff);
buf[0] = (uint8_t) ((num >> 24) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 4);
}
int uwsgi_buffer_u32le(struct uwsgi_buffer *ub, uint32_t num) {
uint8_t buf[4];
buf[0] = (uint8_t) (num & 0xff);
buf[1] = (uint8_t) ((num >> 8) & 0xff);
buf[2] = (uint8_t) ((num >> 16) & 0xff);
buf[3] = (uint8_t) ((num >> 24) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 4);
}
int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
uint8_t buf[8];
buf[7] = (uint8_t) (num & 0xff);
buf[6] = (uint8_t) ((num >> 8) & 0xff);
buf[5] = (uint8_t) ((num >> 16) & 0xff);
buf[4] = (uint8_t) ((num >> 24) & 0xff);
buf[3] = (uint8_t) ((num >> 32) & 0xff);
buf[2] = (uint8_t) ((num >> 40) & 0xff);
buf[1] = (uint8_t) ((num >> 48) & 0xff);
buf[0] = (uint8_t) ((num >> 56) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 8);
}
int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) {
char ip[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, addr, ip, INET_ADDRSTRLEN)) {
uwsgi_error("uwsgi_buffer_append_ipv4() -> inet_ntop()");
return -1;
}
return uwsgi_buffer_append(ub, ip, strlen(ip));
}
int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
return -1;
}
return uwsgi_buffer_append(ub, buf, ret);
}
int uwsgi_buffer_append_keyval(struct uwsgi_buffer *ub, char *key, uint16_t keylen, char *val, uint16_t vallen) {
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
if (uwsgi_buffer_u16le(ub, vallen)) return -1;
return uwsgi_buffer_append(ub, val, vallen);
}
int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *ub, char *key, uint32_t keylen, char *val, uint32_t vallen) {
if (uwsgi_buffer_u32be(ub, keylen)) return -1;
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
if (uwsgi_buffer_u32be(ub, vallen)) return -1;
return uwsgi_buffer_append(ub, val, vallen);
}
int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keylen, int64_t num) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
return -1;
}
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
if (uwsgi_buffer_u16le(ub, ret)) return -1;
return uwsgi_buffer_append(ub, buf, ret);
}
int uwsgi_buffer_append_valnum(struct uwsgi_buffer *ub, int64_t num) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
return -1;
}
if (uwsgi_buffer_u16le(ub, ret)) return -1;
return uwsgi_buffer_append(ub, buf, ret);
}
int uwsgi_buffer_append_keyipv4(struct uwsgi_buffer *ub, char *key, uint16_t keylen, void *addr) {
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
if (uwsgi_buffer_u16le(ub, 15)) return -1;
char *ptr = ub->buf + (ub->pos - 2);
if (uwsgi_buffer_append_ipv4(ub, addr)) return -1;
// fix the size
*ptr = ((ub->buf+ub->pos) - (ptr+2));
return 0;
}
int uwsgi_buffer_append_base64(struct uwsgi_buffer *ub, char *s, size_t len) {
size_t b64_len = 0;
char *b64 = uwsgi_base64_encode(s, len, &b64_len);
if (!b64) return -1;
int ret = uwsgi_buffer_append(ub, b64, b64_len);
free(b64);
return ret;
}
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
if (ub->buf)
free(ub->buf);
free(ub);
}
ssize_t uwsgi_buffer_write_simple(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
size_t remains = ub->pos;
while(remains) {
ssize_t len = write(wsgi_req->fd, ub->buf + (ub->pos - remains), remains);
if (len <= 0) {
return len;
}
remains -= len;
}
return ub->pos;
}
int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
size_t remains = ub->pos;
char *ptr = ub->buf;
@@ -114,3 +319,38 @@ int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
return 0;
}
int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modifier2) {
if (ub->pos < 4) return -1;
ub->buf[0] = modifier1;
ub->buf[1] = (uint8_t) ((ub->pos - 4) & 0xff);
ub->buf[2] = (uint8_t) (((ub->pos - 4) >> 8) & 0xff);
ub->buf[3] = modifier2;
return 0;
}
struct uwsgi_buffer *uwsgi_buffer_from_file(char *filename) {
struct stat st;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
return NULL;
}
if (fstat(fd, &st)) {
close(fd);
return NULL;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(st.st_size);
ssize_t len = read(fd, ub->buf, st.st_size);
close(fd);
if (len != st.st_size) {
uwsgi_buffer_destroy(ub);
return NULL;
}
ub->pos = len;
return ub;
}
+1464 -239
View File
File diff suppressed because it is too large Load Diff
-464
View File
@@ -1,464 +0,0 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_UDP
static void cluster_manage_opt(char *key, uint16_t keylen, char *value, uint16_t vallen, void *foobar) {
add_exported_option(uwsgi_concat2n(key, keylen, "", 0), uwsgi_concat2n(value, vallen, "", 0), 0);
}
void cluster_setup() {
int rlen;
// get cluster configuration
if (uwsgi.cluster != NULL) {
// get multicast socket
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
// ask for cluster options only if bot pre-existent options are set
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
// now wait max 60 seconds and resend multicast request every 10 seconds
for (;;) {
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
continue;
}
waitfd:
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
if (rlen < 0) {
break;
}
else if (rlen > 0) {
// receive the packet
char clusterbuf[4096];
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, cluster_manage_opt, NULL)) {
uwsgi_configure();
goto options_parsed;
}
else {
goto waitfd;
}
}
}
}
options_parsed:
if (!uwsgi.cluster_nodes)
uwsgi_cluster_add_me();
}
}
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
int i;
struct uwsgi_cluster_node *ucn;
char *tcp_port;
#ifdef UWSGI_DEBUG
uwsgi_log("adding node\n");
#endif
tcp_port = strchr(nucn->name, ':');
#ifndef UWSGI_ZEROMQ
if (tcp_port == NULL) {
#else
char *zmq_dash = strchr(nucn->name, '-');
if (tcp_port == NULL && zmq_dash == NULL) {
#endif
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
return;
}
// first check for already present node
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0) {
if (!strcmp(ucn->name, nucn->name)) {
ucn->status = UWSGI_NODE_OK;
ucn->last_seen = uwsgi_now();
// update requests
ucn->requests = nucn->requests;
return;
}
}
}
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] == 0) {
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
ucn->workers = nucn->workers;
ucn->ucn_addr.sin_family = AF_INET;
if (tcp_port) {
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
tcp_port[0] = 0;
}
if (nucn->name[0] == 0) {
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
}
else {
#ifdef UWSGI_DEBUG
uwsgi_log("%s\n", nucn->name);
#endif
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
}
ucn->type = type;
// here memory can be freed, as it is allocated by uwsgi_concat2n
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
tcp_port[0] = ':';
}
ucn->last_seen = uwsgi_now();
ucn->requests = nucn->requests;
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
return;
}
}
uwsgi_log("unable to add node %s\n", nucn->name);
}
int uwsgi_cluster_add_me() {
const char *key1 = "hostname";
const char *key2 = "address";
const char *key3 = "workers";
const char *key4 = "requests";
char *ptrbuf;
uint16_t ustrlen;
char numproc[6];
#ifdef UWSGI_ZEROMQ
char uuid_zmq_str[37];
uuid_t uuid_zmq;
if (!uwsgi.sockets && !uwsgi.zeromq) {
#else
if (!uwsgi.sockets) {
#endif
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
exit(1);
}
snprintf(numproc, 6, "%d", uwsgi.numproc);
size_t len;
if (uwsgi.sockets) {
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
}
#ifdef UWSGI_ZEROMQ
else if (uwsgi.zeromq) {
uuid_generate(uuid_zmq);
uuid_unparse(uuid_zmq, uuid_zmq_str);
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
}
#endif
else {
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
}
char *buf = uwsgi_malloc(len);
ptrbuf = buf;
ustrlen = strlen(key1);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, key1, strlen(key1));
ptrbuf += strlen(key1);
ustrlen = strlen(uwsgi.hostname);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
ptrbuf += strlen(uwsgi.hostname);
if (uwsgi.sockets && uwsgi.sockets->name) {
ustrlen = strlen(key2);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, key2, strlen(key2));
ptrbuf += strlen(key2);
ustrlen = strlen(uwsgi.sockets->name);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
ptrbuf += strlen(uwsgi.sockets->name);
}
#ifdef UWSGI_ZEROMQ
else if (uwsgi.zeromq) {
ustrlen = strlen(key2);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, key2, strlen(key2));
ptrbuf += strlen(key2);
ustrlen = strlen(uuid_zmq_str);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
ptrbuf += strlen(uuid_zmq_str);
}
#endif
ustrlen = strlen(key3);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, key3, strlen(key3));
ptrbuf += strlen(key3);
ustrlen = strlen(numproc);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, numproc, strlen(numproc));
ptrbuf += strlen(numproc);
ustrlen = strlen(key4);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, key4, strlen(key4));
ptrbuf += strlen(key4);
ustrlen = 1;
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ptrbuf, "0", 1);
ptrbuf += 1;
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
free(buf);
#ifdef UWSGI_DEBUG
uwsgi_log("add_me() successfull\n");
#endif
return 0;
}
int uwsgi_cluster_join(char *name) {
int fd;
char *cp;
int broadcast = 0;
if (name[0] == ':') {
fd = bind_to_udp(name, 0, 1);
broadcast = 1;
}
else {
fd = bind_to_udp(name, 1, 0);
}
if (fd >= 0) {
cp = strchr(name, ':');
cp[0] = 0;
uwsgi.mc_cluster_addr.sin_family = AF_INET;
if (broadcast) {
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
}
else {
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
}
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
cp[0] = ':';
// announce my presence to all the nodes
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
}
else {
exit(1);
}
return fd;
}
char *uwsgi_cluster_best_node() {
int i;
int best_node = -1;
struct uwsgi_cluster_node *ucn;
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
if (best_node == -1) {
best_node = i;
}
else {
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
best_node = i;
}
}
}
}
if (best_node == -1) {
return NULL;
}
uwsgi.shared->nodes[best_node].last_choosen = uwsgi_now();
return uwsgi.shared->nodes[best_node].name;
}
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
char *tmpstr;
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
#ifdef UWSGI_DEBUG
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
#endif
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
strncpy(ucn->nodename, val, UMIN(vallen, 255));
}
if (!uwsgi_strncmp("address", 7, key, keylen)) {
strncpy(ucn->name, val, UMIN(vallen, 100));
}
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
ucn->workers = atoi(tmpstr);
free(tmpstr);
}
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
ucn->requests = strtoul(tmpstr, NULL, 0);
free(tmpstr);
}
}
void manage_cluster_message(char *cluster_opt_buf, int cluster_opt_size) {
struct uwsgi_cluster_node nucn;
switch (uwsgi.workers[0].cores[0].req.uh.modifier1) {
case 95:
memset(&nucn, 0, sizeof(struct uwsgi_cluster_node));
#ifdef __BIG_ENDIAN__
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
#endif
uwsgi_hooked_parse(uwsgi.workers[0].cores[0].req.buffer, uwsgi.workers[0].cores[0].req.uh.pktsize, manage_cluster_announce, &nucn);
if (nucn.name[0] != 0) {
uwsgi_cluster_add_node(&nucn, CLUSTER_NODE_DYNAMIC);
}
break;
case 96:
#ifdef __BIG_ENDIAN__
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
#endif
uwsgi_log_verbose("%.*s\n", uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
break;
case 98:
if (kill(getpid(), SIGHUP)) {
uwsgi_error("kill()");
}
break;
case 99:
if (uwsgi.cluster_nodes)
break;
if (uwsgi.workers[0].cores[0].req.uh.modifier2 == 0) {
uwsgi_log("requested configuration data, sending %d bytes\n", cluster_opt_size);
sendto(uwsgi.cluster_fd, cluster_opt_buf, cluster_opt_size, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr));
}
break;
case 73:
#ifdef __BIG_ENDIAN__
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
#endif
uwsgi_log_verbose("[uWSGI cluster %s] new node available: %.*s\n", uwsgi.cluster, uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
break;
}
}
#endif
char *uwsgi_setup_clusterbuf(size_t * size) {
size_t cluster_opt_size = 4;
int i;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->key);
if (uwsgi.exported_opts[i]->value) {
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->value);
}
else {
cluster_opt_size += 2 + 1;
}
}
//uwsgi_log("cluster opts size: %d\n", cluster_opt_size);
char *cluster_opt_buf = uwsgi_malloc(cluster_opt_size);
struct uwsgi_header *uh = (struct uwsgi_header *) cluster_opt_buf;
uh->modifier1 = 99;
uh->pktsize = cluster_opt_size - 4;
uh->modifier2 = 1;
#ifdef __BIG_ENDIAN__
uh->pktsize = uwsgi_swap16(uh->pktsize);
#endif
char *cptrbuf = cluster_opt_buf + 4;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
uint16_t ustrlen = strlen(uwsgi.exported_opts[i]->key);
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(cptrbuf, uwsgi.exported_opts[i]->key, ustrlen);
cptrbuf += ustrlen;
if (uwsgi.exported_opts[i]->value) {
ustrlen = strlen(uwsgi.exported_opts[i]->value);
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(cptrbuf, uwsgi.exported_opts[i]->value, ustrlen);
}
else {
ustrlen = 1;
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
*cptrbuf = '1';
}
cptrbuf += ustrlen;
}
return cluster_opt_buf;
}
+81
View File
@@ -0,0 +1,81 @@
#include <uwsgi.h>
/*
cookie management functions (mainly used by the internal routing subsystem)
*/
static char *check_cookie(char *cookie, uint16_t cookie_len, char *key, uint16_t keylen, uint16_t *vallen) {
uint16_t orig_cookie_len = cookie_len-1;
// first lstrip white spaces
char *ptr = cookie;
uint16_t i;
for(i=0;i<cookie_len;i++) {
if (isspace((int)ptr[i])) {
cookie++;
cookie_len--;
}
else {
break;
}
}
// then rstrip (skipping the first char...)
for(i=orig_cookie_len;i>0;i--) {
if (isspace((int)ptr[i])) {
cookie_len--;
}
else {
break;
}
}
// now search for the first equal sign
char *equal = memchr(cookie, '=', cookie_len);
if (!equal) return NULL;
if (uwsgi_strncmp(key, keylen, cookie, equal-cookie)) {
return NULL;
}
cookie_len -= (equal-cookie)+1;
if (cookie_len == 0) return NULL;
*vallen = cookie_len;
return equal+1;
}
char *uwsgi_get_cookie(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
uint16_t i;
char *cookie = wsgi_req->cookie;
uint16_t cookie_len = 0;
char *ptr = wsgi_req->cookie;
//start splitting by ;
for(i=0;i<wsgi_req->cookie_len;i++) {
if (!cookie) {
cookie = ptr + i;
}
if (ptr[i] == ';') {
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
if (value) {
return value;
}
cookie_len = 0;
cookie = NULL;
}
else {
cookie_len++;
}
}
if (cookie_len > 0) {
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
if (value) {
return value;
}
}
return NULL;
}
+14 -3
View File
@@ -30,6 +30,16 @@ extern struct uwsgi_server uwsgi;
*/
void uwsgi_daemons_smart_check() {
static time_t last_run = 0;
time_t now = uwsgi_now();
if (now - last_run <= 0) {
return;
}
last_run = now;
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pidfile) {
@@ -41,14 +51,14 @@ void uwsgi_daemons_smart_check() {
}
else {
ud->pidfile_checks++;
if (ud->pidfile_checks >= (uint64_t) ud->freq) {
if (ud->pidfile_checks >= (unsigned int) ud->freq) {
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
uwsgi_spawn_daemon(ud);
}
}
}
else if (checked_pid != ud->pid) {
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
uwsgi_log("[uwsgi-daemons] found changed pid for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
ud->pid = checked_pid;
}
// all ok, pidfile and process found
@@ -183,6 +193,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
else {
// close uwsgi sockets
uwsgi_close_all_sockets();
uwsgi_close_all_fds();
if (ud->daemonize) {
/* refork... */
@@ -204,7 +215,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
exit(1);
}
if (devnull != 0) {
if (dup2(devnull, 0)) {
if (dup2(devnull, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
+331 -81
View File
@@ -6,7 +6,6 @@ a supervisor for multiple uWSGI instances
*/
#include "uwsgi.h"
#include <glob.h>
extern struct uwsgi_server uwsgi;
@@ -88,7 +87,7 @@ void uwsgi_emperor_blacklist_add(char *id) {
}
}
strcpy(uebi->id, id);
strncpy(uebi->id, id, 0xff);
gettimeofday(&uebi->first_attempt, NULL);
memcpy(&uebi->last_attempt, &uebi->first_attempt, sizeof(struct timeval));
uebi->throttle_level = uwsgi.emperor_throttle;
@@ -136,6 +135,77 @@ int uwsgi_emperor_is_valid(char *name) {
return 0;
}
static char *emperor_check_on_demand_socket(char *filename) {
size_t len = 0;
if (uwsgi.emperor_on_demand_extension) {
char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension);
int fd = open(tmp, O_RDONLY);
free(tmp);
if (fd < 0) return NULL;
char *ret = uwsgi_read_fd(fd, &len, 1);
close(fd);
// change the first non prinabel character to 0
size_t i;
for(i=0;i<len;i++) {
if (ret[i] < 32) {
ret[i] = 0;
break;
}
}
if (ret[0] == 0) {
free(ret);
return NULL;
}
return ret;
}
else if (uwsgi.emperor_on_demand_directory) {
// we need to build the socket path automagically
char *start_of_vassal_name = uwsgi_get_last_char(filename, '/');
if (!start_of_vassal_name) {
start_of_vassal_name = filename;
}
else {
start_of_vassal_name++;
}
char *last_dot = uwsgi_get_last_char(filename, '.');
if (!last_dot) return NULL;
return uwsgi_concat4n(uwsgi.emperor_on_demand_directory, strlen(uwsgi.emperor_on_demand_directory), "/", 1, start_of_vassal_name, last_dot - start_of_vassal_name, ".socket", 7);
}
else if (uwsgi.emperor_on_demand_exec) {
int cpipe[2];
if (pipe(cpipe)) {
uwsgi_error("emperor_check_on_demand_socket()pipe()");
return NULL;
}
char *cmd = uwsgi_concat4(uwsgi.emperor_on_demand_exec, " \"", filename, "\"");
int r = uwsgi_run_command(cmd, NULL, cpipe[1]);
free(cmd);
if (r < 0) {
close(cpipe[0]);
close(cpipe[1]);
return NULL;
}
char *ret = uwsgi_read_fd(cpipe[0], &len, 1);
close(cpipe[0]);
close(cpipe[1]);
// change the first non prinabel character to 0
size_t i;
for(i=0;i<len;i++) {
if (ret[i] < 32) {
ret[i] = 0;
break;
}
}
if (ret[0] == 0) {
free(ret);
return NULL;
}
return ret;
}
return NULL;
}
// this is the monitor for non-glob directories
void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
struct uwsgi_instance *ui_current;
@@ -176,7 +246,9 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
}
}
else {
emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
char *socket_name = emperor_check_on_demand_socket(de->d_name);
emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid, socket_name);
if (socket_name) free(socket_name);
}
}
closedir(dir);
@@ -186,8 +258,24 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
while (c_ui) {
if (c_ui->scanner == ues) {
if (stat(c_ui->name, &st)) {
emperor_stop(c_ui);
if (c_ui->zerg) {
char *colon = strrchr(c_ui->name, ':');
if (!colon) {
emperor_stop(c_ui);
}
else {
char *filename = uwsgi_calloc(0xff);
memcpy(filename, c_ui->name, colon - c_ui->name);
if (stat(filename, &st)) {
emperor_stop(c_ui);
}
free(filename);
}
}
else {
if (stat(c_ui->name, &st)) {
emperor_stop(c_ui);
}
}
}
c_ui = c_ui->ui_next;
@@ -235,7 +323,9 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
}
}
else {
emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]);
emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid, socket_name);
if (socket_name) free(socket_name);
}
}
@@ -246,9 +336,25 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
while (c_ui) {
if (c_ui->scanner == ues) {
if (stat(c_ui->name, &st)) {
emperor_stop(c_ui);
}
if (c_ui->zerg) {
char *colon = strrchr(c_ui->name, ':');
if (!colon) {
emperor_stop(c_ui);
}
else {
char *filename = uwsgi_calloc(0xff);
memcpy(filename, c_ui->name, colon - c_ui->name);
if (stat(filename, &st)) {
emperor_stop(c_ui);
}
free(filename);
}
}
else {
if (stat(c_ui->name, &st)) {
emperor_stop(c_ui);
}
}
}
c_ui = c_ui->ui_next;
}
@@ -325,7 +431,7 @@ static void emperor_stats() {
while (c_ui) {
uwsgi_log("vassal instance %s (last modified %d) status %d loyal %d zerg %d\n", c_ui->name, c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
uwsgi_log("vassal instance %s (last modified %lld) status %d loyal %d zerg %d\n", c_ui->name, (long long) c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
c_ui = c_ui->ui_next;
}
@@ -346,6 +452,22 @@ struct uwsgi_instance *emperor_get_by_fd(int fd) {
return NULL;
}
struct uwsgi_instance *emperor_get_by_socket_fd(int fd) {
struct uwsgi_instance *c_ui = ui;
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
// over engineering...
if (c_ui->on_demand_fd != -1 && c_ui->on_demand_fd == fd) {
return c_ui;
}
}
return NULL;
}
struct uwsgi_instance *emperor_get(char *name) {
@@ -399,6 +521,10 @@ void emperor_del(struct uwsgi_instance *c_ui) {
uwsgi.emperor_broodlord_count--;
}
if (c_ui->socket_name) {
free(c_ui->socket_name);
}
free(c_ui);
}
@@ -417,18 +543,29 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
struct uwsgi_header uh;
// reload the uWSGI instance
if (write(c_ui->pipe[0], "\1", 1) != 1) {
uwsgi_error("write()");
}
// push the config to the config pipe (if needed)
if (c_ui->use_config) {
if (write(c_ui->pipe[0], "\0", 1) != 1) {
uwsgi_error("write()");
uh.modifier1 = 115;
uh.pktsize = c_ui->config_len;
uh.modifier2 = 0;
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
uwsgi_error("[uwsgi-emperor] write() header config");
}
}
else {
if (write(c_ui->pipe[0], "\1", 1) != 1) {
uwsgi_error("write()");
else {
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
uwsgi_error("[uwsgi-emperor] write() config");
}
}
}
c_ui->respawns++;
c_ui->last_mod = mod;
c_ui->last_run = uwsgi_now();
@@ -436,17 +573,10 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
uwsgi_log("[emperor] reload the uwsgi instance %s\n", c_ui->name);
}
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) {
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name) {
struct uwsgi_instance *c_ui = ui;
struct uwsgi_instance *n_ui = NULL;
pid_t pid;
char **vassal_argv;
char *uef;
char **uenvs;
int counter;
char *colon = NULL;
int i;
struct timeval tv;
#ifdef UWSGI_DEBUG
@@ -454,7 +584,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
#endif
if (strlen(name) > (0xff - 1)) {
uwsgi_log("[emperor] invalid vassal name\n", name);
uwsgi_log("[emperor] invalid vassal name: %s\n", name);
return;
}
@@ -502,8 +632,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
c_ui = c_ui->ui_next;
}
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
memset(n_ui, 0, sizeof(struct uwsgi_instance));
n_ui = uwsgi_calloc(sizeof(struct uwsgi_instance));
if (config) {
n_ui->use_config = 1;
@@ -534,10 +663,60 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
n_ui->first_run = uwsgi_now();
n_ui->last_run = n_ui->first_run;
n_ui->on_demand_fd = -1;
if (socket_name) {
n_ui->socket_name = uwsgi_str(socket_name);
}
n_ui->pid = -1;
// ok here we check if we need to bind to the specified socket or continue with the activation
if (socket_name) {
char *tcp_port = strchr(socket_name, ':');
if (tcp_port) {
// disable deferred accept for this socket
int current_defer_accept = uwsgi.no_defer_accept;
uwsgi.no_defer_accept = 1;
n_ui->on_demand_fd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port);
uwsgi.no_defer_accept = current_defer_accept;
}
else {
n_ui->on_demand_fd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
if (n_ui->on_demand_fd < 0) {
uwsgi_error("emperor_add()/bind()");
free(n_ui);
c_ui->ui_next = NULL;
return;
}
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd);
uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name);
return;
}
if (uwsgi_emperor_vassal_start(n_ui)) {
// clear the vassal
free(n_ui);
c_ui->ui_next = NULL;
}
}
int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
int i;
char *colon = NULL;
int counter;
char **uenvs;
char *uef;
char **vassal_argv;
pid_t pid;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
uwsgi_error("socketpair()");
goto clear;
return -1;
}
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]);
@@ -545,10 +724,14 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
if (n_ui->use_config) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
uwsgi_error("socketpair()");
goto clear;
return -1;
}
}
if (n_ui->zerg) {
uwsgi.emperor_broodlord_num++;
}
// TODO pre-start hook
// a new uWSGI instance will start
@@ -560,23 +743,37 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
n_ui->pid = pid;
// close the right side of the pipe
close(n_ui->pipe[1]);
// close the "on demand" socket
if (n_ui->on_demand_fd > -1) {
close(n_ui->on_demand_fd);
n_ui->on_demand_fd = -1;
}
if (n_ui->use_config) {
close(n_ui->pipe_config[1]);
}
if (n_ui->use_config) {
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
uwsgi_error("write()");
}
close(n_ui->pipe_config[0]);
struct uwsgi_header uh;
uh.modifier1 = 115;
uh.pktsize = n_ui->config_len;
uh.modifier2 = 0;
if (write(n_ui->pipe_config[0], &uh, 4) != 4) {
uwsgi_error("[uwsgi-emperor] write() header config");
}
else {
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) {
uwsgi_error("[uwsgi-emperor] write() config");
}
}
}
return;
return 0;
}
else {
if (uwsgi.emperor_tyrant) {
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name);
if (setgid(gid)) {
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name);
if (setgid(n_ui->gid)) {
uwsgi_error("setgid()");
exit(1);
}
@@ -585,7 +782,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
exit(1);
}
if (setuid(uid)) {
if (setuid(n_ui->uid)) {
uwsgi_error("setuid()");
exit(1);
}
@@ -602,6 +799,16 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
free(uef);
// add UWSGI_BROODLORD_NUM
if (n_ui->zerg) {
uef = uwsgi_num2str(uwsgi.emperor_broodlord_num);
if (setenv("UWSGI_BROODLORD_NUM", uef, 1)) {
uwsgi_error("setenv()");
exit(1);
}
free(uef);
}
if (n_ui->use_config) {
uef = uwsgi_num2str(n_ui->pipe_config[1]);
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
@@ -618,6 +825,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
if (unsetenv(oe)) {
uwsgi_error("unsetenv()");
free(oe);
break;
}
free(oe);
@@ -654,7 +862,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
vassal_argv[0] = uwsgi.binary_path;
if (uwsgi.emperor_broodlord) {
colon = strchr(name, ':');
colon = strchr(n_ui->name, ':');
if (colon) {
colon[0] = 0;
}
@@ -662,17 +870,17 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
// initialize to a default value
vassal_argv[1] = "--inherit";
if (!strcmp(name + (strlen(name) - 4), ".xml"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml"))
vassal_argv[1] = "--xml";
if (!strcmp(name + (strlen(name) - 4), ".ini"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini"))
vassal_argv[1] = "--ini";
if (!strcmp(name + (strlen(name) - 4), ".yml"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml"))
vassal_argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml"))
vassal_argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 3), ".js"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js"))
vassal_argv[1] = "--json";
if (!strcmp(name + (strlen(name) - 5), ".json"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json"))
vassal_argv[1] = "--json";
if (colon) {
@@ -680,16 +888,16 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
vassal_argv[2] = name;
vassal_argv[2] = n_ui->name;
if (uwsgi.emperor_magic_exec) {
if (!access(name, R_OK | X_OK)) {
vassal_argv[2] = uwsgi_concat2("exec://", name);
if (!access(n_ui->name, R_OK | X_OK)) {
vassal_argv[2] = uwsgi_concat2("exec://", n_ui->name);
}
}
if (n_ui->use_config) {
vassal_argv[2] = uwsgi_concat2("emperor://", name);
vassal_argv[2] = uwsgi_concat2("emperor://", n_ui->name);
}
counter = 3;
@@ -702,18 +910,29 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
vassal_argv[counter] = NULL;
// disable stdin
int stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
// disable stdin OR map it to the "on demand" socket
if (n_ui->on_demand_fd > -1) {
if (n_ui->on_demand_fd != 0) {
if (dup2(n_ui->on_demand_fd, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(n_ui->on_demand_fd);
}
}
if (stdin_fd != 0) {
if (dup2(stdin_fd, 0)) {
uwsgi_error("dup2()");
else {
int stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
close(stdin_fd);
if (stdin_fd != 0) {
if (dup2(stdin_fd, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(stdin_fd);
}
}
// close all of the unneded fd
@@ -747,11 +966,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
exit(UWSGI_EXILE_CODE);
}
clear:
free(n_ui);
c_ui->ui_next = NULL;
return -1;
}
void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *ues) {
@@ -784,6 +999,8 @@ void uwsgi_imperial_monitor_directory_init(struct uwsgi_emperor_scanner *ues) {
exit(1);
}
ues->arg = uwsgi.emperor_absolute_dir;
}
struct uwsgi_imperial_monitor *imperial_monitor_get_by_id(char *scheme) {
@@ -907,6 +1124,8 @@ void emperor_loop() {
char notification_message[64];
struct rlimit rl;
uwsgi.disable_nuclear_blast = 1;
uwsgi.emperor_stats_fd = -1;
if (uwsgi.emperor_pidfile) {
@@ -988,9 +1207,9 @@ void emperor_loop() {
}
// check if a monitor is mapped to that file descriptor
if (uwsgi_emperor_scanner_event(interesting_fd))
if (uwsgi_emperor_scanner_event(interesting_fd)) {
continue;
}
ui_current = emperor_get_by_fd(interesting_fd);
if (ui_current) {
@@ -998,9 +1217,7 @@ void emperor_loop() {
ssize_t rlen = read(interesting_fd, &byte, 1);
if (rlen <= 0) {
// SAFE
if (!ui_current->config_len) {
emperor_del(ui_current);
}
emperor_del(ui_current);
}
else {
if (byte == 17) {
@@ -1021,14 +1238,24 @@ void emperor_loop() {
else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
char *zerg_name = uwsgi_concat3(ui_current->name, ":", "zerg");
emperor_add(NULL, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid);
// here we discard socket name as broodlord/zerg cannot be on demand
emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid, NULL);
free(zerg_name);
}
}
}
else {
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
close(interesting_fd);
ui_current = emperor_get_by_socket_fd(interesting_fd);
if (ui_current) {
event_queue_del_fd(uwsgi.emperor_queue, ui_current->on_demand_fd, event_queue_read());
if (uwsgi_emperor_vassal_start(ui_current)) {
emperor_del(ui_current);
}
}
else {
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
close(interesting_fd);
}
}
}
@@ -1054,7 +1281,9 @@ void emperor_loop() {
has_children = 0;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
has_children++;
if (ui_current->pid > -1) {
has_children++;
}
}
if (uwsgi.notify) {
@@ -1106,7 +1335,7 @@ void emperor_loop() {
}
else {
// UNSAFE
emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid);
emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, ui_current->socket_name);
emperor_del(ui_current);
}
break;
@@ -1200,7 +1429,7 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keyval_comma(us, "id", c_ui->name))
goto end0;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) c_ui->pid))
if (uwsgi_stats_keyslong_comma(us, "pid", (long long) c_ui->pid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "born", (unsigned long long) c_ui->born))
goto end0;
@@ -1219,6 +1448,9 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keylong_comma(us, "zerg", (unsigned long long) c_ui->zerg))
goto end0;
if (uwsgi_stats_keyval_comma(us, "on_demand", c_ui->socket_name ? c_ui->socket_name : ""))
goto end0;
if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) c_ui->uid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid))
@@ -1322,13 +1554,22 @@ end:
void uwsgi_emperor_start() {
if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) {
if (uwsgi.emperor_procname) {
uwsgi_set_processname(uwsgi.emperor_procname);
}
uwsgi_notify_ready();
emperor_loop();
// never here
exit(1);
}
uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor");
if (uwsgi.emperor_procname) {
uwsgi.emperor_pid = uwsgi_fork(uwsgi.emperor_procname);
}
else {
uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor");
}
if (uwsgi.emperor_pid < 0) {
uwsgi_error("pid()");
exit(1);
@@ -1362,7 +1603,7 @@ void uwsgi_check_emperor() {
}
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid) {
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) {
if (!uwsgi_emperor_is_valid(name))
return;
@@ -1380,16 +1621,25 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
}
// check if mtime is changed and the uWSGI instance must be reloaded
if (ts > ui_current->last_mod) {
// make a new config (free the old one)
free(ui_current->config);
ui_current->config = config;
ui_current->config_len = strlen(config);
// always respawn (no need for amqp-style rules)
// make a new config (free the old one) if needed
if (config) {
if (ui_current->config)
free(ui_current->config);
ui_current->config = uwsgi_str(config);
ui_current->config_len = strlen(ui_current->config);
}
// reload the instance
emperor_respawn(ui_current, ts);
}
}
else {
// make a copy of the config as it will be freed
emperor_add(ues, name, ts, uwsgi_str(config), strlen((const char *) config), uid, gid);
char *new_config = NULL;
size_t new_config_len = 0;
if (config) {
new_config = uwsgi_str(config);
new_config_len = strlen(new_config);
}
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name);
}
}
+45
View File
@@ -0,0 +1,45 @@
#include <uwsgi.h>
// generate internal server error message
void uwsgi_500(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) return;
if (uwsgi_response_add_connection_close(wsgi_req)) return;
uwsgi_response_write_body_do(wsgi_req, "Internal Server Error", 21);
}
void uwsgi_404(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "404 Not Found", 13)) return;
if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/plain", 10)) return;
uwsgi_response_write_body_do(wsgi_req, "Not Found", 9);
}
void uwsgi_403(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "403 Forbidden", 13)) return;
if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return;
uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9);
}
void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
char *redirect = NULL;
size_t redirect_len = 0;
if (uwsgi_response_prepare_headers(wsgi_req, "301 Moved Permanently", 21)) return;
if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (wsgi_req->query_string_len == 0) {
redirect = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1);
redirect_len = wsgi_req->path_info_len + 1;
}
else {
redirect = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/?", 2, wsgi_req->query_string, wsgi_req->query_string_len);
redirect_len = wsgi_req->path_info_len + 2 + wsgi_req->query_string_len;
}
uwsgi_response_add_header(wsgi_req, "Location", 8, redirect, redirect_len);
free(redirect);
return;
}
+242 -2
View File
@@ -2,6 +2,233 @@
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_EVENT_USE_POLL
#define UWSGI_EVENT_IN POLLIN
#define UWSGI_EVENT_OUT POLLOUT
int uwsgi_poll_event_queue_max = 0;
struct uwsgi_poll_event {
int nevents;
int max_events;
pthread_mutex_t lock;
struct pollfd *poll;
};
struct uwsgi_poll_event **uwsgi_poll_event_queue;
// all of the public functions must be heavy locked
static int uwsgi_poll_fd_is_registered(struct uwsgi_poll_event *upe, int fd) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
return 1;
}
}
return 0;
}
static int uwsgi_poll_fd_add(struct uwsgi_poll_event *upe, int fd, int event) {
int pos = upe->nevents;
if (pos > upe->max_events) return -1;
upe->poll[pos].fd = fd;
upe->poll[pos].events = event;
upe->nevents++;
return 0;
}
static int uwsgi_poll_fd_del(struct uwsgi_poll_event *upe, int fd) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
if (i < upe->nevents-1) {
memcpy(&upe->poll[i], &upe->poll[i+1], sizeof(struct uwsgi_poll_event) * (upe->nevents - (i+1)));
}
upe->nevents--;
return 0;
}
}
return -1;
}
static void uwsgi_poll_queue_rebuild(struct uwsgi_poll_event *upe) {
// we need to check if some file descriptor is no more valid
int i;
for(i=0;i<upe->nevents;i++) {
if (!uwsgi_valid_fd(upe->poll[i].fd)) {
uwsgi_poll_fd_del(upe, upe->poll[i].fd);
}
}
}
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
uwsgi_poll_queue_rebuild(upe);
int ret = poll(upe->poll, upe->nevents, timeout * 1000);
if (ret > 0) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].revents) {
*interesting_fd = upe->poll[i].fd;
pthread_mutex_unlock(&upe->lock);
return 1;
}
}
}
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_init() {
if (!uwsgi_poll_event_queue) {
uwsgi_poll_event_queue = uwsgi_calloc(sizeof(struct uwsgi_poll_event *) * uwsgi.max_fd);
}
int eq = uwsgi_poll_event_queue_max;
uwsgi_poll_event_queue[eq] = uwsgi_calloc(sizeof(struct uwsgi_poll_event));
uwsgi_poll_event_queue_max++;
uwsgi_poll_event_queue[eq]->poll = uwsgi_malloc(sizeof(struct pollfd) * uwsgi.max_fd);
uwsgi_poll_event_queue[eq]->max_events = uwsgi.max_fd;
pthread_mutex_init(&uwsgi_poll_event_queue[eq]->lock, NULL);
return eq;
}
void *event_queue_alloc(int nevents) {
return uwsgi_calloc(sizeof(struct pollfd) * nevents);
}
int event_queue_interesting_fd_is_read(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
if (upoll->revents & POLLIN) {
return 1;
}
return 0;
}
int event_queue_fd_write_to_readwrite(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
upe->poll[i].events = POLLIN|POLLOUT;
pthread_mutex_unlock(&upe->lock);
return 0;
}
}
pthread_mutex_unlock(&upe->lock);
return -1;
}
int event_queue_fd_read_to_readwrite(int eq, int fd) {
return event_queue_fd_write_to_readwrite(eq, fd);
}
int event_queue_interesting_fd_is_write(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
if (upoll->revents & POLLOUT) {
return 1;
}
return 0;
}
int event_queue_add_fd_read(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
if (uwsgi_poll_fd_is_registered(upe, fd)) {
pthread_mutex_unlock(&upe->lock);
return 0;
}
int ret = uwsgi_poll_fd_add(upe, fd, POLLIN);
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_add_fd_write(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
if (uwsgi_poll_fd_is_registered(upe, fd)) {
pthread_mutex_unlock(&upe->lock);
return 0;
}
int ret = uwsgi_poll_fd_add(upe, fd, POLLOUT);
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_del_fd(int eq, int fd, int event) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int ret = uwsgi_poll_fd_del(upe, fd);
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
uwsgi_poll_queue_rebuild(upe);
int ret = poll(upe->poll, upe->nevents, timeout * 1000);
int cnt = 0;
if (ret > 0) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].revents) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[cnt];
upoll->fd = upe->poll[i].fd;
upoll->revents = upe->poll[i].revents;
upoll->events = upe->poll[i].events;
cnt++;
}
}
}
pthread_mutex_unlock(&upe->lock);
if (ret <= 0) return ret;
return cnt;
}
int event_queue_interesting_fd_has_error(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
if (upoll->revents & POLLERR || upoll->revents & POLLHUP || upoll->revents & POLLNVAL) {
return 1;
}
return 0;
}
int event_queue_interesting_fd(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
return upoll->fd;
}
int event_queue_fd_write_to_read(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
upe->poll[i].events = POLLIN;
pthread_mutex_unlock(&upe->lock);
return 0;
}
}
pthread_mutex_unlock(&upe->lock);
return -1;
}
int event_queue_fd_read_to_write(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
upe->poll[i].events = POLLOUT;
pthread_mutex_unlock(&upe->lock);
return 0;
}
}
pthread_mutex_unlock(&upe->lock);
return -1;
}
#endif
#ifdef UWSGI_EVENT_USE_PORT
#include <port.h>
@@ -108,7 +335,7 @@ int event_queue_interesting_fd_has_error(void *events, int id) {
int event_queue_interesting_fd_is_read(void *events, int id) {
port_event_t *pe = (port_event_t *) events;
if (pe[id].portev_events = POLLIN) {
if (pe[id].portev_events == POLLIN) {
return 1;
}
return 0;
@@ -124,7 +351,7 @@ int event_queue_interesting_fd_is_write(void *events, int id) {
int event_queue_add_fd_read(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *) eq)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
uwsgi_error("port_associate");
return -1;
}
@@ -171,6 +398,7 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
int ret;
uint_t nget = 1;
timespec_t ts;
if (timeout >= 0) {
ts.tv_sec = timeout;
@@ -189,6 +417,18 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
return 0;
}
uint_t i;
port_event_t *pe = (port_event_t *) events;
for(i=0;i<nget;i++) {
port_event_t *pe_i = &pe[i];
if (pe_i->portev_source == PORT_SOURCE_FD) {
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, NULL)) {
uwsgi_error("port_associate");
}
}
}
return nget;
}
+499
View File
@@ -0,0 +1,499 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
Exceptions management
generally exceptions are printed in the logs, but if you enable
an exception manager they will be stored in a (relatively big) uwsgi packet
with the following structure.
"vars" -> keyval of request vars
"backtrace" -> list of backtrace lines. Each line is a list of 5 elements filename,line,function,text,custom
"unix" -> seconds since the epoch
"class" -> the exception class
"msg" -> a text message mapped to the extension
"repr" -> a text message mapped to the extension in language-specific gergo
"wid" -> worker id
"core" -> the core generating the exception
"pid" -> pid of the worker
"node" -> hostname
Other vars can be added, but you cannot be sure they will be used by exceptions handler.
The exception-uwsgi packet is passed "as is" to the exception handler
Exceptions hooks:
a request plugin can export that hooks:
struct uwsgi_buffer *backtrace(struct wsgi_request *);
struct uwsgi_buffer *exception_class(struct wsgi_request *);
struct uwsgi_buffer *exception_msg(struct wsgi_request *);
struct uwsgi_buffer *exception_repr(struct wsgi_request *);
void exception_log(struct wsgi_request *);
Remember to reset the exception status (if possibile) after each call
Exceptions catcher:
This is a special development-mode in which exceptions are printed
to the HTTP client.
*/
struct uwsgi_buffer *uwsgi_exception_handler_object(struct wsgi_request *wsgi_req) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
if (uwsgi_buffer_append_keyval(ub, "vars", 4, wsgi_req->buffer,wsgi_req->uh->pktsize)) goto error;
if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) {
struct uwsgi_buffer *bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req);
if (bt) {
if (uwsgi_buffer_append_keyval(ub, "backtrace", 9, bt->buf, bt->pos)) {
uwsgi_buffer_destroy(bt);
goto error;
}
uwsgi_buffer_destroy(bt);
}
}
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
struct uwsgi_buffer *ec = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req);
if (ec) {
if (uwsgi_buffer_append_keyval(ub, "class", 5, ec->buf, ec->pos)) {
uwsgi_buffer_destroy(ec);
goto error;
}
uwsgi_buffer_destroy(ec);
}
}
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
struct uwsgi_buffer *em = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
if (em) {
if (uwsgi_buffer_append_keyval(ub, "msg", 3, em->buf, em->pos)) {
uwsgi_buffer_destroy(em);
goto error;
}
uwsgi_buffer_destroy(em);
}
}
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
struct uwsgi_buffer *er = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req);
if (er) {
if (uwsgi_buffer_append_keyval(ub, "repr", 4, er->buf, er->pos)) {
uwsgi_buffer_destroy(er);
goto error;
}
uwsgi_buffer_destroy(er);
}
}
if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now())) goto error;
if (uwsgi_buffer_append_keynum(ub, "wid", 3, uwsgi.mywid)) goto error;
if (uwsgi_buffer_append_keynum(ub, "pid", 3, uwsgi.mypid)) goto error;
if (uwsgi_buffer_append_keynum(ub, "core", 4, wsgi_req->async_id)) goto error;
if (uwsgi_buffer_append_keyval(ub, "node", 4, uwsgi.hostname, uwsgi.hostname_len)) goto error;
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
static void append_vars_to_ubuf(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data;
if (uwsgi_buffer_append(ub, key, keylen)) return;
if (uwsgi_buffer_append(ub, " = ", 3)) return;
if (uwsgi_buffer_append(ub, val, vallen)) return;
if (uwsgi_buffer_append(ub, "\n", 1)) return;
}
static void append_backtrace_to_ubuf(uint16_t pos, char *value, uint16_t len, void *data) {
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data;
uint16_t item = 0;
if (pos > 0) {
item = pos % 5;
}
switch(item) {
// filename
case 0:
if (uwsgi_buffer_append(ub, "filename: \"", 11)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
break;
// lineno
case 1:
if (uwsgi_buffer_append(ub, "line: ", 6)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, " ", 1)) return;
break;
// function
case 2:
if (uwsgi_buffer_append(ub, "function: \"", 11)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
break;
// text
case 3:
if (len > 0) {
if (uwsgi_buffer_append(ub, "text/code: \"", 12)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
}
break;
// custom
case 4:
if (len > 0) {
if (uwsgi_buffer_append(ub, "custom: \"", 9)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
}
if (uwsgi_buffer_append(ub, "\n", 1)) return;
break;
default:
break;
}
}
int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) {
return -1;
}
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) {
return -1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error;
if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error;
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error;
if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error;
if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error;
if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error;
if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error;
if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error;
if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error;
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req);
if (ub_exc_repr) {
if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) {
uwsgi_buffer_destroy(ub_exc_repr);
goto error;
}
uwsgi_buffer_destroy(ub_exc_repr);
}
else {
goto notavail3;
}
}
else {
notavail3:
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
}
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error;
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req);
if (ub_exc_class) {
if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) {
uwsgi_buffer_destroy(ub_exc_class);
goto error;
}
uwsgi_buffer_destroy(ub_exc_class);
}
else {
goto notavail;
}
}
else {
notavail:
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
}
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error;
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
if (ub_exc_msg) {
if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) {
uwsgi_buffer_destroy(ub_exc_msg);
goto error;
}
uwsgi_buffer_destroy(ub_exc_msg);
}
else {
goto notavail2;
}
}
else {
notavail2:
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
}
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error;
if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) {
struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req);
if (ub_exc_bt) {
struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096);
if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) {
uwsgi_buffer_destroy(ub_exc_bt);
uwsgi_buffer_destroy(parsed_bt);
goto error;
}
uwsgi_buffer_destroy(ub_exc_bt);
if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) {
uwsgi_buffer_destroy(parsed_bt);
goto error;
}
uwsgi_buffer_destroy(parsed_bt);
}
else {
goto notavail4;
}
}
else {
notavail4:
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
}
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) {
goto error;
}
if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) {
goto error;
}
uwsgi_buffer_destroy(ub);
return 0;
error:
uwsgi_buffer_destroy(ub);
return -1;
}
static void uwsgi_exception_run_handlers(struct uwsgi_buffer *ub) {
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
struct iovec iov[2];
iov[1].iov_base = ub->buf;
iov[1].iov_len = ub->pos;
while(usl) {
struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) usl->custom_ptr;
iov[0].iov_base = &uehi;
iov[0].iov_len = sizeof(long);
// now send the message to the exception handler thread
if (writev(uwsgi.exception_handler_thread->pipe[0], iov, 2) != (ssize_t) (ub->pos+sizeof(long))) {
uwsgi_error("[uwsgi-exception-handler-error] uwsgi_exception_run_handlers()/writev()");
}
usl = usl->next;
}
}
void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) {
int do_exit = uwsgi.reload_on_exception;
if (!wsgi_req) goto log2;
if (do_exit) goto check_catch;
if (wsgi_req && uwsgi.exception_handlers_instance) {
struct uwsgi_buffer *ehi = uwsgi_exception_handler_object(wsgi_req);
if (ehi) {
uwsgi_exception_run_handlers(ehi);
uwsgi_buffer_destroy(ehi);
}
}
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].exceptions++;
uwsgi_apps[wsgi_req->app_id].exceptions++;
if (uwsgi.reload_on_exception_type && uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
if (ub) {
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_type;
while (usl) {
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
do_exit = 1;
uwsgi_buffer_destroy(ub);
goto check_catch;
}
usl = usl->next;
}
uwsgi_buffer_destroy(ub);
}
}
if (uwsgi.reload_on_exception_value && uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
if (ub) {
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_value;
while (usl) {
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
do_exit = 1;
uwsgi_buffer_destroy(ub);
goto check_catch;
}
usl = usl->next;
}
uwsgi_buffer_destroy(ub);
}
}
if (uwsgi.reload_on_exception_repr && uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
if (ub) {
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_repr;
while (usl) {
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
do_exit = 1;
uwsgi_buffer_destroy(ub);
goto check_catch;
}
usl = usl->next;
}
uwsgi_buffer_destroy(ub);
}
}
check_catch:
if (catch && wsgi_req) {
if (uwsgi_exceptions_catch(wsgi_req)) {
// for now, just goto, new features could be added
goto log;
}
}
log:
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_log) {
uwsgi.p[wsgi_req->uh->modifier1]->exception_log(wsgi_req);
}
log2:
if (do_exit) {
exit(UWSGI_EXCEPTION_CODE);
}
}
struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *name, int (*func)(struct uwsgi_exception_handler_instance *, char *, size_t)) {
struct uwsgi_exception_handler *old_ueh = NULL, *ueh = uwsgi.exception_handlers;
while(ueh) {
if (!strcmp(name, ueh->name)) {
return NULL;
}
old_ueh = ueh;
ueh = ueh->next;
}
ueh = uwsgi_calloc(sizeof(struct uwsgi_exception_handler));
ueh->name = name;
ueh->func = func;
if (old_ueh) {
old_ueh->next = ueh;
}
else {
uwsgi.exception_handlers = ueh;
}
return ueh;
}
struct uwsgi_exception_handler *uwsgi_exception_handler_by_name(char *name) {
struct uwsgi_exception_handler *ueh = uwsgi.exception_handlers;
while(ueh) {
if (!strcmp(name, ueh->name)) {
return ueh;
}
ueh = ueh->next;
}
return NULL;
}
static void uwsgi_exception_handler_thread_loop(struct uwsgi_thread *ut) {
char *buf = uwsgi_malloc(uwsgi.exception_handler_msg_size + sizeof(long));
for (;;) {
int interesting_fd = -1;
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret > 0) {
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
if (len > (ssize_t)(sizeof(long) + 1)) {
size_t msg_size = len - sizeof(long);
char *msg = buf + sizeof(long);
long ptr = 0;
memcpy(&ptr, buf, sizeof(long));
struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) ptr;
if (!uehi)
break;
if (uehi->handler->func(uehi, msg, msg_size)) {
uwsgi_log("[uwsgi-exception] error running the handler \"%s\" args: \"%s\"\n", uehi->handler->name, uehi->arg ? uehi->arg : "");
}
}
}
}
free(buf);
}
void uwsgi_exception_setup_handlers() {
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
while(usl) {
char *handler = uwsgi_str(usl->value);
char *colon = strchr(handler, ':');
if (colon) {
*colon = 0;
}
struct uwsgi_exception_handler *ueh = uwsgi_exception_handler_by_name(handler);
if (!ueh) {
uwsgi_log("unable to find exception handler: %s\n", handler);
free(handler);
exit(1);
}
free(handler);
struct uwsgi_exception_handler_instance *uehi = uwsgi_calloc(sizeof(struct uwsgi_exception_handler_instance));
uehi->handler = ueh;
if (colon) {
uehi->arg = colon+1;
}
usl->custom_ptr = uehi;
usl = usl->next;
}
}
void uwsgi_exceptions_handler_thread_start() {
// start the exception_handler_thread
uwsgi.exception_handler_thread = uwsgi_thread_new(uwsgi_exception_handler_thread_loop);
if (!uwsgi.exception_handler_thread) {
uwsgi_log("unable to spawn exception handler thread\n");
exit(1);
}
}
+5
View File
@@ -41,6 +41,10 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
return ug;
}
static void gateway_brutal_end() {
_exit(UWSGI_END_CODE);
}
void gateway_respawn(int id) {
pid_t gw_pid;
@@ -65,6 +69,7 @@ void gateway_respawn(int id) {
}
#endif
uwsgi.mypid = getpid();
atexit(gateway_brutal_end);
signal(SIGALRM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, end_me);
+93
View File
@@ -0,0 +1,93 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
// Bernstein classic hash (this is not static as it is used by other areas)
uint32_t djb33x_hash(char *key, uint64_t keylen) {
register uint32_t hash = 5381;
uint64_t i;
for (i = 0; i < keylen; i++) {
hash = ((hash << 5) + hash) ^ key[i];
}
return hash;
}
// Murmur2 hash Copyright (C) Austin Appleby
// adapted from nginx
uint32_t murmur2_hash(char *key, uint64_t keylen) {
uint32_t h, k;
uint8_t *ukey = (uint8_t *) key;
h = 0 ^ keylen;
while (keylen >= 4) {
k = ukey[0];
k |= ukey[1] << 8;
k |= ukey[2] << 16;
k |= ukey[3] << 24;
k *= 0x5bd1e995;
k ^= k >> 24;
k *= 0x5bd1e995;
h *= 0x5bd1e995;
h ^= k;
ukey += 4;
keylen -= 4;
}
switch (keylen) {
case 3:
h ^= key[2] << 16;
case 2:
h ^= key[1] << 8;
case 1:
h ^= key[0];
h *= 0x5bd1e995;
}
h ^= h >> 13;
h *= 0x5bd1e995;
h ^= h >> 15;
return h;
}
struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) {
struct uwsgi_hash_algo *uha = uwsgi.hash_algos;
while(uha) {
if (!strcmp(name, uha->name)) {
return uha;
}
uha = uha->next;
}
return NULL;
}
void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) {
struct uwsgi_hash_algo *old_uha = NULL, *uha = uwsgi.hash_algos;
while(uha) {
if (!strcmp(uha->name, name)) return;
old_uha = uha;
uha = uha->next;
}
uha = uwsgi_calloc(sizeof(struct uwsgi_hash_algo));
uha->name = name;
uha->func = func;
if (old_uha) {
old_uha->next = uha;
}
else {
uwsgi.hash_algos = uha;
}
}
void uwsgi_hash_algo_register_all() {
uwsgi_hash_algo_register("djb33x", djb33x_hash);
uwsgi_hash_algo_register("murmur2", murmur2_hash);
}
+19 -10
View File
@@ -1,6 +1,4 @@
#ifdef UWSGI_INI
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -9,6 +7,8 @@ extern struct uwsgi_server uwsgi;
This memory must not be freed for all the server lifecycle
*/
static char *last_file = NULL;
void ini_rstrip(char *line) {
off_t i;
@@ -54,9 +54,9 @@ char *ini_get_key(char *key) {
return ptr;
}
char *ini_get_line(char *ini, off_t size) {
char *ini_get_line(char *ini, size_t size) {
off_t i;
size_t i;
char *ptr = ini;
for (i = 0; i < size; i++) {
@@ -78,7 +78,7 @@ char *ini_get_line(char *ini, off_t size) {
void uwsgi_ini_config(char *file, char *magic_table[]) {
int len = 0;
size_t len = 0;
char *ini;
char *ini_line;
@@ -92,6 +92,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
char *section_asked = "uwsgi";
char *colon;
if (uwsgi_check_scheme(file)) {
colon = uwsgi_get_last_char(file, '/');
colon = uwsgi_get_last_char(colon, ':');
@@ -105,13 +106,23 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
if (colon[1] != 0) {
section_asked = colon + 1;
}
if (colon == file) {
file = last_file;
}
}
if (file[0] != 0) {
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
if (file[0] != 0 && file != last_file) {
uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file);
}
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
if (file != last_file) {
if (last_file) {
free(last_file);
}
last_file = uwsgi_str(file);
}
while (len) {
ini_line = ini_get_line(ini, len);
@@ -156,5 +167,3 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
}
#endif
+168 -13
View File
@@ -2,6 +2,61 @@
extern struct uwsgi_server uwsgi;
struct http_status_codes {
const char key[3];
const char *message;
int message_size;
};
/* statistically ordered */
struct http_status_codes hsc[] = {
{"200", "OK"},
{"302", "Found"},
{"404", "Not Found"},
{"500", "Internal Server Error"},
{"301", "Moved Permanently"},
{"304", "Not Modified"},
{"303", "See Other"},
{"403", "Forbidden"},
{"307", "Temporary Redirect"},
{"401", "Unauthorized"},
{"400", "Bad Request"},
{"405", "Method Not Allowed"},
{"408", "Request Timeout"},
{"100", "Continue"},
{"101", "Switching Protocols"},
{"201", "Created"},
{"202", "Accepted"},
{"203", "Non-Authoritative Information"},
{"204", "No Content"},
{"205", "Reset Content"},
{"206", "Partial Content"},
{"300", "Multiple Choices"},
{"305", "Use Proxy"},
{"402", "Payment Required"},
{"406", "Not Acceptable"},
{"407", "Proxy Authentication Required"},
{"409", "Conflict"},
{"410", "Gone"},
{"411", "Length Required"},
{"412", "Precondition Failed"},
{"413", "Request Entity Too Large"},
{"414", "Request-URI Too Long"},
{"415", "Unsupported Media Type"},
{"416", "Requested Range Not Satisfiable"},
{"417", "Expectation Failed"},
{"501", "Not Implemented"},
{"502", "Bad Gateway"},
{"503", "Service Unavailable"},
{"504", "Gateway Timeout"},
{"505", "HTTP Version Not Supported"},
{"", NULL},
};
void uwsgi_init_default() {
uwsgi.cpus = 1;
@@ -13,7 +68,6 @@ void uwsgi_init_default() {
uwsgi.signal_socket = -1;
uwsgi.my_signal_socket = -1;
uwsgi.cache_server_fd = -1;
uwsgi.stats_fd = -1;
uwsgi.stats_pusher_default_freq = 3;
@@ -32,15 +86,18 @@ void uwsgi_init_default() {
uwsgi.subscribe_freq = 10;
uwsgi.subscription_tolerance = 17;
uwsgi.cluster_fd = -1;
uwsgi.cores = 1;
uwsgi.threads = 1;
// default max number of rpc slot
uwsgi.rpc_max = 64;
uwsgi.offload_threads_events = 64;
uwsgi.default_app = -1;
uwsgi.buffer_size = 4096;
uwsgi.body_read_warning = 8;
uwsgi.numproc = 1;
uwsgi.forkbomb_delay = 2;
@@ -52,18 +109,22 @@ void uwsgi_init_default() {
uwsgi.log_master_bufsize = 8192;
uwsgi.worker_reload_mercy = 60;
uwsgi.max_vars = MAX_VARS;
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
#ifdef UWSGI_SPOOLER
// a workers hould be running for at least 10 seconds
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] = 10;
uwsgi.shared->spooler_frequency = 30;
uwsgi.shared->spooler_signal_pipe[0] = -1;
uwsgi.shared->spooler_signal_pipe[1] = -1;
#endif
uwsgi.shared->mule_signal_pipe[0] = -1;
uwsgi.shared->mule_signal_pipe[1] = -1;
@@ -73,20 +134,37 @@ void uwsgi_init_default() {
uwsgi.shared->worker_log_pipe[0] = -1;
uwsgi.shared->worker_log_pipe[1] = -1;
uwsgi.shared->worker_req_log_pipe[0] = -1;
uwsgi.shared->worker_req_log_pipe[1] = -1;
uwsgi.req_log_fd = 2;
#ifdef UWSGI_SSL
// 1 day of tolerance
uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
uwsgi.ssl_sessions_timeout = 300;
#endif
#ifdef UWSGI_ALARM
uwsgi.alarm_freq = 3;
#endif
uwsgi.alarm_msg_size = 8192;
uwsgi.exception_handler_msg_size = 65536;
#ifdef UWSGI_MULTICAST
uwsgi.multicast_ttl = 1;
#endif
uwsgi.multicast_loop = 1;
// filling http status codes
struct http_status_codes *http_sc;
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
http_sc->message_size = strlen(http_sc->message);
}
uwsgi.empty = "";
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
uwsgi_websockets_init();
}
void uwsgi_setup_reload() {
@@ -218,7 +296,7 @@ void uwsgi_commandline_config() {
void uwsgi_setup_workers() {
int i, j;
// allocate shared memory for workers + master
uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1 + uwsgi.grunt));
uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1));
for (i = 0; i <= uwsgi.numproc; i++) {
// allocate memory for apps
@@ -229,7 +307,8 @@ void uwsgi_setup_workers() {
// this is a trick for avoiding too much memory areas
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
void *buffers = uwsgi_malloc_shared(uwsgi.buffer_size * uwsgi.cores);
// add 4 bytes for uwsgi header
void *buffers = uwsgi_malloc_shared((uwsgi.buffer_size+4) * uwsgi.cores);
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
void *post_buf = NULL;
if (uwsgi.post_buffering > 0)
@@ -239,8 +318,8 @@ void uwsgi_setup_workers() {
for (j = 0; j < uwsgi.cores; j++) {
// allocate shared memory for thread states (required for some language, like python)
uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j);
// raw per-request buffer
uwsgi.workers[i].cores[j].buffer = buffers + (uwsgi.buffer_size * j);
// raw per-request buffer (+4 bytes for uwsgi header)
uwsgi.workers[i].cores[j].buffer = buffers + ((uwsgi.buffer_size+4) * j);
// iovec for uwsgi vars
uwsgi.workers[i].cores[j].hvec = hvec + ((sizeof(struct iovec) * uwsgi.vec_size) * j);
if (post_buf)
@@ -262,7 +341,11 @@ void uwsgi_setup_workers() {
}
total_memory *= (uwsgi.numproc + uwsgi.master_process);
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", total_memory, total_memory / 1024, uwsgi.cores * uwsgi.numproc);
if (uwsgi.numproc > 0)
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", (unsigned long long) total_memory, (unsigned long long) (total_memory / 1024), uwsgi.cores * uwsgi.numproc);
// allocate signal table
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
}
@@ -293,3 +376,75 @@ pid_t uwsgi_daemonize2() {
return uwsgi.mypid;
}
// fix/check related options
void sanitize_args() {
if (uwsgi.async > 1) {
uwsgi.cores = uwsgi.async;
}
if (uwsgi.threads > 1) {
uwsgi.has_threads = 1;
uwsgi.cores = uwsgi.threads;
}
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
if (!uwsgi.post_buffering) {
uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
}
}
if (uwsgi.write_errors_exception_only) {
uwsgi.ignore_sigpipe = 1;
uwsgi.ignore_write_errors = 1;
}
if (uwsgi.cheaper_count == 0) uwsgi.cheaper = 0;
if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) {
uwsgi_log("invalid cheaper value: must be lower than processes\n");
exit(1);
}
if (uwsgi.cheaper && uwsgi.cheaper_count) {
if (uwsgi.cheaper_initial) {
if (uwsgi.cheaper_initial < uwsgi.cheaper_count) {
uwsgi_log("warning: invalid cheaper-initial value (%d), must be equal or higher than cheaper (%d), using %d as initial number of workers\n",
uwsgi.cheaper_initial, uwsgi.cheaper_count, uwsgi.cheaper_count);
uwsgi.cheaper_initial = uwsgi.cheaper_count;
}
else if (uwsgi.cheaper_initial > uwsgi.numproc) {
uwsgi_log("warning: invalid cheaper-initial value (%d), must be lower or equal than worker count (%d), using %d as initial number of workers\n",
uwsgi.cheaper_initial, uwsgi.numproc, uwsgi.numproc);
uwsgi.cheaper_initial = uwsgi.numproc;
}
}
else {
uwsgi.cheaper_initial = uwsgi.cheaper_count;
}
}
if (uwsgi.auto_snapshot > 0 && uwsgi.auto_snapshot > uwsgi.numproc) {
uwsgi_log("invalid auto-snapshot value: must be <= than processes\n");
exit(1);
}
if (uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0 && uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] >= uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]) {
uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME], uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]);
exit(1);
}
}
const char *uwsgi_http_status_msg(char *status, uint16_t *len) {
struct http_status_codes *http_sc;
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
if (!strncmp(http_sc->key, status, 3)) {
*len = http_sc->message_size;
return http_sc->message;
}
}
return NULL;
}
+1008
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -13,7 +13,7 @@ extern struct uwsgi_server uwsgi;
void uwsgi_json_config(char *file, char *magic_table[]) {
int len = 0;
size_t len = 0;
char *json_data;
@@ -45,7 +45,7 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
}
}
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
+1076
View File
File diff suppressed because it is too large Load Diff
+98 -3
View File
@@ -45,6 +45,10 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
#ifdef UWSGI_LOCK_USE_MUTEX
#ifdef OBSOLETE_LINUX_KERNEL
#undef EOWNERDEAD
#endif
#ifdef EOWNERDEAD
#define UWSGI_LOCK_ENGINE_NAME "pthread robust mutexes"
int uwsgi_pthread_robust_mutexes_enabled = 1;
@@ -60,6 +64,12 @@ int uwsgi_pthread_robust_mutexes_enabled = 1;
#define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlock_t)
#endif
#ifndef PTHREAD_PRIO_INHERIT
int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr,
int __protocol);
#define PTHREAD_PRIO_INHERIT 1
#endif
// REMEMBER lock must contains space for both pthread_mutex_t and pthread_mutexattr_t !!!
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
@@ -81,8 +91,15 @@ retry:
}
#ifdef EOWNERDEAD
#ifndef PTHREAD_MUTEX_ROBUST
#define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
#endif
if (pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) {
uwsgi_log("unable to set PTHREAD_PRIO_INHERIT\n");
exit(1);
}
if (uwsgi_pthread_robust_mutexes_enabled) {
if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST_NP)) {
if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST)) {
uwsgi_log("unable to make the mutex 'robust'\n");
exit(1);
}
@@ -384,6 +401,60 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_unlock_fast(uli);
}
#elif defined(UWSGI_LOCK_USE_WINDOWS_MUTEX)
#define UWSGI_LOCK_ENGINE_NAME "windows mutexes"
#define UWSGI_LOCK_SIZE sizeof(HANDLE)
#define UWSGI_RWLOCK_SIZE sizeof(HANDLE)
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
struct _SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(struct _SECURITY_ATTRIBUTES));
sa.bInheritHandle = 1;
uli->lock_ptr = CreateMutex(&sa, FALSE, NULL);
return uli;
}
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
WaitForSingleObject(uli->lock_ptr, INFINITE);
uli->pid = uwsgi.mypid;
}
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
ReleaseMutex(uli->lock_ptr);
uli->pid = 0;
}
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
if (WaitForSingleObject(uli->lock_ptr, 0) == WAIT_TIMEOUT) {
return 0;
}
return uli->pid;
}
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
return uwsgi_lock_fast_init(id);
}
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_lock_fast(uli);
}
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_lock_fast(uli);
}
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
return uwsgi_lock_fast_check(uli);
}
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_unlock_fast(uli);
}
#else
#define uwsgi_lock_fast_init uwsgi_lock_ipcsem_init
@@ -460,7 +531,9 @@ void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
memcpy(&semid, uli->lock_ptr, sizeof(int));
retry:
if (semop(semid, &sb, 1)) {
if (errno == EINTR) goto retry;
uwsgi_error("semop()");
}
}
@@ -475,7 +548,9 @@ void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
memcpy(&semid, uli->lock_ptr, sizeof(int));
retry:
if (semop(semid, &sb, 1)) {
if (errno == EINTR) goto retry;
uwsgi_error("semop()");
}
@@ -540,6 +615,10 @@ pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) {
void uwsgi_setup_locking() {
int i;
if (uwsgi.locking_setup) return;
// use the fastest available locking
if (uwsgi.lock_engine) {
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
@@ -556,8 +635,10 @@ void uwsgi_setup_locking() {
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem;
uwsgi.lock_size = 8;
uwsgi.rwlock_size = 8;
return;
goto ready;
}
uwsgi_log("unable to find lock engine \"%s\"\n", uwsgi.lock_engine);
exit(1);
}
uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
@@ -576,8 +657,8 @@ void uwsgi_setup_locking() {
uwsgi.lock_size = UWSGI_LOCK_SIZE;
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
ready:
// application generic lock
int i;
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)));
@@ -608,8 +689,22 @@ void uwsgi_setup_locking() {
uwsgi.cron_table_lock = uwsgi_lock_init("cron");
}
if (uwsgi.use_thunder_lock) {
// process shared thunder lock
uwsgi.the_thunder_lock = uwsgi_lock_init("thunder");
}
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
#ifdef UWSGI_SSL
// register locking for legions
struct uwsgi_legion *ul = uwsgi.legions;
while(ul) {
ul->lock = uwsgi_lock_init(uwsgi_concat2("legion_", ul->legion));
ul = ul->next;
}
#endif
uwsgi.locking_setup = 1;
}
+530 -91
View File
@@ -1,9 +1,9 @@
#define _NO_UWSGI_RB
#include "uwsgi.h"
#ifndef __DragonFly__
#include <uwsgi.h>
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#include <kvm.h>
#include <sys/user.h>
#include <kvm.h>
#elif defined(__sun__)
/* Terrible Hack !!! */
#ifndef _LP64
@@ -17,6 +17,10 @@
#include <sys/sysctl.h>
#endif
#ifdef __DragonFly__
#include <uwsgi.h>
#endif
extern struct uwsgi_server uwsgi;
//use this instead of fprintf to avoid buffering mess with udp logging
@@ -144,6 +148,21 @@ void create_logpipe(void) {
exit(1);
}
if (uwsgi.req_log_master) {
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_req_log_pipe)) {
#else
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_req_log_pipe)) {
#endif
uwsgi_error("socketpair()\n");
exit(1);
}
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[0]);
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[1]);
uwsgi.req_log_fd = uwsgi.shared->worker_req_log_pipe[1];
}
}
#ifdef UWSGI_ZEROMQ
@@ -194,7 +213,6 @@ void logto(char *logfile) {
int fd;
#ifdef UWSGI_UDP
char *udp_port;
struct sockaddr_in udp_addr;
@@ -230,7 +248,6 @@ void logto(char *logfile) {
}
}
else {
#endif
if (uwsgi.log_truncate) {
fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
}
@@ -248,9 +265,7 @@ void logto(char *logfile) {
uwsgi_error("chmod()");
}
}
#ifdef UWSGI_UDP
}
#endif
/* stdout */
@@ -294,62 +309,71 @@ void uwsgi_setup_log() {
}
static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl) {
char *id = NULL;
char *name = usl->value;
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space - name, "", 0);
name = space + 1;
}
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
// make a copy of the logger
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
if (colon) {
choosen_logger->arg = colon + 1;
// check for empty string
if (*choosen_logger->arg == 0) {
choosen_logger->arg = NULL;
}
*colon = ':';
}
return choosen_logger;
}
void uwsgi_setup_log_master(void) {
struct uwsgi_string_list *usl = uwsgi.requested_logger;
while (usl) {
char *id = NULL;
char *name = usl->value;
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum(name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space - name, "", 0);
name = space + 1;
}
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
// make a copy of the logger
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
if (colon) {
choosen_logger->arg = colon + 1;
// check for empty string
if (*choosen_logger->arg == 0) {
choosen_logger->arg = NULL;
}
*colon = ':';
}
struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl);
uwsgi_append_logger(choosen_logger);
usl = usl->next;
}
usl = uwsgi.requested_req_logger;
while (usl) {
struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl);
uwsgi_append_req_logger(choosen_logger);
usl = usl->next;
}
#ifdef UWSGI_PCRE
// set logger by its id
struct uwsgi_regexp_list *url = uwsgi.log_route;
@@ -357,6 +381,11 @@ void uwsgi_setup_log_master(void) {
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
url = url->next;
}
url = uwsgi.log_req_route;
while (url) {
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
url = url->next;
}
#endif
uwsgi.original_log_fd = dup(1);
@@ -458,13 +487,13 @@ void uwsgi_check_logrotate(void) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
if (dup2(fd, uwsgi.original_log_fd) < 0) {
uwsgi_error("dup2()");
grace_them_all(0);
else {
if (dup2(fd, uwsgi.original_log_fd) < 0) {
uwsgi_error("dup2()");
grace_them_all(0);
}
close(fd);
}
close(fd);
}
else {
uwsgi_error("unable to rotate log: rename()");
@@ -527,7 +556,7 @@ void log_request(struct wsgi_request *wsgi_req) {
if (uwsgi.shared->options[UWSGI_OPTION_LOG_BIG] && (wsgi_req->response_size >= uwsgi.shared->options[UWSGI_OPTION_LOG_BIG])) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result)) {
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && wsgi_req->via == UWSGI_VIA_SENDFILE) {
goto logit;
}
@@ -572,16 +601,19 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
}
}
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
via = msg1;
}
// mark route() requests
if (wsgi_req->status == -17) {
via = msg3;
}
else if (wsgi_req->status == -30) {
via = msg4;
// mark requests via (sendfile, route, offload...)
switch(wsgi_req->via) {
case UWSGI_VIA_SENDFILE:
via = msg1;
break;
case UWSGI_VIA_ROUTE:
via = msg3;
break;
case UWSGI_VIA_OFFLOAD:
via = msg4;
break;
default:
break;
}
#ifdef __sun__
@@ -610,23 +642,21 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1) {
#ifndef UNBIT
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
#else
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
#endif
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024,
(unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
logvec[logvecpos].iov_base = mempkt;
logvec[logvecpos].iov_len = rlen;
logvecpos++;
}
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %llu %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, wsgi_req->remote_user, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %llu %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, wsgi_req->remote_user, wsgi_req->var_cnt, wsgi_req->uh->pktsize,
24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
// not enough space for logging the request, just log a (safe) minimal message
if (rlen > 4096) {
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %s%s(- %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %s%s(- %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->var_cnt, wsgi_req->uh->pktsize,
24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
// argh, last resort, truncate it
if (rlen > 4096) {
rlen = 4096;
@@ -637,13 +667,17 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
logvec[logvecpos].iov_len = rlen;
// do not check for errors
rlen = writev(2, logvec, logvecpos + 1);
rlen = writev(uwsgi.req_log_fd, logvec, logvecpos + 1);
}
void get_memusage(uint64_t * rss, uint64_t * vsz) {
#ifdef UNBIT
*vsz = syscall(356);
uint64_t ret[2];
ret[0] = 0; ret[1] = 0;
syscall(358, ret);
*vsz = ret[0];
*rss = ret[1] * uwsgi.page_size;
#elif defined(__linux__)
FILE *procfile;
int i;
@@ -656,6 +690,18 @@ void get_memusage(uint64_t * rss, uint64_t * vsz) {
fclose(procfile);
}
*rss = *rss * uwsgi.page_size;
#elif defined(__CYGWIN__)
// same as Linux but rss is not in pages...
FILE *procfile;
int i;
procfile = fopen("/proc/self/stat", "r");
if (procfile) {
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) vsz, (unsigned long long *) rss);
if (i != 2) {
uwsgi_log("warning: invalid record in /proc/self/stat\n");
}
fclose(procfile);
}
#elif defined (__sun__)
psinfo_t info;
int procfd;
@@ -695,8 +741,13 @@ void get_memusage(uint64_t * rss, uint64_t * vsz) {
struct kinfo_proc *kproc;
kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, &cnt);
if (kproc && cnt > 0) {
#if defined(__FreeBSD__)
*vsz = kproc->ki_size;
*rss = kproc->ki_rssize * uwsgi.page_size;
#elif defined(__DragonFly__)
*vsz = kproc->kp_vm_map_size;
*rss = kproc->kp_vm_rssize * uwsgi.page_size;
#endif
}
#elif defined(UWSGI_NEW_OPENBSD)
struct kinfo_proc *kproc;
@@ -761,6 +812,7 @@ void uwsgi_register_logger(char *name, ssize_t(*func) (struct uwsgi_logger *, ch
ul->configured = 0;
ul->fd = -1;
ul->data = NULL;
ul->buf = NULL;
#ifdef UWSGI_DEBUG
@@ -785,6 +837,24 @@ void uwsgi_append_logger(struct uwsgi_logger *ul) {
}
}
void uwsgi_append_req_logger(struct uwsgi_logger *ul) {
if (!uwsgi.choosen_req_logger) {
uwsgi.choosen_req_logger = ul;
return;
}
struct uwsgi_logger *ucl = uwsgi.choosen_req_logger;
while (ucl) {
if (!ucl->next) {
ucl->next = ul;
return;
}
ucl = ucl->next;
}
}
struct uwsgi_logger *uwsgi_get_logger(char *name) {
struct uwsgi_logger *ul = uwsgi.loggers;
@@ -815,6 +885,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
struct uwsgi_logchunk *logchunk = uwsgi.logchunks;
ssize_t rlen = 0;
const char *empty_var = "-";
while (logchunk) {
int pos = logchunk->vec;
// raw string
@@ -851,18 +922,25 @@ void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 0;
}
}
if (uwsgi.logvectors[wsgi_req->async_id][pos].iov_len == 0 && logchunk->type != 0) {
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = (char *) empty_var;
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 1;
}
logchunk = logchunk->next;
}
// do not check for errors
rlen = writev(2, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors);
rlen = writev(uwsgi.req_log_fd, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors);
// free allocated memory
logchunk = uwsgi.logchunks;
while (logchunk) {
if (logchunk->free) {
if (uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_len > 0) {
free(uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base);
if (uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base != empty_var) {
free(uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base);
}
}
}
logchunk = logchunk->next;
@@ -923,17 +1001,39 @@ void uwsgi_build_log_format(char *format) {
}
ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) {
static ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->status);
return strlen(*buf);
}
ssize_t uwsgi_lf_epoch(struct wsgi_request * wsgi_req, char **buf) {
static ssize_t uwsgi_lf_rsize(struct wsgi_request *wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->response_size);
return strlen(*buf);
}
static ssize_t uwsgi_lf_hsize(struct wsgi_request *wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->headers_size);
return strlen(*buf);
}
static ssize_t uwsgi_lf_size(struct wsgi_request *wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->headers_size+wsgi_req->response_size);
return strlen(*buf);
}
static ssize_t uwsgi_lf_cl(struct wsgi_request *wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->post_cl);
return strlen(*buf);
}
static ssize_t uwsgi_lf_epoch(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi_now());
return strlen(*buf);
}
ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
static ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_malloc(26);
#ifdef __sun__
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, *buf, 26);
@@ -943,23 +1043,98 @@ ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
return 24;
}
ssize_t uwsgi_lf_time(struct wsgi_request * wsgi_req, char **buf) {
static ssize_t uwsgi_lf_time(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->start_of_request / 1000000);
return strlen(*buf);
}
static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_malloc(64);
time_t now = wsgi_req->start_of_request / 1000000;
size_t ret = strftime(*buf, 64, "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
if (ret == 0) {
*buf[0] = 0;
return 0;
}
return ret;
}
ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) {
static ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
return strlen(*buf);
}
ssize_t uwsgi_lf_msecs(struct wsgi_request * wsgi_req, char **buf) {
static ssize_t uwsgi_lf_msecs(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str((wsgi_req->end_of_request - wsgi_req->start_of_request) / 1000);
return strlen(*buf);
}
static ssize_t uwsgi_lf_pid(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi.mypid);
return strlen(*buf);
}
static ssize_t uwsgi_lf_wid(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi.mywid);
return strlen(*buf);
}
static ssize_t uwsgi_lf_switches(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->switches);
return strlen(*buf);
}
static ssize_t uwsgi_lf_vars(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->var_cnt);
return strlen(*buf);
}
static ssize_t uwsgi_lf_core(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->async_id);
return strlen(*buf);
}
static ssize_t uwsgi_lf_vsz(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].vsz_size);
return strlen(*buf);
}
static ssize_t uwsgi_lf_rss(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].rss_size);
return strlen(*buf);
}
static ssize_t uwsgi_lf_vszM(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
return strlen(*buf);
}
static ssize_t uwsgi_lf_rssM(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
return strlen(*buf);
}
static ssize_t uwsgi_lf_pktsize(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->uh->pktsize);
return strlen(*buf);
}
static ssize_t uwsgi_lf_modifier1(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->uh->modifier1);
return strlen(*buf);
}
static ssize_t uwsgi_lf_modifier2(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->uh->modifier2);
return strlen(*buf);
}
static ssize_t uwsgi_lf_headers(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->header_cnt);
return strlen(*buf);
}
void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
@@ -1018,11 +1193,39 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
logchunk->pos = offsetof(struct wsgi_request, protocol);
logchunk->pos_len = offsetof(struct wsgi_request, protocol_len);
}
else if (!uwsgi_strncmp(ptr, len, "uagent", 6)) {
logchunk->pos = offsetof(struct wsgi_request, user_agent);
logchunk->pos_len = offsetof(struct wsgi_request, user_agent_len);
}
else if (!uwsgi_strncmp(ptr, len, "referer", 7)) {
logchunk->pos = offsetof(struct wsgi_request, referer);
logchunk->pos_len = offsetof(struct wsgi_request, referer_len);
}
else if (!uwsgi_strncmp(ptr, len, "status", 6)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_status;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "rsize", 5)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_rsize;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "hsize", 5)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_hsize;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "size", 4)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_size;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "cl", 2)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_cl;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "micros", 6)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_micros;
@@ -1038,6 +1241,11 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
logchunk->func = uwsgi_lf_time;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "ltime", 5)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_ltime;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "ctime", 5)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_ctime;
@@ -1048,9 +1256,240 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
logchunk->func = uwsgi_lf_epoch;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "pid", 3)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_pid;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "wid", 3)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_wid;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "switches", 8)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_switches;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "vars", 4)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_vars;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "core", 4)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_core;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "vsz", 3)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_vsz;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "rss", 3)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_rss;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "vszM", 4)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_vszM;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "rssM", 4)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_rssM;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "pktsize", 7)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_pktsize;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "modifier1", 9)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_modifier1;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "modifier2", 9)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_modifier2;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "headers", 7)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_headers;
logchunk->free = 1;
}
// logvar
else {
logchunk->type = 2;
}
}
}
int uwsgi_master_log(void) {
ssize_t rlen = read(uwsgi.shared->worker_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
if (rlen > 0) {
#ifdef UWSGI_PCRE
uwsgi_alarm_log_check(uwsgi.log_master_buf, rlen);
struct uwsgi_regexp_list *url = uwsgi.log_drain_rules;
while (url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
return 0;
}
url = url->next;
}
if (uwsgi.log_filter_rules) {
int show = 0;
url = uwsgi.log_filter_rules;
while (url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
show = 1;
break;
}
url = url->next;
}
if (!show)
return 0;
}
url = uwsgi.log_route;
int finish = 0;
while (url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
if (ul_route) {
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
finish = 1;
}
}
url = url->next;
}
if (finish)
return 0;
#endif
int raw_log = 1;
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while (ul) {
// check for named logger
if (ul->id) {
goto next;
}
ul->func(ul, uwsgi.log_master_buf, rlen);
raw_log = 0;
next:
ul = ul->next;
}
if (raw_log) {
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
}
return 0;
}
return -1;
}
int uwsgi_master_req_log(void) {
ssize_t rlen = read(uwsgi.shared->worker_req_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
if (rlen > 0) {
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list *url = uwsgi.log_req_route;
int finish = 0;
while (url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
if (ul_route) {
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
finish = 1;
}
}
url = url->next;
}
if (finish)
return 0;
#endif
int raw_log = 1;
struct uwsgi_logger *ul = uwsgi.choosen_req_logger;
while (ul) {
// check for named logger
if (ul->id) {
goto next;
}
ul->func(ul, uwsgi.log_master_buf, rlen);
raw_log = 0;
next:
ul = ul->next;
}
if (raw_log) {
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
}
return 0;
}
return -1;
}
static void *logger_thread_loop(void *noarg) {
struct pollfd logpoll[2];
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
logpoll[0].events = POLLIN;
logpoll[0].fd = uwsgi.shared->worker_log_pipe[0];
int logpolls = 1;
if (uwsgi.req_log_master) {
logpoll[1].events = POLLIN;
logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0];
}
for (;;) {
int ret = poll(logpoll, logpolls, -1);
if (ret > 0) {
if (logpoll[0].revents & POLLIN) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
uwsgi_master_log();
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
}
else if (logpolls > 1 && logpoll[1].revents & POLLIN) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
uwsgi_master_req_log();
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
}
}
}
return NULL;
}
void uwsgi_threaded_logger_spawn() {
pthread_t logger_thread;
if (pthread_create(&logger_thread, NULL, logger_thread_loop, NULL)) {
uwsgi_error("pthread_create()");
uwsgi_log("falling back to non-threaded logger...\n");
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]);
if (uwsgi.req_log_master) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]);
}
uwsgi.threaded_logger = 0;
}
}
+1 -6
View File
@@ -64,12 +64,10 @@ void simple_loop() {
void uwsgi_loop_cores_run(void *(*func) (void *)) {
int i;
#ifdef UWSGI_THREADING
for (i = 1; i < uwsgi.threads; i++) {
long j = i;
pthread_create(&uwsgi.workers[uwsgi.mywid].cores[i].thread_id, &uwsgi.threads_attr, func, (void *) j);
}
#endif
long y = 0;
func((void *) y);
}
@@ -120,12 +118,9 @@ void *simple_loop_run(void *arg1) {
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) {
uwsgi_setup_thread_req(core_id, wsgi_req);
}
#endif
// initialize the main event queue to monitor sockets
int main_queue = event_queue_init();
@@ -146,7 +141,7 @@ void *simple_loop_run(void *arg1) {
continue;
}
if (wsgi_req_recv(wsgi_req)) {
if (wsgi_req_recv(main_queue, wsgi_req)) {
uwsgi_destroy_request(wsgi_req);
continue;
}
+166 -876
View File
File diff suppressed because it is too large Load Diff
+278
View File
@@ -0,0 +1,278 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
// check if all of the workers are dead and exit uWSGI
void uwsgi_master_check_death() {
if (uwsgi_instance_is_dying) {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0) {
return;
}
}
uwsgi_log("goodbye to uWSGI.\n");
exit(0);
}
}
// check if all of the workers are dead, and trigger a reload
int uwsgi_master_check_reload(char **argv) {
if (uwsgi_instance_is_reloading) {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0) {
return 0;
}
}
uwsgi_reload(argv);
// never here (unless in shared library mode)
return -1;
}
return 0;
}
// check for chain reload
void uwsgi_master_check_chain() {
if (!uwsgi.status.chain_reloading) return;
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
uwsgi.status.chain_reloading = 0;
uwsgi_log_verbose("chain reloading complete\n");
}
int i;
uwsgi_block_signal(SIGHUP);
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
uwsgi_curse(i, SIGHUP);
break;
}
}
uwsgi_unblock_signal(SIGHUP);
}
// special function for assuming all of the workers are dead
void uwsgi_master_commit_status() {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
uwsgi.workers[i].pid = 0;
}
}
void uwsgi_master_check_idle() {
static time_t last_request_timecheck = 0;
static uint64_t last_request_count = 0;
int i;
int waitpid_status;
if (!uwsgi.idle || uwsgi.status.is_cheap)
return;
uwsgi.current_time = uwsgi_now();
if (!last_request_timecheck)
last_request_timecheck = uwsgi.current_time;
// security check, stop the check if there are busy workers
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
if (uwsgi_worker_is_busy(i)) {
return;
}
}
}
if (last_request_count != uwsgi.workers[0].requests) {
last_request_timecheck = uwsgi.current_time;
last_request_count = uwsgi.workers[0].requests;
}
// a bit of over-engeneering to avoid clock skews
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) {
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
uwsgi.status.is_cheap = 1;
if (uwsgi.die_on_idle) {
if (uwsgi.has_emperor) {
char byte = 22;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
kill_them_all(0);
}
}
else {
kill_them_all(0);
}
return;
}
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi.workers[i].cheaped = 1;
if (uwsgi.workers[i].pid == 0)
continue;
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
if (errno != ECHILD)
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
}
}
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
last_request_timecheck = 0;
}
}
void uwsgi_master_check_workers_deadline() {
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
/* first check for harakiri */
if (uwsgi.workers[i].harakiri > 0) {
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
}
}
/* then user-defined harakiri */
if (uwsgi.workers[i].user_harakiri > 0) {
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
}
}
// then for evil memory checkers
if (uwsgi.evil_reload_on_as) {
if ((rlim_t) uwsgi.workers[i].vsz_size >= uwsgi.evil_reload_on_as) {
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].vsz_size = 0;
}
}
if (uwsgi.evil_reload_on_rss) {
if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) {
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].rss_size = 0;
}
}
// check if worker was running longer than allowed lifetime
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
uwsgi.workers[i].manage_next_request = 0;
kill(uwsgi.workers[i].pid, SIGWINCH);
}
}
// need to find a better way
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
}
}
void uwsgi_master_check_gateways_deadline() {
int i;
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways_harakiri[i] > 0) {
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
if (ushared->gateways[i].pid > 0) {
kill(ushared->gateways[i].pid, SIGKILL);
}
ushared->gateways_harakiri[i] = 0;
}
}
}
}
void uwsgi_master_check_mules_deadline() {
int i;
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].harakiri > 0) {
if (uwsgi.mules[i].harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid);
kill(uwsgi.mules[i].pid, SIGKILL);
uwsgi.mules[i].harakiri = 0;
}
}
}
}
void uwsgi_master_check_spoolers_deadline() {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
kill(uspool->pid, SIGKILL);
uspool->harakiri = 0;
}
uspool = uspool->next;
}
}
int uwsgi_master_check_spoolers_death(int diedpid) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->pid > 0 && diedpid == uspool->pid) {
uwsgi_log("OOOPS the spooler is no more...trying respawn...\n");
uspool->respawned++;
uspool->pid = spooler_start(uspool);
return -1;
}
uspool = uspool->next;
}
return 0;
}
int uwsgi_master_check_emperor_death(int diedpid) {
if (uwsgi.emperor_pid >= 0 && diedpid == uwsgi.emperor_pid) {
uwsgi_log_verbose("!!! Emperor died !!!\n");
uwsgi_emperor_start();
return -1;
}
return 0;
}
int uwsgi_master_check_mules_death(int diedpid) {
int i;
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid == diedpid) {
uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid);
uwsgi_mule(i + 1);
return -1;
}
}
return 0;
}
int uwsgi_master_check_gateways_death(int diedpid) {
int i;
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid == diedpid) {
gateway_respawn(i);
return -1;
}
}
return 0;
}
int uwsgi_master_check_daemons_death(int diedpid) {
/* reload the daemons */
if (uwsgi_daemon_check_pid_reload(diedpid)) {
return -1;
}
return 0;
}
int uwsgi_worker_is_busy(int wid) {
int i;
for(i=0;i<uwsgi.cores;i++) {
if (uwsgi.workers[wid].cores[i].in_request) {
return 1;
}
}
return 0;
}
+174
View File
@@ -0,0 +1,174 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int uwsgi_master_manage_events(int interesting_fd) {
// is a logline ?
if (uwsgi.log_master && !uwsgi.threaded_logger) {
// stderr log ?
if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) {
uwsgi_master_log();
return 0;
}
// req log ?
if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) {
uwsgi_master_req_log();
return 0;
}
}
// stats server ?
if (uwsgi.stats && uwsgi.stats_fd > -1) {
if (interesting_fd == uwsgi.stats_fd) {
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
return 0;
}
}
// a zerg connection ?
if (uwsgi.zerg_server) {
if (interesting_fd == uwsgi.zerg_server_fd) {
uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL);
return 0;
}
}
// emperor event ?
if (uwsgi.has_emperor) {
if (interesting_fd == uwsgi.emperor_fd) {
uwsgi_master_manage_emperor();
return 0;
}
}
// wakeup from cheap mode ?
if (uwsgi.status.is_cheap) {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
uwsgi.status.is_cheap = 0;
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
// how many worker we need to respawn ?
int needed = uwsgi.numproc;
// if in cheaper mode, just respawn the minimal amount
if (uwsgi.cheaper) {
needed = uwsgi.cheaper_count;
}
int i;
for (i = 1; i <= needed; i++) {
if (uwsgi_respawn_worker(i))
return -1;
}
// here we continue instead of returning
break;
}
uwsgi_sock = uwsgi_sock->next;
}
}
// an SNMP request ?
if (uwsgi.snmp_addr && interesting_fd == uwsgi.snmp_fd) {
uwsgi_master_manage_snmp(uwsgi.snmp_fd);
return 0;
}
// a UDP request ?
if (uwsgi.udp_socket && interesting_fd == uwsgi.udp_fd) {
uwsgi_master_manage_udp(uwsgi.udp_fd);
return 0;
}
// check if some file monitor is ready
// no need to lock as we are only getting registered items (and only the master can register them)
int i;
for (i = 0; i < ushared->files_monitored_cnt; i++) {
if (ushared->files_monitored[i].registered) {
if (interesting_fd == ushared->files_monitored[i].fd) {
struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd);
// now call the file_monitor handler
if (uf)
uwsgi_route_signal(uf->sig);
return 0;
}
}
}
// check if some timer elapsed
// no need to lock again
for (i = 0; i < ushared->timers_cnt; i++) {
if (ushared->timers[i].registered) {
if (interesting_fd == ushared->timers[i].fd) {
struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd);
// now call the timer handler
if (ut)
uwsgi_route_signal(ut->sig);
return 0;
}
}
}
uint8_t uwsgi_signal;
// check for worker signal
if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) {
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("uwsgi_master_manage_events()/read()");
}
else if (rlen > 0) {
uwsgi_route_signal(uwsgi_signal);
}
else {
// TODO restart workers here
uwsgi_log_verbose("lost connection with workers !!!\n");
close(interesting_fd);
}
return 0;
}
// check for spooler signal
if (uwsgi.spoolers) {
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) {
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("uwsgi_master_manage_events()/read()");
}
else if (rlen > 0) {
uwsgi_route_signal(uwsgi_signal);
}
else {
// TODO restart spoolers here
uwsgi_log_verbose("lost connection with spoolers\n");
close(interesting_fd);
}
return 0;
}
}
// check for mules signal
if (uwsgi.mules_cnt > 0) {
if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) {
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("uwsgi_master_manage_events()/read()");
}
else if (rlen > 0) {
uwsgi_route_signal(uwsgi_signal);
}
else {
// TODO respawn mules here
uwsgi_log_verbose("lost connection with mules\n");
close(interesting_fd);
}
// return 0;
}
}
return 0;
}
+329 -64
View File
@@ -5,15 +5,82 @@ extern struct uwsgi_server uwsgi;
void worker_wakeup() {
}
uint64_t uwsgi_worker_exceptions(int wid) {
uint64_t total = 0;
int i;
for(i=0;i<uwsgi.cores;i++) {
total += uwsgi.workers[wid].cores[i].exceptions;
}
return total;
}
void uwsgi_curse(int wid, int sig) {
uwsgi.workers[wid].cursed_at = uwsgi_now();
uwsgi.workers[wid].no_mercy_at = uwsgi.workers[wid].cursed_at + uwsgi.worker_reload_mercy;
if (sig) {
(void) kill(uwsgi.workers[wid].pid, sig);
}
}
static void uwsgi_signal_spoolers(int signum) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->pid > 0) {
kill(uspool->pid, signum);
uwsgi_log("killing the spooler with pid %d\n", uspool->pid);
}
uspool = uspool->next;
}
}
void uwsgi_destroy_processes() {
int i;
int waitpid_status;
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0) {
kill(ushared->gateways[i].pid, SIGKILL);
waitpid(ushared->gateways[i].pid, &waitpid_status, 0);
uwsgi_log("gateway \"%s %d\" has been buried (pid: %d)\n", ushared->gateways[i].name, ushared->gateways[i].num, (int) ushared->gateways[i].pid);
}
}
// TODO mules can be programmed to be gracefully reloaded
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
kill(uwsgi.mules[i].pid, SIGKILL);
waitpid(uwsgi.mules[i].pid, &waitpid_status, 0);
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
}
}
}
void uwsgi_master_cleanup_hooks(void) {
int j;
// could be an inherited atexit hook
if (uwsgi.mywid > 0)
if (uwsgi.mypid != uwsgi.workers[0].pid)
return;
uwsgi.cleaning = 1;
uwsgi.status.is_cleaning = 1;
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->master_cleanup) {
@@ -78,8 +145,7 @@ int uwsgi_calc_cheaper(void) {
#endif
uwsgi.workers[oldest_worker].cheaped = 1;
uwsgi.workers[oldest_worker].manage_next_request = 0;
// wakeup task in case of wait
(void) kill(uwsgi.workers[oldest_worker].pid, SIGWINCH);
uwsgi_curse(oldest_worker, SIGWINCH);
}
}
@@ -131,7 +197,7 @@ int uwsgi_cheaper_algo_spare(void) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
// if a non-busy worker is found, the overload_count is decremented and stop the cycle
if (uwsgi.workers[i].busy == 0) {
if (uwsgi_worker_is_busy(i) == 0) {
if (overload_count > 0)
overload_count--;
goto healthy;
@@ -174,7 +240,7 @@ healthy:
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
if (uwsgi.workers[i].busy == 1)
if (uwsgi_worker_is_busy(i) == 1)
busy_workers++;
}
}
@@ -307,43 +373,44 @@ void uwsgi_reload(char **argv) {
uwsgi_sock = uwsgi_sock->next;
}
if (found) continue;
if (!found) {
if (uwsgi.has_emperor) {
if (i == uwsgi.emperor_fd) {
found = 1;
}
if (uwsgi.has_emperor) {
if (i == uwsgi.emperor_fd) {
continue;
}
if (i == uwsgi.emperor_fd_config) {
continue;
}
}
if (uwsgi.log_master) {
if (uwsgi.original_log_fd > -1) {
if (i == uwsgi.original_log_fd) {
found = 1;
continue;
}
}
if (uwsgi.shared->worker_log_pipe[0] > -1) {
if (i == uwsgi.shared->worker_log_pipe[0]) {
found = 1;
continue;
}
}
if (uwsgi.shared->worker_log_pipe[1] > -1) {
if (i == uwsgi.shared->worker_log_pipe[1]) {
found = 1;
continue;
}
}
}
if (!found) {
#ifdef __APPLE__
fcntl(i, F_SETFD, FD_CLOEXEC);
fcntl(i, F_SETFD, FD_CLOEXEC);
#else
close(i);
close(i);
#endif
}
}
#ifdef UWSGI_AS_SHARED_LIBRARY
@@ -373,44 +440,10 @@ void uwsgi_reload(char **argv) {
}
void master_check_cluster_nodes() {
int i;
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
struct uwsgi_cluster_node *ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
// should i retry ?
if (uwsgi.master_cycles % ucn->errors == 0) {
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
ucn->status = UWSGI_NODE_OK;
uwsgi_log("re-enabled cluster node %d/%s\n", i, ucn->name);
}
else {
ucn->errors++;
}
}
}
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
if ((uwsgi.current_time - ucn->last_seen) > 30) {
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
ucn->name[0] = 0;
}
}
}
}
void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
int i;
// close the cache server
if (uwsgi.cache_server_fd != -1) {
close(uwsgi.cache_server_fd);
}
if (uwsgi.master_process) {
if (uwsgi.master_queue > -1)
close(uwsgi.master_queue);
@@ -443,14 +476,13 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
close(uwsgi.workers[i].signal_pipe[1]);
}
}
#ifdef UWSGI_SPOOLER
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
close(uwsgi.shared->spooler_signal_pipe[1]);
}
#endif
if (uwsgi.shared->mule_signal_pipe[0] != -1)
close(uwsgi.shared->mule_signal_pipe[0]);
@@ -503,12 +535,15 @@ int uwsgi_respawn_worker(int wid) {
uwsgi.workers[wid].pending_harakiri = 0;
uwsgi.workers[wid].rss_size = 0;
uwsgi.workers[wid].vsz_size = 0;
// ... reset stopped_at
uwsgi.workers[wid].cursed_at = 0;
uwsgi.workers[wid].no_mercy_at = 0;
// internal statuses should be reset too
uwsgi.workers[wid].cheaped = 0;
uwsgi.workers[wid].busy = 0;
uwsgi.workers[wid].suspended = 0;
// SUSPENSION is managed by the user, not the master...
//uwsgi.workers[wid].suspended = 0;
uwsgi.workers[wid].sig = 0;
// this is required for various checks
@@ -547,7 +582,6 @@ int uwsgi_respawn_worker(int wid) {
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
/*
uwsgi.workers[uwsgi.mywid].cheaped = 0;
uwsgi.workers[uwsgi.mywid].busy = 0;
uwsgi.workers[uwsgi.mywid].suspended = 0;
uwsgi.workers[uwsgi.mywid].sig = 0;
*/
@@ -555,12 +589,18 @@ int uwsgi_respawn_worker(int wid) {
// reset the apps count with a copy from the master
uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt;
// reset wsgi_request structures
for(i=0;i<uwsgi.cores;i++) {
uwsgi.workers[uwsgi.mywid].cores[i].in_request = 0;
memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request));
}
uwsgi_fixup_fds(wid, 0, NULL);
uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1];
if (uwsgi.master_process) {
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) {
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.status.is_cheap)) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->master_fixup) {
uwsgi.p[i]->master_fixup(1);
@@ -715,7 +755,7 @@ void uwsgi_manage_command_cron(time_t now) {
}
}
if (current_cron->month < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(current_cron->month)) == 0) {
if ((uwsgi_cron_delta->tm_mon % abs(current_cron->month)) == 0) {
uc_month = uwsgi_cron_delta->tm_mon;
}
}
@@ -861,6 +901,66 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_comma(us))
goto end;
if (uwsgi.caches) {
if (uwsgi_stats_key(us, "caches"))
goto end;
if (uwsgi_stats_list_open(us)) goto end;
struct uwsgi_cache *uc = uwsgi.caches;
while(uc) {
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keyval_comma(us, "name", uc->name ? uc->name : "default"))
goto end;
if (uwsgi_stats_keyval_comma(us, "hash", uc->hash->name))
goto end;
if (uwsgi_stats_keylong_comma(us, "hashsize", (unsigned long long) uc->hashsize))
goto end;
if (uwsgi_stats_keylong_comma(us, "keysize", (unsigned long long) uc->keysize))
goto end;
if (uwsgi_stats_keylong_comma(us, "max_items", (unsigned long long) uc->max_items))
goto end;
if (uwsgi_stats_keylong_comma(us, "blocks", (unsigned long long) uc->blocks))
goto end;
if (uwsgi_stats_keylong_comma(us, "blocksize", (unsigned long long) uc->blocksize))
goto end;
if (uwsgi_stats_keylong_comma(us, "items", (unsigned long long) uc->n_items))
goto end;
if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) uc->hits))
goto end;
if (uwsgi_stats_keylong_comma(us, "miss", (unsigned long long) uc->miss))
goto end;
if (uwsgi_stats_keylong(us, "full", (unsigned long long) uc->full))
goto end;
if (uwsgi_stats_object_close(us))
goto end;
if (uc->next) {
if (uwsgi_stats_comma(us))
goto end;
}
uc = uc->next;
}
if (uwsgi_stats_comma(us))
goto end;
}
if (uwsgi_stats_key(us, "sockets"))
goto end;
@@ -920,7 +1020,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests))
goto end;
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi.workers[i + 1].exceptions))
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi_worker_exceptions(i + 1)))
goto end;
if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count))
goto end;
@@ -938,7 +1038,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keyval_comma(us, "status", "cheap"))
goto end;
}
else if (uwsgi.workers[i + 1].suspended && !uwsgi.workers[i + 1].busy) {
else if (uwsgi.workers[i + 1].suspended && !uwsgi_worker_is_busy(i+1)) {
if (uwsgi_stats_keyval_comma(us, "status", "pause"))
goto end;
}
@@ -947,7 +1047,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum))
goto end;
}
else if (uwsgi.workers[i + 1].busy) {
else if (uwsgi_worker_is_busy(i+1)) {
if (uwsgi_stats_keyval_comma(us, "status", "busy"))
goto end;
}
@@ -1052,7 +1152,21 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keylong_comma(us, "offloaded_requests", (unsigned long long) uc->offloaded_requests))
goto end;
if (uwsgi_stats_keylong(us, "in_request", (unsigned long long) uc->in_request))
if (uwsgi_stats_keylong_comma(us, "write_errors", (unsigned long long) uc->write_errors))
goto end;
if (uwsgi_stats_keylong_comma(us, "in_request", (unsigned long long) uc->in_request))
goto end;
if (uwsgi_stats_key(us, "vars"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
if (uwsgi_stats_dump_vars(us, uc)) goto end;
if (uwsgi_stats_list_close(us))
goto end;
@@ -1080,7 +1194,6 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_close(us))
goto end;
#ifdef UWSGI_SPOOLER
struct uwsgi_spooler *uspool = uwsgi.spoolers;
if (uspool) {
if (uwsgi_stats_comma(us))
@@ -1119,12 +1232,147 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_close(us))
goto end;
}
#ifdef UWSGI_SSL
struct uwsgi_legion *legion = NULL;
if (uwsgi.legions) {
if (uwsgi_stats_comma(us))
goto end;
if (uwsgi_stats_key(us, "legions"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
legion = uwsgi.legions;
while (legion) {
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keyval_comma(us, "legion", legion->legion))
goto end;
if (uwsgi_stats_keyval_comma(us, "addr", legion->addr))
goto end;
if (uwsgi_stats_keyval_comma(us, "uuid", legion->uuid))
goto end;
if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) legion->valor))
goto end;
if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) legion->checksum))
goto end;
if (uwsgi_stats_keylong_comma(us, "quorum", (unsigned long long) legion->quorum))
goto end;
if (uwsgi_stats_keylong_comma(us, "i_am_the_lord", (unsigned long long) legion->i_am_the_lord))
goto end;
if (uwsgi_stats_keylong_comma(us, "lord_valor", (unsigned long long) legion->lord_valor))
goto end;
if (uwsgi_stats_keyvaln_comma(us, "lord_uuid", legion->lord_uuid, 36))
goto end;
// legion nodes start
if (uwsgi_stats_key(us, "nodes"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
struct uwsgi_string_list *nodes = legion->nodes;
while (nodes) {
if (uwsgi_stats_str(us, nodes->value))
goto end;
nodes = nodes->next;
if (nodes) {
if (uwsgi_stats_comma(us))
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end;
if (uwsgi_stats_comma(us))
goto end;
// legion members start
if (uwsgi_stats_key(us, "members"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
uwsgi_rlock(legion->lock);
struct uwsgi_legion_node *node = legion->nodes_head;
while (node) {
if (uwsgi_stats_object_open(us))
goto unlock_legion_mutex;
if (uwsgi_stats_keyvaln_comma(us, "name", node->name, node->name_len))
goto unlock_legion_mutex;
if (uwsgi_stats_keyval_comma(us, "uuid", node->uuid))
goto unlock_legion_mutex;
if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) node->valor))
goto unlock_legion_mutex;
if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) node->checksum))
goto unlock_legion_mutex;
if (uwsgi_stats_keylong(us, "last_seen", (unsigned long long) node->last_seen))
goto unlock_legion_mutex;
if (uwsgi_stats_object_close(us))
goto unlock_legion_mutex;
node = node->next;
if (node) {
if (uwsgi_stats_comma(us))
goto unlock_legion_mutex;
}
}
uwsgi_rwunlock(legion->lock);
if (uwsgi_stats_list_close(us))
goto end;
// legion nodes end
if (uwsgi_stats_object_close(us))
goto end;
legion = legion->next;
if (legion) {
if (uwsgi_stats_comma(us))
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end;
}
#endif
if (uwsgi_stats_object_close(us))
goto end;
return us;
#ifdef UWSGI_SSL
unlock_legion_mutex:
if (legion)
uwsgi_rwunlock(legion->lock);
#endif
end:
free(us->base);
free(us);
@@ -1221,3 +1469,20 @@ void trigger_harakiri(int i) {
// to avoid races
}
void uwsgi_master_fix_request_counters() {
int i;
uint64_t total_counter = 0;
for (i = 1; i <= uwsgi.numproc;i++) {
uint64_t tmp_counter = 0;
int j;
for(j=0;j<uwsgi.cores;j++) {
tmp_counter += uwsgi.workers[i].cores[j].requests;
}
uwsgi.workers[i].requests = tmp_counter;
total_counter += tmp_counter;
}
uwsgi.workers[0].requests = total_counter;
}
+16 -3
View File
@@ -41,10 +41,22 @@ void uwsgi_mule(int id) {
uwsgi_error("prctl()");
}
#endif
signal(SIGALRM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, end_me);
signal(SIGTERM, end_me);
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
uwsgi.muleid = id;
// avoid race conditions
uwsgi.mules[id - 1].id = id;
uwsgi.mules[id - 1].pid = getpid();
uwsgi.mypid = uwsgi.mules[id - 1].pid;
uwsgi_fixup_fds(0, id, NULL);
@@ -70,8 +82,8 @@ void uwsgi_mule(int id) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->mule) {
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
// never here
break;
// never here ?
end_me(1);
}
}
}
@@ -198,7 +210,7 @@ void uwsgi_mule_handler() {
}
}
if (!found)
uwsgi_log("*** mule %d received a %d bytes message ***\n", uwsgi.muleid, len);
uwsgi_log("*** mule %d received a %ld bytes message ***\n", uwsgi.muleid, (long) len);
}
}
}
@@ -425,6 +437,7 @@ void uwsgi_setup_mules_and_farms() {
mules_list++;
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
free(farm_value);
// create the socket pipe
create_signal_pipe(uwsgi.farms[i].signal_pipe);
+6 -3
View File
@@ -20,7 +20,9 @@ void uwsgi_systemd_notify(char *message) {
msghdr->msg_iovlen = 3;
sendmsg(uwsgi.notification_fd, msghdr, 0);
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
uwsgi_error("sendmsg()");
}
}
void uwsgi_systemd_notify_ready(void) {
@@ -33,8 +35,9 @@ void uwsgi_systemd_notify_ready(void) {
msghdr->msg_iovlen = 1;
sendmsg(uwsgi.notification_fd, msghdr, 0);
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
uwsgi_error("sendmsg()");
}
}
+213 -92
View File
@@ -4,6 +4,17 @@
uWSGI offloading subsystem
steps to offload a task
1) allocate a uwsgi_offload_request structure (could be on stack)
struct uwsgi_offload_request uor;
2) prepare it for a specific engine (last argument is the takeover flag)
uwsgi_offload_setup(my_engine, &uor, 1)
3) run it (last argument is the waiter)
int uwsgi_offload_run(wsgi_req, &uor, NULL);
between 2 and 3 you can set specific values
*/
@@ -13,19 +24,20 @@ extern struct uwsgi_server uwsgi;
#define uwsgi_offload_0r_1w(x, y) if (event_queue_del_fd(ut->queue, x, event_queue_read())) return -1;\
if (event_queue_fd_read_to_write(ut->queue, y)) return -1;
static int uwsgi_offload_net_transfer(struct uwsgi_thread *, struct uwsgi_offload_request *, int);
static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *, struct uwsgi_offload_request *, int);
void uwsgi_offload_setup(struct uwsgi_offload_engine *uoe, struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req, uint8_t takeover) {
static void uwsgi_offload_setup(struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req,
int (*func)(struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
wsgi_req->fd_closed = 1;
memset(uor, 0, sizeof(struct uwsgi_offload_request));
uor->s = wsgi_req->poll.fd;
uor->func = func;
// put socket in non-blocking mode
uwsgi_socket_nb(uor->s);
uor->engine = uoe;
uor->s = wsgi_req->fd;
uor->fd = -1;
uor->fd2 = -1;
// an engine could changes behaviour based on pipe anf takeover values
uor->pipe[0] = -1;
uor->pipe[1] = -1;
uor->takeover = takeover;
}
static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
@@ -38,89 +50,102 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
struct uwsgi_thread *ut = uwsgi.offload_thread[uc->offload_rr];
uc->offload_rr++;
if (write(ut->pipe[0], uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) {
if (uor->takeover) {
wsgi_req->fd_closed = 0;
}
return -1;
}
return 0;
}
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socket, struct uwsgi_buffer *ubuf) {
/*
// fill offload request
struct uwsgi_offload_request uor;
uwsgi_offload_setup(&uor, wsgi_req, uwsgi_offload_net_transfer);
transfer offload engine:
name -> socket name
ubuf -> data to send
uor.fd = uwsgi_connect(socket, 0, 1);
if (uor.fd < 0) {
uwsgi_error("uwsgi_offload_request_net_do() -> connect()");
goto error;
*/
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
if (!uor->name) {
return -1;
}
uor.ubuf = ubuf;
if (uwsgi_offload_enqueue(wsgi_req, &uor)) {
goto error2;
uor->fd = uwsgi_connect(uor->ubuf->buf, 0, 1);
if (uor->fd < 0) {
uwsgi_error("u_offload_transfer_prepare()/connect()");
return -1;
}
return 0;
error2:
close(uor.fd);
error:
wsgi_req->fd_closed = 0;
return -1;
}
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, char *filename, size_t len) {
/*
// fill offload request
struct uwsgi_offload_request uor;
uwsgi_offload_setup(&uor, wsgi_req, uwsgi_offload_sendfile_transfer);
sendfile offload engine:
name -> filename to transfer
fd -> file descriptor of file to transfer
fd2 -> sendfile destination (default wsgi_req->fd)
len -> size of the file or amount of data to transfer
pos -> position in the file
uor.fd = open(filename, O_RDONLY | O_NONBLOCK);
if (uor.fd < 0) {
uwsgi_error_open(filename);
goto error;
*/
static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
if (!uor->name && uor->fd == -1) return -1;
if (uor->name) {
uor->fd = open(uor->name, O_RDONLY | O_NONBLOCK);
if (uor->fd < 0) {
uwsgi_error_open(uor->name);
return -1;
}
}
// make a fstat to get the file size
if (!len) {
if (!uor->len) {
struct stat st;
if (fstat(uor.fd, &st)) {
uwsgi_error("fstat()");
goto error2;
if (fstat(uor->fd, &st)) {
uwsgi_error("u_offload_sendfile_prepare()/fstat()");
if (uor->name) {
close(uor->fd);
}
return -1;
}
len = st.st_size;
uor->len = st.st_size;
}
uor.len = len;
if (uwsgi_offload_enqueue(wsgi_req, &uor)) {
goto error2;
if (uor->fd2 == -1) {
uor->fd2 = uor->s;
}
uor->s = -1;
return 0;
error2:
close(uor.fd);
error:
wsgi_req->fd_closed = 0;
return -1;
}
static void uwsgi_offload_close(struct uwsgi_offload_request *uor) {
static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
// close the socket and the file descriptor
close(uor->s);
close(uor->fd);
if (uor->takeover && uor->s > -1) {
close(uor->s);
}
if (uor->fd != -1) {
close(uor->fd);
}
if (uor->fd2 != -1) {
close(uor->fd2);
}
// remove the structure from the linked list;
struct uwsgi_offload_request *prev = uor->prev;
struct uwsgi_offload_request *next = uor->next;
if (uor == uwsgi.offload_requests_head) {
uwsgi.offload_requests_head = next;
if (uor == ut->offload_requests_head) {
ut->offload_requests_head = next;
}
if (uor == uwsgi.offload_requests_tail) {
uwsgi.offload_requests_tail = prev;
if (uor == ut->offload_requests_tail) {
ut->offload_requests_tail = prev;
}
if (prev) {
@@ -139,27 +164,32 @@ static void uwsgi_offload_close(struct uwsgi_offload_request *uor) {
uwsgi_buffer_destroy(uor->ubuf);
}
if (uor->pipe[0] != -1) {
close(uor->pipe[1]);
close(uor->pipe[0]);
}
free(uor);
}
static void uwsgi_offload_append(struct uwsgi_offload_request *uor) {
static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
if (!uwsgi.offload_requests_head) {
uwsgi.offload_requests_head = uor;
if (!ut->offload_requests_head) {
ut->offload_requests_head = uor;
}
if (uwsgi.offload_requests_tail) {
uwsgi.offload_requests_tail->next = uor;
uor->prev = uwsgi.offload_requests_tail;
if (ut->offload_requests_tail) {
ut->offload_requests_tail->next = uor;
uor->prev = ut->offload_requests_tail;
}
uwsgi.offload_requests_tail = uor;
ut->offload_requests_tail = uor;
}
static struct uwsgi_offload_request *uwsgi_offload_get_by_fd(int s) {
struct uwsgi_offload_request *uor = uwsgi.offload_requests_head;
static struct uwsgi_offload_request *uwsgi_offload_get_by_fd(struct uwsgi_thread *ut, int s) {
struct uwsgi_offload_request *uor = ut->offload_requests_head;
while (uor) {
if (uor->s == s || uor->fd == s) {
if (uor->s == s || uor->fd == s || uor->fd2 == s) {
return uor;
}
uor = uor->next;
@@ -185,22 +215,22 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
free(uor);
continue;
}
// start monitoring socket for write
if (uor->func(ut, uor, -1)) {
uwsgi_offload_close(uor);
// cal the event function for the first time
if (uor->engine->event_func(ut, uor, -1)) {
uwsgi_offload_close(ut, uor);
continue;
}
uwsgi_offload_append(uor);
uwsgi_offload_append(ut, uor);
continue;
}
// get the task from the interesting fd
struct uwsgi_offload_request *uor = uwsgi_offload_get_by_fd(interesting_fd);
struct uwsgi_offload_request *uor = uwsgi_offload_get_by_fd(ut, interesting_fd);
if (!uor)
continue;
// run the hook
if (uor->func(ut, uor, interesting_fd)) {
uwsgi_offload_close(uor);
if (uor->engine->event_func(ut, uor, interesting_fd)) {
uwsgi_offload_close(ut, uor);
}
}
}
@@ -221,41 +251,42 @@ the offload task starts after having acquired the file fd
*/
static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
static int u_offload_sendfile_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;
if (event_queue_add_fd_write(ut->queue, uor->fd2)) return -1;
return 0;
}
#if defined(__linux__) || defined(__sun__)
ssize_t len = sendfile(uor->s, uor->fd, &uor->pos, 128 * 1024);
ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024);
if (len > 0) {
uor->written += len;
if (uor->written >= uor->len) {
return -1;
}
return 0;
}
else if (len < 0) {
uwsgi_offload_retry
uwsgi_error("sendfile()");
uwsgi_error("u_offload_sendfile_do()");
}
#elif defined(__FreeBSD__) || defined(__DragonFly__)
off_t sbytes = 0;
int ret = sendfile(uor->fd, uor->s, uor->pos, 0, NULL, &sbytes, 0);
int ret = sendfile(uor->fd, uor->fd2, uor->pos, 0, NULL, &sbytes, 0);
// transfer finished
if (ret == -1) {
uor->pos += sbytes;
uwsgi_offload_retry
uwsgi_error("sendfile()");
uwsgi_error("u_offload_sendfile_do()");
}
#elif defined(__APPLE__)
off_t len = 0;
int ret = sendfile(uor->fd, uor->s, uor->pos, &len, NULL, 0);
int ret = sendfile(uor->fd, uor->fd2, uor->pos, &len, NULL, 0);
// transfer finished
if (ret == -1) {
uor->pos += len;
uwsgi_offload_retry
uwsgi_error("sendfile()");
uwsgi_error("u_offload_sendfile_do()");
}
#endif
return -1;
@@ -272,7 +303,7 @@ the offload task starts soon after the call to connect()
3 -> write to s
4 -> write to fd
*/
static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
ssize_t rlen;
@@ -288,7 +319,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
if (fd == uor->fd) {
uor->status = 1;
// ok try to send the request right now...
return uwsgi_offload_net_transfer(ut, uor, fd);
return u_offload_transfer_do(ut, uor, fd);
}
return -1;
// write event (or just connected)
@@ -306,7 +337,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
}
else if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("uwsgi_offload_net_transfer() -> write()");
uwsgi_error("u_offload_transfer_do() -> write()");
}
}
return -1;
@@ -326,11 +357,11 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
}
if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("uwsgi_offload_net_transfer() -> read()/fd");
uwsgi_error("u_offload_transfer_do() -> read()/fd");
}
}
else if (fd == uor->s) {
rlen = read(uor->fd, uor->buf, 4096);
rlen = read(uor->s, uor->buf, 4096);
if (rlen > 0) {
uor->to_write = rlen;
uor->pos = 0;
@@ -340,7 +371,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
}
if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("uwsgi_offload_net_transfer() -> read()/s");
uwsgi_error("u_offload_transfer_do() -> read()/s");
}
}
return -1;
@@ -359,7 +390,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
}
else if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("uwsgi_offload_net_transfer() -> write()/s");
uwsgi_error("u_offload_transfer_do() -> write()/s");
}
return -1;
// write event on fd
@@ -377,7 +408,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
}
else if (rlen < 0) {
uwsgi_offload_retry
uwsgi_error("uwsgi_offload_net_transfer() -> write()/fd");
uwsgi_error("u_offload_transfer_do() -> write()/fd");
}
return -1;
default:
@@ -386,3 +417,93 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
return -1;
}
int uwsgi_offload_run(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor, int *wait) {
if (uor->engine->prepare_func(wsgi_req, uor)) {
return -1;
}
if (wait) {
if (pipe(uor->pipe)) {
uwsgi_error("uwsgi_offload_setup()/pipe()");
return -1;
}
*wait = uor->pipe[0];
uwsgi_socket_nb(uor->pipe[0]);
uwsgi_socket_nb(uor->pipe[1]);
}
if (uor->takeover) {
wsgi_req->fd_closed = 1;
}
if (uwsgi_offload_enqueue(wsgi_req, uor)) {
close(uor->pipe[0]);
close(uor->pipe[1]);
if (uor->takeover) {
wsgi_req->fd_closed = 0;
}
return -1;
}
return 0;
};
struct uwsgi_offload_engine *uwsgi_offload_engine_by_name(char *name) {
struct uwsgi_offload_engine *uoe = uwsgi.offload_engines;
while(uoe) {
if (!strcmp(name, uoe->name)) {
return uoe;
}
}
return NULL;
}
struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*prepare_func)(struct wsgi_request *, struct uwsgi_offload_request *), int (*event_func) (struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
struct uwsgi_offload_engine *old_engine=NULL,*engine=uwsgi.offload_engines;
while(engine) {
if (!strcmp(engine->name, name)) {
return engine;
}
old_engine = engine;
engine = engine->next;
}
engine = uwsgi_calloc(sizeof(struct uwsgi_offload_engine));
engine->name = name;
engine->prepare_func = prepare_func;
engine->event_func = event_func;
if (old_engine) {
old_engine->next = engine;
}
else {
uwsgi.offload_engines = engine;
}
return engine;
}
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);
}
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
struct uwsgi_offload_request uor;
uwsgi_offload_setup(uwsgi.offload_engine_sendfile, &uor, wsgi_req, 1);
uor.fd = fd;
uor.len = len;
return uwsgi_offload_run(wsgi_req, &uor, NULL);
}
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname, struct uwsgi_buffer *ubuf) {
struct uwsgi_offload_request uor;
uwsgi_offload_setup(uwsgi.offload_engine_transfer, &uor, wsgi_req, 1);
uor.name = socketname;
uor.ubuf = ubuf;
return uwsgi_offload_run(wsgi_req, &uor, NULL);
}
+3 -4
View File
@@ -24,7 +24,7 @@ static void uwsgi_plugin_parse_section(char *filename) {
}
#endif
static int plugin_already_loaded(const char *plugin) {
int plugin_already_loaded(const char *plugin) {
int i;
for (i = 0; i < 256; i++) {
@@ -76,8 +76,8 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
char *plugin_filename = NULL;
int need_free = 0;
char *plugin_name = plugin;
char *plugin_symbol_name_start = plugin;
char *plugin_name = uwsgi_strip(uwsgi_str(plugin));
char *plugin_symbol_name_start = plugin_name;
struct uwsgi_plugin *up;
char linkpath_buf[1024], linkpath[1024];
@@ -165,7 +165,6 @@ success:
uwsgi_log("%s\n", linkpath);
#endif
free(plugin_entry_symbol);
up = dlsym(plugin_handle, plugin_entry_symbol);
char *slash = uwsgi_get_last_char(linkpath, '/');
if (!slash) {
slash = linkpath;
+107
View File
@@ -0,0 +1,107 @@
#include <uwsgi.h>
/*
upload progress facilities
*/
extern struct uwsgi_server uwsgi;
char *uwsgi_upload_progress_create(struct wsgi_request *wsgi_req, int *fd) {
const char *x_progress_id = "X-Progress-ID=";
char *xpi_ptr = (char *) x_progress_id;
uint16_t i;
char *upload_progress_filename = NULL;
if (wsgi_req->uri_len <= 51)
return NULL;
for (i = 0; i < wsgi_req->uri_len; i++) {
if (wsgi_req->uri[i] == xpi_ptr[0]) {
if (xpi_ptr[0] == '=') {
if (wsgi_req->uri + i + 36 <= wsgi_req->uri + wsgi_req->uri_len) {
upload_progress_filename = wsgi_req->uri + i + 1;
}
break;
}
xpi_ptr++;
}
else {
xpi_ptr = (char *) x_progress_id;
}
}
// now check for valid uuid (from spec available at http://en.wikipedia.org/wiki/Universally_unique_identifier)
if (!upload_progress_filename)
return NULL;
uwsgi_log("upload progress uuid = %.*s\n", 36, upload_progress_filename);
if (!check_hex(upload_progress_filename, 8))
return NULL;
if (upload_progress_filename[8] != '-')
return NULL;
if (!check_hex(upload_progress_filename + 9, 4))
return NULL;
if (upload_progress_filename[13] != '-')
return NULL;
if (!check_hex(upload_progress_filename + 14, 4))
return NULL;
if (upload_progress_filename[18] != '-')
return NULL;
if (!check_hex(upload_progress_filename + 19, 4))
return NULL;
if (upload_progress_filename[23] != '-')
return NULL;
if (!check_hex(upload_progress_filename + 24, 12))
return NULL;
upload_progress_filename = uwsgi_concat4n(uwsgi.upload_progress, strlen(uwsgi.upload_progress), "/", 1, upload_progress_filename, 36, ".js", 3);
// here we use O_EXCL to avoid eventual application bug in uuid generation/using
*fd = open(upload_progress_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP);
if (*fd < 0) {
uwsgi_error_open(upload_progress_filename);
free(upload_progress_filename);
return NULL;
}
return upload_progress_filename;
}
int uwsgi_upload_progress_update(struct wsgi_request *wsgi_req, int fd, size_t remains) {
char buf[4096];
int ret = snprintf(buf, 4096, "{ \"state\" : \"uploading\", \"received\" : %llu, \"size\" : %llu }\r\n", (unsigned long long) (wsgi_req->post_cl - remains), (unsigned long long) wsgi_req->post_cl);
if (ret < 0) {
return -1;
}
if (lseek(fd, 0, SEEK_SET)) {
uwsgi_error("uwsgi_upload_progress_update()/lseek()");
return -1;
}
if (write(fd, buf, ret) != ret) {
uwsgi_error("uwsgi_upload_progress_update()/write()");
return -1;
}
if (fsync(fd)) {
uwsgi_error("uwsgi_upload_progress_update()/fsync()");
return -1;
}
return 0;
}
void uwsgi_upload_progress_destroy(char *filename, int fd) {
close(fd);
if (unlink(filename)) {
uwsgi_error("uwsgi_upload_progress_destroy()/unlink()");
}
free(filename);
}
+456 -1416
View File
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
#include <uwsgi.h>
/*
QUERY_STRING management functions (mainly used by the internal routing subsystem)
*/
static char *check_qs(char *qs, uint16_t qs_len, char *key, uint16_t keylen, uint16_t *vallen) {
// search for the equal sign
char *equal = memchr(qs, '=', qs_len);
if (!equal) return NULL;
if (uwsgi_strncmp(key, keylen, qs, equal-qs)) {
return NULL;
}
qs_len -= (equal-qs)+1;
if (qs_len == 0) return NULL;
*vallen = qs_len;
return equal+1;
}
char *uwsgi_get_qs(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
uint16_t i;
char *qs = wsgi_req->query_string;
uint16_t qs_len = 0;
char *ptr = wsgi_req->query_string;
//start splitting by ;
for(i=0;i<wsgi_req->query_string_len;i++) {
if (!qs) {
qs = ptr + i;
}
if (ptr[i] == '&') {
char *value = check_qs(qs, qs_len, key, keylen, vallen);
if (value) {
return value;
}
qs_len = 0;
qs = NULL;
}
else {
qs_len++;
}
}
if (qs_len > 0) {
char *value = check_qs(qs, qs_len, key, keylen, vallen);
if (value) {
return value;
}
}
return NULL;
}
+2 -1
View File
@@ -47,6 +47,7 @@ void uwsgi_init_queue() {
// fix header
uwsgi.queue_header = uwsgi.queue;
uwsgi.queue += 16;
close(queue_fd);
}
else {
uwsgi.queue = mmap(NULL, (uwsgi.queue_blocksize * uwsgi.queue_size) + 16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
@@ -65,7 +66,7 @@ void uwsgi_init_queue() {
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
uwsgi_log("*** Queue subsystem initialized: %luMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
}
char *uwsgi_queue_get(uint64_t index, uint64_t * size) {
+334 -32
View File
@@ -1,65 +1,367 @@
/*
uWSGI timers implementation
uWSGI rbtree implementation based on nginx
based on Linux hrtimers and nginx timeout management.
rbtree with allowed duplicate keys is used
Copyright (C) Igor Sysoev
Copyright (C) Nginx, Inc.
Copyright (C) Unbit S.a.s.
The red-black tree code is based on the algorithm described in
the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
*/
#include "uwsgi.h"
#include <uwsgi.h>
struct rb_root *uwsgi_init_rb_timer() {
#define uwsgi_rbt_red(node) ((node)->color = 1)
#define uwsgi_rbt_black(node) ((node)->color = 0)
#define uwsgi_rbt_is_red(node) ((node)->color)
#define uwsgi_rbt_is_black(node) (!uwsgi_rbt_is_red(node))
#define uwsgi_rbt_copy_color(n1, n2) (n1->color = n2->color)
struct rb_root *u_rb_root = uwsgi_malloc(sizeof(struct rb_root));
u_rb_root->rb_node = NULL;
struct uwsgi_rbtree *uwsgi_init_rb_timer() {
return u_rb_root;
struct uwsgi_rbtree *tree = uwsgi_calloc(sizeof(struct uwsgi_rbtree));
struct uwsgi_rb_timer *sentinel = uwsgi_calloc(sizeof(struct uwsgi_rb_timer));
// no need to set it black, calloc already did it
//uwsgi_rbt_black(sentinel);
tree->root = sentinel;
tree->sentinel = sentinel;
return tree;
}
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct rb_root *root) {
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
struct rb_node *node = root->rb_node;
if (!node)
node = tree->root;
struct uwsgi_rb_timer *sentinel = tree->sentinel;
if (node == NULL)
return NULL;
if (tree->root == sentinel) return NULL;
while (node->rb_left != NULL) {
node = node->rb_left;
while (node->left != sentinel) {
node = node->left;
}
return ((struct uwsgi_rb_timer *) node);
return node;
}
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct rb_root *root, time_t key, void *data) {
static void uwsgi_rbtree_lr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
struct uwsgi_rb_timer *urbt = uwsgi_malloc(sizeof(struct uwsgi_rb_timer));
struct rb_node **p = &root->rb_node, *parent = NULL;
struct uwsgi_rb_timer *current_rb_timer;
struct uwsgi_rb_timer *temp;
memset(urbt, 0, sizeof(struct uwsgi_rb_timer));
temp = node->right;
node->right = temp->left;
urbt->key = key;
urbt->data = data;
if (temp->left != sentinel) {
temp->left->parent = node;
}
while (*p) {
parent = *p;
temp->parent = node->parent;
current_rb_timer = (struct uwsgi_rb_timer *) parent;
if (node == *root) {
*root = temp;
}
else if (node == node->parent->left) {
node->parent->left = temp;
}
else {
node->parent->right = temp;
}
temp->left = node;
node->parent = temp;
}
static void uwsgi_rbtree_rr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
struct uwsgi_rb_timer *temp;
temp = node->left;
node->left = temp->right;
if (temp->right != sentinel) {
temp->right->parent = node;
}
temp->parent = node->parent;
if (node == *root) {
*root = temp;
}
else if (node == node->parent->right) {
node->parent->right = temp;
}
else {
node->parent->left = temp;
}
temp->right = node;
node->parent = temp;
}
static void uwsgi_rbt_add(struct uwsgi_rb_timer *temp, struct uwsgi_rb_timer *node, struct uwsgi_rb_timer *sentinel) {
struct uwsgi_rb_timer **p;
for (;;) {
p = (node->value < temp->value) ? &temp->left : &temp->right;
if (*p == sentinel)
break;
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
uwsgi_rbt_red(node);
}
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct uwsgi_rbtree *tree, uint64_t value, void *data) {
struct uwsgi_rb_timer *node = uwsgi_malloc(sizeof(struct uwsgi_rb_timer));
struct uwsgi_rb_timer *new_node = node;
node->value = value;
node->data = data;
struct uwsgi_rb_timer *temp = NULL;
/* a binary tree insert */
struct uwsgi_rb_timer **root = &tree->root;
struct uwsgi_rb_timer *sentinel = tree->sentinel;
if (*root == sentinel) {
node->parent = NULL;
node->left = sentinel;
node->right = sentinel;
uwsgi_rbt_black(node);
*root = node;
return new_node;
}
uwsgi_rbt_add(*root, node, sentinel);
/* re-balance tree */
while (node != *root && uwsgi_rbt_is_red(node->parent)) {
if (node->parent == node->parent->parent->left) {
temp = node->parent->parent->right;
if (uwsgi_rbt_is_red(temp)) {
uwsgi_rbt_black(node->parent);
uwsgi_rbt_black(temp);
uwsgi_rbt_red(node->parent->parent);
node = node->parent->parent;
}
else {
if (node == node->parent->right) {
node = node->parent;
uwsgi_rbtree_lr(root, sentinel, node);
}
uwsgi_rbt_black(node->parent);
uwsgi_rbt_red(node->parent->parent);
uwsgi_rbtree_rr(root, sentinel, node->parent->parent);
}
if (key <= current_rb_timer->key) {
p = &(*p)->rb_left;
}
else {
p = &(*p)->rb_right;
temp = node->parent->parent->left;
if (uwsgi_rbt_is_red(temp)) {
uwsgi_rbt_black(node->parent);
uwsgi_rbt_black(temp);
uwsgi_rbt_red(node->parent->parent);
node = node->parent->parent;
}
else {
if (node == node->parent->left) {
node = node->parent;
uwsgi_rbtree_rr(root, sentinel, node);
}
uwsgi_rbt_black(node->parent);
uwsgi_rbt_red(node->parent->parent);
uwsgi_rbtree_lr(root, sentinel, node->parent->parent);
}
}
}
rb_link_node((struct rb_node *) urbt, parent, p);
uwsgi_rbt_black(*root);
rb_insert_color((struct rb_node *) urbt, root);
return new_node;
}
return urbt;
void uwsgi_del_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
uint8_t red;
struct uwsgi_rb_timer **root, *sentinel, *subst, *temp, *w;
/* a binary tree delete */
root = &tree->root;
sentinel = tree->sentinel;
if (node->left == sentinel) {
temp = node->right;
subst = node;
}
else if (node->right == sentinel) {
temp = node->left;
subst = node;
}
else {
subst = uwsgi_min_rb_timer(tree, node->right);
if (subst->left != sentinel) {
temp = subst->left;
}
else {
temp = subst->right;
}
}
if (subst == *root) {
*root = temp;
uwsgi_rbt_black(temp);
return;
}
red = uwsgi_rbt_is_red(subst);
if (subst == subst->parent->left) {
subst->parent->left = temp;
}
else {
subst->parent->right = temp;
}
if (subst == node) {
temp->parent = subst->parent;
}
else {
if (subst->parent == node) {
temp->parent = subst;
}
else {
temp->parent = subst->parent;
}
subst->left = node->left;
subst->right = node->right;
subst->parent = node->parent;
uwsgi_rbt_copy_color(subst, node);
if (node == *root) {
*root = subst;
}
else {
if (node == node->parent->left) {
node->parent->left = subst;
}
else {
node->parent->right = subst;
}
}
if (subst->left != sentinel) {
subst->left->parent = subst;
}
if (subst->right != sentinel) {
subst->right->parent = subst;
}
}
if (red) {
return;
}
/* a delete fixup */
while (temp != *root && uwsgi_rbt_is_black(temp)) {
if (temp == temp->parent->left) {
w = temp->parent->right;
if (uwsgi_rbt_is_red(w)) {
uwsgi_rbt_black(w);
uwsgi_rbt_red(temp->parent);
uwsgi_rbtree_lr(root, sentinel, temp->parent);
w = temp->parent->right;
}
if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) {
uwsgi_rbt_red(w);
temp = temp->parent;
}
else {
if (uwsgi_rbt_is_black(w->right)) {
uwsgi_rbt_black(w->left);
uwsgi_rbt_red(w);
uwsgi_rbtree_rr(root, sentinel, w);
w = temp->parent->right;
}
uwsgi_rbt_copy_color(w, temp->parent);
uwsgi_rbt_black(temp->parent);
uwsgi_rbt_black(w->right);
uwsgi_rbtree_lr(root, sentinel, temp->parent);
temp = *root;
}
}
else {
w = temp->parent->left;
if (uwsgi_rbt_is_red(w)) {
uwsgi_rbt_black(w);
uwsgi_rbt_red(temp->parent);
uwsgi_rbtree_rr(root, sentinel, temp->parent);
w = temp->parent->left;
}
if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) {
uwsgi_rbt_red(w);
temp = temp->parent;
}
else {
if (uwsgi_rbt_is_black(w->left)) {
uwsgi_rbt_black(w->right);
uwsgi_rbt_red(w);
uwsgi_rbtree_lr(root, sentinel, w);
w = temp->parent->left;
}
uwsgi_rbt_copy_color(w, temp->parent);
uwsgi_rbt_black(temp->parent);
uwsgi_rbt_black(w->left);
uwsgi_rbtree_rr(root, sentinel, temp->parent);
temp = *root;
}
}
}
uwsgi_rbt_black(temp);
}
+572
View File
@@ -0,0 +1,572 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int uwsgi_simple_wait_read_hook(int fd, int timeout) {
struct pollfd upoll;
timeout = timeout * 1000;
upoll.fd = fd;
upoll.events = POLLIN;
upoll.revents = 0;
int ret = poll(&upoll, 1, timeout);
if (ret > 0) {
if (upoll.revents & POLLIN) {
return 1;
}
return -1;
}
if (ret < 0) {
uwsgi_error("uwsgi_simple_wait_read_hook()/poll()");
}
return ret;
}
/*
seek()/rewind() language-independent implementations.
*/
void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) {
if (wsgi_req->post_file) {
if (pos < 0) {
if (fseek(wsgi_req->post_file, pos, SEEK_CUR)) {
uwsgi_error("uwsgi_request_body_seek()/fseek()");
}
wsgi_req->post_pos = ftell(wsgi_req->post_file);
return;
}
if (fseek(wsgi_req->post_file, pos, SEEK_SET)) {
uwsgi_error("uwsgi_request_body_seek()/fseek()");
}
wsgi_req->post_pos = ftell(wsgi_req->post_file);
return;
}
if (uwsgi.post_buffering) {
if (pos < 0) {
if (pos > (off_t) wsgi_req->post_pos) {
wsgi_req->post_pos = 0;
return;
}
wsgi_req->post_pos -= pos;
return;
}
if (pos >= (off_t) uwsgi.post_buffering) {
pos = uwsgi.post_buffering - 1;
}
wsgi_req->post_pos = pos;
}
}
/*
read() and readline() language-independent implementations.
*/
#define uwsgi_read_error0(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: Client closed connection\n",\
(unsigned long long) x,\
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
#define uwsgi_read_error(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: %s\n",\
(unsigned long long) x,\
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos,\
strerror(errno));
#define uwsgi_read_timeout(x) uwsgi_log("[uwsgi-body-read] Timeout reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu\n",\
(unsigned long long) x,\
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
size_t remains = UMIN(uwsgi.buffer_size, wsgi_req->post_cl - wsgi_req->post_pos);
int ret;
// allocate more memory if needed
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) {
memcpy(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos = 0;
// still something to use ?
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark < remains) {
char *tmp_buf = realloc(wsgi_req->post_readline_buf, wsgi_req->post_readline_size + remains);
if (!tmp_buf) {
uwsgi_error("consume_body_for_readline()/realloc()");
return -1;
}
wsgi_req->post_readline_buf = tmp_buf;
wsgi_req->post_readline_size += remains;
// INFORM THE USER HIS readline() USAGE IS FOOLISH
if (!wsgi_req->post_warning && wsgi_req->post_readline_size > (uwsgi.body_read_warning * 1024*1024)) {
uwsgi_log("[uwsgi-warning] you are using readline() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_readline_size/(1024*1024)));
wsgi_req->post_warning = 1;
}
}
}
remains = UMIN(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, wsgi_req->post_cl - wsgi_req->post_pos);
// read from a file
if (wsgi_req->post_file) {
size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, remains, 1, wsgi_req->post_file);
if (ret == 0) {
uwsgi_error("consume_body_for_readline()/fread()");
return -1;
}
wsgi_req->post_pos += remains;
wsgi_req->post_readline_watermark += remains;
return 0;
}
// read from post_buffering memory
if (uwsgi.post_buffering) {
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, remains);
wsgi_req->post_pos += remains;
wsgi_req->post_readline_watermark += remains;
return 0;
}
// read from socket
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
if (len > 0) {
wsgi_req->post_pos += len;
wsgi_req->post_readline_watermark += len;
return 0;
}
if (len == 0) {
uwsgi_read_error(remains);
return -1;
}
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
uwsgi_read_error(remains);
return -1;
}
wait:
ret = uwsgi_wait_read_req(wsgi_req);
if (ret > 0) {
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
if (len > 0) {
wsgi_req->post_pos += len;
wsgi_req->post_readline_watermark += len;
return 0;
}
uwsgi_read_error(remains);
return -1;
}
// 0 means timeout
else if (ret == 0) {
uwsgi_read_timeout(remains);
return -1;
}
uwsgi_read_error(remains);
return -1;
}
// TODO take hint into account
// readline_buf is allocated when needed and freed at the end of the request
char *uwsgi_request_body_readline(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
// return 0 if no post_cl or pos >= post_cl and no residual data
if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
return uwsgi.empty;
}
// some residual data ?
if (wsgi_req->post_readline_pos > 0) {
size_t i;
for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
// found a newline
if (wsgi_req->post_readline_buf[i] == '\n') {
*rlen = (i+1)-wsgi_req->post_readline_pos;
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos += *rlen;
// all the readline buffer has been consumed
if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
wsgi_req->post_readline_pos = 0;
wsgi_req->post_readline_watermark = 0;
}
return buf;
}
}
// ok, no newline found, continue below
}
// allocate memory on the first round
if (!wsgi_req->post_readline_buf) {
size_t amount = UMIN(uwsgi.buffer_size, wsgi_req->post_cl);
wsgi_req->post_readline_buf = malloc(amount);
if (!wsgi_req->post_readline_buf) {
uwsgi_error("uwsgi_request_body_readline()/malloc()");
*rlen = -1;
return NULL;
}
wsgi_req->post_readline_size = amount;
}
// ok, no newline found, consume a bit more of memory and retry
for(;;) {
// no more data to consume
if (wsgi_req->post_pos >= wsgi_req->post_cl) break;
if (consume_body_for_readline(wsgi_req)) {
*rlen = -1;
return NULL;
}
size_t i;
for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
if (wsgi_req->post_readline_buf[i] == '\n') {
*rlen = (i+1)-wsgi_req->post_readline_pos;
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos += *rlen;
if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
wsgi_req->post_readline_pos = 0;
wsgi_req->post_readline_watermark = 0;
}
return buf;
}
}
}
// no line found, let's return all
*rlen = wsgi_req->post_readline_size - wsgi_req->post_readline_pos;
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos = 0;
return buf;
}
char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
int ret = -1;
size_t remains = hint;
// return empty if no post_cl or pos >= post_cl and no residual data
if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
return uwsgi.empty;
}
// return the whole input
if (remains <= 0) {
remains = wsgi_req->post_cl;
}
// some residual data ?
if (wsgi_req->post_readline_pos > 0) {
if (remains <= (wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos)) {
*rlen = remains;
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos += remains;
return buf;
}
// the hint is higher than residual data, let's copy it to read() memory and go on
size_t avail = wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos;
// check if we have enough memory...
if (avail > wsgi_req->post_read_buf_size) {
char *tmp_buf = realloc(wsgi_req->post_read_buf, avail);
if (!tmp_buf) {
uwsgi_error("uwsgi_request_body_read()/realloc()");
*rlen = -1;
return NULL;
}
wsgi_req->post_read_buf = tmp_buf;
wsgi_req->post_read_buf_size = avail;
if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
wsgi_req->post_warning = 1;
}
}
// fix remains...
if (remains > 0) {
remains -= avail;
}
*rlen += avail;
memcpy(wsgi_req->post_read_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, avail);
wsgi_req->post_readline_pos = 0;
wsgi_req->post_readline_watermark = 0;
}
if (remains + wsgi_req->post_pos > wsgi_req->post_cl) {
remains = wsgi_req->post_cl - wsgi_req->post_pos;
}
if (remains == 0) {
if (*rlen > 0) {
return wsgi_req->post_read_buf;
}
else {
return uwsgi.empty;
}
}
// read from post buffering memory
if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) {
*rlen += remains;
char *buf = wsgi_req->post_buffering_buf+wsgi_req->post_pos;
wsgi_req->post_pos += remains;
return buf;
}
// ok we need to check if we need to allocate memory
if (!wsgi_req->post_read_buf) {
wsgi_req->post_read_buf = malloc(remains);
if (!wsgi_req->post_read_buf) {
uwsgi_error("uwsgi_request_body_read()/malloc()");
*rlen = -1;
return NULL;
}
wsgi_req->post_read_buf_size = remains;
}
// need to realloc ?
else {
if ((remains+*rlen) > wsgi_req->post_read_buf_size) {
char *tmp_buf = realloc(wsgi_req->post_read_buf, (remains+*rlen));
if (!tmp_buf) {
uwsgi_error("uwsgi_request_body_read()/realloc()");
*rlen = -1;
return NULL;
}
wsgi_req->post_read_buf = tmp_buf;
wsgi_req->post_read_buf_size = (remains+*rlen);
if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
wsgi_req->post_warning = 1;
}
}
}
// check for disk buffered body first (they are all read in one shot)
if (wsgi_req->post_file) {
if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) {
*rlen = -1;
uwsgi_error("uwsgi_request_body_read()/fread()");
return NULL;
}
*rlen += remains;
wsgi_req->post_pos+= remains;
return wsgi_req->post_read_buf;
}
// ok read all the required bytes...
while(remains > 0) {
// here we first try to read (as data could be already available)
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen , remains);
if (len > 0) {
wsgi_req->post_pos+=len;
remains -= len;
*rlen += len;
continue;
}
// client closed connection...
if (len == 0) {
*rlen = -1;
uwsgi_read_error0(remains);
return NULL;
}
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
*rlen = -1;
uwsgi_read_error(remains);
return NULL;
}
wait:
ret = uwsgi_wait_read_req(wsgi_req);
if (ret > 0) {
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen, remains);
if (len > 0) {
wsgi_req->post_pos+=len;
remains -= len;
*rlen += len;
continue;
}
*rlen = -1;
if (len == 0) {
uwsgi_read_error0(remains);
}
else {
uwsgi_read_error(remains);
}
return NULL;
}
// 0 means timeout
else if (ret == 0) {
*rlen = 0;
uwsgi_read_timeout(remains);
return NULL;
}
*rlen = -1;
uwsgi_read_error(remains);
return NULL;
}
return wsgi_req->post_read_buf;
}
/*
post buffering
*/
int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
size_t remains = wsgi_req->post_cl;
int ret;
char *ptr = wsgi_req->post_buffering_buf;
while (remains > 0) {
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
}
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
if (rlen > 0) {
remains -= rlen;
ptr += rlen;
continue;
}
if (rlen == 0) {
uwsgi_read_error0(remains);
return -1;
}
if (rlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
uwsgi_read_error(remains);
return -1;
}
wait:
ret = uwsgi_wait_read_req(wsgi_req);
if (ret > 0) {
rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
if (rlen > 0) {
remains -= rlen;
ptr += rlen;
continue;
}
}
if (ret < 0) {
uwsgi_read_error(remains);
return -1;
}
uwsgi_read_timeout(remains);
return -1;
}
return 0;
}
int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
size_t post_remains = wsgi_req->post_cl;
int ret;
int upload_progress_fd = -1;
char *upload_progress_filename = NULL;
wsgi_req->post_file = tmpfile();
if (!wsgi_req->post_file) {
uwsgi_error("uwsgi_postbuffer_do_in_disk()/tmpfile()");
return -1;
}
if (uwsgi.upload_progress) {
// first check for X-Progress-ID size
// separator + 'X-Progress-ID' + '=' + uuid
upload_progress_filename = uwsgi_upload_progress_create(wsgi_req, &upload_progress_fd);
if (!upload_progress_filename) {
uwsgi_log("invalid X-Progress-ID value: must be a UUID\n");
}
}
// manage buffered data and upload progress
while (post_remains > 0) {
// during post buffering we need to constantly reset the harakiri
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
}
// we use the already available post buffering buffer to read chunks....
size_t remains = UMIN(post_remains, uwsgi.post_buffering);
// first try to read data (there could be something already available
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
if (rlen > 0) goto write;
if (rlen == 0) {
uwsgi_read_error0(remains);
goto end;
}
if (rlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
uwsgi_read_error(remains);
goto end;
}
wait:
ret = uwsgi_wait_read_req(wsgi_req);
if (ret > 0) {
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
if (rlen > 0) goto write;
if (rlen == 0) {
uwsgi_read_error0(remains);
}
else {
uwsgi_read_error(remains);
}
goto end;
}
if (ret < 0) {
uwsgi_read_error(remains);
goto end;
}
uwsgi_read_timeout(remains);
goto end;
write:
if (fwrite(wsgi_req->post_buffering_buf, rlen, 1, wsgi_req->post_file) != 1) {
uwsgi_error("uwsgi_postbuffer_do_in_disk()/fwrite()");
goto end;
}
post_remains -= rlen;
if (upload_progress_filename) {
// stop updating it on errors
if (uwsgi_upload_progress_update(wsgi_req, upload_progress_fd, post_remains)) {
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
upload_progress_filename = NULL;
}
}
}
rewind(wsgi_req->post_file);
if (upload_progress_filename) {
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
}
return 0;
end:
if (upload_progress_filename) {
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
}
return -1;
}
+10 -1
View File
@@ -65,7 +65,15 @@ char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *o
int i;
int dollar = 0;
char *res = uwsgi_malloc(dst_n + (src_n * n) + 1);
size_t dollars = n;
for(i=0;i<dst_n;i++) {
if (dst[i] == '$') {
dollars++;
}
}
char *res = uwsgi_malloc(dst_n + (src_n * dollars) + 1);
char *ptr = res;
for (i = 0; i < dst_n; i++) {
@@ -79,6 +87,7 @@ char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *o
}
}
else {
*ptr++ = '$';
*ptr++ = dst[i];
}
dollar = 0;
+862 -64
View File
@@ -1,68 +1,302 @@
#ifdef UWSGI_ROUTING
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
struct uwsgi_route_var *uwsgi_register_route_var(char *name, char *(*func)(struct wsgi_request *, char *, uint16_t, uint16_t *)) {
struct uwsgi_route_var *old_urv = NULL,*urv = uwsgi.route_vars;
while(urv) {
if (!strcmp(urv->name, name)) {
return urv;
}
old_urv = urv;
urv = urv->next;
}
urv = uwsgi_calloc(sizeof(struct uwsgi_route_var));
urv->name = name;
urv->name_len = strlen(name);
urv->func = func;
if (old_urv) {
old_urv->next = urv;
}
else {
uwsgi.route_vars = urv;
}
return urv;
}
struct uwsgi_route_var *uwsgi_get_route_var(char *name, uint16_t name_len) {
struct uwsgi_route_var *urv = uwsgi.route_vars;
while(urv) {
if (!uwsgi_strncmp(urv->name, urv->name_len, name, name_len)) {
return urv;
}
urv = urv->next;
}
return NULL;
}
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *subject, uint16_t subject_len, char *data, size_t data_len) {
char *pass1 = data;
size_t pass1_len = data_len;
// cannot fail
if (subject) {
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector, ur->ovn);
pass1_len = strlen(pass1);
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(pass1_len);
size_t i;
int status = 0;
char *key = NULL;
size_t keylen = 0;
for(i=0;i<pass1_len;i++) {
switch(status) {
case 0:
if (pass1[i] == '$') {
status = 1;
break;
}
if (uwsgi_buffer_append(ub, pass1 + i, 1)) goto error;
break;
case 1:
if (pass1[i] == '{') {
status = 2;
key = pass1+i+1;
keylen = 0;
break;
}
status = 0;
key = NULL;
keylen = 0;
if (uwsgi_buffer_append(ub, "$", 1)) goto error;
if (uwsgi_buffer_append(ub, pass1 + i, 1)) goto error;
break;
case 2:
if (pass1[i] == '}') {
uint16_t vallen = 0;
int need_free = 0;
char *value = NULL;
char *bracket = memchr(key, '[', keylen);
if (bracket && keylen > 0 && key[keylen-1] == ']') {
struct uwsgi_route_var *urv = uwsgi_get_route_var(key, bracket - key);
if (urv) {
need_free = urv->need_free;
value = urv->func(wsgi_req, bracket + 1, keylen - (urv->name_len+2), &vallen);
}
else {
value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
}
}
else {
value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
}
if (value) {
if (uwsgi_buffer_append(ub, value, vallen)) {
if (need_free) {
free(value);
}
goto error;
}
if (need_free) {
free(value);
}
}
status = 0;
key = NULL;
keylen = 0;
break;
}
keylen++;
break;
default:
break;
}
}
// fix the buffer
if (status == 1) {
if (uwsgi_buffer_append(ub, "$", 1)) goto error;
}
else if (status == 2) {
if (uwsgi_buffer_append(ub, "${", 2)) goto error;
if (keylen > 0) {
if (uwsgi_buffer_append(ub, key, keylen)) goto error;
}
}
// add the final NULL byte (to simplify plugin work)
if (uwsgi_buffer_append(ub, "\0", 1)) goto error;
// .. but came back of 1 position to avoid accounting it
ub->pos--;
if (pass1 != data) {
free(pass1);
}
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
struct uwsgi_route *routes = uwsgi.routes;
void *goon_func = NULL;
int n = -1;
if (!routes)
char *orig_subject = subject;
uint16_t orig_subject_len = subject_len;
while (routes) {
if (wsgi_req->route_goto > 0 && wsgi_req->route_pc < wsgi_req->route_goto) {
goto next;
}
if (goon_func && goon_func == routes->func) {
goto next;
}
goon_func = NULL;
wsgi_req->route_goto = 0;
if (!routes->if_func) {
// could be a "run"
if (!routes->subject) {
n = 0;
goto run;
}
if (!subject) {
char **subject2 = (char **) (((char *) (wsgi_req)) + routes->subject);
uint16_t *subject_len2 = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
subject = *subject2 ;
subject_len = *subject_len2;
}
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector, routes->ovn);
}
else {
int ret = routes->if_func(wsgi_req, routes);
// error
if (ret < 0) {
return UWSGI_ROUTE_BREAK;
}
// true
if (!routes->if_negate) {
if (ret == 0) {
goto next;
}
n = ret;
}
else {
if (ret > 0) {
goto next;
}
n = 1;
}
}
run:
if (n >= 0) {
wsgi_req->is_routing = 1;
int ret = routes->func(wsgi_req, routes);
wsgi_req->is_routing = 0;
if (ret == UWSGI_ROUTE_BREAK) {
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
return ret;
}
if (ret == UWSGI_ROUTE_CONTINUE) {
return ret;
}
if (ret == UWSGI_ROUTE_GOON) {
goon_func = routes->func;
}
}
next:
subject = orig_subject;
subject_len = orig_subject_len;
routes = routes->next;
if (routes) wsgi_req->route_pc++;
}
return UWSGI_ROUTE_CONTINUE;
}
int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.routes)
return UWSGI_ROUTE_CONTINUE;
// avoid loops
if (wsgi_req->is_routing)
return UWSGI_ROUTE_CONTINUE;
if (uwsgi_parse_vars(wsgi_req)) {
return UWSGI_ROUTE_BREAK;
}
while (routes) {
char **subject = (char **) (((char *) (wsgi_req)) + routes->subject);
uint16_t *subject_len = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
#ifdef UWSGI_DEBUG
uwsgi_log("route subject = %.*s\n", *subject_len, *subject);
#endif
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, *subject, *subject_len, routes->ovector, routes->ovn);
if (n >= 0) {
int ret = routes->func(wsgi_req, routes);
if (ret == UWSGI_ROUTE_BREAK) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
if (ret != UWSGI_ROUTE_NEXT) {
return ret;
}
}
routes = routes->next;
}
return UWSGI_ROUTE_CONTINUE;
}
int uwsgi_apply_routes_fast(struct wsgi_request *wsgi_req, char *uri, int len) {
struct uwsgi_route *routes = uwsgi.routes;
if (!routes)
// in case of static files serving previous rules could be applied
if (wsgi_req->routes_applied) {
return UWSGI_ROUTE_CONTINUE;
while (routes) {
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, uri, len, routes->ovector, routes->ovn);
if (n >= 0) {
int ret = routes->func(wsgi_req, routes);
if (ret == UWSGI_ROUTE_BREAK) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
if (ret != UWSGI_ROUTE_NEXT) {
return ret;
}
}
routes = routes->next;
}
return UWSGI_ROUTE_CONTINUE;
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
}
static void *uwsgi_route_get_condition_func(char *name) {
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
while(urc) {
if (!strcmp(urc->name, name)) {
return urc->func;
}
urc = urc->next;
}
return NULL;
}
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;
uint64_t pos = 0;
while(ur) {
old_ur = ur;
ur = ur->next;
pos++;
}
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
if (old_ur) {
old_ur->next = ur;
}
else {
uwsgi.routes = ur;
}
ur->pos = pos;
// is it a label ?
if (foobar == NULL) {
ur->label = value;
ur->label_len = strlen(value);
return;
}
char *route = uwsgi_str(value);
char *space = strchr(route, ' ');
if (!strcmp(foobar, "run")) {
command = route;
goto done;
}
space = strchr(route, ' ');
if (!space) {
uwsgi_log("invalid route syntax\n");
exit(1);
@@ -70,23 +304,27 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
*space = 0;
struct uwsgi_route *ur = uwsgi.routes;
if (!ur) {
uwsgi.routes = uwsgi_calloc(sizeof(struct uwsgi_route));
ur = uwsgi.routes;
}
else {
while (ur) {
if (!ur->next) {
ur->next = uwsgi_calloc(sizeof(struct uwsgi_route));
ur = ur->next;
break;
}
ur = ur->next;
if (!strcmp(foobar, "if") || !strcmp(foobar, "if-not")) {
char *colon = strchr(route, ':');
if (!colon) {
uwsgi_log("invalid route condition syntax\n");
exit(1);
}
*colon = 0;
if (!strcmp(foobar, "if-not")) {
ur->if_negate = 1;
}
foobar = colon+1;
ur->if_func = uwsgi_route_get_condition_func(route);
if (!ur->if_func) {
uwsgi_log("unable to find \"%s\" route condition\n", route);
exit(1);
}
}
if (!strcmp(foobar, "http_host")) {
else if (!strcmp(foobar, "http_host")) {
ur->subject = offsetof(struct wsgi_request, host);
ur->subject_len = offsetof(struct wsgi_request, host_len);
}
@@ -98,21 +336,45 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
ur->subject = offsetof(struct wsgi_request, query_string);
ur->subject_len = offsetof(struct wsgi_request, query_string_len);
}
else if (!strcmp(foobar, "remote_addr")) {
ur->subject = offsetof(struct wsgi_request, remote_addr);
ur->subject_len = offsetof(struct wsgi_request, remote_addr_len);
}
else if (!strcmp(foobar, "user_agent")) {
ur->subject = offsetof(struct wsgi_request, user_agent);
ur->subject_len = offsetof(struct wsgi_request, user_agent_len);
}
else if (!strcmp(foobar, "referer")) {
ur->subject = offsetof(struct wsgi_request, referer);
ur->subject_len = offsetof(struct wsgi_request, referer_len);
}
else if (!strcmp(foobar, "remote_user")) {
ur->subject = offsetof(struct wsgi_request, remote_user);
ur->subject_len = offsetof(struct wsgi_request, remote_user_len);
}
else {
ur->subject = offsetof(struct wsgi_request, path_info);
ur->subject_len = offsetof(struct wsgi_request, path_info_len);
}
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
exit(1);
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->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
if (ur->ovn > 0) {
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
}
char *command = space + 1;
command = space + 1;
done:
ur->action = uwsgi_str(command);
char *colon = strchr(command, ':');
if (!colon) {
@@ -138,6 +400,7 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
last_ur->is_last = 1;
return;
}
break;
}
r = r->next;
}
@@ -146,6 +409,498 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
exit(1);
}
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;
while(r) {
if (!strcmp(router, r->name)) {
goto found;
}
r = r->next;
}
free(args);
return -1;
found:
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
// initialize the virtual route
if (r->func(ur, args)) {
free(ur);
free(args);
return -1;
}
// call it
int ret = ur->func(wsgi_req, ur);
if (ur->free) {
ur->free(ur);
}
free(ur);
free(args);
return ret;
}
// continue/last route
static int uwsgi_router_continue_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
return UWSGI_ROUTE_CONTINUE;
}
static int uwsgi_router_continue(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_continue_func;
return 0;
}
// break route
static int uwsgi_router_break_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
if (route->data_len >= 3) {
if (uwsgi_response_prepare_headers(wsgi_req, route->data, route->data_len)) goto end;
if (uwsgi_response_add_connection_close(wsgi_req)) goto end;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end;
// no need to check for return value
uwsgi_response_write_headers_do(wsgi_req);
}
end:
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_break_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// goon route
static int uwsgi_router_goon_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
return UWSGI_ROUTE_GOON;
}
static int uwsgi_router_goon(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_goon_func;
return 0;
}
// log route
static int uwsgi_router_log_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;
uwsgi_log("%.*s\n", ub->pos, ub->buf);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_log(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_log_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// logvar route
static int uwsgi_router_logvar_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->data2, ur->data2_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uwsgi_logvar_add(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_logvar(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_logvar_func;
char *equal = strchr(arg, '=');
if (!equal) {
uwsgi_log("invalid logvar syntax, must be key=value\n");
exit(1);
}
ur->data = arg;
ur->data_len = equal-arg;
ur->data2 = equal+1;
ur->data2_len = strlen(ur->data2);
return 0;
}
// goto route
static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
// build the label (if needed)
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;
// find the label
struct uwsgi_route *routes = uwsgi.routes;
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;
goto found;
}
next:
routes = routes->next;
}
wsgi_req->route_goto = ur->custom;
found:
uwsgi_buffer_destroy(ub);
if (wsgi_req->route_goto <= wsgi_req->route_pc) {
wsgi_req->route_goto = 0;
uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
return UWSGI_ROUTE_BREAK;
}
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_goto(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_goto_func;
ur->data = arg;
ur->data_len = strlen(arg);
ur->custom = atoi(arg);
return 0;
}
// addvar route
static int uwsgi_router_addvar_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->data2, ur->data2_len);
if (!ub) return UWSGI_ROUTE_BREAK;
if (!uwsgi_req_append(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_addvar(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_addvar_func;
char *equal = strchr(arg, '=');
if (!equal) {
uwsgi_log("[uwsgi-route] invalid addvar syntax, must be KEY=VAL\n");
exit(1);
}
ur->data = arg;
ur->data_len = equal-arg;
ur->data2 = equal+1;
ur->data2_len = strlen(ur->data2);
return 0;
}
// addheader route
static int uwsgi_router_addheader_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;
uwsgi_additional_header_add(wsgi_req, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_addheader(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_addheader_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// remheader route
static int uwsgi_router_remheader_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;
uwsgi_remove_header(wsgi_req, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_remheader(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_remheader_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// signal route
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_signal_send(uwsgi.signal_socket, route->custom);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_signal(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_signal_func;
ur->custom = atoi(arg);
return 0;
}
// send route
static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_response_write_body_do(wsgi_req, route->data, route->data_len);
if (route->custom) {
uwsgi_response_write_body_do(wsgi_req, "\r\n", 2);
}
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_send(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_send_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
static int uwsgi_router_send_crnl(struct uwsgi_route *ur, char *arg) {
uwsgi_router_send(ur, arg);
ur->custom = 1;
return 0;
}
static int uwsgi_route_condition_exists(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (uwsgi_file_exists(ub->buf)) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_route_condition_isfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (uwsgi_is_file(ub->buf)) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
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);
pcre_free(pattern);
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_free_study(pattern_extra);
#else
pcre_free(pattern_extra);
#endif
return 1;
}
uwsgi_buffer_destroy(ub);
pcre_free(pattern);
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_free_study(pattern_extra);
#else
pcre_free(pattern_extra);
#endif
return 0;
}
static int uwsgi_route_condition_empty(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (ub->pos == 0) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_route_condition_equal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if(!uwsgi_strncmp(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_startswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if(!uwsgi_starts_with(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if (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);
return 1;
}
zero:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_isdir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (uwsgi_is_dir(ub->buf)) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_route_condition_islink(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (uwsgi_is_link(ub->buf)) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_route_condition_isexec(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (!access(ub->buf, X_OK)) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
// register embedded routers
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("logvar", uwsgi_router_logvar);
uwsgi_register_router("goto", uwsgi_router_goto);
uwsgi_register_router("addvar", uwsgi_router_addvar);
uwsgi_register_router("addheader", uwsgi_router_addheader);
uwsgi_register_router("delheader", uwsgi_router_remheader);
uwsgi_register_router("remheader", uwsgi_router_remheader);
uwsgi_register_router("signal", uwsgi_router_signal);
uwsgi_register_router("send", uwsgi_router_send);
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
uwsgi_register_route_condition("islink", uwsgi_route_condition_islink);
uwsgi_register_route_condition("isexec", uwsgi_route_condition_isexec);
uwsgi_register_route_condition("equal", uwsgi_route_condition_equal);
uwsgi_register_route_condition("isequal", uwsgi_route_condition_equal);
uwsgi_register_route_condition("eq", uwsgi_route_condition_equal);
uwsgi_register_route_condition("==", uwsgi_route_condition_equal);
uwsgi_register_route_condition("startswith", uwsgi_route_condition_startswith);
uwsgi_register_route_condition("endswith", uwsgi_route_condition_endswith);
uwsgi_register_route_condition("regexp", uwsgi_route_condition_regexp);
uwsgi_register_route_condition("re", uwsgi_route_condition_regexp);
uwsgi_register_route_condition("empty", uwsgi_route_condition_empty);
uwsgi_register_route_var("cookie", uwsgi_get_cookie);
uwsgi_register_route_var("qs", uwsgi_get_qs);
}
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
struct uwsgi_router *ur = uwsgi.routers;
@@ -169,4 +924,47 @@ struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi
return NULL;
}
struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*func) (struct wsgi_request *, struct uwsgi_route *)) {
struct uwsgi_route_condition *old_urc = NULL,*urc = uwsgi.route_conditions;
while(urc) {
if (!strcmp(urc->name, name)) {
return urc;
}
old_urc = urc;
urc = urc->next;
}
urc = uwsgi_calloc(sizeof(struct uwsgi_route_condition));
urc->name = name;
urc->func = func;
if (old_urc) {
old_urc->next = urc;
}
else {
uwsgi.route_conditions = urc;
}
return urc;
}
void uwsgi_routing_dump() {
struct uwsgi_route *routes = uwsgi.routes;
if (!routes) return;
uwsgi_log("*** dumping internal 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 routing table ***\n");
}
#endif
+78 -42
View File
@@ -7,25 +7,51 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
struct uwsgi_rpc *urpc;
int ret = -1;
if (uwsgi.mywid != 0) {
uwsgi_log("you can register RPC functions only in the master\n");
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
uwsgi_log("only the master and the workers can register RPC functions\n");
return -1;
}
uwsgi_lock(uwsgi.rpc_table_lock);
if (uwsgi.shared->rpc_count < MAX_RPC) {
urpc = &uwsgi.shared->rpc_table[uwsgi.shared->rpc_count];
// first check if a function is already registered
size_t i;
for(i=0;i<uwsgi.shared->rpc_count[uwsgi.mywid];i++) {
int pos = (uwsgi.mywid * uwsgi.rpc_max) + i;
urpc = &uwsgi.rpc_table[pos];
if (!strcmp(name, urpc->name)) {
goto already;
}
}
if (uwsgi.shared->rpc_count[uwsgi.mywid] < uwsgi.rpc_max) {
int pos = (uwsgi.mywid * uwsgi.rpc_max) + uwsgi.shared->rpc_count[uwsgi.mywid];
urpc = &uwsgi.rpc_table[pos];
uwsgi.shared->rpc_count[uwsgi.mywid]++;
already:
memcpy(urpc->name, name, strlen(name));
urpc->modifier1 = modifier1;
urpc->args = args;
urpc->func = func;
uwsgi.shared->rpc_count++;
urpc->shared = uwsgi.mywid == 0 ? 1 : 0;
ret = 0;
uwsgi_log("registered RPC function %s\n", name);
if (uwsgi.mywid == 0) {
uwsgi_log("registered shared/inherited RPC function \"%s\"\n", name);
}
else {
uwsgi_log("registered RPC function \"%s\" on worker %d\n", name, uwsgi.mywid);
}
}
// implement cow
if (uwsgi.mywid == 0) {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
uwsgi.shared->rpc_count[i] = uwsgi.shared->rpc_count[0];
int pos = (i * uwsgi.rpc_max);
memcpy(&uwsgi.rpc_table[pos], uwsgi.rpc_table, sizeof(struct uwsgi_rpc) * uwsgi.rpc_max);
}
}
uwsgi_unlock(uwsgi.rpc_table_lock);
@@ -36,13 +62,15 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
struct uwsgi_rpc *urpc = NULL;
int i;
uint64_t i;
uint16_t ret = 0;
for (i = 0; i < uwsgi.shared->rpc_count; i++) {
if (uwsgi.shared->rpc_table[i].name[0] != 0) {
if (!strcmp(uwsgi.shared->rpc_table[i].name, name)) {
urpc = &uwsgi.shared->rpc_table[i];
int pos = (uwsgi.mywid * uwsgi.rpc_max);
for (i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) {
if (uwsgi.rpc_table[pos + i].name[0] != 0) {
if (!strcmp(uwsgi.rpc_table[pos + i].name, name)) {
urpc = &uwsgi.rpc_table[pos + i];
break;
}
}
@@ -62,25 +90,31 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
uint8_t i;
uint16_t ulen;
struct uwsgi_header uh;
struct uwsgi_header *uh = NULL;
char *buffer = NULL;
*len = 0;
if (node == NULL || !strcmp(node, "")) {
// allocate the whole buffer
buffer = uwsgi_malloc(65536);
buffer = uwsgi_malloc(UMAX16);
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
return buffer;
}
// connect to node
int fd = uwsgi_connect(node, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
// connect to node (async way)
int fd = uwsgi_connect(node, 0, 1);
if (fd < 0)
return NULL;
// wait for connection;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) {
close(fd);
return NULL;
}
// prepare a uwsgi array
uint16_t buffer_size = 2 + strlen(func);
@@ -89,14 +123,16 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
}
// allocate the whole buffer
buffer = uwsgi_malloc(65536);
buffer = uwsgi_malloc(4+buffer_size);
uh.modifier1 = 173;
uh.pktsize = buffer_size;
uh.modifier2 = 0;
// set the uwsgi header
uh = (struct uwsgi_header *) buffer;
uh->modifier1 = 173;
uh->pktsize = buffer_size;
uh->modifier2 = 0;
// add func to the array
char *bufptr = buffer;
char *bufptr = buffer + 4;
ulen = strlen(func);
*bufptr++ = (uint8_t) (ulen & 0xff);
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
@@ -111,33 +147,33 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
bufptr += ulen;
}
if (write(fd, &uh, 4) != 4) {
uwsgi_error("write()");
close(fd);
free(buffer);
return NULL;
// ok the reuqest is ready, let's send it in non blocking way
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
goto error;
}
if (write(fd, buffer, buffer_size) != buffer_size) {
uwsgi_error("write()");
close(fd);
free(buffer);
return NULL;
}
if (uwsgi_read_response(fd, &uh, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &buffer) < 0) {
close(fd);
free(buffer);
return NULL;
// ok time to wait for the response in non blocking way
size_t rlen = buffer_size+4;
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
goto error;
}
close(fd);
*len = uh.pktsize;
*len = rlen;
if (*len == 0) {
free(buffer);
return NULL;
goto error;
}
return buffer;
error:
close(fd);
free(buffer);
return NULL;
}
void uwsgi_rpc_init() {
uwsgi.rpc_table = uwsgi_calloc_shared((sizeof(struct uwsgi_rpc) * uwsgi.rpc_max) * (uwsgi.numproc+1));
uwsgi.shared->rpc_count = uwsgi_calloc_shared(sizeof(uint64_t) * (uwsgi.numproc+1));
}
+24 -159
View File
@@ -2,173 +2,38 @@
extern struct uwsgi_server uwsgi;
ssize_t uwsgi_sendfile(struct wsgi_request * wsgi_req) {
int fd = wsgi_req->sendfile_fd;
int sockfd = wsgi_req->poll.fd;
struct stat stat_buf;
ssize_t sst = 0;
if (!wsgi_req->sendfile_fd_size) {
if (fstat(fd, &stat_buf)) {
uwsgi_error("fstat()");
goto end;
}
else {
wsgi_req->sendfile_fd_size = stat_buf.st_size;
}
}
if (wsgi_req->sendfile_fd_size) {
if (!wsgi_req->sendfile_fd_chunk)
wsgi_req->sendfile_fd_chunk = 4096;
if (wsgi_req->socket->proto_sendfile) {
sst = wsgi_req->socket->proto_sendfile(wsgi_req);
}
else {
sst = uwsgi_do_sendfile(sockfd, wsgi_req->sendfile_fd, wsgi_req->sendfile_fd_size, wsgi_req->sendfile_fd_chunk, &wsgi_req->sendfile_fd_pos, uwsgi.async);
}
}
end:
return sst;
}
ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk, off_t * pos, int async) {
// sendfile() abstraction
ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
#if defined(__FreeBSD__) || defined(__DragonFly__)
int sf_ret;
off_t sf_len = filesize;
if (async > 1) {
sf_len = chunk;
sf_ret = sendfile(filefd, sockfd, *pos, 0, NULL, &sf_len, 0);
*pos += sf_len;
}
else {
sf_ret = sendfile(filefd, sockfd, 0, 0, NULL, &sf_len, 0);
}
if (sf_ret < 0) {
if (errno != EAGAIN) {
uwsgi_error("sendfile()");
return 0;
}
}
return sf_len;
off_t sf_len = len;
int sf_ret = sendfile(filefd, sockfd, pos, len, NULL, &sf_len, 0);
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
return -1;
#elif defined(__APPLE__)
int sf_ret;
off_t sf_len = filesize;
if (async > 1) {
sf_len = chunk;
sf_ret = sendfile(filefd, sockfd, *pos, &sf_len, NULL, 0);
*pos += sf_len;
}
else {
sf_ret = sendfile(filefd, sockfd, 0, &sf_len, NULL, 0);
}
if (sf_ret) {
#ifdef UWSGI_DEBUG
uwsgi_log("sf_len = %d\n", sf_len);
#endif
uwsgi_error("sendfile()");
return 0;
}
return sf_len;
off_t sf_len = len;
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
return -1;
#elif defined(__linux__) || defined(__sun__)
int sf_ret;
size_t written = 0;
if (async > 1) {
sf_ret = sendfile(sockfd, filefd, pos, chunk);
if (sf_ret < 0) {
uwsgi_error("sendfile()");
return 0;
}
return sf_ret;
}
while (written < filesize) {
sf_ret = sendfile(sockfd, filefd, pos, filesize - written);
if (sf_ret < 0) {
uwsgi_error("sendfile()");
return 0;
}
else if (sf_ret == 0) {
return 0;
}
written += sf_ret;
}
return written;
off_t off = pos;
return sendfile(sockfd, filefd, &off, len);
#else
static size_t nosf_buf_size = 0;
static char *nosf_buf;
char *nosf_buf2;
ssize_t jlen = 0;
ssize_t rlen = 0;
ssize_t i = 0;
if (!nosf_buf) {
nosf_buf = malloc(chunk);
}
else if (chunk != nosf_buf_size) {
nosf_buf2 = realloc(nosf_buf, chunk);
if (!nosf_buf2) {
free(nosf_buf);
// for platform not supporting sendfile we need to rely on boring read/write
// generally that platforms have very low memory, so use a 8k buffer
char buf[8192];
if (pos > 0) {
if (lseek(filefd, pos, SEEK_SET)) {
uwsgi_error("uwsgi_sendfile_do()/seek()");
return -1;
}
nosf_buf = nosf_buf2;
}
if (!nosf_buf) {
uwsgi_error("sendfile malloc()/realloc()");
return 0;
ssize_t rlen = read(filefd, buf, UMIN(len, 8192));
if (rlen <= 0) {
uwsgi_error("uwsgi_sendfile_do()/read()");
return -1;
}
nosf_buf_size = chunk;
if (async > 1) {
jlen = read(filefd, nosf_buf, chunk);
if (jlen <= 0) {
uwsgi_error("read()");
return 0;
}
jlen = write(sockfd, nosf_buf, jlen);
if (jlen <= 0) {
uwsgi_error("write()");
return 0;
}
return jlen;
}
while (i < (int) filesize) {
jlen = read(filefd, nosf_buf, chunk);
if (jlen <= 0) {
uwsgi_error("read()");
break;
}
i += jlen;
jlen = write(sockfd, nosf_buf, jlen);
if (jlen <= 0) {
uwsgi_error("write()");
break;
}
rlen += jlen;
}
return rlen;
return write(sockfd, buf, rlen);
#endif
}
+11 -8
View File
@@ -106,13 +106,11 @@ void uwsgi_setup_inherited_sockets() {
//now close all the unbound fd
for (j = 3; j < (int) uwsgi.max_fd; j++) {
int useless = 1;
#ifdef UWSGI_MULTICAST
if (j == uwsgi.cluster_fd)
continue;
#endif
if (uwsgi.has_emperor) {
if (j == uwsgi.emperor_fd)
continue;
if (j == uwsgi.emperor_fd_config)
continue;
}
if (uwsgi.shared->worker_log_pipe[0] > -1) {
@@ -125,13 +123,18 @@ void uwsgi_setup_inherited_sockets() {
continue;
}
if (uwsgi.original_log_fd > -1) {
if (j == uwsgi.original_log_fd)
if (uwsgi.shared->worker_req_log_pipe[0] > -1) {
if (j == uwsgi.shared->worker_req_log_pipe[0])
continue;
}
if (uwsgi.cache_server && uwsgi.cache_server_fd != -1) {
if (j == uwsgi.cache_server_fd)
if (uwsgi.shared->worker_req_log_pipe[1] > -1) {
if (j == uwsgi.shared->worker_req_log_pipe[1])
continue;
}
if (uwsgi.original_log_fd > -1) {
if (j == uwsgi.original_log_fd)
continue;
}
+27 -12
View File
@@ -6,7 +6,9 @@ int uwsgi_signal_handler(uint8_t sig) {
struct uwsgi_signal_entry *use = NULL;
use = &uwsgi.shared->signal_table[sig];
int pos = (uwsgi.mywid * 256) + sig;
use = &uwsgi.shared->signal_table[pos];
if (!use->handler)
return -1;
@@ -55,13 +57,11 @@ int uwsgi_signal_handler(uint8_t sig) {
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
}
}
#ifdef UWSGI_SPOOLER
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
}
}
#endif
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
@@ -77,20 +77,19 @@ int uwsgi_signal_handler(uint8_t sig) {
set_mule_harakiri(0);
}
}
#ifdef UWSGI_SPOOLER
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(0);
}
}
#endif
return ret;
}
int uwsgi_signal_registered(uint8_t sig) {
if (uwsgi.shared->signal_table[sig].handler != NULL)
int pos = (uwsgi.mywid * 256) + sig;
if (uwsgi.shared->signal_table[pos].handler != NULL)
return 1;
return 0;
@@ -100,15 +99,23 @@ 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.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
uwsgi_log("only the master and the workers can register signal handlers\n");
return -1;
}
if (strlen(receiver) > 63)
return -1;
uwsgi_lock(uwsgi.signal_table_lock);
use = &uwsgi.shared->signal_table[sig];
int pos = (uwsgi.mywid * 256) + sig;
use = &uwsgi.shared->signal_table[pos];
if (use->handler) {
uwsgi_log("[uwsgi-signal] you cannot re-register a signal !!!\n");
if (use->handler && uwsgi.mywid == 0) {
uwsgi_log("[uwsgi-signal] you cannot re-register a signal as the master !!!\n");
uwsgi_unlock(uwsgi.signal_table_lock);
return -1;
}
@@ -125,6 +132,15 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver);
}
// check for cow
if (uwsgi.mywid == 0) {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
int pos = (i * 256);
memcpy(&uwsgi.shared->signal_table[pos], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256);
}
}
uwsgi_unlock(uwsgi.signal_table_lock);
return 0;
@@ -426,7 +442,8 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
void uwsgi_route_signal(uint8_t sig) {
struct uwsgi_signal_entry *use = &ushared->signal_table[sig];
int pos = (uwsgi.mywid * 256) + sig;
struct uwsgi_signal_entry *use = &ushared->signal_table[pos];
int i;
// send to first available worker
@@ -457,7 +474,6 @@ void uwsgi_route_signal(uint8_t sig) {
else if (!strcmp(use->receiver, "subscribed")) {
}
// route to spooler
#ifdef UWSGI_SPOOLER
else if (!strcmp(use->receiver, "spooler")) {
if (ushared->worker_signal_pipe[0] != -1) {
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
@@ -465,7 +481,6 @@ void uwsgi_route_signal(uint8_t sig) {
}
}
}
#endif
else if (!strcmp(use->receiver, "mules")) {
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi_signal_send(uwsgi.mules[i].signal_pipe[0], sig)) {
+15 -6
View File
@@ -1,6 +1,4 @@
#ifdef UWSGI_SNMP
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -408,6 +406,17 @@ int uwsgi_setup_snmp(void) {
return snmp_fd;
}
#else
#warning "*** SNMP support is disabled ***"
#endif
void uwsgi_master_manage_snmp(int snmp_fd) {
struct sockaddr_in udp_client;
socklen_t udp_len = sizeof(udp_client);
ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
if (rlen < 0) {
uwsgi_error("recvfrom()");
}
else if (rlen > 0) {
manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
}
}
+173 -139
View File
@@ -2,6 +2,23 @@
extern struct uwsgi_server uwsgi;
static int uwsgi_socket_strcmp(char *sock1, char *sock2) {
size_t sock1_len = strlen(sock1);
size_t sock2_len = strlen(sock2);
if (!uwsgi_starts_with(sock1, sock1_len, "0.0.0.0:", 8)) {
sock1 += 7;
sock1_len = strlen(sock1);
}
if (!uwsgi_starts_with(sock2, sock2_len, "0.0.0.0:", 8)) {
sock2 += 7;
sock2_len = strlen(sock2);
}
return uwsgi_strncmp(sock1, sock1_len, sock2, sock2_len);
}
char *uwsgi_getsockname(int fd) {
socklen_t socket_type_len = sizeof(struct sockaddr_un);
@@ -49,6 +66,7 @@ int bind_to_unix_dgram(char *socket_name) {
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (unlink(socket_name) != 0 && errno != ENOENT) {
@@ -68,6 +86,7 @@ int bind_to_unix_dgram(char *socket_name) {
#endif
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
return serverfd;
@@ -83,6 +102,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
if (strlen(socket_name) > 102) {
uwsgi_log("invalid socket name\n");
uwsgi_nuclear_blast();
return -1;
}
if (socket_name[0] == '@') {
@@ -96,6 +116,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
if (uws_addr == NULL) {
uwsgi_error("malloc()");
uwsgi_nuclear_blast();
return -1;
}
memset(uws_addr, 0, sizeof(struct sockaddr_un));
@@ -103,6 +124,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (abstract_socket == 0) {
if (unlink(socket_name) != 0 && errno != ENOENT) {
@@ -140,12 +162,14 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
#endif
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
return -1;
}
// chmod unix socket for lazy users
@@ -168,7 +192,6 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
return serverfd;
}
#ifdef UWSGI_UDP
int bind_to_udp(char *socket_name, int multicast, int broadcast) {
int serverfd;
struct sockaddr_in uws_addr;
@@ -176,10 +199,7 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
int bcast = 1;
int reuse = 1;
#ifdef UWSGI_MULTICAST
struct ip_mreq mc;
uint8_t loop = 1;
#endif
udp_port = strchr(socket_name, ':');
if (udp_port == NULL) {
@@ -196,7 +216,6 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
uws_addr.sin_family = AF_INET;
uws_addr.sin_port = htons(atoi(udp_port + 1));
#ifdef UWSGI_MULTICAST
if (!broadcast && !multicast) {
char quad[4];
char *first_part = strchr(socket_name, '.');
@@ -207,9 +226,6 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
multicast = 1;
}
}
#else
if (!broadcast) {
#endif
if (!strcmp(socket_name, "255.255.255.255")) {
broadcast = 1;
}
@@ -236,14 +252,12 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
uwsgi_error("setsockopt()");
}
#ifdef UWSGI_MULTICAST
if (multicast) {
// if multicast is enabled remember to bind to INADDR_ANY
uws_addr.sin_addr.s_addr = INADDR_ANY;
mc.imr_multiaddr.s_addr = inet_addr(socket_name);
mc.imr_interface.s_addr = INADDR_ANY;
}
#endif
if (broadcast) {
if (setsockopt(serverfd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) {
@@ -259,10 +273,9 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
return -1;
}
#ifdef UWSGI_MULTICAST
if (multicast) {
uwsgi_log("[uWSGI] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port));
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) {
uwsgi_log("[uwsgi-mcast] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port));
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &uwsgi.multicast_loop, sizeof(uwsgi.multicast_loop))) {
uwsgi_error("setsockopt()");
}
@@ -275,13 +288,11 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
}
}
#endif
udp_port[0] = ':';
return serverfd;
}
#endif
int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) {
@@ -474,7 +485,7 @@ char *generate_socket_name(char *socket_name) {
}
uwsgi_log("unable to find avalid socket address\n");
uwsgi_log("unable to find a valid socket address\n");
#endif
uwsgi_nuclear_blast();
}
@@ -547,20 +558,40 @@ socklen_t socket_to_in_addr(char *socket_name, char *port, int portn, struct soc
int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
int serverfd;
#ifdef AF_INET6
struct sockaddr_in6 uws_addr;
#else
struct sockaddr_in uws_addr;
#endif
int reuse = 1;
int family = AF_INET;
socklen_t addr_len = sizeof(struct sockaddr_in);
socket_to_in_addr(socket_name, tcp_port, 0, &uws_addr);
#ifdef AF_INET6
if (socket_name[0] == '[' && tcp_port[-1] == ']') {
family = AF_INET6;
socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr);
addr_len = sizeof(struct sockaddr_in6);
}
else {
#endif
socket_to_in_addr(socket_name, tcp_port, 0, (struct sockaddr_in *) &uws_addr);
#ifdef AF_INET6
}
#endif
serverfd = socket(AF_INET, SOCK_STREAM, 0);
serverfd = socket(family, SOCK_STREAM, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEADDR setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
#ifdef __linux__
@@ -571,6 +602,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) {
uwsgi_error("IP_FREEBIND setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
#endif
@@ -580,12 +612,26 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEPORT setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
#else
uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n");
#endif
}
if (uwsgi.tcp_fast_open) {
#ifdef TCP_FASTOPEN
if (setsockopt(serverfd, SOL_TCP, TCP_FASTOPEN, (const void *) &uwsgi.tcp_fast_open, sizeof(int)) < 0) {
uwsgi_error("TCP_FASTOPEN setsockopt()");
}
else {
uwsgi_log("TCP_FASTOPEN enabled on %s\n", socket_name);
}
#else
uwsgi_log("!!! your system does not support TCP_FASTOPEN !!!\n");
#endif
}
if (uwsgi.so_send_timeout) {
struct timeval tv;
tv.tv_sec = uwsgi.so_send_timeout;
@@ -593,6 +639,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(struct timeval)) < 0) {
uwsgi_error("SO_SNDTIMEO setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
@@ -621,25 +668,28 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
}
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
if (bind(serverfd, (struct sockaddr *) &uws_addr, addr_len) != 0) {
if (errno == EADDRINUSE) {
uwsgi_log("probably another instance of uWSGI is running on the same address (%s).\n", socket_name);
}
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
#ifdef __linux__
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn");
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%i).\n", somaxconn);
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
uwsgi_nuclear_blast();
return -1;
}
#endif
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
return -1;
}
@@ -707,7 +757,16 @@ int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_s
}
#endif
ret = connect(fdpoll->fd, addr, addr_size);
#ifdef MSG_FASTOPEN
if (addr->sa_family == AF_INET && uwsgi.tcp_fast_open_client) {
ret = sendto(fdpoll->fd, "", 0, MSG_FASTOPEN, addr, addr_size);
}
else {
#endif
ret = connect(fdpoll->fd, addr, addr_size);
#ifdef MSG_FASTOPEN
}
#endif
if (async) {
if (ret < 0 && errno != EINPROGRESS) {
@@ -718,7 +777,7 @@ int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_s
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
// hmm, nothing to do, as we are already non-blocking
uwsgi_socket_b(fdpoll->fd);
#else
/* re-set blocking socket */
arg &= (~O_NONBLOCK);
@@ -923,6 +982,7 @@ struct uwsgi_socket *uwsgi_new_socket(char *name) {
char *auto_port = uwsgi_num2str(ntohs(sin.sin_port));
char *auto_ip = inet_ntoa(sin.sin_addr);
uwsgi_sock->name = uwsgi_concat3n(auto_ip, strlen(auto_ip), ":", 1, auto_port, strlen(auto_port));
free(auto_port);
}
}
@@ -1042,7 +1102,7 @@ void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) {
}
}
}
#ifdef UWSGI_IPV6
#ifdef AF_INET6
else if (gsa.sa->sa_family == AF_INET6) {
char *computed_addr;
char computed_port[6];
@@ -1358,87 +1418,7 @@ nextsock:
}
#ifdef UWSGI_IPV6
int bind_to_tcp6(char *socket_name, int listen_queue, char *tcp_port) {
int serverfd;
struct sockaddr_in6 uws_addr;
int reuse = 1;
socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr);
serverfd = socket(AF_INET6, SOCK_STREAM, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
uwsgi_nuclear_blast();
}
#ifdef __linux__
#ifdef IP_FREEBIND
if (uwsgi.freebind) {
if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
uwsgi_nuclear_blast();
}
}
#endif
#endif
if (uwsgi.reuse_port) {
#ifdef SO_REUSEPORT
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
uwsgi_nuclear_blast();
}
#else
uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n");
#endif
}
if (!uwsgi.no_defer_accept) {
#ifdef __linux__
if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], sizeof(int))) {
uwsgi_error("setsockopt()");
}
// OSX has no SO_ACCEPTFILTER !!!
#elif defined(__freebsd__)
struct accept_filter_arg afa;
strcpy(afa.af_name, "dataready");
afa.af_arg[0] = 0;
if (setsockopt(serverfd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(struct accept_filter_arg))) {
uwsgi_error("setsockopt()");
}
#endif
}
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
if (errno == EADDRINUSE) {
uwsgi_log("probably another instance of uWSGI is running on the same address.\n");
}
uwsgi_error("bind()");
uwsgi_nuclear_blast();
}
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
}
if (tcp_port)
tcp_port[0] = ':';
return serverfd;
}
#ifdef AF_INET6
socklen_t socket_to_in_addr6(char *socket_name, char *port, int portn, struct sockaddr_in6 * sin_addr) {
memset(sin_addr, 0, sizeof(struct sockaddr_in6));
@@ -1494,9 +1474,9 @@ void uwsgi_setup_shared_sockets() {
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);
}
else {
#ifdef UWSGI_IPV6
#ifdef AF_INET6
if (shared_sock->name[0] == '[' && tcp_port[-1] == ']') {
shared_sock->fd = bind_to_tcp6(shared_sock->name, uwsgi.listen_queue, tcp_port);
shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port);
shared_sock->family = AF_INET6;
// fix socket name
shared_sock->name = uwsgi_getsockname(shared_sock->fd);
@@ -1509,7 +1489,7 @@ void uwsgi_setup_shared_sockets() {
// fix socket name
shared_sock->name = uwsgi_getsockname(shared_sock->fd);
uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
#ifdef UWSGI_IPV6
#ifdef AF_INET6
}
#endif
}
@@ -1528,7 +1508,7 @@ void uwsgi_setup_shared_sockets() {
for (i = 3; i < (int) uwsgi.max_fd; i++) {
char *sock = uwsgi_getsockname(i);
if (sock) {
if (!strcmp(sock, shared_sock->name)) {
if (!uwsgi_socket_strcmp(sock, shared_sock->name)) {
if (strchr(sock, ':')) {
uwsgi_log("uwsgi shared socket %d inherited TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i);
shared_sock->family = AF_INET;
@@ -1539,9 +1519,7 @@ void uwsgi_setup_shared_sockets() {
}
shared_sock->fd = i;
}
else {
free(sock);
}
free(sock);
}
}
}
@@ -1611,7 +1589,7 @@ void uwsgi_map_sockets() {
exit(1);
}
if (fd != uwsgi_sock->fd) {
if (dup2(fd, uwsgi_sock->fd)) {
if (dup2(fd, uwsgi_sock->fd) < 0) {
uwsgi_error("dup2()");
exit(1);
}
@@ -1655,9 +1633,9 @@ void uwsgi_bind_sockets() {
uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
}
else {
#ifdef UWSGI_IPV6
#ifdef AF_INET6
if (uwsgi_sock->name[0] == '[' && tcp_port[-1] == ']') {
uwsgi_sock->fd = bind_to_tcp6(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
uwsgi_log("uwsgi socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
uwsgi_sock->family = AF_INET6;
}
@@ -1666,7 +1644,7 @@ void uwsgi_bind_sockets() {
uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
uwsgi_sock->family = AF_INET;
#ifdef UWSGI_IPV6
#ifdef AF_INET6
}
#endif
}
@@ -1702,14 +1680,14 @@ void uwsgi_bind_sockets() {
gsa.sa = (struct sockaddr *) &usa;
if (!uwsgi.skip_zero && !getsockname(0, gsa.sa, &socket_type_len)) {
if (gsa.sa->sa_family == AF_UNIX) {
uwsgi_sock = uwsgi_new_socket(usa.sa_un.sun_path);
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
uwsgi_sock->family = AF_UNIX;
uwsgi_sock->fd = 0;
uwsgi_sock->bound = 1;
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
}
else {
uwsgi_sock = uwsgi_new_socket(uwsgi_concat2("::", ""));
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
uwsgi_sock->family = AF_INET;
uwsgi_sock->fd = 0;
uwsgi_sock->bound = 1;
@@ -1723,7 +1701,7 @@ void uwsgi_bind_sockets() {
exit(1);
}
if (fd != 0) {
if (dup2(fd, 0)) {
if (dup2(fd, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
@@ -1742,14 +1720,14 @@ void uwsgi_bind_sockets() {
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->auto_port) {
#ifdef UWSGI_IPV6
#ifdef AF_INET6
if (uwsgi_sock->family == AF_INET6) {
uwsgi_log("uwsgi socket %d bound to TCP6 address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
}
else {
#endif
uwsgi_log("uwsgi socket %d bound to TCP address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
#ifdef UWSGI_IPV6
#ifdef AF_INET6
}
#endif
}
@@ -1760,6 +1738,7 @@ void uwsgi_bind_sockets() {
}
void uwsgi_set_sockets_protocols() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
char *requested_protocol = uwsgi_sock->proto_name;
@@ -1781,6 +1760,7 @@ void uwsgi_set_sockets_protocols() {
}
}
setup_proto:
if (!requested_protocol) {
requested_protocol = uwsgi.protocol;
@@ -1789,28 +1769,70 @@ setup_proto:
if (requested_protocol && !strcmp("http", requested_protocol)) {
uwsgi_sock->proto = uwsgi_proto_http_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write;
uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev;
uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header;
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
uwsgi_sock->proto_sendfile = NULL;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
uwsgi_sock->proto_write = uwsgi_proto_base_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
if (uwsgi.offload_threads > 0)
uwsgi_sock->can_offload = 1;
}
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
if (uwsgi.protocol && (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi"))) {
uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] = 1;
}
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_writev = uwsgi_proto_fastcgi_writev;
uwsgi_sock->proto_write_header = uwsgi_proto_fastcgi_write_header;
uwsgi_sock->proto_writev_header = uwsgi_proto_fastcgi_writev_header;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
}
else if (requested_protocol && (!strcmp("fastcgi-nph", requested_protocol) || !strcmp("fcgi-nph", requested_protocol))) {
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
}
else if (requested_protocol && (!strcmp("scgi", requested_protocol) || !strcmp("scgi", requested_protocol))) {
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
uwsgi_sock->proto_write = uwsgi_proto_base_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
}
else if (requested_protocol && (!strcmp("scgi-nph", requested_protocol) || !strcmp("scgi-nph", requested_protocol))) {
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
uwsgi_sock->proto_write = uwsgi_proto_base_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
}
#ifdef UWSGI_ZEROMQ
else if (requested_protocol && !strcmp("zmq", requested_protocol)) {
uwsgi.zeromq = 1;
@@ -1819,11 +1841,13 @@ setup_proto:
else {
uwsgi_sock->proto = uwsgi_proto_uwsgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write;
uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev;
uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header;
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
uwsgi_sock->proto_sendfile = NULL;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
uwsgi_sock->proto_write = uwsgi_proto_base_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
if (uwsgi.offload_threads > 0)
uwsgi_sock->can_offload = 1;
@@ -1834,3 +1858,13 @@ nextsock:
}
void uwsgi_tcp_nodelay(int fd) {
#ifdef TCP_NODELAY
int flag = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
uwsgi_error("uwsgi_tcp_nodelay()/setsockopt()");
}
#endif
}
+12 -7
View File
@@ -1,4 +1,3 @@
#ifdef UWSGI_SPOOLER
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
@@ -97,8 +96,18 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
exit(1);
}
else if (pid == 0) {
signal(SIGALRM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, end_me);
signal(SIGTERM, end_me);
// USR1 will be used to wake up the spooler
uwsgi_unix_signal(SIGUSR1, spooler_wakeup);
signal(SIGUSR2, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
uwsgi.mywid = -1;
uwsgi.mypid = getpid();
uspool->pid = uwsgi.mypid;
@@ -245,7 +254,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
close(fd);
if (!uwsgi.spooler_quiet)
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename);
// and here waiting threads can continue
uwsgi_unlock(uspool->lock);
@@ -538,7 +547,7 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
uspool->tasks++;
if (ret == -2) {
if (!uwsgi.spooler_quiet)
uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, uwsgi_now() - now);
uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now);
destroy_spool(dir, task);
}
// re-spool it
@@ -574,7 +583,3 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
}
}
}
#else
#warning "*** Spooler support is disabled ***"
#endif
+1 -1
View File
@@ -8,7 +8,7 @@ extern struct uwsgi_server uwsgi;
static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) {
// make a copy of the string
if (field_count >= 2) {
int value_len = strlen(fields[1]) + 1;
size_t value_len = strlen(fields[1]) + 1;
char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table);
add_exported_option(uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0);
}
+499
View File
@@ -0,0 +1,499 @@
#include "../uwsgi.h"
#include <openssl/rand.h>
extern struct uwsgi_server uwsgi;
/*
ssl additional datas are retrieved via indexes.
You can create an index with SSL_CTX_get_ex_new_index and
set data in it with SSL_CTX_set_ex_data
*/
void uwsgi_ssl_init(void) {
OPENSSL_config(NULL);
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
uwsgi.ssl_initialized = 1;
}
void uwsgi_ssl_info_cb(SSL const *ssl, int where, int ret) {
if (where & SSL_CB_HANDSHAKE_DONE) {
if (ssl->s3) {
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
}
}
}
int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
return 1;
}
int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
char session_blob[4096];
int len = i2d_SSL_SESSION(sess, NULL);
if (len > 4096) {
if (uwsgi.ssl_verbose) {
uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len);
}
return 0;
}
unsigned char *p = (unsigned char *) session_blob;
i2d_SSL_SESSION(sess, &p);
// ok let's write the value to the cache
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
if (uwsgi_cache_set2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) {
if (uwsgi.ssl_verbose) {
uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len);
}
}
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
return 0;
}
SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) {
uint64_t valsize = 0;
*copy = 0;
uwsgi_rlock(uwsgi.ssl_sessions_cache->lock);
char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize);
if (!value) {
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
if (uwsgi.ssl_verbose) {
uwsgi_log("[uwsgi-ssl] cache miss\n");
}
return NULL;
}
SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize);
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
return sess;
}
void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
if (uwsgi_cache_del2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, 0, 0)) {
if (uwsgi.ssl_verbose) {
uwsgi_log("[uwsgi-ssl] error removing cache item\n");
}
}
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
}
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (!servername) return SSL_TLSEXT_ERR_NOACK;
size_t servername_len = strlen(servername);
struct uwsgi_string_list *usl = uwsgi.sni;
while(usl) {
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
return SSL_TLSEXT_ERR_OK;
}
usl = usl->next;
}
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
while(url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, (char *)servername, servername_len) >= 0) {
SSL_set_SSL_CTX(ssl, url->custom_ptr);
return SSL_TLSEXT_ERR_OK;
}
url = url->next;
}
#endif
if (uwsgi.sni_dir) {
size_t sni_dir_len = strlen(uwsgi.sni_dir);
char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4);
char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4);
char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3);
if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) {
char *client_ca = NULL;
if (uwsgi_file_exists(sni_dir_client_ca)) {
client_ca = sni_dir_client_ca;
}
usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
if (!usl) goto done;
free(sni_dir_cert);
free(sni_dir_key);
free(sni_dir_client_ca);
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername);
return SSL_TLSEXT_ERR_OK;
}
done:
free(sni_dir_cert);
free(sni_dir_key);
free(sni_dir_client_ca);
}
return SSL_TLSEXT_ERR_NOACK;
}
#endif
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
if (!ctx) {
uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
return NULL;
}
// this part is taken from nginx and stud, removing unneeded functionality
// stud (for me) has made the best choice on choosing DH approach
long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
// disable compression (if possibile)
#ifdef SSL_OP_NO_COMPRESSION
ssloptions |= SSL_OP_NO_COMPRESSION;
#endif
// release/reuse buffers as soon as possibile
#ifdef SSL_MODE_RELEASE_BUFFERS
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
SSL_CTX_free(ctx);
return NULL;
}
// this part is based from stud
BIO *bio = BIO_new_file(crt, "r");
if (bio) {
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (dh) {
SSL_CTX_set_tmp_dh(ctx, dh);
DH_free(dh);
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
#ifdef NID_X9_62_prime256v1
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
#endif
#endif
#endif
}
}
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
SSL_CTX_free(ctx);
return NULL;
}
// if ciphers are specified, prefer server ciphers
if (ciphers && strlen(ciphers) > 0) {
if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name);
SSL_CTX_free(ctx);
return NULL;
}
ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
}
// set session context (if possibile), this is required for client certificate authentication
if (name) {
SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name));
}
if (client_ca) {
if (client_ca[0] == '!') {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback);
client_ca++;
}
else {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback);
}
// in the future we should allow to set the verify depth
SSL_CTX_set_verify_depth(ctx, 1);
if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
SSL_CTX_free(ctx);
return NULL;
}
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
if (!list) {
uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
SSL_CTX_free(ctx);
return NULL;
}
SSL_CTX_set_client_CA_list(ctx, list);
}
SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb);
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb);
#endif
// disable session caching by default
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
if (uwsgi.ssl_sessions_use_cache) {
// we need to early initialize locking and caching
uwsgi_setup_locking();
uwsgi_cache_create_all();
uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
if (!uwsgi.ssl_sessions_cache) {
uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
exit(1);
}
if (!uwsgi.ssl_sessions_cache->max_items) {
uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n");
exit(1);
}
if (uwsgi.ssl_sessions_cache->blocksize < 4096) {
uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n");
exit(1);
}
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|
SSL_SESS_CACHE_NO_INTERNAL|
SSL_SESS_CACHE_NO_AUTO_CLEAR);
#ifdef SSL_OP_NO_TICKET
ssloptions |= SSL_OP_NO_TICKET;
#endif
// just for fun
SSL_CTX_sess_set_cache_size(ctx, 0);
// set the callback for ssl sessions
SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb);
SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb);
SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb);
}
SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
SSL_CTX_set_options(ctx, ssloptions);
return ctx;
}
char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) {
// openssl could not be initialized
if (!uwsgi.ssl_initialized) {
uwsgi_ssl_init();
}
*s_len = 0;
EVP_PKEY *pk = NULL;
char *algo = uwsgi_str(algo_key);
char *colon = strchr(algo, ':');
if (!colon) {
uwsgi_log("invalid RSA signature syntax, must be: <digest>:<pemfile>\n");
free(algo);
return NULL;
}
*colon = 0;
char *keyfile = colon + 1;
char *signature = NULL;
FILE *kf = fopen(keyfile, "r");
if (!kf) {
uwsgi_error_open(keyfile);
free(algo);
return NULL;
}
if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) {
uwsgi_log("unable to load private key: %s\n", keyfile);
free(algo);
fclose(kf);
return NULL;
}
fclose(kf);
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
if (!ctx) {
free(algo);
EVP_PKEY_free(pk);
return NULL;
}
const EVP_MD *md = EVP_get_digestbyname(algo);
if (!md) {
uwsgi_log("unknown digest algo: %s\n", algo);
free(algo);
EVP_PKEY_free(pk);
EVP_MD_CTX_destroy(ctx);
return NULL;
}
*s_len = EVP_PKEY_size(pk);
signature = uwsgi_malloc(*s_len);
if (EVP_SignInit_ex(ctx, md, NULL) == 0) {
ERR_print_errors_fp(stderr);
free(signature);
signature = NULL;
*s_len = 0;
goto clear;
}
if (EVP_SignUpdate(ctx, message, message_len) == 0) {
ERR_print_errors_fp(stderr);
free(signature);
signature = NULL;
*s_len = 0;
goto clear;
}
if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) {
ERR_print_errors_fp(stderr);
free(signature);
signature = NULL;
*s_len = 0;
goto clear;
}
clear:
free(algo);
EVP_PKEY_free(pk);
EVP_MD_CTX_destroy(ctx);
return signature;
}
char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
uint16_t i;
char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5);
for (i = strlen(base) + 1; i < (strlen(base) + 1) + keylen; i++) {
if (filename[i] >= '0' && filename[i] <= '9')
continue;
if (filename[i] >= 'A' && filename[i] <= 'Z')
continue;
if (filename[i] >= 'a' && filename[i] <= 'z')
continue;
if (filename[i] == '.')
continue;
if (filename[i] == '-')
continue;
if (filename[i] == '_')
continue;
filename[i] = '_';
}
return filename;
}
char *uwsgi_ssl_rand(size_t len) {
unsigned char *buf = uwsgi_calloc(len+1);
if (RAND_bytes(buf, len) <= 0) {
return NULL;
}
return (char *) buf;
}
char *uwsgi_sha1(char *src, size_t len, char *dst) {
SHA_CTX sha;
SHA1_Init(&sha);
SHA1_Update(&sha, src, len);
SHA1_Final((unsigned char *)dst, &sha);
return dst;
}
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
SHA_CTX sha;
SHA1_Init(&sha);
SHA1_Update(&sha, s1, len1);
SHA1_Update(&sha, s2, len2);
SHA1_Final((unsigned char *)dst, &sha);
return dst;
}
void uwsgi_opt_sni(char *opt, char *value, void *foobar) {
char *client_ca = NULL;
char *v = uwsgi_str(value);
char *space = strchr(v, ' ');
if (!space) {
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
exit(1);
}
*space = 0;
char *crt = space+1;
char *key = strchr(crt, ',');
if (!key) {
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
exit(1);
}
*key = '\0'; key++;
char *ciphers = strchr(key, ',');
if (ciphers) {
*ciphers = '\0'; ciphers++;
client_ca = strchr(ciphers, ',');
if (client_ca) {
*client_ca = '\0'; client_ca++;
}
}
if (!uwsgi.ssl_initialized) {
uwsgi_ssl_init();
}
SSL_CTX *ctx = uwsgi_ssl_new_server_context(v, crt, key, ciphers, client_ca);
if (!ctx) {
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", v);
free(v);
return;
}
#ifdef UWSGI_PCRE
if (!strcmp(opt, "sni-regexp")) {
struct uwsgi_regexp_list *url = uwsgi_regexp_new_list(&uwsgi.sni_regexp, v);
url->custom_ptr = ctx;
}
else {
#endif
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, v);
usl->custom_ptr = ctx;
#ifdef UWSGI_PCRE
}
#endif
}
struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
if (!uwsgi.ssl_initialized) {
uwsgi_ssl_init();
}
SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
if (!ctx) {
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name);
return NULL;
}
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name);
usl->custom_ptr = ctx;
return usl;
}
+623
View File
@@ -0,0 +1,623 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
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;
// check for supported encodings
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
// check for 'all'
if (uwsgi.static_gzip_all) goto gzip;
// 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)) {
goto gzip;
}
usl = usl->next;
}
// 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)) {
goto gzip;
}
usl = usl->next;
}
#ifdef UWSGI_PCRE
// 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) {
goto gzip;
}
url = url->next;
}
#endif
return 0;
gzip:
memcpy(filename + filename_len, ".gz\0", 4);
filename_len += 3;
if (stat(filename, st)) {
filename_len -= 3;
filename[filename_len] = 0;
return 0;
}
return 1;
}
static int set_http_date(time_t t, char *dst) {
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static char *months[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"
};
struct tm *hdtm = gmtime(&t);
int ret = snprintf(dst, 31, "%s, %02d %s %4d %02d:%02d:%02d GMT",
week[hdtm->tm_wday], hdtm->tm_mday, months[hdtm->tm_mon], hdtm->tm_year + 1900, hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
if (ret <= 0 || ret > 31) {
return 0;
}
return ret;
}
// only RFC 1123 is supported
static time_t parse_http_date(char *date, uint16_t len) {
struct tm hdtm;
if (len != 29 && date[3] != ',')
return 0;
hdtm.tm_mday = uwsgi_str2_num(date + 5);
switch (date[8]) {
case 'J':
if (date[9] == 'a') {
hdtm.tm_mon = 0;
break;
}
if (date[9] == 'u') {
if (date[10] == 'n') {
hdtm.tm_mon = 5;
break;
}
if (date[10] == 'l') {
hdtm.tm_mon = 6;
break;
}
return 0;
}
return 0;
case 'F':
hdtm.tm_mon = 1;
break;
case 'M':
if (date[9] != 'a')
return 0;
if (date[10] == 'r') {
hdtm.tm_mon = 2;
break;
}
if (date[10] == 'y') {
hdtm.tm_mon = 4;
break;
}
return 0;
case 'A':
if (date[10] == 'r') {
hdtm.tm_mon = 3;
break;
}
if (date[10] == 'g') {
hdtm.tm_mon = 7;
break;
}
return 0;
case 'S':
hdtm.tm_mon = 8;
break;
case 'O':
hdtm.tm_mon = 9;
break;
case 'N':
hdtm.tm_mon = 10;
break;
case 'D':
hdtm.tm_mon = 11;
break;
default:
return 0;
}
hdtm.tm_year = uwsgi_str4_num(date + 12) - 1900;
hdtm.tm_hour = uwsgi_str2_num(date + 17);
hdtm.tm_min = uwsgi_str2_num(date + 20);
hdtm.tm_sec = uwsgi_str2_num(date + 23);
return timegm(&hdtm);
}
int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type;
time_t now = wsgi_req->start_of_request / 1000000;
// 30+1
char expires[31];
while (udd) {
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
udd = uwsgi.static_expires_type_mtime;
while (udd) {
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
return 0;
}
#ifdef UWSGI_PCRE
int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filename_len, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires;
time_t now = wsgi_req->start_of_request / 1000000;
// 30+1
char expires[31];
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
udd = uwsgi.static_expires_mtime;
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
return 0;
}
int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_path_info;
time_t now = wsgi_req->start_of_request / 1000000;
// 30+1
char expires[31];
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
udd = uwsgi.static_expires_path_info_mtime;
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
return 0;
}
int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri;
time_t now = wsgi_req->start_of_request / 1000000;
// 30+1
char expires[31];
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
udd = uwsgi.static_expires_uri_mtime;
while (udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime + delta, expires);
if (size > 0) {
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
}
return 0;
}
udd = udd->next;
}
return 0;
}
#endif
char *uwsgi_get_mime_type(char *name, int namelen, int *size) {
int i;
int count = 0;
char *ext = NULL;
for (i = namelen - 1; i >= 0; i--) {
if (!isalnum((int) name[i])) {
if (name[i] == '.') {
ext = name + (namelen - count);
break;
}
}
count++;
}
if (!ext)
return NULL;
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
while (udd) {
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
udd->hits++;
// auto optimization
if (udd->prev) {
if (udd->hits > udd->prev->hits) {
struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev;
if (udd_parent) {
udd_parent->next = udd;
}
if (udd->next) {
udd->next->prev = udd_prev;
}
udd_prev->prev = udd;
udd_prev->next = udd->next;
udd->prev = udd_parent;
udd->next = udd_prev;
if (udd->prev == NULL) {
uwsgi.mimetypes = udd;
}
}
}
*size = udd->vallen;
return udd->value;
}
udd = udd->next;
}
return NULL;
}
ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t file_len) {
size_t len = dir_len;
if (len + 1 + file_len > PATH_MAX) {
return -1;
}
if (dir[len - 1] == '/') {
memcpy(dir + len, file, file_len);
dir[len + file_len] = 0;
len += file_len;
}
else {
dir[len] = '/';
memcpy(dir + len + 1, file, file_len);
dir[len + 1 + file_len] = 0;
len += 1 + file_len;
}
return len;
}
static int uwsgi_static_stat(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st, struct uwsgi_string_list **index) {
int ret = stat(filename, st);
// if non-existant return -1
if (ret < 0)
return -1;
if (S_ISREG(st->st_mode))
return 0;
// check for index
if (S_ISDIR(st->st_mode)) {
struct uwsgi_string_list *usl = uwsgi.static_index;
while (usl) {
ssize_t new_len = uwsgi_append_static_path(filename, *filename_len, usl->value, usl->len);
if (new_len >= 0) {
#ifdef UWSGI_DEBUG
uwsgi_log("checking for %s\n", filename);
#endif
if (uwsgi_is_file2(filename, st)) {
*index = usl;
*filename_len = new_len;
return 0;
}
// reset to original name
filename[*filename_len] = 0;
}
usl = usl->next;
}
}
return -1;
}
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
int mime_type_size = 0;
char http_last_modified[49];
if (uwsgi.threads > 1)
pthread_mutex_lock(&uwsgi.lock_static);
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&uwsgi.lock_static);
if (wsgi_req->if_modified_since_len) {
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
if (st->st_mtime <= ims) {
uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16);
return uwsgi_response_write_headers_do(wsgi_req);
}
}
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif
// HTTP status
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
#ifdef UWSGI_PCRE
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
uwsgi_add_expires_path_info(wsgi_req, st);
uwsgi_add_expires_uri(wsgi_req, st);
#endif
// Content-Type (if available)
if (mime_type_size > 0 && mime_type) {
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
// check for content-type related headers
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
}
// increase static requests counter
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;
// nginx
if (uwsgi.file_serve_mode == 1) {
if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
// this is the final header (\r\n added)
int size = set_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
}
// apache
else if (uwsgi.file_serve_mode == 2) {
if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
// this is the final header (\r\n added)
int size = set_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
}
// raw
else {
// here we need to choose if we want the gzip variant;
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
}
// set Content-Length
if (uwsgi_response_add_content_length(wsgi_req, st->st_size)) return -1;
int size = set_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
// if it is a HEAD request just skip transfer
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
wsgi_req->status = 200;
return 0;
}
// Ok, the file must be transferred from uWSGI
// offloading will be automatically managed
int fd = open(real_filename, O_RDONLY);
if (fd < 0) return -1;
// fd will be closed in the following function
uwsgi_response_sendfile_do(wsgi_req, fd, 0, st->st_size);
}
wsgi_req->status = 200;
return 0;
}
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) {
struct stat st;
char real_filename[PATH_MAX + 1];
size_t real_filename_len = 0;
char *filename = NULL;
size_t filename_len = 0;
struct uwsgi_string_list *index = NULL;
if (!is_a_file) {
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
filename_len = document_root_len + 1 + path_info_len;
}
else {
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
filename_len = document_root_len;
}
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
#endif
if (uwsgi.static_cache_paths) {
uwsgi_rlock(uwsgi.static_cache_paths->lock);
uint64_t item_len;
char *item = uwsgi_cache_get2(uwsgi.static_cache_paths, filename, filename_len, &item_len);
if (item && item_len > 0 && item_len <= PATH_MAX) {
memcpy(real_filename, item, item_len);
real_filename_len = item_len;
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
goto found;
}
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
}
if (!realpath(filename, real_filename)) {
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n");
#endif
free(filename);
return -1;
}
real_filename_len = strlen(real_filename);
if (uwsgi.static_cache_paths) {
uwsgi_wlock(uwsgi.static_cache_paths->lock);
uwsgi_cache_set2(uwsgi.static_cache_paths, filename, filename_len, real_filename, real_filename_len, uwsgi.use_static_cache_paths, UWSGI_CACHE_FLAG_UPDATE);
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
}
found:
free(filename);
if (uwsgi_starts_with(real_filename, real_filename_len, document_root, document_root_len)) {
struct uwsgi_string_list *safe = uwsgi.static_safe;
while(safe) {
if (!uwsgi_starts_with(real_filename, real_filename_len, safe->value, safe->len)) {
goto safe;
}
safe = safe->next;
}
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s or a safe path\n", real_filename, document_root_len, document_root);
return -1;
}
safe:
if (!uwsgi_static_stat(wsgi_req, real_filename, &real_filename_len, &st, &index)) {
if (index) {
// if we are here the PATH_INFO need to be changed
if (uwsgi_req_append_path_info_with_index(wsgi_req, index->value, index->len)) {
return -1;
}
}
// skip methods other than GET and HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
return -1;
}
// check for skippable ext
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
while (sse) {
if (real_filename_len >= sse->len) {
if (!uwsgi_strncmp(real_filename + (real_filename_len - sse->len), sse->len, sse->value, sse->len)) {
return -1;
}
}
sse = sse->next;
}
#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) {
return 0;
}
wsgi_req->routes_applied = 1;
#endif
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
return -1;
}
+110 -9
View File
@@ -13,6 +13,7 @@ struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) {
us->chunk = chunk_size;
us->size = chunk_size;
us->tabs = 1;
us->dirty = 0;
us->minified = uwsgi.stats_minified;
if (!us->minified) {
us->base[1] = '\n';
@@ -314,6 +315,45 @@ int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long l
return uwsgi_stats_comma(us);
}
int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) {
if (uwsgi_stats_apply_tabs(us))
return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
if (ret < 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base)
return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
if (ret < 0)
return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keyslong_comma(struct uwsgi_stats *us, char *key, long long num) {
int ret = uwsgi_stats_keyslong(us, key, num);
if (ret)
return -1;
return uwsgi_stats_comma(us);
}
void uwsgi_send_stats(int fd, struct uwsgi_stats *(*func) (void)) {
struct sockaddr_un client_src;
@@ -373,7 +413,7 @@ struct uwsgi_stats_pusher *uwsgi_stats_pusher_get(char *name) {
return usp;
}
void uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
struct uwsgi_stats_pusher_instance *old_uspi = NULL, *uspi = uwsgi.stats_pusher_instances;
while (uspi) {
old_uspi = uspi;
@@ -382,13 +422,18 @@ void uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
uspi = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_instance));
uspi->pusher = pusher;
uspi->arg = arg;
if (arg) {
uspi->arg = uwsgi_str(arg);
}
uspi->raw = pusher->raw;
if (old_uspi) {
old_uspi->next = uspi;
}
else {
uwsgi.stats_pusher_instances = uspi;
}
return uspi;
}
void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
@@ -413,12 +458,17 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
while (uspi) {
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
if ((uspi->last_run + delta) <= now) {
if (!us) {
us = uwsgi_master_generate_stats();
if (!us)
goto next;
if (uspi->raw) {
uspi->pusher->func(uspi, now, NULL, 0);
}
else {
if (!us) {
us = uwsgi_master_generate_stats();
if (!us)
goto next;
}
uspi->pusher->func(uspi, now, us->base, us->pos);
}
uspi->pusher->func(uspi, us->base, us->pos);
uspi->last_run = now;
}
next:
@@ -444,6 +494,7 @@ void uwsgi_stats_pusher_setup() {
pusher = uwsgi_stats_pusher_get(ssp);
if (!pusher) {
uwsgi_log("unable to find \"%s\" stats_pusher\n", ssp);
free(ssp);
exit(1);
}
char *arg = NULL;
@@ -453,10 +504,11 @@ void uwsgi_stats_pusher_setup() {
}
uwsgi_stats_pusher_add(pusher, arg);
usl = usl->next;
free(ssp);
}
}
void uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, char *, size_t)) {
struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, time_t, char *, size_t)) {
struct uwsgi_stats_pusher *pusher = uwsgi.stats_pushers, *old_pusher = NULL;
@@ -475,6 +527,8 @@ void uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pu
else {
uwsgi.stats_pushers = pusher;
}
return pusher;
}
struct uwsgi_stats_pusher_file_conf {
@@ -483,7 +537,7 @@ struct uwsgi_stats_pusher_file_conf {
char *separator;
};
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *json, size_t json_len) {
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
if (!uspi->configured) {
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
@@ -520,3 +574,50 @@ void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *jso
close(fd);
}
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
if (us->dirty) return;
uint16_t i;
// replace " with '
for(i=0;i<kl;i++) {
if (k[i] == '"') {
k[i] = '\'';
}
}
for(i=0;i<vl;i++) {
if (v[i] == '"') {
v[i] = '\'';
}
}
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
if (uwsgi_stats_str(us, var)) {
us->dirty = 1;
free(var);
return;
}
free(var);
if (uwsgi_stats_comma(us)) {
us->dirty = 1;
}
return;
}
int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) {
if (!uc->in_request) return 0;
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi.workers[0].cores[0].buffer;
uint16_t pktsize = uh->pktsize;
if (!pktsize) return 0;
char *dst = uwsgi.workers[0].cores[0].buffer;
memcpy(dst, uc->buffer+4, uwsgi.buffer_size);
// ok now check if something changed...
if (!uc->in_request) return 0;
if (uh->pktsize != pktsize) return 0;
if (memcmp(dst, uc->buffer+4, uwsgi.buffer_size)) return 0;
// nothing changed let's dump vars
int ret = uwsgi_hooked_parse(dst, pktsize, stats_dump_var, us);
if (ret) return -1;
if (us->dirty) return -1;
if (uwsgi_stats_str(us, "")) return -1;
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
#include "../uwsgi.h"
/*
Storage subsystem: filesystem-like abstraction
struct uwsgi_storage_engine {
char *name;
uint16_t name_len;
int64_t (*get)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
int64_t (*set)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
};
struct uwsgi_storage {
char *name;
uint16_t name_len;
struct uwsgi_storage_engine *engine;
};
*/
struct uwsgi_storage* uwsgi_storage_by_name(char *name, uint16_t name_len) {
if (!name_len) {
name_len = strlen(name);
}
struct uwsgi_storage *s = uwsgi.virtualdisks;
while(s) {
if (!uwsgi_strncmp(s->name, s->name_len, name, name_len)) {
return s;
}
s = s->next;
}
return NULL;
}
int64_t uwsgi_storage_get(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *out_buf, uint64_t pos, uint64_t size, uint64_t flags) {
if (!storage->get) return -1;
return storage->get(key, key_len, out_buf, pos, size, flags);
}
int64_t uwsgi_storage_set(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *in_buf, uint64_t pos, uint64_t size, uint64_t flags) {
if (!storage->set) return -1;
return storage->set(key, key_len, out_buf, pos, size, flags);
}
+340
View File
@@ -0,0 +1,340 @@
#include <uwsgi.h>
// check if a string_list contains an item
struct uwsgi_string_list *uwsgi_string_list_has_item(struct uwsgi_string_list *list, char *key, size_t keylen) {
struct uwsgi_string_list *usl = list;
while (usl) {
if (keylen == usl->len) {
if (!memcmp(key, usl->value, keylen)) {
return usl;
}
}
usl = usl->next;
}
return NULL;
}
// lower a string
char *uwsgi_lower(char *str, size_t size) {
size_t i;
for (i = 0; i < size; i++) {
str[i] = tolower((int) str[i]);
}
return str;
}
// check if a string is contained in another one
char *uwsgi_str_contains(char *str, int slen, char what) {
int i;
for (i = 0; i < slen; i++) {
if (str[i] == what) {
return str + i;
}
}
return NULL;
}
int uwsgi_contains_n(char *s1, size_t s1_len, char *s2, size_t s2_len) {
size_t i;
char *ptr = s2;
for (i = 0; i < s1_len; i++) {
if (s1[i] == *ptr) {
ptr++;
if (ptr == s2 + s2_len) {
return 1;
}
}
else {
ptr = s2;
}
}
return 0;
}
// fast compare 2 sized strings
int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
if (slen != dlen)
return 1;
return memcmp(src, dst, dlen);
}
// fast compare 2 sized strings (case insensitive)
int uwsgi_strnicmp(char *src, int slen, char *dst, int dlen) {
if (slen != dlen)
return 1;
return strncasecmp(src, dst, dlen);
}
// fast sized check of initial part of a string
int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
if (slen < dlen)
return -1;
return memcmp(src, dst, dlen);
}
// unsized check
int uwsgi_startswith(char *src, char *what, int wlen) {
int i;
for (i = 0; i < wlen; i++) {
if (src[i] != what[i])
return -1;
}
return 0;
}
// concatenate strings
char *uwsgi_concatn(int c, ...) {
va_list s;
char *item;
int j = c;
char *buf;
size_t len = 1;
size_t tlen = 1;
va_start(s, c);
while (j > 0) {
item = va_arg(s, char *);
if (item == NULL) {
break;
}
len += va_arg(s, int);
j--;
}
va_end(s);
buf = uwsgi_malloc(len);
memset(buf, 0, len);
j = c;
len = 0;
va_start(s, c);
while (j > 0) {
item = va_arg(s, char *);
if (item == NULL) {
break;
}
tlen = va_arg(s, int);
memcpy(buf + len, item, tlen);
len += tlen;
j--;
}
va_end(s);
return buf;
}
char *uwsgi_concat2(char *one, char *two) {
char *buf;
size_t len = strlen(one) + strlen(two) + 1;
buf = uwsgi_malloc(len);
buf[len - 1] = 0;
memcpy(buf, one, strlen(one));
memcpy(buf + strlen(one), two, strlen(two));
return buf;
}
char *uwsgi_concat4(char *one, char *two, char *three, char *four) {
char *buf;
size_t len = strlen(one) + strlen(two) + strlen(three) + strlen(four) + 1;
buf = uwsgi_malloc(len);
buf[len - 1] = 0;
memcpy(buf, one, strlen(one));
memcpy(buf + strlen(one), two, strlen(two));
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
memcpy(buf + strlen(one) + strlen(two) + strlen(three), four, strlen(four));
return buf;
}
char *uwsgi_concat3(char *one, char *two, char *three) {
char *buf;
size_t len = strlen(one) + strlen(two) + strlen(three) + 1;
buf = uwsgi_malloc(len);
buf[len - 1] = 0;
memcpy(buf, one, strlen(one));
memcpy(buf + strlen(one), two, strlen(two));
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
return buf;
}
char *uwsgi_concat2n(char *one, int s1, char *two, int s2) {
char *buf;
size_t len = s1 + s2 + 1;
buf = uwsgi_malloc(len);
buf[len - 1] = 0;
memcpy(buf, one, s1);
memcpy(buf + s1, two, s2);
return buf;
}
char *uwsgi_concat2nn(char *one, int s1, char *two, int s2, int *len) {
char *buf;
*len = s1 + s2 + 1;
buf = uwsgi_malloc(*len);
buf[*len - 1] = 0;
memcpy(buf, one, s1);
memcpy(buf + s1, two, s2);
return buf;
}
char *uwsgi_concat3n(char *one, int s1, char *two, int s2, char *three, int s3) {
char *buf;
size_t len = s1 + s2 + s3 + 1;
buf = uwsgi_malloc(len);
buf[len - 1] = 0;
memcpy(buf, one, s1);
memcpy(buf + s1, two, s2);
memcpy(buf + s1 + s2, three, s3);
return buf;
}
char *uwsgi_concat4n(char *one, int s1, char *two, int s2, char *three, int s3, char *four, int s4) {
char *buf;
size_t len = s1 + s2 + s3 + s4 + 1;
buf = uwsgi_malloc(len);
buf[len - 1] = 0;
memcpy(buf, one, s1);
memcpy(buf + s1, two, s2);
memcpy(buf + s1 + s2, three, s3);
memcpy(buf + s1 + s2 + s3, four, s4);
return buf;
}
// concat unsized strings
char *uwsgi_concat(int c, ...) {
va_list s;
char *item;
size_t len = 1;
int j = c;
char *buf;
va_start(s, c);
while (j > 0) {
item = va_arg(s, char *);
if (item == NULL) {
break;
}
len += (int) strlen(item);
j--;
}
va_end(s);
buf = uwsgi_malloc(len);
memset(buf, 0, len);
j = c;
len = 0;
va_start(s, c);
while (j > 0) {
item = va_arg(s, char *);
if (item == NULL) {
break;
}
memcpy(buf + len, item, strlen(item));
len += strlen(item);
j--;
}
va_end(s);
return buf;
}
char *uwsgi_strncopy(char *s, int len) {
char *buf;
buf = uwsgi_malloc(len + 1);
buf[len] = 0;
memcpy(buf, s, len);
return buf;
}
// this move a string back of one char and put a 0 at the end (used in uwsgi parsers for buffer reusing)
char *uwsgi_cheap_string(char *buf, int len) {
int i;
char *cheap_buf = buf - 1;
for (i = 0; i < len; i++) {
*cheap_buf++ = buf[i];
}
buf[len - 1] = 0;
return buf - 1;
}
+254 -176
View File
@@ -91,7 +91,7 @@ static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_sub
if (min_rc == 0 || node->reference < min_rc) {
min_rc = node->reference;
choosen_node = node;
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->requests <= node->requests))
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->last_requests <= node->last_requests))
break;
}
}
@@ -125,7 +125,7 @@ static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_su
if (min_rc == 0 || ref < min_rc) {
min_rc = ref;
choosen_node = node;
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->requests <= node->requests))
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->last_requests <= node->last_requests))
break;
}
}
@@ -376,6 +376,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->weight = usr->weight;
if (!node->weight)
node->weight = 1;
node->last_requests = 0;
return node;
}
old_node = node;
@@ -394,6 +395,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->modifier1 = usr->modifier1;
node->modifier2 = usr->modifier2;
node->requests = 0;
node->last_requests = 0;
node->transferred = 0;
node->reference = 0;
node->death_mark = 0;
@@ -470,6 +472,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->nodes->len = usr->address_len;
current_slot->nodes->reference = 0;
current_slot->nodes->requests = 0;
current_slot->nodes->last_requests = 0;
current_slot->nodes->transferred = 0;
current_slot->nodes->death_mark = 0;
current_slot->nodes->failcnt = 0;
@@ -514,31 +517,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
// TODO rewrite it using uwsgi buffers
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign) {
char value_cores[sizeof(UMAX64_STR) + 1];
char value_load[sizeof(UMAX64_STR) + 1];
char value_weight[sizeof(UMAX64_STR) + 1];
int value_cores_size = uwsgi_long2str2n(uwsgi.numproc * uwsgi.cores, value_cores, sizeof(UMAX64_STR));
int value_load_size = uwsgi_long2str2n(uwsgi.shared->load, value_load, sizeof(UMAX64_STR));
int value_weight_size = 0;
if (uwsgi.auto_weight) {
value_weight_size = uwsgi_long2str2n(uwsgi.numproc * uwsgi.cores, value_weight, sizeof(UMAX64_STR));
}
else {
value_weight_size = uwsgi_long2str2n(uwsgi.weight, value_weight, sizeof(UMAX64_STR));
}
char value_modifier1[4];
char value_modifier2[4];
int value_modifier1_size = uwsgi_long2str2n(modifier1, value_modifier1, 3);
int value_modifier2_size = uwsgi_long2str2n(modifier2, value_modifier2, 3);
if (socket_name == NULL && !uwsgi.sockets)
return;
@@ -546,173 +526,44 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
socket_name = uwsgi.sockets->name;
}
size_t ssb_size = 4 + (2 + 3) + (2 + keysize) + (2 + 7) + (2 + strlen(socket_name)) + (2 + 9 + 2 + value_modifier1_size) + (2 + 9 + 2 + value_modifier2_size) + (2 + 5 + 2 + value_cores_size) + (2 + 4 + 2 + value_load_size) + (2 + 6 + 2 + value_weight_size);
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
char *subscrbuf = uwsgi_malloc(ssb_size);
// leave space for uwsgi header
char *ssb = subscrbuf + 4;
// make space for uwsgi header
ub->pos = 4;
// key = "domain"
uint16_t ustrlen = 3;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "key", ustrlen);
ssb += ustrlen;
ustrlen = keysize;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, key, ustrlen);
ssb += ustrlen;
// address = "first uwsgi socket"
ustrlen = 7;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "address", ustrlen);
ssb += ustrlen;
ustrlen = strlen(socket_name);
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, socket_name, ustrlen);
ssb += ustrlen;
// modifier1 = "modifier1"
ustrlen = 9;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "modifier1", ustrlen);
ssb += ustrlen;
ustrlen = value_modifier1_size;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, value_modifier1, value_modifier1_size);
ssb += ustrlen;
// modifier2 = "modifier2"
ustrlen = 9;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "modifier2", ustrlen);
ssb += ustrlen;
ustrlen = value_modifier2_size;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, value_modifier2, value_modifier2_size);
ssb += ustrlen;
// cores = uwsgi.numproc * uwsgi.cores
ustrlen = 5;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "cores", ustrlen);
ssb += ustrlen;
ustrlen = value_cores_size;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, value_cores, value_cores_size);
ssb += ustrlen;
// load
ustrlen = 4;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "load", ustrlen);
ssb += ustrlen;
ustrlen = value_load_size;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, value_load, value_load_size);
ssb += ustrlen;
// weight
ustrlen = 6;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "weight", ustrlen);
ssb += ustrlen;
ustrlen = value_weight_size;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, value_weight, value_weight_size);
ssb += ustrlen;
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end;
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end;
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end;
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end;
if (uwsgi.auto_weight) {
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores )) goto end;
}
else {
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight )) goto end;
}
#ifdef UWSGI_SSL
if (sign) {
// add space for "unix" item
char unix_dst[sizeof(UMAX64_STR) + 1];
if (snprintf(unix_dst, sizeof(UMAX64_STR) + 1, "%lu", (unsigned long) (uwsgi_now() + (time_t) cmd)) < 1) {
uwsgi_error("unable to generate unix time for subscription !!!\n");
free(subscrbuf);
return;
}
ssb_size += 2 + 4 + 2 + strlen(unix_dst);
char *new_buf = realloc(subscrbuf, ssb_size);
if (!new_buf) {
uwsgi_error("realloc()");
free(subscrbuf);
return;
}
// fix ssb (new_buf base could be changed)
ssb = (new_buf + (ssb - subscrbuf));
subscrbuf = new_buf;
ustrlen = 4;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "unix", ustrlen);
ssb += ustrlen;
ustrlen = strlen(unix_dst);
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, unix_dst, strlen(unix_dst));
ssb += ustrlen;
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd) )) goto end;
unsigned int signature_len = 0;
char *signature = uwsgi_rsa_sign(sign, subscrbuf + 4, ssb_size - 4, &signature_len);
char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len);
if (signature && signature_len > 0) {
// add space for "sign" item
ssb_size += 2 + 4 + 2 + signature_len;
char *new_buf = realloc(subscrbuf, ssb_size);
if (!new_buf) {
uwsgi_error("realloc()");
if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) {
free(signature);
free(subscrbuf);
return;
goto end;
}
// fix ssb (new_buf base could be changed)
ssb = (new_buf + (ssb - subscrbuf));
subscrbuf = new_buf;
ustrlen = 4;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, "sign", ustrlen);
ssb += ustrlen;
ustrlen = signature_len;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(ssb, signature, signature_len);
ssb += ustrlen;
free(signature);
}
}
#endif
send_udp_message(224, cmd, udp_address, subscrbuf, ssb_size - 4);
free(subscrbuf);
send_udp_message(224, cmd, udp_address, ub->buf, ub->pos - 4);
end:
uwsgi_buffer_destroy(ub);
}
@@ -756,3 +607,230 @@ struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
}
return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
}
void uwsgi_subscribe(char *subscription, uint8_t cmd) {
size_t subfile_size;
size_t i;
char *key = NULL;
int keysize = 0;
char *modifier1 = NULL;
int modifier1_len = 0;
char *socket_name = NULL;
char *udp_address = subscription;
char *udp_port = NULL;
char *subscription_key = NULL;
char *sign = NULL;
// check for explicit socket_name
char *equal = strchr(subscription, '=');
if (equal) {
socket_name = subscription;
if (socket_name[0] == '=') {
equal = strchr(socket_name + 1, '=');
if (!equal)
return;
*equal = '\0';
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
if (!us)
return;
socket_name = us->name;
}
*equal = '\0';
udp_address = equal + 1;
}
// check for unix socket
if (udp_address[0] != '/') {
udp_port = strchr(udp_address, ':');
if (!udp_port) {
if (equal)
*equal = '=';
return;
}
subscription_key = strchr(udp_port + 1, ':');
}
else {
subscription_key = strchr(udp_address + 1, ':');
}
if (!subscription_key) {
if (equal)
*equal = '=';
return;
}
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
if (subscription_key[1] == '@') {
if (!uwsgi_file_exists(subscription_key + 2))
goto clear;
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
if (subfile_size > 0) {
key = lines;
for (i = 0; i < subfile_size; i++) {
if (lines[i] == 0) {
if (keysize > 0) {
if (key[0] != '#' && key[0] != '\n') {
modifier1 = strchr(key, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
modifier1_len = strlen(modifier1);
keysize = strlen(key);
}
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
modifier1 = NULL;
modifier1_len = 0;
}
}
break;
}
else if (lines[i] == '\n') {
if (keysize > 0) {
if (key[0] != '#' && key[0] != '\n') {
lines[i] = 0;
modifier1 = strchr(key, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
modifier1_len = strlen(modifier1);
keysize = strlen(key);
}
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
modifier1 = NULL;
modifier1_len = 0;
lines[i] = '\n';
}
}
key = lines + i + 1;
keysize = 0;
continue;
}
keysize++;
}
free(lines);
}
}
else {
modifier1 = strchr(subscription_key + 1, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
sign = strchr(modifier1 + 1, ',');
if (sign) {
*sign = 0;
sign++;
}
modifier1_len = strlen(modifier1);
}
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
if (modifier1)
modifier1[-1] = ',';
if (sign)
sign[-1] = ',';
}
clear:
if (equal)
*equal = '=';
free(udp_address);
}
void uwsgi_subscribe2(char *arg, uint8_t cmd) {
char *s2_server = NULL;
char *s2_key = NULL;
char *s2_socket = NULL;
char *s2_addr = NULL;
char *s2_weight = NULL;
char *s2_sign = NULL;
char *s2_modifier1 = NULL;
char *s2_modifier2 = NULL;
char *s2_check = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"server", &s2_server,
"key", &s2_key,
"socket", &s2_socket,
"addr", &s2_addr,
"weight", &s2_weight,
"modifier1", &s2_modifier1,
"modifier2", &s2_modifier2,
"sign", &s2_sign,
"check", &s2_check,
NULL)) {
return;
}
if (!s2_server || !s2_key) goto end;
if (s2_check) {
if (uwsgi_file_exists(s2_check)) goto end;
}
if (s2_weight) {
uwsgi.weight = atoi(s2_weight);
}
if (s2_socket) {
struct uwsgi_socket *us = uwsgi_get_socket_by_num(atoi(s2_socket));
if (us) {
if (s2_addr) {
free(s2_addr);
}
s2_addr = uwsgi_str(us->name);
}
}
uint8_t modifier1 = 0;
uint8_t modifier2 = 0;
if (s2_modifier1) {
modifier1 = atoi(s2_modifier1);
}
if (s2_modifier2) {
modifier2 = atoi(s2_modifier2);
}
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign);
end:
if (s2_server) free(s2_server);
if (s2_key) free(s2_key);
if (s2_socket) free(s2_socket);
if (s2_addr) free(s2_addr);
if (s2_weight) free(s2_weight);
if (s2_modifier1) free(s2_modifier1);
if (s2_modifier2) free(s2_modifier2);
if (s2_sign) free(s2_sign);
if (s2_check) free(s2_check);
}
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
// -- subscribe
struct uwsgi_string_list *subscriptions = uwsgi.subscriptions;
while (subscriptions) {
if (verbose) {
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
}
uwsgi_subscribe(subscriptions->value, cmd);
subscriptions = subscriptions->next;
}
// --subscribe2
subscriptions = uwsgi.subscriptions2;
while (subscriptions) {
if (verbose) {
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
}
uwsgi_subscribe2(subscriptions->value, cmd);
subscriptions = subscriptions->next;
}
}
+56
View File
@@ -0,0 +1,56 @@
#include <uwsgi.h>
/*
uWSGI timebomb
this is a simple thread waiting for a timeout and calling exit
with the specified value.
You can use it as a last resort in async apps that could block
normal uWSGI behaviours
*/
struct time_bomb {
int timeout;
int exit_code;
};
static void *time_bomb(void *arg) {
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
struct time_bomb *tb = (struct time_bomb *) arg;
struct timeval tv;
tv.tv_sec = tb->timeout;
tv.tv_usec = 0;
select(0, NULL, NULL, NULL, &tv);
uwsgi_log_verbose("*** BOOOOOOM ***\n");
exit(tb->exit_code);
}
void uwsgi_time_bomb(int timeout, int exit_code) {
pthread_t time_bomb_thread;
struct time_bomb *tb = uwsgi_malloc(sizeof(struct time_bomb));
tb->timeout = timeout;
tb->exit_code = exit_code;
if (pthread_create(&time_bomb_thread, NULL, time_bomb, (void *) tb)) {
uwsgi_error("pthread_create()");
uwsgi_log("unable to setup the time bomb, goodbye\n");
exit(exit_code);
}
else {
uwsgi_log_verbose("Fire in the hole !!! (%d seconds to detonation)\n", timeout);
}
}
+551 -1767
View File
File diff suppressed because it is too large Load Diff
+418 -343
View File
File diff suppressed because it is too large Load Diff
+359
View File
@@ -0,0 +1,359 @@
#include "uwsgi.h"
/*
uWSGI websockets functions
sponsored by 20Tab S.r.l. <info@20tab.com>
*/
extern struct uwsgi_server uwsgi;
static struct uwsgi_buffer *uwsgi_websocket_message(char *msg, size_t len) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(10 + len);
if (uwsgi_buffer_u8(ub, 0x81)) goto error;
if (len < 126) {
if (uwsgi_buffer_u8(ub, len)) goto error;
}
else if (len <= (uint16_t) 0xffff) {
if (uwsgi_buffer_u8(ub, 126)) goto error;
if (uwsgi_buffer_u16be(ub, len)) goto error;
}
else {
if (uwsgi_buffer_u8(ub, 127)) goto error;
if (uwsgi_buffer_u64be(ub, len)) goto error;
}
if (uwsgi_buffer_append(ub, msg, len)) goto error;
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
static int uwsgi_websockets_ping(struct wsgi_request *wsgi_req) {
if (uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_ping->buf, uwsgi.websockets_ping->pos)) {
return -1;
}
wsgi_req->websocket_last_ping = uwsgi_now();
return 0;
}
static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) {
return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos);
}
static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
time_t now = uwsgi_now();
// first round
if (wsgi_req->websocket_last_ping == 0) {
return uwsgi_websockets_ping(wsgi_req);
}
// pong not received ?
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
return -1;
}
return 0;
}
// pong received, send anther ping
if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
return uwsgi_websockets_ping(wsgi_req);
}
return 0;
}
static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len) {
struct uwsgi_buffer *ub = uwsgi_websocket_message(msg, len);
if (!ub) return -1;
ssize_t ret = uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
return ret;
}
int uwsgi_websocket_send(struct wsgi_request *wsgi_req, char *msg, size_t len) {
if (wsgi_req->websocket_closed) {
return -1;
}
ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len);
if (ret < 0) {
wsgi_req->websocket_closed = 1;
}
return ret;
}
static void uwsgi_websocket_parse_header(struct wsgi_request *wsgi_req) {
uint8_t byte1 = wsgi_req->websocket_buf->buf[0];
uint8_t byte2 = wsgi_req->websocket_buf->buf[1];
wsgi_req->websocket_opcode = byte1 & 0xf;
wsgi_req->websocket_has_mask = byte2 >> 7;
wsgi_req->websocket_size = byte2 & 0x7f;
}
static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) {
// de-mask buffer
uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size));
size_t i;
if (wsgi_req->websocket_has_mask) {
uint8_t *mask = ptr-4;
for(i=0;i<wsgi_req->websocket_size;i++) {
ptr[i] = ptr[i] ^ mask[i%4];
}
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(wsgi_req->websocket_size);
if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error;
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error;
wsgi_req->websocket_phase = 0;
wsgi_req->websocket_need = 2;
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb) {
int ret = -1;
for(;;) {
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
if (rlen > 0) return rlen;
if (rlen == 0) return -1;
if (rlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
if (nb) {
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
return -1;
}
return 0;
}
goto wait;
}
uwsgi_error("uwsgi_websockets_recv_pkt()");
return -1;
}
wait:
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.websockets_ping_freq);
if (ret > 0) {
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
if (rlen > 0) return rlen;
if (rlen <= 0) return -1;
}
if (ret < 0) {
uwsgi_error("uwsgi_websockets_recv_pkt()");
return -1;
}
// send unsolicited pong
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
return -1;
}
}
return -1;
}
static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) {
if (!wsgi_req->websocket_buf) {
// this buffer will be destroyed on connection close
wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size);
// need 2 byte header
wsgi_req->websocket_need = 2;
}
for(;;) {
size_t remains = wsgi_req->websocket_buf->pos;
// i have data;
if (remains >= wsgi_req->websocket_need) {
switch(wsgi_req->websocket_phase) {
// header
case 0:
uwsgi_websocket_parse_header(wsgi_req);
wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4);
if (wsgi_req->websocket_size == 126) {
wsgi_req->websocket_need += 2;
wsgi_req->websocket_phase = 1;
wsgi_req->websocket_pktsize += 2;
}
else if (wsgi_req->websocket_size == 127) {
wsgi_req->websocket_need += 8;
wsgi_req->websocket_phase = 1;
wsgi_req->websocket_pktsize += 8;
}
else {
wsgi_req->websocket_phase = 2;
}
break;
// size
case 1:
if (wsgi_req->websocket_size == 126) {
wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2);
}
else if (wsgi_req->websocket_size == 127) {
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
}
else {
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
return NULL;
}
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
return NULL;
}
wsgi_req->websocket_phase = 2;
break;
// mask check
case 2:
if (wsgi_req->websocket_has_mask) {
wsgi_req->websocket_need += 4;
wsgi_req->websocket_phase = 3;
}
else {
wsgi_req->websocket_need += wsgi_req->websocket_size;
wsgi_req->websocket_phase = 4;
}
break;
// mask
case 3:
wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
wsgi_req->websocket_need += wsgi_req->websocket_size;
wsgi_req->websocket_phase = 4;
break;
// message
case 4:
switch (wsgi_req->websocket_opcode) {
// message
case 0:
case 1:
case 2:
return uwsgi_websockets_parse(wsgi_req);
// close
case 0x8:
return NULL;
// ping
case 0x9:
if (uwsgi_websockets_pong(wsgi_req)) {
return NULL;
}
break;
// pong
case 0xA:
wsgi_req->websocket_last_pong = uwsgi_now();
break;
default:
break;
}
// reset the status
wsgi_req->websocket_phase = 0;
wsgi_req->websocket_need = 2;
// decapitate the buffer
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL;
break;
// oops
default:
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
return NULL;
}
}
// need more data
else {
if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL;
ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb);
if (len <= 0) {
if (nb == 1 && len == 0) {
// return an empty buffer to signal blocking event
return uwsgi_buffer_new(0);
}
return NULL;
}
// update buffer size
wsgi_req->websocket_buf->pos+=len;
}
}
return NULL;
}
struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *wsgi_req) {
if (wsgi_req->websocket_closed) {
return NULL;
}
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 0);
if (!ub) {
wsgi_req->websocket_closed = 1;
}
return ub;
}
struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *wsgi_req) {
if (wsgi_req->websocket_closed) {
return NULL;
}
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 1);
if (!ub) {
wsgi_req->websocket_closed = 1;
}
return ub;
}
ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
ssize_t len = wsgi_req->socket->proto_write(wsgi_req, ub->buf, ub->pos);
if (wsgi_req->write_errors > 0) {
return -1;
}
return len;
}
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
#ifdef UWSGI_SSL
char sha1[20];
if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
if (origin_len > 0) {
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
}
else {
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
}
// generate websockets sha1 and encode it to base64
if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
size_t b64_len = 0;
char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
if (!b64) return -1;
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
free(b64);
return -1;
}
free(b64);
wsgi_req->websocket_last_pong = uwsgi_now();
return uwsgi_response_write_headers_do(wsgi_req);
#else
uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
return -1;
#endif
}
void uwsgi_websockets_init() {
uwsgi.websockets_pong = uwsgi_buffer_new(2);
uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2);
uwsgi.websockets_ping = uwsgi_buffer_new(2);
uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2);
uwsgi.websockets_ping_freq = 30;
uwsgi.websockets_pong_tolerance = 3;
uwsgi.websockets_max_size = 1024;
}
+312
View File
@@ -0,0 +1,312 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
}
// status could be NNN or NNN message
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1;
if (!wsgi_req->headers) {
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
wsgi_req->headers->limit = UMAX16;
}
// reset the buffer (could be useful for rollbacks...)
wsgi_req->headers->pos = 0;
struct uwsgi_buffer *hh = NULL;
if (status_len <= 4) {
char *new_sc = NULL;
size_t new_sc_len = 0;
uint16_t sc_len = 0;
const char *sc = uwsgi_http_status_msg(status, &sc_len);
if (sc) {
new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len);
new_sc_len = 4+sc_len;
}
else {
new_sc = uwsgi_concat2n(status, 3, " Unknown", 8);
new_sc_len = 11;
}
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len);
free(new_sc);
}
else {
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len);
}
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);
wsgi_req->write_errors++;
return -1;
}
//each protocol has its header generator
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;
struct uwsgi_string_list *rh = uwsgi.remove_headers;
while(rh) {
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
return 0;
}
rh = rh->next;
}
rh = wsgi_req->remove_headers;
while(rh) {
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
return 0;
}
rh = rh->next;
}
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_write_headers_do(struct wsgi_request *wsgi_req) {
if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) {
return UWSGI_OK;
}
struct uwsgi_string_list *ah = uwsgi.additional_headers;
while(ah) {
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
ah = ah->next;
}
ah = wsgi_req->additional_headers;
while(ah) {
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
ah = ah->next;
}
if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;}
for(;;) {
int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos);
if (ret < 0) {
if (!uwsgi.ignore_write_errors) {
uwsgi_error("uwsgi_response_write_headers_do()");
}
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_response_write_headers_do() TIMEOUT !!!\n");
wsgi_req->write_errors++;
return -1;
}
}
wsgi_req->headers_size += wsgi_req->write_pos;
// reset for the next write
wsgi_req->write_pos = 0;
wsgi_req->headers_sent = 1;
return UWSGI_OK;
}
// this is the function called by all request plugins to send chunks to the client
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->headers_sent) {
int ret = uwsgi_response_write_headers_do(wsgi_req);
if (ret == UWSGI_OK) goto sendbody;
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
wsgi_req->write_errors++;
return -1;
}
sendbody:
if (len == 0) return UWSGI_OK;
for(;;) {
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
if (ret < 0) {
if (!uwsgi.ignore_write_errors) {
uwsgi_error("uwsgi_response_write_body_do()");
}
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_response_write_body_do() TIMEOUT !!!\n");
wsgi_req->write_errors++;
return -1;
}
}
wsgi_req->response_size += wsgi_req->write_pos;
// reset for the next write
wsgi_req->write_pos = 0;
// now we need to check if the chunk must be stored
if (wsgi_req->cache_it) {
if (!wsgi_req->cached_response) {
wsgi_req->cached_response = uwsgi_buffer_new(len);
}
// if we are unable to append the buffer, we just stop caching it
if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
}
return UWSGI_OK;
}
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
int can_close = 1;
if (fd == wsgi_req->sendfile_fd) can_close = 0;
if (wsgi_req->write_errors) return -1;
if (!wsgi_req->headers_sent) {
int ret = uwsgi_response_write_headers_do(wsgi_req);
if (ret == UWSGI_OK) goto sendfile;
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
}
sendfile:
if (len == 0) {
struct stat st;
if (fstat(fd, &st)) {
uwsgi_error("fstat()");
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
}
len = st.st_size;
}
if (wsgi_req->socket->can_offload) {
// of we cannot close the socket (before the app will close it later)
// let's dup it
if (!can_close) {
int tmp_fd = dup(fd);
if (tmp_fd < 0) {
uwsgi_error("uwsgi_response_sendfile_do()/dup()");
wsgi_req->write_errors++;
return -1;
}
fd = tmp_fd;
can_close = 1;
}
if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, len)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->response_size += len;
return 0;
}
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
}
wsgi_req->via = UWSGI_VIA_SENDFILE;
for(;;) {
int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
if (ret < 0) {
if (!uwsgi.ignore_write_errors) {
uwsgi_error("uwsgi_response_sendfile_do()");
}
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
}
if (ret == UWSGI_OK) {
break;
}
ret = uwsgi_wait_write_req(wsgi_req);
if (ret < 0) {
wsgi_req->write_errors++;
if (can_close) close(fd);
return -1;
}
if (ret == 0) {
uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
wsgi_req->write_errors++;
return -1;
}
}
wsgi_req->response_size += wsgi_req->write_pos;
// reset for the next write
wsgi_req->write_pos = 0;
// close the file descriptor
if (can_close) close(fd);
return UWSGI_OK;
}
int uwsgi_simple_wait_write_hook(int fd, int timeout) {
struct pollfd upoll;
timeout = timeout * 1000;
upoll.fd = fd;
upoll.events = POLLOUT;
upoll.revents = 0;
int ret = poll(&upoll, 1, timeout);
if (ret > 0) {
if (upoll.revents & POLLOUT) {
return 1;
}
return -1;
}
if (ret < 0) {
uwsgi_error("uwsgi_simple_wait_write_hook()/poll()");
}
return ret;
}
+3 -3
View File
@@ -20,7 +20,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
char *xml_id;
char *xml_content;
int xml_size = 0;
size_t xml_size = 0;
if (uwsgi_check_scheme(filename)) {
colon = uwsgi_get_last_char(filename, '/');
@@ -47,7 +47,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
exit(1);
}
uwsgi_log("[uWSGI] parsing config file %s\n", filename);
uwsgi_log_initial("[uWSGI] parsing config file %s\n", filename);
element = xmlDocGetRootElement(doc);
if (element == NULL) {
@@ -221,7 +221,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
char *colon;
char *xml_content;
int xml_size = 0;
size_t xml_size = 0;
int done = 0;
if (uwsgi_check_scheme(filename)) {
+5 -5
View File
@@ -61,9 +61,9 @@ int yaml_get_depth(char *line) {
return depth;
}
char *yaml_get_line(char *yaml, off_t size) {
char *yaml_get_line(char *yaml, size_t size) {
off_t i;
size_t i;
char *ptr = yaml;
int comment = 0;
@@ -96,7 +96,7 @@ char *yaml_get_line(char *yaml, off_t size) {
void uwsgi_yaml_config(char *file, char *magic_table[]) {
int len = 0;
size_t len = 0;
char *yaml;
int in_uwsgi_section = 0;
@@ -122,7 +122,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
}
}
uwsgi_log("[uWSGI] getting YAML configuration from %s\n", file);
uwsgi_log_initial("[uWSGI] getting YAML configuration from %s\n", file);
yaml = uwsgi_open_and_read(file, &len, 1, magic_table);
@@ -137,7 +137,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
exit(1);
}
yaml_parser_set_input_string(&parser, (const unsigned char *) yaml, (size_t) len - 1);
yaml_parser_set_input_string(&parser, (unsigned char *) yaml, (size_t) len - 1);
while (parsing) {
if (!yaml_parser_scan(&parser, &token)) {
+55
View File
@@ -0,0 +1,55 @@
#include <uwsgi.h>
int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
z->zalloc = Z_NULL;
z->zfree = Z_NULL;
z->opaque = Z_NULL;
if (deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) != Z_OK) {
//if (deflateInit(z, Z_DEFAULT_COMPRESSION)) {
return -1;
}
if (dict && dict_len) {
if (deflateSetDictionary(z, (Bytef *) dict, dict_len) != Z_OK) {
return -1;
}
}
return 0;
}
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
// calculate the amount of bytes needed for output (+30 should be enough)
Bytef *dbuf = uwsgi_malloc(len+30);
z->avail_in = len;
z->next_in = (Bytef *) buf;
z->avail_out = len+30;
z->next_out = dbuf;
if (len > 0) {
if (deflate(z, Z_SYNC_FLUSH) != Z_OK) {
free(dbuf);
return NULL;
}
}
else {
if (deflate(z, Z_FINISH) != Z_STREAM_END) {
free(dbuf);
return NULL;
}
deflateEnd(z);
}
*dlen = (z->next_out - dbuf);
return (char *) dbuf;
}
void uwsgi_crc32(uint32_t *ctx, char *buf, size_t len) {
if (!buf) {
*ctx = crc32(*ctx, Z_NULL, 0);
}
else {
*ctx = crc32(*ctx, (const Bytef *) buf, len);
}
}
View File
-90
View File
@@ -1,90 +0,0 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="../">{% trans 'Home' %}</a> &rsaquo;
{% trans 'uWSGI' %}
</div>
{% endblock %}
{% block content %}
<div id="content-main">
<h1>uWSGI status</h1>
<b>masterpid:</b> {{masterpid}}<br/>
<b>started_on:</b> {{started_on}}<br/>
<b>buffer size:</b> {{buffer_size}}<br/>
<b>workers:</b> {{numproc}}<br/>
<b>total requests:</b> {{total_requests}}<br/>
<br/>
<div class="module" style="width:860px">
<table>
<caption style="width:860px">workers</caption>
<thead>
<tr>
<th scope="row">id</th>
<th scope="row">pid</th>
<th scope="row">requests</th>
<th scope="row">running time (milliseconds)</th>
<th scope="row">load</th>
<th scope="row">last spawn</th>
<th scope="row">respawn count</th>
<th scope="row">address space (vsz)</th>
<th scope="row">resident memory (rss)</th>
</tr>
</thead>
<tbody>
{% for w in workers %}
<tr>
<td align="center">{{w.id}}</td>
<td align="center">{{w.pid}}</td>
<td align="right">{{w.requests}}</td>
<td align="right">{{w.running_time}}</td>
<td align="right">{{w.load|floatformat:2}} %</td>
<td align="right">{{w.last_spawn_str}}</td>
<td align="right">{{w.respawn_count}}</td>
<td align="right">{{w.vsz|filesizeformat}}</td>
<td align="right">{{w.rss|filesizeformat}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="module" style="width:860px">
<table>
<caption style="width:860px">spooler jobs</caption>
<thead>
<tr>
<th scope="row">job filename</th>
<th scope="row">environment</th>
</tr>
</thead>
<tbody>
{% for j in jobs %}
<tr>
<td align="left">{{j.file}}</td>
<td align="left">{{j.env}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if masterpid %}
<br/>
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
{% csrf_token %}
<input type="submit" value="gracefully reload uWSGI" name="_reload"/>
</form>
{% endif %}
</div>
{% endblock %}
-10
View File
@@ -1,10 +0,0 @@
import sys, os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from django.conf.urls.defaults import *
urlpatterns = patterns('uwsgi_admin.views',
(r'^$', 'index'),
(r'^reload/$', 'reload')
)
-42
View File
@@ -1,42 +0,0 @@
import uwsgi
import time
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.admin.views.decorators import staff_member_required
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
def index(request):
workers = uwsgi.workers()
total_load = time.time() - uwsgi.started_on
for w in workers:
w['load'] = (100 * (w['running_time']/1000))/total_load
w['last_spawn_str'] = time.ctime(w['last_spawn'])
jobs = []
if 'spooler' in uwsgi.opt:
spooler_jobs = uwsgi.spooler_jobs()
for j in spooler_jobs:
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
return render_to_response('uwsgi.html', {'masterpid': uwsgi.masterpid(),
'started_on': time.ctime(uwsgi.started_on),
'buffer_size': uwsgi.buffer_size,
'total_requests': uwsgi.total_requests(),
'numproc': uwsgi.numproc,
'workers': workers,
'jobs': jobs,
}, RequestContext(request, {}))
index = staff_member_required(index)
def reload(request):
if uwsgi.masterpid() > 0:
uwsgi.reload()
request.user.message_set.create(message="uWSGI reloaded")
else:
request.user.message_set.create(message="The uWSGI master process is not active")
return HttpResponseRedirect(reverse(index))
reload = staff_member_required(reload)
-29
View File
@@ -1,29 +0,0 @@
from django.template.base import TemplateDoesNotExist
from django.template.loader import BaseLoader
from django.conf import settings
try:
import uwsgi
on_uwsgi = True
except:
on_uwsgi = False
class Loader(BaseLoader):
is_usable = on_uwsgi
def symbolize(self, name):
return name.replace('.','_').replace('/','_').replace('-','_')
def load_template_source(self, template_name, template_dirs=None):
filename = 'templates_' + self.symbolize(template_name)
for app in settings.INSTALLED_APPS:
try:
symbol = "%s_%s" % (self.symbolize(app), filename)
return (uwsgi.embedded_data(symbol), "sym://%s" % symbol)
except:
pass
raise TemplateDoesNotExist(template_name)
View File
View File
+77
View File
@@ -0,0 +1,77 @@
# to run the server
# uwsgi --plugin psgi,coroae --http-socket :9090 --http-socket-modifier1 5 --coroae 8 --psgi examples/corostream.pl --master
# to test it
# curl -D /dev/stdout -N --raw http://localhost:9090/
use Coro::AnyEvent;
use AnyEvent::HTTP;
my $signal_handler = sub {
my $signum = shift;
print "i am the signal ".$signum."\n" ;
};
my $signal_timer = sub {
my $signum = shift;
print "2 seconds elapsed\n";
};
uwsgi::register_signal(17, '', $signal_handler);
uwsgi::register_signal(30, '', $signal_timer);
# raise the signal 30 every 2 seconds
uwsgi::add_timer(30, 2);
sub streamer {
$responder = shift;
# generate the headers and start streaming the response
my $writer = $responder->( [200, ['Content-Type' => 'text/plain']]);
$writer->write("Hello, the streaming is starting...\n");
for(my $i=0;$i<5;$i++) {
Coro::AnyEvent::sleep 1;
$writer->write("[".$i."] one seconds elapsed...\n");
}
$writer->write("let me show you the coroae plugin source taken from github\n\n");
# this condvar will allow us to wait for the github response
my $w = AnyEvent->condvar;
my $uwsgi_coroae_src = '';
http_get 'https://raw.github.com/unbit/uwsgi/master/plugins/coroae/coroae.c', sub { $uwsgi_coroae_src = $_[0] ; $w->send;};
$w->recv;
$writer->write($uwsgi_coroae_src);
Coro::AnyEvent::sleep 1;
$writer->write("now let's raise a uwsgi signal...\n");
uwsgi::signal(17);
Coro::AnyEvent::sleep 1;
$writer->write("another one second elapsed, time to finish.\n");
Coro::AnyEvent::sleep 1;
$writer->write("Goodbye\n");
$writer->close;
print "the request ended, but we are still here\n";
Coro::AnyEvent::sleep 1;
print "another second elapsed, time to end (really)\n";
}
# our PSGI app
my $app = sub {
my $env = shift;
return \&streamer;
}
View File
View File
View File

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