Compare commits

..
142 Commits
Author SHA1 Message Date
Unbit 02693489fe fixed php headers generation 2013-03-28 12:13:23 +01:00
Unbit 0f5dba5828 apache 2.4 support in mod_proxy_uwsgi 2013-03-28 11:19:13 +01:00
Unbit e528d4c4b7 implemented --emperor-tyrant-nofollow 2013-03-28 10:18:01 +01:00
Unbit 52a3af6acf prepare for uWSGI 1.9.3 2013-03-28 10:05:24 +01:00
Unbit dcefea9958 added rpcret routing action 2013-03-28 10:03:33 +01:00
Unbit 59121ff834 added --lua-load, fixed lua rpc memory leak 2013-03-28 09:21:47 +01:00
Unbit 7f5bb6d472 allows usage of configurators in the emperor 2013-03-28 09:07:15 +01:00
Unbit 639c1a508c support for lua ordered arrays in configurations 2013-03-28 09:00:10 +01:00
Unbit 417a26fc64 added config.lua example 2013-03-28 08:02:32 +01:00
Unbit 210ccd0063 allows configuration via lua 2013-03-28 08:02:07 +01:00
unbit 1bf0162d38 Merge pull request #196 from ryankask/jvm-plugin-import
Fix imports for the JVM plugin
2013-03-27 02:53:03 -07:00
Ryan Kaskel e93027fd7e Fix imports for JVM plugin. 2013-03-27 09:48:14 +00:00
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
109 changed files with 6235 additions and 3065 deletions
+4
View File
@@ -1,5 +1,9 @@
*.o
*.py[co]
*.class
*.jar
/uwsgi
/uwsgibuild.*
/t/ring/target
-683
View File
@@ -1,683 +0,0 @@
*** current ***
* 1.5
- added --not-alarm-log
- support for TCP_FASTOPEN (Linux-only)
- improved emperor reloading
- added --get
- Legion subsystem
- emperor_zeromq plugin
- SNI support
- distributed SSL session cache
*** november 2012 ***
* 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
+43
View File
@@ -217,6 +217,45 @@ static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
return OK;
}
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
{
apr_pool_t *pool;
request_rec *rp;
apr_pool_create(&pool, c->pool);
rp = apr_pcalloc(pool, sizeof(*r));
rp->pool = pool;
rp->status = HTTP_OK;
rp->headers_in = apr_table_make(pool, 50);
rp->subprocess_env = apr_table_make(pool, 50);
rp->headers_out = apr_table_make(pool, 12);
rp->err_headers_out = apr_table_make(pool, 5);
rp->notes = apr_table_make(pool, 5);
rp->server = r->server;
rp->log = r->log;
rp->proxyreq = r->proxyreq;
rp->request_time = r->request_time;
rp->connection = c;
rp->output_filters = c->output_filters;
rp->input_filters = c->input_filters;
rp->proto_output_filters = c->output_filters;
rp->proto_input_filters = c->input_filters;
rp->useragent_ip = c->client_ip;
rp->useragent_addr = c->client_addr;
rp->request_config = ap_create_request_config(pool);
proxy_run_create_req(r, rp);
return rp;
}
#endif
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
{
@@ -337,7 +376,11 @@ static int uwsgi_handler(request_rec *r, proxy_worker *worker,
}
// ADD PATH_INFO
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
size_t w_len = strlen(worker->s->name);
#else
size_t w_len = strlen(worker->name);
#endif
char *u_path_info = r->filename + 6 + w_len;
int delta = 0;
if (u_path_info[0] != '/') {
-1
View File
@@ -1 +0,0 @@
object file for embedded files will be put here
-5
View File
@@ -1,18 +1,13 @@
[uwsgi]
xml = auto
ini = true
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
snmp = true
ssl = auto
async = true
ldap = auto
pcre = auto
routing = auto
alarm = auto
ipv6 = false
debug = false
unbit = false
xml_implementation = libxml2
+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
+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 = .
+13 -5
View File
@@ -1,26 +1,34 @@
[uwsgi]
xml = true
ini = true
yaml = true
json = false
sqlite3 = false
zeromq = false
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
+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
+26
View File
@@ -328,3 +328,29 @@ int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modi
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;
}
+33
View File
@@ -0,0 +1,33 @@
#include <uwsgi.h>
/*
pluggable configuration system
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) {
struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators;
while(uc) {
if (!strcmp(uc->name, name)) {
return uc;
}
old_uc = uc;
uc = uc->next;
}
uc = uwsgi_calloc(sizeof(struct uwsgi_configurator));
uc->name = name;
uc->func = func;
if (old_uc) {
old_uc->next = uc;
}
else {
uwsgi.configurators = uc;
}
return uc;
}
+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;
}
+276 -55
View File
@@ -122,19 +122,101 @@ void uwsgi_emperor_blacklist_remove(char *id) {
struct uwsgi_emperor_scanner *emperor_scanners;
static int has_extra_extension(char *name) {
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while(usl) {
if (uwsgi_endswith(name, usl->value)) {
return 1;
}
usl = usl->next;
}
return 0;
}
int uwsgi_emperor_is_valid(char *name) {
if (uwsgi_endswith(name, ".xml") || uwsgi_endswith(name, ".ini") || uwsgi_endswith(name, ".yml") || uwsgi_endswith(name, ".yaml") || uwsgi_endswith(name, ".js") || uwsgi_endswith(name, ".json")) {
if (uwsgi_endswith(name, ".xml") || uwsgi_endswith(name, ".ini") || uwsgi_endswith(name, ".yml") || uwsgi_endswith(name, ".yaml") || uwsgi_endswith(name, ".js") || uwsgi_endswith(name, ".json") || has_extra_extension(name)) {
if (strlen(name) < 0xff) {
return 1;
}
}
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;
@@ -160,10 +242,27 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
ui_current = emperor_get(de->d_name);
uid_t t_uid = st.st_uid;
gid_t t_gid = st.st_gid;
if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) {
struct stat lst;
if (lstat(de->d_name, &lst)) {
uwsgi_error("[emperor-tyrant]/lstat()");
if (ui_current) {
uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", de->d_name);
emperor_stop(ui_current);
}
continue;
}
t_uid = lst.st_uid;
t_gid = lst.st_gid;
}
if (ui_current) {
// check if uid or gid are changed, in such case, stop the instance
if (uwsgi.emperor_tyrant) {
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
if (t_uid != ui_current->uid || t_gid != ui_current->gid) {
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", de->d_name);
emperor_stop(ui_current);
continue;
@@ -175,7 +274,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, t_uid, t_gid, socket_name);
if (socket_name) free(socket_name);
}
}
closedir(dir);
@@ -235,10 +336,27 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
ui_current = emperor_get(g.gl_pathv[i]);
uid_t t_uid = st.st_uid;
gid_t t_gid = st.st_gid;
if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) {
struct stat lst;
if (lstat(g.gl_pathv[i], &lst)) {
uwsgi_error("[emperor-tyrant]/lstat()");
if (ui_current) {
uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
emperor_stop(ui_current);
}
continue;
}
t_uid = lst.st_uid;
t_gid = lst.st_gid;
}
if (ui_current) {
// check if uid or gid are changed, in such case, stop the instance
if (uwsgi.emperor_tyrant) {
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
if (t_uid != ui_current->uid || t_gid != ui_current->gid) {
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
emperor_stop(ui_current);
continue;
@@ -250,7 +368,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, t_uid, t_gid, socket_name);
if (socket_name) free(socket_name);
}
}
@@ -377,6 +497,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) {
@@ -430,6 +566,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);
}
@@ -478,17 +618,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
@@ -544,8 +677,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;
@@ -576,10 +708,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]);
@@ -587,7 +769,7 @@ 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;
}
}
@@ -606,6 +788,11 @@ 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]);
}
@@ -625,13 +812,13 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
}
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);
}
@@ -640,7 +827,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);
}
@@ -720,7 +907,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;
}
@@ -728,34 +915,43 @@ 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";
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while(usl) {
if (uwsgi_endswith(n_ui->name, usl->value)) {
vassal_argv[1] = "--config";
break;
}
usl = usl->next;
}
if (colon) {
colon[0] = ':';
}
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;
@@ -768,18 +964,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) < 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
@@ -813,11 +1020,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) {
@@ -975,6 +1178,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) {
@@ -1087,14 +1292,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(ui_current->scanner, 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);
}
}
}
@@ -1120,7 +1335,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) {
@@ -1172,7 +1389,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;
@@ -1266,7 +1483,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;
@@ -1285,6 +1502,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))
@@ -1403,6 +1623,7 @@ void uwsgi_emperor_start() {
else {
uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor");
}
if (uwsgi.emperor_pid < 0) {
uwsgi_error("pid()");
exit(1);
@@ -1436,7 +1657,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;
@@ -1473,6 +1694,6 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
new_config = uwsgi_str(config);
new_config_len = strlen(new_config);
}
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid);
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name);
}
}
+227
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>
+14 -6
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;
@@ -106,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) {
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);
@@ -157,5 +167,3 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
}
#endif
+1 -1
View File
@@ -296,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
+3 -3
View File
@@ -770,10 +770,10 @@ timeout:
// check if an fd is valid
int uwsgi_valid_fd(int fd) {
int ret = fcntl(fd, F_GETFL);
if (ret == 0) {
return 1;
if (ret == -1) {
return 0;
}
return 0;
return 1;
}
void uwsgi_close_all_fds(void) {
+146 -6
View File
@@ -75,6 +75,41 @@ void uwsgi_parse_legion(char *key, uint16_t keylen, char *value, uint16_t vallen
memcpy(ul->lord_uuid, value, 36);
}
}
else if (!uwsgi_strncmp(key, keylen, "scroll", 6)) {
ul->scroll = value;
ul->scroll_len = vallen;
}
}
// this function is called when a node is added or removed (heavy locking is needed)
static void legion_rebuild_scrolls(struct uwsgi_legion *ul) {
uint64_t max_size = ul->scrolls_max_size;
// first, try to add myself
if (ul->scroll_len + (uint64_t) 2 > max_size) {
uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n");
ul->scroll_len = 0;
return;
}
char *ptr = ul->scrolls;
*ptr ++= (uint8_t) (ul->scroll_len & 0xff);
*ptr ++= (uint8_t) ((ul->scroll_len >> 8) &0xff);
memcpy(ptr, ul->scroll, ul->scroll_len); ptr += ul->scroll_len;
ul->scrolls_len = 2 + ul->scroll_len;
// ok start adding nodes;
struct uwsgi_legion_node *uln = ul->nodes_head;
while(uln) {
if (ul->scrolls_len + 2 + uln->scroll_len > max_size) {
uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n");
return;
}
*ptr ++= (uint8_t) (uln->scroll_len & 0xff);
*ptr ++= (uint8_t) ((uln->scroll_len >> 8) &0xff);
memcpy(ptr, uln->scroll, uln->scroll_len); ptr += uln->scroll_len;
ul->scrolls_len += 2 + uln->scroll_len;
uln = uln->next;
}
}
// critical section (remember to lock when you use it)
@@ -100,6 +135,7 @@ struct uwsgi_legion_node *uwsgi_legion_add_node(struct uwsgi_legion *ul, uint16_
ul->nodes_head = node;
}
return node;
@@ -137,6 +173,8 @@ void uwsgi_legion_remove_node(struct uwsgi_legion *ul, struct uwsgi_legion_node
}
free(node);
legion_rebuild_scrolls(ul);
}
struct uwsgi_legion_node *uwsgi_legion_get_node(struct uwsgi_legion *ul, uint64_t valor, char *name, uint16_t name_len, char *uuid) {
@@ -170,9 +208,9 @@ static void legions_check_nodes() {
struct uwsgi_legion_node *tmp_node = node;
node = node->next;
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s left Legion %s\n", tmp_node->name_len, tmp_node->name, tmp_node->valor, 36, tmp_node->uuid, legion->legion);
pthread_mutex_lock(&legion->lock);
uwsgi_wlock(legion->lock);
uwsgi_legion_remove_node(legion, tmp_node);
pthread_mutex_unlock(&legion->lock);
uwsgi_rwunlock(legion->lock);
continue;
}
node = node->next;
@@ -281,6 +319,15 @@ static void legions_check_nodes_step2() {
}
usl = usl->next;
}
if (ul->scroll_len > 0 && ul->scroll_len <= ul->lord_scroll_size) {
uwsgi_wlock(ul->lock);
ul->lord_scroll_len = ul->scroll_len;
memcpy(ul->lord_scroll, ul->scroll, ul->lord_scroll_len);
uwsgi_rwunlock(ul->lock);
}
else {
ul->lord_scroll_len = 0;
}
ul->i_am_the_lord = uwsgi_now();
// trick: reduce the time needed by the old lord to unlord itself
uwsgi_legion_announce(ul);
@@ -289,6 +336,11 @@ static void legions_check_nodes_step2() {
else {
if (ul->i_am_the_lord) {
uwsgi_log("[uwsgi-legion] a new Lord (valor: %llu uuid: %.*s) raised for Legion %s...\n", ul->lord_valor, 36, ul->lord_uuid, ul->legion);
if (ul->lord_scroll_len > 0) {
uwsgi_log("*********** The New Lord Scroll ***********\n\n");
uwsgi_log("%.*s\n", ul->lord_scroll_len, ul->lord_scroll);
uwsgi_log("\n*********** End of the New Lord Scroll ***********\n\n");
}
// no more lord, trigger unlord hooks
struct uwsgi_string_list *usl = ul->unlord_hooks;
while (usl) {
@@ -354,6 +406,18 @@ struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *ul) {
ul->lord_valor = best_valor;
memcpy(ul->lord_uuid, best_uuid, 36);
if (!best_node) return NULL;
if (best_node->scroll_len > 0 && best_node->scroll_len <= ul->lord_scroll_size) {
uwsgi_wlock(ul->lock);
ul->lord_scroll_len = best_node->scroll_len;
memcpy(ul->lord_scroll, best_node->scroll, ul->lord_scroll_len);
uwsgi_rwunlock(ul->lock);
}
else {
ul->lord_scroll_len = 0;
}
return best_node;
}
@@ -483,9 +547,17 @@ static void *legion_loop(void *foobar) {
struct uwsgi_legion_node *node = uwsgi_legion_get_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
if (!node) {
// add the new node
pthread_mutex_lock(&ul->lock);
uwsgi_wlock(ul->lock);
node = uwsgi_legion_add_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
pthread_mutex_unlock(&ul->lock);
if (!node) continue;
if (legion_msg.scroll_len > 0) {
node->scroll = uwsgi_malloc(legion_msg.scroll_len);
node->scroll_len = legion_msg.scroll_len;
memcpy(node->scroll, legion_msg.scroll, node->scroll_len);
}
// we are still locked (and safe), let's rebuild the scrolls list
legion_rebuild_scrolls(ul);
uwsgi_rwunlock(ul->lock);
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
}
@@ -624,6 +696,11 @@ int uwsgi_legion_announce(struct uwsgi_legion *ul) {
goto err;
if (uwsgi_buffer_append_keyval(ub, "lord_uuid", 9, ul->lord_uuid, 36))
goto err;
if (ul->scroll_len > 0) {
if (uwsgi_buffer_append_keyval(ub, "scroll", 6, ul->scroll, ul->scroll_len))
goto err;
}
#ifdef UWSGI_UUID
#endif
@@ -716,8 +793,33 @@ void uwsgi_opt_legion_quorum(char *opt, char *value, void *foobar) {
}
ul->quorum = atoi(space+1);
free(legion);
}
void uwsgi_opt_legion_scroll(char *opt, char *value, void *foobar) {
char *legion = uwsgi_str(value);
char *space = strchr(legion, ' ');
if (!space) {
uwsgi_log("invalid legion-scroll syntax, must be <legion> <scroll>\n");
exit(1);
}
*space = 0;
struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
if (!ul) {
uwsgi_log("unknown legion: %s\n", legion);
exit(1);
}
ul->scroll = space+1;
ul->scroll_len = strlen(ul->scroll);
// DO NOT FREE IT !!!
//free(legion);
}
void uwsgi_opt_legion_hook(char *opt, char *value, void *foobar) {
@@ -867,7 +969,18 @@ void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
ul->encrypt_ctx = ctx;
ul->decrypt_ctx = ctx2;
pthread_mutex_init(&ul->lock, NULL);
if (!uwsgi.legion_scroll_max_size) {
uwsgi.legion_scroll_max_size = 4096;
}
if (!uwsgi.legion_scroll_list_max_size) {
uwsgi.legion_scroll_list_max_size = 32768;
}
ul->lord_scroll_size = uwsgi.legion_scroll_max_size;
ul->lord_scroll = uwsgi_calloc_shared(ul->lord_scroll_size);
ul->scrolls_max_size = uwsgi.legion_scroll_list_max_size;
ul->scrolls = uwsgi_calloc_shared(ul->scrolls_max_size);
uwsgi_legion_add(ul);
}
@@ -929,8 +1042,35 @@ next:
int uwsgi_legion_i_am_the_lord(char *name) {
struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
if (legion && legion->i_am_the_lord) {
if (!legion) return 0;
if (legion->i_am_the_lord) {
return 1;
}
return 0;
}
char *uwsgi_legion_lord_scroll(char *name, uint16_t *rlen) {
char *buf = NULL;
struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
if (!legion) return 0;
uwsgi_rlock(legion->lock);
if (legion->lord_scroll_len > 0) {
buf = uwsgi_malloc(legion->lord_scroll_len);
memcpy(buf, legion->lord_scroll, legion->lord_scroll_len);
*rlen = legion->lord_scroll_len;
}
uwsgi_rwunlock(legion->lock);
return buf;
}
char *uwsgi_legion_scrolls(char *name, uint64_t *rlen) {
char *buf = NULL;
struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
if (!legion) return NULL;
uwsgi_rlock(legion->lock);
buf = uwsgi_malloc(legion->scrolls_len);
memcpy(buf, legion->scrolls, legion->scrolls_len);
*rlen = legion->scrolls_len;
uwsgi_rwunlock(legion->lock);
return buf;
}
+63
View File
@@ -401,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
@@ -641,6 +695,15 @@ ready:
}
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;
}
+33 -12
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
@@ -314,7 +318,7 @@ static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl)
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum(name[i])) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
@@ -638,12 +642,8 @@ 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++;
@@ -673,7 +673,11 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
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;
@@ -686,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;
@@ -725,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;
+3 -3
View File
@@ -1312,7 +1312,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_open(us))
goto end;
pthread_mutex_lock(&legion->lock);
uwsgi_rlock(legion->lock);
struct uwsgi_legion_node *node = legion->nodes_head;
while (node) {
if (uwsgi_stats_object_open(us))
@@ -1342,7 +1342,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto unlock_legion_mutex;
}
}
pthread_mutex_unlock(&legion->lock);
uwsgi_rwunlock(legion->lock);
if (uwsgi_stats_list_close(us))
goto end;
@@ -1371,7 +1371,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
#ifdef UWSGI_SSL
unlock_legion_mutex:
if (legion)
pthread_mutex_unlock(&legion->lock);
uwsgi_rwunlock(legion->lock);
#endif
end:
free(us->base);
+1
View File
@@ -437,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);
+94 -53
View File
@@ -28,13 +28,6 @@ ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char
struct uwsgi_header *uh;
if (message) {
uh = (struct uwsgi_header *) message;
}
else {
uh = (struct uwsgi_header *) uwsgi_malloc(4);
}
udp_port = strchr(host, ':');
if (udp_port) {
udp_port[0] = 0;
@@ -64,6 +57,13 @@ ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char
}
if (message) {
uh = (struct uwsgi_header *) message;
}
else {
uh = (struct uwsgi_header *) uwsgi_malloc(4);
}
uh->modifier1 = modifier1;
#ifdef __BIG_ENDIAN__
uh->pktsize = uwsgi_swap16(message_size);
@@ -354,6 +354,13 @@ static int uwsgi_proto_check_11(struct wsgi_request *wsgi_req, char *key, char *
return 0;
}
if (!uwsgi_proto_key("HTTP_COOKIE", 11)) {
wsgi_req->cookie = buf;
wsgi_req->cookie_len = len;
return 0;
}
if (!uwsgi_proto_key("UWSGI_APPID", 11)) {
wsgi_req->appid = buf;
wsgi_req->appid_len = len;
@@ -578,7 +585,7 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
ptrbuf = buffer;
bufferend = ptrbuf + wsgi_req->uh->pktsize;
int i;
/* set an HTTP 500 status as default */
wsgi_req->status = 500;
@@ -673,7 +680,6 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
next:
// manage post buffering (if needed as post_file could be created before)
if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) {
// read to disk if post_cl > post_buffering (it will eventually do upload progress...)
@@ -759,12 +765,7 @@ next:
}
// check for static files
// 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 0;
}
/* CHECK FOR STATIC FILES */
// skip extensions
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
@@ -886,44 +887,6 @@ nextsm2:
return 0;
}
ssize_t uwsgi_send_empty_pkt(int fd, char *socket_name, uint8_t modifier1, uint8_t modifier2) {
struct uwsgi_header uh;
char *port;
uint16_t s_port;
struct sockaddr_in uaddr;
int ret;
uh.modifier1 = modifier1;
uh.pktsize = 0;
uh.modifier2 = modifier2;
if (socket_name) {
port = strchr(socket_name, ':');
if (!port)
return -1;
s_port = atoi(port + 1);
port[0] = 0;
memset(&uaddr, 0, sizeof(struct sockaddr_in));
uaddr.sin_family = AF_INET;
uaddr.sin_addr.s_addr = inet_addr(socket_name);
uaddr.sin_port = htons(s_port);
port[0] = ':';
ret = sendto(fd, &uh, 4, 0, (struct sockaddr *) &uaddr, sizeof(struct sockaddr_in));
}
else {
ret = send(fd, &uh, 4, 0);
}
if (ret < 0) {
uwsgi_error("sendto()");
}
return ret;
}
int uwsgi_hooked_parse(char *buffer, size_t len, void (*hook) (char *, uint16_t, char *, uint16_t, void *), void *data) {
char *ptrbuf, *bufferend;
@@ -1005,9 +968,24 @@ int uwsgi_hooked_parse_array(char *buffer, size_t len, void (*hook) (uint16_t, c
}
/*
the following functions need to take in account that POST data could be already available in wsgi_req->buffer (generally when uwsgi protocol is in use)
In such a case, allocate a proto_parser_buf and move data there
*/
char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
if (!wsgi_req->proto_parser_buf) {
if (wsgi_req->proto_parser_remains > 0) {
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains);
memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains);
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf;
}
}
if ((wsgi_req->uh->pktsize + (2 + keylen + 2 + vallen)) > uwsgi.buffer_size) {
uwsgi_log("not enough buffer space to add %.*s variable, consider increasing it with the --buffer-size option\n", keylen, key);
return NULL;
@@ -1043,3 +1021,66 @@ char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen
return ptr;
}
int uwsgi_req_append_path_info_with_index(struct wsgi_request *wsgi_req, char *index, uint16_t index_len) {
if (!wsgi_req->proto_parser_buf) {
if (wsgi_req->proto_parser_remains > 0) {
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains);
memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains);
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf;
}
}
uint8_t need_slash = 0;
if (wsgi_req->path_info_len > 0) {
if (wsgi_req->path_info[wsgi_req->path_info_len-1] != '/') {
need_slash = 1;
}
}
wsgi_req->path_info_len += need_slash + index_len;
// 2 + 9 + 2
if ((wsgi_req->uh->pktsize + (13 + wsgi_req->path_info_len)) > uwsgi.buffer_size) {
uwsgi_log("not enough buffer space to transform the PATH_INFO variable, consider increasing it with the --buffer-size option\n");
return -1;
}
if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) {
uwsgi_log("max vec size reached for PATH_INFO + index. skip this request.\n");
return -1;
}
uint16_t keylen = 9;
char *ptr = wsgi_req->buffer + wsgi_req->uh->pktsize;
*ptr++ = (uint8_t) (keylen & 0xff);
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
memcpy(ptr, "PATH_INFO", keylen);
wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr;
wsgi_req->hvec[wsgi_req->var_cnt].iov_len = keylen;
wsgi_req->var_cnt++;
ptr += keylen;
*ptr++ = (uint8_t) (wsgi_req->path_info_len & 0xff);
*ptr++ = (uint8_t) ((wsgi_req->path_info_len >> 8) & 0xff);
char *new_path_info = ptr;
memcpy(ptr, wsgi_req->path_info, wsgi_req->path_info_len - (need_slash + index_len));
ptr+=wsgi_req->path_info_len - (need_slash + index_len);
if (need_slash) {
*ptr ++= '/';
}
memcpy(ptr, index, index_len);
wsgi_req->hvec[wsgi_req->var_cnt].iov_base = new_path_info;
wsgi_req->hvec[wsgi_req->var_cnt].iov_len = wsgi_req->path_info_len;
wsgi_req->var_cnt++;
wsgi_req->uh->pktsize += 13 + wsgi_req->path_info_len;
wsgi_req->path_info = new_path_info;
return 0;
}
+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;
}
+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);
+14 -14
View File
@@ -108,64 +108,65 @@ static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
}
}
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, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, 1, 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 += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
wsgi_req->post_pos += remains;
wsgi_req->post_readline_watermark += remains;
return 0;
}
// read from post_buffering memory
if (uwsgi.post_buffering) {
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
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 , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
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(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
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 , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
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(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
// 0 means timeout
else if (ret == 0) {
uwsgi_read_timeout(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_timeout(remains);
return -1;
}
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
@@ -347,7 +348,6 @@ char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize
if (wsgi_req->post_file) {
if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) {
*rlen = -1;
uwsgi_log("%llu\n", remains);
uwsgi_error("uwsgi_request_body_read()/fread()");
return NULL;
}
+241 -19
View File
@@ -3,6 +3,43 @@
extern struct uwsgi_server uwsgi;
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;
@@ -44,9 +81,32 @@ struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, stru
case 2:
if (pass1[i] == '}') {
uint16_t vallen = 0;
char *value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
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)) goto error;
if (uwsgi_buffer_append(ub, value, vallen)) {
if (need_free) {
free(value);
}
goto error;
}
if (need_free) {
free(value);
}
}
status = 0;
key = NULL;
@@ -72,8 +132,9 @@ struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, stru
}
// 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);
@@ -85,17 +146,23 @@ error:
return NULL;
}
static int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
struct uwsgi_route *routes = uwsgi.routes;
void *goon_func = NULL;
int n = -1;
char *orig_subject = subject;
uint16_t orig_subject_len = subject_len;
while (routes) {
if (routes->label) goto next;
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;
}
@@ -103,6 +170,11 @@ static int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, u
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);
@@ -132,6 +204,7 @@ static int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, u
}
}
run:
if (n >= 0) {
wsgi_req->is_routing = 1;
int ret = routes->func(wsgi_req, routes);
@@ -149,6 +222,8 @@ static int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, u
}
}
next:
subject = orig_subject;
subject_len = orig_subject_len;
routes = routes->next;
if (routes) wsgi_req->route_pc++;
}
@@ -169,34 +244,29 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
return UWSGI_ROUTE_BREAK;
}
// in case of static files serving previous rules could be applied
if (wsgi_req->routes_applied) {
return UWSGI_ROUTE_CONTINUE;
}
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
}
int uwsgi_apply_routes_fast(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
if (!uwsgi.routes)
return UWSGI_ROUTE_CONTINUE;
// avoid loops
if (wsgi_req->is_routing)
return UWSGI_ROUTE_CONTINUE;
return uwsgi_apply_routes_do(wsgi_req, subject, subject_len);
}
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) {
@@ -223,7 +293,12 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
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);
@@ -299,7 +374,8 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
}
}
char *command = space + 1;
command = space + 1;
done:
ur->action = uwsgi_str(command);
char *colon = strchr(command, ':');
@@ -344,12 +420,14 @@ int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args
}
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
@@ -358,6 +436,7 @@ found:
ur->free(ur);
}
free(ur);
free(args);
return ret;
}
@@ -625,6 +704,133 @@ static int uwsgi_route_condition_isfile(struct wsgi_request *wsgi_req, struct uw
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;
@@ -682,6 +888,19 @@ void uwsgi_register_embedded_routers() {
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 *)) {
@@ -740,6 +959,9 @@ void uwsgi_routing_dump() {
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);
}
+10
View File
@@ -123,6 +123,16 @@ void uwsgi_setup_inherited_sockets() {
continue;
}
if (uwsgi.shared->worker_req_log_pipe[0] > -1) {
if (j == uwsgi.shared->worker_req_log_pipe[0])
continue;
}
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;
+1 -1
View File
@@ -137,7 +137,7 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
int i;
for(i=1;i<=uwsgi.numproc;i++) {
int pos = (i * 256);
memcpy(&uwsgi.shared->signal_table[pos], use, sizeof(struct uwsgi_signal_entry) * 256);
memcpy(&uwsgi.shared->signal_table[pos], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256);
}
}
+33 -1
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
@@ -561,11 +585,13 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
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__
@@ -576,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
@@ -585,6 +612,7 @@ 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");
@@ -611,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;
}
}
@@ -645,6 +674,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
}
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
#ifdef __linux__
@@ -652,12 +682,14 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (somaxconn > 0 && uwsgi.listen_queue > 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;
}
@@ -1476,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;
+25 -7
View File
@@ -393,7 +393,7 @@ ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t f
return len;
}
int uwsgi_static_stat(char *filename, size_t *filename_len, struct stat *st) {
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
@@ -412,7 +412,8 @@ int uwsgi_static_stat(char *filename, size_t *filename_len, struct stat *st) {
#ifdef UWSGI_DEBUG
uwsgi_log("checking for %s\n", filename);
#endif
if (!uwsgi_static_stat(filename, filename_len, st)) {
if (uwsgi_is_file2(filename, st)) {
*index = usl;
*filename_len = new_len;
return 0;
}
@@ -521,6 +522,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
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);
@@ -580,23 +582,39 @@ found:
safe:
if (!uwsgi_static_stat(real_filename, &real_filename_len, &st)) {
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)) {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes_fast(wsgi_req, real_filename, real_filename_len) == UWSGI_ROUTE_BREAK)
return 0;
#endif
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);
}
+45 -1
View File
@@ -315,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;
@@ -383,7 +422,10 @@ struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pu
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;
}
@@ -452,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;
@@ -461,6 +504,7 @@ void uwsgi_stats_pusher_setup() {
}
uwsgi_stats_pusher_add(pusher, arg);
usl = usl->next;
free(ssp);
}
}
+56 -5
View File
@@ -622,6 +622,25 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
free(wsgi_req->proto_parser_buf);
}
// do we need to store the response in the cache
if (wsgi_req->cache_it) {
// only response with a body and a status code of 200 can be cached (TODO allows it to be configurable)
if (wsgi_req->cached_response && wsgi_req->status == 200 && wsgi_req->response_size > 0) {
uwsgi_cache_magic_set(wsgi_req->cache_it->buf, wsgi_req->cache_it->pos,
wsgi_req->cached_response->buf, wsgi_req->cached_response->pos, wsgi_req->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, wsgi_req->cache_it_to ? wsgi_req->cache_it_to->buf : NULL);
}
uwsgi_buffer_destroy(wsgi_req->cache_it);
}
if (wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it_to);
}
if (wsgi_req->cached_response) {
uwsgi_buffer_destroy(wsgi_req->cached_response);
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
@@ -659,7 +678,7 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
}
// defunct process reaper
if (uwsgi.shared->options[UWSGI_OPTION_REAPER] == 1 || uwsgi.grunt) {
if (uwsgi.shared->options[UWSGI_OPTION_REAPER] == 1) {
while (waitpid(WAIT_ANY, &waitpid_status, WNOHANG) > 0);
}
@@ -1248,6 +1267,16 @@ int uwsgi_is_file(char *filename) {
return 0;
}
int uwsgi_is_file2(char *filename, struct stat *st) {
if (stat(filename, st)) {
return 0;
}
if (S_ISREG(st->st_mode))
return 1;
return 0;
}
int uwsgi_is_dir(char *filename) {
struct stat st;
if (stat(filename, &st)) {
@@ -1504,7 +1533,7 @@ void add_exported_option(char *key, char *value, int configured) {
while (blacklist) {
if (!strcmp(key, blacklist->value)) {
uwsgi_log("uWSGI error: forbidden option \"%s\"\n", key);
uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key);
exit(1);
}
blacklist = blacklist->next;
@@ -1520,11 +1549,25 @@ void add_exported_option(char *key, char *value, int configured) {
whitelist = whitelist->next;
}
if (!allowed) {
uwsgi_log("uWSGI error: forbidden option \"%s\"\n", key);
uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key);
exit(1);
}
}
if (uwsgi.blacklist_context) {
if (uwsgi_list_has_str(uwsgi.blacklist_context, key)) {
uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key);
exit(1);
}
}
if (uwsgi.whitelist_context) {
if (!uwsgi_list_has_str(uwsgi.whitelist_context, key)) {
uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key);
exit(1);
}
}
if (uwsgi.logic_opt_running)
goto add;
@@ -1839,7 +1882,7 @@ int uwsgi_list_has_num(char *list, int num) {
int uwsgi_list_has_str(char *list, char *str) {
char *list2 = uwsgi_concat2(list + 1, "");
char *list2 = uwsgi_str(list);
char *p = strtok(list2, " ");
while (p != NULL) {
@@ -2446,13 +2489,19 @@ void uwsgi_chown(char *filename, char *owner) {
char *uwsgi_get_binary_path(char *argvzero) {
#if defined(__linux__)
#if defined(__linux__) || defined(__CYGWIN__)
char *buf = uwsgi_calloc(PATH_MAX + 1);
ssize_t len = readlink("/proc/self/exe", buf, PATH_MAX);
if (len > 0) {
return buf;
}
free(buf);
#elif defined(_WIN32)
char *buf = uwsgi_calloc(PATH_MAX + 1);
if (GetModuleFileName(NULL, buf, PATH_MAX) > 0) {
return buf;
}
free(buf);
#elif defined(__NetBSD__)
char *buf = uwsgi_calloc(PATH_MAX + 1);
ssize_t len = readlink("/proc/curproc/exe", buf, PATH_MAX);
@@ -2917,11 +2966,13 @@ pid_t uwsgi_fork(char *name) {
pid_t pid = fork();
if (pid == 0) {
#ifndef __CYGWIN__
if (uwsgi.never_swap) {
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
uwsgi_error("mlockall()");
}
}
#endif
#if defined(__linux__) || defined(__sun__)
int i;
+145 -20
View File
@@ -70,6 +70,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
{"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE},
{"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0},
@@ -80,6 +81,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
{"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"if-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_opt, UWSGI_OPT_IMMEDIATE},
{"if-not-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_opt, UWSGI_OPT_IMMEDIATE},
@@ -108,6 +110,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"if-directory", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE},
{"endif", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"end-if", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"blacklist", required_argument, 0, "set options blacklist context", uwsgi_opt_set_str, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE},
{"end-blacklist", no_argument, 0, "clear options blacklist context", uwsgi_opt_set_null, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE},
{"whitelist", required_argument, 0, "set options whitelist context", uwsgi_opt_set_str, &uwsgi.whitelist_context, UWSGI_OPT_IMMEDIATE},
{"end-whitelist", no_argument, 0, "clear options whitelist context", uwsgi_opt_set_null, &uwsgi.whitelist_context, UWSGI_OPT_IMMEDIATE},
{"ignore-sigpipe", no_argument, 0, "do not report (annoying) SIGPIPE", uwsgi_opt_true, &uwsgi.ignore_sigpipe, 0},
{"ignore-write-errors", no_argument, 0, "do not report (annoying) write()/writev() errors", uwsgi_opt_true, &uwsgi.ignore_write_errors, 0},
@@ -163,6 +172,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-required-heartbeat", required_argument, 0, "set the Emperor tolerance about heartbeats", uwsgi_opt_set_int, &uwsgi.emperor_heartbeat, 0},
{"emperor-pidfile", required_argument, 0, "write the Emperor pid in the specified file", uwsgi_opt_set_str, &uwsgi.emperor_pidfile, 0},
{"emperor-tyrant", no_argument, 0, "put the Emperor in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant, 0},
{"emperor-tyrant-nofollow", no_argument, 0, "do not follow symlinks when checking for uid/gid in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant_nofollow, 0},
{"emperor-stats", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0},
{"emperor-stats-server", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0},
{"early-emperor", no_argument, 0, "spawn the emperor as soon as possibile", uwsgi_opt_true, &uwsgi.early_emperor, 0},
@@ -170,6 +180,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-throttle", required_argument, 0, "set throttling level (in milliseconds) for bad behaving vassals (default 1000)", uwsgi_opt_set_int, &uwsgi.emperor_throttle, 0},
{"emperor-max-throttle", required_argument, 0, "set max throttling level (in milliseconds) for bad behaving vassals (default 3 minutes)", uwsgi_opt_set_int, &uwsgi.emperor_max_throttle, 0},
{"emperor-magic-exec", no_argument, 0, "prefix vassals config files with exec:// if they have the executable bit", uwsgi_opt_true, &uwsgi.emperor_magic_exec, 0},
{"emperor-on-demand-extension", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0},
{"emperor-on-demand-ext", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0},
{"emperor-on-demand-directory", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0},
{"emperor-on-demand-dir", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0},
{"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
{"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"vassals-inherit", required_argument, 0, "add config templates to vassals config", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
@@ -250,6 +267,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"chroot", required_argument, 0, "chroot() to the specified directory", uwsgi_opt_set_str, &uwsgi.chroot, 0},
{"uid", required_argument, 0, "setuid to the specified user/uid", uwsgi_opt_set_uid, NULL, 0},
{"gid", required_argument, 0, "setgid to the specified group/gid", uwsgi_opt_set_gid, NULL, 0},
{"immediate-uid", required_argument, 0, "setuid to the specified user/uid IMMEDIATELY", uwsgi_opt_set_immediate_uid, NULL, UWSGI_OPT_IMMEDIATE},
{"immediate-gid", required_argument, 0, "setgid to the specified group/gid IMMEDIATELY", uwsgi_opt_set_immediate_gid, NULL, UWSGI_OPT_IMMEDIATE},
{"no-initgroups", no_argument, 0, "disable additional groups set via initgroups()", uwsgi_opt_true, &uwsgi.no_initgroups, 0},
#ifdef UWSGI_CAP
{"cap", required_argument, 0, "set process capability", uwsgi_opt_set_cap, NULL, 0},
@@ -264,9 +283,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"exec-as-user", required_argument, 0, "run the specified command after privileges drop", uwsgi_opt_add_string_list, &uwsgi.exec_as_user, 0},
{"exec-as-user-atexit", required_argument, 0, "run the specified command before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.exec_as_user_atexit, 0},
{"exec-pre-app", required_argument, 0, "run the specified command before app loading", uwsgi_opt_add_string_list, &uwsgi.exec_pre_app, 0},
#ifdef UWSGI_INI
{"exec-post-app", required_argument, 0, "run the specified command after app loading", uwsgi_opt_add_string_list, &uwsgi.exec_post_app, 0},
{"ini", required_argument, 0, "load config from ini file", uwsgi_opt_load_ini, NULL, UWSGI_OPT_IMMEDIATE},
#endif
#ifdef UWSGI_YAML
{"yaml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
{"yal", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
@@ -366,6 +384,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"legion-setup", required_argument, 0, "action to call on legion setup", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-death", required_argument, 0, "action to call on legion death (shutdown of the instance)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-quorum", required_argument, 0, "set the quorum of a legion", uwsgi_opt_legion_quorum, NULL, UWSGI_OPT_MASTER},
{"legion-scroll", required_argument, 0, "set the scroll of a legion", uwsgi_opt_legion_scroll, NULL, UWSGI_OPT_MASTER},
{"legion-scroll-max-size", required_argument, 0, "set max size of legion scroll buffer", uwsgi_opt_set_16bit, &uwsgi.legion_scroll_max_size, 0},
{"legion-scroll-list-max-size", required_argument, 0, "set max size of legion scroll list buffer", uwsgi_opt_set_64bit, &uwsgi.legion_scroll_list_max_size, 0},
{"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
{"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
#endif
@@ -476,7 +497,6 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"die-on-idle", no_argument, 0, "shutdown uWSGI when idle", uwsgi_opt_true, &uwsgi.die_on_idle, 0},
{"mount", required_argument, 0, "load application under mountpoint", uwsgi_opt_add_string_list, &uwsgi.mounts, 0},
{"worker-mount", required_argument, 0, "load application under mountpoint in the specified worker or after workers spawn", uwsgi_opt_add_string_list, &uwsgi.mounts, 0},
{"grunt", no_argument, 0, "enable grunt mode (in-request fork)", uwsgi_opt_true, &uwsgi.grunt, 0},
{"threads", required_argument, 0, "run each worker in prethreaded mode with the specified number of threads", uwsgi_opt_set_int, &uwsgi.threads, UWSGI_OPT_THREADS},
{"thread-stacksize", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS},
@@ -498,6 +518,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"route-label", required_argument, 0, "add a routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
{"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0},
{"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0},
{"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
{"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
#endif
@@ -602,9 +623,6 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"allowed-modifiers", required_argument, 0, "comma separated list of allowed modifiers", uwsgi_opt_set_str, &uwsgi.allowed_modifiers, 0},
{"remap-modifier", required_argument, 0, "remap request modifier from one id to another", uwsgi_opt_set_str, &uwsgi.remap_modifier, 0},
{"app", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "use the more advanced \"mount\" option", 0},
{"static-offload-to-thread", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "use the more advanced \"offload-threads\" option", 0},
{"dump-options", no_argument, 0, "dump the full list of available options", uwsgi_opt_true, &uwsgi.dump_options, 0},
{"show-config", no_argument, 0, "show the current config reformatted as ini", uwsgi_opt_true, &uwsgi.show_config, 0},
{"print", required_argument, 0, "simple print", uwsgi_opt_print, NULL, 0},
@@ -774,8 +792,12 @@ void config_magic_table_fill(char *filename, char **magic_table) {
char *section = uwsgi_get_last_char(filename, ':');
if (section) {
*section = 0;
if (section == filename) {
goto reuse;
}
}
// we have a special case for symlinks
if (uwsgi_is_link(filename)) {
if (filename[0] != '/') {
@@ -829,6 +851,7 @@ void config_magic_table_fill(char *filename, char **magic_table) {
if (uwsgi_get_last_char(magic_table['s'], '.'))
magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.') - magic_table['s'], "", 0);
reuse:
if (section) {
magic_table['x'] = section+1;
*section = ':';
@@ -971,9 +994,18 @@ void grace_them_all(int signum) {
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying)
return;
int i;
if (uwsgi.lazy) {
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi_curse(i, SIGHUP);
}
return;
}
uwsgi.status.gracefully_reloading = 1;
int i;
int waitpid_status;
@@ -1006,8 +1038,6 @@ void grace_them_all(int signum) {
}
}
else if (uwsgi.workers[i].pid > 0) {
if (uwsgi.lazy)
uwsgi.workers[i].destroy = 1;
uwsgi_curse(i, SIGHUP);
}
}
@@ -1022,6 +1052,9 @@ void grace_them_all(int signum) {
void uwsgi_nuclear_blast() {
// the Emperor (as an example) cannot nuke itself
if (uwsgi.disable_nuclear_blast) return;
if (!uwsgi.workers) {
reap_them_all(0);
}
@@ -1264,6 +1297,7 @@ void signal_pidfile(int sig, char *filename) {
else {
uwsgi_log("error: invalid pidfile\n");
}
free(buffer);
}
/*static*/ void uwsgi_command_signal(char *opt) {
@@ -1590,10 +1624,6 @@ int main(int argc, char *argv[], char *envp[]) {
int i;
#ifdef UNBIT
//struct uidsec_struct us;
#endif
struct utsname uuts;
// signal mask is inherited, and sme process manager could make a real mess...
@@ -1695,7 +1725,13 @@ int main(int argc, char *argv[], char *envp[]) {
// count/set the current reload status
uwsgi_setup_reload();
#ifdef __CYGWIN__
SYSTEM_INFO si;
GetSystemInfo(&si);
uwsgi.page_size = si.dwPageSize;
#else
uwsgi.page_size = getpagesize();
#endif
uwsgi.binary_path = uwsgi_get_binary_path(argv[0]);
// ok we can now safely play with argv and environ
@@ -1731,6 +1767,7 @@ int main(int argc, char *argv[], char *envp[]) {
// set a couple of 'static' magic vars
uwsgi.magic_table['v'] = uwsgi.cwd;
uwsgi.magic_table['h'] = uwsgi.hostname;
uwsgi.magic_table['V'] = UWSGI_VERSION;
// you can embed a ini file in the uWSGi binary with default options
#ifdef UWSGI_EMBED_CONFIG
@@ -1779,12 +1816,14 @@ int main(int argc, char *argv[], char *envp[]) {
// initial log setup (files and daemonization)
uwsgi_setup_log();
#ifndef __CYGWIN__
// enable never-swap mode
if (uwsgi.never_swap) {
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
uwsgi_error("mlockall()");
}
}
#endif
if (uwsgi.flock2)
uwsgi_opt_flock(NULL, uwsgi.flock2, NULL);
@@ -3098,6 +3137,18 @@ void uwsgi_init_all_apps() {
}
}
usl = uwsgi.exec_post_app;
while (usl) {
uwsgi_log("running \"%s\" (post app)...\n", usl->value);
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
exit(1);
}
usl = usl->next;
}
}
void uwsgi_init_worker_mount_apps() {
@@ -3140,6 +3191,59 @@ void uwsgi_opt_true(char *opt, char *value, void *key) {
}
}
void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
gid_t gid = atoi(value);
if (gid == 0) {
struct group *ugroup = getgrnam(value);
if (ugroup)
gid = ugroup->gr_gid;
}
if (gid <= 0) {
uwsgi_log("uwsgi_opt_set_immediate_gid(): invalid gid %d\n", (int) gid);
exit(1);
}
if (setgid(gid)) {
uwsgi_error("uwsgi_opt_set_immediate_gid()/setgid()");
exit(1);
}
if (setgroups(0, NULL)) {
uwsgi_error("uwsgi_opt_set_immediate_gid()/setgroups()");
exit(1);
}
gid = getgid();
if (!gid) {
exit(1);
}
uwsgi_log("immediate gid: %d\n", (int) gid);
}
void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) {
uid_t uid = atoi(value);
if (uid == 0) {
struct passwd *upasswd = getpwnam(value);
if (upasswd)
uid = upasswd->pw_uid;
}
if (uid <= 0) {
uwsgi_log("uwsgi_opt_set_immediate_uid(): invalid uid %d\n", uid);
exit(1);
}
if (setuid(uid)) {
uwsgi_error("uwsgi_opt_set_immediate_uid()/setuid()");
exit(1);
}
uid = getuid();
if (!uid) {
exit(1);
}
uwsgi_log("immediate uid: %d\n", (int) uid);
}
void uwsgi_opt_set_int(char *opt, char *value, void *key) {
int *ptr = (int *) key;
if (value) {
@@ -3224,6 +3328,12 @@ void uwsgi_opt_set_str(char *opt, char *value, void *key) {
*ptr = (char *) value;
}
void uwsgi_opt_set_null(char *opt, char *value, void *key) {
char **ptr = (char **) key;
*ptr = NULL;
}
void uwsgi_opt_set_logger(char *opt, char *value, void *prefix) {
if (!value)
@@ -3457,7 +3567,8 @@ void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
void uwsgi_opt_load_plugin(char *opt, char *value, void *none) {
char *p = strtok(uwsgi_concat2(value, ""), ",");
char *plugins_list = uwsgi_concat2(value, "");
char *p = strtok(plugins_list, ",");
while (p != NULL) {
#ifdef UWSGI_DEBUG
uwsgi_debug("loading plugin %s\n", p);
@@ -3467,6 +3578,8 @@ void uwsgi_opt_load_plugin(char *opt, char *value, void *none) {
}
p = strtok(NULL, ",");
}
free(p);
free(plugins_list);
}
void uwsgi_opt_check_static(char *opt, char *value, void *foobar) {
@@ -3680,12 +3793,10 @@ void uwsgi_opt_deprecated(char *opt, char *value, void *message) {
void uwsgi_opt_load(char *opt, char *filename, void *none) {
#ifdef UWSGI_INI
if (uwsgi_endswith(filename, ".ini")) {
uwsgi_opt_load_ini(opt, filename, none);
return;
}
#endif
#ifdef UWSGI_XML
if (uwsgi_endswith(filename, ".xml")) {
uwsgi_opt_load_xml(opt, filename, none);
@@ -3712,6 +3823,9 @@ void uwsgi_opt_load(char *opt, char *filename, void *none) {
return;
}
#endif
// fallback to pluggable system
uwsgi_opt_load_config(opt, filename, none);
}
void uwsgi_opt_logic(char *opt, char *arg, void *func) {
@@ -3733,12 +3847,25 @@ void uwsgi_opt_logic(char *opt, char *arg, void *func) {
void uwsgi_opt_noop(char *opt, char *foo, void *bar) {
}
#ifdef UWSGI_INI
void uwsgi_opt_load_ini(char *opt, char *filename, void *none) {
config_magic_table_fill(filename, uwsgi.magic_table);
uwsgi_ini_config(filename, uwsgi.magic_table);
}
#endif
void uwsgi_opt_load_config(char *opt, char *filename, void *none) {
struct uwsgi_configurator *uc = uwsgi.configurators;
while(uc) {
if (uwsgi_endswith(filename, uc->name)) {
config_magic_table_fill(filename, uwsgi.magic_table);
uc->func(filename, uwsgi.magic_table);
return;
}
uc = uc->next;
}
uwsgi_log("unable to load configuration from %s\n", filename);
exit(1);
}
#ifdef UWSGI_XML
void uwsgi_opt_load_xml(char *opt, char *filename, void *none) {
@@ -3824,7 +3951,6 @@ void uwsgi_opt_flock(char *opt, char *filename, void *none) {
uwsgi_log("uWSGI ERROR: %s is locked by another instance\n", filename);
exit(1);
}
}
void uwsgi_opt_flock_wait(char *opt, char *filename, void *none) {
@@ -3838,7 +3964,6 @@ void uwsgi_opt_flock_wait(char *opt, char *filename, void *none) {
if (uwsgi_fcntl_lock(fd)) {
exit(1);
}
}
// report CFLAGS used for compiling the server
+13
View File
@@ -141,6 +141,7 @@ int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
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;
@@ -182,6 +183,18 @@ sendbody:
// reset for the next write
wsgi_req->write_pos = 0;
// now we need to check if the chunk must be stored
if (wsgi_req->cache_it) {
if (!wsgi_req->cached_response) {
wsgi_req->cached_response = uwsgi_buffer_new(len);
}
// if we are unable to append the buffer, we just stop caching it
if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
}
return UWSGI_OK;
}
+9
View File
@@ -0,0 +1,9 @@
config = {}
config['immediate-uid'] = 'roberto'
config['immediate-gid'] = 'roberto'
config['http-socket'] = ':9090'
config['env'] = { 'FOO=bar', 'TEST=topogigio' }
config['module'] = 'werkzeug.testapp:test_app'
return config
+8
View File
@@ -0,0 +1,8 @@
config = {}
config[1] = { ['http-socket']=':9090' }
config[2] = { ['env']='FOO=bar' }
config[3] = { ['env']='TEST=topogigio' }
config[4] = { ['module']='werkzeug.testapp:test_app' }
return config
+13 -25
View File
@@ -6,42 +6,30 @@ extern struct uwsgi_server uwsgi;
int uwsgi_request_admin(struct wsgi_request *wsgi_req) {
uint32_t opt_value = 0;
ssize_t len;
if (wsgi_req->uh.pktsize != 0 && wsgi_req->uh.pktsize != 4)
if (wsgi_req->uh->pktsize != 0 && wsgi_req->uh->pktsize != 4)
return UWSGI_OK;
// write request
if (wsgi_req->uh.pktsize == 4) {
if (wsgi_req->uh->pktsize == 4) {
memcpy(&opt_value, wsgi_req->buffer, 4);
uwsgi_log( "setting internal option %d to %d\n", wsgi_req->uh.modifier2, opt_value);
uwsgi.shared->options[wsgi_req->uh.modifier2] = opt_value;
uwsgi_log( "setting internal option %d to %d\n", wsgi_req->uh->modifier2, opt_value);
uwsgi.shared->options[wsgi_req->uh->modifier2] = opt_value;
// ACK
wsgi_req->uh.modifier1 = 255;
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 1;
len = write(wsgi_req->poll.fd, wsgi_req, 4);
if (len != 4) {
uwsgi_error("write()");
}
wsgi_req->uh->modifier1 = 255;
wsgi_req->uh->pktsize = 0;
wsgi_req->uh->modifier2 = 1;
uwsgi_response_write_body_do(wsgi_req, (char *)wsgi_req->uh , 4);
}
// get request
else {
uwsgi_log( "internal option %d = %d\n", wsgi_req->uh.modifier2, uwsgi.shared->options[wsgi_req->uh.modifier2]);
uwsgi_log( "internal option %d = %d\n", wsgi_req->uh->modifier2, uwsgi.shared->options[wsgi_req->uh->modifier2]);
wsgi_req->uh.modifier1 = 10;
wsgi_req->uh.pktsize = 4;
len = write(wsgi_req->poll.fd, wsgi_req, 4);
if (len != 4) {
uwsgi_error("write()");
return UWSGI_OK;
}
len = write(wsgi_req->poll.fd, (char *) &uwsgi.shared->options[wsgi_req->uh.modifier2], 4);
if (len != 4) {
uwsgi_error("write()");
}
wsgi_req->uh->modifier1 = 10;
wsgi_req->uh->pktsize = 4;
uwsgi_response_write_body_do(wsgi_req, (char *)wsgi_req->uh , 4);
uwsgi_response_write_body_do(wsgi_req, (char *) &uwsgi.shared->options[wsgi_req->uh->modifier2], 4);
}
return UWSGI_OK;
+46 -10
View File
@@ -9,9 +9,10 @@
extern struct uwsgi_server uwsgi;
struct carbon_server_list {
char *value; // server address
int healthy;
int errors;
char *hostname;
char *port;
struct carbon_server_list *next;
};
@@ -33,6 +34,7 @@ struct uwsgi_carbon {
char *root_node;
char *hostname_dot_replacement;
char *hostname;
int resolve_hostname;
struct uwsgi_stats_pusher *pusher;
} u_carbon;
@@ -46,6 +48,8 @@ static struct uwsgi_option carbon_options[] = {
{"carbon-retry-delay", required_argument, 0, "set connection retry delay in seconds (default 7)", uwsgi_opt_set_int, &u_carbon.retry_delay, 0},
{"carbon-root", required_argument, 0, "set carbon metrics root node (default 'uwsgi')", uwsgi_opt_set_str, &u_carbon.root_node, 0},
{"carbon-hostname-dots", required_argument, 0, "set char to use as a replacement for dots in hostname (dots are not replaced by default)", uwsgi_opt_set_str, &u_carbon.hostname_dot_replacement, 0},
{"carbon-name-resolve", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{"carbon-resolve-names", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -59,15 +63,32 @@ static void carbon_post_init() {
while(usl) {
struct carbon_server_list *u_server = uwsgi_calloc(sizeof(struct carbon_server_list));
u_server->value = usl->value;
u_server->healthy = 1;
u_server->errors = 0;
char *p = strtok(usl->value, ":");
while (p) {
if (!u_server->hostname) {
u_server->hostname = uwsgi_str(p);
}
else if (!u_server->port) {
u_server->port = uwsgi_str(p);
}
else break;
p = strtok(NULL, ":");
}
if (!u_server->hostname || !u_server->port) {
uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value);
usl = usl->next;
continue;
}
if (u_carbon.servers_data) {
u_server->next = u_carbon.servers_data;
}
u_carbon.servers_data = u_server;
uwsgi_log("[carbon] added server %s\n", usl->value);
uwsgi_log("[carbon] added server %s:%s\n", u_server->hostname, u_server->port);
usl = usl->next;
}
@@ -80,7 +101,7 @@ static void carbon_post_init() {
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
if (u_carbon.max_retries <= 0) u_carbon.max_retries = 1;
if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7;
if (!u_carbon.id) {
if (!u_carbon.id) {
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
for(i=0;i<(int)strlen(u_carbon.id);i++) {
@@ -145,6 +166,8 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
int i;
int fd;
int wok;
char *ip;
char *carbon_address = NULL;
for (i = 0; i < uwsgi.numproc; i++) {
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
@@ -157,31 +180,44 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
if (retry_cycle && usl->healthy)
// skip healthy servers during retry cycle
goto nxt;
if (retry_cycle && usl->healthy == 0)
uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->value, usl->errors);
uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->hostname, usl->errors);
if (!retry_cycle) {
usl->healthy = 1;
usl->errors = 0;
}
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
if (u_carbon.resolve_hostname) {
ip = uwsgi_resolve_ip(usl->hostname);
if (!ip) {
uwsgi_log("[carbon] Could not resolve hostname %s\n", usl->hostname);
goto nxt;
}
carbon_address = uwsgi_concat3(ip, ":", usl->port);
}
else {
carbon_address = uwsgi_concat3(usl->hostname, ":", usl->port);
}
fd = uwsgi_connect(carbon_address, u_carbon.timeout, 0);
if (fd < 0) {
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", usl->value);
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", carbon_address);
if (usl->errors < u_carbon.max_retries) {
u_carbon.need_retry = 1;
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
} else {
uwsgi_log("[carbon] Maximum number of retries for %s (%d)\n",
usl->value, u_carbon.max_retries);
carbon_address, u_carbon.max_retries);
usl->healthy = 0;
usl->errors = 0;
}
usl->healthy = 0;
usl->errors++;
free(carbon_address);
goto nxt;
}
free(carbon_address);
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
+1 -1
View File
@@ -4,7 +4,7 @@ extern struct uwsgi_server uwsgi;
static int uwsgi_echo_request(struct wsgi_request *wsgi_req) {
return uwsgi_response_write_body_do(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
return uwsgi_response_write_body_do(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize);
}
struct uwsgi_plugin echo_plugin = {
+2 -2
View File
@@ -49,7 +49,7 @@ void uwsgi_imperial_monitor_amqp_event(struct uwsgi_emperor_scanner *ues) {
}
if (msgsize > 0) {
emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0);
emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0, NULL);
}
end0:
@@ -88,7 +88,7 @@ end0:
emperor_respawn(ui_current, uwsgi_now());
}
else {
emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0);
emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0, NULL);
}
free(config_file);
+4 -2
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include "client/dbclient.h"
@@ -60,7 +60,9 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
vassal_gid = tmp_gid;
}
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid);
const char *socket_name = p.getStringField("socket");
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
+8 -1
View File
@@ -1,7 +1,14 @@
import os
NAME='emperor_mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
LIBS = []
if not 'UWSGI_MONGODB_NOLIB' in os.environ:
LIBS.append('-lmongoclient')
LIBS.append('-lboost_thread')
LIBS.append('-lboost_filesystem')
GCC_LIST = ['plugin', 'emperor_mongodb.cc']
+5 -1
View File
@@ -68,7 +68,11 @@ void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) {
vassal_uid = uwsgi_str_num(q_uid, strlen(q_uid));
vassal_gid = uwsgi_str_num(q_gid, strlen(q_gid));
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid);
char *socket_name = NULL;
if (PQnfields(res) > 5) {
socket_name = PQgetvalue(res, i, 5);
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid, socket_name);
}
}
+23 -4
View File
@@ -64,15 +64,16 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
int64_t more = 0;
size_t more_size = sizeof(more);
int i;
zmq_msg_t msg[5];
zmq_msg_t msg[6];
zmq_msg_init(&msg[0]);
zmq_msg_init(&msg[1]);
zmq_msg_init(&msg[2]);
zmq_msg_init(&msg[3]);
zmq_msg_init(&msg[4]);
zmq_msg_init(&msg[5]);
for(i=0;i<5;i++) {
for(i=0;i<6;i++) {
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
zmq_recvmsg(ues->data, &msg[i], ZMQ_DONTWAIT);
#else
@@ -105,6 +106,11 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
char *ez_gid = NULL;
size_t ez_gid_len = 0;
char *ez_socket_name = NULL;
size_t ez_socket_name_len = 0;
char *socket_name = NULL;
// config
if (i > 1) {
ez_config = zmq_msg_data(&msg[2]);
@@ -123,6 +129,12 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
ez_gid_len = zmq_msg_size(&msg[4]);
}
// gid
if (i > 4) {
ez_socket_name = zmq_msg_data(&msg[5]);
ez_socket_name_len = zmq_msg_size(&msg[5]);
}
char *name = uwsgi_concat2n(ez_name, ez_name_len, "", 0);
// ok let's start checking commands
@@ -142,10 +154,16 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
vassal_gid = uwsgi_str_num(ez_gid, ez_gid_len);
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid);
if (ez_socket_name) {
socket_name = uwsgi_concat2n(ez_socket_name, ez_socket_name_len, "", 0);
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid, socket_name);
if (config) {
free(config);
}
if (socket_name) {
free(socket_name);
}
}
// destroy an instance
else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 6)) {
@@ -158,7 +176,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
}
}
else {
uwsgi_log("[emperor-zeromq] unkonwn command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd);
uwsgi_log("[emperor-zeromq] unknown command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd);
}
free(name);
@@ -168,6 +186,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
zmq_msg_close(&msg[2]);
zmq_msg_close(&msg[3]);
zmq_msg_close(&msg[4]);
zmq_msg_close(&msg[5]);
}
// this is the event manager
+2 -1
View File
@@ -2,6 +2,7 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_rack ur;
extern struct uwsgi_plugin rack_plugin;
struct ufib {
int enabled;
@@ -45,7 +46,7 @@ static void fiber_schedule_to_req() {
int error = 0;
rb_protect(rb_fiber_schedule_to_req, 0, &error);
if (error) {
uwsgi_ruby_exception();
rack_plugin.exception_log(NULL);
rb_gc_unregister_address(&ufiber.fib[id]);
uwsgi.wsgi_req->async_status = UWSGI_OK;
}
+141
View File
@@ -0,0 +1,141 @@
#include <uwsgi.h>
#include <GeoIP.h>
#include <GeoIPCity.h>
struct uwsgi_geoip {
char *country_db;
char *city_db;
GeoIP *country;
GeoIP *city;
} ugeoip;
struct uwsgi_option uwsgi_geoip_options[] = {
{"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0},
{"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
};
static int uwsgi_geoip_init() {
if (ugeoip.country_db) {
ugeoip.country = GeoIP_open(ugeoip.country_db, GEOIP_MEMORY_CACHE);
if (!ugeoip.country) {
uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db);
exit(1);
}
}
if (ugeoip.city_db) {
ugeoip.city = GeoIP_open(ugeoip.city_db, GEOIP_MEMORY_CACHE);
if (!ugeoip.city) {
uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db);
exit(1);
}
}
return 0;
}
static char *uwsgi_route_var_geoip(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
uint32_t ip;
char ip_str[16];
// should be enough for geo coords
char lonlat[64];
memset(ip_str, 0, 16);
memcpy(ip_str, wsgi_req->remote_addr, wsgi_req->remote_addr_len);
if (inet_pton(AF_INET, ip_str, &ip) <= 0) {
return NULL;
}
ip = htonl(ip);
char *value = NULL;
// always prefer the city database;
GeoIP *g = ugeoip.city;
if (!g) {
g = ugeoip.country;
if (g) {
if (!uwsgi_strncmp(key, keylen, "country_code", 12)) {
value = (char *) GeoIP_country_code_by_ipnum(g, ip);
}
else if (!uwsgi_strncmp(key, keylen, "country_code3", 13)) {
value = (char *) GeoIP_country_code3_by_ipnum(g, ip);
}
else if (!uwsgi_strncmp(key, keylen, "country_name", 12)) {
value = (char *) GeoIP_country_name_by_ipnum(g, ip);
}
if (value) {
*vallen = strlen(value);
return uwsgi_str(value);
}
}
return NULL;
}
GeoIPRecord *gr = GeoIP_record_by_ipnum(g, ip);
if (!gr) return NULL;
// ok let's generate the output
if (!uwsgi_strncmp(key, keylen, "continent", 9)) {
value = gr->continent_code;
}
else if (!uwsgi_strncmp(key, keylen, "country_code", 12)) {
value = gr->country_code;
}
else if (!uwsgi_strncmp(key, keylen, "country_code3", 13)) {
value = gr->country_code3;
}
else if (!uwsgi_strncmp(key, keylen, "country_name", 12)) {
value = gr->country_name;
}
else if (!uwsgi_strncmp(key, keylen, "region", 6)) {
value = gr->region;
}
else if (!uwsgi_strncmp(key, keylen, "region_name", 11)) {
value = (char *) GeoIP_region_name_by_code(gr->country_code, gr->region);
}
else if (!uwsgi_strncmp(key, keylen, "city", 4)) {
value = gr->city;
}
else if (!uwsgi_strncmp(key, keylen, "postal_code", 11)) {
value = gr->postal_code;
}
else if (!uwsgi_strncmp(key, keylen, "latitude", 8) || !uwsgi_strncmp(key, keylen, "lat", 3)) {
snprintf(lonlat, 64, "%f", gr->latitude);
value = lonlat;
}
else if (!uwsgi_strncmp(key, keylen, "longitude", 9) || !uwsgi_strncmp(key, keylen, "lon", 3)) {
snprintf(lonlat, 64, "%f", gr->longitude);
value = lonlat;
}
else if (!uwsgi_strncmp(key, keylen, "dma", 3)) {
snprintf(lonlat, 64, "%d", gr->dma_code);
value = lonlat;
}
else if (!uwsgi_strncmp(key, keylen, "area", 4)) {
snprintf(lonlat, 64, "%d", gr->area_code);
value = lonlat;
}
if (value) {
*vallen = strlen(value);
char *ret = uwsgi_str(value);
GeoIPRecord_delete(gr);
return ret;
}
GeoIPRecord_delete(gr);
return NULL;
}
static void register_route_vars_geoip() {
struct uwsgi_route_var *urv = uwsgi_register_route_var("geoip", uwsgi_route_var_geoip);
urv->need_free = 1;
}
struct uwsgi_plugin geoip_plugin = {
.name = "geoip",
.options = uwsgi_geoip_options,
.init = uwsgi_geoip_init,
.on_load = register_route_vars_geoip,
};
+8
View File
@@ -0,0 +1,8 @@
NAME='geoip'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lGeoIP']
GCC_LIST = ['geoip']
+11 -1
View File
@@ -18,6 +18,7 @@ static void uwsgi_opt_setup_gevent(char *opt, char *value, void *null) {
static struct uwsgi_option gevent_options[] = {
{"gevent", required_argument, 0, "a shortcut enabling gevent loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_gevent, NULL, UWSGI_OPT_THREADS},
{"gevent-monkey-patch", no_argument, 0, "call gevent.monkey.patch_all() automatically on startup", uwsgi_opt_true, &ugevent.monkey, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -317,6 +318,16 @@ static void gevent_loop() {
exit(1);
}
// call gevent.monkey.patch_all() if requested
if (ugevent.monkey) {
PyObject *gevent_monkey_dict = get_uwsgi_pydict("gevent.monkey");
if (!gevent_monkey_dict) uwsgi_pyexit;
PyObject *gevent_monkey_patch_all = PyDict_GetItemString(gevent_monkey_dict, "patch_all");
if (!gevent_monkey_patch_all) uwsgi_pyexit;
PyObject *ret = python_call(gevent_monkey_patch_all, PyTuple_New(0), 0, NULL);
if (!ret) uwsgi_pyexit;
}
ugevent.spawn = PyDict_GetItemString(gevent_dict, "spawn");
if (!ugevent.spawn) uwsgi_pyexit;
@@ -329,7 +340,6 @@ static void gevent_loop() {
ugevent.greenlet_switch_args = PyTuple_New(0);
Py_INCREF(ugevent.greenlet_switch_args);
PyObject *gevent_get_hub = PyDict_GetItemString(gevent_dict, "get_hub");
ugevent.hub = python_call(gevent_get_hub, PyTuple_New(0), 0, NULL);
+1
View File
@@ -52,5 +52,6 @@ struct uwsgi_gevent {
PyObject *signal_watcher;
PyObject **watchers;
int destroy;
int monkey;
};
+2 -2
View File
@@ -587,6 +587,8 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
size_t len = main_peer->in->pos;
char *ptr = main_peer->in->buf;
hr->rnrn = 0;
for (j = 0; j < len; j++) {
if (*ptr == '\r' && (hr->rnrn == 0 || hr->rnrn == 2)) {
hr->rnrn++;
@@ -770,8 +772,6 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
}
hr->rnrn = 0;
hr->port = ugs->port;
hr->port_len = ugs->port_len;
switch(ugs->mode) {
+2
View File
@@ -108,3 +108,5 @@ int uwsgi_jvm_object_to_response_body(struct wsgi_request *, jobject);
jobject uwsgi_jvm_bytearray(char *, size_t);
char *uwsgi_jvm_bytearray2c(jobject);
void uwsgi_jvm_release_bytearray(jobject, char *);
jobject uwsgi_jvm_to_string(jobject);
+31 -8
View File
@@ -243,6 +243,15 @@ jobject uwsgi_jvm_entryset(jobject o) {
return uwsgi_jvm_call_object(o, mid);
}
jobject uwsgi_jvm_to_string(jobject o) {
jclass c = uwsgi_jvm_class_from_object(o);
if (!c) return NULL;
jmethodID mid = uwsgi_jvm_get_method_id_quiet(c, "toString", "()Ljava/lang/String;");
uwsgi_jvm_local_unref(c);
if (!mid) return NULL;
return uwsgi_jvm_call_object(o, mid);
}
int uwsgi_jvm_object_to_response_body(struct wsgi_request *wsgi_req, jobject body) {
// check for string
@@ -297,20 +306,35 @@ int uwsgi_jvm_object_to_response_body(struct wsgi_request *wsgi_req, jobject bod
ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len);
uwsgi_jvm_release_chars(chunk, c_body);
uwsgi_jvm_local_unref(chunk);
if (ret) goto done;
continue;
}
else if (uwsgi_jvm_object_is_instance(chunk, ujvm.bytearray_class)) {
if (uwsgi_jvm_object_is_instance(chunk, ujvm.bytearray_class)) {
char *c_body = uwsgi_jvm_bytearray2c(chunk);
size_t c_body_len = uwsgi_jvm_array_len(chunk);
ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len);
uwsgi_jvm_release_bytearray(chunk, c_body);
uwsgi_jvm_local_unref(chunk);
if (ret) goto done;
continue;
}
else {
uwsgi_log("body iterable item must be java/lang/String or array of bytes!!!\n");
uwsgi_jvm_local_unref(chunk);
goto done;
jobject str_o = uwsgi_jvm_to_string(chunk);
if (str_o) {
char *c_body = uwsgi_jvm_str2c(str_o);
size_t c_body_len = uwsgi_jvm_strlen(str_o);
ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len);
uwsgi_jvm_release_chars(str_o, c_body);
uwsgi_jvm_local_unref(str_o);
uwsgi_jvm_local_unref(chunk);
if (ret) goto done;
continue;
}
if (ret) goto done;
uwsgi_log("body iterable item must be java/lang/String or array of bytes!!!\n");
uwsgi_jvm_local_unref(chunk);
goto done;
}
done:
uwsgi_jvm_local_unref(chunks);
@@ -592,11 +616,10 @@ int uwsgi_jvm_consume_input_stream(struct wsgi_request *wsgi_req, size_t chunk,
break;
}
// get the body of the array
size_t buf_len = uwsgi_jvm_array_len(byte_buffer);
char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, byte_buffer, JNI_FALSE);
if (!buf) { ret = -1; break; }
//send
if (uwsgi_response_write_body_do(wsgi_req, buf, buf_len)) {
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) {
(*ujvm_env)->ReleaseByteArrayElements(ujvm_env, byte_buffer, (jbyte *) buf, 0);
ret = -1; break;
}
+27 -9
View File
@@ -1,4 +1,5 @@
import os,sys
import os
import shutil
NAME='jvm'
@@ -20,6 +21,9 @@ if operating_system == 'darwin':
if os.path.exists(jvm):
JVM_INCPATH = ["-Wno-deprecated-declarations", "-I%s" % jvm]
JVM_LIBPATH = ["-framework JavaVM"]
elif operating_system.startswith('cygwin'):
JVM_INCPATH = ['-I"/cygdrive/c/Program Files/Java/jdk1.7.0_17/include"', '-I"/cygdrive/c/Program Files/Java/jdk1.7.0_17/include/win32"']
JVM_LIBPATH = ['-L"/cygdrive/c/Program Files/Java/jdk1.7.0_17/jre/bin/server"']
else:
known_jvms = ('/usr/lib/jvm/java-7-openjdk', '/usr/local/openjdk7', '/usr/lib/jvm/java-6-openjdk', '/usr/local/openjdk', '/usr/java', '/usr/lib/jvm/java/')
for jvm in known_jvms:
@@ -33,15 +37,15 @@ else:
JVM_LIBPATH = ["-L%s/jre/lib/%s/server" % (jvm, arch)]
break
try:
JVM_INCPATH = os.environ['UWSGICONFIG_JVM_INCPATH']
except:
pass
try:
JVM_INCPATH = ['-I"' + os.environ['UWSGICONFIG_JVM_INCPATH'] + '"']
except:
pass
try:
JVM_LIBPATH = os.environ['UWSGICONFIG_JVM_LIBPATH']
except:
pass
try:
JVM_LIBPATH = ['-L"' + os.environ['UWSGICONFIG_JVM_LIBPATH'] + '"']
except:
pass
if not JVM_INCPATH or not JVM_LIBPATH:
print("unable to autodetect the JVM path, please specify UWSGICONFIG_JVM_INCPATH and UWSGICONFIG_JVM_LIBPATH environment vars")
@@ -66,3 +70,17 @@ def post_build(config):
if os.system("cd %s/plugins/jvm ; jar cvf uwsgi.jar *.class" % os.getcwd()) != 0:
os._exit(1)
print("*** uwsgi.jar available in %s/plugins/jvm/uwsgi.jar ***" % os.getcwd())
env = os.environ.get('VIRTUAL_ENV')
if env:
src = "%s/plugins/jvm/uwsgi.jar" % os.getcwd()
tgt = "%s/lib/uwsgi.jar" % env
shutil.copyfile(src, tgt)
print("*** uwsgi.jar had been copied to %s" % tgt)
plugin = "%s/jvm_plugin.so" % os.getcwd()
if os.path.exists(plugin):
tgt = "%s/bin/jvm_plugin.so" % env
shutil.copyfile(plugin, tgt)
print("*** jvm_plugin.so had been copied to %s" % tgt)
+1 -1
View File
@@ -8,7 +8,7 @@ except:
exec(f.read(), up)
f.close()
NAME='ring'
NAME='jwsgi'
CFLAGS = up['CFLAGS']
CFLAGS.append('-I%s' % jvm_path)
LDFLAGS = []
+173
View File
@@ -0,0 +1,173 @@
#include <uwsgi.h>
/*
this is an UDP logger encrypting each packet with the choosen algo, key and iv.
It is useful in cloud services without persistent storage for which you want to send logs to an external system.
Syntax: --logger/--req-logger crypto:addr=<udp_address>,algo=<algorithm>,secret=<key>,iv=<iv>,prefix=<prefix>
example:
uwsgi --plugin logcrypto --logger crypto:addr=127.0.0.1:1717,algo=bf-cbc,secret=ciaociao -M -p 4 -s :3031
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_crypto_logger_conf {
EVP_CIPHER_CTX *encrypt_ctx;
char *addr;
char *algo;
char *secret;
char *iv;
char *prefix;
size_t prefix_len;
};
static void uwsgi_crypto_logger_setup_encryption(struct uwsgi_crypto_logger_conf *uclc) {
if (!uwsgi.ssl_initialized) {
uwsgi_ssl_init();
}
uclc->encrypt_ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(uclc->encrypt_ctx);
const EVP_CIPHER *cipher = EVP_get_cipherbyname(uclc->algo);
if (!cipher) {
uwsgi_log_safe("[uwsgi-logcrypto] unable to find algorithm/cipher\n");
exit(1);
}
int cipher_len = EVP_CIPHER_key_length(cipher);
size_t s_len = strlen(uclc->secret);
if ((unsigned int) cipher_len > s_len) {
char *secret_tmp = uwsgi_malloc(cipher_len);
memcpy(secret_tmp, uclc->secret, s_len);
memset(secret_tmp + s_len, 0, cipher_len - s_len);
uclc->secret = secret_tmp;
}
int iv_len = EVP_CIPHER_iv_length(cipher);
size_t s_iv_len = 0;
if (uclc->iv) {
s_iv_len = strlen(uclc->iv);
}
if ((unsigned int) iv_len > s_iv_len) {
char *secret_tmp = uwsgi_malloc(iv_len);
memcpy(secret_tmp, uclc->iv, s_iv_len);
memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len);
uclc->iv = secret_tmp;
}
if (EVP_EncryptInit_ex(uclc->encrypt_ctx, cipher, NULL, (const unsigned char *) uclc->secret, (const unsigned char *) uclc->iv) <= 0) {
uwsgi_error_safe("uwsgi_crypto_logger_setup_encryption()/EVP_EncryptInit_ex()");
exit(1);
}
}
static ssize_t uwsgi_crypto_logger(struct uwsgi_logger *ul, char *message, size_t len) {
struct uwsgi_crypto_logger_conf *uclc = (struct uwsgi_crypto_logger_conf *) ul->data;
if (!ul->configured) {
uclc = uwsgi_calloc(sizeof(struct uwsgi_crypto_logger_conf));
if (uwsgi_kvlist_parse(ul->arg, strlen(ul->arg), ',', '=',
"addr", &uclc->addr,
"algo", &uclc->algo,
"secret", &uclc->secret,
"iv", &uclc->iv,
"prefix", &uclc->prefix,
NULL)) {
uwsgi_log_safe("[uwsgi-logcrypto] unable to parse options\n");
exit(1);
}
if (!uclc->addr || !uclc->algo || !uclc->secret) {
uwsgi_log_safe("[uwsgi-logcrypto] you have to specify at least addr,algo and secret options\n");
exit(1);
}
if (uclc->prefix) {
uclc->prefix_len = strlen(uclc->prefix);
}
char *colon = strchr(uclc->addr, ':');
if (!colon) {
uwsgi_log_safe("[uwsgi-logcrypto] invalid UDP address\n");
exit(1);
}
ul->addr_len = socket_to_in_addr(uclc->addr, colon, 0, &ul->addr.sa_in);
ul->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (ul->fd < 0) {
uwsgi_error_safe("uwsgi_crypto_logger()/socket()");
exit(1);
}
uwsgi_crypto_logger_setup_encryption(uclc);
ul->data = uclc;
ul->configured = 1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto error;
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
if (uclc->prefix) {
if (uwsgi_buffer_append(ub, uclc->prefix, uclc->prefix_len)) goto error;
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
}
if (uwsgi_buffer_append(ub, message, len)) goto error;
// let's encrypt the message
unsigned char *encrypted = uwsgi_malloc(ub->pos + EVP_MAX_BLOCK_LENGTH);
if (EVP_EncryptInit_ex(uclc->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
uwsgi_error_safe("[uwsgi-logcrypto] EVP_EncryptInit_ex()");
free(encrypted);
goto error;
}
int e_len = 0;
if (EVP_EncryptUpdate(uclc->encrypt_ctx, encrypted, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) {
uwsgi_error("[uwsgi-logcrypto] EVP_EncryptUpdate()");
free(encrypted);
goto error;
}
int tmplen = 0;
if (EVP_EncryptFinal_ex(uclc->encrypt_ctx, encrypted + e_len, &tmplen) <= 0) {
uwsgi_error("[uwsgi-logcrypto] EVP_EncryptFinal_ex()");
free(encrypted);
goto error;
}
uwsgi_buffer_destroy(ub);
ssize_t rlen = sendto(ul->fd, encrypted, e_len + tmplen, 0, (struct sockaddr *) &ul->addr.sa_in, ul->addr_len);
free(encrypted);
return rlen;
error:
uwsgi_buffer_destroy(ub);
return -1;
}
static void uwsgi_logcrypto_register() {
uwsgi_register_logger("crypto", uwsgi_crypto_logger);
}
struct uwsgi_plugin logcrypto_plugin = {
.name = "logcrypto",
.on_load = uwsgi_logcrypto_register,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='logcrypto'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['logcrypto']
+115 -22
View File
@@ -10,6 +10,7 @@ struct uwsgi_lua {
struct lua_State **L;
char *filename;
struct uwsgi_string_list *load;
} ulua;
#define lca(L, n) ulua_check_args(L, __FUNCTION__, n)
@@ -17,6 +18,7 @@ struct uwsgi_lua {
static struct uwsgi_option uwsgi_lua_options[] = {
{"lua", required_argument, 0, "load lua wsapi app", uwsgi_opt_set_str, &ulua.filename, 0},
{"lua-load", required_argument, 0, "load a lua file", uwsgi_opt_add_string_list, &ulua.load, 0},
{0, 0, 0, 0},
@@ -69,7 +71,7 @@ static int uwsgi_api_register_rpc(lua_State *L) {
lua_pushvalue(L, 2);
func = luaL_ref(L, LUA_REGISTRYINDEX);
uwsgi_log("registered function %d in global table\n", func);
uwsgi_log("registered function %d in Lua global table\n", func);
lfunc = func;
if (uwsgi_register_rpc((char *)name, 6, 0, (void *) lfunc)) {
@@ -387,36 +389,48 @@ static int uwsgi_lua_init(){
static void uwsgi_lua_app() {
int i;
if (ulua.filename) {
if (!ulua.filename && !ulua.load) return;
for(i=0;i<uwsgi.cores;i++) {
ulua.L[i] = luaL_newstate();
luaL_openlibs(ulua.L[i]);
luaL_register(ulua.L[i], "uwsgi", uwsgi_api);
if (luaL_loadfile(ulua.L[i], ulua.filename)) {
uwsgi_log("unable to load file %s: %s\n", ulua.filename, lua_tostring(ulua.L[i], -1));
exit(1);
struct uwsgi_string_list *usl = ulua.load;
while(usl) {
if (luaL_dofile(ulua.L[i], usl->value)) {
uwsgi_log("unable to load Lua file %s: %s\n", usl->value, lua_tostring(ulua.L[i], -1));
exit(1);
}
usl = usl->next;
}
if (ulua.filename) {
if (luaL_loadfile(ulua.L[i], ulua.filename)) {
uwsgi_log("unable to load Lua file %s: %s\n", ulua.filename, lua_tostring(ulua.L[i], -1));
exit(1);
}
// use a pcall
//lua_call(ulua.L[i], 0, 1);
if (lua_pcall(ulua.L[i], 0, 1, 0) != 0) {
uwsgi_log("%s\n", lua_tostring(ulua.L[i], -1));
exit(1);
}
// use a pcall
//lua_call(ulua.L[i], 0, 1);
if (lua_pcall(ulua.L[i], 0, 1, 0) != 0) {
uwsgi_log("%s\n", lua_tostring(ulua.L[i], -1));
exit(1);
}
// if the loaded lua app returns as a table, fetch the
// run function.
if (lua_istable(ulua.L[i], 2)) {
lua_pushstring(ulua.L[i], "run" );
lua_gettable(ulua.L[i], 2);
lua_replace(ulua.L[i], 2);
}
// if the loaded lua app returns as a table, fetch the
// run function.
if (lua_istable(ulua.L[i], 2)) {
lua_pushstring(ulua.L[i], "run" );
lua_gettable(ulua.L[i], 2);
lua_replace(ulua.L[i], 2);
}
if (! lua_isfunction(ulua.L[i], 2)) {
uwsgi_log("Can't find WSAPI entry point (no function, nor a table with function'run').\n");
exit(1);
if (! lua_isfunction(ulua.L[i], 2)) {
uwsgi_log("Can't find WSAPI entry point (no function, nor a table with function'run').\n");
exit(1);
}
}
}
}
}
@@ -665,13 +679,91 @@ static uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t a
#endif
if (sl <= 0xffff) {
memcpy(buffer, sv, sl);
lua_pop(L, 1);
return sl;
}
lua_pop(L, 1);
return 0;
}
static void uwsgi_lua_configurator_array(lua_State *L) {
int i;
int n = luaL_getn(L, -3);
for(i=1;i<=n;i++) {
lua_rawgeti(L, 1, i);
if (lua_istable(L, -1)) {
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
char *key = uwsgi_str((char *)lua_tostring(L, -2));
char *value = uwsgi_str((char *)lua_tostring(L, -1));
add_exported_option(key, value, 0);
lua_pop(L, 1);
}
}
}
}
static void uwsgi_lua_configurator(char *filename, char *magic_table[]) {
size_t len = 0;
uwsgi_log_initial("[uWSGI] getting Lua configuration from %s\n", filename);
char *code = uwsgi_open_and_read(filename, &len, 1, magic_table);
lua_State *L = luaL_newstate();
if (!L) {
uwsgi_log("unable to initialize Lua state for configuration\n");
exit(1);
}
luaL_openlibs(L);
if (luaL_dostring(L, code) != 0) {
uwsgi_log("error running Lua configurator: %s\n", lua_tostring(L, -1));
exit(1);
}
if (!lua_istable(L, -1)) {
uwsgi_log("Lua configurator has to return a table !!!\n");
exit(1);
}
lua_pushnil(L);
// we always use uwsgi_str to avoid GC destroying our strings
// and to be able to call lua_close at the end
while (lua_next(L, -2) != 0) {
// array ?
if (lua_isnumber(L, -2)) {
uwsgi_lua_configurator_array(L);
break;
}
// dictionary
else {
char *key = uwsgi_str((char *)lua_tostring(L, -2));
if (lua_istable(L, -1)) {
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
char *value = uwsgi_str((char *)lua_tostring(L, -1));
add_exported_option(key, value, 0);
lua_pop(L, 1);
}
}
else {
char *value = uwsgi_str((char *)lua_tostring(L, -1));
add_exported_option(key, value, 0);
}
}
lua_pop(L, 1);
}
// this will destroy the whole Lua state
lua_close(L);
}
static void uwsgi_register_lua_features() {
uwsgi_register_configurator(".lua", uwsgi_lua_configurator);
}
struct uwsgi_plugin lua_plugin = {
@@ -688,5 +780,6 @@ struct uwsgi_plugin lua_plugin = {
.code_string = uwsgi_lua_code_string,
.rpc = uwsgi_lua_rpc,
.on_load = uwsgi_register_lua_features,
};
+9
View File
@@ -0,0 +1,9 @@
#include <uwsgi.h>
#include "client/dbclient.h"
extern "C" int uwsgi_mongodb_version() {
// this is only a hack to force the linked to embed libmongoclient.a
mongo::DBClientConnection c;
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
#include <uwsgi.h>
/*
a fake plugin used for preloading mongodb library when only available as static.
*/
int uwsgi_mongodb_version(void);
struct uwsgi_plugin mongodb_plugin = {
.name = "mongodb",
.init = uwsgi_mongodb_version,
};
+8
View File
@@ -0,0 +1,8 @@
NAME='mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
GCC_LIST = ['plugin', 'foobar.cc']
+104 -7
View File
@@ -48,6 +48,7 @@ struct uwsgi_mono {
char *assembly_name ;
struct uwsgi_string_list *key;
struct uwsgi_string_list *index;
// GC frequency
uint64_t gc_freq;
@@ -61,6 +62,10 @@ struct uwsgi_mono {
MonoClass *application_class;
MonoClass *api_class;
MonoClass *byte_class;
MonoClassField *filepath;
// thunk
void (*process_request)(MonoObject *, MonoException **);
@@ -78,15 +83,53 @@ struct uwsgi_option uwsgi_mono_options[] = {
{"mono-config", required_argument, 0, "set the Mono config file", uwsgi_opt_set_str, &umono.config, 0},
{"mono-assembly", required_argument, 0, "load the specified main assembly (default: uwsgi.dll)", uwsgi_opt_set_str, &umono.assembly_name, 0},
{"mono-exec", required_argument, 0, "exec the specified assembly just before app loading", uwsgi_opt_add_string_list, &umono.exec, 0},
{"mono-index", required_argument, 0, "add an asp.net index file", uwsgi_opt_add_string_list, &umono.index, 0},
};
static MonoString *uwsgi_mono_method_GetFilePath(MonoObject *this) {
MonoString *ret = NULL;
// cache it !!!
MonoObject *filepath = mono_field_get_value_object(mono_domain_get(), umono.filepath, this);
if (filepath) {
return (MonoString *) filepath;
}
struct wsgi_request *wsgi_req = current_wsgi_req();
return mono_string_new_len(mono_domain_get(), wsgi_req->path_info, wsgi_req->path_info_len);
struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id];
char *path = uwsgi_concat3n(app->interpreter, strlen(app->interpreter), "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
size_t path_len = strlen(app->interpreter) + 1 + wsgi_req->path_info_len;
if (!uwsgi_file_exists(path)) {
free(path);
goto simple;
}
if (uwsgi_is_dir(path)) {
struct uwsgi_string_list *usl = umono.index;
while(usl) {
char *index = uwsgi_concat3n(path, path_len, "/", 1 , usl->value, usl->len);
if (uwsgi_file_exists(index)) {
ret = mono_string_new(mono_domain_get(), index + strlen(app->interpreter));
free(path);
free(index);
mono_field_set_value(this, umono.filepath, ret);
return ret;
}
free(index);
usl = usl->next;
}
}
free(path);
simple:
ret = mono_string_new_len(mono_domain_get(), wsgi_req->path_info, wsgi_req->path_info_len);
mono_field_set_value(this, umono.filepath, ret);
return ret;
}
static MonoString *uwsgi_mono_method_GetUriPath(MonoObject *this) {
return uwsgi_mono_method_GetFilePath(this);
}
static MonoString *uwsgi_mono_method_MapPath(MonoObject *this, MonoString *virtualPath) {
// first we need to get the physical path and append the virtualPath to it
struct wsgi_request *wsgi_req = current_wsgi_req();
struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id];
char *path = uwsgi_concat3n(app->interpreter, strlen(app->interpreter), "/", 1, mono_string_to_utf8(virtualPath), mono_string_length(virtualPath));
@@ -115,11 +158,6 @@ static MonoString *uwsgi_mono_method_GetHttpVersion(MonoObject *this) {
return mono_string_new_len(mono_domain_get(), wsgi_req->protocol, wsgi_req->protocol_len);
}
static MonoString *uwsgi_mono_method_GetUriPath(MonoObject *this) {
struct wsgi_request *wsgi_req = current_wsgi_req();
return mono_string_new_len(mono_domain_get(), wsgi_req->path_info, wsgi_req->path_info_len);
}
static MonoString *uwsgi_mono_method_GetRemoteAddress(MonoObject *this) {
struct wsgi_request *wsgi_req = current_wsgi_req();
return mono_string_new_len(mono_domain_get(), wsgi_req->remote_addr, wsgi_req->remote_addr_len);
@@ -221,6 +259,26 @@ static int uwsgi_mono_method_api_WorkerId() {
return uwsgi.mywid;
}
static MonoArray *uwsgi_mono_method_api_CacheGet(MonoString *key, MonoString *cache) {
char *c_key = mono_string_to_utf8(key);
uint16_t c_keylen = mono_string_length(key);
char *c_cache = NULL;
if (cache) {
c_cache = mono_string_to_utf8(cache);
}
uint64_t vallen = 0 ;
char *value = uwsgi_cache_magic_get(c_key, c_keylen, &vallen, c_cache);
if (value) {
MonoArray *ret = mono_array_new(mono_domain_get(), umono.byte_class, vallen);
char *buf = mono_array_addr(ret, char, 0);
memcpy(buf, value, vallen);
free(value);
return ret;
}
return NULL;
}
static void uwsgi_mono_add_internal_calls() {
// uWSGIRequest
mono_add_internal_call("uwsgi.uWSGIRequest::SendResponseFromMemory", uwsgi_mono_method_SendResponseFromMemory);
@@ -246,6 +304,7 @@ static void uwsgi_mono_add_internal_calls() {
mono_add_internal_call("uwsgi.api::Signal", uwsgi_mono_method_api_Signal);
mono_add_internal_call("uwsgi.api::WorkerId", uwsgi_mono_method_api_WorkerId);
mono_add_internal_call("uwsgi.api::RegisterSignal", uwsgi_mono_method_api_RegisterSignal);
mono_add_internal_call("uwsgi.api::CacheGet", uwsgi_mono_method_api_CacheGet);
}
static int uwsgi_mono_init() {
@@ -280,6 +339,16 @@ static void uwsgi_mono_create_jit() {
uwsgi_log("Mono JIT initialized on worker %d with version %s\n", uwsgi.mywid, umono.version);
MonoAssembly *assembly = mono_domain_assembly_open(umono.main_domain, umono.assembly_name);
if (!assembly) {
uwsgi_log("%s not found trying in global gac...\n", umono.assembly_name);
assembly = mono_assembly_load_with_partial_name(umono.assembly_name, NULL);
if (!assembly) {
if (!strcmp("uwsgi.dll", umono.assembly_name)) {
assembly = mono_assembly_load_with_partial_name("uwsgi", NULL);
}
}
}
if (!assembly) {
uwsgi_log("unable to load \"%s\" in the Mono domain\n", umono.assembly_name);
exit(1);
@@ -298,6 +367,23 @@ static void uwsgi_mono_create_jit() {
exit(1);
}
umono.byte_class = mono_class_from_name(mono_get_corlib(), "System", "Byte");
if (!umono.byte_class) {
uwsgi_log("unable to get reference to class System.Byte\n");
exit(1);
}
MonoClass *urequest = mono_class_from_name(image, "uwsgi", "uWSGIRequest");
if (!urequest) {
uwsgi_log("unable to get reference to class uwsgi.uWSGIRequest\n");
exit(1);
}
umono.filepath = mono_class_get_field_from_name(urequest, "filepath");
if (!umono.filepath) {
uwsgi_log("unable to get reference to field uwsgi.uWSGIRequest.filepath\n");
}
umono.api_class = mono_class_from_name(image, "uwsgi", "api");
if (!umono.api_class) {
uwsgi_log("unable to get reference to class uwsgi.api\n");
@@ -484,6 +570,17 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id];
app->requests++;
// check for directory without slash
char *path = uwsgi_concat3n(app->interpreter, strlen(app->interpreter), "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
size_t path_len = strlen(app->interpreter) + 1 + wsgi_req->path_info_len;
if (uwsgi_is_dir(path) && path[path_len-1] != '/') {
free(path);
uwsgi_redirect_to_slash(wsgi_req);
return UWSGI_OK;
}
free(path);
MonoException *exc = NULL;
umono.process_request(app->callable, &exc);
+10
View File
@@ -6,6 +6,8 @@ using System.Web.Hosting;
using System.Text;
using System.Runtime.CompilerServices;
[assembly: System.Reflection.AssemblyVersion ("0.0.0.1")]
namespace uwsgi {
public delegate void uWSGIHook();
@@ -32,10 +34,15 @@ namespace uwsgi {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern public static void Signal(int signum);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern public static byte[] CacheGet(string key, string cache=null);
}
class uWSGIRequest: HttpWorkerRequest {
private String filepath = null;
public override string GetAppPath() {
return "/";
}
@@ -135,6 +142,9 @@ namespace uwsgi {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern public override void SendUnknownResponseHeader (string name, string value);
public string hack_current_filename() {
return filepath;
}
}
public class uWSGIApplicationHost: MarshalByRefObject {
+4 -2
View File
@@ -7,6 +7,8 @@ LIBS = os.popen('pkg-config --libs mono-2').read().rstrip().split()
GCC_LIST = ['mono_plugin']
def post_build(config):
if os.system("mcs /target:library /r:System.Web.dll plugins/mono/uwsgi.cs") != 0:
if os.system("sn -k plugins/mono/uwsgi.key") != 0:
os._exit(1)
print("*** uwsgi.dll available in %s/plugins/mono ***" % os.getcwd())
if os.system("mcs /target:library /r:System.Web.dll /keyfile:plugins/mono/uwsgi.key plugins/mono/uwsgi.cs") != 0:
os._exit(1)
print("*** uwsgi.dll available in %s/plugins/mono/uwsgi.dll ***" % os.getcwd())
+1 -1
View File
@@ -96,7 +96,7 @@ static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
}
else {
char *sl = SG(sapi_headers).http_status_line;
uwsgi_response_prepare_headers(wsgi_req, sl, strlen(sl));
uwsgi_response_prepare_headers(wsgi_req, sl + 8 , strlen(sl) - 8);
}
h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
+4 -2
View File
@@ -305,7 +305,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
// cache most used values
wi->error = PyFile_FromFile(stderr, "wsgi_errors", "w", NULL);
Py_INCREF(wi->error);
Py_INCREF((PyObject *)wi->error);
wi->gateway_version = PyTuple_New(2);
PyTuple_SetItem(wi->gateway_version, 0, PyInt_FromLong(1));
@@ -563,7 +563,9 @@ PyObject *uwsgi_file_loader(void *arg1) {
char *callable = up.callable;
if (!callable) callable = "application";
char *py_filename = uwsgi_concat2("uwsgi_file_", uwsgi_pythonize(filename));
char *pythonized_filename = uwsgi_pythonize(filename);
char *py_filename = uwsgi_concat2("uwsgi_file_", pythonized_filename);
free(pythonized_filename);
wsgi_file_module = uwsgi_pyimport_by_filename(py_filename, filename);
if (!wsgi_file_module) {
+2 -4
View File
@@ -55,7 +55,6 @@ void uwsgi_opt_pyver(char *opt, char *foo, void *bar) {
}
#ifdef UWSGI_INI
void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) {
uwsgi_opt_load_ini(opt, value, NULL);
@@ -72,7 +71,6 @@ void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) {
}
}
#endif
struct uwsgi_option uwsgi_python_options[] = {
{"wsgi-file", required_argument, 0, "load .wsgi file", uwsgi_opt_set_str, &up.file_config, 0},
@@ -121,13 +119,13 @@ struct uwsgi_option uwsgi_python_options[] = {
{"web3", required_argument, 0, "load a web3 app", uwsgi_opt_set_str, &up.web3, 0},
{"pump", required_argument, 0, "load a pump app", uwsgi_opt_set_str, &up.pump, 0},
{"wsgi-lite", required_argument, 0, "load a wsgi-lite app", uwsgi_opt_set_str, &up.wsgi_lite, 0},
#ifdef UWSGI_INI
{"ini-paste", required_argument, 0, "load a paste.deploy config file containing uwsgi section", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
{"ini-paste-logged", required_argument, 0, "load a paste.deploy config file containing uwsgi section (load loggers too)", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"reload-os-env", no_argument, 0, "force reload of os.environ at each request", uwsgi_opt_true, &up.reload_os_env, 0},
#ifndef __CYGWIN__
#ifndef UWSGI_PYPY
{"no-site", no_argument, 0, "do not import site module", uwsgi_opt_true, &Py_NoSiteFlag, 0},
#endif
#endif
{"pyshell", no_argument, 0, "run an interactive python shell in the uWSGI environment", uwsgi_opt_pyshell, NULL, 0},
{"pyshell-oneshot", no_argument, 0, "run an interactive python shell in the uWSGI environment (one-shot variant)", uwsgi_opt_pyshell, NULL, 0},
+9 -6
View File
@@ -335,28 +335,31 @@ shit:
if (code_start) {
code_end = name_to_symbol_pkg(fullname2, "end");
if (code_end) {
char *symbolized;
PyObject *mod = PyImport_AddModule(fullname);
if (!mod) goto clear;
PyObject *dict = PyModule_GetDict(mod);
if (!dict) goto clear;
source = uwsgi_concat2n(code_start, code_end-code_start, "", 0);
modname = uwsgi_concat3("sym://", symbolize(fullname), "___init___py");
symbolized = symbolize(fullname);
modname = uwsgi_concat3("sym://", symbolized, "___init___py");
PyObject *pkgpath = Py_BuildValue("[O]", PyString_FromString(modname));
PyDict_SetItemString(dict, "__path__", pkgpath);
PyDict_SetItemString(dict, "__loader__", self);
code = Py_CompileString(source, modname, Py_file_input);
if (!code) {
PyErr_Print();
goto shit2;
}
code = Py_CompileString(source, modname, Py_file_input);
if (!code) {
PyErr_Print();
goto shit2;
}
mod = PyImport_ExecCodeModuleEx(fullname, code, modname);
Py_DECREF(code);
shit2:
free(symbolized);
free(source);
free(modname);
free(fullname2);
+54 -59
View File
@@ -454,6 +454,57 @@ PyObject *py_uwsgi_i_am_the_lord(PyObject * self, PyObject * args) {
Py_INCREF(Py_False);
return Py_False;
}
PyObject *py_uwsgi_lord_scroll(PyObject * self, PyObject * args) {
char *legion_name = NULL;
if (!PyArg_ParseTuple(args, "s:lord_scroll", &legion_name)) {
return NULL;
}
uint16_t rlen = 0;
char *buf = uwsgi_legion_lord_scroll(legion_name, &rlen);
if (!buf) {
Py_INCREF(Py_None);
return Py_None;
}
PyObject *ret = PyString_FromStringAndSize(buf, rlen);
free(buf);
return ret;
}
static void scrolls_items(uint16_t pos, char *key, uint16_t keylen, void *data) {
PyObject *list = (PyObject *) data;
PyObject *zero = PyString_FromStringAndSize(key, keylen);
PyList_Append(list, zero);
Py_DECREF(zero);
}
PyObject *py_uwsgi_scrolls(PyObject * self, PyObject * args) {
char *legion_name = NULL;
if (!PyArg_ParseTuple(args, "s:scrolls", &legion_name)) {
return NULL;
}
uint64_t rlen = 0;
char *buf = uwsgi_legion_scrolls(legion_name, &rlen);
if (!buf) goto end;
PyObject *list = PyList_New(0);
if (uwsgi_hooked_parse_array(buf, rlen, scrolls_items, list)) {
goto error;
}
free(buf);
return list;
error:
free(buf);
end:
Py_INCREF(Py_None);
return Py_None;
}
#endif
PyObject *py_uwsgi_register_signal(PyObject * self, PyObject * args) {
@@ -717,7 +768,7 @@ static PyObject *py_uwsgi_route(PyObject * self, PyObject * args) {
return NULL;
}
int ret = uwsgi_route_api_func(wsgi_req, uwsgi_str(router_name), uwsgi_str(router_args));
int ret = uwsgi_route_api_func(wsgi_req, router_name, uwsgi_str(router_args));
return PyInt_FromLong(ret);
}
#endif
@@ -2331,63 +2382,6 @@ PyObject *py_uwsgi_parse_file(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
pid_t grunt_pid;
struct wsgi_request *wsgi_req = py_current_wsgi_req();
if (uwsgi.grunt) {
uwsgi_log("spawning a grunt from worker %d (pid :%d)...\n", uwsgi.mywid, uwsgi.mypid);
}
else {
uwsgi_log("grunt support is disabled !!!\n");
goto clear;
}
// use a normal fork here
grunt_pid = fork();
if (grunt_pid < 0) {
uwsgi_error("fork()");
goto clear;
}
// now i am a grunt, avoid it making mess
else if (grunt_pid == 0) {
// it will no more accepts requests
uwsgi_close_all_sockets();
// create a new session
setsid();
// exit on SIGPIPE
signal(SIGPIPE, (void *) &end_me);
// here we create a new worker. Each grunt will race on this datas, so do not rely on them
uwsgi.mywid = uwsgi.numproc + 1;
uwsgi.mypid = getpid();
memset(&uwsgi.workers[uwsgi.mywid], 0, sizeof(struct uwsgi_worker));
// this is pratically useless...
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
// this field will be overwrite after each call
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
// reset the random seed
uwsgi_python_reset_random_seed();
// TODO
// manage thread in grunt processes
Py_INCREF(Py_True);
return Py_True;
}
// close connection on the original worker
if (PyTuple_Size(args) == 0) {
if (wsgi_req->socket) {
wsgi_req->socket->proto_close(wsgi_req);
}
wsgi_req->fd_closed = 1;
}
clear:
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef uwsgi_spooler_methods[] = {
#ifdef PYTHREE
{"send_to_spooler", (PyCFunction) py_uwsgi_send_spool, METH_VARARGS | METH_KEYWORDS, ""},
@@ -2434,7 +2428,6 @@ static PyMethodDef uwsgi_advanced_methods[] = {
{"get_logvar", py_uwsgi_get_logvar, METH_VARARGS, ""},
{"alarm", py_uwsgi_alarm, METH_VARARGS, ""},
{"disconnect", py_uwsgi_disconnect, METH_VARARGS, ""},
{"grunt", py_uwsgi_grunt, METH_VARARGS, ""},
{"lock", py_uwsgi_lock, METH_VARARGS, ""},
{"is_locked", py_uwsgi_is_locked, METH_VARARGS, ""},
{"unlock", py_uwsgi_unlock, METH_VARARGS, ""},
@@ -2471,6 +2464,8 @@ static PyMethodDef uwsgi_advanced_methods[] = {
{"logsize", py_uwsgi_logsize, METH_VARARGS, ""},
#ifdef UWSGI_SSL
{"i_am_the_lord", py_uwsgi_i_am_the_lord, METH_VARARGS, ""},
{"lord_scroll", py_uwsgi_lord_scroll, METH_VARARGS, ""},
{"scrolls", py_uwsgi_scrolls, METH_VARARGS, ""},
#endif
{"async_sleep", py_uwsgi_async_sleep, METH_VARARGS, ""},
{"async_connect", py_uwsgi_async_connect, METH_VARARGS, ""},
+22 -8
View File
@@ -58,11 +58,12 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
char *status_line = NULL;
size_t status_line_len = 0;
#ifdef PYTHREE
PyObject *zero = NULL;
PyObject *zero2 = NULL;
if (self != Py_None) {
PyObject *zero = PyUnicode_AsASCIIString(head);
zero = PyUnicode_AsASCIIString(head);
status_line = PyBytes_AsString(zero);
status_line_len = PyBytes_Size(zero);
Py_DECREF(zero);
}
else {
status_line = PyBytes_AsString(head);
@@ -73,9 +74,15 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
status_line_len = PyString_Size(head);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, status_line, status_line_len)) {
#ifdef PYTHREE
Py_DECREF(zero);
#endif
return PyErr_Format(PyExc_TypeError, "unable to set HTTP status line");
}
#ifdef PYTHREE
Py_DECREF(zero);
#endif
headers = PyTuple_GetItem(args, 1);
if (!headers) {
@@ -125,10 +132,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
PyObject *zero = PyUnicode_AsASCIIString(h_key);
zero = PyUnicode_AsASCIIString(h_key);
k = PyBytes_AsString(zero);
kl = PyBytes_Size(zero);
Py_DECREF(zero);
}
else {
k = PyBytes_AsString(h_key);
@@ -141,10 +147,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
PyObject *zero = PyUnicode_AsASCIIString(h_value);
v = PyBytes_AsString(zero);
vl = PyBytes_Size(zero);
Py_DECREF(zero);
zero2 = PyUnicode_AsASCIIString(h_value);
v = PyBytes_AsString(zero2);
vl = PyBytes_Size(zero2);
}
else {
v = PyBytes_AsString(h_value);
@@ -156,9 +161,18 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#endif
if (uwsgi_response_add_header(wsgi_req, k, kl, v, vl)) {
#ifdef PYTHREE
Py_DECREF(zero);
Py_DECREF(zero2);
#endif
return PyErr_Format(PyExc_TypeError, "unable to add header to the response");
}
#ifdef PYTHREE
Py_DECREF(zero);
Py_DECREF(zero2);
#endif
}
if (up.start_response_nodelay) {
+14 -14
View File
@@ -320,7 +320,7 @@ uint16_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[],
ret = rb_protect(rack_call_rpc_handler, rb_args, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
return 0;
}
@@ -489,7 +489,7 @@ void uwsgi_rack_preinit_apps() {
int error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
usl = usl->next;
}
@@ -519,7 +519,7 @@ void uwsgi_rack_init_apps(void) {
error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
usl = usl->next;
}
@@ -527,7 +527,7 @@ void uwsgi_rack_init_apps(void) {
if (ur.rack) {
ur.dispatcher = rb_protect(init_rack_app, rb_str_new2(ur.rack), &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
if (ur.dispatcher == Qnil) {
@@ -551,7 +551,7 @@ void uwsgi_rack_init_apps(void) {
uwsgi_log("loading rails app %s\n", ur.rails);
rb_protect( require_rails, 0, &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
uwsgi_log("rails app %s ready\n", ur.rails);
@@ -573,7 +573,7 @@ void uwsgi_rack_init_apps(void) {
if (acim_call == Qtrue) {
ur.dispatcher = rb_protect(uwsgi_rb_call_new, ac_dispatcher, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
}
@@ -583,7 +583,7 @@ void uwsgi_rack_init_apps(void) {
uwsgi_log("non-rack rails version detected...loading thin adapter...\n");
rb_protect( require_thin, 0, &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
VALUE thin_rack = rb_const_get(rb_cObject, rb_intern("Rack"));
@@ -591,7 +591,7 @@ void uwsgi_rack_init_apps(void) {
VALUE thin_rack_adapter_rails = rb_const_get(thin_rack_adapter, rb_intern("Rails"));
ur.dispatcher = rb_protect( uwsgi_rb_call_new, thin_rack_adapter_rails, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
}
@@ -963,7 +963,7 @@ VALUE init_rack_app( VALUE script ) {
#endif
rb_protect( require_rack, 0, &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
return Qnil;
}
@@ -1038,7 +1038,7 @@ int uwsgi_rack_mule(char *opt) {
if (uwsgi_endswith(opt, (char *)".rb")) {
rb_protect( uwsgi_require_file, rb_str_new2(opt), &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
return 0;
}
return 1;
@@ -1063,7 +1063,7 @@ void uwsgi_rb_post_fork() {
// call the post_fork_hook
rb_protect(uwsgi_rb_pfh, 0, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
}
@@ -1081,7 +1081,7 @@ int uwsgi_rack_mule_msg(char *message, size_t len) {
VALUE arg = rb_str_new(message, len);
rb_protect(uwsgi_rb_mmh, arg, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
return 1;
}
@@ -1107,7 +1107,7 @@ int uwsgi_rack_signal_handler(uint8_t sig, void *handler) {
rb_ary_store(args, 1, rbsig);
rb_protect(rack_call_signal_handler, args, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
rb_gc();
return -1;
}
@@ -1155,7 +1155,7 @@ int uwsgi_rack_spooler(char *filename, char *buf, uint16_t len, char *body, size
VALUE ret = rb_protect(uwsgi_rb_do_spooler, spool_dict, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
rb_gc();
return -1;
}
+7 -4
View File
@@ -244,7 +244,7 @@ static int uwsgi_ring_request(struct wsgi_request *wsgi_req) {
// *** REQUEST GENERATION ***
if (uwsgi_ring_request_item_add_keyword(hm, "request-method", 14, wsgi_req->method, wsgi_req->method_len)) goto end;
if (uwsgi_ring_request_item_add(hm, "uri", 3, wsgi_req->uri, wsgi_req->uri_len)) goto end;
if (uwsgi_ring_request_item_add(hm, "uri", 3, wsgi_req->path_info, wsgi_req->path_info_len)) goto end;
if (uwsgi_ring_request_item_add(hm, "server-name", 11, wsgi_req->host, wsgi_req->host_len)) goto end;
// server-port is required !!!
@@ -450,10 +450,13 @@ static int uwsgi_ring_setup() {
}
char *namespace = uwsgi_str(uring.app);
char *colon = strchr(namespace, ':');
char *colon = strchr(namespace, '/');
if (!colon) {
uwsgi_log("invalid ring application namespace/handler\n");
exit(1);
colon = strchr(namespace, ':');
if (!colon) {
uwsgi_log("invalid ring application namespace/handler\n");
exit(1);
}
}
*colon = 0;
uring.handler = uwsgi_jvm_call_object_static(clojure, clojure_var, uwsgi_jvm_str(namespace, 0), uwsgi_jvm_str(colon+1, 0));
+13
View File
@@ -1,3 +1,6 @@
import os
import shutil
jvm_path = 'plugins/jvm'
up = {}
@@ -14,3 +17,13 @@ CFLAGS.append('-I%s' % jvm_path)
LDFLAGS = []
LIBS = []
GCC_LIST = ['ring_plugin']
def post_build(config):
env = os.environ.get('VIRTUAL_ENV')
if env:
plugin = "%s/ring_plugin.so" % os.getcwd()
if os.path.exists(plugin):
tgt = "%s/bin/ring_plugin.so" % env
shutil.copyfile(plugin, tgt)
print("*** ring_plugin.so had been copied to %s" % tgt)
@@ -4,6 +4,9 @@
#ifdef __linux__
#include <crypt.h>
#elif defined(__CYGWIN__)
#include <crypt.h>
pthread_mutex_t ur_basicauth_crypt_mutex;
#else
pthread_mutex_t ur_basicauth_crypt_mutex;
#endif
+97 -66
View File
@@ -10,83 +10,133 @@ extern struct uwsgi_server uwsgi;
syntax:
route = /^foobar1(.*)/ cache:key=foo$1poo,type=body
route = /^foobar1 cache:var=PATH_INFO,type=body
route = /^foobar2 cache:var=REQUEST_URI,type=full
route = /^foobar3 cache:var=REQUEST_URI,type=body,content_type=text/html
route = /^foobar1(.*)/ cache:key=foo$1poo,content_type=text/html,name=foobar
*/
struct uwsgi_router_cache_conf {
// the name of the cache
char *name;
size_t name_len;
char *key;
size_t key_len;
char *var;
char *type;
long var_offset;
long var_offset_len;
char *content_type;
char *name;
size_t content_type_len;
// 0 -> full, 1 -> body
int type_num;
struct uwsgi_cache *cache;
char *expires_str;
uint64_t expires;
};
// be tolerant on errors
static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
// overwrite previous run
if (wsgi_req->cache_it) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
if (wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it_to);
wsgi_req->cache_it_to = NULL;
}
// build key and name
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
wsgi_req->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!wsgi_req->cache_it) return UWSGI_ROUTE_NEXT;
if (urcc->name) {
wsgi_req->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len);
if (!wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
}
wsgi_req->cache_it_expires = urcc->expires;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
if (!uwsgi.cache_max_items) return UWSGI_ROUTE_NEXT;
char *c_k = NULL;
uint16_t c_k_len = 0;
int k_need_free = 0;
if (urcc->key) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
c_k = uwsgi_regexp_apply_ovec(*subject, *subject_len, urcc->key, urcc->key_len, ur->ovector, ur->ovn);
c_k_len = strlen(c_k);
k_need_free = 1;
}
else {
char **key = (char **) (((char *) wsgi_req) + urcc->var_offset);
uint16_t *keylen = (uint16_t *) (((char *) wsgi_req) + urcc->var_offset_len);
c_k = *key;
c_k_len = *keylen;
}
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get(c_k, c_k_len, &valsize, urcc->name);
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, urcc->name);
uwsgi_buffer_destroy(ub);
if (value) {
if (urcc->type_num == 1) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
}
// body only
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
uwsgi_response_write_body_do(wsgi_req, value, valsize);
free(value);
if (k_need_free) free(c_k);
if (ur->custom)
return UWSGI_ROUTE_NEXT;
return UWSGI_ROUTE_BREAK;
}
if (k_need_free) free(c_k);
return UWSGI_ROUTE_NEXT;
error:
free(value);
if (k_need_free) free(c_k);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cache_store;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"name", &urcc->name,
"expires", &urcc->expires_str, NULL)) {
uwsgi_log("invalid cachestore route syntax: %s\n", args);
goto error;
}
if (urcc->key) {
urcc->key_len = strlen(urcc->key);
}
if (urcc->name) {
urcc->name_len = strlen(urcc->name);
}
if (!urcc->key) {
uwsgi_log("invalid cachestore route syntax: you need to specify a cache key\n");
goto error;
}
if (urcc->expires_str) {
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
}
ur->data2 = urcc;
return 0;
error:
if (urcc->key) free(urcc->key);
if (urcc->name) free(urcc->name);
if (urcc->expires_str) free(urcc->expires_str);
return -1;
}
static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cache;
ur->data = args;
@@ -94,10 +144,9 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"var", &urcc->var,
"content_type", &urcc->content_type,
"name", &urcc->name,
"type", &urcc->type, NULL)) {
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
@@ -106,35 +155,15 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
urcc->key_len = strlen(urcc->key);
}
if (!urcc->key && !urcc->var) {
uwsgi_log("invalid route syntax: you need to specify a cache key or var\n");
if (!urcc->key) {
uwsgi_log("invalid route syntax: you need to specify a cache key\n");
exit(1);
}
if (!urcc->type) urcc->type = "full";
if (!urcc->content_type) urcc->content_type = "text/html";
urcc->content_type_len = strlen(urcc->content_type);
if (urcc->var) {
if (!strcmp(urcc->var, "REQUEST_URI")) {
urcc->var_offset = offsetof(struct wsgi_request, uri);
urcc->var_offset_len = offsetof(struct wsgi_request, uri_len);
}
else if (!strcmp(urcc->var, "PATH_INFO")) {
urcc->var_offset = offsetof(struct wsgi_request, path_info);
urcc->var_offset_len = offsetof(struct wsgi_request, path_info_len);
}
else {
urcc->var_offset = offsetof(struct wsgi_request, uri);
urcc->var_offset_len = offsetof(struct wsgi_request, uri_len);
}
}
if (!strcmp(urcc->type, "body")) {
urcc->type_num = 1;
}
ur->data2 = urcc;
return 0;
}
@@ -148,6 +177,8 @@ static int uwsgi_router_cache_continue(struct uwsgi_route *ur, char *args) {
static void router_cache_register() {
uwsgi_register_router("cache", uwsgi_router_cache);
uwsgi_register_router("cache-continue", uwsgi_router_cache_continue);
uwsgi_register_router("cachestore", uwsgi_router_cache_store);
uwsgi_register_router("cache-store", uwsgi_router_cache_store);
}
struct uwsgi_plugin router_cache_plugin = {
+208
View File
@@ -40,10 +40,218 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
#ifdef UWSGI_ROUTING
static int uwsgi_routing_func_rpc(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
char *argv[UMAX8];
// this is the size of each argument
uint16_t argvs[UMAX8];
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
uint16_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
ret = UWSGI_ROUTE_BREAK;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;}
if (uwsgi_response_add_content_length(wsgi_req, size)) {free(response) ; goto end;}
uwsgi_response_write_body_do(wsgi_req, response, size);
free(response);
end:
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
}
}
return ret;
}
// "next" || "continue" || "break(.*)" || "goon" || "goto .+"
static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
char *argv[UMAX8];
// this is the size of each argument
uint16_t argvs[UMAX8];
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
uint16_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
ret = UWSGI_ROUTE_CONTINUE;
if (!uwsgi_strncmp(response, size, "next", 4 )) {
ret = UWSGI_ROUTE_NEXT;
}
else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
ret = UWSGI_ROUTE_CONTINUE;
}
else if (!uwsgi_strncmp(response, size, "goon", 4 )) {
ret = UWSGI_ROUTE_GOON;
}
else if (!uwsgi_starts_with(response, size, "break", 5 )) {
ret = UWSGI_ROUTE_BREAK;
if (size > 6) {
if (uwsgi_response_prepare_headers(wsgi_req, response+6, size-6)) goto end0;
if (uwsgi_response_add_connection_close(wsgi_req)) goto end0;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end0;
// no need to check for return value
uwsgi_response_write_headers_do(wsgi_req);
}
}
else if (!uwsgi_starts_with(response, size, "goto ", 5)) {
ret = UWSGI_ROUTE_BREAK;
if (size > 5) {
// find the label
struct uwsgi_route *routes = uwsgi.routes;
while(routes) {
if (!routes->label) goto next;
if (!uwsgi_strncmp(routes->label, routes->label_len, response+5, size-5)) {
ret = UWSGI_ROUTE_NEXT;
wsgi_req->route_goto = routes->pos;
goto found;
}
next:
routes = routes->next;
}
goto end0;
found:
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");
ret = UWSGI_ROUTE_BREAK;
}
}
}
end0:
free(response);
end:
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
}
}
return ret;
}
/*
ur->data = the func name
ur->custom = the number of arguments
ur->data2 = the pointer to the args
ur->data3 = the pointer to the args sizes
*/
static int uwsgi_router_rpc_base(struct uwsgi_route *ur, char *args) {
ur->custom = 0;
ur->data2 = uwsgi_calloc(sizeof(char *) * UMAX8);
ur->data3 = uwsgi_calloc(sizeof(uint16_t) * UMAX8);
char *p = strtok(args, " ");
while(p) {
if (!ur->data) {
ur->data = p;
}
else {
if (ur->custom >= UMAX8) {
uwsgi_log("unable to register route: maximum number of rpc args reached\n");
free(ur->data2);
free(ur->data3);
return -1;
}
char **argv = (char **) ur->data2;
uint16_t *argvs = (uint16_t *) ur->data3;
argv[ur->custom] = p;
argvs[ur->custom] = strlen(p);
ur->custom++;
}
p = strtok(NULL, " ");
}
if (!ur->data) {
uwsgi_log("unable to register route: you need to specify an rpc function\n");
free(ur->data2);
free(ur->data3);
return -1;
}
return 0;
}
static int uwsgi_router_rpc(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_rpc;
return uwsgi_router_rpc_base(ur, args);
}
static int uwsgi_router_rpc_ret(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_rpc_ret;
return uwsgi_router_rpc_base(ur, args);
}
static void router_rpc_register() {
uwsgi_register_router("call", uwsgi_router_rpc);
uwsgi_register_router("rpc", uwsgi_router_rpc);
uwsgi_register_router("rpcret", uwsgi_router_rpc_ret);
}
#endif
struct uwsgi_plugin rpc_plugin = {
.name = "rpc",
.modifier1 = 173,
.request = uwsgi_rpc_request,
#ifdef UWSGI_ROUTING
.on_load = router_rpc_register,
#endif
};
+7 -7
View File
@@ -20,16 +20,19 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
if (uspool == NULL) {
uwsgi_log("the spooler is inactive !!!...skip\n");
uwsgi_send_empty_pkt(wsgi_req->poll.fd, NULL, 255, 0);
uh.modifier1 = 255;
uh.pktsize = 0;
uh.modifier2 = 0;
uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4);
return -1;
}
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, wsgi_req->async_id, wsgi_req->buffer, wsgi_req->uh.pktsize, NULL, 0, NULL, 0);
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, wsgi_req->async_id, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0, NULL, 0);
uh.modifier1 = 255;
uh.pktsize = 0;
if (i > 0) {
uh.modifier2 = 1;
if (write(wsgi_req->poll.fd, &uh, 4) != 4) {
if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) {
uwsgi_log("disconnected client, remove spool file.\n");
/* client disconnect, remove spool file */
if (unlink(spool_filename)) {
@@ -43,10 +46,7 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
else {
/* announce a failed spool request */
uh.modifier2 = 0;
i = write(wsgi_req->poll.fd, &uh, 4);
if (i != 4) {
uwsgi_error("write()");
}
uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4);
}
return -1;
+526
View File
@@ -0,0 +1,526 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
#define UWSGI_SSI_MAX_ARGS 8
/*
uWSGI server side includes implementation
*/
struct uwsgi_ssi_arg {
char *key;
size_t key_len;
char *value;
size_t val_len;
};
struct uwsgi_ssi_cmd {
char *name;
size_t name_len;
struct uwsgi_buffer *(*func)(struct wsgi_request *, struct uwsgi_ssi_arg *, int);
struct uwsgi_ssi_cmd *next;
};
struct uwsgi_ssi_cmd *uwsgi_ssi_commands = NULL;
static struct uwsgi_ssi_cmd* uwsgi_ssi_get_cmd(char *name, size_t name_len) {
struct uwsgi_ssi_cmd *usc = uwsgi_ssi_commands;
while(usc) {
if (!uwsgi_strncmp(usc->name, usc->name_len, name, name_len)) {
return usc;
}
usc = usc->next;
}
return NULL;
}
static struct uwsgi_ssi_cmd *uwsgi_register_ssi_command(char *name, struct uwsgi_buffer *(*func)(struct wsgi_request *, struct uwsgi_ssi_arg *, int)) {
struct uwsgi_ssi_cmd *old_usc = NULL,*usc = uwsgi_ssi_commands;
while(usc) {
if (!strcmp(usc->name, name)) {
return usc;
}
old_usc = usc;
usc = usc->next;
}
usc = uwsgi_calloc(sizeof(struct uwsgi_ssi_cmd));
usc->name = name;
usc->name_len = strlen(name);
usc->func = func;
if (old_usc) {
old_usc->next = usc;
}
else {
uwsgi_ssi_commands = usc;
}
return usc;
}
static int uwsgi_ssi_parse_args(struct wsgi_request *wsgi_req, char *buf, size_t len, struct uwsgi_ssi_arg *argv, int *argc) {
// status [0]null/= [1]" [2]" [3]\s
size_t i;
uint8_t status = 0;
char *key = buf;
size_t key_len = 0;
char *value = NULL;
size_t val_len = 0;
for(i=0;i<len;i++) {
switch(status) {
case 0:
if (buf[i] == '=') {
status = 1;
}
else {
key_len++;
}
break;
case 1:
if (buf[i] == '"') {
status = 2;
}
else {
return -1;
}
break;
case 2:
if (buf[i] == '"') {
status = 3;
argv[*argc].key = key; argv[*argc].key_len = key_len;
argv[*argc].value = value; argv[*argc].val_len = val_len;
*argc = *argc+1;
if (*argc >= UWSGI_SSI_MAX_ARGS) {
return -1;
}
key = NULL;
key_len = 0;
value = NULL;
val_len = 0;
}
else {
if (!value) {
value = buf + i;
}
val_len++;
}
break;
case 3:
if (!isspace((int)buf[i])) {
key = buf + i;
key_len = 1;
status = 0;
}
break;
default:
return -1;
}
}
return 0;
}
static struct uwsgi_buffer *uwsgi_ssi_parse_command(struct wsgi_request *wsgi_req, char *buf, size_t len) {
// storage for arguments
struct uwsgi_ssi_arg argv[UWSGI_SSI_MAX_ARGS];
int argc = 0;
// first remove white spaces from the begin and the end
char *cmd = buf;
size_t cmd_len = len;
size_t i;
for(i=0;i<len;i++) {
if (isspace((int)buf[i])) {
cmd++;
cmd_len--;
}
else {
break;
}
}
// then rstrip (skipping the first char...)
for(i=(len-1);i>0;i--) {
if (isspace((int)buf[i])) {
cmd_len--;
}
else {
break;
}
}
// now get the command
char *ssi_cmd = cmd;
size_t ssi_cmd_len = 0;
int found = 0;
for(i=0;i<cmd_len;i++) {
if (isspace(cmd[i])) {
found = 1;
break;
}
ssi_cmd_len++;
}
struct uwsgi_ssi_cmd *usc = uwsgi_ssi_get_cmd(ssi_cmd, ssi_cmd_len);
if (!usc) return NULL ;
if (!found) goto run;
// now split the args
char *cmd_args = cmd + ssi_cmd_len + 1;
size_t cmd_args_len = cmd_len - (ssi_cmd_len + 1);
for(i=(ssi_cmd_len + 1);i<cmd_len;i++) {
if (isspace((int)cmd[i])) {
cmd_args++;
cmd_args_len--;
}
else {
break;
}
}
if (uwsgi_ssi_parse_args(wsgi_req, cmd_args, cmd_args_len, argv, &argc)) {
return NULL;
}
run:
return usc->func(wsgi_req, argv, argc);
}
static struct uwsgi_buffer *uwsgi_ssi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t i;
uint8_t status = 0;
char *cmd = NULL;
size_t cmd_len = 0;
struct uwsgi_buffer *ub = uwsgi_buffer_new(len);
// parsing status 0[null] 1[<] 2[!] 3[-] 4[-] 5[#/-] 6[-] 7[>]
// on status 6-7-8 the reset action come back to 5 instead of 0
for(i=0;i<len;i++) {
switch(status) {
case 0:
if (buf[i] == '<') {
status = 1;
}
else {
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 1:
status = 0;
if (buf[i] == '!') {
status = 2;
}
else {
if (uwsgi_buffer_append(ub, "<", 1)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 2:
status = 0;
if (buf[i] == '-') {
status = 3;
}
else {
if (uwsgi_buffer_append(ub, "<!", 2)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 3:
status = 0;
if (buf[i] == '-') {
status = 4;
}
else {
if (uwsgi_buffer_append(ub, "<!-", 3)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 4:
status = 0;
if (buf[i] == '#') {
status = 5;
}
else {
if (uwsgi_buffer_append(ub, "<!--", 4)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 5:
if (buf[i] == '-') {
status = 6;
break;
}
if (!cmd) {
cmd = buf+i;
}
cmd_len++;
break;
case 6:
status = 5;
if (buf[i] == '-') {
status = 7;
}
else {
cmd_len+=2;
}
break;
case 7:
status = 5;
if (buf[i] == '>') {
status = 0;
struct uwsgi_buffer *ub_cmd = uwsgi_ssi_parse_command(wsgi_req, cmd, cmd_len);
if (ub_cmd) {
if (uwsgi_buffer_append(ub, ub_cmd->buf, ub_cmd->pos)) {
uwsgi_buffer_destroy(ub_cmd);
goto error;
}
uwsgi_buffer_destroy(ub_cmd);
}
cmd = NULL;
cmd_len = 0;
}
else {
cmd_len+=3;
}
break;
default:
goto error;
}
}
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
static int uwsgi_ssi_request(struct wsgi_request *wsgi_req) {
struct uwsgi_buffer *ub = NULL;
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
if (!wsgi_req->document_root_len || !wsgi_req->path_info_len) {
uwsgi_log("[uwsgi-ssi] DOCUMENT_ROOT and PATH_INFO must be defined !!!\n");
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
char *filename = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
size_t filename_len = wsgi_req->document_root_len + 1 + wsgi_req->path_info_len;
// we expand the path for future security implementations
char *real_filename = uwsgi_expand_path(filename, filename_len, NULL);
free(filename);
if (!real_filename) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(real_filename);
free(real_filename);
if (!ub_ssi) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos);
uwsgi_buffer_destroy(ub_ssi);
if (!ub) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
// prepare headers
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_length
if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_type
if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) {
uwsgi_500(wsgi_req);
goto end;
}
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
if (ub) {
uwsgi_buffer_destroy(ub);
}
return UWSGI_OK;
}
static char *uwsgi_ssi_get_arg(struct uwsgi_ssi_arg *argv, int argc, char *key, size_t key_len, size_t *val_len) {
int i;
for(i=0;i<argc;i++) {
struct uwsgi_ssi_arg *arg = &argv[i];
if (!uwsgi_strncmp(arg->key, arg->key_len, key, key_len)) {
*val_len = arg->val_len;
return arg->value;
}
}
return NULL;
}
// echo command
static struct uwsgi_buffer *ssi_cmd_echo(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
size_t var_len = 0;
char *var = uwsgi_ssi_get_arg(argv, argc, "var", 3, &var_len);
if (!var || var_len == 0) return NULL;
uint16_t rlen = 0;
char *value = uwsgi_get_var(wsgi_req, var, var_len, &rlen);
if (!value) return NULL;
if (rlen == 0) return NULL;
struct uwsgi_buffer *ub = uwsgi_buffer_new(rlen);
if (uwsgi_buffer_append(ub, value, rlen)) {
uwsgi_buffer_destroy(ub);
return NULL;
}
return ub;
};
// printenv command
static struct uwsgi_buffer *ssi_cmd_printenv(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
int i;
for (i = 0; i < wsgi_req->var_cnt; i += 2) {
if (uwsgi_buffer_append(ub, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) goto error;
if (uwsgi_buffer_append(ub, "=", 1)) goto error;
if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto error;
if (uwsgi_buffer_append(ub, "\n", 1)) goto error;
}
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
};
// include command
static struct uwsgi_buffer *ssi_cmd_include(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
size_t var_len = 0;
char *var = uwsgi_ssi_get_arg(argv, argc, "file", 4, &var_len);
if (!var || var_len == 0) return NULL;
char *filename = uwsgi_concat2n(var, var_len, "", 0);
struct uwsgi_buffer *ub = uwsgi_buffer_from_file(filename);
free(filename);
return ub;
}
// cache command (uWSGI specific)
static struct uwsgi_buffer *ssi_cmd_cache(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
size_t var_len = 0;
char *var = uwsgi_ssi_get_arg(argv, argc, "key", 3, &var_len);
if (!var || var_len == 0) return NULL;
size_t cache_len = 0;
char *cache = uwsgi_ssi_get_arg(argv, argc, "name", 4, &cache_len);
char *cache_name = NULL;
if (cache && cache_len) {
cache_name = uwsgi_concat2n(cache, cache_len, "", 0);
}
uint64_t rlen = 0;
char *value = uwsgi_cache_magic_get(var, var_len, &rlen, cache_name);
if (cache_name) free(cache_name);
struct uwsgi_buffer *ub = NULL;
if (value) {
ub = uwsgi_buffer_new(rlen);
if (uwsgi_buffer_append(ub, value, rlen)) {
free(value);
uwsgi_buffer_destroy(ub);
return NULL;
}
free(value);
}
return ub;
}
static int uwsgi_routing_func_ssi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_buffer *ub = NULL;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub_filename) goto end;
struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(ub_filename->buf);
uwsgi_buffer_destroy(ub_filename);
if (!ub_ssi) goto end;
ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos);
uwsgi_buffer_destroy(ub_ssi);
if (!ub) goto end;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end;
if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
if (ub) uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_ssi(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_ssi;
ur->data = args;
ur->data_len = strlen(args);
return 0;
}
static int uwsgi_ssi_init() {
uwsgi_register_ssi_command("echo", ssi_cmd_echo);
uwsgi_register_ssi_command("printenv", ssi_cmd_printenv);
uwsgi_register_ssi_command("include", ssi_cmd_include);
uwsgi_register_ssi_command("cache", ssi_cmd_cache);
return 0;
}
static void uwsgi_ssi_register_router() {
uwsgi_register_router("ssi", uwsgi_router_ssi);
}
static void uwsgi_ssi_log(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
struct uwsgi_plugin ssi_plugin = {
.name = "ssi",
.modifier1 = 19,
.init = uwsgi_ssi_init,
.request = uwsgi_ssi_request,
.after_request = uwsgi_ssi_log,
.on_load = uwsgi_ssi_register_router,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='ssi'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['ssi']
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
void stats_pusher_mongodb(struct uwsgi_stats_pusher_instance *, time_t, char *, size_t);
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include "client/dbclient.h"
+8 -1
View File
@@ -1,7 +1,14 @@
import os
NAME='stats_pusher_mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
LIBS = []
if not 'UWSGI_MONGODB_NOLIB' in os.environ:
LIBS.append('-lmongoclient')
LIBS.append('-lboost_thread')
LIBS.append('-lboost_filesystem')
GCC_LIST = ['plugin', 'stats_pusher_mongodb.cc']
+137
View File
@@ -0,0 +1,137 @@
#include <uwsgi.h>
/*
this is a stats pusher plugin for the statsd server:
--stats-push statsd:address[,prefix]
example:
--stats-push statsd:127.0.0.1:8125,myinstance
it is pretty minimal, but will be extended after the 2.0 metric subsystem will be released
*/
extern struct uwsgi_server uwsgi;
// configuration of a statsd node
struct statsd_node {
int fd;
union uwsgi_sockaddr addr;
socklen_t addr_len;
char *prefix;
uint16_t prefix_len;
};
static int statsd_send_worker_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, char *metric, uint16_t metric_len, int64_t value) {
struct statsd_node *sn = (struct statsd_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
if (uwsgi_buffer_num64(ub, wid)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_num64(ub, value)) return -1;
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("stats_pusher_statsd()/sendto()");
}
return 0;
}
static int statsd_send_core_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, int coreid, char *metric, uint16_t metric_len, int64_t value) {
struct statsd_node *sn = (struct statsd_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
if (uwsgi_buffer_num64(ub, wid)) return -1;
if (uwsgi_buffer_append(ub, ".core", 5)) return -1;
if (uwsgi_buffer_num64(ub, coreid)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_num64(ub, value)) return -1;
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("stats_pusher_statsd()/sendto()");
}
return 0;
}
static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
if (!uspi->configured) {
struct statsd_node *sn = uwsgi_calloc(sizeof(struct statsd_node));
char *comma = strchr(uspi->arg, ',');
if (comma) {
sn->prefix = comma+1;
sn->prefix_len = strlen(sn->prefix);
*comma = 0;
}
else {
sn->prefix = "uwsgi";
sn->prefix_len = 5;
}
char *colon = strchr(uspi->arg, ':');
if (!colon) {
uwsgi_log("invalid statsd address %s\n", uspi->arg);
if (comma) *comma = ',';
free(sn);
return;
}
sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in);
sn->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sn->fd < 0) {
uwsgi_error("stats_pusher_statsd()/socket()");
if (comma) *comma = ',';
free(sn);
return;
}
uwsgi_socket_nb(sn->fd);
if (comma) *comma = ',';
uspi->data = sn;
uspi->configured = 1;
}
// we use the same buffer for all of the packets
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
int i, j;
// send workers metrics
for(i=1;i<=uwsgi.numproc;i++) {
if (statsd_send_worker_gauge(ub, uspi, i, "requests", 8, uwsgi.workers[i].requests)) goto end;
for(j=0;j<uwsgi.cores;j++) {
if (statsd_send_core_gauge(ub, uspi, i, j, "exceptions", 10, uwsgi.workers[i].cores[j].exceptions)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "requests", 8, uwsgi.workers[i].cores[j].requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "routed_requests", 15, uwsgi.workers[i].cores[j].routed_requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "static_requests", 15, uwsgi.workers[i].cores[j].static_requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "offloaded_requests", 18, uwsgi.workers[i].cores[j].offloaded_requests)) goto end;
}
}
end:
uwsgi_buffer_destroy(ub);
}
static void stats_pusher_statsd_init(void) {
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("statsd", stats_pusher_statsd);
// we use a custom format not the JSON one
usp->raw = 1;
}
struct uwsgi_plugin stats_pusher_statsd_plugin = {
.name = "stats_pusher_statsd",
.on_load = stats_pusher_statsd_init,
};
@@ -0,0 +1,7 @@
NAME='stats_pusher_statsd'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['plugin']
+8
View File
@@ -0,0 +1,8 @@
import os
NAME='xslt'
CFLAGS = os.popen('xslt-config --cflags').read().rstrip().split()
LDFLAGS = os.popen('xslt-config --libs').read().rstrip().split()
LIBS = []
GCC_LIST = ['xslt']
+406
View File
@@ -0,0 +1,406 @@
#include <uwsgi.h>
#include <libxslt/xsltutils.h>
#include <libxslt/transform.h>
/*
XSLT request plugin
it takes an XML file as input (taken from DOCUMENT_ROOT + PATH_INFO by default)
it search for an XSLT stylesheet (by default in DOCUMENT_ROOT + PATH_INFO - ext + .xsl|.xslt)
it applies params (by default taken from the QUERY_STRING)
XSLT routing instruction
xslt:doc=<path1>,stylesheet=<path2>,params=<params>
*/
struct uwsgi_xslt_config {
struct uwsgi_string_list *docroot;
struct uwsgi_string_list *ext;
struct uwsgi_string_list *var;
struct uwsgi_string_list *stylesheet;
char *content_type;
uint16_t content_type_len;
} uxslt;
struct uwsgi_router_xslt_conf {
char *doc;
uint16_t doc_len;
char *stylesheet;
uint16_t stylesheet_len;
char *params;
uint16_t params_len;
char *content_type;
uint16_t content_type_len;
};
struct uwsgi_option uwsgi_xslt_options[] = {
{"xslt-docroot", required_argument, 0, "add a document_root for xslt processing", uwsgi_opt_add_string_list, &uxslt.docroot, 0},
{"xslt-ext", required_argument, 0, "search for xslt stylesheets with the specified extension", uwsgi_opt_add_string_list, &uxslt.ext, 0},
{"xslt-var", required_argument, 0, "get the xslt stylesheet path from the specified request var", uwsgi_opt_add_string_list, &uxslt.var, 0},
{"xslt-stylesheet", required_argument, 0, "if no xslt stylesheet file can be found, use the specified one", uwsgi_opt_add_string_list, &uxslt.stylesheet, 0},
{"xslt-content-type", required_argument, 0, "set the content-type for the xslt rsult (default: text/html)", uwsgi_opt_set_str, &uxslt.content_type, 0},
{NULL, 0, 0, NULL, NULL, NULL, 0},
};
static char *uwsgi_xslt_apply(char *xmlfile, char *xsltfile, char *params, int *rlen) {
char **vparams = NULL;
char *tmp_params = NULL;
uint16_t count = 0;
if (params) {
// first count the number of items
size_t i;
size_t params_len = strlen(params);
for(i=0;i<params_len;i++) {
if (params[i] == '=') {
count++;
}
}
vparams = uwsgi_calloc( sizeof(char *) * ((count * 2) + 1));
tmp_params = uwsgi_str(params);
char *p = strtok(tmp_params, "&");
int pos = 0;
while(p) {
char *equal = strchr(p, '=');
if (equal) {
*equal = 0;
vparams[pos] = p; pos++;
vparams[pos] = uwsgi_concat3("\"", equal+1, "\""); pos++;
}
p = strtok(NULL, "&");
}
}
// we reset them every time to avoid collision with other xml engines
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
xmlDocPtr doc = xmlParseFile(xmlfile);
if (!doc) {
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
return NULL;
}
xsltStylesheetPtr ss = xsltParseStylesheetFile((const xmlChar *) xsltfile);
if (!ss) {
xmlFreeDoc(doc);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
return NULL;
}
xmlDocPtr res = xsltApplyStylesheet(ss, doc, (const char **) vparams);
if (!res) {
xsltFreeStylesheet(ss);
xmlFreeDoc(doc);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
return NULL;
}
xmlChar *output;
int ret = xsltSaveResultToString(&output, rlen, res, ss);
xsltFreeStylesheet(ss);
xmlFreeDoc(res);
xmlFreeDoc(doc);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
if (ret < 0) return NULL;
return (char *) output;
}
static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
char *xmlfile = NULL;
char *output = NULL;
int output_rlen = 0;
char filename[PATH_MAX+1];
size_t filename_len = 0;
char stylesheet[PATH_MAX+1];
size_t stylesheet_len = 0;
char *params = NULL;
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
// set default values
if (!uxslt.content_type_len) {
if (!uxslt.content_type) {
uxslt.content_type = "text/html";
}
uxslt.content_type_len = strlen(uxslt.content_type);
}
struct uwsgi_string_list *usl = uxslt.docroot;
// first check for static docroots
if (usl) {
while(usl) {
xmlfile = uwsgi_concat3n(usl->value, usl->len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
if (uwsgi_is_file(xmlfile)) {
break;
}
free(xmlfile);
xmlfile = NULL;
usl = usl->next;
}
}
// fallback to DOCUMENT_ROOT
else {
if (wsgi_req->document_root_len == 0) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
xmlfile = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
}
if (!xmlfile) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
// we have the full path, check if it is valid
if (!uwsgi_expand_path(xmlfile, strlen(xmlfile), filename)) {
free(xmlfile);
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
free(xmlfile);
if (!uwsgi_is_file(filename)) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
filename_len = strlen(filename);
// now search for the xslt file
int found = 0;
// first check for specific vars
usl = uxslt.var;
while(usl) {
uint16_t rlen;
char *value = uwsgi_get_var(wsgi_req, usl->value, usl->len, &rlen);
if (value) {
memcpy(stylesheet, value, rlen);
stylesheet[rlen] = 0;
stylesheet_len = rlen;
found = 1;
break;
}
usl = usl->next;
}
if (found) goto apply;
// then check for custom extensions
if (uxslt.ext) {
usl = uxslt.ext;
while(usl) {
char *tmp_path = uwsgi_concat2n(filename, filename_len, usl->value, usl->len);
if (uwsgi_is_file(tmp_path)) {
stylesheet_len = filename_len + usl->len;
memcpy(stylesheet, tmp_path, stylesheet_len);
stylesheet[stylesheet_len] = 0;
free(tmp_path);
found = 1;
break;
}
free(tmp_path);
usl = usl->next;
}
}
// use default extensions .xsl/.xslt
else {
char *tmp_path = uwsgi_concat2n(filename, filename_len, ".xsl", 4);
if (uwsgi_is_file(tmp_path)) {
stylesheet_len = filename_len + 4;
memcpy(stylesheet, tmp_path, stylesheet_len);
stylesheet[stylesheet_len] = 0;
free(tmp_path);
goto apply;
}
free(tmp_path);
tmp_path = uwsgi_concat2n(filename, filename_len, ".xslt", 5);
if (uwsgi_is_file(tmp_path)) {
stylesheet_len = filename_len + 5;
memcpy(stylesheet, tmp_path, stylesheet_len);
stylesheet[stylesheet_len] = 0;
found = 1;
}
free(tmp_path);
}
if (found) goto apply;
// finally check for static stylesheets
usl = uxslt.stylesheet;
while(usl) {
if (uwsgi_is_file(usl->value)) {
memcpy(stylesheet, usl->value, usl->len);
stylesheet_len = usl->len;
stylesheet[stylesheet_len] = 0;
found = 1;
break;
}
usl = usl->next;
}
if (found) goto apply;
uwsgi_404(wsgi_req);
return UWSGI_OK;
apply:
if (wsgi_req->query_string_len > 0) {
params = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0);
}
// we have both the file and the stylesheet, let's run the engine
output = uwsgi_xslt_apply(filename, stylesheet, params, &output_rlen);
if (params) free(params);
if (!output) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
// prepare headers
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_length
if (uwsgi_response_add_content_length(wsgi_req, output_rlen)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_type
if (uwsgi_response_add_content_type(wsgi_req, uxslt.content_type, uxslt.content_type_len)) {
uwsgi_500(wsgi_req);
goto end;
}
uwsgi_response_write_body_do(wsgi_req, output, output_rlen);
end:
xmlFree(output);
return UWSGI_OK;
}
static void uwsgi_xslt_log(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_xslt_conf *urxc = (struct uwsgi_router_xslt_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_doc = NULL;
struct uwsgi_buffer *ub_stylesheet = NULL;
struct uwsgi_buffer *ub_params = NULL;
struct uwsgi_buffer *ub_content_type = NULL;
ub_doc = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->doc, urxc->doc_len);
if (!ub_doc) goto end;
ub_stylesheet = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->stylesheet, urxc->stylesheet_len);
if (!ub_stylesheet) goto end;
if (urxc->params) {
ub_params = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->params, urxc->params_len);
if (!ub_params) goto end;
}
if (urxc->content_type) {
ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len);
if (!ub_content_type) goto end;
}
int rlen;
char *output = uwsgi_xslt_apply( ub_doc->buf, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen);
if (!output) goto end;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, rlen)) goto end;
if (uwsgi_response_add_content_type(wsgi_req, urxc->content_type, urxc->content_type_len)) goto end;
uwsgi_response_write_body_do(wsgi_req, output, rlen);
xmlFree(output);
end:
if (ub_doc) uwsgi_buffer_destroy(ub_doc);
if (ub_stylesheet) uwsgi_buffer_destroy(ub_stylesheet);
if (ub_params) uwsgi_buffer_destroy(ub_params);
if (ub_content_type) uwsgi_buffer_destroy(ub_content_type);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_xslt(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_xslt;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_xslt_conf *urxc = uwsgi_calloc(sizeof(struct uwsgi_router_xslt_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"doc", &urxc->doc,
"stylesheet", &urxc->stylesheet,
"content_type", &urxc->content_type,
"params", &urxc->params,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urxc->doc && !urxc->stylesheet) {
uwsgi_log("invalid route syntax: you need to specify a doc and a stylesheet\n");
exit(1);
}
urxc->doc_len = strlen(urxc->doc);
urxc->stylesheet_len = strlen(urxc->stylesheet);
if (urxc->params) urxc->params_len = strlen(urxc->params);
if (!urxc->content_type) urxc->content_type = "text/html";
urxc->content_type_len = strlen(urxc->content_type);
ur->data2 = urxc;
return 0;
}
static void router_xslt_register() {
uwsgi_register_router("xslt", uwsgi_router_xslt);
}
struct uwsgi_plugin xslt_plugin = {
.name = "xslt",
.modifier1 = 23,
.options = uwsgi_xslt_options,
.request = uwsgi_request_xslt,
.after_request = uwsgi_xslt_log,
.on_load = router_xslt_register,
};
+7 -2
View File
@@ -104,18 +104,23 @@ struct zergpool_socket *add_zergpool_socket(char *name, char *sockets) {
p = strtok(sock_list, ",");
while(p) {
char *port = strchr(p, ':');
char *sockname;
if (!port) {
z_sock->sockets[pos] = bind_to_unix(p, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
uwsgi_log("zergpool %s bound to UNIX socket %s (fd: %d)\n", name, uwsgi_getsockname(z_sock->sockets[pos]), z_sock->sockets[pos]);
sockname = uwsgi_getsockname(z_sock->sockets[pos]);
uwsgi_log("zergpool %s bound to UNIX socket %s (fd: %d)\n", name, sockname, z_sock->sockets[pos]);
}
else {
char *gsn = generate_socket_name(p);
z_sock->sockets[pos] = bind_to_tcp(gsn, uwsgi.listen_queue, strchr(gsn, ':'));
uwsgi_log("zergpool %s bound to TCP socket %s (fd: %d)\n", name, uwsgi_getsockname(z_sock->sockets[pos]), z_sock->sockets[pos]);
sockname = uwsgi_getsockname(z_sock->sockets[pos]);
uwsgi_log("zergpool %s bound to TCP socket %s (fd: %d)\n", name, sockname, z_sock->sockets[pos]);
}
pos++;
p = strtok(NULL, ",");
free(sockname);
}
free(sock_list);
return z_sock;
}
+203 -194
View File
@@ -1,32 +1,37 @@
#include "../uwsgi.h"
/*
generic ZeroMQ functions + Mongrel2 protocol parser
*/
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
void *uwsgi_zeromq_init() {
if (!uwsgi.zmq_context) {
uwsgi.zmq_context = zmq_init(1);
if (uwsgi.zmq_context == NULL) {
uwsgi_error("zmq_init()");
exit(1);
}
if (uwsgi.zmq_context == NULL) {
uwsgi_error("zmq_init()");
exit(1);
}
}
return uwsgi.zmq_context;
}
void uwsgi_zeromq_init_sockets() {
uwsgi_zeromq_init();
uwsgi_zeromq_init();
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (!uwsgi_sock->proto_name || strcmp(uwsgi_sock->proto_name, "zmq")) {
goto zmq_next;
}
uwsgi_proto_zeromq_setup(uwsgi_sock);
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (!uwsgi_sock->proto_name || strcmp(uwsgi_sock->proto_name, "zmq")) {
goto zmq_next;
}
uwsgi_proto_zeromq_setup(uwsgi_sock);
zmq_next:
uwsgi_sock = uwsgi_sock->next;
uwsgi_sock = uwsgi_sock->next;
}
}
}
@@ -80,6 +85,7 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val));
}
// pretty easy, we get the file and we map it to wsgi_req->post_file, uWSGI read api will automatically use this
if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) {
wsgi_req->post_file = fopen(json_val, "r");
if (!wsgi_req->post_file) {
@@ -126,12 +132,12 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-forwarded-for"))) {
char *colon = strchr(json_val, ',');
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val));
}
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val));
}
}
@@ -228,7 +234,7 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
if (!uwsgi_strncmp("host", 4, key, keylen)) {
char *colon = memchr(val, ':', vallen);
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1)-val));
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1) - val));
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
@@ -250,11 +256,11 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) {
char *colon = memchr(val, ',', vallen);
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen);
}
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen);
}
}
else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) {
async_upload += 1;
@@ -266,9 +272,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
if (query_string == NULL) {
// always set QUERY_STRING
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
}
// always set QUERY_STRING
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
}
// reject uncomplete upload
if (async_upload == 1) {
@@ -277,6 +283,7 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
return 0;
}
// fake function, we parse requests in the accept phase
int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
@@ -284,130 +291,35 @@ int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) {
void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_id) {
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull);
#ifdef ZMQ_FD
if (uwsgi.threads > 1) {
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd_threads[async_id], &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd_threads[async_id], &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
}
uwsgi_sock->retry[async_id] = 1;
}
#endif
}
void uwsgi_proto_zeromq_setup(struct uwsgi_socket *uwsgi_sock) {
char *responder = strchr(uwsgi_sock->name, ',');
if (!responder) {
uwsgi_log("invalid zeromq address\n");
exit(1);
}
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
responder++;
uwsgi_sock->pub = zmq_socket(uwsgi.zmq_context, ZMQ_PUB);
if (uwsgi_sock->pub == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
// generate uuid
uuid_t uuid_zmq;
uuid_generate(uuid_zmq);
uuid_unparse(uuid_zmq, uwsgi_sock->uuid);
if (zmq_setsockopt(uwsgi_sock->pub, ZMQ_IDENTITY, uwsgi_sock->uuid, 36) < 0) {
uwsgi_error("zmq_setsockopt()");
exit(1);
}
if (zmq_connect(uwsgi_sock->pub, responder) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
uwsgi_log("zeromq UUID for responder %s on worker %d: %.*s\n", responder, uwsgi.mywid, 36, uwsgi_sock->uuid);
uwsgi_sock->proto = uwsgi_proto_zeromq_parser;
uwsgi_sock->proto_accept = uwsgi_proto_zeromq_accept;
uwsgi_sock->proto_close = uwsgi_proto_zeromq_close;
/*
uwsgi_sock->proto_write = uwsgi_proto_zeromq_write;
uwsgi_sock->proto_write_header = uwsgi_proto_zeromq_write_header;
uwsgi_sock->proto_sendfile = uwsgi_proto_zeromq_sendfile;
*/
uwsgi_sock->proto_thread_fixup = uwsgi_proto_zeromq_thread_fixup;
uwsgi_sock->edge_trigger = 1;
uwsgi_sock->retry = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->retry[0] = 1;
// inform loop engine about edge trigger status
uwsgi.is_et = 1;
// initialize a lock for multithread usage
if (uwsgi.threads > 1) {
pthread_mutex_init(&uwsgi_sock->lock, NULL);
}
// one pull per-thread
if (pthread_key_create(&uwsgi_sock->key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull);
#ifdef ZMQ_FD
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd, &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
}
if (uwsgi.threads > 1) {
uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->fd_threads[0] = uwsgi_sock->fd;
}
#else
uwsgi_sock->fd = -1;
#endif
uwsgi_sock->bound = 1;
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
uwsgi_sock->recv_flag = ZMQ_DONTWAIT;
#else
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
#endif
// fake function, the bosy is i na file or completely in memory
ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
return 0;
}
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
zmq_msg_t message;
@@ -527,19 +439,14 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2);
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
// handle post data
// handle post data (in memory)
if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) {
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
#ifdef UWSGI_DEBUG
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
#endif
wsgi_req->post_file = tmpfile();
if (fwrite(message_ptr, wsgi_req->post_cl, 1, wsgi_req->post_file) != 1) {
uwsgi_error("fwrite()");
zmq_msg_close(&message);
goto retry;
}
rewind(wsgi_req->post_file);
wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl);
memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl);
}
}
@@ -563,10 +470,6 @@ retry:
return -1;
}
static void uwsgi_proto_zeromq_free(void *data, void *hint) {
free(data);
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
zmq_msg_t reply;
@@ -574,82 +477,188 @@ void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
if (!wsgi_req->proto_parser_pos)
return;
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, uwsgi_proto_zeromq_free, NULL);
if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock);
// no need to pass a free function (the buffer will be freed during cloe_request)
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()");
#else
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()");
#endif
uwsgi_error("zmq_send()");
}
if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
}
ssize_t uwsgi_proto_zeromq_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
zmq_msg_t reply;
char *zmq_body;
if (len == 0)
return 0;
if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) {
uwsgi_error("uwsgi_proto_zeromq_write()/zmq_msg_init_size()");
return -1;
}
zmq_body = uwsgi_concat2n(wsgi_req->proto_parser_buf, (int) wsgi_req->proto_parser_pos, buf, (int) len);
//uwsgi_log("|%.*s|\n", (int)wsgi_req->proto_parser_pos+len, zmq_body);
char *zmq_body = zmq_msg_data(&reply);
memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos);
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
zmq_msg_init_data(&reply, zmq_body, wsgi_req->proto_parser_pos + len, uwsgi_proto_zeromq_free, NULL);
if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
#else
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
#endif
if (!uwsgi.ignore_write_errors) {
uwsgi_error("zmq_send()");
}
wsgi_req->write_errors++;
if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
return 0;
return -1;
}
if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
return len;
return UWSGI_OK;
}
ssize_t uwsgi_proto_zeromq_sendfile(struct wsgi_request * wsgi_req) {
/*
ssize_t len;
char buf[65536];
size_t remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of
messages mongrel2 is able to manage). If we send a big static file we can fill that buffer immediately. How to deal with this ? We know that the
message ring can contains a fixed amount of messages. We could try to split the file in chunks (upto the maximum number supported by a specific mongrel2 instance).
This is suboptimal, but there are no better solutions for now. Before you ask: do you really think that sending a single message with a 2GB file is a good approach ?????
By the way, for now, waiting for a better approach, we use a 2MB buffer. Should support flawlessly files up to 32MB without being rejected by mongrel2. For bigger files you
can tune it to higher values (or increase the mongrel2 ring buffer)
wsgi_req->sendfile_fd_chunk = 65536;
*/
if (uwsgi.async > 1) {
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
return uwsgi_proto_zeromq_write(wsgi_req, buf, len);
#define UWSGI_MONGREL2_MAX_MSGSIZE 2*1024*1024
int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
size_t chunk_size = UMIN( len - wsgi_req->write_pos, UWSGI_MONGREL2_MAX_MSGSIZE);
char *tmp_buf = uwsgi_malloc(chunk_size);
ssize_t rlen = read(fd, tmp_buf, chunk_size);
if (rlen <= 0) {
free(tmp_buf);
return -1;
}
wsgi_req->write_pos += rlen;
if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) {
free(tmp_buf);
return -1;
}
while (remains) {
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
len = uwsgi_proto_zeromq_write(wsgi_req, buf, len);
remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
free(tmp_buf);
if (wsgi_req->write_pos == len) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
return wsgi_req->sendfile_fd_pos;
void uwsgi_proto_zeromq_setup(struct uwsgi_socket *uwsgi_sock) {
char *responder = strchr(uwsgi_sock->name, ',');
if (!responder) {
uwsgi_log("invalid zeromq address\n");
exit(1);
}
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
responder++;
uwsgi_sock->pub = zmq_socket(uwsgi.zmq_context, ZMQ_PUB);
if (uwsgi_sock->pub == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
// generate uuid
uuid_t uuid_zmq;
uuid_generate(uuid_zmq);
uuid_unparse(uuid_zmq, uwsgi_sock->uuid);
if (zmq_setsockopt(uwsgi_sock->pub, ZMQ_IDENTITY, uwsgi_sock->uuid, 36) < 0) {
uwsgi_error("zmq_setsockopt()");
exit(1);
}
if (zmq_connect(uwsgi_sock->pub, responder) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
uwsgi_log("zeromq UUID for responder %s on worker %d: %.*s\n", responder, uwsgi.mywid, 36, uwsgi_sock->uuid);
uwsgi_sock->proto = uwsgi_proto_zeromq_parser;
uwsgi_sock->proto_accept = uwsgi_proto_zeromq_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_zeromq_read_body;
uwsgi_sock->proto_write = uwsgi_proto_zeromq_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_zeromq_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_zeromq_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_zeromq_close;
uwsgi_sock->proto_thread_fixup = uwsgi_proto_zeromq_thread_fixup;
uwsgi_sock->edge_trigger = 1;
uwsgi_sock->retry = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->retry[0] = 1;
// inform loop engine about edge trigger status
uwsgi.is_et = 1;
// initialize a lock for multithread usage
if (uwsgi.threads > 1) {
pthread_mutex_init(&uwsgi_sock->lock, NULL);
}
// one pull per-thread
if (pthread_key_create(&uwsgi_sock->key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull);
#ifdef ZMQ_FD
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd, &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
}
if (uwsgi.threads > 1) {
uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->fd_threads[0] = uwsgi_sock->fd;
}
#else
uwsgi_sock->fd = -1;
#endif
uwsgi_sock->bound = 1;
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
uwsgi_sock->recv_flag = ZMQ_DONTWAIT;
#else
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
#endif
}
-2
View File
@@ -91,8 +91,6 @@ setup(name='uWSGI',
description='The uWSGI server',
author='Unbit',
author_email='info@unbit.it',
download_url='http://projects.unbit.it/downloads/uwsgi-%s.tar.gz'
% (uc.uwsgi_version),
license='GPL2',
py_modules=['uwsgidecorators'],
distclass=uWSGIDistribution,
+5
View File
@@ -0,0 +1,5 @@
<%@ language="C#"%>
Hello 1<br/>
<%= System.Text.Encoding.UTF8.GetString(uwsgi.api.CacheGet("/etc/passwd")) %><br/>
Hello 1<br/>
+21
View File
@@ -0,0 +1,21 @@
Ring Test Suite
================
how to build and run
---------------------
* cd UWSGIROOT
* cd t/ring
* lein uberjar
* cd ../..
* uwsgi t/ring/config.ini
* open http://localhost:9090 in your browser
run cases in jetty
-------------------
* lein ring server
* open http://localhost:3000 in your browser
+11
View File
@@ -0,0 +1,11 @@
[uwsgi]
http-socket = :9090
http-socket-modifier1 = 8
http-socket-modifier2 = 1
jvm-classpath = plugins/jvm/uwsgi.jar
jvm-classpath = t/ring/target/uwsgi-ring-tests-0.0.1-standalone.jar
jvm-class = uwsgi/ring/tests/app
ring-app = uwsgi.ring.tests.app/app
+10
View File
@@ -0,0 +1,10 @@
(defproject unbit/uwsgi-ring-tests "0.0.1"
:description "uwsgi-ring-tests: test cases for uwsgi ring server"
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.5"]
[ring/ring "1.1.0"]]
:source-paths ["src"]
:aot [uwsgi.ring.tests.app]
)
+29
View File
@@ -0,0 +1,29 @@
(ns uwsgi.ring.tests.app
(:use compojure.core)
(:use [ring.middleware params
keyword-params
nested-params
multipart-params])
(:require [compojure.route :as route]
[uwsgi.ring.tests.basic :as basic]
[uwsgi.ring.tests.body :as body]
[uwsgi.ring.tests.simple :as simple]
[uwsgi.ring.tests.upload :as upload])
(:gen-class
:main true))
(defn app-routes [req]
(if (= (get req :uri) "/")
(basic/index-page req)
((routes simple/app-routes body/app-routes upload/app-routes (route/not-found "<h1>Page not found</h1>")) req)))
(def app
(-> app-routes
wrap-keyword-params
wrap-nested-params
wrap-params
wrap-multipart-params))
(defn -main [& args]
(println "uwsgi ring tests app loaded"))
+30
View File
@@ -0,0 +1,30 @@
(ns uwsgi.ring.tests.basic)
(defn index-page [req] {:status 200
:headers { "Content-Type" "text/html" , "Server" "uWSGI" }
:body (str "<h1>Ring test suites</h1>"
"<h2>Simple tests</h2>"
"<ul>"
"<li><a href='/hello'>hello</a></li>"
"<li><a href='/echo?msg=abc'>echo</a></li>"
"<li><a href='/palindrome?msg=abc'>palindrome</a></li>"
"</ul>"
"<h2>Body type tests</h2>"
"<ul>"
"<li><a href='/sequence'>sequence</a></li>"
"<li><a href='/file'>file</a></li>"
"<li><a href='/stream'>stream</a></li>"
"</ul>"
"<h2>Upload tests</h2>"
"<form action='/upload' enctype='multipart/form-data' method='post'>"
"<p>"
"Please select a file<br>"
"<input type='file' name='file' size='40'>"
"</p>"
"<input type='submit' value='Upload'>"
"</form>"
"<h2>Other tests</h2>"
"<ul>"
"<li>...</li>"
"</ul>")})
+20
View File
@@ -0,0 +1,20 @@
(ns uwsgi.ring.tests.body
(:use [compojure.core]))
; generating primary numbers
; http://clojuredocs.org/clojure_core/clojure.core/lazy-seq#example_1000
(defn sieve [s]
(cons (first s)
(lazy-seq (sieve (filter #(not= 0 (mod % (first s)))
(rest s))))))
(defn numsequence [] (take 20 (sieve (iterate inc 2))))
(defn file [] (java.io.File. "CONTRIBUTORS"))
(defn stream [] (java.io.FileInputStream. (java.io.File. "CONTRIBUTORS")))
(defroutes app-routes
(GET "/sequence" [] (numsequence))
(GET "/file" [] (file))
(GET "/stream" [] (stream)))
+14
View File
@@ -0,0 +1,14 @@
(ns uwsgi.ring.tests.simple
(:use [compojure.core]) )
(defn hello [] "Hello, World!")
(defn echo [msg] msg)
(defn palindrome [msg] (clojure.string/reverse msg) )
(defroutes app-routes
(GET "/hello" [] (hello) )
(GET "/echo" [msg] (echo msg) )
(GET "/palindrome" [msg] (palindrome msg) )
)

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