Compare commits

..
229 Commits
Author SHA1 Message Date
Unbit d580705e71 prepare for 2.0.11.2 2015-10-07 06:34:01 +02:00
Ragnar Rova 93b0f72b11 OSX 10.11 supports TCP_FASTOPEN
But does not define SOL_TCP.
IPPROTO_TCP is the equivalent.

xrmx: Backport from b608eb1772
Fix #1056
2015-10-03 15:59:14 +02:00
Unbit 8906d5d0c4 attempt to fix http parser 2015-09-16 16:05:43 +02:00
Roberto De Ioris d56f16c56f fixed req threaded logger 2015-08-27 05:46:00 +02:00
Unbit a3caf36515 backported fix for fastrouter subscriptions modifiers 2015-08-04 09:49:04 +02:00
Roberto De Ioris b6ed470ee8 bump minor version to 2.0.11.2 2015-08-02 07:52:37 +02:00
Roberto De Ioris 22425fe92a fixed alarm backlog 2015-08-02 07:45:43 +02:00
Unbit 37bc47cb82 uWSGI 2.0.11.1 2015-07-19 08:17:07 +02:00
Unbit 35701f6ac6 fixed #963 2015-07-19 08:11:06 +02:00
Roberto De Ioris fb23d4a8ae Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2015-07-13 13:25:23 +02:00
Unbit 30c667d34f added unix signal registration hook 2015-07-06 16:11:53 +02:00
Unbit d09fd561b6 uWSGI 2.0.11 2015-07-01 08:53:41 +02:00
Roberto De Ioris ff05c16577 Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2015-07-01 08:51:04 +02:00
Unbit eefaa98cf3 backported pypy fixes from 2.1 2015-07-01 08:37:40 +02:00
Fabrizio Gennari 9c4d563c72 Check whether *value is indeed an SvRV before casting it 2015-07-01 06:12:54 +02:00
James Oakley ceda8a41e3 Fix version detection for gcc 5 2015-06-30 08:05:41 +02:00
Unbit 3021ba3f85 ensure the mem_collector does not receive signals 2015-06-16 18:30:19 +02:00
Roberto De Ioris 3be7312aa8 added fixpathinfo routing action 2015-06-07 19:37:48 +02:00
Roberto De Ioris 83d782051c fixed shared sockets for gateways 2015-06-03 07:23:16 +02:00
protoCall7 70996049cc Changed abs to labs because offset is declared as a long 2015-06-02 09:03:30 +02:00
Jay Oster e219e209a0 Add null terminator to uwsgi_get_dot_h() and uwsgi_config_py()
- Fixes #933
2015-06-02 09:00:01 +02:00
Unbit eb728cfe23 added sor and micros routing vars 2015-05-28 12:24:03 +02:00
unbit 7569544329 Merge pull request #929 from hulu/wait-init-thread-last
Wait for initial thread last.
2015-05-23 05:19:56 +02:00
Roberto De Ioris ee86bf593d fixed #649 2015-05-23 05:16:24 +02:00
Roberto De Ioris 27ea120325 added memory collector 2015-05-17 05:50:35 +02:00
Unbit dd21877dcb attempt to fix a bug spotted by funkybob on irc 2015-05-15 06:41:31 +02:00
Roberto De Ioris 36ca76a231 backported coverity fixes by riccardo #908 2015-05-14 06:28:52 +02:00
Unbit 0e339cf968 added bigranges sharedarea tests 2015-05-13 15:45:26 +02:00
Unbit 762200fdd6 fixed #922 2015-05-13 15:09:18 +02:00
Roberto De Ioris 688a464451 fixed #914 2015-05-12 06:28:06 +02:00
Roberto De Ioris 0dafe8aa5e backported gzip fix 2015-05-08 06:59:52 +02:00
Roberto De Ioris 5410cb4fe7 backported ssl ca management fix 2015-05-06 07:25:18 +02:00
Charlie Root 86f55a69cf fixed OpenBSD build on 2.0 2015-05-02 13:00:31 +02:00
Roberto De Ioris 6bd59ffe1c backported #848 2015-05-01 13:35:25 +02:00
Roberto De Ioris 95a139f73d backported wait-for-socket and wait_for hooks 2015-05-01 13:32:50 +02:00
Roberto De Ioris 2e71d62704 added Curtis Maloney to CONTRIBUTORS 2015-04-13 06:53:35 +02:00
Roberto De Ioris 8942e832e9 backported build fix from 2.1 2015-04-13 06:53:19 +02:00
Unbit 14b0a512e4 fixed #883 2015-04-10 15:53:42 +02:00
Unbit 0c062bbc1a fixed typo 2015-03-25 09:41:07 +01:00
Roberto De Ioris c63d94cb6e uWSGI 2.0.10 2015-03-17 08:34:34 +01:00
Unbit 4da7564c3b added support for UNIX sockets to rsyslog 2015-03-16 20:29:34 +01:00
Riccardo Magliocchetti d38edd839e Don't lower security standards with gcc 4.9
For some reason since e4d65c07ce
we started compiling -Wno-format, possibly because of plugins
dependencies not compiling.
Fedora (and Debian to some degrees) are starting to default to
-Wformat -Werror=format-security which is something sensible for
uwsgi. So let the distro handle the situation when a very recent
gcc version is encountered since they probably know better.
2015-03-11 14:04:04 +01:00
Ivan Kruglov cce041c7f0 psgi_loader: make sure that at least two params are passed to XS_input_seek() 2015-03-09 11:36:06 +01:00
Ivan Kruglov ca68d6938a psgi_loader: fix a one off bug in XS_input_seek() 2015-03-09 11:35:42 +01:00
Unbit 6d700e5a8b fixed #846 2015-02-19 06:53:21 +01:00
Unbit bad07a8520 attempt to fix #833 2015-02-11 11:32:33 +01:00
Roberto De Ioris 363b88a7b7 fixed emperor wrapper 2015-02-10 20:35:55 +01:00
Roberto De Ioris 932ed8ee29 fixed emperor wrappers logs 2015-02-10 20:31:04 +01:00
Roberto De Ioris 7b8e12911a backported --emperor-wrapper-fallback and --emperor-wraper-override 2015-02-10 20:27:02 +01:00
Roberto De Ioris c95062856b added safeexec hook 2015-02-10 20:10:19 +01:00
Unbit 6840b287d4 fixed scandir usage 2015-02-08 17:31:50 +01:00
Unbit ae9104ed91 fix return value for hv_store in uwsgi::opt 2015-02-08 17:30:29 +01:00
Roberto De Ioris 6c8d6ea15b typo 2015-01-28 07:09:48 +01:00
Roberto De Ioris 755eb3956d fixed exception handler for arguments 2015-01-28 06:50:14 +01:00
Roberto De Ioris 225dc6f7a3 fixed #806 2015-01-18 20:49:44 +01:00
Unbit 8509c41fd6 it's 2015 2015-01-05 20:29:02 +01:00
Unbit 2ae9ac8b88 another range header improvement 2015-01-05 13:53:13 +01:00
Unbit fed00ee5d6 fixed range 2015-01-04 15:02:54 +01:00
Unbit 66099275ca updated gemspec file 2014-12-29 10:07:07 +01:00
Unbit e7a40eb173 completed backporting of fastrouter post buffering 2014-12-27 13:30:16 +01:00
Riccardo Magliocchetti 8342150b78 Fix fastrouter compilation
After 6a8f18a9bb

Fix #801
2014-12-27 13:28:41 +01:00
Roberto De Ioris e2253f3693 backport of fastrouter buffering 2014-12-27 13:28:08 +01:00
Roberto De Ioris d2f07c7583 implemented uwsgi::opt in perl 2014-12-12 07:01:28 +01:00
Roberto De Ioris 1c87053a13 implemented --pull-header 2014-12-11 15:54:21 +01:00
Unbit d69e23414f another check for mod_proxy_uwsgi 2014-12-10 10:45:06 +01:00
Roberto De Ioris 3d37d272ee fixed master-fifo + cheaper 2014-12-09 09:53:45 +01:00
Riccardo Magliocchetti 9094a0f811 Fix leak on error in bind_to_unix
Spotted by cppcheck.
2014-12-09 09:44:36 +01:00
Unbit 97efcca2b7 improved mono plugin 2014-12-04 20:55:58 +01:00
Roberto De Ioris 2445fd1f61 fixed #776 2014-12-06 10:39:27 +01:00
Unbit 3234e0aae8 fixed #680 2014-12-06 09:14:17 +01:00
Unbit c5e7eb5d95 fix #785 2014-12-05 15:22:53 +01:00
Unbit e051e4fe1c another attempt at fixing mod_proxy_uwsgi 2014-12-05 15:08:47 +01:00
Unbit 5f691ec987 attempt to fix #774 2014-12-05 09:23:55 +01:00
Unbit a8e0aac9b0 fixed #787 2014-12-05 09:11:11 +01:00
Unbit bcdbab247c fix peer name in corerouters [2] 2014-11-22 13:22:21 +01:00
Roberto De Ioris 2e378dfc29 Merge branch 'uwsgi-2.0' of github.com:unbit/uwsgi into uwsgi-2.0 2014-11-22 13:19:28 +01:00
Roberto De Ioris acc270ad81 try to fix peer name in corerouter 2014-11-22 13:12:11 +01:00
Unbit b0c3ee02f9 detect modern pypy 2014-11-21 08:35:41 +01:00
Unbit 06ab5eaee5 fix #778 2014-11-21 08:34:44 +01:00
Roberto De Ioris 46de2ae0cb attempt to fix #340 2014-11-21 06:47:04 +01:00
Unbit 65fe93ac14 fixed hr_ssl_clear_errors 2014-11-20 07:35:18 +01:00
Roberto De Ioris f7cdd22f9a attempt to fix error propagation in https 2014-11-20 07:25:19 +01:00
Andjelko Horvat 3d553d2ae0 Daemon touch kill failback. 2014-11-19 10:45:59 +01:00
Unbit 582d5828aa another round of ssl fixes 2014-11-18 19:15:29 +01:00
Unbit 245a66b0e5 try to improve ssl management 2014-11-18 18:57:59 +01:00
Roberto De Ioris 596c81124e fixed destruction 2014-11-16 20:59:45 +01:00
Unbit a86a1fcc40 added active-workers signal target, aimed at improving #58 2014-11-16 18:47:33 +01:00
Unbit 34036ac8b4 Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2014-11-15 13:17:56 +01:00
Unbit 11cd6c34a5 fixed python3 --py-auto-reload-ignore 2014-11-15 13:17:52 +01:00
Unbit aaea6ff2e2 fixed modifiers usage in corerouters 2014-11-15 06:32:25 +01:00
Unbit 38c30bc257 bump version to 2.0.9 2014-11-15 05:26:20 +01:00
Unbit 2f3e83b78e added httpdumb router and subscribe-with-modifier 2014-11-14 15:41:42 +01:00
Roberto De Ioris 43e8c65841 support yajl brew 2014-11-14 06:03:08 +01:00
Unbit 555902a0ee less strict http generator 2014-11-13 11:56:44 +01:00
Unbit 9d4f4eb3c3 backported #772 2014-11-12 07:43:34 +01:00
Ævar Arnfjörð Bjarmason 5d338cfb3a psgi: Ensure that we call any DESTROY hooks on psgix.harakiri.commit
Before this we'd just exit(0) and let the OS clean up after us, but
e.g. with post-buffering=1 we'll end up with a temporary file in /tmp
that we won't clean up when we exit unless DESTROY is called.

This resulted in us leaking files in /tmp if we ever had a request where
the last request before a harakiri was a POST request with a body we'd
buffer to /tmp.

We'd have similar leaks in any user-defined code that required DESTROY
to run.

Aside from this I'm still not very comfortable with what this whole code
here in psgi_plugin.c and psgi_loader.c is doing when managing the
interpreter(s). It:

 * Doesn't consistently call PERL_SET_CONTEXT() as described in "perldoc
   perlembed".

 * Nothing calls PERL_SYS_TERM() either.

 * Should we be calling uwsgi_perl_free_stashes() here too?

To test this:

    UWSGI_PROFILE=psgi python uwsgiconfig.py --build
    ./uwsgi --master --http-socket localhost:1234 --psgi t/perl/test_harakiri.psgi

Then elsewhere:

    curl 'localhost:1234?0'
    curl 'localhost:1234?1'

Both of those should emit "Calling DESTROY".
2014-11-12 07:38:18 +01:00
Riccardo Magliocchetti 3406441d95 systemdlogger: fix compilation with -Werror=format-security 2014-11-06 18:53:30 +01:00
Unbit df08c7bfb5 fixed unmasked websocket 2014-11-06 09:02:21 +01:00
Unbit 75b4a3cb28 clear if sweep_on_full fails 2014-11-05 13:06:24 +01:00
Unbit c356c01f12 Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2014-11-02 10:51:50 +01:00
Unbit ba8aa44baa attempt to fix #766 2014-11-02 10:51:39 +01:00
Roberto De Ioris a1dc7a660c use uwsgi_buffer for send_ack in #760 2014-11-02 09:33:07 +01:00
Roberto De Ioris 3a4663844b fixed #760 2014-11-02 06:42:53 +01:00
Mattia Barbon 309f449a43 Fix latent refcounting bug
It can be reproduced by enabling the Perl debugger inside a PSGI application:

    {
        package DB;

        sub DB { }
        sub sub { &$sub }
    }

    $^P = 0x73f;

    sub { [200, ['Content-Type' => 'text/plain'], ['Hello World']] }

For every request the following warnings are emitted:

    Attempt to free unreferenced scalar: SV 0xfea6e8, Perl interpreter: 0xd534a0.
    Attempt to free unreferenced scalar: SV 0xfea718, Perl interpreter: 0xd534a0.

where the unreferenced scalars are the uwsgi::input/uwsgi::error instances
created in build_psgi_env.

The calling convention for Perl subroutines is that the values pushed on the
stack must be mortalized in the callee, and if the caller wants to retain them,
it must do a SvREFCNT_inc to undo the effect of the mortalization.

Before this patch XS_input/XS_error were not mortalizing the value, and
uwsgi_perl_obj_new was not incrementing the reference count, so the two bugs
balanced each other.

When running under debugger, Perl forwards all function/method calls to
DB::sub, which causes a mortal copy of the return value of
uwsgi::input/error::new to be pushed on the stack. The value is cleared by the
FREETMPS at the end of uwsgi_perl_obj_new, and the freed value is added to the
environment hash. The warning is emitted at the end of the request when the
environment hash is freed and Perl notices that some of the values has been
already freed.
2014-11-02 06:13:20 +01:00
Mattia Barbon f059a69312 Remove unnecessary mortalization
newRV(sv_newmortal()) is equivalent to newRV_noinc(newSV(0)): the former
creates a new SV with refcount 1, schedules a decrement "soon" (the
mortalization) and increments the refcount, the net result is a refcount of 1,
which is what the latter does.
2014-11-02 06:13:04 +01:00
Unbit 93116a1239 prepare for 2.0.8 2014-10-26 05:30:44 +01:00
unbit 5e4440443a Merge pull request #755 from aldur/manage_script_name_fix
manage_script_name fix for tricky resources
2014-10-24 17:19:50 +02:00
Unbit 373481b888 backported rtsp support 2014-10-24 17:12:52 +02:00
Unbit 105b9c69cf backported --hook-post-fork 2014-10-24 12:07:05 +02:00
Unbit 9012ead72c backported https fix for ssl shutdown 2014-10-24 11:49:18 +02:00
Roberto De Ioris 6c1d2625a8 backported support for chunked input management in the http/https router 2014-10-19 12:54:12 +02:00
Unbit c0733b5771 Merge remote-tracking branch 'origin/uwsgi-2.0-cache-lazy-expire' into uwsgi-2.0 2014-10-18 04:23:39 +02:00
Unbit f4759d7acd fixed php SCRIPT_NAME usage when --php-app is in place 2014-10-18 04:19:41 +02:00
Unbit 7082188a06 allow appendn hook without second argument 2014-10-17 13:15:30 +02:00
Unbit bcd9ed011d try to load trollius on python2 2014-10-17 13:04:46 +02:00
Nigel Heron 25c6d7a3a1 fix heap corruption in carbon plugin 2014-10-17 05:18:58 +02:00
Roberto De Ioris 675c02c7fa fixed #749 2014-10-16 20:53:47 +02:00
Roberto De Ioris 32896a1418 fixed #748 2014-10-16 08:26:13 +02:00
Unbit 548e736d84 fixed #746 2014-10-15 10:06:27 +02:00
Unbit 87575b1a22 disable SSLv3 by default and allow setting raw ssl options 2014-10-15 09:11:18 +02:00
Roberto De Ioris 1aa6eeca1b added sweep_on_full, clear_on_full and no_expire 2014-10-14 05:24:28 +02:00
Unbit f778e30d48 run the sweeper only if required 2014-10-13 13:00:07 +02:00
Unbit e071184d53 ignore lazy caches from the sweeper 2014-10-13 12:55:26 +02:00
Unbit 1d09cde778 implemented cache lazy expire 2014-10-13 12:40:40 +02:00
Greg Dahlman 70ee29becb added wait for fs and wait for mountpoint 2014-10-10 11:06:44 +02:00
Unbit 60e26333bf allows building external plugins as embedded 2014-10-10 11:00:28 +02:00
Unbit 865b9c199d improved offload api 2014-10-10 10:58:45 +02:00
Unbit 833193a1ba added UWSGI_HAS_OFFLOAD_UBUFS 2014-10-10 10:58:41 +02:00
Unbit 4eab050634 added 8 uwsgi_buffer and 8 custom fields to offload request 2014-10-10 10:57:03 +02:00
Aldur 688d1d3b75 fixed python3 support in spooler decorators 2014-10-10 10:55:18 +02:00
Unbit 349daee614 fixed uwsgidecorators spooler arguments 2014-10-10 10:49:18 +02:00
Unbit 0d272cf747 added Adriano Di Luzio to 2.0 CONTRIBUTORS 2014-10-10 10:47:19 +02:00
Unbit 46ac28efae fixed tcsetattr 2014-10-10 10:45:58 +02:00
Unbit 31b3bcc83d fixed kevent 2014-10-10 10:45:06 +02:00
Unbit f364d676fa automatically manage HTTP_X_FORWARDED_PROTO 2014-10-10 10:40:13 +02:00
Unbit c72fde1eed ensure PSGI response headers are in the right format [2] 2014-10-03 08:32:03 +02:00
Unbit a5cacfbba6 ensure PSGI response headers are in the right format 2014-10-03 08:31:52 +02:00
Unbit 921cfa5d79 backported daemons and proto http fixes from 2.1 2014-10-03 08:30:11 +02:00
Roberto De Ioris 9c676c62f5 destroy the whole instance on Emperor error 2014-10-03 08:26:57 +02:00
Roberto De Ioris 2917de3e76 exit on Emperor error 2014-10-03 08:26:43 +02:00
Unbit e836272c07 attempt to fix #732 2014-10-03 08:26:21 +02:00
Roberto De Ioris 7e25452242 set version to 2.0.7.1 2014-09-12 06:37:06 +02:00
unbit 42d42d9e4c Merge pull request #714 from xiaost/add-spooler_pids-api
python: add `spooler_pids` api for multi-spooler
2014-09-11 18:31:33 +02:00
xiaost 73c3e971e6 python: add spooler_pids api for multi-spooler
the old `spooler_pid` api only returns the first spooler pid
2014-09-11 23:34:13 +08:00
rdeioris b627edf1b8 Merge pull request #697 from xrmx/ignoreup
Update gitignore
2014-09-11 11:34:34 +02:00
Unbit 7fbc46750b attempt to fix #713 2014-09-11 08:22:19 +02:00
Unbit 1a63634359 report chdir() 2014-09-10 07:44:37 +02:00
Unbit c30e99a0df attempt to fix #611 2014-09-09 07:49:52 +02:00
Roberto De Ioris 3c53f26cbd ready for 2.0.7 2014-09-05 06:48:15 +02:00
Unbit a5c74293d8 fixed #702 2014-08-31 19:58:40 +01:00
Roberto De Ioris e5da0fc28c fix for #703, waiting for confirmation 2014-08-30 08:34:46 +02:00
Unbit 8e9bcc4758 implemented two new triggers for broodlord mode 2014-08-29 06:51:31 +02:00
Unbit bcf1f46d33 added vassal's plugin hooks 2014-08-28 18:09:02 +02:00
Unbit 8cd13f2ad9 fixed sendfile on smartos/omnios 2014-08-26 12:43:40 +02:00
Unbit 13df278cc4 attempt to fix emperor messaging on smartos/omnios 2014-08-26 12:27:36 +02:00
Unbit 56fedbd80c fixed stats vacuum 2014-08-26 09:45:00 +02:00
Unbit c4b563f260 fixed #644 2014-08-26 07:41:11 +02:00
Unbit 39706c5899 fixed #693 2014-08-26 07:25:37 +02:00
Unbit e45f710694 fix multiple python mountpoints with multiple threads in cow mode 2014-08-26 07:10:27 +02:00
unbit 0c86212aa2 Merge pull request #699 from nextsux/patch-1
Update rados.c
2014-08-24 20:28:27 +02:00
Martin Mlynář 3cfa743cb5 Update rados.c
According to http://ceph.com/docs/master/rados/api/librados/ rados_write Returns: 0 on success, negative error code on failure. When using <= comparsion, PUT method always ends with ISE 500.
2014-08-24 20:10:28 +02:00
Riccardo Magliocchetti f14cb7e02a Update gitignore
Failed patch(1) rej files, gccgo, mono and go plugins compiled
files, coverity work dir and tarball.
2014-08-20 15:55:24 +02:00
unbit 7fbc4013ca Merge pull request #679 from xrmx/logger
logfile: add support for filesize based rotation
2014-08-17 12:06:38 +02:00
Riccardo Magliocchetti 0324e5965c logfile: add support for filesize based rotation
Extends the logfile plugin sntax to accept a key value string.
Supported values are:
- logfile, the actual file name of the log file (mandatory)
- backupname, the file name of the rotated log
- maxsize, the size in bytes that triggers rotation

maxsize is mandatory if you want rotation, if you omit backupname the logfile with a
timestamp appended would be used as file name.

Example:

logger = staticlogger file:logfile=%dstatic.log,backupname=%dstatic.log.old,maxsize=1500
log-route = staticlogger app: -1|req: -1

will create a file based logger called static logger that would log
all the static requests to a file called static.log, which would be
rotated each 1500 bytes to a file named static.log.old

Fixes #542
2014-08-17 11:50:34 +02:00
unbit 2050d38f96 Merge pull request #687 from goir/uwsgi_remove_invalid_cache_file
add store_delete option to cache.
2014-08-17 11:49:11 +02:00
Goir fadce6cfe5 add store_delete option to cache. This automatically removes invalid caches files 2014-08-17 10:39:32 +02:00
Roberto De Ioris 0ac4f8f1e4 prepare for 2.0.7 2014-08-16 17:05:26 +02:00
unbit 51e81eff31 Merge pull request #688 from xrmx/coverity1608
Few coverity fixes
2014-08-16 16:58:40 +02:00
Riccardo Magliocchetti 4818a5d386 plugins/rpc: fix a couple of memory leaks
Always free response, in the worst case we are freeing NULL which
is a NOP.
Reported by Coverity as CID #1231246, #1231245
2014-08-16 16:52:59 +02:00
Riccardo Magliocchetti 4457fbefd6 core/rpc: avoid double close
Reported by coverity as CID #1231253
2014-08-16 16:31:32 +02:00
Roberto De Ioris 9780e5fc5e attempt to fix solaris/smartos events with emperor 2014-08-16 16:24:39 +02:00
Roberto De Ioris 9c18e0e12a fixed fastcgi and scgi protocols with out of buffer 2014-08-15 19:05:43 +02:00
unbit c4c146dca4 Merge pull request #685 from Ventero/mono
Fix symbol lookup error in the Mono plugin on OS X.
2014-08-15 06:03:28 +02:00
Ventero 08e1cf211c Fix symbol lookup error in the Mono plugin on OS X.
On OS X, mono libraries have to link against the Foundation framework.
2014-08-14 21:35:39 +02:00
Unbit a52a6fc1e1 fixed #683 2014-08-12 13:11:30 +02:00
Unbit 6e1c468eed fixed #669 2014-08-12 13:10:04 +02:00
Unbit 1c186db72a fix emperor destroy on mount/umount hook errors 2014-08-11 10:16:26 +02:00
Unbit 92a8d6f2c5 fixed uwsgi.rpc 2014-08-08 22:14:03 +02:00
Unbit 144ffbaa25 attempt to ignore user namespace in setns 2014-08-08 13:21:02 +02:00
Roberto De Ioris 3e910aaca2 fixed #666 2014-08-05 20:14:19 +02:00
Riccardo Magliocchetti 5b2a3c28d0 logging: reindent setup_choosen_logger 2014-08-04 16:27:14 +02:00
Riccardo Magliocchetti 01a5611159 logging: extract uwsgi_log_do_rotate from uwsgi_log_rotate
So it can be reused
2014-08-04 16:24:22 +02:00
Riccardo Magliocchetti bf692c4d18 logging: fixup uwsgi_log_rotate indentation
So one can actually read it
2014-08-04 15:39:20 +02:00
Riccardo Magliocchetti a09ee5153d Update Riccardo's entry in CONTRIBUTORS 2014-08-01 15:58:29 +02:00
Unbit bc9f5d6f88 allow calling the spooler from every cpython context 2014-08-01 12:41:55 +02:00
unbit ec25be94ba Merge pull request #675 from rectalogic/memcpy-fix
Use memmove instead of memcpy since src/dest may be overlapping.
2014-07-28 17:07:39 +02:00
Andrew Wason 7e8e113921 Use memmove instead of memcpy since src/dest may be overlapping.
Fixes #671
2014-07-28 09:21:45 -04:00
Unbit 0575859f2d attempt to fix #667 2014-07-24 09:09:15 +02:00
Unbit e9c0bf91ad fixed #668 2014-07-24 08:55:52 +02:00
rdeioris 53fb764830 Merge pull request #664 from akx/remove-compiled-java
Issue #663: Remove compiled uwsgi.class file to keep binaries out of the repo.
2014-07-21 10:13:17 +02:00
Aarni Koskela 76393e36be Remove compiled uwsgi.class file to keep binaries out of the repo. (Addresses issue #663) 2014-07-20 20:41:51 +03:00
Unbit 94a39e1755 fixed typo 2014-07-12 11:37:42 +02:00
Unbit e675b49ef8 added Mathieu Dupuy to CONTRIBUTORS 2014-07-11 08:48:18 +02:00
unbit 78b330dd96 Merge pull request #660 from andrewbevitt/master
Add cache length parameter to the PHP parameter parsing.
2014-07-09 16:34:26 +02:00
Andrew Bevitt 293ee92791 Add cache length parameter to the parameter parsing. 2014-07-10 00:11:19 +10:00
unbit dac7457927 Merge pull request #659 from CashStar/stats_pusher_statsd_counter_fix
send data as a counter, m has no meaning in statsd
2014-07-09 08:25:57 +02:00
Joshua C. Forest e1b3d8fd1a send data as a counter, m has no meaning in statsd 2014-07-08 16:19:30 -04:00
Unbit b1669d1887 2.0.6 is ready 2014-07-01 09:04:40 +02:00
Roberto De Ioris 095bd60f77 added if-hostname 2014-07-01 06:58:14 +02:00
Unbit c3d33c90a0 fixed wrongly nulled filename in rados 2014-06-30 11:57:02 +02:00
Roberto De Ioris 4905b64f2e improved buffer json escaping 2014-06-28 08:13:11 +02:00
Unbit cfe1e9de7b implemented OPTIONS in rados 2014-06-28 07:28:41 +02:00
Unbit 82dcfd338d added mkcol to rados 2014-06-28 07:02:47 +02:00
Unbit c696065d3c added uwsgi[rsize] routing var 2014-06-27 15:18:33 +02:00
Unbit 8746141afa the Rados plugin is no more based on the GlusterFS one 2014-06-27 15:03:53 +02:00
Unbit e2b2a16b8c fixed sync rados behaviour 2014-06-27 15:02:56 +02:00
Unbit 406daeb3ae first attempt in improving rados multithreading 2014-06-27 14:45:25 +02:00
Unbit acbc073c81 improved timeout 2014-06-27 14:37:23 +02:00
Unbit 2ad23e95dd implemented PUT and DELETE methods for rados 2014-06-27 14:23:43 +02:00
Unbit 807259f25b fixed rados async support 2014-06-27 13:44:53 +02:00
unbit 4b06b2391c Merge pull request #657 from johto/fifo_recreation
Remove the old FIFO socket from the event queue when recreating it
2014-06-25 07:34:29 +02:00
Marko Tiikkaja 8c0adef6e7 Remove the old FIFO socket from the event queue when recreating it
The previous code had two problems:
  1) It never removed the old fd from the event loop, which meant that
if the new fd received a different index, the old fd would keeping
waking up the master process repeatedly.
  2) If the new fd got the same index but the master loop went back to
epoll_wait() fast enough, Linux would claim that the socket is ready for
reading, but read() would return 0 again, which would cause the FIFO to
be recreated again, etc.

Fix by removing the old fd from the event queue before recreating it.
2014-06-24 13:49:20 +02:00
Unbit 52ea289283 try to fix SCRIPT_NAME and PATH_TRANSLATED in php plugin 2014-06-23 10:58:05 +02:00
Unbit bfb6e21e2a prepare for 2.0.6 2014-06-19 15:45:31 +02:00
Unbit 84d6f54ddd added fastrouter-fallback-on-no-key 2014-06-19 11:49:25 +02:00
Unbit 775afe1e86 added support for unix socket in apache mod_proxy_uwsgi 2014-06-19 05:52:26 +02:00
Unbit cabb5f3e8e another attempt at fixing mod_proxy_uwsgi for apache2.2/2.4 2014-06-19 04:37:31 +02:00
Unbit aae6413cb1 added callint scheme 2014-06-12 11:26:02 +02:00
Unbit 6666848ac3 another attempt in improving chain reloading 2014-06-11 18:32:26 +02:00
Unbit c6f1911686 fixed #649 2014-06-11 09:18:26 +02:00
Unbit ef4ee87fed fixed shortcut for ssl-socket 2014-06-08 06:36:09 +02:00
Unbit 2a2f1a9928 allow hacking the php sapi name 2014-06-08 06:21:28 +02:00
Unbit f1caa39f51 added chdir to attach-daemon2 2014-06-06 15:05:43 +02:00
Roberto De Ioris 536ffdcc79 fixed a memory leak with subscriptions 2014-06-06 04:20:39 +02:00
Unbit d3313a39b7 fixed #645 2014-06-03 18:37:00 +02:00
Unbit 89da4a97a6 another attempt for #645 2014-06-03 16:52:14 +02:00
Unbit 3e41d5927a attempt to fix #645 2014-06-03 13:16:48 +02:00
Unbit 6a32f5d49d fast fix for 2.0.5.1 2014-06-01 08:06:26 +02:00
Roberto De Ioris bf67984049 fixed #642 2014-06-02 06:53:06 +02:00
98 changed files with 2930 additions and 607 deletions
+10
View File
@@ -4,6 +4,12 @@
*.jar
*~
*.so
*.gox
*.a
*.dll
*.key
*.orig
*.rej
/uwsgi
/uwsgibuild.*
@@ -12,3 +18,7 @@
/t/ring/target
core/dot_h.c
+# coverity
+/cov-int/
+uwsgi.tar.xz
+5 -1
View File
@@ -1,7 +1,7 @@
- this is a incomplete list of all the contributors of the project -
Roberto De Ioris, Unbit, <roberto@unbit.it>
Riccardo Magliocchetti, Unbit, <riccardo@unbit.it>
Riccardo Magliocchetti
Yann Malet, Lincoln Loop
Simon Litchfield
Masahiro Honma, <hiratara@cpan.org>
@@ -28,3 +28,7 @@ Ryan Petrello
Danila Shtan <danila@shtan.ru>
Ævar Arnfjörð Bjarmason
Yu Zhao (getcwd)
Mathieu Dupuy
Adriano Di Luzio (adriano@unbit.it)
Curtis Maloney
Vladimir Didenko
+80 -10
View File
@@ -67,14 +67,19 @@ static int uwsgi_canon(request_rec *r, char *url)
}
url += sizeof(UWSGI_SCHEME); /* Keep slashes */
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
// is it a unix socket ?
if (strlen(url) == 2) {
*sport = 0;
}
else {
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"error parsing URL %s: %s", url, err);
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
}
apr_snprintf(sport, sizeof(sport), ":%u", port);
}
apr_snprintf(sport, sizeof(sport), ":%u", port);
if (ap_strchr(host, ':')) { /* if literal IPv6 address */
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
@@ -253,6 +258,43 @@ static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
return rp;
}
static apr_status_t ap_proxy_buckets_lifetime_transform(request_rec *r,
apr_bucket_brigade *from, apr_bucket_brigade *to)
{
apr_bucket *e;
apr_bucket *new;
const char *data;
apr_size_t bytes;
apr_status_t rv = APR_SUCCESS;
apr_brigade_cleanup(to);
for (e = APR_BRIGADE_FIRST(from);
e != APR_BRIGADE_SENTINEL(from);
e = APR_BUCKET_NEXT(e)) {
if (!APR_BUCKET_IS_METADATA(e)) {
apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else if (APR_BUCKET_IS_FLUSH(e)) {
new = apr_bucket_flush_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else if (APR_BUCKET_IS_EOS(e)) {
new = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964)
"Unhandled bucket type of type %s in"
" proxy_buckets_lifetime_transform", e->type->name);
apr_bucket_delete(e);
rv = APR_EGENERAL;
}
}
return rv;
}
#endif
@@ -263,6 +305,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
const char *buf;
char *value, *end;
int len;
int backend_broke = 1;
apr_status_t rc;
conn_rec *c = r->connection;
apr_off_t readbytes;
@@ -274,6 +317,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
rp->proxyreq = PROXYREQ_RESPONSE;
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
apr_bucket_brigade *pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
len = ap_getline(buffer, sizeof(buffer), rp, 1);
@@ -321,12 +365,13 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
}
for(;;) {
int finish = 0;
while(!finish) {
rv = ap_get_brigade(rp->input_filters, bb,
AP_MODE_READBYTES, mode,
conf->io_buffer_size);
if (APR_STATUS_IS_EAGAIN(rv)
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ) {
e = apr_bucket_flush_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
if (ap_pass_brigade(r->output_filters, bb) || c->aborted) {
@@ -342,21 +387,46 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
else if (rv != APR_SUCCESS) {
ap_proxy_backend_broke(r, bb);
ap_pass_brigade(r->output_filters, bb);
backend_broke = 1;
break;
}
mode = APR_NONBLOCK_READ;
apr_brigade_length(bb, 0, &readbytes);
backend->worker->s->read += readbytes;
ap_pass_brigade(r->output_filters, bb);
if (APR_BRIGADE_EMPTY(bb)) {
apr_brigade_cleanup(bb);
break;
}
ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
// found the last brigade?
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) finish = 1;
// do not pass chunk if it is zero_sized
apr_brigade_length(pass_bb, 0, &readbytes);
if ((readbytes > 0 && ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS) || c->aborted) {
finish = 1;
}
apr_brigade_cleanup(bb);
apr_brigade_cleanup(pass_bb);
}
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(bb);
return OK;
if (c->aborted || backend_broke) {
return DONE;
}
return OK;
}
static int uwsgi_handler(request_rec *r, proxy_worker *worker,
Binary file not shown.
+2 -1
View File
@@ -369,7 +369,8 @@ void async_schedule_to_req_green(void) {
uwsgi.schedule_fix(wsgi_req);
}
// switch after each yield
uwsgi.schedule_to_main(wsgi_req);
if (uwsgi.schedule_to_main)
uwsgi.schedule_to_main(wsgi_req);
}
#ifdef UWSGI_ROUTING
+10 -1
View File
@@ -128,7 +128,16 @@ int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
// need to escape \ and "
size_t i;
for(i=0;i<len;i++) {
if (buf[i] == '"') {
if (buf[i] == '\t') {
if (uwsgi_buffer_append(ub, "\\t", 2)) return -1;
}
else if (buf[i] == '\n') {
if (uwsgi_buffer_append(ub, "\\n", 2)) return -1;
}
else if (buf[i] == '\r') {
if (uwsgi_buffer_append(ub, "\\r", 2)) return -1;
}
else if (buf[i] == '"') {
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
}
else if (buf[i] == '\\') {
+106 -30
View File
@@ -24,6 +24,49 @@ extern struct uwsgi_server uwsgi;
*/
static void cache_full(struct uwsgi_cache *uc) {
uint64_t i;
int force_clear = 0;
if (!uc->ignore_full) {
if (uc->purge_lru)
uwsgi_log("LRU item will be purged from cache \"%s\"\n", uc->name);
else
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
}
uc->full++;
if (uc->purge_lru && uc->lru_head)
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
// we do not need locking here !
if (uc->sweep_on_full) {
uint64_t removed = 0;
uint64_t now = (uint64_t) uwsgi_now();
if (uc->next_scan <= now) {
uc->next_scan = now + uc->sweep_on_full;
for (i = 1; i < uc->max_items; i++) {
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->expires > 0 && uci->expires <= now) {
if (!uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
removed++;
}
}
}
if (removed == 0) {
force_clear = 1;
}
}
}
if (uc->clear_on_full || force_clear) {
for (i = 1; i < uc->max_items; i++) {
uwsgi_cache_del2(uc, NULL, 0, i, 0);
}
}
}
static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t need) {
// how many blocks we need ?
uint64_t needed_blocks = need/uc->blocksize;
@@ -331,6 +374,14 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
int cache_fd;
struct stat cst;
if (uc->store_delete && !stat(uc->store, &cst) && ((size_t) cst.st_size != uc->filesize || !S_ISREG(cst.st_mode))) {
uwsgi_log("Removing invalid cache store file: %s\n", uc->store);
if (unlink(uc->store) != 0) {
uwsgi_log("Cannot remove invalid cache store file: %s\n", uc->store);
exit(1);
}
}
if (stat(uc->store, &cst)) {
uwsgi_log("creating a new cache store file: %s\n", uc->store);
cache_fd = open(uc->store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
@@ -412,6 +463,17 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
}
static uint64_t check_lazy(struct uwsgi_cache *uc, struct uwsgi_cache_item *uci, uint64_t slot) {
if (!uci->expires || !uc->lazy_expire) return slot;
uint64_t now = (uint64_t) uwsgi_now();
// expired ?
if (uci->expires <= now) {
uwsgi_cache_del2(uc, NULL, 0, slot, UWSGI_CACHE_FLAG_LOCAL);
return 0;
}
return slot;
}
static uint64_t uwsgi_cache_get_index(struct uwsgi_cache *uc, char *key, uint16_t keylen) {
uint32_t hash = uc->hash->func(key, keylen);
@@ -437,7 +499,7 @@ static uint64_t uwsgi_cache_get_index(struct uwsgi_cache *uc, char *key, uint16_
if (memcmp(uci->key, key, keylen))
goto cycle;
return slot;
return check_lazy(uc, uci, slot);
cycle:
while (uci->next) {
@@ -460,8 +522,9 @@ cycle:
continue;
if (uci->keysize != keylen)
continue;
if (!memcmp(uci->key, key, keylen))
return slot;
if (!memcmp(uci->key, key, keylen)) {
return check_lazy(uc, uci, slot);
}
}
return 0;
@@ -710,15 +773,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) {
if (!uc->unused_blocks_stack_ptr) {
if (!uc->ignore_full) {
if (uc->purge_lru)
uwsgi_log("LRU item will be purged from cache \"%s\"\n", uc->name);
else
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
}
uc->full++;
if (uc->purge_lru && uc->lru_head)
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
cache_full(uc);
if (!uc->unused_blocks_stack_ptr)
goto end;
}
@@ -733,16 +788,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
else {
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
if (uci->first_block == 0xffffffffffffffffLLU) {
if (!uc->ignore_full)
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
uc->unused_blocks_stack_ptr++;
cache_full(uc);
goto end;
}
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
if (uci->first_block + needed_blocks >= uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
@@ -837,16 +890,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uint64_t old_first_block = uci->first_block;
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
if (uci->first_block == 0xffffffffffffffffLLU) {
if (!uc->ignore_full)
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
uci->first_block = old_first_block;
cache_full(uc);
goto end;
}
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
if (uci->first_block + needed_blocks >= uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
@@ -1052,7 +1103,7 @@ static uint64_t cache_sweeper_free_items(struct uwsgi_cache *uc) {
uint64_t i;
uint64_t freed_items = 0;
if (uc->no_expire || uc->purge_lru)
if (uc->no_expire || uc->purge_lru || uc->lazy_expire)
return 0;
uwsgi_rlock(uc->lock);
@@ -1131,20 +1182,24 @@ void uwsgi_cache_start_sweepers() {
if (uwsgi.cache_no_expire)
return;
int need_to_run = 0;
while(uc) {
pthread_t cache_sweeper;
if (!uc->no_expire && !uc->purge_lru) {
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) {
uwsgi_error("pthread_create()");
uwsgi_log("unable to run the sweeper!!!\n");
}
else {
uwsgi_log("sweeper thread enabled\n");
}
if (!uc->no_expire && !uc->purge_lru && !uc->lazy_expire) {
need_to_run = 1;
break;
}
uc = uc->next;
}
if (!need_to_run) return;
pthread_t cache_sweeper;
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) {
uwsgi_error("uwsgi_cache_start_sweepers()/pthread_create()");
uwsgi_log("unable to run the cache sweeper!!!\n");
return;
}
uwsgi_log("cache sweeper thread enabled\n");
}
void uwsgi_cache_start_sync_servers() {
@@ -1212,6 +1267,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_keysize = NULL;
char *c_store = NULL;
char *c_store_sync = NULL;
char *c_store_delete = NULL;
char *c_nodes = NULL;
char *c_sync = NULL;
char *c_udp_servers = NULL;
@@ -1220,6 +1276,10 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_math_initial = NULL;
char *c_ignore_full = NULL;
char *c_purge_lru = NULL;
char *c_lazy_expire = NULL;
char *c_sweep_on_full = NULL;
char *c_clear_on_full = NULL;
char *c_no_expire = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"name", &c_name,
@@ -1236,6 +1296,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"store", &c_store,
"store_sync", &c_store_sync,
"storesync", &c_store_sync,
"store_delete", &c_store_delete,
"storedelete", &c_store_delete,
"node", &c_nodes,
"nodes", &c_nodes,
"sync", &c_sync,
@@ -1250,6 +1312,11 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"ignore_full", &c_ignore_full,
"purge_lru", &c_purge_lru,
"lru", &c_purge_lru,
"lazy_expire", &c_lazy_expire,
"lazy", &c_lazy_expire,
"sweep_on_full", &c_sweep_on_full,
"clear_on_full", &c_clear_on_full,
"no_expire", &c_no_expire,
NULL)) {
uwsgi_log("unable to parse cache definition\n");
exit(1);
@@ -1299,8 +1366,17 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
if (c_use_last_modified) uc->use_last_modified = 1;
if (c_ignore_full) uc->ignore_full = 1;
if (c_store_delete) uc->store_delete = 1;
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
if (c_lazy_expire) uc->lazy_expire = 1;
if (c_sweep_on_full) {
uc->sweep_on_full = uwsgi_n64(c_sweep_on_full);
}
if (c_clear_on_full) uc->clear_on_full = 1;
if (c_no_expire) uc->no_expire = 1;
uc->store_sync = uwsgi.cache_store_sync;
if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); }
+20
View File
@@ -294,6 +294,26 @@ int uwsgi_logic_opt_if_not_plugin(char *key, char *value) {
return 0;
}
int uwsgi_logic_opt_if_hostname(char *key, char *value) {
if (!strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) {
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
return 1;
}
return 0;
}
int uwsgi_logic_opt_if_not_hostname(char *key, char *value) {
if (strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) {
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
return 1;
}
return 0;
}
int uwsgi_count_options(struct uwsgi_option *uopt) {
struct uwsgi_option *aopt;
+18 -2
View File
@@ -237,7 +237,12 @@ void uwsgi_detach_daemons() {
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
int waitpid_status;
while (!kill(ud->pid, 0)) {
kill(-(ud->pid), ud->stop_signal);
if (uwsgi_instance_is_reloading && ud->reload_signal > 0) {
kill(-(ud->pid), ud->reload_signal);
}
else {
kill(-(ud->pid), ud->stop_signal);
}
sleep(1);
waitpid(ud->pid, &waitpid_status, WNOHANG);
if (uwsgi_now() >= timeout) {
@@ -292,11 +297,18 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
uwsgi_close_all_sockets();
uwsgi_close_all_fds();
if (ud->chdir) {
if (chdir(ud->chdir)) {
uwsgi_error("uwsgi_spawn_daemon()/chdir()");
exit(1);
}
}
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && defined(CLONE_NEWPID)
if (ud->ns_pid) {
// we need to create a new session
if (setsid() < 0) {
uwsgi_error("setsid()");
uwsgi_error("uwsgi_spawn_daemon()/setsid()");
exit(1);
}
// avoid the need to set stop_signal in attach-daemon2
@@ -497,6 +509,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
char *d_uid = NULL;
char *d_gid = NULL;
char *d_ns_pid = NULL;
char *d_chdir = NULL;
char *arg = uwsgi_str(value);
@@ -518,6 +531,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
"uid", &d_uid,
"gid", &d_gid,
"ns_pid", &d_ns_pid,
"chdir", &d_chdir,
NULL)) {
uwsgi_log("invalid --%s keyval syntax\n", opt);
exit(1);
@@ -565,6 +579,8 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
#endif
uwsgi_ud->ns_pid = d_ns_pid ? 1 : 0;
uwsgi_ud->chdir = d_chdir;
if (d_touch) {
size_t i,rlen = 0;
char **argv = uwsgi_split_quoted(d_touch, strlen(d_touch), ";", &rlen);
+82 -4
View File
@@ -13,6 +13,7 @@ void emperor_send_stats(int);
time_t emperor_throttle;
int emperor_throttle_level;
int emperor_warming_up = 1;
struct uwsgi_instance *ui;
@@ -867,7 +868,16 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
#ifdef UWSGI_DEBUG
uwsgi_log("emperor throttle = %d\n", emperor_throttle_level);
#endif
usleep(emperor_throttle_level);
if (emperor_warming_up) {
if (emperor_throttle_level > 0) {
// wait 10 milliseconds in case of fork-bombing
// pretty random value, but should avoid the load average to increase
usleep(10);
}
}
else {
usleep(emperor_throttle_level);
}
if (uwsgi.emperor_tyrant) {
if (uid == 0 || gid == 0) {
@@ -1015,14 +1025,14 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
uwsgi_foreach(usl, uwsgi.mount_as_emperor) {
uwsgi_log("mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
uwsgi_log("unable to mount %s\n", usl->value);
}
}
uwsgi_foreach(usl, uwsgi.umount_as_emperor) {
uwsgi_log("un-mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
uwsgi_log("unable to umount %s\n", usl->value);
}
}
uwsgi_foreach(usl, uwsgi.exec_as_emperor) {
@@ -1093,7 +1103,20 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
}
static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
int i;
// run plugin hooks for the vassal
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->vassal) {
uwsgi.p[i]->vassal(n_ui);
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->vassal) {
uwsgi.gp[i]->vassal(n_ui);
}
}
#ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
@@ -1350,7 +1373,6 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
}
// close all of the unneded fd
int i;
for (i = 3; i < (int) uwsgi.max_fd; i++) {
if (uwsgi_fd_is_safe(i))
continue;
@@ -1429,11 +1451,45 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
func(n_ui->name, n_ui->uid, n_ui->gid);
}
// ->vassal_before_exec
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->vassal_before_exec) {
uwsgi.p[i]->vassal_before_exec(n_ui);
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->vassal) {
uwsgi.gp[i]->vassal_before_exec(n_ui);
}
}
if (uwsgi.emperor_wrapper_override) {
char *orig_wrapper = vassal_argv[0];
uwsgi_foreach(usl, uwsgi.emperor_wrapper_override) {
vassal_argv[0] = usl->value;
uwsgi_log("[emperor] trying to use %s as binary wrapper ...\n", usl->value);
execvp(vassal_argv[0], vassal_argv);
// not here if the binary is found
}
vassal_argv[0] = orig_wrapper;
}
// start !!!
if (execvp(vassal_argv[0], vassal_argv)) {
uwsgi_error("execvp()");
}
uwsgi_log("[emperor] binary path: %s\n", vassal_argv[0]);
uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n");
// trying fallback
uwsgi_foreach(usl, uwsgi.emperor_wrapper_fallback) {
uwsgi_log("[emperor] trying to use %s as binary fallback ...\n", usl->value);
vassal_argv[0] = usl->value;
execvp(vassal_argv[0], vassal_argv);
// not here if the binary is found
}
// never here
exit(UWSGI_EXILE_CODE);
}
@@ -1528,6 +1584,7 @@ void uwsgi_emperor_run_scanners(void) {
ues->monitor->func(ues);
ues = ues->next;
}
emperor_warming_up = 0;
}
void emperor_build_scanners() {
@@ -1738,6 +1795,8 @@ void emperor_loop() {
if (ui_current) {
char byte;
ssize_t rlen = read(interesting_fd, &byte, 1);
// retry if needed
if (rlen < 0 && uwsgi_is_again()) continue;
if (rlen <= 0) {
// SAFE
event_queue_del_fd(uwsgi.emperor_queue, interesting_fd, event_queue_read());
@@ -2236,6 +2295,9 @@ void uwsgi_check_emperor() {
}
free(env_emperor_fd_config);
}
if (fds)
free(fds);
close(proxy_fd);
break;
}
next:
@@ -2322,7 +2384,17 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
void uwsgi_master_manage_emperor() {
char byte;
#ifdef UWSGI_EVENT_USE_PORT
// special cose for port event system
// place the socket in non-blocking mode
uwsgi_socket_nb(uwsgi.emperor_fd);
#endif
ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1);
#ifdef UWSGI_EVENT_USE_PORT
// special cose for port event system
// and place back in blocking mode
uwsgi_socket_b(uwsgi.emperor_fd);
#endif
if (rlen > 0) {
uwsgi_log_verbose("received message %d from emperor\n", byte);
// remove me
@@ -2342,6 +2414,12 @@ void uwsgi_master_manage_emperor() {
uwsgi_unblock_signal(SIGHUP);
}
}
#ifdef UWSGI_EVENT_USE_PORT
// special cose for port event system
else if (rlen < 0 && uwsgi_is_again()) {
return;
}
#endif
else {
uwsgi_error("uwsgi_master_manage_emperor()/read()");
uwsgi_log("lost connection with my emperor !!!\n");
+8
View File
@@ -45,6 +45,14 @@ void uwsgi_403(struct wsgi_request *wsgi_req) {
uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9);
}
void uwsgi_405(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "405 Method Not Allowed", 22)) return;
if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (error_page(wsgi_req, uwsgi.error_page_403)) return;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return;
uwsgi_response_write_body_do(wsgi_req, "Method Not Allowed", 18);
}
void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
char *redirect = NULL;
+7 -6
View File
@@ -414,11 +414,11 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
}
if (ret < 0) {
if (errno != ETIME) {
uwsgi_error("port_getn()");
return -1;
}
return 0;
if (errno == ETIME) return 0;
if (errno != EINTR) {
uwsgi_error("port_getn()");
}
return -1;
}
uint_t i;
@@ -452,6 +452,7 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
else {
ret = port_get(eq, &pe, NULL);
}
if (ret < 0) {
if (errno == ETIME) return 0;
if (errno != EINTR) {
@@ -947,7 +948,7 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
struct timespec ts;
struct kevent ev;
if (timeout <= 0) {
if (timeout < 0) {
ret = kevent(eq, NULL, 0, &ev, 1, NULL);
}
else {
+1 -2
View File
@@ -464,6 +464,7 @@ void uwsgi_exception_setup_handlers() {
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
while(usl) {
// do not free handler !!!
char *handler = uwsgi_str(usl->value);
char *colon = strchr(handler, ':');
if (colon) {
@@ -472,10 +473,8 @@ void uwsgi_exception_setup_handlers() {
struct uwsgi_exception_handler *ueh = uwsgi_exception_handler_by_name(handler);
if (!ueh) {
uwsgi_log("unable to find exception handler: %s\n", handler);
free(handler);
exit(1);
}
free(handler);
struct uwsgi_exception_handler_instance *uehi = uwsgi_calloc(sizeof(struct uwsgi_exception_handler_instance));
uehi->handler = ueh;
+2
View File
@@ -80,6 +80,7 @@ void uwsgi_master_fifo_prepare() {
uwsgi_fifo_table['-'] = uwsgi_cheaper_decrease;
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
uwsgi_fifo_table['B'] = vassal_sos;
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
uwsgi_fifo_table['E'] = emperor_rescan;
@@ -131,6 +132,7 @@ int uwsgi_master_fifo_manage(int fd) {
}
// fifo destroyed, recreate it
else if (rlen == 0) {
event_queue_del_fd(uwsgi.master_queue, uwsgi.master_fifo_fd, event_queue_read());
close(fd);
uwsgi.master_fifo_fd = uwsgi_master_fifo();
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
+1 -1
View File
@@ -72,7 +72,7 @@ void gateway_respawn(int id) {
if (gw_pid == 0) {
uwsgi_fixup_fds(0, 0, ug);
uwsgi_close_all_sockets();
uwsgi_close_all_unshared_sockets();
if (uwsgi.master_as_root)
uwsgi_as_root();
#ifdef __linux__
+66 -6
View File
@@ -91,6 +91,14 @@ static int uwsgi_hook_exec(char *arg) {
return ret;
}
static int uwsgi_hook_safeexec(char *arg) {
int ret = uwsgi_run_command_and_wait(NULL, arg);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret);
}
return 0;
}
static int uwsgi_hook_exit(char *arg) {
int exit_code = 0;
if (strlen(arg) > 1) {
@@ -233,17 +241,26 @@ static int uwsgi_hook_writen(char *arg) {
static int uwsgi_hook_appendn(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook appendn syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
if (space)
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
if (space)
*space = ' ';
return -1;
}
if (!space) {
// simple newline
if (write(fd, "\n", 1) != 1) {
uwsgi_error("uwsgi_hook_appendn()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
*space = ' ';
size_t l = strlen(space+1);
char *buf = uwsgi_malloc(l + 1);
@@ -390,6 +407,24 @@ static int uwsgi_hook_hostname(char *arg) {
#endif
}
static int uwsgi_hook_unix_signal(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid unix_signal syntax, must be <signum> <func>\n");
return -1;
}
*space = 0;
int signum = atoi(arg);
*space = ' ';
void (*func)(int) = dlsym(RTLD_DEFAULT, space+1);
if (!func) {
uwsgi_log("unable to find function \"%s\"\n", space+1);
return -1;
}
uwsgi_unix_signal(signum, func);
return 0;
}
static int uwsgi_hook_callint(char *arg) {
char *space = strchr(arg, ' ');
@@ -540,6 +575,22 @@ static int uwsgi_hook_retryrpc(char *arg) {
return 0;
}
static int uwsgi_hook_wait_for_fs(char *arg) {
return uwsgi_wait_for_fs(arg, 0);
}
static int uwsgi_hook_wait_for_file(char *arg) {
return uwsgi_wait_for_fs(arg, 1);
}
static int uwsgi_hook_wait_for_dir(char *arg) {
return uwsgi_wait_for_fs(arg, 2);
}
static int uwsgi_hook_wait_for_socket(char *arg) {
return uwsgi_wait_for_socket(arg);
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
uwsgi_register_hook("chdir", uwsgi_hook_chdir);
@@ -553,6 +604,7 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("sticky", uwsgi_hook_sticky);
uwsgi_register_hook("exec", uwsgi_hook_exec);
uwsgi_register_hook("safeexec", uwsgi_hook_safeexec);
uwsgi_register_hook("create", uwsgi_hook_creat);
uwsgi_register_hook("creat", uwsgi_hook_creat);
@@ -580,6 +632,14 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
uwsgi_register_hook("wait_for_fs", uwsgi_hook_wait_for_fs);
uwsgi_register_hook("wait_for_file", uwsgi_hook_wait_for_file);
uwsgi_register_hook("wait_for_dir", uwsgi_hook_wait_for_dir);
uwsgi_register_hook("wait_for_socket", uwsgi_hook_wait_for_socket);
uwsgi_register_hook("unix_signal", uwsgi_hook_unix_signal);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
+5 -1
View File
@@ -73,7 +73,7 @@ void uwsgi_init_default() {
uwsgi.stats_pusher_default_freq = 3;
uwsgi.original_log_fd = -1;
uwsgi.original_log_fd = 2;
uwsgi.emperor_fd_config = -1;
uwsgi.emperor_fd_proxy = -1;
@@ -471,6 +471,10 @@ void sanitize_args() {
exit(1);
}
if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) {
if (!uwsgi.mem_collector_freq) uwsgi.mem_collector_freq = 3;
}
/* here we try to choose if thunder lock is a good thing */
#ifdef UNBIT
if (uwsgi.numproc > 1 && !uwsgi.map_socket) {
+21
View File
@@ -392,6 +392,26 @@ static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) {
return buffer;
}
static char *uwsgi_scheme_callint(char *url, size_t *size, int add_zero) {
int (*func)(void) = dlsym(RTLD_DEFAULT, url);
if (!func) {
uwsgi_log("unable to find symbol %s\n", url);
exit(1);
}
char *s = uwsgi_num2str(func());
*size = strlen(s);
if (add_zero) {
*size += 1;
}
char *buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, s, strlen(s));
free(s);
return buffer;
}
static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) {
void *sym_start_ptr = NULL, *sym_end_ptr = NULL;
@@ -1249,6 +1269,7 @@ void uwsgi_setup_schemes() {
uwsgi_register_scheme("fd", uwsgi_scheme_fd);
uwsgi_register_scheme("exec", uwsgi_scheme_exec);
uwsgi_register_scheme("call", uwsgi_scheme_call);
uwsgi_register_scheme("callint", uwsgi_scheme_callint);
}
struct uwsgi_string_list *uwsgi_check_scheme(char *file) {
+9 -8
View File
@@ -277,14 +277,12 @@ static void legions_check_nodes_step2() {
memcpy(best_uuid, node->uuid, 36);
}
// go on if i am not an arbiter
else if (ul->valor > 0) {
// no potential Lord is available, i will propose myself
// but only if i am not suspended...
if (uwsgi_now() > ul->suspended_til) {
best_valor = ul->valor;
memcpy(best_uuid, ul->uuid, 36);
i_am_the_best = 1;
}
// no potential Lord is available, i will propose myself
// but only if i am not suspended...
else if (ul->valor > 0 && uwsgi_now() > ul->suspended_til) {
best_valor = ul->valor;
memcpy(best_uuid, ul->uuid, 36);
i_am_the_best = 1;
}
else {
// empty lord
@@ -1212,6 +1210,9 @@ next:
legion = legion->next;
}
// this must be called only by the master !!!
if (!uwsgi.workers) return;
if (uwsgi.workers[0].pid != getpid()) return;
uwsgi_legion_announce_death();
}
+98 -86
View File
@@ -3,6 +3,7 @@
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#include <sys/user.h>
#include <sys/sysctl.h>
#include <kvm.h>
#elif defined(__sun__)
/* Terrible Hack !!! */
@@ -13,10 +14,6 @@
#define _FILE_OFFSET_BITS 64
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <sys/sysctl.h>
#endif
#ifdef __DragonFly__
#include <uwsgi.h>
#endif
@@ -301,19 +298,27 @@ void logto(char *logfile) {
}
/* stdout */
if (fd != 1) {
if (dup2(fd, 1) < 0) {
// if the log-master is already active, just re-set the original_log_fd
if (uwsgi.shared->worker_log_pipe[0] == -1) {
/* stdout */
if (fd != 1) {
if (dup2(fd, 1) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(fd);
}
/* stderr */
if (dup2(1, 2) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(fd);
}
/* stderr */
if (dup2(1, 2) < 0) {
uwsgi_error("dup2()");
exit(1);
uwsgi.original_log_fd = 2;
}
else {
uwsgi.original_log_fd = fd;
}
}
@@ -346,51 +351,51 @@ void uwsgi_setup_log() {
static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl) {
char *id = NULL;
char *name = usl->value;
char *name = usl->value;
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space - name, "", 0);
name = space + 1;
}
}
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space - name, "", 0);
name = space + 1;
}
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
// make a copy of the logger
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
// make a copy of the logger
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
if (colon) {
choosen_logger->arg = colon + 1;
// check for empty string
if (*choosen_logger->arg == 0) {
choosen_logger->arg = NULL;
}
*colon = ':';
}
return choosen_logger;
if (colon) {
choosen_logger->arg = colon + 1;
// check for empty string
if (*choosen_logger->arg == 0) {
choosen_logger->arg = NULL;
}
*colon = ':';
}
return choosen_logger;
}
void uwsgi_setup_log_master(void) {
@@ -511,40 +516,46 @@ void uwsgi_check_logrotate(void) {
}
}
void uwsgi_log_rotate() {
if (!uwsgi.logfile) return;
char *rot_name = uwsgi.log_backupname;
int need_free = 0;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) uwsgi_now());
rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str);
free(ts_str);
need_free = 1;
}
// this will be rawly written to the logfile
uwsgi_logfile_write("logsize: %llu, triggering rotation to %s...\n", (unsigned long long) uwsgi.shared->logsize, rot_name);
if (rename(uwsgi.logfile, rot_name) == 0) {
// reopen logfile and dup'it, on dup2 error, exit(1)
int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
// this will be written to the original file
uwsgi_error_open(uwsgi.logfile);
void uwsgi_log_do_rotate(char *logfile, char *rotatedfile, off_t logsize, int log_fd) {
int need_free = 0;
char *rot_name = rotatedfile;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) uwsgi_now());
rot_name = uwsgi_concat3(logfile, ".", ts_str);
free(ts_str);
need_free = 1;
}
// this will be rawly written to the logfile
uwsgi_logfile_write("logsize: %llu, triggering rotation to %s...\n", (unsigned long long) logsize, rot_name);
if (rename(logfile, rot_name) == 0) {
// reopen logfile and dup'it, on dup2 error, exit(1)
int fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
// this will be written to the original file
uwsgi_error_open(logfile);
exit(1);
}
else {
if (dup2(fd, log_fd) < 0) {
// this could be lost :(
uwsgi_error("uwsgi_log_do_rotate()/dup2()");
exit(1);
}
else {
if (dup2(fd, uwsgi.original_log_fd) < 0) {
// this could be lost :(
uwsgi_error("uwsgi_log_rotate()/dup2()");
exit(1);
}
close(fd);
}
}
else {
uwsgi_error("unable to rotate log: rename()");
}
if (need_free)
free(rot_name);
}
close(fd);
}
}
else {
uwsgi_error("unable to rotate log: rename()");
}
if (need_free)
free(rot_name);
}
void uwsgi_log_rotate() {
if (!uwsgi.logfile)
return;
uwsgi_log_do_rotate(uwsgi.logfile, uwsgi.log_backupname, uwsgi.shared->logsize, uwsgi.original_log_fd);
}
void uwsgi_log_reopen() {
@@ -1500,6 +1511,7 @@ static void *logger_thread_loop(void *noarg) {
if (uwsgi.req_log_master) {
logpoll[1].events = POLLIN;
logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0];
logpolls++;
}
+36 -16
View File
@@ -7,6 +7,7 @@ void uwsgi_update_load_counters() {
int i;
uint64_t busy_workers = 0;
uint64_t idle_workers = 0;
static time_t last_sos = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
@@ -21,6 +22,15 @@ void uwsgi_update_load_counters() {
if (busy_workers >= (uint64_t) uwsgi.numproc) {
ushared->overloaded++;
if (uwsgi.vassal_sos) {
if (uwsgi.current_time - last_sos > uwsgi.vassal_sos) {
uwsgi_log_verbose("asking Emperor for reinforcements (overload: %llu)...\n", (unsigned long long) ushared->overloaded);
vassal_sos();
last_sos = uwsgi.current_time;
}
}
}
ushared->busy_workers = busy_workers;
@@ -248,17 +258,18 @@ static void master_check_listen_queue() {
if (uwsgi_sock->queue > backlog) {
backlog = uwsgi_sock->queue;
}
if (uwsgi_sock->queue > 0 && uwsgi_sock->queue >= uwsgi_sock->max_queue) {
uwsgi_log_verbose("*** uWSGI listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu) ***\n", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
}
if (uwsgi.alarm_backlog) {
char buf[1024];
int ret = snprintf(buf, 1024, "listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu)", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
if (ret > 0 && ret < 1024) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.alarm_backlog) {
uwsgi_alarm_trigger(usl->value, buf, ret);
if (uwsgi.alarm_backlog) {
char buf[1024];
int ret = snprintf(buf, 1024, "listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu)", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
if (ret > 0 && ret < 1024) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.alarm_backlog) {
uwsgi_alarm_trigger(usl->value, buf, ret);
}
}
}
}
@@ -273,17 +284,23 @@ static void master_check_listen_queue() {
if (uwsgi.vassal_sos_backlog > 0 && uwsgi.has_emperor) {
if (uwsgi.shared->backlog >= (uint64_t) uwsgi.vassal_sos_backlog) {
// ask emperor for help
char byte = 30;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
}
else {
uwsgi_log_verbose("asking Emperor for reinforcements (backlog: %llu)...\n", (unsigned long long) uwsgi.shared->backlog);
}
uwsgi_log_verbose("asking Emperor for reinforcements (backlog: %llu)...\n", (unsigned long long) uwsgi.shared->backlog);
vassal_sos();
}
}
}
void vassal_sos() {
if (!uwsgi.has_emperor) {
uwsgi_log("[broodlord] instance not governed by an Emperor !!!\n");
return;
}
char byte = 30;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("vassal_sos()/write()");
}
}
int master_loop(char **argv, char **environ) {
struct timeval last_respawn;
@@ -845,7 +862,10 @@ int master_loop(char **argv, char **environ) {
if (touched) {
uwsgi_log_verbose("*** %s has been touched... reloading daemon \"%s\" (pid: %d) !!! ***\n", touched, ud->command, (int) ud->pid);
if (kill(-ud->pid, ud->stop_signal)) {
uwsgi_error("[uwsgi-daemon/touch] kill()");
// killing process group failed, try to kill by process id
if (kill(ud->pid, ud->stop_signal)) {
uwsgi_error("[uwsgi-daemon/touch] kill()");
}
}
}
}
+56 -18
View File
@@ -39,27 +39,51 @@ int uwsgi_master_check_reload(char **argv) {
// check for chain reload
void uwsgi_master_check_chain() {
static time_t last_check = 0;
if (!uwsgi.status.chain_reloading) return;
int i;
int needed_procs = 0;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0) {
needed_procs++;
}
}
if (uwsgi.status.chain_reloading > needed_procs) {
uwsgi.status.chain_reloading = 0;
uwsgi_log_verbose("chain reloading complete\n");
}
uwsgi_block_signal(SIGHUP);
for(i=1;i<=uwsgi.numproc;i++) {
// do not curse a worker until the old one is ready
if (uwsgi.workers[i].accepting == 0) break;
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
uwsgi_curse(i, SIGHUP);
break;
// we need to ensure the previous worker (if alive) is accepting new requests
// before going on
if (uwsgi.status.chain_reloading > 1) {
struct uwsgi_worker *previous_worker = &uwsgi.workers[uwsgi.status.chain_reloading-1];
// is the previous worker alive ?
if (previous_worker->pid > 0 && !previous_worker->cheaped) {
// the worker has been respawned but it is still not ready
if (previous_worker->accepting == 0) {
time_t now = uwsgi_now();
if (now != last_check) {
uwsgi_log_verbose("chain is still waiting for worker %d...\n", uwsgi.status.chain_reloading-1);
last_check = now;
}
return;
}
}
}
// if all the processes are recycled, the chain is over
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
uwsgi.status.chain_reloading = 0;
uwsgi_log_verbose("chain reloading complete\n");
return;
}
uwsgi_block_signal(SIGHUP);
int i;
for(i=uwsgi.status.chain_reloading;i<=uwsgi.numproc;i++) {
struct uwsgi_worker *uw = &uwsgi.workers[i];
if (uw->pid > 0 && !uw->cheaped && uw->accepting) {
// the worker could have been already cursed
if (uw->cursed_at == 0) {
uwsgi_log_verbose("chain next victim is worker %d\n", i);
uwsgi_curse(i, SIGHUP);
}
break;
}
else {
uwsgi.status.chain_reloading++;
}
}
uwsgi_unblock_signal(SIGHUP);
}
@@ -120,12 +144,25 @@ void uwsgi_master_check_idle() {
uwsgi.workers[i].cheaped = 1;
if (uwsgi.workers[i].pid == 0)
continue;
// first send SIGINT
kill(uwsgi.workers[i].pid, SIGINT);
// and start waiting upto 3 seconds
int j;
for(j=0;j<3;j++) {
sleep(1);
int ret = waitpid(uwsgi.workers[i].pid, &waitpid_status, WNOHANG);
if (ret == 0) continue;
if (ret == (int) uwsgi.workers[i].pid) goto done;
// on error, directly send SIGKILL
break;
}
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
if (errno != ECHILD)
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
}
else {
done:
uwsgi.workers[i].pid = 0;
uwsgi.workers[i].rss_size = 0;
uwsgi.workers[i].vsz_size = 0;
@@ -317,6 +354,7 @@ int uwsgi_master_check_daemons_death(int diedpid) {
int uwsgi_worker_is_busy(int wid) {
int i;
if (uwsgi.workers[uwsgi.mywid].sig) return 1;
for(i=0;i<uwsgi.cores;i++) {
if (uwsgi.workers[wid].cores[i].in_request) {
return 1;
+5
View File
@@ -162,6 +162,7 @@ int uwsgi_calc_cheaper(void) {
ignore_algo = 1;
}
uwsgi.cheaper_fifo_delta = 0;
goto safe;
}
// if cheaper limits wants to change worker count, then skip cheaper algo
@@ -172,6 +173,7 @@ int uwsgi_calc_cheaper(void) {
needed_workers = 0;
}
safe:
if (needed_workers > 0) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
@@ -702,6 +704,7 @@ int uwsgi_respawn_worker(int wid) {
for(i=0;i<uwsgi.cores;i++) {
uwsgi.workers[uwsgi.mywid].cores[i].in_request = 0;
memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request));
memset(uwsgi.workers[uwsgi.mywid].cores[i].buffer, 0, sizeof(struct uwsgi_header));
}
uwsgi_fixup_fds(wid, 0, NULL);
@@ -1719,6 +1722,7 @@ void uwsgi_setns_preopen() {
}
while ((de = readdir(ns)) != NULL) {
if (strlen(de->d_name) > 0 && de->d_name[0] == '.') continue;
if (!strcmp(de->d_name, "user")) continue;
struct uwsgi_string_list *usl = NULL;
int found = 0;
uwsgi_foreach(usl, uwsgi.setns_socket_skip) {
@@ -1777,6 +1781,7 @@ void uwsgi_master_manage_setns(int fd) {
}
while ((de = readdir(ns)) != NULL) {
if (strlen(de->d_name) > 0 && de->d_name[0] == '.') continue;
if (!strcmp(de->d_name, "user")) continue;
struct uwsgi_string_list *usl = NULL;
int found = 0;
uwsgi_foreach(usl, uwsgi.setns_socket_skip) {
+38
View File
@@ -55,6 +55,9 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
}
return -1;
}
#ifdef UWSGI_DEBUG
uwsgi_log("[offload] created session %p\n", uor);
#endif
return 0;
}
@@ -159,6 +162,12 @@ static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsg
}
static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
// call the free function asap
if (uor->free) {
uor->free(uor);
}
// close the socket and the file descriptor
if (uor->takeover && uor->s > -1) {
close(uor->s);
@@ -197,12 +206,41 @@ static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_re
uwsgi_buffer_destroy(uor->ubuf);
}
if (uor->ubuf1) {
uwsgi_buffer_destroy(uor->ubuf1);
}
if (uor->ubuf2) {
uwsgi_buffer_destroy(uor->ubuf2);
}
if (uor->ubuf3) {
uwsgi_buffer_destroy(uor->ubuf3);
}
if (uor->ubuf4) {
uwsgi_buffer_destroy(uor->ubuf4);
}
if (uor->ubuf5) {
uwsgi_buffer_destroy(uor->ubuf5);
}
if (uor->ubuf6) {
uwsgi_buffer_destroy(uor->ubuf6);
}
if (uor->ubuf7) {
uwsgi_buffer_destroy(uor->ubuf7);
}
if (uor->ubuf8) {
uwsgi_buffer_destroy(uor->ubuf8);
}
if (uor->pipe[0] != -1) {
close(uor->pipe[1]);
close(uor->pipe[0]);
}
free(uor);
#ifdef UWSGI_DEBUG
uwsgi_log("[offload] destroyed session %p\n", uor);
#endif
}
static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
+40 -20
View File
@@ -527,6 +527,11 @@ static int uwsgi_proto_check_22(struct wsgi_request *wsgi_req, char *key, char *
return 0;
}
if (!uwsgi_proto_key("HTTP_X_FORWARDED_PROTO", 22)) {
wsgi_req->scheme = buf;
wsgi_req->scheme_len = len;
}
return 0;
}
@@ -731,25 +736,40 @@ next:
}
for (i = 0; i < uwsgi_apps_cnt; i++) {
//uwsgi_log("app mountpoint = %.*s\n", uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint);
if (orig_path_info_len >= uwsgi_apps[i].mountpoint_len) {
if (!uwsgi_startswith(orig_path_info, uwsgi_apps[i].mountpoint, uwsgi_apps[i].mountpoint_len) && uwsgi_apps[i].mountpoint_len > best_found) {
best_found = uwsgi_apps[i].mountpoint_len;
wsgi_req->script_name = uwsgi_apps[i].mountpoint;
wsgi_req->script_name_len = uwsgi_apps[i].mountpoint_len;
wsgi_req->path_info = orig_path_info + wsgi_req->script_name_len;
wsgi_req->path_info_len = orig_path_info_len - wsgi_req->script_name_len;
char* mountpoint = uwsgi_apps[i].mountpoint;
int mountpoint_len = uwsgi_apps[i].mountpoint_len;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = wsgi_req->script_name;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = wsgi_req->script_name_len;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_base = wsgi_req->path_info;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_len = wsgi_req->path_info_len;
#ifdef UWSGI_DEBUG
uwsgi_log("managed SCRIPT_NAME = %.*s PATH_INFO = %.*s\n", wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->path_info_len, wsgi_req->path_info);
#endif
}
// Ignore trailing mountpoint slashes
if (mountpoint_len > 0 && mountpoint[mountpoint_len - 1] == '/') {
mountpoint_len -= 1;
}
//uwsgi_log("app mountpoint = %.*s\n", uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint);
// Check if mountpoint could be a possible candidate
if (orig_path_info_len < mountpoint_len || // it should be shorter than or equal to path_info
mountpoint_len <= best_found || // it should be better than the previous found
// should have the same prefix of path_info
uwsgi_startswith(orig_path_info, mountpoint, mountpoint_len) ||
// and should not be "misleading"
(orig_path_info_len > mountpoint_len && orig_path_info[mountpoint_len] != '/' )) {
continue;
}
best_found = mountpoint_len;
wsgi_req->script_name = uwsgi_apps[i].mountpoint;
wsgi_req->script_name_len = uwsgi_apps[i].mountpoint_len;
wsgi_req->path_info = orig_path_info + wsgi_req->script_name_len;
wsgi_req->path_info_len = orig_path_info_len - wsgi_req->script_name_len;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = wsgi_req->script_name;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = wsgi_req->script_name_len;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_base = wsgi_req->path_info;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_len = wsgi_req->path_info_len;
#ifdef UWSGI_DEBUG
uwsgi_log("managed SCRIPT_NAME = %.*s PATH_INFO = %.*s\n", wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->path_info_len, wsgi_req->path_info);
#endif
}
}
}
@@ -1051,7 +1071,7 @@ char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen
wsgi_req->var_cnt++;
ptr += keylen;
*ptr++ = (uint8_t) (vallen & 0xff);
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
@@ -1118,13 +1138,13 @@ int uwsgi_req_append_path_info_with_index(struct wsgi_request *wsgi_req, char *i
*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;
}
+1 -1
View File
@@ -123,7 +123,7 @@ static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
// allocate more memory if needed
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) {
memcpy(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
memmove(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos = 0;
// still something to use ?
+70
View File
@@ -756,6 +756,27 @@ static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) {
return 0;
}
// force content length
static int transform_forcecl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos);
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
wsgi_req->write_errors++;
return -1;
}
// do not check for errors !!!
uwsgi_response_add_header_force(wsgi_req, "Content-Length", 14, buf, ret);
return 0;
}
static int uwsgi_router_forcecl_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_add_transformation(wsgi_req, transform_forcecl, NULL);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_forcecl(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_forcecl_func;
return 0;
}
// log route
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -1194,6 +1215,27 @@ static int uwsgi_router_setpathinfo(struct uwsgi_route *ur, char *arg) {
return 0;
}
// fixpathinfo route
static int uwsgi_router_fixpathinfo_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
if (wsgi_req->script_name_len == 0)
return UWSGI_ROUTE_NEXT;
char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, wsgi_req->path_info+wsgi_req->script_name_len, wsgi_req->path_info_len - wsgi_req->script_name_len);
if (!ptr) {
return UWSGI_ROUTE_BREAK;
}
wsgi_req->path_info = wsgi_req->path_info+wsgi_req->script_name_len;
wsgi_req->path_info_len = wsgi_req->path_info_len - wsgi_req->script_name_len;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_fixpathinfo(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_fixpathinfo_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setscheme route
static int uwsgi_router_setscheme_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -1753,6 +1795,14 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
ret = uwsgi_num2str(uwsgi.shared->backlog);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "rsize", 5)) {
ret = uwsgi_64bit2str(wsgi_req->response_size);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "sor", 3)) {
ret = uwsgi_64bit2str(wsgi_req->start_of_request);
*vallen = strlen(ret);
}
return ret;
}
@@ -1789,6 +1839,10 @@ static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint
ret = uwsgi_num2str(uwsgi_now());
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "micros", 6)) {
ret = uwsgi_64bit2str(uwsgi_micros());
*vallen = strlen(ret);
}
return ret;
}
@@ -1846,6 +1900,7 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("seturi", uwsgi_router_seturi);
uwsgi_register_router("setremoteaddr", uwsgi_router_setremoteaddr);
uwsgi_register_router("setpathinfo", uwsgi_router_setpathinfo);
uwsgi_register_router("fixpathinfo", uwsgi_router_fixpathinfo);
uwsgi_register_router("setdocroot", uwsgi_router_setdocroot);
uwsgi_register_router("setscheme", uwsgi_router_setscheme);
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
@@ -1861,6 +1916,7 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("flush", uwsgi_router_flush);
uwsgi_register_router("fixcl", uwsgi_router_fixcl);
uwsgi_register_router("forcecl", uwsgi_router_forcecl);
uwsgi_register_router("harakiri", uwsgi_router_harakiri);
@@ -2041,5 +2097,19 @@ next4:
usl->custom2 = strlen(space+1);
uwsgi_log("collecting header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr);
}
uwsgi_foreach(usl, uwsgi.pull_headers) {
char *space = strchr(usl->value, ' ');
if (!space) {
uwsgi_log("invalid pull header syntax, must be <header> <var>\n");
exit(1);
}
*space = 0;
usl->custom = strlen(usl->value);
*space = ' ';
usl->custom_ptr = space+1;
usl->custom2 = strlen(space+1);
uwsgi_log("pulling header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr);
}
}
#endif
+2 -1
View File
@@ -193,12 +193,13 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
close(fd);
*len = rlen;
if (*len == 0) {
goto error;
goto error2;
}
return buffer;
error:
close(fd);
error2:
free(buffer);
return NULL;
+10 -1
View File
@@ -20,9 +20,18 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
return -1;
#elif defined(__linux__) || defined(__sun__) || defined(__GNU_kFreeBSD__)
#elif defined(__linux__) || defined(__GNU_kFreeBSD__)
off_t off = pos;
return sendfile(sockfd, filefd, &off, len);
#elif defined(__sun__)
off_t off = pos;
ssize_t wlen = sendfile(sockfd, filefd, &off, len);
if (wlen < 0 && uwsgi_is_again()) {
if (off - pos > 0) {
return off-pos;
}
}
return wlen;
#endif
no_sendfile:
+9 -9
View File
@@ -280,8 +280,8 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t of
}
uwsgi.sharedareas[id]->id = id;
uwsgi.sharedareas[id]->fd = fd;
uwsgi.sharedareas[id]->pages = len / uwsgi.page_size;
if (len % uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->pages = len / (size_t) uwsgi.page_size;
if (len % (size_t) uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->max_pos = len-1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
@@ -292,12 +292,12 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t of
struct uwsgi_sharedarea *uwsgi_sharedarea_init(int pages) {
int id = uwsgi_sharedarea_new_id();
uwsgi.sharedareas[id] = uwsgi_calloc_shared(uwsgi.page_size * (pages + 1));
uwsgi.sharedareas[id]->area = ((char *) uwsgi.sharedareas[id]) + uwsgi.page_size;
uwsgi.sharedareas[id] = uwsgi_calloc_shared((size_t)uwsgi.page_size * (size_t)(pages + 1));
uwsgi.sharedareas[id]->area = ((char *) uwsgi.sharedareas[id]) + (size_t) uwsgi.page_size;
uwsgi.sharedareas[id]->id = id;
uwsgi.sharedareas[id]->fd = -1;
uwsgi.sharedareas[id]->pages = pages;
uwsgi.sharedareas[id]->max_pos = (uwsgi.page_size * pages) -1;
uwsgi.sharedareas[id]->max_pos = ((size_t)uwsgi.page_size * (size_t)pages) -1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
free(id_str);
@@ -310,8 +310,8 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *area, uint64_t len) {
uwsgi.sharedareas[id]->area = area;
uwsgi.sharedareas[id]->id = id;
uwsgi.sharedareas[id]->fd = -1;
uwsgi.sharedareas[id]->pages = len / uwsgi.page_size;
if (len % uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->pages = len / (size_t) uwsgi.page_size;
if (len % (size_t) uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->max_pos = len-1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
@@ -348,8 +348,8 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
else {
len = uwsgi_n64(s_size);
}
pages = len / uwsgi.page_size;
if (len % uwsgi.page_size != 0) pages++;
pages = len / (size_t) uwsgi.page_size;
if (len % (size_t) uwsgi.page_size != 0) pages++;
}
if (s_offset) {
+10
View File
@@ -331,6 +331,16 @@ void uwsgi_route_signal(uint8_t sig) {
}
}
}
// send to al lactive workers
else if (!strcmp(use->receiver, "active-workers")) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0 && !uwsgi.workers[i].cheaped && !uwsgi.workers[i].suspended) {
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
}
}
}
// route to specific worker
else if (!strncmp(use->receiver, "worker", 6)) {
i = atoi(use->receiver + 6);
+22 -2
View File
@@ -189,7 +189,10 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
memset(uws_addr, 0, sizeof(struct sockaddr_un));
serverfd = create_server_socket(AF_UNIX, SOCK_STREAM);
if (serverfd < 0) return -1;
if (serverfd < 0) {
free(uws_addr);
return -1;
}
if (abstract_socket == 0) {
if (unlink(socket_name) != 0 && errno != ENOENT) {
uwsgi_error("error removing unix socket, unlink()");
@@ -563,6 +566,7 @@ char *generate_socket_name(char *socket_name) {
ifa = ifap;
while (ifa) {
memset(new_addr, 0, 16);
if (!ifa->ifa_addr) goto next;
sin = (struct sockaddr_in *) ifa->ifa_addr;
if (inet_ntop(AF_INET, (void *) &sin->sin_addr.s_addr, new_addr, 16)) {
if (!strncmp(socket_name, new_addr, strlen(socket_name))) {
@@ -575,6 +579,7 @@ char *generate_socket_name(char *socket_name) {
}
next:
ifaf = ifa;
ifa = ifaf->ifa_next;
@@ -705,6 +710,11 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (uwsgi.tcp_fast_open) {
#ifdef TCP_FASTOPEN
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
#endif
if (setsockopt(serverfd, SOL_TCP, TCP_FASTOPEN, (const void *) &uwsgi.tcp_fast_open, sizeof(int)) < 0) {
uwsgi_error("TCP_FASTOPEN setsockopt()");
}
@@ -1244,10 +1254,20 @@ void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) {
}
void uwsgi_close_all_sockets() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->bound)
close(uwsgi_sock->fd);
uwsgi_sock = uwsgi_sock->next;
}
}
void uwsgi_close_all_unshared_sockets() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->bound)
if (uwsgi_sock->bound && !uwsgi_sock->shared)
close(uwsgi_sock->fd);
uwsgi_sock = uwsgi_sock->next;
}
+7 -9
View File
@@ -200,11 +200,13 @@ static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, ui
}
}
/*
CHANGED in 2.0.7: wsgi_req is useless !
*/
char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) {
struct timeval tv;
static uint64_t internal_counter = 0;
int core_id = 0;
int fd = -1;
struct spooler_req sr;
@@ -232,10 +234,6 @@ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len,
}
}
if (wsgi_req) {
core_id = wsgi_req->async_id;
}
// this lock is for threads, the pid value in filename will avoid multiprocess races
uwsgi_lock(uspool->lock);
@@ -260,7 +258,7 @@ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len,
// no need to check for errors...
(void) mkdir(filename, 0777);
ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(),
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
if (ret <= 0 || ret >=(int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
@@ -272,8 +270,8 @@ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len,
else {
filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256;
filename = uwsgi_malloc(filename_len);
int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter,
rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
if (ret <= 0 || ret >= (int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
free(filename);
@@ -482,7 +480,7 @@ static void spooler_scandir(struct uwsgi_spooler *uspool, char *dir) {
if (!dir)
dir = uspool->dir;
n = scandir(dir, &tasklist, 0, versionsort);
n = scandir(dir, &tasklist, NULL, versionsort);
if (n < 0) {
uwsgi_error("scandir()");
return;
+21 -1
View File
@@ -30,7 +30,18 @@ void uwsgi_ssl_info_cb(SSL const *ssl, int where, int ret) {
}
int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
return 1;
if (!ok && uwsgi.ssl_verbose) {
char buf[256];
X509 *err_cert;
int depth;
int err;
depth = X509_STORE_CTX_get_error_depth(x509_store);
err_cert = X509_STORE_CTX_get_current_cert(x509_store);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
err = X509_STORE_CTX_get_error(x509_store);
uwsgi_log("[uwsgi-ssl] client certificate verify error: num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf);
}
return ok;
}
int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
@@ -210,6 +221,10 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
ssloptions |= SSL_OP_NO_COMPRESSION;
#endif
if (!uwsgi.sslv3) {
ssloptions |= SSL_OP_NO_SSLv3;
}
// release/reuse buffers as soon as possibile
#ifdef SSL_MODE_RELEASE_BUFFERS
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
@@ -396,6 +411,11 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.ssl_options) {
ssloptions |= atoi(usl->value);
}
SSL_CTX_set_options(ctx, ssloptions);
+12 -13
View File
@@ -463,23 +463,22 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
wsgi_req->do_not_account_avg_rt = 1;
size_t fsize = st->st_size;
if (wsgi_req->range_to) {
fsize = wsgi_req->range_to - wsgi_req->range_from;
if (fsize > (size_t)st->st_size) {
fsize = st->st_size;
}
// security check
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
wsgi_req->range_to = 0;
}
else {
// reset in case of inconsistent size
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
fsize = 0;
}
else {
fsize -= wsgi_req->range_from;
}
fsize -= wsgi_req->range_from;
}
if (wsgi_req->range_to) {
fsize = (wsgi_req->range_to - wsgi_req->range_from)+1;
if (fsize + wsgi_req->range_from > (size_t) (st->st_size)) {
fsize = st->st_size - wsgi_req->range_from;
}
}
// HTTP status
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
+10
View File
@@ -679,6 +679,10 @@ static struct uwsgi_buffer *uwsgi_subscription_ub(char *key, size_t keysize, uin
goto end;
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name)))
goto end;
if (uwsgi.subscribe_with_modifier1) {
modifier1 = atoi(uwsgi.subscribe_with_modifier1);
}
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1))
goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2))
@@ -1072,6 +1076,12 @@ end:
free(s2_sign);
if (s2_check)
free(s2_check);
if (s2_sni_crt)
free(s2_sni_crt);
if (s2_sni_key)
free(s2_sni_key);
if (s2_sni_ca)
free(s2_sni_ca);
}
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
+109 -4
View File
@@ -699,6 +699,22 @@ void uwsgi_as_root() {
}
}
uwsgi_foreach(usl, uwsgi.wait_for_fs) {
if (uwsgi_wait_for_fs(usl->value, 0)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_file) {
if (uwsgi_wait_for_fs(usl->value, 1)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_dir) {
if (uwsgi_wait_for_fs(usl->value, 2)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_mountpoint) {
if (uwsgi_wait_for_mountpoint(usl->value)) exit(1);
}
uwsgi_hooks_run(uwsgi.hook_as_root, "as root", 1);
uwsgi_foreach(usl, uwsgi.mount_as_root) {
@@ -1019,8 +1035,14 @@ void uwsgi_destroy_request(struct wsgi_request *wsgi_req) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
}
memset(wsgi_req, 0, sizeof(struct wsgi_request));
// reset for avoiding following requests to fail on non-uwsgi protocols
// thanks Marko Tiikkaja for catching it
wsgi_req->uh->pktsize = 0;
// some plugins expected async_id to be defined before setup
int tmp_id = wsgi_req->async_id;
memset(wsgi_req, 0, sizeof(struct wsgi_request));
wsgi_req->async_id = tmp_id;
}
// finalize/close/free a request
@@ -1166,8 +1188,8 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
wsgi_req->uh->pktsize = 0;
tmp_id = wsgi_req->async_id;
memset(wsgi_req, 0, sizeof(struct wsgi_request));
// some plugins expected async_id to be defined before setup
wsgi_req->async_id = tmp_id;
// yes, this is pretty useless but we cannot ensure all of the plugin have the same behaviour
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
@@ -3393,7 +3415,7 @@ struct uwsgi_app *uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int
}
if (!uwsgi.no_default_app) {
if ((mountpoint_len == 0 || (mountpoint_len = -1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
if ((mountpoint_len == 0 || (mountpoint_len == 1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
uwsgi.default_app = id;
}
}
@@ -3492,7 +3514,7 @@ int uwsgi_tmpfd() {
tmpdir = "/tmp";
}
#ifdef O_TMPFILE
fd = open(tmpdir, O_TMPFILE | O_RDWR);
fd = open(tmpdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
if (fd >= 0) {
return fd;
}
@@ -4424,6 +4446,7 @@ void uwsgi_setns(char *path) {
}
}
free(fds);
close(ns_fd);
break;
}
if (fds)
@@ -4457,3 +4480,85 @@ mode_t uwsgi_mode_t(char *value, int *error) {
return mode;
}
int uwsgi_wait_for_mountpoint(char *mountpoint) {
if (!uwsgi.wait_for_fs_timeout) {
uwsgi.wait_for_fs_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", mountpoint, uwsgi.wait_for_fs_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_fs_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", mountpoint, counter);
return -1;
}
struct stat st0;
struct stat st1;
if (stat(mountpoint, &st0)) goto retry;
if (!S_ISDIR(st0.st_mode)) goto retry;
char *relative = uwsgi_concat2(mountpoint, "/../");
if (stat(relative, &st1)) {
free(relative);
goto retry;
}
free(relative);
// useless :P
if (!S_ISDIR(st1.st_mode)) goto retry;
if (st0.st_dev == st1.st_dev) goto retry;
uwsgi_log_verbose("%s mounted\n", mountpoint);
return 0;
retry:
sleep(1);
counter++;
}
return -1;
}
// type -> 1 file, 2 dir, 0 both
int uwsgi_wait_for_fs(char *filename, int type) {
if (!uwsgi.wait_for_fs_timeout) {
uwsgi.wait_for_fs_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", filename, uwsgi.wait_for_fs_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_fs_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", filename, counter);
return -1;
}
struct stat st;
if (stat(filename, &st)) goto retry;
if (type == 1 && !S_ISREG(st.st_mode)) goto retry;
if (type == 2 && !S_ISDIR(st.st_mode)) goto retry;
uwsgi_log_verbose("%s found\n", filename);
return 0;
retry:
sleep(1);
counter++;
}
return -1;
}
int uwsgi_wait_for_socket(char *socket_name) {
if (!uwsgi.wait_for_socket_timeout) {
uwsgi.wait_for_socket_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", socket_name, uwsgi.wait_for_socket_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_socket_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", socket_name, counter);
return -1;
}
// wait for 1 second to respect uwsgi.wait_for_fs_timeout
int fd = uwsgi_connect(socket_name, 1, 0);
if (fd < 0) goto retry;
close(fd);
uwsgi_log_verbose("%s ready\n", socket_name);
return 0;
retry:
sleep(1);
counter++;
}
return -1;
}
+121 -28
View File
@@ -2,7 +2,7 @@
*** uWSGI ***
Copyright (C) 2009-2014 Unbit S.a.s. <info@unbit.it>
Copyright (C) 2009-2015 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -39,8 +39,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"socket", required_argument, 's', "bind to the specified UNIX/TCP socket using default protocol", uwsgi_opt_add_socket, NULL, 0},
{"uwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol", uwsgi_opt_add_socket, "uwsgi", 0},
#ifdef UWSGI_SSL
{"suwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
{"ssl-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
{"suwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
{"ssl-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
#endif
{"http-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP protocol", uwsgi_opt_add_socket, "http", 0},
@@ -71,8 +71,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
{"socket-protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
{"shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
{"undeferred-shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0},
{"shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
{"undeferred-shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0},
{"processes", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
{"workers", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
{"thunder-lock", no_argument, 0, "serialize accept() usage (if possible)", uwsgi_opt_true, &uwsgi.use_thunder_lock, 0},
@@ -120,6 +120,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"if-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_reload, UWSGI_OPT_IMMEDIATE},
{"if-not-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_reload, UWSGI_OPT_IMMEDIATE},
{"if-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_hostname, UWSGI_OPT_IMMEDIATE},
{"if-not-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_hostname, UWSGI_OPT_IMMEDIATE},
{"if-exists", required_argument, 0, "(opt logic) check for file/directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE},
{"if-not-exists", required_argument, 0, "(opt logic) check for file/directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_exists, UWSGI_OPT_IMMEDIATE},
{"ifexists", required_argument, 0, "(opt logic) check for file/directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE},
@@ -199,6 +202,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor", required_argument, 0, "run the Emperor", uwsgi_opt_add_string_list, &uwsgi.emperor, 0},
{"emperor-proxy-socket", required_argument, 0, "force the vassal to became an Emperor proxy", uwsgi_opt_set_str, &uwsgi.emperor_proxy, 0},
{"emperor-wrapper", required_argument, 0, "set a binary wrapper for vassals", uwsgi_opt_set_str, &uwsgi.emperor_wrapper, 0},
{"emperor-wrapper-override", required_argument, 0, "set a binary wrapper for vassals to try before the default one", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_override, 0},
{"emperor-wrapper-fallback", required_argument, 0, "set a binary wrapper for vassals to try as a last resort", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_fallback, 0},
{"emperor-nofollow", no_argument, 0, "do not follow symlinks when checking for mtime", uwsgi_opt_true, &uwsgi.emperor_nofollow, 0},
{"emperor-procname", required_argument, 0, "set the Emperor process name", uwsgi_opt_set_str, &uwsgi.emperor_procname, 0},
{"emperor-freq", required_argument, 0, "set the Emperor scan frequency (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.emperor_freq, 0},
@@ -238,6 +243,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"vassals-include-before", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes_before, 0},
{"vassals-start-hook", required_argument, 0, "run the specified command before each vassal starts", uwsgi_opt_set_str, &uwsgi.vassals_start_hook, 0},
{"vassals-stop-hook", required_argument, 0, "run the specified command after vassal's death", uwsgi_opt_set_str, &uwsgi.vassals_stop_hook, 0},
{"vassal-sos", required_argument, 0, "ask emperor for reinforcement when overloaded", uwsgi_opt_set_int, &uwsgi.vassal_sos, 0},
{"vassal-sos-backlog", required_argument, 0, "ask emperor for sos if backlog queue has more items than the value specified", uwsgi_opt_set_int, &uwsgi.vassal_sos_backlog, 0},
{"vassals-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
{"vassal-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
@@ -389,6 +395,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"hook-as-user-atexit", required_argument, 0, "run the specified hook before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.hook_as_user_atexit, 0},
{"hook-pre-app", required_argument, 0, "run the specified hook before app loading", uwsgi_opt_add_string_list, &uwsgi.hook_pre_app, 0},
{"hook-post-app", required_argument, 0, "run the specified hook after app loading", uwsgi_opt_add_string_list, &uwsgi.hook_post_app, 0},
{"hook-post-fork", required_argument, 0, "run the specified hook after each fork", uwsgi_opt_add_string_list, &uwsgi.hook_post_fork, 0},
{"hook-accepting", required_argument, 0, "run the specified hook after each worker enter the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting, 0},
{"hook-accepting1", required_argument, 0, "run the specified hook after the first worker enters the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1, 0},
{"hook-accepting-once", required_argument, 0, "run the specified hook after each worker enter the accepting phase (once per-instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting_once, 0},
@@ -456,6 +463,15 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"wait-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
{"wait-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
{"wait-for-fs", required_argument, 0, "wait for the specified filesystem item to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-file", required_argument, 0, "wait for the specified file to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-dir", required_argument, 0, "wait for the specified directory to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-mountpoint", required_argument, 0, "wait for the specified mountpoint to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_mountpoint, 0},
{"wait-for-fs-timeout", required_argument, 0, "set the timeout for wait-for-fs/file/dir", uwsgi_opt_set_int, &uwsgi.wait_for_fs_timeout, 0},
{"wait-for-socket", required_argument, 0, "wait for the specified socket to be ready before loading apps", uwsgi_opt_add_string_list, &uwsgi.wait_for_socket, 0},
{"wait-for-socket-timeout", required_argument, 0, "set the timeout for wait-for-socket", uwsgi_opt_set_int, &uwsgi.wait_for_socket_timeout, 0},
{"call-asap", required_argument, 0, "call the specified function as soon as possible", uwsgi_opt_add_string_list, &uwsgi.call_asap, 0},
{"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0},
{"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0},
@@ -505,6 +521,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"reload-on-rss", required_argument, 0, "reload if rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_rss, UWSGI_OPT_MEMORY},
{"evil-reload-on-as", required_argument, 0, "force the master to reload a worker if its address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_as, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY},
{"evil-reload-on-rss", required_argument, 0, "force the master to reload a worker if its rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_rss, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY},
{"mem-collector-freq", required_argument, 0, "set the memory collector frequency when evil reloads are in place", uwsgi_opt_set_int, &uwsgi.mem_collector_freq, 0},
{"reload-on-fd", required_argument, 0, "reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.reload_on_fd, UWSGI_OPT_MASTER},
{"brutal-reload-on-fd", required_argument, 0, "brutal reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.brutal_reload_on_fd, UWSGI_OPT_MASTER},
@@ -621,6 +638,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"subscription-tolerance", required_argument, 0, "set tolerance for subscription servers", uwsgi_opt_set_int, &uwsgi.subscription_tolerance, 0},
{"unsubscribe-on-graceful-reload", no_argument, 0, "force unsubscribe request even during graceful reload", uwsgi_opt_true, &uwsgi.unsubscribe_on_graceful_reload, 0},
{"start-unsubscribed", no_argument, 0, "configure subscriptions but do not send them (useful with master fifo)", uwsgi_opt_true, &uwsgi.subscriptions_blocked, 0},
{"subscribe-with-modifier1", required_argument, 0, "force the specififed modifier1 when subscribing", uwsgi_opt_set_str, &uwsgi.subscribe_with_modifier1, UWSGI_OPT_MASTER},
{"snmp", optional_argument, 0, "enable the embedded snmp server", uwsgi_opt_snmp, NULL, 0},
{"snmp-community", required_argument, 0, "set the snmp community string", uwsgi_opt_snmp_community, NULL, 0},
#ifdef UWSGI_SSL
@@ -633,6 +653,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"sni", required_argument, 0, "add an SNI-governed SSL context", uwsgi_opt_sni, NULL, 0},
{"sni-dir", required_argument, 0, "check for cert/key/client_ca file in the specified directory and create a sni/ssl context on demand", uwsgi_opt_set_str, &uwsgi.sni_dir, 0},
{"sni-dir-ciphers", required_argument, 0, "set ssl ciphers for sni-dir option", uwsgi_opt_set_str, &uwsgi.sni_dir_ciphers, 0},
{"ssl-enable3", no_argument, 0, "enable SSLv3 (insecure)", uwsgi_opt_true, &uwsgi.sslv3, 0},
{"ssl-option", no_argument, 0, "set a raw ssl option (numeric value)", uwsgi_opt_add_string_list, &uwsgi.ssl_options, 0},
#ifdef UWSGI_PCRE
{"sni-regexp", required_argument, 0, "add an SNI-governed SSL context (the key is a regexp)", uwsgi_opt_sni, NULL, 0},
#endif
@@ -680,7 +702,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
{"alarm-cheap", required_argument, 0, "use main alarm thread rather than create dedicated threads for curl-based alarms", uwsgi_opt_true, &uwsgi.alarm_cheap, 0},
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"alarm-freq", required_argument, 0, "tune the anti-loop alarm system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
{"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
@@ -699,13 +721,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"alarm-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
{"alarms-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
{"alarm-msg-size", required_argument, 0, "set the max size of an alarm message (default 8192)", uwsgi_opt_set_64bit, &uwsgi.alarm_msg_size, 0},
{"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER},
{"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER},
{"log-master-bufsize", required_argument, 0, "set the buffer size for the master logger. bigger log messages will be truncated", uwsgi_opt_set_64bit, &uwsgi.log_master_bufsize, 0},
{"log-master-stream", no_argument, 0, "create the master logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_stream, 0},
{"log-master-req-stream", no_argument, 0, "create the master requests logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_req_stream, 0},
{"log-reopen", no_argument, 0, "reopen log after reload", uwsgi_opt_true, &uwsgi.log_reopen, 0},
{"log-truncate", no_argument, 0, "truncate log on startup", uwsgi_opt_true, &uwsgi.log_truncate, 0},
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_LOG_MASTER},
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER},
{"log-backupname", required_argument, 0, "set logfile name after rotation", uwsgi_opt_set_str, &uwsgi.log_backupname, 0},
{"logdate", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
@@ -846,6 +868,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"collect-header", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
{"response-header-collect", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
{"pull-header", required_argument, 0, "store the specified response header in a request var and remove it from the response (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.pull_headers, 0},
{"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
{"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME},
{"static-check", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
@@ -1156,7 +1180,7 @@ void wait_for_threads() {
int sudden_death = 0;
pthread_mutex_lock(&uwsgi.six_feet_under_lock);
for (i = 0; i < uwsgi.threads; i++) {
for (i = 1; i < uwsgi.threads; i++) {
if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) {
if (pthread_cancel(uwsgi.workers[uwsgi.mywid].cores[i].thread_id)) {
uwsgi_error("pthread_cancel()\n");
@@ -1169,7 +1193,7 @@ void wait_for_threads() {
goto end;
// wait for thread termination
for (i = 0; i < uwsgi.threads; i++) {
for (i = 1; i < uwsgi.threads; i++) {
if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) {
ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, NULL);
if (ret) {
@@ -1178,6 +1202,22 @@ void wait_for_threads() {
}
}
// cancel inital thread last since after pthread_cancel() and
// pthread_join() is called on it, the whole process will appear to be
// a zombie. although it won't eliminate process zombie time, but it
// should minimize it.
if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[0].thread_id, pthread_self())) {
if (pthread_cancel(uwsgi.workers[uwsgi.mywid].cores[0].thread_id)) {
uwsgi_error("pthread_cancel() on initial thread\n");
goto end;
}
ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[0].thread_id, NULL);
if (ret) {
uwsgi_log("pthread_join() = %d on initial thread\n", ret);
}
}
end:
pthread_mutex_unlock(&uwsgi.six_feet_under_lock);
@@ -1530,8 +1570,10 @@ static void vacuum(void) {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
if (uwsgi.restore_tc) {
if (tcsetattr(0, TCSANOW, &uwsgi.termios)) {
uwsgi_error("tcsetattr()");
if (getpid() == masterpid) {
if (tcsetattr(0, TCSANOW, &uwsgi.termios)) {
uwsgi_error("vacuum()/tcsetattr()");
}
}
}
@@ -1580,6 +1622,17 @@ static void vacuum(void) {
next:
uwsgi_sock = uwsgi_sock->next;
}
if (uwsgi.stats) {
// is a unix socket ?
if (!strchr(uwsgi.stats, ':') && uwsgi.stats[0] != '@') {
if (unlink(uwsgi.stats)) {
uwsgi_error("unlink()");
}
else {
uwsgi_log("VACUUM: unix socket %s (stats) removed.\n", uwsgi.stats);
}
}
}
}
}
}
@@ -2231,7 +2284,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
// setup master logging
if (uwsgi.log_master && !uwsgi.daemonize2 && uwsgi.logfile)
if (uwsgi.log_master && !uwsgi.daemonize2)
uwsgi_setup_log_master();
// setup offload engines
@@ -2511,17 +2564,19 @@ int uwsgi_start(void *v_argv) {
uwsgi_as_root();
}
// wait for socket
uwsgi_foreach(usl, uwsgi.wait_for_socket) {
if (uwsgi_wait_for_socket(usl->value)) exit(1);
}
if (uwsgi.logto2) {
if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
int setup_log = 0;
if (!uwsgi.logfile) setup_log = 1; // logto() will replace uwsgi.logfile and we need to check it later
logto(uwsgi.logto2);
if (setup_log)
uwsgi_setup_log_master();
}
}
if (uwsgi.chdir) {
uwsgi_log("chdir() to %s\n", uwsgi.chdir);
if (chdir(uwsgi.chdir)) {
uwsgi_error("chdir()");
exit(1);
@@ -3182,6 +3237,24 @@ next2:
}
// this lives in a worker thread and periodically scans for memory usage
// when evil reloaders are in place
void *mem_collector(void *foobar) {
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
uwsgi_log_verbose("mem-collector thread started for worker %d\n", uwsgi.mywid);
for(;;) {
sleep(uwsgi.mem_collector_freq);
uint64_t rss, vsz;
get_memusage(&rss, &vsz);
uwsgi.workers[uwsgi.mywid].rss_size = rss;
uwsgi.workers[uwsgi.mywid].vsz_size = vsz;
}
return NULL;
}
int uwsgi_run() {
// !!! from now on, we could be in the master or in a worker !!!
@@ -3208,6 +3281,11 @@ int uwsgi_run() {
}
#endif
if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) {
pthread_t t;
pthread_create(&t, NULL, mem_collector, NULL);
}
// eventually maps (or disable) sockets for the worker
uwsgi_map_sockets();
@@ -3270,6 +3348,8 @@ int uwsgi_run() {
}
}
uwsgi_hooks_run(uwsgi.hook_post_fork, "post-fork", 1);
if (uwsgi.worker_exec2) {
char *w_argv[2];
w_argv[0] = uwsgi.worker_exec2;
@@ -3346,6 +3426,7 @@ void uwsgi_worker_run() {
}
if (uwsgi.chdir2) {
uwsgi_log("chdir() to %s\n", uwsgi.chdir2);
if (chdir(uwsgi.chdir2)) {
uwsgi_error("chdir()");
exit(1);
@@ -3419,7 +3500,10 @@ void uwsgi_ignition() {
if (uwsgi.has_emperor && uwsgi.mywid == 1) {
char byte = 5;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
uwsgi_error("emperor-i-am-ready-to-accept/write()");
uwsgi_log_verbose("lost communication with the Emperor, goodbye...\n");
gracefully_kill_them_all(0);
exit(1);
}
}
@@ -3787,7 +3871,8 @@ void uwsgi_opt_false(char *opt, char *value, void *key) {
}
void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
gid_t gid = atoi(value);
gid_t gid = 0;
if (is_a_number(value)) gid = atoi(value);
if (gid == 0) {
struct group *ugroup = getgrnam(value);
if (ugroup)
@@ -3816,7 +3901,8 @@ void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) {
uid_t uid = atoi(value);
uid_t uid = 0;
if (is_a_number(value)) uid = atoi(value);
if (uid == 0) {
struct passwd *upasswd = getpwnam(value);
if (upasswd)
@@ -3863,7 +3949,8 @@ void uwsgi_opt_set_int(char *opt, char *value, void *key) {
}
void uwsgi_opt_uid(char *opt, char *value, void *key) {
uid_t uid = atoi(value);
uid_t uid = 0;
if (is_a_number(value)) uid = atoi(value);
if (!uid) {
struct passwd *p = getpwnam(value);
if (p) {
@@ -3881,7 +3968,8 @@ void uwsgi_opt_uid(char *opt, char *value, void *key) {
}
void uwsgi_opt_gid(char *opt, char *value, void *key) {
gid_t gid = atoi(value);
gid_t gid = 0;
if (is_a_number(value)) gid = atoi(value);
if (!gid) {
struct group *g = getgrnam(value);
if (g) {
@@ -4182,15 +4270,13 @@ void uwsgi_opt_print(char *opt, char *value, void *str) {
}
void uwsgi_opt_set_uid(char *opt, char *value, void *none) {
uwsgi.uid = atoi(value);
if (is_a_number(value)) uwsgi.uid = atoi(value);
if (!uwsgi.uid)
uwsgi.uidname = value;
}
void uwsgi_opt_set_gid(char *opt, char *value, void *none) {
uwsgi.gid = atoi(value);
if (is_a_number(value)) uwsgi.gid = atoi(value);
if (!uwsgi.gid)
uwsgi.gidname = value;
}
@@ -4377,6 +4463,7 @@ int uwsgi_zerg_attach(char *value) {
if (zerg == NULL) {
uwsgi_log("--- invalid data received from zerg-server ---\n");
close(zerg_fd);
return -1;
}
@@ -4672,7 +4759,7 @@ extern char *uwsgi_dot_h;
char *uwsgi_get_dot_h() {
char *src = uwsgi_dot_h;
size_t len = strlen(src);
char *ptr = uwsgi_malloc(len / 2);
char *ptr = uwsgi_malloc((len / 2) + 1);
char *base = ptr;
size_t i;
unsigned int u;
@@ -4693,6 +4780,9 @@ char *uwsgi_get_dot_h() {
base = ub->buf;
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
#else
// add final null byte
*ptr = '\0';
#endif
return base;
}
@@ -4705,7 +4795,7 @@ extern char *uwsgi_config_py;
char *uwsgi_get_config_py() {
char *src = uwsgi_config_py;
size_t len = strlen(src);
char *ptr = uwsgi_malloc(len / 2);
char *ptr = uwsgi_malloc((len / 2) + 1);
char *base = ptr;
size_t i;
unsigned int u;
@@ -4726,6 +4816,9 @@ char *uwsgi_get_config_py() {
base = ub->buf;
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
#else
// add final null byte
*ptr = '\0';
#endif
return base;
}
+1
View File
@@ -273,6 +273,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
}
else {
wsgi_req->websocket_need += wsgi_req->websocket_size;
wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
wsgi_req->websocket_phase = 4;
}
break;
+10 -1
View File
@@ -124,9 +124,18 @@ error:
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
// collect the header ?
// pull/collect the header ?
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.pull_headers) {
if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
wsgi_req->write_errors++ ; return -1;
}
return 0;
}
}
uwsgi_foreach(usl, uwsgi.collect_headers) {
if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
+12 -3
View File
@@ -312,8 +312,6 @@ static void asyncio_loop() {
uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook;
uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook;
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
if (uwsgi.async < 2) {
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
exit(1);
@@ -323,9 +321,20 @@ static void asyncio_loop() {
uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n");
}
if (!uwsgi.schedule_to_req) {
uwsgi.schedule_to_req = async_schedule_to_req_green;
}
else {
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
}
#ifndef PYTHREE
PyObject *asyncio = PyImport_ImportModule("trollius");
#else
PyObject *asyncio = PyImport_ImportModule("asyncio");
#endif
if (!asyncio) uwsgi_pyexit;
uasyncio.mod = asyncio;
uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL);
+5 -2
View File
@@ -71,7 +71,9 @@ static void carbon_post_init() {
u_server->errors = 0;
char *p, *ctx = NULL;
uwsgi_foreach_token(usl->value, ":", p, ctx) {
// make a copy to not clobber argv
char *tmp = uwsgi_str(usl->value);
uwsgi_foreach_token(tmp, ":", p, ctx) {
if (!u_server->hostname) {
u_server->hostname = uwsgi_str(p);
}
@@ -81,6 +83,7 @@ static void carbon_post_init() {
else
break;
}
free(tmp);
if (!u_server->hostname || !u_server->port) {
uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value);
usl = usl->next;
@@ -196,7 +199,7 @@ static int carbon_push_stats(int retry_cycle, time_t now) {
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];
u_carbon.last_busyness_values[i] = uwsgi.workers[i+1].running_time;
u_carbon.was_busy[i-1] += uwsgi_worker_is_busy(i+1);
u_carbon.was_busy[i] += uwsgi_worker_is_busy(i+1);
}
needs_retry = 0;
+1 -1
View File
@@ -533,9 +533,9 @@ static int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
memcpy(full_path, tmp_path, full_path_len+1);
if (uwsgi_starts_with(full_path, full_path_len, docroot, docroot_len)) {
uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot);
if (need_free)
free(docroot);
uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot);
return -1;
}
+17 -5
View File
@@ -75,6 +75,12 @@ void uwsgi_cr_peer_reset(struct corerouter_peer *peer) {
peer->hook_write = NULL;
}
if (peer->is_buffering) {
if (peer->buffering_fd != -1) {
close(peer->buffering_fd);
}
}
peer->failed = 0;
peer->soopt = 0;
peer->timed_out = 0;
@@ -84,7 +90,13 @@ void uwsgi_cr_peer_reset(struct corerouter_peer *peer) {
}
// destroy a peer
void uwsgi_cr_peer_del(struct corerouter_peer *peer) {
int uwsgi_cr_peer_del(struct corerouter_peer *peer) {
// first of all check if we need to run a flush procedure
if (peer->flush && !peer->is_flushing) {
peer->is_flushing = 1;
// on success, suspend the execution
if (peer->flush(peer) > 0) return -1;
}
struct corerouter_peer *prev = peer->prev;
struct corerouter_peer *next = peer->next;
@@ -111,6 +123,7 @@ void uwsgi_cr_peer_del(struct corerouter_peer *peer) {
uwsgi_buffer_destroy(peer->out);
}
free(peer);
return 0;
}
void uwsgi_opt_corerouter(char *opt, char *value, void *cr) {
@@ -310,7 +323,6 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
}
if (peer->failed) {
if (peer->soopt) {
if (!ucr->quiet)
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt));
@@ -384,7 +396,7 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
}
end:
uwsgi_cr_peer_del(peer);
if (uwsgi_cr_peer_del(peer) < 0) return;
if (peer == cs->main_peer) {
cs->main_peer = NULL;
@@ -402,7 +414,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
struct corerouter_peer *main_peer = cr_session->main_peer;
if (main_peer) {
uwsgi_cr_peer_del(main_peer);
if (uwsgi_cr_peer_del(main_peer) < 0) return;
}
// free peers
@@ -414,7 +426,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
if (ucr->subscriptions && tmp_peer->un && tmp_peer->un->len) {
tmp_peer->un->reference--;
}
uwsgi_cr_peer_del(tmp_peer);
if (uwsgi_cr_peer_del(tmp_peer) < 0) return;
}
// could be used to free additional resources
+9 -3
View File
@@ -180,8 +180,8 @@ struct corerouter_peer {
uint16_t retries;
// parsed key
char *key;
uint16_t key_len;
char key[0xff];
uint8_t key_len;
uint8_t modifier1;
uint8_t modifier2;
@@ -190,6 +190,12 @@ struct corerouter_peer {
struct corerouter_peer *next;
int current_timeout;
ssize_t (*flush)(struct corerouter_peer *);
int is_flushing;
int is_buffering;
int buffering_fd;
};
struct uwsgi_corerouter {
@@ -271,7 +277,7 @@ struct uwsgi_corerouter {
char *resubscribe_bind;
size_t buffer_size;
int fallback_on_no_key;
};
// a session is started when a client connect to the router
+2
View File
@@ -53,6 +53,7 @@ int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct coreroute
peer->instance_address = peer->un->name;
peer->instance_address_len = peer->un->len;
peer->modifier1 = peer->un->modifier1;
peer->modifier2 = peer->un->modifier2;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);
@@ -88,6 +89,7 @@ split:
peer->instance_address = peer->un->name;
peer->instance_address_len = peer->un->len;
peer->modifier1 = peer->un->modifier1;
peer->modifier2 = peer->un->modifier2;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);
+17 -26
View File
@@ -2,13 +2,6 @@
#define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01"
#ifdef __BIG_ENDIAN__
#define ntohll(x) x
#else
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
#endif
#define htonll(x) ntohll(x)
#define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; }
struct amqp_frame_header {
@@ -69,13 +62,8 @@ static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) {
static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) {
uint64_t tmp_longlong;
if (ptr+8 > watermark) return NULL;
memcpy(&tmp_longlong, ptr, 8);
*llv = ntohll(tmp_longlong);
*llv = uwsgi_be64(ptr);
return ptr+8;
}
@@ -85,26 +73,29 @@ static int amqp_send_ack(int fd, uint64_t delivery_tag) {
uint32_t size = 4 + 8 + 1;
size = htonl(size);
struct uwsgi_buffer *ub = uwsgi_buffer_new(64);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
if (uwsgi_buffer_append(ub, "\1\0\1", 3)) goto end;
// send size
amqp_send(fd, &size, 4);
// send class 60 method 80
amqp_send(fd, "\x00\x3C\x00\x50", 4);
if (uwsgi_buffer_u32be(ub, size)) goto end;
// send class 60 method 80
if (uwsgi_buffer_append(ub, "\x00\x3C\x00\x50", 4)) goto end;
// set delivery_tag
delivery_tag = htonll(delivery_tag);
amqp_send(fd, &delivery_tag, 8);
if (uwsgi_buffer_u64be(ub, delivery_tag)) goto end;
if (uwsgi_buffer_append(ub, "\0\xCE", 2)) goto end;
// empty bits
amqp_send(fd, "\0", 1);
// send buffer to socket
if (write(fd, ub->buf, ub->pos) < 0) {
uwsgi_error("amqp_send_ack()/write()");
goto end;
}
// send frame-end
amqp_send(fd, "\xCE", 1);
uwsgi_buffer_destroy(ub);
return 0;
end:
uwsgi_buffer_destroy(ub);
return -1;
}
char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) {
+1 -1
View File
@@ -2,6 +2,6 @@
NAME='emperor_zeromq'
CFLAGS = []
LDFLAGS = []
LIBS = []
LIBS = ['-lzmq']
GCC_LIST = ['emperor_zeromq']
+127 -16
View File
@@ -16,6 +16,8 @@ extern struct uwsgi_server uwsgi;
struct fastrouter_session {
struct corerouter_session session;
int has_key;
uint64_t content_length;
uint64_t buffered;
};
static struct uwsgi_option fastrouter_options[] = {
@@ -42,7 +44,7 @@ static struct uwsgi_option fastrouter_options[] = {
{"fastrouter-timeout", required_argument, 0, "set fastrouter timeout", uwsgi_opt_set_int, &ufr.cr.socket_timeout, 0},
{"fastrouter-post-buffering", required_argument, 0, "enable fastrouter post buffering", uwsgi_opt_set_64bit, &ufr.cr.post_buffering, 0},
{"fastrouter-post-buffering-dir", required_argument, 0, "put fastrouter buffered files to the specified directory", uwsgi_opt_set_str, &ufr.cr.pb_base_dir, 0},
{"fastrouter-post-buffering-dir", required_argument, 0, "put fastrouter buffered files to the specified directory (noop, use TMPDIR env)", uwsgi_opt_set_str, &ufr.cr.pb_base_dir, 0},
{"fastrouter-stats", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"fastrouter-stats-server", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
@@ -55,6 +57,7 @@ static struct uwsgi_option fastrouter_options[] = {
{"fastrouter-resubscribe-bind", required_argument, 0, "bind to the specified address when re-subscribing", uwsgi_opt_set_str, &ufr.cr.resubscribe_bind, 0},
{"fastrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &ufr.cr.buffer_size, 0},
{"fastrouter-fallback-on-no-key", no_argument, 0, "move to fallback node even if a subscription key is not found", uwsgi_opt_true, &ufr.cr.fallback_on_no_key, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -65,21 +68,27 @@ static void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vall
//uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
if (!uwsgi_strncmp("SERVER_NAME", 11, key, keylen) && !peer->key_len) {
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
return;
}
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !fr->has_key) {
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
return;
}
if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) {
fr->has_key = 1;
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
fr->has_key = 1;
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
return;
}
@@ -96,6 +105,12 @@ static void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vall
}
return;
}
if (ufr.cr.post_buffering > 0) {
if (!uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) {
fr->content_length = uwsgi_str_num(val, vallen);
}
}
}
// writing client body to the instance
@@ -156,6 +171,23 @@ static ssize_t fr_instance_read(struct corerouter_peer *peer) {
return len;
}
static ssize_t fr_instance_sendfile(struct corerouter_peer *peer) {
struct fastrouter_session *fr = (struct fastrouter_session *) peer->session;
ssize_t len = uwsgi_sendfile_do(peer->fd, peer->session->main_peer->buffering_fd, fr->buffered, fr->content_length - fr->buffered);
if (len < 0) {
cr_try_again;
uwsgi_cr_error(peer, "fr_instance_sendfile()/sendfile()");
return -1;
}
if (len == 0) return 0;
fr->buffered += len;
if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len;
if (fr->buffered >= fr->content_length) {
cr_reset_hooks(peer);
}
return len;
}
// send the uwsgi request header and vars
static ssize_t fr_instance_send_request(struct corerouter_peer *peer) {
ssize_t len = cr_write(peer, "fr_instance_send_request()");
@@ -166,9 +198,16 @@ static ssize_t fr_instance_send_request(struct corerouter_peer *peer) {
if (cr_write_complete(peer)) {
// reset the original read buffer
peer->out->pos = 0;
// start waiting for body
peer->session->main_peer->last_hook_read = fr_read_body;
cr_reset_hooks(peer);
if (!peer->session->main_peer->is_buffering) {
// start waiting for body
peer->session->main_peer->last_hook_read = fr_read_body;
cr_reset_hooks(peer);
}
else {
peer->hook_write = fr_instance_sendfile;
// stop reading from the client
peer->session->main_peer->last_hook_read = NULL;
}
}
return len;
@@ -183,8 +222,8 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
peer->can_retry = 0;
// fix modifiers
peer->in->buf[0] = peer->session->main_peer->modifier1;
peer->in->buf[3] = peer->session->main_peer->modifier2;
peer->session->main_peer->in->buf[0] = peer->modifier1;
peer->session->main_peer->in->buf[3] = peer->modifier2;
// prepare to write the uwsgi packet
peer->out = peer->session->main_peer->in;
@@ -196,20 +235,73 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
// called after receaving the uwsgi header (read vars)
static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
struct fastrouter_session *fr = (struct fastrouter_session *) main_peer->session;
struct corerouter_peer *new_peer = NULL;
ssize_t len = 0;
struct uwsgi_header *uh = (struct uwsgi_header *) main_peer->in->buf;
// better to store it as the original buf address could change
uint16_t pktsize = uh->pktsize;
// are we buffering ?
if (main_peer->is_buffering) {
// memory or disk ?
if (fr->content_length <= ufr.cr.post_buffering) {
// increase buffer if needed
if (uwsgi_buffer_fix(main_peer->in, pktsize+4+fr->content_length))
return -1;
len = cr_read_exact(main_peer, pktsize+4+fr->content_length, "fr_recv_uwsgi_vars()");
if (!len) return 0;
// whole body read ?
if (main_peer->in->pos == (size_t)(pktsize+4+fr->content_length)) {
main_peer->is_buffering = 0;
goto done;
}
return len;
}
// first round ?
if (main_peer->buffering_fd == -1) {
main_peer->buffering_fd = uwsgi_tmpfd();
if (main_peer->buffering_fd < 0) return -1;
}
char buf[32768];
size_t remains = fr->content_length - fr->buffered;
ssize_t rlen = read(main_peer->fd, buf, UMIN(32768, remains));
if (rlen < 0) {
cr_try_again;
uwsgi_cr_error(main_peer, "fr_recv_uwsgi_vars()/read()");
return -1;
}
if (rlen == 0) return 0;
fr->buffered += rlen;
if (write(main_peer->buffering_fd, buf, rlen) != rlen) {
uwsgi_cr_error(main_peer, "fr_recv_uwsgi_vars()/write()");
return -1;
}
// have we done ?
if (fr->buffered >= fr->content_length) {
fr->buffered = 0;
len = rlen;
goto done;
}
return rlen;
}
// increase buffer if needed
if (uwsgi_buffer_fix(main_peer->in, pktsize+4))
return -1;
ssize_t len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()");
len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()");
if (!len) return 0;
// headers received, ready to choose the instance
if (main_peer->in->pos == (size_t)(pktsize+4)) {
struct uwsgi_corerouter *ucr = main_peer->session->corerouter;
struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session);
new_peer = uwsgi_cr_peer_add(main_peer->session);
new_peer->last_hook_read = fr_instance_read;
// find the hostname
@@ -226,8 +318,27 @@ static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
return -1;
// check instance
if (new_peer->instance_address_len == 0)
if (new_peer->instance_address_len == 0) {
if (ufr.cr.fallback_on_no_key) {
new_peer->failed = 1;
new_peer->can_retry = 1;
corerouter_close_peer(&ufr.cr, new_peer);
return len;
}
return -1;
}
// buffering ?
if (ufr.cr.post_buffering > 0 && fr->content_length > 0) {
main_peer->is_buffering = 1;
main_peer->buffering_fd = -1;
return len;
}
done:
if (!new_peer) {
new_peer = main_peer->session->peers;
}
new_peer->can_retry = 1;
+42
View File
@@ -100,6 +100,31 @@ retry:
return Py_None;
}
PyObject *py_uwsgi_gevent_int(PyObject *self, PyObject *args) {
uwsgi_log("Brutally killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL);
PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL);
uwsgi_log_verbose("stopping gevent sockets watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
int i,count = uwsgi_count_sockets(uwsgi.sockets);
for(i=0;i<count;i++) {
PyObject_CallMethod(ugevent.watchers[i], "stop", NULL);
}
uwsgi_log_verbose("main gevent watchers stopped for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
if (!ugevent.wait_for_hub) {
PyObject_CallMethod(ugevent.ctrl_gl, "kill", NULL);
}
Py_INCREF(Py_None);
return Py_None;
}
static void uwsgi_gevent_gbcw() {
// already running
@@ -333,6 +358,7 @@ PyMethodDef uwsgi_gevent_signal_def[] = { {"uwsgi_gevent_signal", py_uwsgi_geven
PyMethodDef uwsgi_gevent_my_signal_def[] = { {"uwsgi_gevent_my_signal", py_uwsgi_gevent_my_signal, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_signal_handler_def[] = { {"uwsgi_gevent_signal_handler", py_uwsgi_gevent_signal_handler, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_handler_def[] = { {"uwsgi_gevent_unix_signal_handler", py_uwsgi_gevent_graceful, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_int_handler_def[] = { {"uwsgi_gevent_unix_signal_int_handler", py_uwsgi_gevent_int, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_ctrl_gl_def[] = { {"uwsgi_gevent_ctrl_gl_handler", py_uwsgi_gevent_ctrl_gl, METH_VARARGS, ""} };
static void gil_gevent_get() {
@@ -488,6 +514,22 @@ static void gevent_loop() {
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
// map SIGINT/SIGTERM with gevent.signal
ge_signal_tuple = PyTuple_New(2);
PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGINT));
PyObject *uwsgi_gevent_unix_signal_int_handler = PyCFunction_New(uwsgi_gevent_unix_signal_int_handler_def, NULL);
Py_INCREF(uwsgi_gevent_unix_signal_int_handler);
PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler);
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
ge_signal_tuple = PyTuple_New(2);
PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGTERM));
PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler);
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
PyObject *wait_for_me = ugevent.hub;
if (!ugevent.wait_for_hub) {
+4
View File
@@ -46,6 +46,8 @@ struct uwsgi_http {
int connect_timeout;
int manage_source;
int enable_proxy_protocol;
int chunked_input;
int manage_rtsp;
};
struct http_session {
@@ -134,6 +136,8 @@ struct http_session {
ssize_t (*func_write)(struct corerouter_peer *);
int is_rtsp;
};
+52 -11
View File
@@ -42,6 +42,8 @@ struct uwsgi_option http_options[] = {
{"http-raw-body", no_argument, 0, "blindly send HTTP body to backends (required for WebSockets and Icecast support in backends)", uwsgi_opt_true, &uhttp.raw_body, 0},
{"http-websockets", no_argument, 0, "automatically detect websockets connections and put the session in raw mode", uwsgi_opt_true, &uhttp.websockets, 0},
{"http-chunked-input", no_argument, 0, "automatically detect chunked input requests and put the session in raw mode", uwsgi_opt_true, &uhttp.chunked_input, 0},
{"http-use-code-string", required_argument, 0, "use code string as hostname->server mapper for the http router", uwsgi_opt_corerouter_cs, &uhttp, 0},
{"http-use-socket", optional_argument, 0, "forward request to the specified uwsgi socket", uwsgi_opt_corerouter_use_socket, &uhttp, 0},
{"http-gracetime", required_argument, 0, "retry connections to dead static nodes after the specified amount of seconds", uwsgi_opt_set_int, &uhttp.cr.static_node_gracetime, 0},
@@ -64,6 +66,7 @@ struct uwsgi_option http_options[] = {
{"http-connect-timeout", required_argument, 0, "set internal http socket timeout for backend connections", uwsgi_opt_set_int, &uhttp.connect_timeout, 0},
{"http-manage-source", no_argument, 0, "manage the SOURCE HTTP method placing the session in raw mode", uwsgi_opt_true, &uhttp.manage_source, 0},
{"http-manage-rtsp", no_argument, 0, "manage RTSP sessions", uwsgi_opt_true, &uhttp.manage_rtsp, 0},
{"http-enable-proxy-protocol", optional_argument, 0, "manage PROXY protocol requests", uwsgi_opt_true, &uhttp.enable_proxy_protocol, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -138,9 +141,14 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t
}
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
if (uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, peer->key, peer->key_len)) return -1;
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
if (uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, peer->key, peer->key_len)) return -1;
}
else {
return -1;
}
}
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
@@ -150,6 +158,11 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t
// in the future we could support chunked requests...
else if (!uwsgi_strncmp("TRANSFER_ENCODING", 17, hh, keylen)) {
hr->session.can_keepalive = 0;
if (uhttp.chunked_input) {
if (!uwsgi_strnicmp(val, vallen, "chunked", 7)) {
hr->raw_body = 1;
}
}
}
else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) {
@@ -158,8 +171,10 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t
}
}
else if (peer->key == uwsgi.hostname && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
}
#ifdef UWSGI_ZLIB
@@ -316,6 +331,10 @@ int http_headers_parse(struct corerouter_peer *peer) {
if (uhttp.keepalive && !uwsgi_strncmp("HTTP/1.1", 8, base, ptr-base)) {
hr->session.can_keepalive = 1;
}
if (uhttp.manage_rtsp && !uwsgi_strncmp("RTSP/1.0", 8, base, ptr-base)) {
hr->raw_body = 1;
hr->is_rtsp = 1;
}
ptr += 2;
found = 1;
break;
@@ -333,7 +352,7 @@ int http_headers_parse(struct corerouter_peer *peer) {
// SERVER_NAME
if (!uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1;
peer->key = uwsgi.hostname;
memcpy(peer->key, uwsgi.hostname, uwsgi.hostname_len);
peer->key_len = uwsgi.hostname_len;
// SERVER_PORT
@@ -445,6 +464,19 @@ int http_headers_parse(struct corerouter_peer *peer) {
hv = hv->next;
}
if (hr->is_rtsp) {
if (uwsgi_starts_with("rtsp://", 7, hr->path_info, hr->path_info_len)) {
char *slash = memchr(hr->path_info + 7, '/', hr->path_info_len - 7);
if (!slash) return -1;
if (slash - (hr->path_info + 7) <= 0xff) {
peer->key_len = slash - (hr->path_info + 7);
memcpy(peer->key, hr->path_info + 7, peer->key_len);
// override PATH_INFO
if (uwsgi_buffer_append_keyval(out, "PATH_INFO", 9, slash, hr->path_info_len - (7 + peer->key_len))) return -1;
}
}
}
return 0;
clear:
@@ -808,10 +840,16 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
if (new_peer->instance_address_len == 0)
return -1;
// fix modifiers
if (uhttp.modifier1)
new_peer->modifier1 = uhttp.modifier1;
if (uhttp.modifier2)
new_peer->modifier2 = uhttp.modifier2;
uint16_t pktsize = new_peer->out->pos-4;
// fix modifiers
new_peer->out->buf[0] = new_peer->session->main_peer->modifier1;
new_peer->out->buf[3] = new_peer->session->main_peer->modifier2;
new_peer->out->buf[0] = new_peer->modifier1;
new_peer->out->buf[3] = new_peer->modifier2;
// fix pktsize
new_peer->out->buf[1] = (uint8_t) (pktsize & 0xff);
new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
@@ -829,6 +867,12 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
if (uwsgi_buffer_append(new_peer->out, main_peer->in->buf + hr->headers_size + 1, hr->remains)) return -1;
}
if (new_peer->modifier1 == 123) {
// reset modifier1 to 0
new_peer->out->buf[0] = 0;
hr->raw_body = 1;
}
if (hr->websockets > 2 && hr->websocket_key_len > 0) {
hr->raw_body = 1;
}
@@ -953,9 +997,6 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
// set the retry hook
cs->retry = hr_retry;
struct http_session *hr = (struct http_session *) cs;
// set the modifier1
cs->main_peer->modifier1 = uhttp.modifier1;
cs->main_peer->modifier2 = uhttp.modifier2;
// default hook
cs->main_peer->last_hook_read = hr_read;
+68 -8
View File
@@ -10,6 +10,14 @@
extern struct uwsgi_http uhttp;
// taken from nginx
static void hr_ssl_clear_errors() {
while (ERR_peek_error()) {
(void) ERR_get_error();
}
ERR_clear_error();
}
void uwsgi_opt_https(char *opt, char *value, void *cr) {
struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr;
char *client_ca = NULL;
@@ -172,9 +180,9 @@ int hr_https_add_vars(struct http_session *hr, struct corerouter_peer *peer, str
if (uwsgi_buffer_append_keyval(out, "HTTPS", 5, "on", 2)) return -1;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
const char *servername = SSL_get_servername(hr->ssl, TLSEXT_NAMETYPE_host_name);
if (servername) {
peer->key = (char *) servername;
peer->key_len = strlen(servername);
if (servername && strlen(servername) <= 0xff) {
peer->key_len = strlen(servername);
memcpy(peer->key, servername, peer->key_len) ;
}
#endif
hr->ssl_client_cert = SSL_get_peer_certificate(hr->ssl);
@@ -234,7 +242,7 @@ void hr_session_ssl_close(struct corerouter_session *cs) {
#endif
// clear the errors (otherwise they could be propagated)
ERR_clear_error();
hr_ssl_clear_errors();
SSL_free(hr->ssl);
}
@@ -270,6 +278,8 @@ ssize_t hr_ssl_write(struct corerouter_peer *main_peer) {
struct corerouter_session *cs = main_peer->session;
struct http_session *hr = (struct http_session *) cs;
hr_ssl_clear_errors();
int ret = SSL_write(hr->ssl, main_peer->out->buf + main_peer->out_pos, main_peer->out->pos - main_peer->out_pos);
if (ret > 0) {
main_peer->out_pos += ret;
@@ -294,9 +304,11 @@ ssize_t hr_ssl_write(struct corerouter_peer *main_peer) {
}
return ret;
}
if (ret == 0) return 0;
int err = SSL_get_error(hr->ssl, ret);
if (err == SSL_ERROR_ZERO_RETURN || err == 0) return 0;
if (err == SSL_ERROR_WANT_READ) {
cr_reset_hooks_and_read(main_peer, hr_ssl_write);
return 1;
@@ -308,7 +320,8 @@ ssize_t hr_ssl_write(struct corerouter_peer *main_peer) {
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_cr_error(main_peer, "hr_ssl_write()");
if (errno != 0)
uwsgi_cr_error(main_peer, "hr_ssl_write()");
}
else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
@@ -322,6 +335,8 @@ ssize_t hr_ssl_read(struct corerouter_peer *main_peer) {
struct corerouter_session *cs = main_peer->session;
struct http_session *hr = (struct http_session *) cs;
hr_ssl_clear_errors();
// try to always leave 4k available
if (uwsgi_buffer_ensure(main_peer->in, uwsgi.page_size)) return -1;
int ret = SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, main_peer->in->len - main_peer->in->pos);
@@ -350,9 +365,11 @@ ssize_t hr_ssl_read(struct corerouter_peer *main_peer) {
#endif
return http_parse(main_peer);
}
if (ret == 0) return 0;
int err = SSL_get_error(hr->ssl, ret);
if (err == SSL_ERROR_ZERO_RETURN || err == 0) return 0;
if (err == SSL_ERROR_WANT_READ) {
cr_reset_hooks_and_read(main_peer, hr_ssl_read);
return 1;
@@ -364,7 +381,49 @@ ssize_t hr_ssl_read(struct corerouter_peer *main_peer) {
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_cr_error(main_peer, "hr_ssl_read()");
if (errno != 0)
uwsgi_cr_error(main_peer, "hr_ssl_read()");
}
else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
ERR_print_errors_fp(stderr);
}
return -1;
}
ssize_t hr_ssl_shutdown(struct corerouter_peer *peer) {
// ensure no hooks are set
if (uwsgi_cr_set_hooks(peer, NULL, NULL)) return -1;
struct corerouter_session *cs = peer->session;
struct http_session *hr = (struct http_session *) cs;
hr_ssl_clear_errors();
int ret = SSL_shutdown(hr->ssl);
int err = 0;
if (ret != 1 && ERR_peek_error()) {
err = SSL_get_error(hr->ssl, ret);
}
// no error, close the connection
if (ret == 1 || err == 0 || err == SSL_ERROR_ZERO_RETURN) return 0;
if (err == SSL_ERROR_WANT_READ) {
if (uwsgi_cr_set_hooks(peer, hr_ssl_shutdown, NULL)) return -1;
return 1;
}
else if (err == SSL_ERROR_WANT_WRITE) {
if (uwsgi_cr_set_hooks(peer, NULL, hr_ssl_shutdown)) return -1;
return 1;
}
else if (err == SSL_ERROR_SYSCALL) {
if (errno != 0)
uwsgi_cr_error(peer, "hr_ssl_shutdown()");
}
else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
@@ -382,6 +441,7 @@ void hr_setup_ssl(struct http_session *hr, struct uwsgi_gateway_socket *ugs) {
SSL_set_ex_data(hr->ssl, uhttp.spdy_index, hr);
#endif
uwsgi_cr_set_hooks(hr->session.main_peer, hr_ssl_read, NULL);
hr->session.main_peer->flush = hr_ssl_shutdown;
hr->session.close = hr_session_ssl_close;
hr->func_write = hr_ssl_write;
}
+4 -2
View File
@@ -556,8 +556,10 @@ static ssize_t spdy_inflate_http_headers(struct http_session *hr) {
}
if (!uwsgi_strncmp(cgi_name, nk_len, "HTTP_HOST", 9)) {
new_peer->key = new_peer->out->buf + (new_peer->out->pos - v_len);
new_peer->key_len = v_len;
if (v_len <= 0xff) {
memcpy(new_peer->key, new_peer->out->buf + (new_peer->out->pos - v_len), v_len);
new_peer->key_len = v_len;
}
}
else if (!uwsgi_strncmp(cgi_name, nk_len, "REQUEST_URI", 11)) {
char *path_info = new_peer->out->buf + (new_peer->out->pos - v_len);
+54 -4
View File
@@ -1,10 +1,49 @@
#include <uwsgi.h>
struct logfile_data {
char *logfile;
char *backupname;
uint64_t maxsize;
};
static ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t len) {
if (!ul->configured) {
if (ul->arg) {
ul->fd = open(ul->arg, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
int is_keyval = 0;
char *backupname = NULL;
char *maxsize = NULL;
char *logfile = NULL;
if (strchr(ul->arg, '=')) {
if (uwsgi_kvlist_parse(ul->arg, strlen(ul->arg), ',', '=',
"logfile", &logfile, "backupname", &backupname, "maxsize", &maxsize, NULL)) {
uwsgi_log("[uwsgi-logfile] invalid keyval syntax\n");
exit(1);
}
is_keyval = 1;
}
if (is_keyval) {
if (!logfile) {
uwsgi_log("[uwsgi-logfile] missing logfile key\n");
return 0;
}
if (maxsize) {
struct logfile_data *data = uwsgi_malloc(sizeof(struct logfile_data));
data->logfile = logfile;
data->backupname = backupname;
data->maxsize = (uint64_t)strtoull(maxsize, NULL, 10);
ul->data = data;
free(maxsize);
maxsize = NULL;
}
} else {
logfile = ul->arg;
}
ul->fd = open(logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (ul->fd >= 0) {
ul->configured = 1;
}
@@ -12,10 +51,21 @@ static ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t
}
if (ul->fd >= 0) {
return write(ul->fd, message, len);
}
return 0;
ssize_t written = write(ul->fd, message, len);
if (ul->data) {
struct logfile_data *data = ul->data;
off_t logsize = lseek(ul->fd, 0, SEEK_CUR);
if (data->maxsize > 0 && (uint64_t) logsize > data->maxsize) {
uwsgi_log_do_rotate(data->logfile, data->backupname, logsize, ul->fd);
}
}
return written;
}
return 0;
}
static ssize_t uwsgi_fd_logger(struct uwsgi_logger *ul, char *message, size_t len) {
+10 -5
View File
@@ -543,7 +543,7 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1);
// if it is -1, try to load a dynamic app
if (wsgi_req->app_id == -1) {
if (wsgi_req->app_id == -1 && key_len > 0) {
if (uwsgi.threads > 1) {
pthread_mutex_lock(&umono.lock_loader);
}
@@ -562,10 +562,15 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
if (wsgi_req->app_id == -1) {
uwsgi_500(wsgi_req);
uwsgi_log("--- unable to find Mono/ASP.NET application ---\n");
// nothing to clear/free
return UWSGI_OK;
if (!uwsgi.no_default_app && uwsgi.default_app > -1 && uwsgi_apps[uwsgi.default_app].modifier1 == mono_plugin.modifier1) {
wsgi_req->app_id = uwsgi.default_app;
}
else {
uwsgi_500(wsgi_req);
uwsgi_log("--- unable to find Mono/ASP.NET application ---\n");
// nothing to clear/free
return UWSGI_OK;
}
}
struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id];
+3
View File
@@ -6,6 +6,9 @@ LDFLAGS = []
LIBS = os.popen('pkg-config --libs mono-2').read().rstrip().split()
GCC_LIST = ['mono_plugin']
if os.uname()[0] == 'Darwin':
LIBS.append('-framework Foundation')
def post_build(config):
if os.system("sn -k plugins/mono/uwsgi.key") != 0:
os._exit(1)
+1 -1
View File
@@ -121,7 +121,7 @@ int uwsgi_buffer_msgpack_int(struct uwsgi_buffer *ub, int64_t num) {
if (num > 0 && num <= 127) {
return uwsgi_buffer_byte(ub, (uint8_t) num);
}
else if (num < 0 && num >= 31) {
else if (num < 0 && num >= -31) {
return uwsgi_buffer_byte(ub, 224 | (int8_t) num);
}
else if (num <= 127 && num >= -127) {
+48 -27
View File
@@ -26,6 +26,8 @@ struct uwsgi_php {
struct uwsgi_string_list *exec_before;
struct uwsgi_string_list *exec_after;
char *sapi_name;
} uphp;
void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
@@ -58,6 +60,7 @@ struct uwsgi_option uwsgi_php_options[] = {
{"php-exec-begin", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
{"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-sapi-name", required_argument, 0, "hack the sapi name (required for enabling zend opcode cache)", uwsgi_opt_set_str, &uphp.sapi_name, 0},
UWSGI_END_OF_OPTIONS
};
@@ -74,7 +77,7 @@ static int sapi_uwsgi_ub_write(const char *str, uint str_length TSRMLS_DC)
return str_length;
}
static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
{
sapi_header_struct *h;
zend_llist_position pos;
@@ -132,7 +135,7 @@ static int sapi_uwsgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
}
static char *sapi_uwsgi_read_cookies(void)
static char *sapi_uwsgi_read_cookies(TSRMLS_D)
{
uint16_t len = 0;
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
@@ -176,11 +179,11 @@ static void sapi_uwsgi_register_variables(zval *track_vars_array TSRMLS_DC)
php_register_variable_safe("DOCUMENT_ROOT", wsgi_req->document_root, wsgi_req->document_root_len, track_vars_array TSRMLS_CC);
if (wsgi_req->path_info_len) {
char *path_translated = ecalloc(1, (wsgi_req->file_len - wsgi_req->script_name_len) + wsgi_req->path_info_len + 1);
char *path_translated = ecalloc(1, wsgi_req->file_len + wsgi_req->path_info_len + 1);
memcpy(path_translated, wsgi_req->file, (wsgi_req->file_len - wsgi_req->script_name_len));
memcpy(path_translated + (wsgi_req->file_len - wsgi_req->script_name_len), wsgi_req->path_info, wsgi_req->path_info_len);
php_register_variable_safe("PATH_TRANSLATED", path_translated, (wsgi_req->file_len - wsgi_req->script_name_len) + wsgi_req->path_info_len , track_vars_array TSRMLS_CC);
memcpy(path_translated, wsgi_req->file, wsgi_req->file_len);
memcpy(path_translated + wsgi_req->file_len, wsgi_req->path_info, wsgi_req->path_info_len);
php_register_variable_safe("PATH_TRANSLATED", path_translated, wsgi_req->file_len + wsgi_req->path_info_len , track_vars_array TSRMLS_CC);
}
else {
php_register_variable_safe("PATH_TRANSLATED", "", 0, track_vars_array TSRMLS_CC);
@@ -251,8 +254,9 @@ PHP_FUNCTION(uwsgi_cache_exists) {
char *key = NULL;
int keylen = 0;
char *cache = NULL;
int cachelen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -266,8 +270,9 @@ PHP_FUNCTION(uwsgi_cache_exists) {
PHP_FUNCTION(uwsgi_cache_clear) {
char *cache = NULL;
int cachelen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -284,8 +289,9 @@ PHP_FUNCTION(uwsgi_cache_del) {
char *key = NULL;
int keylen = 0;
char *cache = NULL;
int cachelen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -301,12 +307,13 @@ PHP_FUNCTION(uwsgi_cache_get) {
char *key = NULL;
int keylen = 0;
char *cache = NULL;
int cachelen = 0;
uint64_t valsize;
if (!uwsgi.caches)
RETURN_NULL();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -326,11 +333,12 @@ PHP_FUNCTION(uwsgi_cache_set) {
int vallen;
uint64_t expires = 0;
char *cache = NULL;
int cachelen = 0;
if (!uwsgi.caches)
RETURN_NULL();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -348,11 +356,12 @@ PHP_FUNCTION(uwsgi_cache_update) {
int vallen;
uint64_t expires = 0;
char *cache = NULL;
int cachelen = 0;
if (!uwsgi.caches)
RETURN_NULL();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -509,7 +518,7 @@ static int php_uwsgi_startup(sapi_module_struct *sapi_module)
}
}
static void sapi_uwsgi_log_message(char *message) {
static void sapi_uwsgi_log_message(char *message TSRMLS_DC) {
uwsgi_log("%s\n", message);
}
@@ -550,6 +559,10 @@ int uwsgi_php_init(void) {
struct uwsgi_string_list *pset = uphp.set;
struct uwsgi_string_list *append_config = uphp.append_config;
#ifdef ZTS
tsrm_startup(1, 1, 0, NULL);
#endif
sapi_startup(&uwsgi_sapi_module);
// applying custom options
@@ -578,8 +591,10 @@ int uwsgi_php_init(void) {
}
}
if (uphp.sapi_name) {
uwsgi_sapi_module.name = uphp.sapi_name;
}
uwsgi_sapi_module.startup(&uwsgi_sapi_module);
uwsgi_log("PHP %s initialized\n", PHP_VERSION);
return 0;
@@ -648,15 +663,23 @@ int uwsgi_php_request(struct wsgi_request *wsgi_req) {
size_t real_filename_len = 0;
struct stat php_stat;
char *filename = NULL;
int force_empty_script_name = 0;
zend_file_handle file_handle;
#ifdef ZTS
TSRMLS_FETCH();
#endif
SG(server_context) = (void *) wsgi_req;
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
char *orig_path_info = wsgi_req->path_info;
uint16_t orig_path_info_len = wsgi_req->path_info_len;
if (uphp.docroot) {
wsgi_req->document_root = uphp.docroot;
}
@@ -713,6 +736,7 @@ int uwsgi_php_request(struct wsgi_request *wsgi_req) {
appready:
wsgi_req->path_info = "";
wsgi_req->path_info_len = 0;
force_empty_script_name = 1;
goto secure2;
}
@@ -733,10 +757,6 @@ oldstyle:
}
}
char *orig_path_info = wsgi_req->path_info;
uint16_t orig_path_info_len = wsgi_req->path_info_len;
if (path_info) {
wsgi_req->path_info = path_info;
wsgi_req->path_info_len = orig_path_info_len - (path_info - orig_path_info);
@@ -846,24 +866,25 @@ secure2:
}
secure3:
if (wsgi_req->document_root[wsgi_req->document_root_len-1] == '/') {
wsgi_req->script_name = real_filename + (wsgi_req->document_root_len-1);
if (force_empty_script_name) {
wsgi_req->script_name = "";
wsgi_req->script_name_len = 0;
}
else {
wsgi_req->script_name = real_filename + wsgi_req->document_root_len;
wsgi_req->script_name = orig_path_info;
if (path_info) {
wsgi_req->script_name_len = path_info - orig_path_info;
}
else {
wsgi_req->script_name_len = orig_path_info_len;
}
}
wsgi_req->script_name_len = strlen(wsgi_req->script_name);
#ifdef UWSGI_DEBUG
uwsgi_log("php filename = %s script_name = %.*s (%d) document_root = %.*s (%d)\n", real_filename, wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->script_name_len,
wsgi_req->document_root_len, wsgi_req->document_root, wsgi_req->document_root_len);
#endif
// now check for allowed paths and extensions
SG(request_info).request_uri = estrndup(wsgi_req->uri, wsgi_req->uri_len);
+57 -9
View File
@@ -11,8 +11,8 @@ XS(XS_input_seek) {
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
psgi_check_args(1);
uwsgi_request_body_seek(wsgi_req, SvIV(ST(0)));
psgi_check_args(2);
uwsgi_request_body_seek(wsgi_req, SvIV(ST(1)));
XSRETURN(0);
}
@@ -25,11 +25,12 @@ XS(XS_error) {
psgi_check_args(0);
if (uwsgi.threads > 1) {
ST(0) = sv_bless(newRV(sv_newmortal()), ((HV **)wi->error)[wsgi_req->async_id]);
ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->error)[wsgi_req->async_id]);
}
else {
ST(0) = sv_bless(newRV(sv_newmortal()), ((HV **)wi->error)[0]);
ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->error)[0]);
}
sv_2mortal(ST(0));
XSRETURN(1);
}
@@ -41,11 +42,12 @@ XS(XS_input) {
psgi_check_args(0);
if (uwsgi.threads > 1) {
ST(0) = sv_bless(newRV(sv_newmortal()), ((HV **)wi->input)[wsgi_req->async_id]);
ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->input)[wsgi_req->async_id]);
}
else {
ST(0) = sv_bless(newRV(sv_newmortal()), ((HV **)wi->input)[0]);
ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->input)[0]);
}
sv_2mortal(ST(0));
XSRETURN(1);
}
@@ -80,11 +82,12 @@ XS(XS_stream)
SvREFCNT_dec(response);
if (uwsgi.threads > 1) {
ST(0) = sv_bless(newRV(sv_newmortal()), ((HV **)wi->stream)[wsgi_req->async_id]);
ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->stream)[wsgi_req->async_id]);
}
else {
ST(0) = sv_bless(newRV(sv_newmortal()), ((HV **)wi->stream)[0]);
ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->stream)[0]);
}
sv_2mortal(ST(0));
XSRETURN(1);
}
else {
@@ -141,7 +144,7 @@ XS(XS_input_read) {
else {
long orig_offset = 0;
// first of all get the new orig_len;
offset = abs(offset);
offset = labs(offset);
if (offset > (long) orig_len) {
new_size = offset;
orig_offset = offset - orig_len;
@@ -271,6 +274,51 @@ nonworker:
newCONSTSUB(stash, "SPOOL_RETRY", newSViv(-1));
newCONSTSUB(stash, "SPOOL_IGNORE", newSViv(0));
HV *_opts = newHV();
int i;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
if (hv_exists(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key))) {
SV **value = hv_fetch(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), 0);
// last resort !!!
if (!value) {
uwsgi_log("[perl] WARNING !!! unable to build uwsgi::opt hash !!!\n");
goto end;
}
if (SvROK(*value) && SvTYPE(SvRV(*value)) == SVt_PVAV) {
if (uwsgi.exported_opts[i]->value == NULL) {
av_push((AV *)SvRV(*value), newSViv(1));
}
else {
av_push((AV *)SvRV(*value), newSVpv(uwsgi.exported_opts[i]->value, 0));
}
}
else {
AV *_opt_a = newAV();
av_push(_opt_a, SvREFCNT_inc(*value));
if (uwsgi.exported_opts[i]->value == NULL) {
av_push(_opt_a, newSViv(1));
}
else {
av_push(_opt_a, newSVpv(uwsgi.exported_opts[i]->value, 0));
}
(void ) hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newRV_inc((SV *) _opt_a), 0);
}
}
else {
if (uwsgi.exported_opts[i]->value == NULL) {
(void )hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newSViv(1), 0);
}
else {
(void)hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newSVpv(uwsgi.exported_opts[i]->value, 0), 0);
}
}
}
newCONSTSUB(stash, "opt", newRV_inc((SV *) _opts));
end:
init_perl_embedded_module();
}
+57 -10
View File
@@ -114,7 +114,7 @@ SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
SPAGAIN;
newobj = POPs;
newobj = SvREFCNT_inc(POPs);
PUTBACK;
FREETMPS;
LEAVE;
@@ -637,6 +637,19 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
// before the environ is set up.
if (!wsgi_req->async_environ) return;
// we need to restore the context in case of multiple interpreters
struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id];
if (uwsgi.threads < 2) {
if (((PerlInterpreter **)wi->interpreter)[0] != uperl.main[0]) {
PERL_SET_CONTEXT(((PerlInterpreter **)wi->interpreter)[0]);
}
}
else {
if (((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id] != uperl.main[wsgi_req->async_id]) {
PERL_SET_CONTEXT(((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id]);
}
}
// dereference %env
SV *env = SvRV((SV *) wsgi_req->async_environ);
@@ -661,15 +674,21 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
}
// Free the $env hash
SvREFCNT_dec(wsgi_req->async_environ);
// async plagued could be defined in other areas...
if (wsgi_req->async_plagued) {
uwsgi_log("*** psgix.harakiri.commit requested ***\n");
// Before we call exit(0) we'll run the
// uwsgi_perl_atexit() hook which'll properly tear
// down the interpreter.
// mark the request as ended (otherwise the atexit hook will be skipped)
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
goodbye_cruel_world();
}
// clear the env
SvREFCNT_dec(wsgi_req->async_environ);
// now we can check for changed files
if (uperl.auto_reload) {
time_t now = uwsgi_now();
@@ -678,6 +697,19 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
}
}
// restore main interpreter if needed
if (uwsgi.threads > 1) {
if (((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id] != uperl.main[wsgi_req->async_id]) {
PERL_SET_CONTEXT(uperl.main[wsgi_req->async_id]);
}
}
else {
if (((PerlInterpreter **)wi->interpreter)[0] != uperl.main[0]) {
PERL_SET_CONTEXT(uperl.main[0]);
}
}
}
int uwsgi_perl_magic(char *mountpoint, char *lazy) {
@@ -803,24 +835,39 @@ void uwsgi_perl_run_hook(SV *hook) {
}
static void uwsgi_perl_atexit() {
int i;
if (uwsgi.mywid == 0) goto realstuff;
// if hijacked do not run atexit hooks
// if hijacked do not run atexit hooks -- TODO: explain why
// not.
if (uwsgi.workers[uwsgi.mywid].hijacked)
return;
goto destroyperl;
// if busy do not run atexit hooks
// if busy do not run atexit hooks (as this part could be called in a signal handler
// while a subroutine is running)
if (uwsgi_worker_is_busy(uwsgi.mywid))
return;
// managing atexit in async mode is a real pain...skip it for now
if (uwsgi.async > 1)
return;
realstuff:
if (uperl.atexit) {
uwsgi_perl_run_hook(uperl.atexit);
}
destroyperl:
// We must free our perl context(s) so any DESTROY hooks
// etc. will run.
for(i=0;i<uwsgi.threads;i++) {
PERL_SET_CONTEXT(uperl.main[i]);
// Destroy the PerlInterpreter, see "perldoc perlembed"
perl_destruct(uperl.main[i]);
perl_free(uperl.main[i]);
}
PERL_SYS_TERM();
free(uperl.main);
}
static uint64_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
+1 -1
View File
@@ -68,7 +68,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
hitem = av_fetch(response, 1, 0);
if (!hitem) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
if (!hitem || !SvRV(*hitem) || SvTYPE(SvRV(*hitem)) != SVt_PVAV) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
headers = (AV *) SvRV(*hitem);
if (!headers) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
+9 -1
View File
@@ -318,6 +318,13 @@ XS(XS_alarm) {
XSRETURN_UNDEF;
}
XS(XS_worker_id) {
dXSARGS;
psgi_check_args(0);
ST(0) = newSViv(uwsgi.mywid);
XSRETURN(1);
}
XS(XS_async_connect) {
dXSARGS;
@@ -946,7 +953,7 @@ XS(XS_spool) {
}
}
char *filename = uwsgi_spool_request(current_wsgi_req(), ub->buf, ub->pos, body, body_len);
char *filename = uwsgi_spool_request(NULL, ub->buf, ub->pos, body, body_len);
uwsgi_buffer_destroy(ub);
if (filename) {
ST(0) = newSVpv(filename, strlen(filename));
@@ -1042,5 +1049,6 @@ void init_perl_embedded_module() {
psgi_xs(spool);
psgi_xs(add_var);
psgi_xs(worker_id);
}
+22 -5
View File
@@ -66,17 +66,34 @@ static int uwsgi_pypy_init() {
}
else {
if (upypy.home) {
// first try with /bin way:
#ifdef __CYGWIN__
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dll");
char *libpath = uwsgi_concat2(upypy.home, "/bin/libpypy-c.dll");
#elif defined(__APPLE__)
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib");
char *libpath = uwsgi_concat2(upypy.home, "/bin/libpypy-c.dylib");
#else
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so");
char *libpath = uwsgi_concat2(upypy.home, "/bin/libpypy-c.so");
#endif
if (uwsgi_file_exists(libpath)) {
upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL);
upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL);
}
free(libpath);
// fallback to old-style way
if (!upypy.handler) {
#ifdef __CYGWIN__
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dll");
#elif defined(__APPLE__)
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib");
#else
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so");
#endif
if (uwsgi_file_exists(libpath)) {
upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL);
}
free(libpath);
}
free(libpath);
}
// fallback to standard library search path
if (!upypy.handler) {
+12 -12
View File
@@ -393,7 +393,7 @@ class WSGIinput(object):
rlen = ffi.new('ssize_t*')
chunk = lib.uwsgi_request_body_read(self.wsgi_req, size, rlen)
if chunk != ffi.NULL:
return ffi.string(chunk, rlen[0])
return ffi.buffer(chunk, rlen[0])[:]
if rlen[0] < 0:
raise IOError("error reading wsgi.input")
raise IOError("error waiting for wsgi.input")
@@ -402,7 +402,7 @@ class WSGIinput(object):
rlen = ffi.new('ssize_t*')
chunk = lib.uwsgi_request_body_readline(self.wsgi_req, hint, rlen)
if chunk != ffi.NULL:
return ffi.string(chunk, rlen[0])
return ffi.buffer(chunk, rlen[0])[:]
if rlen[0] < 0:
raise IOError("error reading line from wsgi.input")
raise IOError("error waiting for line on wsgi.input")
@@ -521,7 +521,7 @@ class uwsgi_pypy_RPC(object):
def __call__(self, argc, argv, argvs, buf):
pargs = []
for i in range(0, argc):
pargs.append(ffi.string(argv[i], argvs[i]))
pargs.append(ffi.buffer(argv[i], argvs[i])[:])
response = self.func(*pargs)
if len(response) > 0:
buf[0] = lib.uwsgi_malloc(len(response))
@@ -560,7 +560,7 @@ def uwsgi_pypy_rpc(node, func, *args):
response = lib.uwsgi_do_rpc(c_node, ffi.new("char[]",func), argc, argv, argvs, rsize)
if response:
ret = ffi.string(response, rsize[0])
ret = ffi.buffer(response, rsize[0])[:]
lib.free(response)
return ret
return None
@@ -587,7 +587,7 @@ def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL):
value = lib.uwsgi_cache_magic_get(key, len(key), vallen, ffi.NULL, cache)
if value == ffi.NULL:
return None
ret = ffi.string(value, vallen[0])
ret = ffi.buffer(value, vallen[0])[:]
libc.free(value)
return ret
uwsgi.cache_get = uwsgi_pypy_uwsgi_cache_get
@@ -617,8 +617,9 @@ def uwsgi_pypy_uwsgi_cache_keys(cache=ffi.NULL):
uci = ffi.new('struct uwsgi_cache_item **')
while True:
uci[0] = lib.uwsgi_cache_keys(uc, pos, uci)
if uci[0] == ffi.NULL: break
l.append(ffi.string(lib.uwsgi_cache_item_key(uci[0]), uci[0].keysize))
if uci[0] == ffi.NULL:
break
l.append(ffi.buffer(lib.uwsgi_cache_item_key(uci[0]), uci[0].keysize)[:])
lib.uwsgi_cache_rwunlock(uc)
return l
uwsgi.cache_keys = uwsgi_pypy_uwsgi_cache_keys
@@ -849,7 +850,7 @@ def uwsgi_pypy_websocket_recv():
ub = lib.uwsgi_websocket_recv(wsgi_req);
if ub == ffi.NULL:
raise IOError("unable to receive websocket message")
ret = ffi.string(ub.buf, ub.pos)
ret = ffi.buffer(ub.buf, ub.pos)[:]
lib.uwsgi_buffer_destroy(ub)
return ret
uwsgi.websocket_recv = uwsgi_pypy_websocket_recv
@@ -862,7 +863,7 @@ def uwsgi_pypy_websocket_recv_nb():
ub = lib.uwsgi_websocket_recv_nb(wsgi_req);
if ub == ffi.NULL:
raise IOError("unable to receive websocket message")
ret = ffi.string(ub.buf, ub.pos)
ret = ffi.buffer(ub.buf, ub.pos)[:]
lib.uwsgi_buffer_destroy(ub)
return ret
uwsgi.websocket_recv_nb = uwsgi_pypy_websocket_recv_nb
@@ -897,7 +898,7 @@ def uwsgi_pypy_chunked_read(timeout=0):
chunk = lib.uwsgi_chunked_read(wsgi_req, rlen, timeout, 0)
if chunk == ffi.NULL:
raise IOError("unable to receive chunked part")
return ffi.string(chunk, rlen[0])
return ffi.buffer(chunk, rlen[0])[:]
uwsgi.chunked_read = uwsgi_pypy_chunked_read
"""
@@ -911,8 +912,7 @@ def uwsgi_pypy_chunked_read_nb():
if lib.uwsgi_is_again() > 0:
return None
raise IOError("unable to receive chunked part")
return ffi.string(chunk, rlen[0])
return ffi.buffer(chunk, rlen[0])[:]
uwsgi.chunked_read_nb = uwsgi_pypy_chunked_read_nb
"""
+8 -1
View File
@@ -325,12 +325,19 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
if (uwsgi.threads > 1 && id) {
// if we have multiple threads we need to initialize a PyThreadState for each one
for(i=0;i<uwsgi.threads;i++) {
//uwsgi_log("%p\n", uwsgi.core[i]->ts[id]);
uwsgi.workers[uwsgi.mywid].cores[i].ts[id] = PyThreadState_New( ((PyThreadState *)wi->interpreter)->interp);
//uwsgi_log("%p\n", uwsgi.workers[uwsgi.mywid].cores[i].ts[id]);
if (!uwsgi.workers[uwsgi.mywid].cores[i].ts[id]) {
uwsgi_log("unable to allocate new PyThreadState structure for app %s", wi->mountpoint);
goto doh;
}
// cow ?
if (uwsgi.mywid == 0) {
int j;
for(j=1;j<=uwsgi.numproc;j++) {
uwsgi.workers[j].cores[i].ts[id] = uwsgi.workers[0].cores[i].ts[id];
}
}
}
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key) );
}
+45 -24
View File
@@ -88,7 +88,7 @@ struct uwsgi_option uwsgi_python_options[] = {
{"module", required_argument,'w', "load a WSGI module", uwsgi_opt_set_str, &up.wsgi_config, 0},
{"wsgi", required_argument, 'w', "load a WSGI module", uwsgi_opt_set_str, &up.wsgi_config, 0},
{"callable", required_argument, 0, "set default WSGI callable name", uwsgi_opt_set_str, &up.callable, 0},
{"test", required_argument, 'J', "test a mdule import", uwsgi_opt_set_str, &up.test_module, 0},
{"test", required_argument, 'J', "test a module import", uwsgi_opt_set_str, &up.test_module, 0},
{"home", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0},
{"virtualenv", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0},
{"venv", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0},
@@ -397,6 +397,7 @@ void uwsgi_python_post_fork() {
PyErr_Clear();
if (uwsgi.mywid > 0) {
uwsgi_python_set_thread_name(0);
if (up.auto_reload) {
// spawn the reloader thread
pthread_t par_tid;
@@ -920,12 +921,16 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) {
if (strchr(app, ':') || uwsgi_endswith(app, ".py") || uwsgi_endswith(app, ".wsgi")) {
uwsgi.wsgi_req->appid = mountpoint;
uwsgi.wsgi_req->appid_len = strlen(mountpoint);
// lazy ?
if (uwsgi.mywid > 0) UWSGI_GET_GIL
if (uwsgi.single_interpreter) {
id = init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
else {
id = init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL, PYTHON_APP_TYPE_WSGI);
}
// lazy ?
if (uwsgi.mywid > 0) UWSGI_RELEASE_GIL
return id;
}
return -1;
@@ -1266,11 +1271,39 @@ void uwsgi_python_enable_threads() {
up.reset_ts = threaded_reset_ts;
}
uwsgi_log("python threads support enabled\n");
}
void uwsgi_python_set_thread_name(int core_id) {
// call threading.currentThread (taken from mod_wsgi, but removes DECREFs as thread in uWSGI are fixed)
PyObject *threading_module = PyImport_ImportModule("threading");
if (threading_module) {
PyObject *threading_module_dict = PyModule_GetDict(threading_module);
if (threading_module_dict) {
#ifdef PYTHREE
PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "current_thread");
#else
PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "currentThread");
#endif
if (threading_current) {
PyObject *current_thread = PyEval_CallObject(threading_current, (PyObject *)NULL);
if (!current_thread) {
// ignore the error
PyErr_Clear();
}
else {
PyObject_SetAttrString(current_thread, "name", PyString_FromFormat("uWSGIWorker%dCore%d", uwsgi.mywid, core_id));
Py_INCREF(current_thread);
}
}
}
}
}
void uwsgi_python_init_thread(int core_id) {
// set a new ThreadState for each thread
@@ -1282,29 +1315,7 @@ void uwsgi_python_init_thread(int core_id) {
uwsgi_log("python ThreadState %d = %p\n", core_id, pts);
#endif
UWSGI_GET_GIL;
// call threading.currentThread (taken from mod_wsgi, but removes DECREFs as thread in uWSGI are fixed)
PyObject *threading_module = PyImport_ImportModule("threading");
if (threading_module) {
PyObject *threading_module_dict = PyModule_GetDict(threading_module);
if (threading_module_dict) {
#ifdef PYTHREE
PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "current_thread");
#else
PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "currentThread");
#endif
if (threading_current) {
PyObject *current_thread = PyEval_CallObject(threading_current, (PyObject *)NULL);
if (!current_thread) {
// ignore the error
PyErr_Clear();
}
else {
PyObject_SetAttrString(current_thread, "name", PyString_FromFormat("uWSGIWorker%dCore%d", uwsgi.mywid, core_id));
Py_INCREF(current_thread);
}
}
}
}
uwsgi_python_set_thread_name(core_id);
UWSGI_RELEASE_GIL;
@@ -1414,7 +1425,15 @@ void *uwsgi_python_autoreloader_thread(void *foobar) {
int found = 0;
struct uwsgi_string_list *usl = up.auto_reload_ignore;
while(usl) {
#ifdef PYTHREE
PyObject *zero = PyUnicode_AsUTF8String(mod_name);
char *str_mod_name = PyString_AsString(zero);
int ret_cmp = strcmp(usl->value, str_mod_name);
Py_DECREF(zero);
if (!ret_cmp) {
#else
if (!strcmp(usl->value, PyString_AsString(mod_name))) {
#endif
found = 1;
break;
}
@@ -1651,6 +1670,8 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
PyDict_SetItemString(spool_dict, "body", value);
Py_DECREF(value);
}
// PyTuple_SetItem steals a reference !!!
Py_INCREF(spool_dict);
PyTuple_SetItem(pyargs, 0, spool_dict);
ret = python_call(spool_func, pyargs, 0, NULL);
+61
View File
@@ -27,7 +27,18 @@ char *uwsgi_python_get_thread_name(PyObject *thread_id) {
if (PyInt_AsLong(thread_ident) == PyInt_AsLong(thread_id)) {
PyObject *thread_name = PyObject_GetAttrString(threads_list_next, "name");
if (!thread_name) goto clear2;
#ifdef PYTHREE
PyObject *thread_name_utf8 = PyUnicode_AsUTF8String(thread_name);
if (!thread_name_utf8) goto clear2;
char *name = NULL;
char *tmp_name = PyString_AsString(thread_name_utf8);
if (tmp_name) {
name = uwsgi_str(tmp_name);
Py_DECREF(thread_name_utf8);
}
#else
char *name = PyString_AsString(thread_name);
#endif
Py_DECREF(threads_list_next);
Py_DECREF(threads_list_iter);
Py_DECREF(threads_list);
@@ -133,6 +144,9 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
PyObject *st_items = PyIter_Next(stacktrace_iter);
// we have the first traceback item
while(st_items) {
#ifdef PYTHREE
int thread_name_need_free = 0;
#endif
PyObject *st_filename = PyTuple_GetItem(st_items, 0);
if (!st_filename) { Py_DECREF(st_items); goto next; }
PyObject *st_lineno = PyTuple_GetItem(st_items, 1);
@@ -149,12 +163,26 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
if (!iov[1].iov_base) {
iov[1].iov_base = "<UnnamedPythonThread>";
}
#ifdef PYTHREE
else {
thread_name_need_free = 1;
}
#endif
iov[1].iov_len = strlen(iov[1].iov_base);
iov[2].iov_base = " filename = ";
iov[2].iov_len = 12;
#ifdef PYTHREE
PyObject *st_filename_utf8 = PyUnicode_AsUTF8String(st_filename);
if (!st_filename_utf8) {
if (thread_name_need_free) free(iov[1].iov_base);
goto next;
}
iov[3].iov_base = PyString_AsString(st_filename_utf8);
#else
iov[3].iov_base = PyString_AsString(st_filename);
#endif
iov[3].iov_len = strlen(iov[3].iov_base);
iov[4].iov_base = " lineno = ";
@@ -166,7 +194,17 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
iov[6].iov_base = " function = ";
iov[6].iov_len = 12 ;
#ifdef PYTHREE
PyObject *st_name_utf8 = PyUnicode_AsUTF8String(st_name);
if (!st_name_utf8) {
if (thread_name_need_free) free(iov[1].iov_base);
Py_DECREF(st_filename_utf8);
goto next;
}
iov[7].iov_base = PyString_AsString(st_name_utf8);
#else
iov[7].iov_base = PyString_AsString(st_name);
#endif
iov[7].iov_len = strlen(iov[7].iov_base);
iov[8].iov_base = "";
@@ -178,10 +216,24 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
iov[10].iov_base = "\n";
iov[10].iov_len = 1;
#ifdef PYTHREE
PyObject *st_line_utf8 = NULL;
#endif
if (st_line) {
iov[8].iov_base = " line = ";
iov[8].iov_len = 8;
#ifdef PYTHREE
PyObject *st_line_utf8 = PyUnicode_AsUTF8String(st_line);
if (!st_line_utf8) {
if (thread_name_need_free) free(iov[1].iov_base);
Py_DECREF(st_filename_utf8);
Py_DECREF(st_name_utf8);
goto next;
}
iov[9].iov_base = PyString_AsString(st_line_utf8);
#else
iov[9].iov_base = PyString_AsString(st_line);
#endif
iov[9].iov_len = strlen(iov[9].iov_base);
}
@@ -192,6 +244,15 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
// free the line_no
free(iov[5].iov_base);
Py_DECREF(st_items);
#ifdef PYTHREE
Py_DECREF(st_filename_utf8);
Py_DECREF(st_name_utf8);
if (st_line_utf8) {
Py_DECREF(st_line_utf8);
}
if (thread_name_need_free)
free(iov[1].iov_base);
#endif
st_items = PyIter_Next(stacktrace_iter);
}
if (write(client_fd, "\n", 1) < 0) {
+89 -3
View File
@@ -382,6 +382,11 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
if (PyString_Check(py_node)) {
node = PyString_AsString(py_node);
}
#ifdef PYTHREE
else if (PyUnicode_Check(py_node)) {
node = PyBytes_AsString(PyUnicode_AsLatin1String(py_node));
}
#endif
py_func = PyTuple_GetItem(args, 1);
@@ -1443,6 +1448,72 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_sharedarea_inc32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int32_t value = 1;
if (!PyArg_ParseTuple(args, "iL|i:sharedarea_inc32", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_inc32(id, pos, value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_inc32()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_dec64(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "iL|l:sharedarea_dec64", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_dec64(id, pos, value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_dec64()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_dec32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int32_t value = 1;
if (!PyArg_ParseTuple(args, "iL|i:sharedarea_dec32", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_dec32(id, pos, value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_dec32()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_write32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
@@ -1855,7 +1926,6 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
PyObject *spool_dict, *spool_vars;
PyObject *zero, *key, *val;
uint16_t keysize, valsize;
struct wsgi_request *wsgi_req = py_current_wsgi_req();
char *body = NULL;
size_t body_len= 0;
@@ -1956,7 +2026,8 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
UWSGI_RELEASE_GIL
char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len);
// current_wsgi_req can be NULL, in such a case a non-thread-safe counter will be used
char *filename = uwsgi_spool_request(NULL, ub->buf, ub->pos, body, body_len);
uwsgi_buffer_destroy(ub);
UWSGI_GET_GIL
@@ -1988,6 +2059,16 @@ PyObject *py_uwsgi_spooler_pid(PyObject * self, PyObject * args) {
return PyInt_FromLong(uspool->pid);
}
PyObject *py_uwsgi_spooler_pids(PyObject * self, PyObject * args) {
PyObject *ret = PyList_New(0);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
PyList_Append(ret, PyInt_FromLong(uspool->pid));
uspool = uspool->next;
}
return ret;
}
PyObject *py_uwsgi_connect(PyObject * self, PyObject * args) {
@@ -2240,7 +2321,8 @@ PyObject *py_uwsgi_stop(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_request_id(PyObject * self, PyObject * args) {
return PyLong_FromUnsignedLongLong(uwsgi.workers[uwsgi.mywid].requests);
struct wsgi_request *wsgi_req = py_current_wsgi_req();
return PyLong_FromUnsignedLongLong(uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests);
}
PyObject *py_uwsgi_worker_id(PyObject * self, PyObject * args) {
@@ -2419,6 +2501,7 @@ static PyMethodDef uwsgi_spooler_methods[] = {
{"set_spooler_frequency", py_uwsgi_spooler_freq, METH_VARARGS, ""},
{"spooler_jobs", py_uwsgi_spooler_jobs, METH_VARARGS, ""},
{"spooler_pid", py_uwsgi_spooler_pid, METH_VARARGS, ""},
{"spooler_pids", py_uwsgi_spooler_pids, METH_VARARGS, ""},
{NULL, NULL},
};
@@ -2552,6 +2635,9 @@ static PyMethodDef uwsgi_sa_methods[] = {
{"sharedarea_write16", py_uwsgi_sharedarea_write16, METH_VARARGS, ""},
{"sharedarea_inclong", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""},
{"sharedarea_inc64", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""},
{"sharedarea_inc32", py_uwsgi_sharedarea_inc32, METH_VARARGS, ""},
{"sharedarea_dec64", py_uwsgi_sharedarea_dec64, METH_VARARGS, ""},
{"sharedarea_dec32", py_uwsgi_sharedarea_dec32, METH_VARARGS, ""},
{"sharedarea_rlock", py_uwsgi_sharedarea_rlock, METH_VARARGS, ""},
{"sharedarea_wlock", py_uwsgi_sharedarea_wlock, METH_VARARGS, ""},
{"sharedarea_unlock", py_uwsgi_sharedarea_unlock, METH_VARARGS, ""},
+2
View File
@@ -299,6 +299,8 @@ int uwsgi_python_send_body(struct wsgi_request *, PyObject *);
int uwsgi_request_python_raw(struct wsgi_request *);
void uwsgi_python_set_thread_name(int);
#define py_current_wsgi_req() current_wsgi_req();\
if (!wsgi_req) {\
return PyErr_Format(PyExc_SystemError, "you can call uwsgi api function only from the main callable");\
+1 -2
View File
@@ -969,7 +969,6 @@ static int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
struct wsgi_request *wsgi_req = current_wsgi_req();
char *body = NULL;
size_t body_len= 0;
@@ -991,7 +990,7 @@ static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) ub);
char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len);
char *filename = uwsgi_spool_request(NULL, ub->buf, ub->pos, body, body_len);
uwsgi_buffer_destroy(ub);
+492 -93
View File
@@ -6,27 +6,55 @@ extern struct uwsgi_server uwsgi;
/*
Author: Javier Guerra
Author: Marcin Deranek
Author: Roberto De Ioris
based on the uWSGI GlusterFS plugin by Roberto De Ioris
--rados-mount mountpoint=/foo,pool=unbit001,config=/etc/ceph.conf
--rados-mount mountpoint=/foo,pool=unbit001,config=/etc/ceph.conf,timeout=30,allow_put=1,allow_delete=1
*/
struct uwsgi_plugin rados_plugin;
struct uwsgi_rados {
// this structure is preallocated (only the pipe part is per-request)
struct uwsgi_rados_io {
int fds[2];
// this is increased at every usage (in locked context)
uint64_t rid;
pthread_mutex_t mutex;
};
// this structure is allocated for each async transaction
struct uwsgi_rados_cb {
// this is copied from the current uwsgi_rados_io->rid
uint64_t rid;
struct uwsgi_rados_io *urio;
};
static struct uwsgi_rados {
int timeout;
struct uwsgi_string_list *mountpoints;
struct uwsgi_rados_io *urio;
} urados;
struct uwsgi_rados_mountpoint {
rados_t cluster;
char *mountpoint;
char *config;
char *pool;
char *str_timeout;
int timeout;
char *allow_put;
char *allow_delete;
char *allow_mkcol;
};
static struct uwsgi_option uwsgi_rados_options[] = {
{"rados-mount", required_argument, 0, "virtual mount the specified rados volume in a uri", uwsgi_opt_add_string_list, &urados.mountpoints, UWSGI_OPT_MIME},
{"rados-timeout", required_argument, 0, "timeout for async operations", uwsgi_opt_set_int, &urados.timeout, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static int uwsgi_rados_read_sync(struct wsgi_request *wsgi_req, rados_ioctx_t *ctx, const char *key, size_t remains) {
static int uwsgi_rados_read_sync(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, const char *key, size_t remains) {
uint64_t off = 0;
while(remains > 0) {
char buf[8192];
@@ -39,119 +67,354 @@ static int uwsgi_rados_read_sync(struct wsgi_request *wsgi_req, rados_ioctx_t *c
return 0;
}
/*
async read of a resource
the uwsgi_rados_async_io structure is passed between threads
the callback simply signal the main core about the availability of data
*/
struct uwsgi_rados_async_io {
int fd[2];
ssize_t rlen;
};
// callback used to asynchronously signal the completion
static void uwsgi_rados_read_async_cb(rados_completion_t comp, void *data) {
struct uwsgi_rados_async_io *aio = (struct uwsgi_rados_async_io *) data;
#ifdef UWSGI_DEBUG
uwsgi_log("[rados-cb] rlen = %d\n", rlen);
#endif
aio->rlen = rados_aio_get_return_value(comp);
// signal the core
if (write(aio->fd[1], "\1", 1) <= 0) {
uwsgi_error("uwsgi_rados_read_async_cb()/write()");
struct uwsgi_rados_cb *urcb = (struct uwsgi_rados_cb *) data;
struct uwsgi_rados_io *urio = urcb->urio;
pthread_mutex_lock(&urio->mutex);
if (urcb->rid != urio->rid) {
uwsgi_log_verbose("[uwsgi-rados] callback %llu woke up too late\n", (unsigned long long) urcb->rid);
}
else {
// signal the core
if (write(urio->fds[1], "\1", 1) <= 0) {
uwsgi_error("uwsgi_rados_read_async_cb()/write()");
}
}
pthread_mutex_unlock(&urio->mutex);
free(urcb);
}
static int uwsgi_rados_read_async(struct wsgi_request *wsgi_req, rados_ioctx_t *ctx, const char *key, size_t remains) {
uint64_t off = 0;
char buf[8192];
struct uwsgi_rados_async_io aio;
static int uwsgi_rados_delete(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, int timeout) {
if (uwsgi.async <= 1) {
return rados_remove(ctx, key);
}
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
int ret = -1;
if (pipe(aio.fd)) {
uwsgi_error("uwsgi_rados_read_async()/pipe()");
return -1;
}
aio.rlen = -1;
rados_completion_t comp;
if (rados_aio_create_completion(&aio, uwsgi_rados_read_async_cb, NULL, &comp) < 0) goto end;
while(remains > 0) {
// trigger an async read
if (rados_aio_read(ctx, key, comp, buf, 8192, off) < 0) goto end;
// wait for the callback to be executed
if (uwsgi.wait_read_hook(aio.fd[0], urados.timeout) <= 0) goto end;
if (aio.rlen <= 0) goto end;
if (uwsgi_response_write_body_do(wsgi_req, buf, aio.rlen)) goto end;
remains -= aio.rlen;
}
ret = 0;
// increase request counter
pthread_mutex_lock(&urio->mutex);
urio->rid++;
pthread_mutex_unlock(&urio->mutex);
struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb));
// map the current request id to the callback
urcb->rid = urio->rid;
// map urio to the callback
urcb->urio = urio;
rados_completion_t comp;
// we use the safe cb here
if (rados_aio_create_completion(urcb, NULL, uwsgi_rados_read_async_cb, &comp) < 0) {
free(urcb);
goto end;
}
if (rados_aio_remove(ctx, key, comp) < 0) {
free(urcb);
rados_aio_release(comp);
goto end;
}
// wait for the callback to be executed
if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) {
rados_aio_release(comp);
goto end;
}
char ack = 1;
if (read(urio->fds[0], &ack, 1) != 1) {
rados_aio_release(comp);
uwsgi_error("uwsgi_rados_delete()/read()");
goto end;
}
if (rados_aio_is_safe_and_cb(comp)) {
ret = rados_aio_get_return_value(comp);
}
rados_aio_release(comp);
end:
rados_aio_release(&comp);
close(aio.fd[0]);
close(aio.fd[1]);
return ret;
}
static int uwsgi_rados_put(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, int timeout) {
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
size_t remains = wsgi_req->post_cl;
uint64_t off = 0;
while(remains > 0) {
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768) , &body_len);
if (!body || body == uwsgi.empty) goto error;
if (uwsgi.async <= 1) {
if (rados_write_full(ctx, key, body, body_len) < 0) {
return -1;
}
}
else {
// increase request counter
pthread_mutex_lock(&urio->mutex);
urio->rid++;
pthread_mutex_unlock(&urio->mutex);
struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb));
// map the current request id to the callback
urcb->rid = urio->rid;
// map urio to the callback
urcb->urio = urio;
rados_completion_t comp;
// use safe for write
if (rados_aio_create_completion(urcb, NULL, uwsgi_rados_read_async_cb, &comp) < 0) {
free(urcb);
goto error;
}
if (rados_aio_write_full(ctx, key, comp, body, body_len) < 0) {
free(urcb);
rados_aio_release(comp);
goto error;
}
// wait for the callback to be executed
if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) {
rados_aio_release(comp);
goto error;
}
char ack = 1;
if (read(urio->fds[0], &ack, 1) != 1) {
rados_aio_release(comp);
uwsgi_error("uwsgi_rados_read_async()/read()");
goto error;
}
if (rados_aio_is_safe_and_cb(comp)) {
if (rados_aio_get_return_value(comp) < 0) {
rados_aio_release(comp);
goto error;
}
}
rados_aio_release(comp);
}
remains -= body_len;
off += body_len;
}
return 0;
error:
return -1;
}
// async stat
static int uwsgi_rados_async_stat(struct uwsgi_rados_io *urio, rados_ioctx_t ctx, const char *key, uint64_t *stat_size, time_t *stat_mtime, int timeout) {
int ret = -1;
// increase request counter
pthread_mutex_lock(&urio->mutex);
urio->rid++;
pthread_mutex_unlock(&urio->mutex);
struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb));
// map the current request id to the callback
urcb->rid = urio->rid;
// map urio to the callback
urcb->urio = urio;
rados_completion_t comp;
if (rados_aio_create_completion(urcb, uwsgi_rados_read_async_cb, NULL, &comp) < 0) {
free(urcb);
goto end;
}
if (rados_aio_stat(ctx, key, comp, stat_size, stat_mtime) < 0) {
free(urcb);
rados_aio_release(comp);
goto end;
}
// wait for the callback to be executed
if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) {
rados_aio_release(comp);
goto end;
}
char ack = 1;
if (read(urio->fds[0], &ack, 1) != 1) {
rados_aio_release(comp);
uwsgi_error("uwsgi_rados_read_async()/read()");
goto end;
}
if (rados_aio_is_complete_and_cb(comp)) {
ret = rados_aio_get_return_value(comp);
}
rados_aio_release(comp);
end:
return ret;
}
static int uwsgi_rados_read_async(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, const char *key, size_t remains, int timeout) {
uint64_t off = 0;
int ret = -1;
char buf[8192];
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
// increase request counter
pthread_mutex_lock(&urio->mutex);
urio->rid++;
pthread_mutex_unlock(&urio->mutex);
while(remains > 0) {
struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb));
// map the current request id to the callback
urcb->rid = urio->rid;
// map urio to the callback
urcb->urio = urio;
rados_completion_t comp;
if (rados_aio_create_completion(urcb, uwsgi_rados_read_async_cb, NULL, &comp) < 0) {
free(urcb);
break;
}
// trigger an async read
if (rados_aio_read(ctx, key, comp, buf, UMIN(remains, 8192), off) < 0) {
free(urcb);
rados_aio_release(comp);
break;
}
// wait for the callback to be executed
if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) {
rados_aio_release(comp);
break;
}
char ack = 1;
if (read(urio->fds[0], &ack, 1) != 1) {
rados_aio_release(comp);
uwsgi_error("uwsgi_rados_read_async()/read()");
break;
}
int rlen = -1;
if (rados_aio_is_complete_and_cb(comp)) {
rlen = rados_aio_get_return_value(comp);
}
rados_aio_release(comp);
if (rlen <= 0) break;
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) break;
remains -= rlen;
off += rlen;
}
if (remains == 0) ret = 0;
pthread_mutex_lock(&urio->mutex);
// increase the counter again
urio->rid++;
pthread_mutex_unlock(&urio->mutex);
return ret;
}
static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) {
char *rad_mountpoint = NULL;
char *rad_config = NULL;
char *rad_poolname = NULL;
struct uwsgi_rados_mountpoint *urmp = uwsgi_calloc(sizeof(struct uwsgi_rados_mountpoint));
if (uwsgi_kvlist_parse(arg, arg_len, ',', '=',
"mountpoint", &rad_mountpoint,
"config", &rad_config,
"pool", &rad_poolname,
"mountpoint", &urmp->mountpoint,
"config", &urmp->config,
"pool", &urmp->pool,
"timeout", &urmp->str_timeout,
"allow_put", &urmp->allow_put,
"allow_delete", &urmp->allow_delete,
"allow_mkcol", &urmp->allow_mkcol,
NULL)) {
uwsgi_log("unable to parse rados mountpoint definition\n");
exit(1);
}
if (!rad_mountpoint|| !rad_poolname) {
if (!urmp->mountpoint|| !urmp->pool) {
uwsgi_log("[rados] mount requires a mountpoint, and a pool name.\n");
exit(1);
}
if (urmp->str_timeout) {
urmp->timeout = atoi(urmp->str_timeout);
}
time_t now = uwsgi_now();
uwsgi_log("[rados] mounting %s ...\n", rad_mountpoint);
uwsgi_log("[rados] mounting %s ...\n", urmp->mountpoint);
rados_t cluster;
if (rados_create(&cluster, NULL) < 0) {
uwsgi_error("Can't create Ceph cluster handle");
uwsgi_error("can't create Ceph cluster handle");
exit(1);
}
if (rad_config)
uwsgi_log("Using Ceph conf:%s\n", rad_config);
urmp->cluster = cluster;
if (urmp->config)
uwsgi_log("using Ceph conf:%s\n", urmp->config);
else
uwsgi_log("Using default Ceph conf.\n");
if (rados_conf_read_file(cluster, rad_config) < 0) {
uwsgi_error("Can't configure Ceph cluster handle");
uwsgi_log("using default Ceph conf.\n");
if (rados_conf_read_file(cluster, urmp->config) < 0) {
uwsgi_error("can't configure Ceph cluster handle");
exit(1);
}
int timeout = urmp->timeout ? urmp->timeout : urados.timeout;
char *timeout_str = uwsgi_num2str(timeout);
rados_conf_set(cluster, "client_mount_timeout", timeout_str);
rados_conf_set(cluster, "rados_mon_op_timeout", timeout_str);
rados_conf_set(cluster, "rados_osd_op_timeout", timeout_str);
free(timeout_str);
if (rados_connect(cluster) < 0) {
uwsgi_error("Can't connect with Ceph cluster");
uwsgi_error("can't connect with Ceph cluster");
exit(1);
}
rados_ioctx_t ctx;
uwsgi_log("Ceph pool: %s\n", rad_poolname);
if (rados_ioctx_create(cluster, rad_poolname, &ctx) < 0) {
uwsgi_error("Can't open rados pool")
rados_shutdown(cluster);
exit(1);
void *ctx_ptr;
if (uwsgi.threads > 1) {
int i;
rados_ioctx_t *ctxes = uwsgi_calloc(sizeof(rados_ioctx_t) * uwsgi.threads);
for(i=0;i<uwsgi.threads;i++) {
if (rados_ioctx_create(cluster, urmp->pool, &ctxes[i]) < 0) {
uwsgi_error("can't open rados pool")
rados_shutdown(cluster);
exit(1);
}
}
ctx_ptr = ctxes;
}
else {
rados_ioctx_t ctx;
if (rados_ioctx_create(cluster, urmp->pool, &ctx) < 0) {
uwsgi_error("can't open rados pool")
rados_shutdown(cluster);
exit(1);
}
ctx_ptr = ctx;
}
char fsid[37];
rados_cluster_fsid(cluster, fsid, 37);
uwsgi_log("connected to Ceph pool: %s on cluster %.*s\n", urmp->pool, 37, fsid);
int id = uwsgi_apps_cnt;
struct uwsgi_app *ua = uwsgi_add_app(id, rados_plugin.modifier1, rad_mountpoint, strlen(rad_mountpoint), NULL, NULL);
struct uwsgi_app *ua = uwsgi_add_app(id, rados_plugin.modifier1, urmp->mountpoint, strlen(urmp->mountpoint), NULL, NULL);
if (!ua) {
uwsgi_log("[rados] unable to mount %s\n", rad_mountpoint);
uwsgi_log("[rados] unable to mount %s\n", urmp->mountpoint);
rados_shutdown(cluster);
exit(1);
}
ua->responder0 = cluster;
ua->responder1 = ctx;
ua->responder0 = ctx_ptr;
ua->responder1 = urmp;
ua->started_at = now;
ua->startup_time = uwsgi_now() - now;
uwsgi_log("Rados app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, rad_mountpoint, (int) ua->startup_time, ctx);
uwsgi_log("Rados app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, urmp->mountpoint, (int) ua->startup_time, ctx_ptr);
}
// we translate the string list to an app representation
@@ -166,6 +429,21 @@ static void uwsgi_rados_setup() {
uwsgi_rados_add_mountpoint(usl->value, usl->len);
usl = usl->next;
}
// now initialize a pthread_mutex for each async core
if (uwsgi.async > 1) {
int i;
urados.urio = uwsgi_calloc(sizeof(struct uwsgi_rados_io) * uwsgi.async);
for(i=0;i<uwsgi.async;i++) {
urados.urio[i].fds[0] = -1;
urados.urio[i].fds[1] = -1;
if (pthread_mutex_init(&urados.urio[i].mutex, NULL)) {
uwsgi_error("uwsgi_rados_setup()/pthread_mutex_init()");
exit(1);
}
}
}
}
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
@@ -199,29 +477,146 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
if (wsgi_req->path_info_len > ua->mountpoint_len &&
memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0)
{
memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) {
memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len);
filename[wsgi_req->path_info_len-ua->mountpoint_len] = 0;
} else {
memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len);
filename[wsgi_req->path_info_len] = 0;
}
filename[wsgi_req->path_info_len] = 0;
struct {
uint64_t size;
time_t mtime;
} st;
rados_ioctx_t ctx = ua->responder1;
// in multithread mode the memory is different (as we need a ctx for each thread) !!!
rados_ioctx_t ctx;
if (uwsgi.threads > 1) {
rados_ioctx_t *ctxes = (rados_ioctx_t *) ua->responder0;
ctx = ctxes[wsgi_req->async_id];
}
else {
ctx = (rados_ioctx_t) ua->responder0;
}
struct uwsgi_rados_mountpoint *urmp = (struct uwsgi_rados_mountpoint *) ua->responder1;
uint64_t stat_size = 0;
time_t stat_mtime = 0;
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
if (uwsgi.async > 1) {
// no need to lock here (the rid protect us)
if (pipe(urio->fds)) {
uwsgi_error("uwsgi_rados_read_async()/pipe()");
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
}
int r = rados_stat(ctx, filename, &st.size, &st.mtime);
if (r < 0) {
if (r == -ENOENT)
int ret = -1;
int timeout = urmp->timeout ? urmp->timeout : urados.timeout;
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
if (uwsgi_response_add_header(wsgi_req, "Dav", 3, "1", 1)) goto end;
struct uwsgi_buffer *ub_allow = uwsgi_buffer_new(64);
if (uwsgi_buffer_append(ub_allow, "OPTIONS, GET, HEAD", 18)) {
uwsgi_buffer_destroy(ub_allow);
goto end;
}
if (urmp->allow_put) {
if (uwsgi_buffer_append(ub_allow, ", PUT", 5)) {
uwsgi_buffer_destroy(ub_allow);
goto end;
}
}
if (urmp->allow_delete) {
if (uwsgi_buffer_append(ub_allow, ", DELETE", 8)) {
uwsgi_buffer_destroy(ub_allow);
goto end;
}
}
if (urmp->allow_mkcol) {
if (uwsgi_buffer_append(ub_allow, ", MKCOL", 7)) {
uwsgi_buffer_destroy(ub_allow);
goto end;
}
}
uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos);
uwsgi_buffer_destroy(ub_allow);
goto end;
}
// MKCOL does not require stat
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) {
if (!urmp->allow_mkcol) {
uwsgi_405(wsgi_req);
goto end;
}
ret = rados_pool_create(urmp->cluster, filename);
if (ret < 0) {
if (ret == -EEXIST) {
uwsgi_405(wsgi_req);
}
else {
uwsgi_500(wsgi_req);
}
goto end;
}
uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);
goto end;
}
if (uwsgi.async > 1) {
ret = uwsgi_rados_async_stat(urio, ctx, filename, &stat_size, &stat_mtime, timeout);
}
else {
ret = rados_stat(ctx, filename, &stat_size, &stat_mtime);
}
// PUT AND MKCOL can be used for non-existent objects
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) {
if (!urmp->allow_put) {
uwsgi_405(wsgi_req);
goto end;
}
if (ret == 0) {
if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) {
uwsgi_500(wsgi_req);
goto end;
}
}
if (uwsgi_rados_put(wsgi_req, ctx, filename, timeout)) {
uwsgi_500(wsgi_req);
goto end;
}
uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);
goto end;
}
else if (ret < 0) {
if (ret == -ENOENT)
uwsgi_404(wsgi_req);
else
uwsgi_403(wsgi_req);
return UWSGI_OK;
goto end;
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) {
if (!urmp->allow_delete) {
uwsgi_405(wsgi_req);
goto end;
}
if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) {
uwsgi_403(wsgi_req);
goto end;
}
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
goto end;
}
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) {
uwsgi_405(wsgi_req);
goto end;
}
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
size_t mime_type_len = 0;
@@ -230,14 +625,14 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end;
}
if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.mtime)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, st.size)) goto end;
if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) stat_mtime)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, stat_size)) goto end;
// skip body on HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
size_t remains = st.size;
size_t remains = stat_size;
if (uwsgi.async > 1) {
if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains)) goto end;
if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains, timeout)) goto end;
}
else {
if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, remains)) goto end;
@@ -245,6 +640,10 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
}
end:
if (uwsgi.async > 1) {
close(urio->fds[0]);
close(urio->fds[1]);
}
return UWSGI_OK;
}
+1 -1
View File
@@ -245,7 +245,7 @@ static int rawrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_ga
peer->last_hook_read = rr_instance_read;
// use the address as hostname
peer->key = cs->ugs->name;
memcpy(peer->key, cs->ugs->name, cs->ugs->name_len);
peer->key_len = cs->ugs->name_len;
// the mapper hook
+9
View File
@@ -30,6 +30,9 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
if (ur->custom & 0x02) {
ub = uwsgi_buffer_new(uwsgi.page_size);
}
else if (ur->custom & 0x04) {
ub = uwsgi_to_http_dumb(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
}
else {
ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
}
@@ -133,10 +136,16 @@ static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) {
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_httpdumb(struct uwsgi_route *ur, char *args) {
ur->custom = 0x04;
return uwsgi_router_http(ur, args);
}
static void router_http_register(void) {
uwsgi_register_router("http", uwsgi_router_http);
uwsgi_register_router("httpdumb", uwsgi_router_httpdumb);
uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp);
uwsgi_register_router("httpconnect", uwsgi_router_http_connect);
uwsgi_register_router("proxyhttpconnect", uwsgi_router_proxyhttp_connect);
+7 -4
View File
@@ -387,6 +387,7 @@ end:
}
static int uwsgi_routing_func_rpc_raw(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *response = NULL;
int ret = -1;
// this is the list of args
char *argv[UMAX8];
@@ -418,7 +419,7 @@ static int uwsgi_routing_func_rpc_raw(struct wsgi_request *wsgi_req, struct uwsg
remote = at+1;
}
uint64_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
@@ -426,12 +427,13 @@ static int uwsgi_routing_func_rpc_raw(struct wsgi_request *wsgi_req, struct uwsg
if (size == 0) goto end;
ret = uwsgi_blob_to_response(wsgi_req, response, size);
free(response);
if (ret == 0) {
ret = UWSGI_ROUTE_BREAK;
}
end:
free(response);
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
@@ -441,6 +443,7 @@ end:
}
static int uwsgi_routing_func_rpc_var(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *response = NULL;
int ret = -1;
// this is the list of args
char *argv[UMAX8];
@@ -472,7 +475,7 @@ static int uwsgi_routing_func_rpc_var(struct wsgi_request *wsgi_req, struct uwsg
remote = at+1;
}
uint64_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
@@ -483,9 +486,9 @@ static int uwsgi_routing_func_rpc_var(struct wsgi_request *wsgi_req, struct uwsg
free(response);
goto end;
}
free(response);
ret = UWSGI_ROUTE_NEXT;
end:
free(response);
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
+12 -2
View File
@@ -31,7 +31,12 @@ ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
exit(1);
}
ul->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (ul->arg[0] == '/') {
ul->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
}
else {
ul->fd = socket(AF_INET, SOCK_DGRAM, 0);
}
if (ul->fd < 0) {
uwsgi_error_safe("socket()");
exit(1);
@@ -62,7 +67,12 @@ ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
*port = 0;
}
ul->addr_len = socket_to_in_addr(ul->arg, NULL, portn, &ul->addr.sa_in);
if (ul->arg[0] == '/') {
ul->addr_len = socket_to_un_addr(ul->arg, &ul->addr.sa_un);
}
else {
ul->addr_len = socket_to_in_addr(ul->arg, NULL, portn, &ul->addr.sa_in);
}
if (port) *port = ':';
if (comma) *comma = ',';
+1 -1
View File
@@ -23,7 +23,7 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
return -1;
}
char *filename = uwsgi_spool_request(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0);
char *filename = uwsgi_spool_request(NULL, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0);
uh.modifier1 = 255;
uh.pktsize = 0;
if (filename) {
+7 -5
View File
@@ -250,7 +250,8 @@ static ssize_t sr_write(struct corerouter_peer *main_peer) {
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_cr_error(main_peer, "sr_write()");
if (errno != 0)
uwsgi_cr_error(main_peer, "sr_write()");
}
else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
@@ -288,15 +289,15 @@ static ssize_t sr_read(struct corerouter_peer *main_peer) {
// set default peer hook
peer->last_hook_read = sr_instance_read;
// use the address as hostname
peer->key = cs->ugs->name;
memcpy(peer->key, cs->ugs->name, cs->ugs->name_len);
peer->key_len = cs->ugs->name_len;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if (usr.sni) {
const char *servername = SSL_get_servername(sr->ssl, TLSEXT_NAMETYPE_host_name);
if (servername) {
peer->key = (char *) servername;
if (servername && strlen(servername) <= 0xff) {
peer->key_len = strlen(servername);
memcpy(peer->key, servername, peer->key_len);
}
}
#endif
@@ -332,7 +333,8 @@ static ssize_t sr_read(struct corerouter_peer *main_peer) {
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_cr_error(main_peer, "sr_ssl_read()");
if (errno != 0)
uwsgi_cr_error(main_peer, "sr_ssl_read()");
}
else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
+1 -1
View File
@@ -92,7 +92,7 @@ static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g");
}
else {
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|m");
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|c");
}
uwsgi_rwunlock(uwsgi.metrics_lock);
if (um->reset_after_push){
+1 -1
View File
@@ -10,7 +10,7 @@ ssize_t uwsgi_systemd_logger(struct uwsgi_logger *ul, char *message, size_t len)
for(i=0;i<len;i++) {
if (message[i] == '\n') {
message[i] = 0;
sd_journal_print(LOG_INFO, base);
sd_journal_print(LOG_INFO, "%s", base);
base = message+i+1;
}
}
+8 -3
View File
@@ -24,7 +24,7 @@ static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transforma
struct uwsgi_buffer *ub = ut->chunk;
if (ut->is_final) {
if (uwsgi_gzip_fix(&utgz->z, utgz->crc32, ub, utgz->len)) {
if (utgz->len > 0 && uwsgi_gzip_fix(&utgz->z, utgz->crc32, ub, utgz->len)) {
free(utgz);
return -1;
}
@@ -32,6 +32,11 @@ static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transforma
return 0;
}
if (ub->pos == 0) {
// Don't try to compress empty responses.
return 0;
}
size_t dlen = 0;
char *gzipped = uwsgi_gzip_chunk(&utgz->z, &utgz->crc32, ub->buf, ub->pos, &dlen);
if (!gzipped) return -1;
@@ -39,7 +44,7 @@ static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transforma
uwsgi_buffer_map(ub, gzipped, dlen);
if (!utgz->header) {
// do not check for errors !!!
uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4);
uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4);
utgz->header = 1;
if (uwsgi_buffer_insert(ub, 0, gzheader, 10)) {
return -1;
@@ -59,7 +64,7 @@ static int uwsgi_routing_func_gzip(struct wsgi_request *wsgi_req, struct uwsgi_r
ut->can_stream = 1;
// this is the trasformation clearing the memory
ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz);
ut->is_final = 1;
ut->is_final = 1;
return UWSGI_ROUTE_NEXT;
}
+4 -2
View File
@@ -287,7 +287,8 @@ retry:
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_error("uwsgi_proto_ssl_write()/SSL_write()");
if (errno != 0)
uwsgi_error("uwsgi_proto_ssl_write()/SSL_write()");
}
return -1;
@@ -383,7 +384,8 @@ retry:
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_error("uwsgi_proto_ssl_read_body()/SSL_read()");
if (errno != 0)
uwsgi_error("uwsgi_proto_ssl_read_body()/SSL_read()");
}
return -1;
+94 -9
View File
@@ -49,7 +49,7 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, s
if (buffer + keylen + hvlen + 2 + 2 >= watermark) {
if (has_prefix) {
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen-5, hh, hvlen, hv);
}
else {
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
@@ -423,7 +423,7 @@ static int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
}
// mute on 0 len...
if (wsgi_req->proto_parser_pos > 0) {
uwsgi_log("uwsgi_proto_http_parser() -> client closed connection");
uwsgi_log("uwsgi_proto_http_parser() -> client closed connection\n");
}
return -1;
@@ -480,6 +480,96 @@ static void uwsgi_httpize_var(char *buf, size_t len) {
}
}
struct uwsgi_buffer *uwsgi_to_http_dumb(struct wsgi_request *wsgi_req, char *host, uint16_t host_len, char *uri, uint16_t uri_len) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto clear;
if (uwsgi_buffer_append(ub, " ", 1)) goto clear;
if (uri_len && uri) {
if (uwsgi_buffer_append(ub, uri, uri_len)) goto clear;
}
else {
if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto clear;
}
if (uwsgi_buffer_append(ub, " ", 1)) goto clear;
if (uwsgi_buffer_append(ub, wsgi_req->protocol, wsgi_req->protocol_len)) goto clear;
if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear;
int i;
char *x_forwarded_for = NULL;
size_t x_forwarded_for_len = 0;
// start adding headers
for(i=0;i<wsgi_req->var_cnt;i++) {
if (!uwsgi_starts_with(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, "HTTP_", 5)) {
char *header = wsgi_req->hvec[i].iov_base+5;
size_t header_len = wsgi_req->hvec[i].iov_len-5;
if (host && !uwsgi_strncmp(header, header_len, "HOST", 4)) goto next;
if (!uwsgi_strncmp(header, header_len, "X_FORWARDED_FOR", 15)) {
x_forwarded_for = wsgi_req->hvec[i+1].iov_base;
x_forwarded_for_len = wsgi_req->hvec[i+1].iov_len;
goto next;
}
if (uwsgi_buffer_append(ub, header, header_len)) goto clear;
// transofmr uwsgi var to http header
uwsgi_httpize_var((ub->buf+ub->pos) - header_len, header_len);
if (uwsgi_buffer_append(ub, ": ", 2)) goto clear;
if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto clear;
if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear;
}
next:
i++;
}
// append custom Host (if needed)
if (host) {
if (uwsgi_buffer_append(ub, "Host: ", 6)) goto clear;
if (uwsgi_buffer_append(ub, host, host_len)) goto clear;
if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear;
}
if (wsgi_req->content_type_len > 0) {
if (uwsgi_buffer_append(ub, "Content-Type: ", 14)) goto clear;
if (uwsgi_buffer_append(ub, wsgi_req->content_type, wsgi_req->content_type_len)) goto clear;
if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear;
}
if (wsgi_req->post_cl > 0) {
if (uwsgi_buffer_append(ub, "Content-Length: ", 16)) goto clear;
if (uwsgi_buffer_num64(ub, (int64_t) wsgi_req->post_cl)) goto clear;
if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear;
}
// append required headers
if (uwsgi_buffer_append(ub, "X-Forwarded-For: ", 17)) goto clear;
if (x_forwarded_for_len > 0) {
if (uwsgi_buffer_append(ub, x_forwarded_for, x_forwarded_for_len)) goto clear;
if (uwsgi_buffer_append(ub, ", ", 2)) goto clear;
}
if (uwsgi_buffer_append(ub, wsgi_req->remote_addr, wsgi_req->remote_addr_len)) goto clear;
if (uwsgi_buffer_append(ub, "\r\n\r\n", 4)) goto clear;
return ub;
clear:
uwsgi_buffer_destroy(ub);
return NULL;
}
struct uwsgi_buffer *uwsgi_to_http(struct wsgi_request *wsgi_req, char *host, uint16_t host_len, char *uri, uint16_t uri_len) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
@@ -513,14 +603,8 @@ struct uwsgi_buffer *uwsgi_to_http(struct wsgi_request *wsgi_req, char *host, ui
// remove dangerous headers
if (!uwsgi_strncmp(header, header_len, "CONNECTION", 10)) goto next;
if (!uwsgi_strncmp(header, header_len, "KEEP_ALIVE", 10)) goto next;
if (!uwsgi_strncmp(header, header_len, "ACCEPT_ENCODING", 15)) goto next;
if (!uwsgi_strncmp(header, header_len, "TE", 2)) goto next;
if (!uwsgi_strncmp(header, header_len, "TRAILER", 7)) goto next;
if (!uwsgi_strncmp(header, header_len, "IF_MATCH", 8)) goto next;
if (!uwsgi_strncmp(header, header_len, "IF_MODIFIED_SINCE", 17)) goto next;
if (!uwsgi_strncmp(header, header_len, "IF_RANGE", 8)) goto next;
if (!uwsgi_strncmp(header, header_len, "IF_UNMODIFIED_SINCE", 19)) goto next;
if (!uwsgi_strncmp(header, header_len, "IF_NONE_MATCH", 13)) goto next;
if (!uwsgi_strncmp(header, header_len, "X_FORWARDED_FOR", 15)) {
x_forwarded_for = wsgi_req->hvec[i+1].iov_base;
x_forwarded_for_len = wsgi_req->hvec[i+1].iov_len;
@@ -676,7 +760,8 @@ retry:
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_error("uwsgi_proto_https_parser()/SSL_read()");
if (errno != 0)
uwsgi_error("uwsgi_proto_https_parser()/SSL_read()");
}
return -1;
empty:
+2 -1
View File
@@ -83,7 +83,8 @@ retry:
}
else if (err == SSL_ERROR_SYSCALL) {
uwsgi_error("uwsgi_proto_suwsgi_parser()/SSL_read()");
if (errno != 0)
uwsgi_error("uwsgi_proto_suwsgi_parser()/SSL_read()");
}
return -1;
+10
View File
@@ -0,0 +1,10 @@
#uwsgi --psgi t/perl/active_workers_signal.pl -s :3031 --perl-no-plack --timer "17 3" -p 8 --cheap --idle 10
my $handler = sub {
print "hello i am the signal handler on worker ".uwsgi::worker_id()."\n";
};
uwsgi::register_signal(17, 'active-workers', $handler);
my $app = sub {
};
+19
View File
@@ -0,0 +1,19 @@
use strict;
use warnings;
{
package psgix::harakiri::tester;
sub DESTROY { print STDERR "$$: Calling DESTROY\n" }
}
sub {
my $env = shift;
die "PANIC: We should support psgix.harakiri here" unless $env->{'psgix.harakiri'};
$env->{'psgix.harakiri.tester'} = bless {} => 'psgix::harakiri::tester';
my $harakiri = $env->{QUERY_STRING};
$env->{'psgix.harakiri.commit'} = $harakiri ? 1 : 0;
return [200, [], [ $harakiri ? "We are about to destroy ourselves\n" : "We will live for another request\n" ]];
}
+4
View File
@@ -0,0 +1,4 @@
# uwsgi --route-run remheader:Content-Length --route-run forcecl: --wsgi-file t/python/forcecl.py --http-socket :9090
def application(e, sr):
sr('200 OK', [('Content-Length', '1'), ('Content-Length', '2')])
return ['xxx']
@@ -0,0 +1,13 @@
[uwsgi]
http-socket = :8080
master = 1
; Three apps on three mountpoints
wsgi-file = %d/useless_app.py
mount = /foo=%d/useless_app.py
mount = /foobis/=%d/useless_app.py
mount = /footris/=%d/useless_app.py
manage-script-name = 1
@@ -0,0 +1,59 @@
#! /usr/bin/env python3
# coding = utf-8
# author = Adriano Di Luzio
# I require requests!
"""
First run:
$ ./uwsgi t/python/manage_script_name/manage_script_name_test.ini
Then run me!
"""
import unittest
import requests
HOST = "http://127.0.0.1:8080"
class ManageScriptNameTest(unittest.TestCase):
def test_classic_mountpoints(self):
mps = {
"/foo",
"/foobis/",
"/footris/"
}
for mp in mps:
# Requests to /foo should kick-in the managed script name.
r = requests.get(HOST + mp)
self.assertEqual(r.text, mp)
ends = mp.endswith("/")
# And equally requests to /foo/
r = requests.get(
HOST + mp + "/") if not ends else requests.get(HOST + mp[:-1])
self.assertEqual(r.text, mp)
# Or correct requests (/foo/resource)
r = requests.get(
HOST + mp + "/" + "resource") if not ends else requests.get(HOST + mp + "resource")
self.assertEqual(r.text, mp)
def test_intriguing_mountpoints(self):
mps = {
"/fooanything",
"/foobisis/",
"/foofighters",
}
for mp in mps:
r = requests.get(HOST + mp)
self.assertEqual(r.text, "")
if __name__ == '__main__':
unittest.main(verbosity=2)
@@ -0,0 +1,3 @@
def application(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return env['SCRIPT_NAME']
+6
View File
@@ -0,0 +1,6 @@
[uwsgi]
socket = /tmp/foo
sharedarea = size=4300000000
pyrun = t/sharedarea/%n.py
+16
View File
@@ -0,0 +1,16 @@
import uwsgi
import unittest
class SharedareaTest(unittest.TestCase):
def test_32(self):
pos = 2L * (1024L ** 3)
uwsgi.sharedarea_write32(0, pos, 17)
self.assertEqual(uwsgi.sharedarea_read32(0, pos), 17)
def test_64(self):
pos = 2L * (1024L ** 3)
uwsgi.sharedarea_write64(0, pos, 30)
self.assertEqual(uwsgi.sharedarea_read64(0, pos), 30)
unittest.main()
+6
View File
@@ -0,0 +1,6 @@
[uwsgi]
socket = /tmp/foo
sharedarea = size=64
pyrun = t/sharedarea/%n.py
+34
View File
@@ -0,0 +1,34 @@
import uwsgi
import unittest
class SharedareaTest(unittest.TestCase):
def setUp(self):
uwsgi.sharedarea_write(0, 0, '\0' * 64)
def test_32(self):
uwsgi.sharedarea_write32(0, 0, 17)
self.assertEqual(uwsgi.sharedarea_read32(0, 0), 17)
def test_inc32(self):
uwsgi.sharedarea_write32(0, 4, 30)
uwsgi.sharedarea_inc32(0, 4, 3)
self.assertEqual(uwsgi.sharedarea_read32(0, 4), 33)
def test_dec32(self):
uwsgi.sharedarea_write32(0, 5, 30)
uwsgi.sharedarea_dec32(0, 5, 4)
self.assertEqual(uwsgi.sharedarea_read32(0, 5), 26)
def test_inc64(self):
uwsgi.sharedarea_write64(0, 8, 17 * (1024 ** 5))
uwsgi.sharedarea_inc64(0, 8, 1)
self.assertEqual(uwsgi.sharedarea_read64(0, 8), 17 * (1024 ** 5) + 1)
def test_dec64(self):
uwsgi.sharedarea_write64(0, 8, 30 * (1024 ** 5))
uwsgi.sharedarea_dec64(0, 8, 30 * (1024 ** 5) - 1)
self.assertEqual(uwsgi.sharedarea_read64(0, 8), 1)
unittest.main()
+1 -1
View File
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = 'uwsgi'
s.license = 'GPL-2'
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
s.date = '2014-06-01'
s.date = '2015-10-07'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+76
View File
@@ -6,6 +6,10 @@
extern "C" {
#endif
#define UWSGI_PLUGIN_API 1
#define UWSGI_HAS_OFFLOAD_UBUFS 1
#define UMAX16 65536
#define UMAX8 256
@@ -604,6 +608,8 @@ struct uwsgi_daemon {
int ns_pid;
int throttle;
char *chdir;
};
struct uwsgi_logger {
@@ -830,6 +836,11 @@ struct uwsgi_cache {
int purge_lru;
uint64_t lru_head;
uint64_t lru_tail;
int store_delete;
int lazy_expire;
uint64_t sweep_on_full;
int clear_on_full;
};
struct uwsgi_option {
@@ -996,6 +1007,7 @@ struct uwsgi_protocol {
};
struct uwsgi_server;
struct uwsgi_instance;
struct uwsgi_plugin {
@@ -1054,6 +1066,9 @@ struct uwsgi_plugin {
struct uwsgi_buffer* (*exception_msg)(struct wsgi_request *);
struct uwsgi_buffer* (*exception_repr)(struct wsgi_request *);
void (*exception_log)(struct wsgi_request *);
void (*vassal)(struct uwsgi_instance *);
void (*vassal_before_exec)(struct uwsgi_instance *);
};
#ifdef UWSGI_PCRE
@@ -2723,6 +2738,33 @@ struct uwsgi_server {
int stats_no_cores;
int stats_no_metrics;
// uWSGI 2.0.7
int vassal_sos;
// uWSGI 2.0.8
struct uwsgi_string_list *wait_for_fs;
struct uwsgi_string_list *wait_for_dir;
struct uwsgi_string_list *wait_for_file;
int wait_for_fs_timeout;
struct uwsgi_string_list *wait_for_mountpoint;
#ifdef UWSGI_SSL
int sslv3;
struct uwsgi_string_list *ssl_options;
#endif
struct uwsgi_string_list *hook_post_fork;
// uWSGI 2.0.9
char *subscribe_with_modifier1;
struct uwsgi_string_list *pull_headers;
// uWSGI 2.0.10
struct uwsgi_string_list *emperor_wrapper_override;
struct uwsgi_string_list *emperor_wrapper_fallback;
// uWSGI 2.0.11
struct uwsgi_string_list *wait_for_socket;
int wait_for_socket_timeout;
int mem_collector_freq;
};
struct uwsgi_rpc {
@@ -3014,6 +3056,7 @@ void uwsgi_xml_config(char *, struct wsgi_request *, char *[]);
void uwsgi_500(struct wsgi_request *);
void uwsgi_403(struct wsgi_request *);
void uwsgi_404(struct wsgi_request *);
void uwsgi_405(struct wsgi_request *);
void uwsgi_redirect_to_slash(struct wsgi_request *);
void manage_snmp(int, uint8_t *, int, struct sockaddr_in *);
@@ -3057,6 +3100,7 @@ struct wsgi_request *find_first_accepting_wsgi_req(void);
struct wsgi_request *find_wsgi_req_by_fd(int);
struct wsgi_request *find_wsgi_req_by_id(int);
void async_schedule_to_req_green(void);
void async_schedule_to_req(void);
int async_add_fd_write(struct wsgi_request *, int, int);
int async_add_fd_read(struct wsgi_request *, int, int);
@@ -3430,6 +3474,7 @@ struct uwsgi_socket *uwsgi_new_shared_socket(char *);
struct uwsgi_socket *uwsgi_del_socket(struct uwsgi_socket *);
void uwsgi_close_all_sockets(void);
void uwsgi_close_all_unshared_sockets(void);
struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **, char *);
#ifdef UWSGI_PCRE
@@ -3790,6 +3835,8 @@ int uwsgi_logic_opt_if_reload(char *, char *);
int uwsgi_logic_opt_if_not_reload(char *, char *);
int uwsgi_logic_opt_if_plugin(char *, char *);
int uwsgi_logic_opt_if_not_plugin(char *, char *);
int uwsgi_logic_opt_if_hostname(char *, char *);
int uwsgi_logic_opt_if_not_hostname(char *, char *);
void uwsgi_opt_resolve(char *, char *, void *);
@@ -4148,6 +4195,7 @@ struct uwsgi_buffer *uwsgi_buffer_from_file(char *);
ssize_t uwsgi_buffer_write_simple(struct wsgi_request *, struct uwsgi_buffer *);
struct uwsgi_buffer *uwsgi_to_http(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
struct uwsgi_buffer *uwsgi_to_http_dumb(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
ssize_t uwsgi_pipe(int, int, int);
ssize_t uwsgi_pipe_sized(int, int, size_t, int);
@@ -4228,6 +4276,28 @@ struct uwsgi_offload_request {
struct uwsgi_offload_request *prev;
struct uwsgi_offload_request *next;
// added in 2.1
struct uwsgi_buffer *ubuf1;
struct uwsgi_buffer *ubuf2;
struct uwsgi_buffer *ubuf3;
struct uwsgi_buffer *ubuf4;
struct uwsgi_buffer *ubuf5;
struct uwsgi_buffer *ubuf6;
struct uwsgi_buffer *ubuf7;
struct uwsgi_buffer *ubuf8;
int64_t custom1;
int64_t custom2;
int64_t custom3;
int64_t custom4;
int64_t custom5;
int64_t custom6;
int64_t custom7;
int64_t custom8;
void *data;
void (*free)(struct uwsgi_offload_request *);
};
struct uwsgi_offload_engine {
@@ -4585,6 +4655,7 @@ void uwsgi_master_fifo_prepare();
int uwsgi_master_fifo();
int uwsgi_master_fifo_manage(int);
void uwsgi_log_do_rotate(char *, char *, off_t, int);
void uwsgi_log_rotate();
void uwsgi_log_reopen();
void uwsgi_reload_workers();
@@ -4783,6 +4854,11 @@ mode_t uwsgi_mode_t(char *, int *);
int uwsgi_notify_socket_manage(int);
int uwsgi_notify_msg(char *, char *, size_t);
void vassal_sos();
int uwsgi_wait_for_fs(char *, int);
int uwsgi_wait_for_mountpoint(char *);
int uwsgi_wait_for_socket(char *);
#ifdef __cplusplus
}
+34 -14
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '2.0.5'
uwsgi_version = '2.0.11.2'
import os
import re
@@ -53,6 +53,11 @@ if CPUCOUNT < 1:
except:
CPUCOUNT = 1
# force single cpu in cygwin mode
if uwsgi_os.startswith('CYGWIN'):
CPUCOUNT=1
binary_list = []
started_at = time.time()
@@ -398,18 +403,26 @@ def build_uwsgi(uc, print_only=False, gcll=None):
path = path.rstrip('/')
if not os.path.isdir(path):
up = {}
if os.path.isfile(path):
bname = os.path.basename(path)
# override path
path = os.path.dirname(path)
up['GCC_LIST'] = [bname]
up['NAME'] = bname.split('.')[0]
if not path: path = '.'
elif os.path.isdir(path):
try:
execfile('%s/uwsgiplugin.py' % path, up)
except:
f = open('%s/uwsgiplugin.py' % path)
exec(f.read(), up)
f.close()
else:
print("Error: plugin '%s' not found" % p)
sys.exit(1)
up = {}
try:
execfile('%s/uwsgiplugin.py' % path, up)
except:
f = open('%s/uwsgiplugin.py' % path)
exec(f.read(), up)
f.close()
p_cflags = cflags[:]
try:
p_cflags += up['CFLAGS']
@@ -676,8 +689,13 @@ class uConf(object):
print("detected include path: %s" % self.include_path)
try:
gcc_major = int(gcc_version.split('.')[0])
gcc_minor = int(gcc_version.split('.')[1])
gcc_version_components = gcc_version.split('.')
gcc_major = int(gcc_version_components[0])
if len(gcc_version_components) > 1:
gcc_minor = int(gcc_version_components[1])
else:
# gcc 5.0 is represented as simply "5"
gcc_minor = 0
except:
raise Exception("you need a C compiler to build uWSGI")
if (sys.version_info[0] == 2) or (gcc_major < 4) or (gcc_major == 4 and gcc_minor < 3):
@@ -685,7 +703,7 @@ class uConf(object):
# add -fno-strict-aliasing only on python2 and gcc < 4.3
if gcc_major >= 4:
self.cflags = self.cflags + [ '-Wextra', '-Wno-unused-parameter', '-Wno-missing-field-initializers' ]
if (gcc_major == 4 and gcc_minor >= 8) or gcc_major > 4:
if gcc_major == 4 and gcc_minor < 9:
self.cflags.append('-Wno-format -Wno-format-security')
self.ldflags = os.environ.get("LDFLAGS", "").split()
@@ -755,7 +773,7 @@ class uConf(object):
if 'UWSGI_PROFILE_OVERRIDE' in os.environ:
for item in os.environ['UWSGI_PROFILE_OVERRIDE'].split(';'):
k,v = item.split('=', 2)
k,v = item.split('=', 1)
self.set(k, v)
if 'UWSGI_AS_LIB' in os.environ:
@@ -1158,6 +1176,8 @@ class uConf(object):
else:
jsonconf = spcall("pkg-config --cflags yajl")
if jsonconf:
if jsonconf.endswith('include/yajl'):
jsonconf = jsonconf.rstrip('yajl')
self.cflags.append(jsonconf)
self.cflags.append("-DUWSGI_JSON")
self.gcc_list.append('core/json')
+28 -3
View File
@@ -18,6 +18,29 @@ mule_functions = {}
postfork_chain = []
# Python3 compatibility
def _encode1(val):
if sys.version_info >= (3, 0) and isinstance(val, str):
return val.encode('utf-8')
else:
return val
def _decode1(val):
if sys.version_info >= (3, 0) and isinstance(val, bytes):
return val.decode('utf-8')
else:
return val
def _encode_to_spooler(vars):
return dict((_encode1(K), _encode1(V)) for (K, V) in vars.items())
def _decode_from_spooler(vars):
return dict((_decode1(K), _decode1(V)) for (K, V) in vars.items())
def get_free_signal():
for signum in range(0, 256):
if not uwsgi.signal_registered(signum):
@@ -27,6 +50,7 @@ def get_free_signal():
def manage_spool_request(vars):
vars = _decode_from_spooler(vars)
f = spooler_functions[vars['ud_spool_func']]
if 'args' in vars:
args = pickle.loads(vars.pop('args'))
@@ -67,7 +91,7 @@ class postfork(object):
class _spoolraw(object):
def __call__(self, *args, **kwargs):
arguments = self.base_dict
arguments = self.base_dict.copy()
if not self.pass_arguments:
if len(args) > 0:
arguments.update(args[0])
@@ -79,8 +103,9 @@ class _spoolraw(object):
if key in kwargs:
spooler_args.update({key: kwargs.pop(key)})
arguments.update(spooler_args)
arguments.update({'args': pickle.dumps(args), 'kwargs': pickle.dumps(kwargs)})
return uwsgi.spool(arguments)
arguments.update(
{'args': pickle.dumps(args), 'kwargs': pickle.dumps(kwargs)})
return uwsgi.spool(_encode_to_spooler(arguments))
# For backward compatibility (uWSGI < 1.9.13)
def spool(self, *args, **kwargs):