Compare commits

..
414 Commits
Author SHA1 Message Date
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
Roberto De Ioris 41b6005d30 fixed http-manage-source type 2014-06-01 06:47:31 +02:00
Roberto De Ioris 497f7efa55 prepare for 2.0.5 2014-06-01 06:18:01 +02:00
Roberto De Ioris ad7ca0b098 fixed #641 2014-05-31 07:44:05 +02:00
Roberto De Ioris 1d591c95f2 fixed #633 2014-05-31 06:41:30 +02:00
Roberto De Ioris d3daca0b16 fixed #640 2014-05-29 19:52:49 +02:00
Unbit bae1ade00a added 'resolve' option 2014-05-29 09:50:50 +02:00
Unbit fd663aedbd added setremoteaddr 2014-05-28 15:41:49 +02:00
Unbit 6b9ce2d755 added test for lru cache purge and fix for lru removal 2014-05-27 11:38:57 +02:00
Unbit bd2728b391 retry on mule_get_msg EAGAIN 2014-05-27 09:41:36 +02:00
unbit dc250fd7b5 Merge pull request #636 from prymitive/issue635
fixed log setup when both --logto and --log2, fixes unbit/uwsgi#635
2014-05-24 09:59:21 +02:00
Łukasz Mierzwa 0a9345b8d4 fixed log setup when both --logto and --log2, fixes unbit/uwsgi#635 2014-05-23 18:44:40 +02:00
unbit db509f2d38 Merge pull request #631 from btall/set-min-set-max
Add new functions 'uwsgi_metric_set_min' & 'uwsgi_metric_set_max', wh…
2014-05-22 15:22:29 +02:00
Unbit b12c39607d less invasive privileges drop when chown-socket is in place 2014-05-22 09:00:43 +02:00
Roberto De Ioris 224260ce3e postpone uwsgi_as_root() call 2014-05-22 05:43:45 +02:00
Roberto De Ioris 5f86d9522f hack for avoiding Safari iOS to make mess with keepalive 2014-05-21 21:35:54 +02:00
Unbit a0fafe7847 try to honour chmod/chown socket in fd0 mode 2014-05-21 12:35:01 +02:00
Babacar TALL daeaf1b231 Doesn't use uwsgi_metric_get for the comparison on uwsgi_metric_set_max and uwsgi_metric_set_min (it introduce a deadlock) 2014-05-20 16:46:25 +02:00
Unbit fbc0a2775f when changing metrics we need a write lock 2014-05-20 16:02:54 +02:00
Unbit d3c89a3f63 various metrics fixes for reset_after_push feature 2014-05-20 15:35:33 +02:00
unbit cd43a0d12d Merge pull request #630 from btall/reset-after-push
Implement a new metric option 'reset_after_push' which will make uWSGI.....
2014-05-20 15:31:01 +02:00
Babacar TALL f06df71bfc Use the wlock when the value is reseted 2014-05-20 14:51:14 +02:00
Babacar TALL eab2472dd0 Exposure of 'uwsgi_metric_set_min' & 'uwsgi_metric_set_max' for python interface. 2014-05-20 11:57:53 +02:00
Babacar TALL 87a2f3585c Add new functions 'uwsgi_metric_set_min' & 'uwsgi_metric_set_max', which...
push respectively a absolute value if she is less than or greater than
that the previous push.

Refactore the function uwsgi_metric_set_min
2014-05-20 11:57:42 +02:00
Babacar TALL c257a9aa98 Update all plugins so that they bear this functionality (reset_after_push) 2014-05-19 15:16:29 +02:00
Babacar TALL 43aebe2d66 Implement a new metric option 'reset_after_push' which will make uWSGI...
reset to 0 the given metric after it's been pushed to the stats backend.
This is handy when you want to automatically reset counters every 'freq'
seconds.
2014-05-19 14:36:25 +02:00
Roberto De Ioris 309115d611 allow to enable the proxy protocol management only in the http router 2014-05-17 11:52:58 +02:00
unbit 5881d41b2b Merge pull request #627 from blue-goji/proxy-protocol-for-http-module
Add ELB proxy protocol support to the HTTP module.
2014-05-16 18:31:43 +02:00
Glenn Maynard 9fe4b7b14a Add ELB proxy protocol support to the HTTP module.
Previously, this was only supported with http-socket.  If you're
using http-socket, you probably have a webserver on top of you--and if
you have that, then uWSGI isn't receiving the proxy protocol anyway.
2014-05-16 16:16:01 +00:00
Unbit 930c19210a inform user about UWSGI_GO_CHEAP_CODE 2014-05-14 15:35:06 +02:00
Unbit 5beb170cfd inform user about UWSGI_GO_CHEAP 2014-05-14 15:34:08 +02:00
Unbit a13103d851 added UWSGI_GO_CHEAP 2014-05-14 15:24:37 +02:00
Unbit bc5a86694f correctly manage 64bit sharedarea numbers on 32bit systems 2014-05-14 11:33:18 +00:00
Unbit 812685096b various sharedarea improvements 2014-05-14 10:45:49 +00:00
Unbit f70c070a0f fixed #622 2014-05-13 19:37:10 +02:00
Unbit accf622ffc fixed #623 2014-05-13 13:26:00 +02:00
Unbit 04173869ee ensure SIGPIPE is ignored in gevent mode 2014-05-13 12:49:58 +02:00
Roberto De Ioris 509a3c5cd4 fixed #620 2014-05-08 06:48:30 +02:00
Unbit 81ad3a916d allow variables in uwsgi router 2014-05-07 11:30:43 +02:00
Unbit 3f93a0b8e4 improved icecast2 management 2014-05-07 06:53:30 +02:00
Unbit 4408b655a4 implement a form of virtualhosting for http/1.0 icecast2 source requests 2014-05-07 06:47:45 +02:00
Unbit 71a6b8a304 more Emperor backports 2014-05-07 06:22:03 +02:00
Unbit 7e9069eabf reindented emperor.c 2014-05-07 06:14:48 +02:00
Roberto De Ioris 6c77dd0e38 fixed typo in SOURCE manager 2014-05-07 06:08:19 +02:00
Roberto De Ioris 27e506c72a added SOURCE management to http router 2014-05-07 06:06:14 +02:00
Roberto De Ioris bea68191e3 backported emperor fixes from 2.1 2014-05-07 06:03:54 +02:00
Unbit 9b207d8a62 added --metrics-no-cores, --stats-no-cores, --stats-no-metrics. fixed #537 2014-05-05 18:19:08 +02:00
Unbit 68d5b2de3b implements eof management in fastcgi parser 2014-05-05 17:37:55 +02:00
Unbit 3a62573005 close pipe and config file descriptors when back to on-demand mode 2014-05-04 19:43:38 +02:00
Unbit 1c6dd42318 added --emperor-no-blacklist 2014-05-04 09:15:15 +02:00
unbit 73ad0677bd Merge pull request #616 from prymitive/ignore_static_file_avg_rt
don't recalculate avg_rt for static files
2014-05-04 08:01:58 +02:00
Łukasz Mierzwa 15b2cf0712 don't recalculate avg_rt for static files 2014-05-03 21:48:41 +02:00
Unbit 0da0fa211a avoid re-calling emperor_simple_do while destroying a vassal 2014-05-03 08:55:34 +02:00
Unbit a8ecd71ffd fixed a typo in emperor mongodb 2014-05-03 08:28:37 +02:00
Unbit ea0a95a441 added error report for emperor error 2014-05-03 08:18:48 +02:00
Unbit 6ac6e58bf7 refactored return action 2014-05-02 12:00:08 +02:00
unbit f2c7addb73 Merge pull request #615 from getcwd/master
core/routing: add new "return/break-with-status" action
2014-05-02 11:43:33 +02:00
Unbit fff5fa536b allow fast moving to/from on_demand mode 2014-05-02 07:14:05 +02:00
Yu Zhao 95825c9b99 core/routing: add "return" action
The new action will allow users to write simplified "break" clause.
For example, "return:403" is equivalent to "break:403 Forbidden",
with response body "Forbidden". The response body is quite useful
for telling end users what goes wrong.
2014-05-01 15:32:08 -07:00
unbit 1e84fcf880 Merge pull request #613 from avar/more-perl-tests-and-benchmarks
More perl tests and benchmarks
2014-05-01 06:12:05 +02:00
Ævar Arnfjörð Bjarmason 0f742a72bf t/perl/hello_benchmark.pl: silly benchmark for CPU count + thunder lock
This is to test how the number of processes and using thunder-lock or
not affects response times.
2014-05-01 01:19:35 +02:00
Ævar Arnfjörð Bjarmason fd96a02576 t/perl/test_sleepy.psgi: perl test file that sleeps a bit
This is to test non-CPU bound servers that are waiting on
something (e.g. a database), expecting that we can have a lot more than
num CPU cores of these and not see performance degration.
2014-05-01 01:19:30 +02:00
unbit 77ca76428d Merge pull request #612 from avar/add-perl-hello-world-test-file
t/perl/test_hello.psgi: perl test file that does nothing but hello, worl...
2014-04-30 21:44:32 +02:00
Ævar Arnfjörð Bjarmason 9ea8f4f07c t/perl/test_hello.psgi: perl test file that does nothing but hello, world
To test a bare-minimal Perl program that does almost nothing at all.
2014-04-30 17:59:41 +00:00
Unbit 9ffc311177 fixed fastcgi parser 2014-04-30 14:40:34 +02:00
Unbit 4f89a350aa fixed json escaper 2014-04-30 07:42:11 +02:00
Unbit 8f18c77587 fixed sharedarea waiting 2014-04-29 11:19:39 +02:00
Unbit 371cafef94 do not explode on milliseconds wait 2014-04-29 07:42:11 +02:00
unbit 89c31e9280 Merge pull request #606 from getcwd/master
plugins/alarm_curl ehancement
2014-04-29 06:45:45 +02:00
Yu Zhao 418d784148 plugins/alarm_curl: option for disabling dedicated alarm threads
A new global option alarm-cheap allows users to disable creating
thread per curl-based alarm. This option can be extended to other
alarm plugins like xmpp.
2014-04-27 15:43:26 -07:00
Yu Zhao c146275e9b plugins/alarm_curl: refactor code
No need to calloc struct uwsgi_alarm_curl_config because all data
we need is populated and stored in struct uwsgi_alarm_curl.

Save some memory when there are hundreds of curl-based alarms.
2014-04-27 15:43:18 -07:00
Yu Zhao eff23382c2 plugins/{airbrake,alarm_curl,alarm_xmpp}: fix race condition
A thread may run immediately after it's created. Trying to pass
parameter to thread using uwsgi_thread->data without preventing
the thread from accessing it first is a race condition. If the
thread accesses uwsgi_thread->data first, uwsgi gets killed by
SIGSEGV.

This patch creates a new function uwsgi_thread_new_with_data()
to assign user provided data to uwsgi_thread->data before the
thread is created.
2014-04-27 14:28:59 -07:00
Yu Zhao d566469c63 plugins/alarm_curl: fix read callback function for libcurl
The read callback for libcurl shouldn't return size that is larger
than the requested size when it's too small to hold email header.
Otherwise curl will abort the operation. And we shouldn't return
1 (which is the current behavior) while there is no header at all.

The expected size of the infile set by option CURLOPT_INFILESIZE
or CURLOPT_INFILESIZE_LARGE should include both header and body
sizes. The infile size is used when server supports the optional
"SIZE" parameter of "MAIL FROM" command. libcurl hangs when wrong
size is passed in.

Since email header remains unchanged for each alarm_curl instance,
we don't have to generate it per alarm request. Based on this, the
solution is quite simple: we generate the header once during
initialization and use it for all alarms.
2014-04-27 11:38:46 -07:00
Yu Zhao e008ce5d56 plugins/alarm_curl: add SSL option to skip certificate verification
The new option ssl_insecure is equivalent to curl command line
option --insecure or -k, which is useful for posting alarms via
HTTPS to a server with self-generated certificate installed.
2014-04-27 11:25:07 -07:00
Yu Zhao 9d21c99183 plugins/alarm_curl: use CRLF instead of LF for line break in MIME
Though most programs accept LF, MIME RFC explicitly requires CRLF.
2014-04-27 11:25:03 -07:00
Yu Zhao 7e80927317 plugins/alarm_curl: free memory used during parsing args 2014-04-27 06:20:18 -07:00
Yu Zhao 6664e7120b plugins/alarm_curl: exit when requested protocol is not support
When SMTP is not supported by libcurl, or user doesn't provide
required URL for libcurl, throw an error message and then exit.
2014-04-27 06:20:18 -07:00
Yu Zhao 687aabd30b plugins/alarm_curl: turn on SMTP protocol
Compiler ignores SMTP support because enums CURLOPT_MAIL_RCPT and
CURLPROTO_SMTP are misused as macros for conditional compilation.

Replace the enums with real macro CURLPROTO_SMTP so compiler can
detect them.
2014-04-27 06:20:15 -07:00
unbit fab656c635 Merge pull request #602 from paulegan/mule-graceful-reload
Support for graceful reload of mule processes.
2014-04-26 19:28:40 +02:00
Paul Egan 72c31dab7a Support for graceful reload of mule processes.
- On reload master now signals mule with HUP instead of KILL.
- Added optional call to PyOS_AfterFork to enable cpython child
  processes to override and trap HUP signal.
- Copied cursed_at/no_mercy_at pattern used with worker processes.
- Added mule_reload_mercy option.
2014-04-26 14:12:48 +01:00
Roberto De Ioris f19a301b73 afaik only darwin misses objcopy 2014-04-26 07:18:24 +02:00
unbit 19a19a8a67 Merge pull request #604 from blablacio/master
Enabling OpenBSD support for uWSGI embedded config
2014-04-26 07:16:04 +02:00
Roberto De Ioris d9c9f41624 better manage ready/accepting vassals states 2014-04-26 07:02:41 +02:00
blablacio dc97853f9f Enabling OpenBSD support for uWSGI embedded config 2014-04-26 06:44:53 +03:00
unbit b089774c36 Merge pull request #603 from tizoc/master
Support for repeated headers in responses in the Lua plugin
2014-04-25 06:45:50 +02:00
Bruno Deferrari f8a271a027 Add a basic test app for the lua plugin 2014-04-24 21:27:16 -03:00
Bruno Deferrari ef12aaf13c Support for repeated headers in responses in the Lua plugin
This is needed for WSAPI conformance, and important for having
good support of Set-Cookie.
2014-04-24 17:30:09 -03:00
unbit a559361a30 Merge pull request #601 from getcwd/master
Add synonym "lru"  for "purge_lru" in cache config
2014-04-23 06:45:16 +02:00
Yu Zhao 6aad281441 Add synonym "lru" for "purge_lru" in cache config 2014-04-22 07:17:53 -07:00
Unbit 7604c67018 ready to release 2.0.4 2014-04-22 08:22:00 +02:00
Roberto De Ioris afc962709f fixed respawn when in on-demand mode 2014-04-21 07:49:57 +02:00
Unbit c11e0654a0 added php session support over cache 2014-04-19 18:42:52 +02:00
Unbit 6e4f47cc76 the corerouter error reporting is still wrong :( 2014-04-19 11:36:06 +02:00
Unbit 20c9f0ef40 another error report fix for the corerouter 2014-04-19 11:25:52 +02:00
Unbit ef3c8a5bd9 fixed tornado plugin 2014-04-19 11:01:14 +02:00
Unbit 76d0438fee added asyncio build profile 2014-04-19 10:58:50 +02:00
Unbit 18fd338908 fixed corerouter error reporting 2014-04-19 10:27:58 +02:00
Unbit 2b35e95706 removed some useless debug 2014-04-19 09:29:43 +02:00
Unbit 4761146599 the asyncio plugin (experimental) 2014-04-19 09:21:19 +02:00
Unbit 3924cc639e added Yu Zhao to CONTRIBUTORS 2014-04-18 06:29:29 +02:00
unbit 5f09de0469 Merge pull request #597 from getcwd/lru
Implement LRU for cache framework
2014-04-18 06:28:10 +02:00
Yu Zhao 4f0e3fb79f Implement LRU for cache framework
If "purge_lru" option is used when creating cache store, the
"expires" parameter for cache_set/cache_update will be ignored.
Instead, all items are placed on an LRU list and when the store
is full, the least recent used one will be evicted.
2014-04-17 20:26:41 -07:00
unbit 05b6baf173 Merge pull request #594 from getcwd/master
cache/sweeper ehancement
2014-04-16 07:03:53 +02:00
Yu Zhao 149823aac4 Only scan cached items when there is expired one
This is an optimization for the sweeper algorithm. By remembering
the least expiration time, we can determine whether we need to go
over all items in a cache store. If we have to, we find the new
least expiration time by examining those that are not expired yet.
2014-04-15 13:57:57 -07:00
Yu Zhao 85d86dc10e Only allocate one sweeper thread
Thread is not cheap on Linux since it involves context switch in the
kernel. And allocating multiple threads is not necessary even on SMP
since the granularity of time is second.
2014-04-15 10:58:29 -07:00
Yu Zhao e97d921909 Optimization for sweeper creation loop
cache_no_expire is a global flag, if it's set, return without further
check when trying to create sweepers.
2014-04-15 08:56:34 -07:00
unbit c5e20bf4da Merge pull request #593 from getcwd/patch-1
add ${HTTPS} to https_socket
2014-04-15 06:15:45 +02:00
getcwd a09d25ccaa add ${HTTPS} to https_socket
https plugin sets ${HTTPS} so should https_socket proto -- admins can write consistent HTTP/HTTPS routing rules for both.
2014-04-14 14:22:31 -07:00
Unbit bf01cea062 added micros() api function 2014-04-12 18:34:57 +02:00
unbit b6459be3e4 Merge pull request #591 from prymitive/ssl_opts
always generate key if (EC)DH is used
2014-04-12 12:25:29 +02:00
Łukasz Mierzwa d42788c17b always generate key if (EC)DH is used 2014-04-12 11:16:05 +02:00
Unbit 872730c116 added mongodb2 imperial monitor 2014-04-11 11:15:17 +02:00
Unbit 6fce0aee84 fixed a typo 2014-04-11 10:36:08 +02:00
Unbit e3d8a02614 add a memo for future offload improvements 2014-04-09 11:24:02 +02:00
Unbit b58696399e added support for http proxy connect in router_http 2014-04-09 10:49:17 +02:00
Unbit 519c9f58b3 Merge branch 'master' of ssh://github.com/unbit/uwsgi 2014-04-09 05:53:48 +02:00
Unbit 2c77c5c639 fixed http and uwsgi internal routers (by Guido Notari) 2014-04-09 05:53:26 +02:00
unbit fb9e5a1891 Merge pull request #587 from prymitive/lseek
check lseek return value in uwsgi_check_logrotate()
2014-04-06 20:11:20 +02:00
unbit 5aa7d1a79f Merge pull request #586 from prymitive/logto2
uwsgi_setup_log_master must always be called after logto()
2014-04-06 20:10:38 +02:00
Łukasz Mierzwa bc3442ba29 uwsgi_setup_log_master must always be called after logto(), this was not happening with --logto2 2014-04-06 15:08:03 +02:00
Łukasz Mierzwa 3061e36089 check lseek return value in uwsgi_check_logrotate() 2014-04-06 15:03:17 +02:00
Unbit 4f8c41cf61 fix headers parsing in http router 2014-04-06 10:15:24 +02:00
unbit b0065c379e Merge pull request #585 from stestagg/master
Fix uwsgi_route_var_mime
2014-04-05 15:58:06 +02:00
Steve Stagg 57f71c974d Fix some bugs introduced in c57baae477 preventing the 'mime' routing function from working with request variables, and actually return the found mimetype
The uwsgi_route_var_mime function had two errors preventing it from (afaics ever) working:
 1. Redefine the 'ret' variable inside an if block. This meant that if the uwsgi_get_mime_type function ever actually found a matching mimetype, the length of the matching value would be corectly set, but the function returns NULL (the value of the function-level ret variable)
 2. The function was looking up the request variable correctly, BUT then passing in the raw config string to uwsgi_get_mime_type NOT the resolved varible value, making the lookup just a waste of cycles.
2014-04-05 13:36:53 +01:00
Unbit b820fefbbd prepare for 2.0.4 2014-04-05 10:15:02 +02:00
Unbit 5f759f0d26 allow duplicate headers in http router 2014-04-05 10:14:11 +02:00
Unbit f7eb9ed1cd improved on_demand mode 2014-04-05 08:56:39 +02:00
Unbit 3a82732b19 advanced http timeout management 2014-04-05 07:57:01 +02:00
Unbit d74e826f71 another patch for reducing emperor race conditions 2014-04-02 09:15:05 +02:00
unbit c846a9b388 Merge pull request #582 from prymitive/cache_full_ignore
allow disabling cache warnings
2014-04-02 00:33:49 +02:00
Łukasz Mierzwa 001e4b6e39 allow disabling cache warnings in --cache2 2014-04-01 20:00:13 +02:00
Unbit a51a396f47 fixed #581 2014-04-01 12:04:31 +02:00
Unbit 17965ea870 faster restart of vassals 2014-04-01 10:52:32 +02:00
Unbit 8a032b41ec combine headers with the same name in HTTP native mode 2014-03-31 10:32:18 +02:00
Roberto De Ioris a489cfc2c1 fixed additional sources 2014-03-28 07:08:15 +01:00
unbit 3b32672ff9 Merge pull request #579 from prymitive/spdy_fix
merge duplicated headers when SPDY is enabled, fixes #572
2014-03-28 06:18:26 +01:00
Łukasz Mierzwa 858131ba57 merge duplicated headers when SPDY is enabled, fixes #572 2014-03-27 21:32:51 +01:00
Unbit 8a8d2f8675 support embedded config on FreeBSD 2014-03-26 16:54:31 +01:00
Unbit 9d37725323 added setmodifier1 and setmodifier2 2014-03-23 07:26:14 +01:00
Unbit e973492267 added no_headers option to keyval based static routers, fixes #576 2014-03-22 18:23:18 +01:00
Unbit 105a68bce9 fixed fatal hooks management 2014-03-22 13:10:00 +01:00
Unbit 0587a0ca53 fixed #557 for --lazy-apps 2014-03-22 13:01:14 +01:00
Unbit d4b259d5e0 fixed #575 2014-03-20 05:48:05 +01:00
Unbit 9e591c587f added rpc hook 2014-03-20 05:38:39 +01:00
Unbit e7cce7b785 fixed segfault for unnamed loggers 2014-03-18 16:16:12 +01:00
unbit 3285b224c2 Merge pull request #573 from prymitive/spdy_fix
Lowercase only header keys, not values.
2014-03-17 09:07:20 +01:00
Roberto De Ioris e4a4942980 prepare for 2.0.3 release 2014-03-17 06:33:04 +01:00
Roberto De Ioris 6f671936fc added uwsgi::add_var to perl 2014-03-17 06:18:15 +01:00
Roberto De Ioris 7d1d992d58 fix tnetstring support #562 2014-03-17 06:02:44 +01:00
Łukasz Mierzwa 2bba4cf15a Lowercase only header keys, not values. Fixes #572 2014-03-16 23:43:28 +01:00
unbit 930f71c562 Merge pull request #571 from avar/avar/fix-2.0.1-perl-refactoring-regression
perl: fix one-off error in 2.0-103-gf041d10 causing warnings in e.g. Pla...
2014-03-16 05:53:54 +01:00
unbit 959bb11f77 Merge pull request #570 from avar/avar/add-sanity-check-to-offset-test
perl: add sanity checks to t/perl/test_input_with_offset.pl
2014-03-16 05:52:19 +01:00
Ævar Arnfjörð Bjarmason 13d8505738 perl: fix one-off error in 2.0-103-gf041d10 causing warnings in e.g. Plack::Request
This newly added support for read() offsets started causing "Use of
uninitialized value in subroutine entry" warnings.

This is all because there was a test for the number of items on the
stack, which ignored that the first argument is always the object, so 3
arguments to read() actually yields 4 arguments on the stack, not 3.

As a result we'd be calling SvIV() on a stack item that wasn't actually
passed in.
2014-03-15 21:05:18 +00:00
Ævar Arnfjörð Bjarmason 93fe463ca8 perl: add sanity checks to t/perl/test_input_with_offset.pl 2014-03-15 20:41:54 +00:00
unbit 5c64c21745 Merge pull request #569 from avar/avar/add-generated-file-to-gitignore
.gitignore: add /core/config_py.c to ignore
2014-03-15 15:16:12 +01:00
Ævar Arnfjörð Bjarmason f825ab542d .gitignore: add /core/config_py.c to ignore
This file added in e4903ee is generated by the build system and should
be in the ignore file.
2014-03-15 14:15:35 +00:00
unbit e744aef144 Merge pull request #568 from avar/avar/perl-add-streaming-test
perl: add a trivial streaming test program
2014-03-15 15:15:23 +01:00
Ævar Arnfjörð Bjarmason 4ded485a8e perl: add a trivial streaming test program
This came out of working on this debugging session:
https://github.com/unbit/uwsgi/issues/567
2014-03-15 14:10:20 +00:00
unbit 2ce5ec3986 Merge pull request #566 from avar/avar/psgi-spelling-error-fix
perl: fix trivial spelling error in psgi_loader.c error message
2014-03-15 14:48:35 +01:00
Ævar Arnfjörð Bjarmason af95f90fb0 perl: fix trivial spelling error in psgi_loader.c error message 2014-03-15 13:47:07 +00:00
unbit 7989dc748b Update CONTRIBUTORS 2014-03-15 14:36:51 +01:00
unbit f85f3e8178 Merge pull request #565 from avar/avar/fix-perl-stacktrace
perl: fix a regression with caller() not indicating the starting *.psgi ...
2014-03-15 14:28:14 +01:00
Ævar Arnfjörð Bjarmason 97809192c8 perl: fix a regression with caller() not indicating the starting *.psgi program
In 2.0.1-41-g3480c30 I introduced a regression with how the top-level
stackframe would appear within Perl programs. Before we'd show the
filename of the *.psgi file, but after we just showed "-e".

We can retain the bugfix I added in 2.0.1-41-g3480c30 while having a
sensible stacktrace by overriding the file via the #line directive.
2014-03-15 13:10:30 +00:00
Roberto De Ioris 5f74e6d964 fixed stupid bug with python add_var 2014-03-15 12:51:15 +01:00
Roberto De Ioris ae87fdd0f7 added uwsgi.add_var 2014-03-15 12:47:59 +01:00
Roberto De Ioris 36c44c83af added disableheaders routing action 2014-03-15 12:04:01 +01:00
Roberto De Ioris 48e13bfc65 add a check for already initialized python vm 2014-03-15 08:48:07 +01:00
Unbit 16cd55637d added support for mongrel2 URL_SCHEME #562 2014-03-14 11:48:36 +01:00
Unbit 39cf2887c4 added SIGURG to the Emperor 2014-03-14 11:28:53 +01:00
Unbit 671bf8a258 try to avoid vassal pipe to have invalid fd numbers 2014-03-14 11:21:20 +01:00
Unbit 89a8ceea81 allows building plugins from git repositories 2014-03-13 14:11:12 +01:00
Roberto De Ioris 6699f4046e better error reporting on websockets errors 2014-03-13 07:35:18 +01:00
Roberto De Ioris 88474b3d96 do not wait for a whole Emperor cycle before checking for each waitpid 2014-03-13 07:03:50 +01:00
unbit 32b6463d06 Merge pull request #559 from hynek/master
Set ECDHE curve independently from DHE parameters
2014-03-13 06:19:11 +01:00
Hynek Schlawack 63cc29a61d Set ECDHE curve independently from DHE parameters 2014-03-12 21:19:52 +01:00
Unbit d58f79eeab fixed #558 2014-03-11 16:18:32 +01:00
Unbit 7b24d2f5de allows vassals to request a config chunk from the emperor 2014-03-11 07:04:23 +01:00
Unbit a93db73d0c Merge branch 'master' of github.com:unbit/uwsgi 2014-03-10 14:52:35 +01:00
Unbit c118c75bfe beter management of failed emperor kills 2014-03-10 14:52:30 +01:00
Unbit 624631d443 fixed tuntap 2014-03-08 13:57:15 +01:00
Unbit b681eab385 fixed SIGWINCH in emperor and added emperor rescan master fifo command 2014-03-08 08:13:30 +01:00
Unbit 91dfe779ff fixed typo 2014-03-08 06:38:50 +01:00
Unbit 0ad50711c0 report key in corerouters 2014-03-08 06:36:38 +01:00
Unbit df6ed26479 more debug for tuntap 2014-03-08 06:24:45 +01:00
Unbit d08778b39c removed useless tuntap debug 2014-03-08 05:59:59 +01:00
Unbit 0c8c2932cf Merge branch 'master' of https://github.com/unbit/uwsgi 2014-03-08 05:44:05 +01:00
Unbit 131bd7da2f try to improve nb tuntap gateway 2014-03-08 05:43:54 +01:00
Unbit d247424442 more useful log alarm 2014-03-07 16:09:04 +01:00
Roberto De Ioris 332fab2150 hack for avoiding libmongoclient to crash on broken cursor 2014-03-07 07:31:42 +01:00
Roberto De Ioris 62d74951db support for git-based plugins 2014-03-05 08:28:17 +01:00
Roberto De Ioris 839638a0ad report socket name on invalid zeromq syntax 2014-03-04 06:38:42 +01:00
Roberto De Ioris 536ae8d013 fixed mongrel2 post_fork hook 2014-03-04 06:32:40 +01:00
Roberto De Ioris 367c4b9bab added on_demand sockets support to mongodb Emperor plugin 2014-03-04 06:08:16 +01:00
Roberto De Ioris 3965c01880 on __APPLE__ use LOG_NOTICE for syslog plugin 2014-03-04 05:44:18 +01:00
Unbit 7e4341a7cd force on demand unix socket to 666 2014-03-02 10:14:58 +01:00
Unbit 8c118c8f62 fixed (and improved) on demand emperor socket 2014-03-02 09:36:17 +01:00
Unbit 5d76b63fac fixed #555 2014-03-01 08:25:35 +01:00
Unbit b0159ea23b prepare for 2.0.2 2014-02-26 17:06:47 +01:00
Unbit d3493df032 do not expode if Devel::StackTrace is missing 2014-02-26 17:06:21 +01:00
Unbit 757c76b569 fix -bash in perl hooks 2014-02-26 12:12:41 +01:00
Unbit 30eebfd335 better perl do usage and --perl-no-plack flag 2014-02-26 12:07:00 +01:00
Unbit c5d7d30439 try to better address #553 2014-02-26 11:39:00 +01:00
unbit 04bc3e117d Merge pull request #553 from avar/avar/do-not-run-psgi-begin-blocks-twice
perl: Don't run BEGIN blocks twice in the provided *.psgi
2014-02-26 08:24:11 +01:00
Ævar Arnfjörð Bjarmason 3480c30674 perl: Don't run BEGIN blocks twice in the provided *.psgi
The psgi loaded was calling perl_parse() with the script ostensibly to
set up xsinit.

However it would also call perl_parse() with the path to our *.psgi
file, whith the result that any BEGIN block in the *.psgi file would be
run twice, but anything outside BEGIN blocks would only run once.

This means that any code within explicit BEGIN blocks will run twice,
and any "use" statement in the *.psgi file will run its import() routine
twice, but due to the module being in %INC already we won't actually
compile things twice.

The previous behavior dates all the way back to the initial introduction
of the PSGI plugin in 299fd9c.

Then when support for local::lib was added in 7cbe751 we initially did a
perl_eval_pv() of a "use" statement like I'm doing here again now, but
later on in 1561dd3 changed it to call perl_parse with the commit
message "another PSGI loading fix".

Since there's no info on what that fixed or what was broken before I
have no idea if I'm introducing a regression here, but I don't see why
this way of loding local::lib shouldn't work, and it correctly munges
@INC for me when I try it.

We may still have this bug in the remaining perl_parse() calls that
remain for supporting "preinit" and "mule".

I haven't tested those modes (I don't use them), but when we load the
Perl apps we should only perl_parse() once with -e1, and then
perl_eval_pv() to actually load the application. We should not call
perl_parse() on code that we're just about to perl_eval_pv(), or we'll
run into this bug.

To test this just run:

    ./uwsgi --http 127.0.0.1:8080 --psgi ./t/perl/test.psgi

It'll no longer PANIC on the BEGIN block being run twice now, at least
in that simplistic non-"preinit" non-"mule" mode.
2014-02-25 18:07:42 +00:00
Unbit a7e6dfc469 fixed python 3 on old compilers, fixes #551 2014-02-25 07:05:46 +01:00
Unbit 5e276b43ad fix poll() usage in #546 2014-02-24 09:14:14 +01:00
Roberto De Ioris 9e6a21602a more cgi improvements 2014-02-22 11:40:23 +01:00
Roberto De Ioris 952c4ce854 minor fixes in non-blocking reads 2014-02-22 11:13:50 +01:00
Roberto De Ioris 951f24e711 fixed #546 2014-02-22 10:46:46 +01:00
Unbit 7bda4c9b63 allow starting in spooler mode only 2014-02-21 08:48:21 +01:00
Unbit 1b25516ced spawn spoolers if requested 2014-02-21 08:42:22 +01:00
Unbit b3020e60f9 fixed long standing bug with caches 2014-02-20 14:19:40 +01:00
Unbit 808d37f33a fixed ftime log var 2014-02-20 10:52:05 +01:00
Unbit 8c8a7f77d1 added async remote signal management 2014-02-20 10:48:30 +01:00
Unbit 3f601af740 fix end-for and end-if 2014-02-20 10:28:30 +01:00
Unbit 7b901ab81e fixed #536 2014-02-20 09:19:41 +01:00
Roberto De Ioris 930eb1e6aa fixed #541 2014-02-20 07:52:47 +01:00
Unbit 77e5931da7 avoid loop in response and error internal routing 2014-02-15 09:35:38 +01:00
Unbit 3e6ddbb3d5 added --php-exec-before/--php-exec-after 2014-02-15 08:59:56 +01:00
Unbit 623bce274a prepare for 2.0.2 2014-02-15 07:31:39 +01:00
Unbit 6c986f8082 fixed pypy execute_source usage 2014-02-15 07:30:17 +01:00
Unbit 10a02064ba Merge branch 'master' of ssh://github.com/unbit/uwsgi 2014-02-13 06:25:18 +01:00
Unbit 774f5a81a5 added --geoip-use-disk, fixes #519 2014-02-13 06:25:07 +01:00
unbit e270593cc0 Merge pull request #533 from ramm/master
typo fix
2014-02-13 06:24:13 +01:00
Unbit b559354845 more tests for bitmap cache 2014-02-13 06:16:02 +01:00
Unbit 46a2fefb04 added overlap check for cache 2014-02-13 06:06:29 +01:00
Unbit c6c9baa7b5 initial test suite for bitmap cache mode 2014-02-12 18:54:39 +01:00
Danila Shtan c37710f4c2 Add myself to contributors
as agreed at https://github.com/unbit/uwsgi/pull/530#issuecomment-34859953
2014-02-12 22:35:10 +05:00
Danila Shtan 943c20b88c typo fix 2014-02-12 22:33:40 +05:00
Unbit a442614db0 fixed #531 2014-02-12 17:00:47 +01:00
Unbit 5830af37ba restore back needed_bytes 2014-02-12 16:25:02 +01:00
unbit de4c563169 Merge pull request #530 from ramm/master
fixed bitmap allocation bugs
2014-02-12 16:22:56 +01:00
Danila Shtan 77f008e24c fix unmark interval inside cache_update 2014-02-12 18:20:39 +05:00
Danila Shtan df0bd832b4 bitmap allocation fix
fix cache_mark offset bug and change cache_unmark according to previous changes)
2014-02-12 17:36:40 +05:00
Danila Shtan 07c42c262f fix comment typos 2014-02-12 15:44:41 +05:00
Danila Shtan cb131836ae remove extra bit in bitmap_pos optimisation
looks like it was added because there was an error in counting last_byte_bit position in cache_mark_blocks()
2014-02-12 15:42:46 +05:00
Danila Shtan 2c6855a969 fix bitmap allocation 2014-02-12 15:37:44 +05:00
Roberto De Ioris 79ca1940de fixed #527 2014-02-12 06:59:24 +01:00
Roberto De Ioris d46879dca9 fixed #528 2014-02-12 06:33:47 +01:00
Roberto De Ioris 9b889f7b77 another spooler-related fix (fd leak) 2014-02-12 06:28:49 +01:00
Roberto De Ioris 1128d09187 fixed #526 2014-02-12 06:05:29 +01:00
Roberto De Ioris d3d4d04fac fixed #524 2014-02-11 06:27:01 +01:00
unbit 4a554db63b Merge pull request #521 from methane/patch-1
logpipe: Don't setsid() twice.
2014-02-10 12:02:27 +01:00
INADA Naoki 8b799b4f9f logpipe: Don't setsid() twice. 2014-02-10 20:00:50 +09:00
136 changed files with 6666 additions and 2091 deletions
+11
View File
@@ -4,10 +4,21 @@
*.jar
*~
*.so
*.gox
*.a
*.dll
*.key
*.orig
*.rej
/uwsgi
/uwsgibuild.*
/core/config_py.c
/t/ring/target
core/dot_h.c
+# coverity
+/cov-int/
+uwsgi.tar.xz
+6 -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>
@@ -25,3 +25,8 @@ Mingli Yuan
Natanael Copa
Roberto Leandrini
Ryan Petrello
Danila Shtan <danila@shtan.ru>
Ævar Arnfjörð Bjarmason
Yu Zhao (getcwd)
Mathieu Dupuy
Adriano Di Luzio (adriano@unbit.it)
+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,
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = python,asyncio,greenlet
inherit = base
Binary file not shown.
+26 -27
View File
@@ -18,18 +18,18 @@ void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
if (msg[len-1] != '\n') {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s\n", len, msg);
uwsgi_log_verbose("ALARM: %.*s\n", len, msg);
}
}
else {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s", len, msg);
uwsgi_log_verbose("ALARM: %.*s", len, msg);
}
}
}
@@ -363,6 +363,19 @@ void uwsgi_alarm_thread_start() {
}
}
void uwsgi_alarm_trigger_uai(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
}
#ifdef UWSGI_PCRE
// check if a log should raise an alarm
void uwsgi_alarm_log_check(char *msg, size_t len) {
@@ -372,7 +385,14 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
while (ual) {
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
if (!ual->negate) {
uwsgi_alarm_log_run(ual, msg, len);
struct uwsgi_alarm_ll *uall = ual->alarms;
while (uall) {
if (uwsgi.alarm_cheap)
uwsgi_alarm_trigger_uai(uall->alarm, msg, len);
else
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
else {
break;
@@ -397,18 +417,6 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
uai->last_msg_size = len;
}
#ifdef UWSGI_PCRE
// call the alarms mapped to a log line
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
struct uwsgi_alarm_ll *uall = ual->alarms;
while (uall) {
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
#endif
// this is the api function workers,mules and whatever you want can call from code
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
if (!uwsgi.alarm_thread) return;
@@ -416,16 +424,7 @@ void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
if (!uai) return;
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
uwsgi_alarm_trigger_uai(uai, msg, len);
}
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
+20 -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
@@ -387,6 +388,23 @@ end:
}
static int uwsgi_async_wait_milliseconds_hook(int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
timeout = timeout / 1000;
if (!timeout) timeout = 1;
async_add_timeout(wsgi_req, timeout);
wsgi_req->async_force_again = 1;
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
if (wsgi_req->async_timed_out) {
wsgi_req->async_timed_out = 0;
return 0;
}
return -1;
}
void async_loop() {
if (uwsgi.async < 2) {
@@ -414,6 +432,7 @@ void async_loop() {
uwsgi.wait_write_hook = async_wait_fd_write;
uwsgi.wait_read_hook = async_wait_fd_read;
uwsgi.wait_read2_hook = async_wait_fd_read2;
uwsgi.wait_milliseconds_hook = uwsgi_async_wait_milliseconds_hook;
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
+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] == '\\') {
+330 -128
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;
@@ -32,7 +75,7 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
// which is the first free bit?
uint64_t bitmap_byte = 0;
uint8_t bitmap_bit = 0;
if (uc->blocks_bitmap_pos > 0) {
bitmap_byte = uc->blocks_bitmap_pos/8;
bitmap_bit = uc->blocks_bitmap_pos % 8;
@@ -45,6 +88,8 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
uint64_t j;
uint64_t found = 0;
uint64_t need_to_scan = uc->blocks_bitmap_size;
// we make an addition round for the corner case of a single byte map not starting from 0
if (bitmap_bit > 0) need_to_scan++;
j = bitmap_byte;
//uwsgi_log("start scanning %llu bytes starting from %llu need: %llu\n", (unsigned long long) need_to_scan, (unsigned long long) bitmap_byte, (unsigned long long) needed_blocks);
while(need_to_scan) {
@@ -73,7 +118,9 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
}
found++;
if (found == needed_blocks) {
//printf("found %llu consecutive bit starting from byte %llu\n", found, base);
#ifdef UWSGI_DEBUG
printf("found %llu consecutive bit starting from byte %llu\n", (unsigned long long) found, (unsigned long long) base);
#endif
return ((base*8) + base_bit);
}
}
@@ -82,12 +129,14 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
}
j++;
need_to_scan--;
// check for overlap
if (j >= need_to_scan) {
// check for overlap (that is not supported)
if (j >= uc->blocks_bitmap_size) {
j = 0;
found = 0;
base = 0xffffffffffffffffLLU;
base_bit = 0;
// we use bitmap_bit only at the first round
bitmap_bit = 0;
}
}
@@ -102,19 +151,27 @@ static uint64_t cache_mark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64
uint64_t first_byte = index/8;
uint8_t first_byte_bit = index % 8;
uint64_t last_byte = (index+needed_blocks)/8;
uint8_t last_byte_bit = (index+needed_blocks) % 8;
// offset starts with 0, so actual last bit is index + needed_blocks - 1
uint64_t last_byte = (index + needed_blocks - 1) / 8;
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
uint64_t needed_bytes = (last_byte - first_byte) + 1;
//uwsgi_log("%llu %u %llu %u\n", first_byte, first_byte_bit, last_byte, last_byte_bit);
uint8_t mask = 0xff >> first_byte_bit;
if (needed_bytes == 1) {
// kinda hacky, but it does the job
mask >>= (7 - last_byte_bit);
mask <<= (7 - last_byte_bit);
}
uc->blocks_bitmap[first_byte] |= mask;
uint64_t needed_bytes = (last_byte - first_byte)+1;
if (needed_bytes > 1) {
mask = 0xff << (8 - last_byte_bit);
uc->blocks_bitmap[last_byte-1] |= mask;
mask = 0xff << (7 - last_byte_bit);
uc->blocks_bitmap[last_byte] |= mask;
}
if (needed_bytes > 2) {
@@ -130,19 +187,28 @@ static void cache_unmark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64_t
uint64_t first_byte = index/8;
uint8_t first_byte_bit = index % 8;
uint64_t last_byte = (index+needed_blocks)/8;
uint8_t last_byte_bit = (index+needed_blocks) % 8;
// offset starts with 0, so actual last bit is index + needed_blocks - 1
uint64_t last_byte = (index + needed_blocks - 1)/8;
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
// here we use XOR (0+0 = 0 | 1+0 = 1 | 0+1 = 1| 1+1 = 0|
uint64_t needed_bytes = (last_byte - first_byte) + 1;
uint8_t mask = 0xff >> first_byte_bit;
uc->blocks_bitmap[first_byte] ^= mask;
uint8_t mask = 0xff >> first_byte_bit;
uint64_t needed_bytes = (last_byte - first_byte)+1;
if (needed_bytes == 1) {
// kinda hacky, but it does the job
mask >>= (7 - last_byte_bit);
mask <<= (7 - last_byte_bit);
}
// here we use AND (0+0 = 0 | 1+0 = 0 | 0+1 = 0| 1+1 = 1)
// 0 in mask means "unmark", 1 in mask means "do not change"
// so we need to invert the mask
uc->blocks_bitmap[first_byte] &= ~mask;
if (needed_bytes > 1) {
mask = 0xff << (8 - last_byte_bit);
uc->blocks_bitmap[last_byte-1] ^= mask;
mask = 0xff << (7 - last_byte_bit);
uc->blocks_bitmap[last_byte] &= ~mask;
}
if (needed_bytes > 2) {
@@ -283,16 +349,24 @@ next2:
void uwsgi_cache_init(struct uwsgi_cache *uc) {
uc->hashtable = uwsgi_calloc_shared(sizeof(uint64_t) * uc->hashsize);
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->blocks);
// the first cache item is always zero
uc->first_available_block = 1;
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->max_items);
uc->unused_blocks_stack_ptr = 0;
uc->filesize = ( (sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items) + (uc->blocksize * uc->blocks);
uint64_t i;
for (i = 1; i < uc->max_items; i++) {
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
}
if (uc->use_blocks_bitmap) {
uc->blocks_bitmap_size = uc->blocks/8;
if (uc->blocks % 8 > 0) uc->blocks_bitmap_size++;
uint8_t m = uc->blocks % 8;
if (m > 0) uc->blocks_bitmap_size++;
uc->blocks_bitmap = uwsgi_calloc_shared(uc->blocks_bitmap_size);
if (m > 0) {
uc->blocks_bitmap[uc->blocks_bitmap_size-1] = 0xff >> m;
}
}
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
@@ -300,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);
@@ -361,7 +443,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
uc->name,
(unsigned long long) uc->filesize / (1024 * 1024),
(unsigned long long) sizeof(struct uwsgi_cache_item)+uc->keysize,
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->max_items),
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->blocks),
(unsigned long long) uc->blocks_bitmap_size);
uwsgi_cache_setup_nodes(uc);
@@ -381,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);
@@ -406,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) {
@@ -429,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;
@@ -441,6 +535,38 @@ uint32_t uwsgi_cache_exists2(struct uwsgi_cache *uc, char *key, uint16_t keylen)
return uwsgi_cache_get_index(uc, key, keylen);
}
static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *next, *curr = cache_item(index);
if (curr->lru_next) {
next = cache_item(curr->lru_next);
next->lru_prev = curr->lru_prev;
} else
uc->lru_tail = curr->lru_prev;
if (curr->lru_prev) {
prev = cache_item(curr->lru_prev);
prev->lru_next = curr->lru_next;
} else
uc->lru_head = curr->lru_next;
}
static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *curr = cache_item(index);
if (uc->lru_tail) {
prev = cache_item(uc->lru_tail);
prev->lru_next = index;
} else
uc->lru_head = index;
curr->lru_next = 0;
curr->lru_prev = uc->lru_tail;
uc->lru_tail = index;
}
char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
@@ -450,6 +576,10 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
return NULL;
*valsize = uci->valsize;
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
}
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
@@ -489,6 +619,10 @@ char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
*valsize = uci->valsize;
if (expires)
*expires = uci->expires;
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
}
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
@@ -523,50 +657,56 @@ char *uwsgi_cache_get4(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t index, uint16_t flags) {
struct uwsgi_cache_item *uci;
int ret = -1;
if (!index)
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) index = uwsgi_cache_get_index(uc, key, keylen);
if (index) {
uci = cache_item(index);
if (uci->keysize > 0) {
// unmark blocks
if (uc->blocks_bitmap) cache_unmark_blocks(uc, uci->first_block, uci->valsize);
// put back the block in unused stack
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
// unlink prev and next (if any)
if (uci->prev) {
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
ucii->next = uci->next;
}
else {
// set next as the new entry point (could be 0)
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
}
if (uci->next) {
struct uwsgi_cache_item *ucii = cache_item(uci->next);
ucii->prev = uci->prev;
}
if (!uci->prev && !uci->next) {
// reset hashtable entry
uc->hashtable[uci->hash % uc->hashsize] = 0;
}
if (uc->purge_lru)
lru_remove_item(uc, index);
uc->n_items--;
}
ret = 0;
uci->keysize = 0;
uci->valsize = 0;
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
// unmark blocks
if (uc->blocks_bitmap) {
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
}
ret = 0;
// relink collisioned entry
if (uci->prev) {
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
ucii->next = uci->next;
}
else {
// set next as the new entry point (could be 0)
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
}
if (uci->next) {
struct uwsgi_cache_item *ucii = cache_item(uci->next);
ucii->prev = uci->prev;
}
if (!uci->prev && !uci->next) {
// reset hashtable entry
//uwsgi_log("!!! resetted hashtable entry !!!\n");
uc->hashtable[uci->hash % uc->hashsize] = 0;
}
uci->hash = 0;
uci->prev = 0;
uci->next = 0;
uci->expires = 0;
uc->n_items--;
if (uc->use_last_modified) {
uc->last_modified_at = uwsgi_now();
}
@@ -584,7 +724,10 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
uint64_t i;
unsigned long long restored = 0;
for (i = 0; i < uc->max_items; i++) {
// reset unused blocks
uc->unused_blocks_stack_ptr = 0;
for (i = 1; i < uc->max_items; i++) {
// valid record ?
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->keysize) {
@@ -596,7 +739,6 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
}
else {
// put this record in unused stack
uc->first_available_block = i;
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
}
@@ -613,7 +755,6 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
struct uwsgi_cache_item *uci, *ucii;
// used to reset key allocation in bitmap mode
uint8_t rollback_mode = 0;
int ret = -1;
time_t now = 0;
@@ -631,56 +772,43 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) {
if (uc->first_available_block >= uc->max_items && !uc->unused_blocks_stack_ptr) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
goto end;
}
if (uc->unused_blocks_stack_ptr) {
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_block);
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
uc->unused_blocks_stack_ptr--;
}
else {
rollback_mode = 1;
index = uc->first_available_block;
if (uc->first_available_block < uc->max_items) {
rollback_mode = 2;
uc->first_available_block++;
}
if (!uc->unused_blocks_stack_ptr) {
cache_full(uc);
if (!uc->unused_blocks_stack_ptr)
goto end;
}
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
uc->unused_blocks_stack_ptr--;
uci = cache_item(index);
if (!uc->blocks_bitmap) {
uci->first_block = index;
}
else {
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
//uwsgi_log("first block = %llu\n", uci->first_block);
if (uci->first_block == 0xffffffffffffffffLLU) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
if (rollback_mode == 0) {
uc->unused_blocks_stack_ptr++;
}
else if (rollback_mode == 2) {
uc->first_available_block--;
}
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+1) > uc->blocks) {
if (uci->first_block + needed_blocks >= uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
}
}
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
if (uc->purge_lru)
lru_add_item(uc, index);
else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!uc->next_scan || uc->next_scan > expires)
uc->next_scan = expires;
}
uci->expires = expires;
uci->hash = uc->hash->func(key, keylen);
@@ -745,9 +873,16 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
}
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
uci = cache_item(index);
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
} else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!uc->next_scan || uc->next_scan > expires)
uc->next_scan = expires;
}
uci->expires = expires;
}
if (uc->blocks_bitmap) {
@@ -755,22 +890,21 @@ 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) {
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+1) > uc->blocks) {
if (uci->first_block + needed_blocks >= uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
}
// unmark the old blocks
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
cache_unmark_blocks(uc, old_first_block, uci->valsize);
}
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
@@ -965,39 +1099,66 @@ void *cache_udp_server_loop(void *ucache) {
return NULL;
}
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 || uc->lazy_expire)
return 0;
uwsgi_rlock(uc->lock);
if (!uc->next_scan || uc->next_scan > (uint64_t)uwsgi.current_time) {
uwsgi_rwunlock(uc->lock);
return 0;
}
uwsgi_rwunlock(uc->lock);
// skip the first slot
for (i = 1; i < uc->max_items; i++) {
struct uwsgi_cache_item *uci = cache_item(i);
uwsgi_wlock(uc->lock);
// we reset next scan time first, then we find the least
// expiration time from those that are NOT expired yet.
if (i == 1)
uc->next_scan = 0;
if (uci->expires) {
if (uci->expires <= (uint64_t)uwsgi.current_time) {
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
freed_items++;
} else if (!uc->next_scan || uc->next_scan > uci->expires) {
uc->next_scan = uci->expires;
}
}
uwsgi_rwunlock(uc->lock);
}
return freed_items;
}
static void *cache_sweeper_loop(void *ucache) {
uint64_t i;
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
struct uwsgi_cache *uc = (struct uwsgi_cache *) ucache;
if (!uwsgi.cache_expire_freq)
uwsgi.cache_expire_freq = 3;
// remove expired cache items TODO use rb_tree timeouts
for (;;) {
struct uwsgi_cache *uc;
for (uc = (struct uwsgi_cache *)ucache; uc; uc = uc->next) {
uint64_t freed_items = cache_sweeper_free_items(uc);
if (uwsgi.cache_report_freed_items && freed_items)
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long)freed_items, uc->name);
}
sleep(uwsgi.cache_expire_freq);
uint64_t freed_items = 0;
// skip the first slot
for (i = 1; i < uc->max_items; i++) {
uwsgi_wlock(uc->lock);
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->expires) {
if (uci->expires < (uint64_t) uwsgi.current_time) {
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
freed_items++;
}
}
uwsgi_rwunlock(uc->lock);
}
if (uwsgi.cache_report_freed_items && freed_items > 0) {
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long) freed_items, uc->name);
}
};
}
return NULL;
}
@@ -1017,19 +1178,28 @@ void uwsgi_cache_sync_all() {
void uwsgi_cache_start_sweepers() {
struct uwsgi_cache *uc = uwsgi.caches;
if (uwsgi.cache_no_expire)
return;
int need_to_run = 0;
while(uc) {
pthread_t cache_sweeper;
if (!uwsgi.cache_no_expire && !uc->no_expire) {
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, (void *) uc)) {
uwsgi_error("pthread_create()");
uwsgi_log("unable to run the sweeper for cache \"%s\" !!!\n", uc->name);
}
else {
uwsgi_log("sweeper thread enabled for cache \"%s\"\n", uc->name);
}
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() {
@@ -1097,12 +1267,19 @@ 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;
char *c_bitmap = NULL;
char *c_use_last_modified = NULL;
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,
@@ -1119,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,
@@ -1130,6 +1309,14 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"bitmap", &c_bitmap,
"lastmod", &c_use_last_modified,
"math_initial", &c_math_initial,
"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);
@@ -1177,9 +1364,19 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
uc->max_item_size = uc->blocksize * uc->blocks;
}
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); }
@@ -1211,6 +1408,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
}
}
if (c_purge_lru)
uc->purge_lru = 1;
}
uwsgi_cache_init(uc);
@@ -1466,7 +1665,10 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
// we have a local cache !!!
if (uc) {
uwsgi_rlock(uc->lock);
if (uc->purge_lru)
uwsgi_wlock(uc->lock);
else
uwsgi_rlock(uc->lock);
char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires);
if (!value) {
uwsgi_rwunlock(uc->lock);
@@ -1788,7 +1990,7 @@ int uwsgi_cache_magic_clear(char *cache) {
if (uc) {
uint64_t i;
uwsgi_wlock(uc->lock);
for (i = 1; i < uwsgi.caches->max_items; i++) {
for (i = 1; i < uc->max_items; i++) {
if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
uwsgi_rwunlock(uc->lock);
return -1;
+38 -1
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;
@@ -400,7 +420,8 @@ void add_exported_option_do(char *key, char *value, int configured, int placehol
if (uwsgi.logic_opt_running)
goto add;
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")) {
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")
|| !strcmp(key, "end-if") || !strcmp(key, "end-for")) {
if (uwsgi.logic_opt_data) {
free(uwsgi.logic_opt_data);
}
@@ -815,3 +836,19 @@ char *uwsgi_manage_placeholder(char *key) {
return current_value;
}
void uwsgi_opt_resolve(char *opt, char *value, void *foo) {
char *equal = strchr(value, '=');
if (!equal) {
uwsgi_log("invalid resolve syntax, must be placeholder=domain\n");
exit(1);
}
char *ip = uwsgi_resolve_ip(equal+1);
if (!ip) {
uwsgi_log("unable to resolve name %s\n", equal+1);
uwsgi_error("uwsgi_resolve_ip()");
exit(1);
}
char *new_opt = uwsgi_concat2n(value, (equal-value)+1, ip, strlen(ip));
uwsgi_opt_set_placeholder(opt, new_opt, (void *) 1);
}
+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);
+867 -586
View File
File diff suppressed because it is too large Load Diff
+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 {
+11
View File
@@ -48,6 +48,14 @@ static void subscriptions_blocker() {
}
}
static void emperor_rescan() {
if (uwsgi.emperor_pid > 0) {
if (kill(uwsgi.emperor_pid, SIGWINCH)) {
uwsgi_error("emperor_rescan()/kill()");
}
}
}
/*
this is called as soon as possibile allowing plugins (or hooks) to override it
@@ -72,8 +80,10 @@ 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;
uwsgi_fifo_table['f'] = uwsgi_refork_master;
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
@@ -122,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);
+88 -6
View File
@@ -233,17 +233,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);
@@ -485,6 +494,60 @@ static int uwsgi_hook_callret(char *arg) {
return func();
}
static int uwsgi_hook_rpc(char *arg) {
int ret = -1;
size_t i, argc = 0;
char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
if (!argc) goto end;
if (argc > 256) goto destroy;
char *argv[256];
uint16_t argvs[256];
char *node = NULL;
char *func = rargv[0];
char *at = strchr(func, '@');
if (at) {
*at = 0;
node = at + 1;
}
for(i=0;i<(argc-1);i++) {
size_t a_len = strlen(rargv[i+1]);
if (a_len > 0xffff) goto destroy;
argv[i] = rargv[i+1] ;
argvs[i] = a_len;
}
uint64_t size = 0;
// response must be always freed
char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size);
if (response) {
if (at) *at = '@';
uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response);
free(response);
ret = 0;
}
destroy:
for(i=0;i<argc;i++) {
free(rargv[i]);
}
end:
free(rargv);
return ret;
}
static int uwsgi_hook_retryrpc(char *arg) {
for(;;) {
int ret = uwsgi_hook_rpc(arg);
if (!ret) break;
sleep(2);
}
return 0;
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
@@ -523,6 +586,9 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
@@ -561,6 +627,22 @@ void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
int ret = uh->func(colon+1);
if (fatal && ret != 0) {
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
if (uwsgi.master_process) {
if (uwsgi.workers) {
if (uwsgi.workers[0].pid == getpid()) {
kill_them_all(0);
return;
}
else {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("uwsgi_hooks_run()/kill()");
exit(1);
}
return;
}
}
}
exit(1);
}
}
+5 -4
View File
@@ -3,9 +3,9 @@
extern struct uwsgi_server uwsgi;
struct http_status_codes {
const char key[3];
const char *message;
int message_size;
const char key[3];
const char *message;
int message_size;
};
/* statistically ordered */
@@ -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;
@@ -113,6 +113,7 @@ void uwsgi_init_default() {
uwsgi.log_master_bufsize = 8192;
uwsgi.worker_reload_mercy = 60;
uwsgi.mule_reload_mercy = 60;
uwsgi.max_vars = MAX_VARS;
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
+43 -3
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;
@@ -517,12 +537,28 @@ fallback:
goto end;
}
// is it a potential virtual file (/proc, /sys...) ?
int is_virtual = 0;
if (sb.st_size == 0) {
is_virtual = 1;
sb.st_size = 4096;
}
buffer = uwsgi_malloc(sb.st_size + add_zero);
len = read(fd, buffer, sb.st_size);
if (len != sb.st_size) {
uwsgi_error("read()");
exit(1);
if (!is_virtual) {
if (len != sb.st_size) {
}
}
else {
if (len >= 0) {
sb.st_size = len;
}
else {
uwsgi_error("read()");
exit(1);
}
}
close(fd);
@@ -951,6 +987,7 @@ int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) {
ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
int ret;
errno = 0;
ssize_t rlen = read(fd, buf, len);
if (rlen > 0) {
return rlen;
@@ -961,8 +998,10 @@ ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
}
return -1;
wait:
errno = 0;
ret = uwsgi.wait_read_hook(fd, timeout);
if (ret > 0) {
errno = 0;
rlen = read(fd, buf, len);
if (rlen > 0) {
return rlen;
@@ -1230,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) {
+3
View File
@@ -1212,6 +1212,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();
}
+109 -89
View File
@@ -301,19 +301,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 +354,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) {
@@ -477,13 +485,19 @@ void uwsgi_check_logrotate(void) {
int need_rotation = 0;
int need_reopen = 0;
off_t logsize;
if (uwsgi.log_master) {
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
}
else {
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
logsize = lseek(2, 0, SEEK_CUR);
}
if (logsize < 0) {
uwsgi_error("uwsgi_check_logrotate()/lseek()");
return;
}
uwsgi.shared->logsize = logsize;
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
need_rotation = 1;
@@ -505,40 +519,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() {
@@ -917,7 +937,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while (ul) {
if (!strcmp(ul->id, id)) {
if (ul->id && !strcmp(ul->id, id)) {
return ul;
}
ul = ul->next;
@@ -1116,7 +1136,7 @@ static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
}
static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) {
if (!uwsgi.log_strftime) {
if (!uwsgi.logformat_strftime || !uwsgi.log_strftime) {
return uwsgi_lf_ltime(wsgi_req, buf);
}
*buf = uwsgi_malloc(64);
@@ -1839,7 +1859,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) {
size_t msg_len = len;
if (msg[len-1] == '\n') msg_len--;
char *e_json = uwsgi_malloc(msg_len * 2);
char *e_json = uwsgi_malloc((msg_len * 2)+1);
escape_json(msg, msg_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
@@ -1848,7 +1868,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
free(e_json);
}
else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) {
char *e_json = uwsgi_malloc(len * 2);
char *e_json = uwsgi_malloc((len * 2)+1);
escape_json(msg, len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
@@ -1869,7 +1889,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
int strftime_len = strftime(sftime, 64, buf, localtime(&now));
free(buf);
if (strftime_len > 0) {
char *e_json = uwsgi_malloc(strftime_len * 2);
char *e_json = uwsgi_malloc((strftime_len * 2)+1);
escape_json(sftime, strftime_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
+46 -8
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;
@@ -135,6 +145,15 @@ void uwsgi_master_check_mercy() {
}
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0 && uwsgi.mules[i].cursed_at) {
if (uwsgi_now() > uwsgi.mules[i].no_mercy_at) {
uwsgi_log_verbose("mule %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i + 1, uwsgi.mules[i].pid);
uwsgi_curse_mule(i, SIGKILL);
}
}
}
}
@@ -264,17 +283,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;
@@ -836,7 +861,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()");
}
}
}
}
@@ -907,6 +935,7 @@ int master_loop(char **argv, char **environ) {
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid == diedpid) {
uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid);
uwsgi.mules[i].pid = 0;
goto next;
}
}
@@ -954,6 +983,11 @@ next:
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) {
uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid);
if (uwsgi.lazy_apps && uwsgi.need_app) {
uwsgi_log_verbose("need-app requested, destroying the instance...\n");
kill_them_all(0);
continue;
}
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) {
uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid);
@@ -969,6 +1003,10 @@ next:
reap_them_all(0);
continue;
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP_CODE) {
uwsgi_log("worker %d asked for cheap mode (pid: %d)...\n", thewid, (int) diedpid);
uwsgi.workers[thewid].cheaped = 1;
}
else if (uwsgi.workers[thewid].manage_next_request) {
if (WIFSIGNALED(waitpid_status)) {
uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
+55 -18
View File
@@ -25,6 +25,11 @@ int uwsgi_master_check_reload(char **argv) {
return 0;
}
}
for(i=0;i<uwsgi.mules_cnt;i++) {
if (uwsgi.mules[i].pid > 0) {
return 0;
}
}
uwsgi_reload(argv);
// never here (unless in shared library mode)
return -1;
@@ -35,26 +40,44 @@ int uwsgi_master_check_reload(char **argv) {
// check for chain reload
void uwsgi_master_check_chain() {
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) {
uwsgi_log_verbose("chain is still waiting for worker %d...\n", uwsgi.status.chain_reloading-1);
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);
}
@@ -115,12 +138,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;
@@ -312,6 +348,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;
+51 -20
View File
@@ -24,6 +24,15 @@ void uwsgi_curse(int wid, int sig) {
}
}
void uwsgi_curse_mule(int mid, int sig) {
uwsgi.mules[mid].cursed_at = uwsgi_now();
uwsgi.mules[mid].no_mercy_at = uwsgi.mules[mid].cursed_at + uwsgi.mule_reload_mercy;
if (sig) {
(void) kill(uwsgi.mules[mid].pid, sig);
}
}
static void uwsgi_signal_spoolers(int signum) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
@@ -43,13 +52,6 @@ void uwsgi_destroy_processes() {
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
@@ -60,14 +62,25 @@ void uwsgi_destroy_processes() {
}
}
// TODO mules can be programmed to be gracefully reloaded
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
kill(uwsgi.mules[i].pid, SIGKILL);
waitpid(uwsgi.mules[i].pid, &waitpid_status, 0);
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
if (uwsgi.emperor_pid > 0) {
kill(uwsgi.emperor_pid, SIGINT);
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
// increase timeout for being more tolerant
timeout+=2;
int waitpid_status;
while (uwsgi_now() < timeout) {
pid_t diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
if (diedpid == uwsgi.emperor_pid) {
goto nomoremperor;
}
uwsgi_log("waiting for Emperor death...\n");
sleep(1);
}
}
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
nomoremperor:
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
}
@@ -149,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
@@ -159,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) {
@@ -399,9 +414,17 @@ void uwsgi_reload(char **argv) {
uwsgi_log("fork()'ing uWSGI...\n");
}
// ask for configuration (if needed)
if (uwsgi.has_emperor && uwsgi.emperor_fd_config > -1) {
char byte = 2;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("uwsgi_reload()/write()");
}
}
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
uwsgi_error("uwsgi_reload()/chdir()");
}
/* check fd table (a module can obviosly open some fd on initialization...) */
@@ -546,9 +569,10 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
}
}
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
close(uwsgi.shared->spooler_signal_pipe[1]);
}
@@ -774,7 +798,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
// allocate 2x the size of original command
// in case we need to escape all chars
char *cmd = uwsgi_malloc(strlen(ud->command)*2);
char *cmd = uwsgi_malloc((strlen(ud->command)*2)+1);
escape_json(ud->command, strlen(ud->command), cmd);
if (uwsgi_stats_keyval_comma(us, "cmd", cmd)) {
free(cmd);
@@ -891,7 +915,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
}
if (uwsgi.has_metrics) {
if (uwsgi.has_metrics && !uwsgi.stats_no_metrics) {
if (uwsgi_stats_key(us, "metrics"))
goto end;
@@ -1123,6 +1147,8 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_close(us))
goto end;
if (uwsgi.stats_no_cores) goto nocores;
if (uwsgi_stats_comma(us))
goto end;
@@ -1184,9 +1210,12 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_close(us))
goto end;
nocores:
if (uwsgi_stats_object_close(us))
goto end;
if (i < uwsgi.numproc - 1) {
if (uwsgi_stats_comma(us))
goto end;
@@ -1262,7 +1291,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keyslong_comma(us, "week", (long long) ucron->week))
goto end;
char *cmd = uwsgi_malloc(strlen(ucron->command)*2);
char *cmd = uwsgi_malloc((strlen(ucron->command)*2)+1);
escape_json(ucron->command, strlen(ucron->command), cmd);
if (uwsgi_stats_keyval_comma(us, "command", cmd)) {
free(cmd);
@@ -1692,6 +1721,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) {
@@ -1750,6 +1780,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) {
+27 -2
View File
@@ -321,6 +321,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
char *m_initial_value = NULL;
char *m_children = NULL;
char *m_alias = NULL;
char *m_reset_after_push = NULL;
if (!strchr(arg, '=')) {
m_name = uwsgi_str(arg);
@@ -340,6 +341,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
"arg3n", &m_arg3n,
"children", &m_children,
"alias", &m_alias,
"reset_after_push", &m_reset_after_push,
NULL)) {
uwsgi_log("invalid metric keyval syntax: %s\n", arg);
exit(1);
@@ -381,6 +383,10 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
struct uwsgi_metric* um = uwsgi_register_metric(m_name, m_oid, type, collector, NULL, freq, NULL);
um->initial_value = initial_value;
if (m_reset_after_push){
um->reset_after_push = 1;
}
if (m_children) {
char *p, *ctx = NULL;
uwsgi_foreach_token(m_children, ";", p, ctx) {
@@ -427,6 +433,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
if (m_initial_value) free(m_initial_value);
if (m_children) free(m_children);
if (m_alias) free(m_alias);
if (m_reset_after_push) free(m_reset_after_push);
return um;
}
@@ -613,7 +620,7 @@ struct uwsgi_metric *uwsgi_metric_find_by_asn(char *asn, size_t len) {
}\
if (!um) return -1;\
if (um->collector || um->type == UWSGI_METRIC_ALIAS) return -1;\
uwsgi_rlock(uwsgi.metrics_lock)
uwsgi_wlock(uwsgi.metrics_lock)
int uwsgi_metric_set(char *name, char *oid, int64_t value) {
um_op;
@@ -694,6 +701,22 @@ int64_t uwsgi_metric_getn(char *name, size_t nlen, char *oid, size_t olen) {
return ret;
}
int uwsgi_metric_set_max(char *name, char *oid, int64_t value) {
um_op;
if (value > *um->value)
*um->value = value;
uwsgi_rwunlock(uwsgi.metrics_lock);
return 0;
}
int uwsgi_metric_set_min(char *name, char *oid, int64_t value) {
um_op;
if ((value > um->initial_value || 0) && value < *um->value)
*um->value = value;
uwsgi_rwunlock(uwsgi.metrics_lock);
return 0;
}
#define uwsgi_metric_name(f, n) ret = snprintf(buf, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
#define uwsgi_metric_name2(f, n, n2) ret = snprintf(buf, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
@@ -768,9 +791,11 @@ void uwsgi_setup_metrics() {
struct uwsgi_metric *vsz = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].vsz_size, 0, NULL);
if (i > 0) uwsgi_metric_add_child(total_vsz, vsz);
// skip core metrics for core 0
// skip core metrics for worker 0
if (i == 0) continue;
if (uwsgi.metrics_no_cores) continue;
int j;
for(j=0;j<uwsgi.cores;j++) {
uwsgi_metric_name2("worker.%d.core.%d.requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.1", i, j);
+9 -6
View File
@@ -43,7 +43,7 @@ void uwsgi_mule(int id) {
#endif
signal(SIGALRM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGHUP, end_me);
signal(SIGINT, end_me);
signal(SIGTERM, end_me);
signal(SIGUSR1, SIG_IGN);
@@ -329,11 +329,13 @@ next:
}
}
int ret = poll(mulepoll, count + farms_count, timeout);
if (ret <= 0) {
uwsgi_error("poll");
int ret = -1;
retry:
ret = poll(mulepoll, count + farms_count, timeout);
if (ret < 0) {
uwsgi_error("uwsgi_mule_get_msg()/poll()");
}
else {
else if (ret > 0 ) {
if (mulepoll[0].revents & POLLIN) {
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
}
@@ -353,7 +355,7 @@ next:
if (interesting_fd > -1) {
len = read(interesting_fd, &uwsgi_signal, 1);
if (len <= 0) {
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) goto clear;
if (uwsgi_is_again()) goto retry;
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
@@ -380,6 +382,7 @@ next:
}
if (len < 0) {
if (uwsgi_is_again()) goto retry;
uwsgi_error("read()");
goto clear;
}
+46
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) {
@@ -237,6 +275,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
void *events = event_queue_alloc(uwsgi.offload_threads_events);
for (;;) {
// TODO make timeout tunable
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events);
for (i = 0; i < nevents; i++) {
int interesting_fd = event_queue_interesting_fd(events, i);
@@ -456,6 +495,13 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
// write event (or just connected)
case 1:
if (fd == uor->fd) {
// maybe we want only a connection...
if (uor->ubuf->pos == 0) {
uor->status = 2;
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
return 0;
}
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
if (rlen > 0) {
uor->written += rlen;
+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 ?
+120 -1
View File
@@ -312,6 +312,7 @@ int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.response_routes) return 0;
if (wsgi_req->response_routes_applied) return 0;
@@ -582,6 +583,39 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
return 0;
}
static int uwsgi_router_return_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route)
{
if (route->data_len < 3)
return UWSGI_ROUTE_BREAK;
uint16_t status_msg_len = 0;
const char *status_msg = uwsgi_http_status_msg(route->data, &status_msg_len);
if (!status_msg)
return UWSGI_ROUTE_BREAK;
char *buf = uwsgi_concat3n(route->data, route->data_len, " ", 1, (char *) status_msg, status_msg_len);
if (uwsgi_response_prepare_headers(wsgi_req, buf, route->data_len + 1 + status_msg_len))
goto end;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10))
goto end;
if (uwsgi_response_add_content_length(wsgi_req, status_msg_len))
goto end;
uwsgi_response_write_body_do(wsgi_req, (char *) status_msg, status_msg_len);
end:
free(buf);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_return(struct uwsgi_route *ur, char *arg)
{
ur->func = uwsgi_router_return_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// simple math router
static int uwsgi_router_simple_math_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -942,6 +976,20 @@ static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) {
return 0;
}
// disable headers
static int uwsgi_router_disableheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->headers_sent = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_disableheaders(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_disableheaders_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// signal route
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
@@ -1071,6 +1119,32 @@ static int uwsgi_router_seturi(struct uwsgi_route *ur, char *arg) {
ur->data_len = strlen(arg);
return 0;
}
// setremoteaddr route
static int uwsgi_router_setremoteaddr_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_ADDR", 11, ub->buf, ub->pos);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->remote_addr = ptr;
wsgi_req->remote_addr_len = ub->pos;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setremoteaddr(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setremoteaddr_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setdocroot route
static int uwsgi_router_setdocroot_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -1144,6 +1218,26 @@ static int uwsgi_router_setscheme(struct uwsgi_route *ur, char *arg) {
return 0;
}
// setmodifiers
static int uwsgi_router_setmodifier1_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->uh->modifier1 = ur->custom;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setmodifier1(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setmodifier1_func;
ur->custom = atoi(arg);
return 0;
}
static int uwsgi_router_setmodifier2_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->uh->modifier2 = ur->custom;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setmodifier2(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setmodifier2_func;
ur->custom = atoi(arg);
return 0;
}
// setuser route
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -1659,6 +1753,10 @@ 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);
}
return ret;
}
@@ -1669,7 +1767,7 @@ static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
if (var_value) {
size_t mime_type_len = 0;
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
ret = uwsgi_get_mime_type(var_value, var_vallen, &mime_type_len);
if (ret) *vallen = mime_type_len;
}
return ret;
@@ -1726,6 +1824,8 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("continue", uwsgi_router_continue);
uwsgi_register_router("last", uwsgi_router_continue);
uwsgi_register_router("break", uwsgi_router_break);
uwsgi_register_router("return", uwsgi_router_return);
uwsgi_register_router("break-with-status", uwsgi_router_return);
uwsgi_register_router("log", uwsgi_router_log);
uwsgi_register_router("donotlog", uwsgi_router_donotlog);
uwsgi_register_router("logvar", uwsgi_router_logvar);
@@ -1736,6 +1836,7 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("remheader", uwsgi_router_remheader);
uwsgi_register_router("clearheaders", uwsgi_router_clearheaders);
uwsgi_register_router("resetheaders", uwsgi_router_clearheaders);
uwsgi_register_router("disableheaders", uwsgi_router_disableheaders);
uwsgi_register_router("signal", uwsgi_router_signal);
uwsgi_register_router("send", uwsgi_router_send);
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
@@ -1747,12 +1848,16 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("setscriptname", uwsgi_router_setscriptname);
uwsgi_register_router("setmethod", uwsgi_router_setmethod);
uwsgi_register_router("seturi", uwsgi_router_seturi);
uwsgi_register_router("setremoteaddr", uwsgi_router_setremoteaddr);
uwsgi_register_router("setpathinfo", uwsgi_router_setpathinfo);
uwsgi_register_router("setdocroot", uwsgi_router_setdocroot);
uwsgi_register_router("setscheme", uwsgi_router_setscheme);
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
uwsgi_register_router("alarm", uwsgi_router_alarm);
uwsgi_register_router("setmodifier1", uwsgi_router_setmodifier1);
uwsgi_register_router("setmodifier2", uwsgi_router_setmodifier2);
uwsgi_register_router("+", uwsgi_router_simple_math_plus);
uwsgi_register_router("-", uwsgi_router_simple_math_minus);
uwsgi_register_router("*", uwsgi_router_simple_math_multiply);
@@ -1940,5 +2045,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
+7 -2
View File
@@ -104,8 +104,12 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
if (node == NULL || !strcmp(node, "")) {
// allocate the whole buffer
if (!uwsgi.rpc_table) {
uwsgi_log("local rpc subsystem is still not initialized !!!\n");
return NULL;
}
*len = uwsgi_rpc(func, argc, argv, argvs, &buffer);
if (*buffer)
if (buffer)
return buffer;
return NULL;
}
@@ -189,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:
+63 -6
View File
@@ -229,8 +229,11 @@ int uwsgi_sharedarea_wait(int id, int freq, int timeout) {
uwsgi_rlock(sa->lock);
uint64_t updates = sa->updates;
uwsgi_rwunlock(sa->lock);
while(timeout == 0 || (timeout > 0 && (waiting/1000) >= timeout)) {
uwsgi.wait_milliseconds_hook(freq);
while(timeout == 0 || waiting == 0 || (timeout > 0 && waiting > 0 && (waiting/1000) < timeout)) {
if (uwsgi.wait_milliseconds_hook(freq)) {
uwsgi_rwunlock(sa->lock);
return -1;
}
waiting += freq;
// lock sa
uwsgi_rlock(sa->lock);
@@ -266,6 +269,27 @@ static struct uwsgi_sharedarea *announce_sa(struct uwsgi_sharedarea *sa) {
return sa;
}
struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t offset) {
int id = uwsgi_sharedarea_new_id();
uwsgi.sharedareas[id] = uwsgi_calloc_shared(sizeof(struct uwsgi_sharedarea));
uwsgi.sharedareas[id]->area = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (uwsgi.sharedareas[id]->area == MAP_FAILED) {
uwsgi_error("uwsgi_sharedarea_init_fd()/mmap()");
exit(1);
}
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]->max_pos = len-1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
free(id_str);
return announce_sa(uwsgi.sharedareas[id]);
}
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));
@@ -301,24 +325,41 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
char *s_fd = NULL;
char *s_ptr = NULL;
char *s_size = NULL;
char *s_offset = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"pages", &s_pages,
"file", &s_file,
"fd", &s_fd,
"ptr", &s_ptr,
"size", &s_size,
"offset", &s_offset,
NULL)) {
uwsgi_log("invalid sharedarea keyval syntax\n");
exit(1);
}
uint64_t len = 0;
off_t offset = 0;
int pages = 0;
if (s_size) {
len = uwsgi_n64(s_size);
if (strlen(s_size) > 2 && s_size[0] == '0' && s_size[1] == 'x') {
len = strtoul(s_size+2, NULL, 16);
}
else {
len = uwsgi_n64(s_size);
}
pages = len / uwsgi.page_size;
if (len % uwsgi.page_size != 0) pages++;
}
if (s_offset) {
if (strlen(s_offset) > 2 && s_offset[0] == '0' && s_offset[1] == 'x') {
offset = strtoul(s_offset+2, NULL, 16);
}
else {
offset = uwsgi_n64(s_offset);
}
}
if (s_pages) {
pages = atoi(s_pages);
@@ -326,27 +367,43 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
char *area = NULL;
struct uwsgi_sharedarea *sa = NULL;
int fd = -1;
if (s_file) {
fd = open(s_file, O_RDWR|O_SYNC);
if (fd < 0) {
uwsgi_error_open(s_file);
exit(1);
}
}
else if (s_fd) {
fd = atoi(s_fd);
}
else if (s_ptr) {
}
if (pages) {
if (!area) {
sa = uwsgi_sharedarea_init(pages);
if (fd > -1) {
sa = uwsgi_sharedarea_init_fd(fd, len, offset);
}
else if (area) {
sa = uwsgi_sharedarea_init_ptr(area, len);
}
else {
uwsgi_sharedarea_init_ptr(area, len);
sa = uwsgi_sharedarea_init(pages);
}
}
else {
uwsgi_log("you need to set a size for a sharedarea !!! [%s]\n", arg);
exit(1);
}
if (s_pages) free(s_pages);
if (s_file) free(s_file);
if (s_fd) free(s_fd);
if (s_ptr) free(s_ptr);
if (s_size) free(s_size);
if (s_offset) free(s_offset);
return sa;
}
+22 -10
View File
@@ -269,20 +269,22 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
uh.pktsize = 0;
uh.modifier2 = sig;
int fd = uwsgi_connect(addr, uwsgi.socket_timeout, 0);
if (fd < 0)
return -1;
int fd = uwsgi_connect(addr, 0, 1);
if (fd < 0) return -1;
if (write(fd, (char *) &uh, 4) != 4) {
uwsgi_error("uwsgi_remote_signal_send()");
close(fd);
return -1;
}
// wait for connection
if (uwsgi.wait_write_hook(fd, uwsgi.socket_timeout) <= 0) goto end;
int ret = uwsgi_read_response(fd, &uh, uwsgi.socket_timeout, NULL);
if (uwsgi_write_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
if (uwsgi_read_whole_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
close(fd);
return ret;
return uh.modifier2;
end:
close(fd);
return -1;
}
@@ -329,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);
+31 -8
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;
@@ -1733,13 +1738,6 @@ void uwsgi_bind_sockets() {
uwsgi_sock = uwsgi_sock->next;
}
if (uwsgi.chown_socket) {
if (!uwsgi.master_as_root) {
uwsgi_as_root();
}
}
int zero_used = 0;
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -1760,6 +1758,24 @@ void uwsgi_bind_sockets() {
uwsgi_sock->fd = 0;
uwsgi_sock->bound = 1;
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
if (!uwsgi.is_a_reload) {
if (uwsgi.chown_socket) {
uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket);
}
if (uwsgi.chmod_socket) {
if (uwsgi.chmod_socket_value) {
if (chmod(uwsgi_sock->name, uwsgi.chmod_socket_value) != 0) {
uwsgi_error("inherit fd0: chmod()");
}
}
else {
uwsgi_log("chmod() fd0 socket to 666 for lazy and brave users\n");
if (chmod(uwsgi_sock->name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) {
uwsgi_error("inherit fd0: chmod()");
}
}
}
}
}
else {
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
@@ -1794,6 +1810,13 @@ void uwsgi_bind_sockets() {
stdin_done:
if (uwsgi.chown_socket) {
if (!uwsgi.master_as_root) {
uwsgi_as_root();
}
}
// check for auto_port socket
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
+11 -8
View File
@@ -190,16 +190,23 @@ static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, ui
}
if (!uwsgi_strncmp(key, key_len, "at", 2)) {
// at can be a float...
char *dot = memchr(value, '.', value_len);
if (dot) {
value_len = dot - value;
}
sr->at = uwsgi_str_num(value, value_len);
return;
}
}
/*
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;
@@ -227,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);
@@ -255,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");
@@ -267,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);
+20 -7
View File
@@ -210,6 +210,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);
@@ -243,19 +247,23 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (dh) {
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_tmp_dh(ctx, dh);
DH_free(dh);
}
}
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
#ifdef NID_X9_62_prime256v1
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
#endif
#endif
#endif
}
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ecdh) {
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
}
#endif
#endif
#endif
if (crt_need_free) free(crt);
@@ -392,6 +400,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);
+2
View File
@@ -459,6 +459,8 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
size_t fsize = st->st_size;
if (wsgi_req->range_to) {
+6 -15
View File
@@ -551,25 +551,16 @@ struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func)
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
if (us->dirty) return;
uint16_t i;
// replace " with '
for(i=0;i<kl;i++) {
if (k[i] == '"') {
k[i] = '\'';
}
}
for(i=0;i<vl;i++) {
if (v[i] == '"') {
v[i] = '\'';
}
}
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
if (uwsgi_stats_str(us, var)) {
char *escaped_var = uwsgi_malloc(((kl+vl+1)*2)+1);
escape_json(var, strlen(var), escaped_var);
free(var);
if (uwsgi_stats_str(us, escaped_var)) {
us->dirty = 1;
free(var);
free(escaped_var);
return;
}
free(var);
free(escaped_var);
if (uwsgi_stats_comma(us)) {
us->dirty = 1;
}
+12
View File
@@ -427,6 +427,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
return NULL;
}
// eventually the packet could be upgraded to sni...
uwsgi_subscription_sni_check(current_slot, usr);
#endif
// remove death mark and update cores and load
node->death_mark = 0;
@@ -677,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))
@@ -1070,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) {
+129 -35
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) {
@@ -982,20 +998,51 @@ nonroot:
}
}
static void close_and_free_request(struct wsgi_request *wsgi_req) {
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
wsgi_req->socket->proto_close(wsgi_req);
}
if (wsgi_req->post_file) {
fclose(wsgi_req->post_file);
}
if (wsgi_req->post_read_buf) {
free(wsgi_req->post_read_buf);
}
if (wsgi_req->post_readline_buf) {
free(wsgi_req->post_readline_buf);
}
if (wsgi_req->proto_parser_buf) {
free(wsgi_req->proto_parser_buf);
}
}
// destroy a request
void uwsgi_destroy_request(struct wsgi_request *wsgi_req) {
wsgi_req->socket->proto_close(wsgi_req);
close_and_free_request(wsgi_req);
int foo;
if (uwsgi.threads > 1) {
// now the thread can die...
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
}
memset(wsgi_req, 0, sizeof(struct wsgi_request));
if (uwsgi.threads > 1) {
// now the thread can die...
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
}
// 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
@@ -1026,10 +1073,11 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uint64_t end_of_request = uwsgi_micros();
wsgi_req->end_of_request = end_of_request;
tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request;
uwsgi.workers[uwsgi.mywid].running_time += tmp_rt;
uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2;
if (!wsgi_req->do_not_account_avg_rt) {
tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request;
uwsgi.workers[uwsgi.mywid].running_time += tmp_rt;
uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2;
}
// get memory usage
if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) {
@@ -1053,27 +1101,8 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uwsgi_apply_final_routes(wsgi_req);
#endif
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
wsgi_req->socket->proto_close(wsgi_req);
}
if (wsgi_req->post_file) {
fclose(wsgi_req->post_file);
}
if (wsgi_req->post_read_buf) {
free(wsgi_req->post_read_buf);
}
if (wsgi_req->post_readline_buf) {
free(wsgi_req->post_readline_buf);
}
if (wsgi_req->proto_parser_buf) {
free(wsgi_req->proto_parser_buf);
}
// close socket and free parsers-allocated memory
close_and_free_request(wsgi_req);
// after_request hook
if (!wsgi_req->is_raw && uwsgi.p[wsgi_req->uh->modifier1]->after_request)
@@ -1159,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;
@@ -3149,6 +3178,10 @@ void escape_json(char *src, size_t len, char *dst) {
*ptr++ = '\\';
*ptr++ = '"';
}
else if (src[i] == '\\') {
*ptr++ = '\\';
*ptr++ = '\\';
}
else {
*ptr++ = src[i];
}
@@ -3382,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;
}
}
@@ -3746,7 +3779,7 @@ static void *uwsgi_thread_run(void *arg) {
return NULL;
}
struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
struct uwsgi_thread *uwsgi_thread_new_with_data(void (*func) (struct uwsgi_thread *), void *data) {
struct uwsgi_thread *ut = uwsgi_calloc(sizeof(struct uwsgi_thread));
@@ -3763,6 +3796,7 @@ struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
uwsgi_socket_nb(ut->pipe[1]);
ut->func = func;
ut->data = data;
pthread_attr_init(&ut->tattr);
pthread_attr_setdetachstate(&ut->tattr, PTHREAD_CREATE_DETACHED);
@@ -3782,6 +3816,10 @@ error:
return NULL;
}
struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
return uwsgi_thread_new_with_data(func, NULL);
}
int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, char kv_separator, ...) {
size_t i;
va_list ap;
@@ -4441,3 +4479,59 @@ 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++;
}
}
// 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++;
}
}
+121 -32
View File
@@ -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},
@@ -101,6 +101,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"declare-option", required_argument, 0, "declare a new uWSGI custom option", uwsgi_opt_add_custom_option, NULL, UWSGI_OPT_IMMEDIATE},
{"declare-option2", required_argument, 0, "declare a new uWSGI custom option (non-immediate)", uwsgi_opt_add_custom_option, NULL, 0},
{"resolve", required_argument, 0, "place the result of a dns query in the specified placeholder, sytax: placeholder=name (immediate option)", uwsgi_opt_resolve, NULL, UWSGI_OPT_IMMEDIATE},
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
{"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE},
@@ -118,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},
@@ -219,6 +224,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
{"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-no-blacklist", no_argument, 0, "disable Emperor blacklisting subsystem", uwsgi_opt_true, &uwsgi.emperor_no_blacklist, 0},
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
{"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0},
#endif
@@ -235,6 +241,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},
@@ -243,6 +250,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0},
{"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0},
{"mule-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a mule can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.mule_reload_mercy, 0},
{"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0},
{"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0},
{"force-gateway", no_argument, 0, "force the spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
@@ -385,6 +393,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},
@@ -452,6 +461,12 @@ 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},
{"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},
@@ -560,6 +575,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"metrics-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metric-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metric-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metrics-no-cores", no_argument, 0, "disable generation of cores-related metrics", uwsgi_opt_true, &uwsgi.metrics_no_cores, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER},
{"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
@@ -570,6 +586,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
{"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"stats-no-cores", no_argument, 0, "disable generation of cores-related stats", uwsgi_opt_true, &uwsgi.stats_no_cores, UWSGI_OPT_MASTER},
{"stats-no-metrics", no_argument, 0, "do not include metrics in stats output", uwsgi_opt_true, &uwsgi.stats_no_metrics, UWSGI_OPT_MASTER},
{"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
{"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0},
{"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0},
@@ -614,6 +632,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
@@ -626,6 +647,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
@@ -672,6 +695,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"use-abort", no_argument, 0, "call abort() on segfault/fpe, could be useful for generating a core dump", uwsgi_opt_true, &uwsgi.use_abort, 0},
{"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-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},
@@ -691,13 +715,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},
@@ -838,6 +862,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},
@@ -1247,6 +1273,11 @@ void kill_them_all(int signum) {
uwsgi_curse(i, SIGINT);
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGINT);
}
}
uwsgi_destroy_processes();
}
@@ -1268,6 +1299,11 @@ void gracefully_kill_them_all(int signum) {
uwsgi_curse(i, SIGHUP);
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGHUP);
}
}
uwsgi_destroy_processes();
}
@@ -1309,6 +1345,12 @@ void grace_them_all(int signum) {
uwsgi_curse(i, SIGHUP);
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGHUP);
}
}
}
void uwsgi_nuclear_blast() {
@@ -1355,6 +1397,11 @@ void reap_them_all(int signum) {
if (uwsgi.workers[i].pid > 0)
uwsgi_curse(i, SIGTERM);
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGTERM);
}
}
}
void harakiri() {
@@ -1501,8 +1548,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()");
}
}
}
@@ -1551,25 +1600,40 @@ 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);
}
}
}
}
}
}
void signal_pidfile(int sig, char *filename) {
int signal_pidfile(int sig, char *filename) {
int ret = 0;
size_t size = 0;
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
if (size > 0) {
if (kill((pid_t) atoi(buffer), sig)) {
uwsgi_error("kill()");
uwsgi_error("signal_pidfile()/kill()");
ret = -1;
}
}
else {
uwsgi_log("error: invalid pidfile\n");
ret = -1;
}
free(buffer);
return ret;
}
/*static*/ void uwsgi_command_signal(char *opt) {
@@ -1916,6 +1980,17 @@ int main(int argc, char *argv[], char *envp[]) {
return uwsgi_run();
}
static char *uwsgi_at_file_read(char *filename) {
size_t size = 0;
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
if (size > 1) {
if (buffer[size-2] == '\n' || buffer[size-2] == '\r') {
buffer[size-2] = 0;
}
}
return buffer;
}
void uwsgi_setup(int argc, char *argv[], char *envp[]) {
#ifdef UWSGI_AS_SHARED_LIBRARY
#ifdef __APPLE__
@@ -2113,7 +2188,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv);
// third pass: FILEs
uwsgi_apply_config_pass('@', uwsgi_simple_file_read);
uwsgi_apply_config_pass('@', uwsgi_at_file_read);
// last pass: REFERENCEs
uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
@@ -2187,7 +2262,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)
if (uwsgi.log_master)
uwsgi_setup_log_master();
// setup offload engines
@@ -2474,6 +2549,7 @@ int uwsgi_start(void *v_argv) {
}
if (uwsgi.chdir) {
uwsgi_log("chdir() to %s\n", uwsgi.chdir);
if (chdir(uwsgi.chdir)) {
uwsgi_error("chdir()");
exit(1);
@@ -2772,6 +2848,7 @@ int uwsgi_start(void *v_argv) {
!uwsgi.command_mode &&
!uwsgi.daemons_cnt &&
!uwsgi.crons &&
!uwsgi.spoolers &&
!uwsgi.emperor_proxy
#ifdef __linux__
&& !uwsgi.setns_socket
@@ -2930,7 +3007,7 @@ unsafe:
}
// initialize locks and socket as soon as possible, as the master could enqueue tasks
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
if (uwsgi.spoolers != NULL) {
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
@@ -3068,15 +3145,13 @@ next:
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
goto next2;
uspool->pid = spooler_start(uspool);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
goto next2;
uspool->pid = spooler_start(uspool);
next2:
uspool = uspool->next;
}
uspool = uspool->next;
}
if (!uwsgi.master_process) {
@@ -3223,6 +3298,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;
@@ -3299,6 +3376,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);
@@ -3372,7 +3450,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);
}
}
@@ -3653,6 +3734,13 @@ void uwsgi_init_all_apps() {
if (uwsgi.need_app) {
if (!uwsgi.lazy)
uwsgi_log("*** no app loaded. GAME OVER ***\n");
if (uwsgi.lazy_apps) {
if (uwsgi.master_process) {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("kill()");
}
}
}
exit(UWSGI_FAILED_APP_CODE);
}
else {
@@ -3733,7 +3821,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)
@@ -3762,7 +3851,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)
@@ -3809,7 +3899,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) {
@@ -3827,7 +3918,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) {
@@ -4128,15 +4220,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;
}
@@ -4183,8 +4273,7 @@ void uwsgi_opt_pidfile_signal(char *opt, char *pidfile, void *sig) {
long *signum_fake_ptr = (long *) sig;
int signum = (long) signum_fake_ptr;
signal_pidfile(signum, pidfile);
exit(0);
exit(signal_pidfile(signum, pidfile));
}
void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
+10 -7
View File
@@ -1,4 +1,4 @@
#include "uwsgi.h"
#include <uwsgi.h>
/*
@@ -10,6 +10,8 @@
extern struct uwsgi_server uwsgi;
#define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr
static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf;
if (!ub) {
@@ -61,7 +63,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
// pong not received ?
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance);
return -1;
}
return 0;
@@ -189,7 +191,7 @@ static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb)
}
goto wait;
}
uwsgi_error("uwsgi_websockets_recv_pkt()");
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
return -1;
}
@@ -201,7 +203,7 @@ wait:
if (rlen <= 0) return -1;
}
if (ret < 0) {
uwsgi_error("uwsgi_websockets_recv_pkt()");
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
return -1;
}
// send unsolicited pong
@@ -254,11 +256,11 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
}
else {
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
return NULL;
}
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
return NULL;
}
wsgi_req->websocket_phase = 2;
@@ -271,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;
@@ -312,7 +315,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
break;
// oops
default:
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
return NULL;
}
}
+41 -24
View File
@@ -82,12 +82,14 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
wsgi_req->status = uwsgi_str3_num(status);
#ifdef UWSGI_ROUTING
// apply error routes
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
if (wsgi_req->is_error_routing == 0) {
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_error_routing = 0;
}
wsgi_req->is_error_routing = 0;
#endif
if (status_len <= 4) {
char *new_sc = NULL;
@@ -122,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)) {
@@ -186,12 +197,14 @@ static int uwsgi_response_write_headers_do0(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_ROUTING
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
if (wsgi_req->is_response_routing == 0) {
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
#endif
struct uwsgi_string_list *ah = uwsgi.additional_headers;
@@ -352,12 +365,14 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
// special case here, we could need to set transformations before
if (!wsgi_req->headers_sent) {
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
if (wsgi_req->is_response_routing == 0) {
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
}
#endif
@@ -435,12 +450,14 @@ int uwsgi_response_writev_body_do(struct wsgi_request *wsgi_req, struct iovec *i
// special case here, we could need to set transformations before
if (!wsgi_req->headers_sent) {
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
if (wsgi_req->is_response_routing == 0) {
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
}
#endif
+3 -4
View File
@@ -271,12 +271,11 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
}
static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_airbrake_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config));
uacc->arg = uai->arg;
ut->data = uacc;
struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_airbrake_loop, uacc);
if (!ut) return;
uai->data_ptr = ut;
}
static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
+145 -81
View File
@@ -3,9 +3,18 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_alarm_curl {
CURL *curl;
struct uwsgi_thread *ut;
int pos;
int blen;
char *body;
int hlen;
char hdr[];
};
struct uwsgi_alarm_curl_config {
int first;
char *arg;
char *url;
char *subject;
char *to;
};
@@ -17,7 +26,7 @@ struct uwsgi_alarm_curl_opt {
};
#ifdef CURLOPT_MAIL_RCPT
#ifdef CURLPROTO_SMTP
static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
uacc->to = arg;
struct curl_slist *list = NULL;
@@ -29,6 +38,7 @@ static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct
p = strtok_r(NULL, ",", &ctx);
}
curl_easy_setopt(curl, option, list);
free(items);
}
#endif
@@ -44,16 +54,33 @@ static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *ar
uacc->subject = arg;
}
static struct uwsgi_alarm_curl_opt uaco[] = {
{"url", CURLOPT_URL, NULL},
#ifdef CURLOPT_MAIL_RCPT
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to },
static void uwsgi_alarm_curl_url(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc)
{
#ifndef CURLPROTO_SMTP
if (!uwsgi_strnicmp(arg, 4, "smtp", 4)) {
uwsgi_error("Please update libcurl to use SMTP protocol.\n");
exit(1);
}
#endif
#ifdef CURLOPT_MAIL_FROM
uacc->url = arg;
curl_easy_setopt(curl, option, arg);
}
static void uwsgi_alarm_curl_ssl_insecure(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
static struct uwsgi_alarm_curl_opt uaco[] = {
{"url", CURLOPT_URL, uwsgi_alarm_curl_url},
#ifdef CURLPROTO_SMTP
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to},
{"mail_from", CURLOPT_MAIL_FROM, NULL},
#endif
{"subject", 0, uwsgi_alarm_curl_set_subject},
{"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl},
{"ssl_insecure", 0, uwsgi_alarm_curl_ssl_insecure},
{"auth_user", CURLOPT_USERNAME, NULL},
{"auth_pass", CURLOPT_PASSWORD, NULL},
{"method", CURLOPT_CUSTOMREQUEST, NULL},
@@ -65,14 +92,10 @@ static struct uwsgi_alarm_curl_opt uaco[] = {
static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_curl_config *uacc) {
struct uwsgi_alarm_curl_opt *o = uaco;
char *equal = strchr(opt,'=');
if (!equal) {
if (!uacc->first) {
curl_easy_setopt(curl, CURLOPT_URL, opt);
uacc->first = 1;
}
if (!equal && !uacc->url) {
uwsgi_alarm_curl_url(curl, CURLOPT_URL, opt, uacc);
return;
}
uacc->first = 1;
*equal = 0;
while(o->name) {
if (!strcmp(o->name, opt)) {
@@ -82,91 +105,137 @@ static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_cu
else {
curl_easy_setopt(curl, o->option, equal+1);
}
goto end;
break;
}
o++;
}
end:
*equal = '=';
}
static size_t uwsgi_alarm_curl_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
struct uwsgi_alarm_curl *uac = userp;
size_t full_size = size * nmemb;
size_t remains = ut->len - ut->pos;
struct uwsgi_alarm_curl_config *uacc = ut->data;
int remains = full_size;
if (remains == 0) return 0;
if (ut->custom0 == 0) {
size_t newline = 0;
size_t required = 1;
char *addr = ptr;
if (uacc->to) required += 4 + strlen(uacc->to) + 1;
if (uacc->subject) required += 9 + strlen(uacc->subject) + 1;
if (required > full_size) goto skip;
if (uacc->to) {
memcpy(addr, "To: ", 4); addr+=4;
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
*addr ++= '\n';
newline = 1;
if (uac->pos < uac->hlen) {
if (remains > uac->hlen - uac->pos) {
memcpy(ptr, uac->hdr + uac->pos, uac->hlen - uac->pos);
ptr += uac->hlen - uac->pos;
remains -= uac->hlen - uac->pos;
uac->pos = uac->hlen;
} else {
memcpy(ptr, uac->hdr + uac->pos, remains);
uac->pos += remains;
return full_size;
}
if (uacc->subject) {
memcpy(addr, "Subject: ", 9); addr+=9;
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
*addr ++= '\n';
newline = 1;
}
skip:
if (newline > 0) {
*addr = '\n';
}
ut->custom0 = 1;
return required;
}
if (full_size < remains) {
remains = full_size;
if (remains > uac->blen + uac->hlen - uac->pos) {
memcpy(ptr, uac->body + uac->pos - uac->hlen, uac->blen + uac->hlen - uac->pos);
remains -= uac->blen + uac->hlen - uac->pos;
uac->pos = uac->blen + uac->hlen;
return full_size - remains;
}
memcpy(ptr, ut->buf + ut->pos, remains);
ut->pos += remains;
return remains;
memcpy(ptr, uac->body + uac->pos - uac->hlen, remains);
uac->pos += remains;
return full_size;
}
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
int interesting_fd;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
static struct uwsgi_alarm_curl *uwsgi_alarm_curl_alloc(struct uwsgi_alarm_curl_config *uacc)
{
char *addr;
struct uwsgi_alarm_curl *uac;
size_t required = 0;
if (uacc->to) required += 4 + strlen(uacc->to) + 2;
if (uacc->subject) required += 9 + strlen(uacc->subject) + 2;
if (required)
required += 2; /* newline between MIME header and body */
uac = uwsgi_malloc(sizeof(*uac) + required);
uac->hlen = required;
addr = uac->hdr;
if (uacc->to) {
memcpy(addr, "To: ", 4); addr += 4;
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
*addr++ = '\r';
*addr++ = '\n';
}
if (uacc->subject) {
memcpy(addr, "Subject: ", 9); addr += 9;
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
*addr++ = '\r';
*addr++ = '\n';
}
if (required) {
*addr++ = '\r';
*addr = '\n';
}
return uac;
}
static struct uwsgi_alarm_curl *uwsgi_alarm_curl_init_curl(struct uwsgi_alarm_instance *uai) {
CURL *curl = curl_easy_init();
// ARGH !!!
if (!curl) return;
if (!curl) {
uwsgi_error("Failed to initialize libcurl.\n");
exit(1);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.socket_timeout);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_alarm_curl_read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
struct uwsgi_alarm_curl_config *uacc = (struct uwsgi_alarm_curl_config *) ut->data;
char *opts = uwsgi_str(uacc->arg);
struct uwsgi_alarm_curl_config uacc;
memset(&uacc, 0, sizeof(uacc));
char *opts = uwsgi_str(uai->arg);
// fill curl options
char *ctx = NULL;
char *p = strtok_r(opts, ";", &ctx);
while(p) {
uwsgi_alarm_curl_setopt(curl, uwsgi_str(p), uacc);
uwsgi_alarm_curl_setopt(curl, p, &uacc);
p = strtok_r(NULL, ";", &ctx);
}
if (!uacc.url) {
uwsgi_error("An URL is required to trigger curl-based alarm.\n");
exit(1);
}
struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_alloc(&uacc);
curl_easy_setopt(curl, CURLOPT_READDATA, uac);
free(opts);
uac->curl = curl;
uai->data_ptr = uac;
return uac;
}
static void uwsgi_alarm_curl_call_curl(struct uwsgi_alarm_curl *uac, char *msg, int len)
{
uac->pos = 0;
uac->body = msg;
uac->blen = len;
curl_easy_setopt(uac->curl, CURLOPT_INFILESIZE, uac->hlen + uac->blen);
CURLcode res = curl_easy_perform(uac->curl);
if (res != CURLE_OK)
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
int interesting_fd;
struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_init_curl(ut->data);
uac->ut = ut;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret < 0) return;
@@ -174,31 +243,26 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
ut->pos = 0;
ut->len = (size_t) rlen;
ut->custom0 = 0;
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
uwsgi_alarm_curl_call_curl(uac, ut->buf, rlen);
}
}
static void uwsgi_alarm_curl_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_curl_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_alarm_curl_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_alarm_curl_config));
uacc->arg = uai->arg;
ut->data = uacc;
if (uwsgi.alarm_cheap)
uwsgi_alarm_curl_init_curl(uai);
else
uwsgi_thread_new_with_data(uwsgi_alarm_curl_loop, uai);
}
// pipe the message into the thread;
static void uwsgi_alarm_curl_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
ut->rlen = write(ut->pipe[0], msg, len);
struct uwsgi_alarm_curl *uac = uai->data_ptr;
if (uwsgi.alarm_cheap)
uwsgi_alarm_curl_call_curl(uac, msg, len);
else {
struct uwsgi_thread *ut = uac->ut;
ut->rlen = write(ut->pipe[0], msg, len);
}
}
static void uwsgi_alarm_curl_load(void) {
+1 -2
View File
@@ -4,10 +4,9 @@ void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *);
static void uwsgi_alarm_xmpp_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_xmpp_loop);
struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_alarm_xmpp_loop, uai->arg);
if (!ut) return;
uai->data_ptr = ut;
ut->data = uai->arg;
}
// pipe the message into the thread;
+387
View File
@@ -0,0 +1,387 @@
#include "../python/uwsgi_python.h"
/*
python >= 3.4 asyncio (PEP 3156) loop engine
EXPERIMENTAL !!!
Author: Roberto De Ioris
*/
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
static struct uwsgi_asyncio {
PyObject *mod;
PyObject *loop;
PyObject *request;
PyObject *hook_fd;
PyObject *hook_timeout;
PyObject *hook_fix;
} uasyncio;
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
static void uwsgi_opt_setup_asyncio(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.socket_timeout < 30) {
uwsgi.socket_timeout = 30;
}
// set loop engine
uwsgi.loop = "asyncio";
}
static struct uwsgi_option asyncio_options[] = {
{"asyncio", required_argument, 0, "a shortcut enabling asyncio loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_asyncio, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
static void gil_asyncio_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
static void gil_asyncio_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static int uwsgi_asyncio_wait_read_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
goto error;
}
// back to loop
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
// back from loop
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static int uwsgi_asyncio_wait_write_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (PyObject_CallMethod(uasyncio.loop, "add_writer", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
goto error;
}
// back to loop
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
// back from loop
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
int timed_out = 0;
if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) {
uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n");
exit(1);
}
struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req = wsgi_req;
PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout;
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
// avoid mess when closing the request
wsgi_req->async_timeout = NULL;
if (timed_out > 0) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
goto end;
}
int status = wsgi_req->socket->proto(wsgi_req);
if (status > 0) {
ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
goto end;
}
// trick for reference counting
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
goto again;
}
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) {
PyErr_Print();
goto end;
}
if (status == 0) {
// we call this two time... overengineering :(
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi.schedule_to_req();
goto again;
}
end:
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi_close_request(uwsgi.wsgi_req);
free_req_queue;
again:
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) {
long uwsgi_sock_ptr = 0;
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_accept", &uwsgi_sock_ptr)) {
return NULL;
}
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
if (wsgi_req == NULL) {
uwsgi_async_queue_is_full(uwsgi_now());
goto end;
}
uwsgi.wsgi_req = wsgi_req;
struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) uwsgi_sock_ptr;
// fill wsgi_request structure
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock );
// mark core as used
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
// in case of errors (or thundering herd, just reset it)
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
free_req_queue;
goto end;
}
wsgi_req->start_of_request = uwsgi_micros();
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
// add callback for protocol
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", wsgi_req->fd, uasyncio.request, (long) wsgi_req) == NULL) {
free_req_queue;
PyErr_Print();
}
// add timeout
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, (long)wsgi_req, 1);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
free_req_queue;
}
else {
// trick for reference counting
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
}
end:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_fd(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_hook_fd", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_timeout(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req->async_timed_out = 1;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_fix(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef uwsgi_asyncio_accept_def[] = { {"uwsgi_asyncio_accept", py_uwsgi_asyncio_accept, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_request_def[] = { {"uwsgi_asyncio_request", py_uwsgi_asyncio_request, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_fd_def[] = { {"uwsgi_asyncio_hook_fd", py_uwsgi_asyncio_hook_fd, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_timeout_def[] = { {"uwsgi_asyncio_hook_timeout", py_uwsgi_asyncio_hook_timeout, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_fix_def[] = { {"uwsgi_asyncio_hook_fix", py_uwsgi_asyncio_hook_fix, METH_VARARGS, ""} };
static void uwsgi_asyncio_schedule_fix(struct wsgi_request *wsgi_req) {
PyObject *cb = PyObject_CallMethod(uasyncio.loop, "call_soon", "Ol", uasyncio.hook_fix, (long) wsgi_req);
if (!cb) goto error;
Py_DECREF(cb);
return;
error:
PyErr_Print();
}
static void asyncio_loop() {
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
if (uwsgi.socket_timeout < 30) {
uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
if (!uwsgi.async_waiting_fd_table)
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_proto_fd_table)
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
// get the GIL
UWSGI_GET_GIL
up.gil_get = gil_asyncio_get;
up.gil_release = gil_asyncio_release;
uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook;
uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook;
if (uwsgi.async < 2) {
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
exit(1);
}
if (!uwsgi.schedule_to_main) {
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);
if (!uasyncio.loop) uwsgi_pyexit;
// main greenlet waiting for connection (one greenlet per-socket)
PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL);
Py_INCREF(asyncio_accept);
uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL);
if (!uasyncio.request) uwsgi_pyexit;
uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL);
if (!uasyncio.hook_fd) uwsgi_pyexit;
uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL);
if (!uasyncio.hook_timeout) uwsgi_pyexit;
uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL);
if (!uasyncio.hook_fix) uwsgi_pyexit;
Py_INCREF(uasyncio.request);
Py_INCREF(uasyncio.hook_fd);
Py_INCREF(uasyncio.hook_timeout);
Py_INCREF(uasyncio.hook_fix);
// call add_handler on each socket
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
uwsgi_pyexit;
}
uwsgi_sock = uwsgi_sock->next;
}
if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) {
uwsgi_pyexit;
}
// never here ?
}
static void asyncio_init() {
uwsgi_register_loop( (char *) "asyncio", asyncio_loop);
}
struct uwsgi_plugin asyncio_plugin = {
.name = "asyncio",
.options = asyncio_options,
.on_load = asyncio_init,
};
+8
View File
@@ -0,0 +1,8 @@
from distutils import sysconfig
NAME='asyncio'
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
LDFLAGS = []
LIBS = []
GCC_LIST = ['asyncio']
+10 -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;
@@ -380,6 +383,11 @@ metrics_loop:
uwsgi_rlock(uwsgi.metrics_lock);
wok = carbon_write(fd, "%s%s.%s.%.*s %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, um->name_len, um->name, (unsigned long long) *um->value, (unsigned long long) now);
uwsgi_rwunlock(uwsgi.metrics_lock);
if (um->reset_after_push){
uwsgi_wlock(uwsgi.metrics_lock);
*um->value = um->initial_value;
uwsgi_rwunlock(uwsgi.metrics_lock);
}
if (!wok) goto clear;
um = um->next;
}
+214 -169
View File
@@ -2,6 +2,8 @@
extern struct uwsgi_server uwsgi;
#define kill_on_error if (!uc.do_not_kill_on_error) { if (kill(cgi_pid, SIGKILL)) uwsgi_error("kill()");}
struct uwsgi_cgi {
struct uwsgi_dyn_dict *mountpoint;
struct uwsgi_dyn_dict *helpers;
@@ -16,6 +18,8 @@ struct uwsgi_cgi {
int has_mountpoints;
struct uwsgi_dyn_dict *default_cgi;
int path_info;
int do_not_kill_on_error;
int async_max_attempts;
} uc ;
static void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
@@ -62,6 +66,9 @@ struct uwsgi_option uwsgi_cgi_options[] = {
{"cgi-path-info", no_argument, 0, "disable PATH_INFO management in cgi scripts", uwsgi_opt_true, &uc.path_info, 0},
{"cgi-do-not-kill-on-error", no_argument, 0, "do not send SIGKILL to cgi script on errors", uwsgi_opt_true, &uc.do_not_kill_on_error, 0},
{"cgi-async-max-attempts", no_argument, 0, "max waitpid() attempts in cgi async mode (default 10)", uwsgi_opt_set_int, &uc.async_max_attempts, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -179,118 +186,154 @@ static char *uwsgi_cgi_get_helper(char *filename) {
}
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t i;
/*
start reading each line until Status or Location are found
-1 error
0 not found
1 found
*/
static int uwsgi_cgi_check_status(struct wsgi_request *wsgi_req, char *buf, size_t len) {
char *key = buf, *value = NULL;
size_t header_size = 0;
int status_sent = 0;
size_t i;
// Search for Status/Location headers
for(i=0;i<len;i++) {
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
// Default status
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
// Default status
#ifdef UWSGI_DEBUG
uwsgi_log("setting default Status header\n");
#endif
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
break;
return 1;
}
// invalid header
else if (value == NULL) {
return -1;
}
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
if ((buf[i-1]) == '\r') {
header_size--;
}
// invalid header
else if (value == NULL) return -1;
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
// remove \r
if ((buf[i-1]) == '\r') {
header_size--;
}
}
// enough space for Status ?
if (header_size >= 11) {
// "Status: NNN"
if (!strncasecmp("Status: ", key, 8)) {
#ifdef UWSGI_DEBUG
uwsgi_log("found Status header: %.*s\n", header_size, key);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
return 1;
}
// Location: X
if (!strncasecmp("Location: ", key, 10)) {
#ifdef UWSGI_DEBUG
uwsgi_log("found Location header: %.*s\n", header_size, key);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
return 1;
}
}
if (header_size >= 11) {
// "Status: NNN"
if (!strncasecmp("Status: ", key, 8)) {
#ifdef UWSGI_DEBUG
uwsgi_log("found Status header: %.*s\n", header_size, key);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
break;
}
// Location: X
if (!strncasecmp("Location: ", key, 10)) {
#ifdef UWSGI_DEBUG
uwsgi_log("found Location header: %.*s\n", header_size, key);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
break;
}
}
key = NULL;
value = NULL;
key = NULL;
value = NULL;
}
else if (buf[i] == ':') {
else if (buf[i] == ':') {
value = buf+i;
}
else if (buf[i] != '\r') {
if (key == NULL) {
key = buf + i;
}
}
}
else if (buf[i] != '\r') {
if (key == NULL) key = buf + i;
}
}
key = buf;
value = NULL;
// no Status/Location found
return 0;
for(i=0;i<len;i++) {
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
i++;
goto send_body;
}
// invalid header
else if (value == NULL) {
return -1;
}
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
if ((buf[i-1]) == '\r') {
header_size--;
}
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) {
size_t i;
size_t header_size = 0;
int status_sent = 0;
size_t remains = blen;
char *ptr = buf;
size_t len = 0;
while(remains > 0) {
ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout);
if (rlen < 0) {
if (!errno) return 1;
return -1;
}
// timed out
if (rlen == 0) return -1;
remains -= rlen;
len += rlen;
ptr += rlen;
// Search for Status/Location headers
if (!status_sent) {
status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len);
if (status_sent < 0) return -1;
// need more data ?
if (status_sent == 0) continue;
}
// send headers
char *key = buf;
char *value = NULL;
for(i=0;i<len;i++) {
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
i++;
goto send_body;
}
// invalid header
else if (value == NULL) {
return -1;
}
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
if ((buf[i-1]) == '\r') {
header_size--;
}
}
}
#ifdef UWSGI_DEBUG
uwsgi_log("found CGI header: %.*s\n", header_size, key);
uwsgi_log("found CGI header: %.*s\n", header_size, key);
#endif
// Ignore "Status: NNN" header
if (status_sent == 0 && header_size >= 11) {
if (!strncasecmp("Status: ", key, 8)) {
status_sent = 1;
key = NULL;
value = NULL;
continue;
// Ignore "Status: NNN" header
if (header_size >= 11) {
if (!strncasecmp("Status: ", key, 8)) {
key = NULL;
value = NULL;
continue;
}
}
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
key = NULL;
value = NULL;
}
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
key = NULL;
value = NULL;
}
else if (buf[i] == ':') {
value = buf+i;
}
else if (buf[i] != '\r') {
if (key == NULL) {
key = buf + i;
else if (buf[i] == ':') {
value = buf+i;
}
else if (buf[i] != '\r') {
if (key == NULL) {
key = buf + i;
}
}
}
}
@@ -592,7 +635,6 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
int post_pipe[2];
int nargs = 0;
int waitpid_status;
ssize_t len;
int i;
char **argv;
@@ -630,126 +672,96 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
close(cgi_pipe[1]);
close(post_pipe[0]);
uwsgi_socket_nb(cgi_pipe[0]);
uwsgi_socket_nb(post_pipe[1]);
// ok start sending post data...
size_t remains = wsgi_req->post_cl;
while(remains > 0) {
ssize_t rlen = 0;
char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
if (!buf) {
close(post_pipe[1]);
goto clear2;
}
if (buf == uwsgi.empty) break;
// write data to the node
if (uwsgi_write_true_nb(post_pipe[1], buf, rlen, uc.timeout)) {
close(post_pipe[1]);
goto clear2;
}
remains -= rlen;
}
close(post_pipe[1]);
// wait for data
char *headers_buf = uwsgi_malloc(uc.buffer_size);
char *ptr = headers_buf;
remains = uc.buffer_size;
int completed = 0;
while(remains > 0) {
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
if (ret > 0) {
len = read(cgi_pipe[0], ptr, remains);
if (len > 0) {
ptr+=len;
remains -= len;
}
else if (len == 0) {
completed = 1;
break;
}
else {
uwsgi_error("read()");
goto clear;
}
continue;
}
else if (ret == 0) {
uwsgi_log("CGI timeout !!!\n");
goto clear;
}
break;
}
char *buf = uwsgi_malloc(uc.buffer_size);
if (uwsgi_cgi_parse(wsgi_req, headers_buf, uc.buffer_size-remains)) {
uwsgi_log("invalid CGI output !!!\n");
int completed = uwsgi_cgi_parse(wsgi_req, cgi_pipe[0], buf, uc.buffer_size);
if (completed < 0) {
uwsgi_log("invalid CGI response !!!\n");
kill_on_error
goto clear;
}
while (!completed) {
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
if (ret > 0) {
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
if (len > 0) {
uwsgi_response_write_body_do(wsgi_req, headers_buf, len);
}
// end of output
else if (len == 0) {
break;
}
else {
uwsgi_error("read()");
ssize_t rlen = uwsgi_read_true_nb(cgi_pipe[0], buf, uc.buffer_size, uc.timeout);
if (rlen > 0) {
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
kill_on_error
goto clear;
}
continue;
}
else if (ret == 0) {
uwsgi_log("CGI timeout !!!\n");
goto clear;
}
break;
else if (rlen == 0) {
uwsgi_log("CGI timeout !!!\n");
kill_on_error
goto clear;
}
else {
if (errno) {
uwsgi_req_error("error reading CGI response\n");
kill_on_error
}
goto clear;
}
}
clear:
free(headers_buf);
free(buf);
clear2:
close(cgi_pipe[0]);
close(post_pipe[1]);
// now wait for process exit/death
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
// in async mode we need a trick...
if (uwsgi.async > 1) {
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
if (diedpid < 0) {
uwsgi_error("waitpid()");
}
else if (diedpid == 0) {
// pass the pid of the cgi to async_plagued (the after request hook will clear the process)
wsgi_req->async_plagued = (int) cgi_pid;
}
}
else {
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
return UWSGI_OK;
}
// close all the fd except wsgi_req->poll.fd and 2;
for(i=0;i< (int)uwsgi.max_fd;i++) {
if (post_pipe[0] == i) {
continue;
}
if (wsgi_req->post_file) {
if (fileno(wsgi_req->post_file) == i) {
continue;
}
}
if (i != wsgi_req->fd && i != 2 && i != cgi_pipe[1]) {
close(i);
}
}
// now map wsgi_req->poll.fd (or async_post) to 0 & cgi_pipe[1] to 1
if (post_pipe[0] != 0) {
dup2(post_pipe[0], 0);
close(post_pipe[0]);
}
#ifdef UWSGI_DEBUG
uwsgi_log("mapping cgi_pipe %d to 1\n", cgi_pipe[1]);
#endif
dup2(post_pipe[0], 0);
close(post_pipe[0]);
dup2(cgi_pipe[1],1);
close(cgi_pipe[1]);
// close all the fd > 2
for(i=3;i<(int)uwsgi.max_fd;i++) {
close(i);
}
// fill cgi env
for(i=0;i<wsgi_req->var_cnt;i++) {
// no need to free the putenv() memory
@@ -913,6 +925,39 @@ clear2:
static void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
if (wsgi_req->async_plagued > 0) {
int waitpid_status;
pid_t cgi_pid = (pid_t) wsgi_req->async_plagued;
int max_attempts = uc.async_max_attempts;
if (!max_attempts) max_attempts = 10;
while(max_attempts) {
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
if (diedpid < 0) {
uwsgi_error("waitpid()");
break;
}
else if (diedpid == 0) {
int ret = uwsgi.wait_milliseconds_hook(1000);
if (ret < 0) {
kill_on_error
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
}
else {
break;
}
max_attempts--;
}
if (max_attempts == 0) {
kill_on_error
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
}
log_request(wsgi_req);
}
+24 -7
View File
@@ -45,6 +45,7 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
if (!bufsize) bufsize = uwsgi.page_size;
peers->in = uwsgi_buffer_new(bufsize);
// add timeout
peers->current_timeout = cs->corerouter->socket_timeout;
peers->timeout = cr_add_timeout(cs->corerouter, peers);
peers->prev = old_peers;
@@ -74,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;
@@ -83,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;
@@ -110,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) {
@@ -309,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));
@@ -383,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;
@@ -401,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
@@ -413,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
@@ -582,8 +595,8 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
cs->corerouter = ucr;
cs->ugs = ugs;
// set initial timeout
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
// set initial timeout (could be overridden)
peer->current_timeout = ucr->socket_timeout;
ucr->active_sessions++;
@@ -622,6 +635,10 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
corerouter_close_session(ucr, cs);
cs = NULL;
}
else {
// truly set the timeout
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
}
return cs;
}
+15 -7
View File
@@ -3,12 +3,12 @@
#define COREROUTER_STATUS_RECV_HDR 2
#define COREROUTER_STATUS_RESPONSE 3
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+u->socket_timeout, x)
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+u->socket_timeout, x)
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+x->current_timeout, x)
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+x->current_timeout, x)
#define cr_del_timeout(u, x) uwsgi_del_rb_timer(u->timeouts, x->timeout); free(x->timeout);
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, x->session->client_address, x->session->client_port, __VA_ARGS__)
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, __VA_ARGS__)
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
errno = EINPROGRESS;\
@@ -180,14 +180,22 @@ 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;
struct corerouter_peer *prev;
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 {
@@ -269,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);
+6 -24
View File
@@ -66,32 +66,14 @@ SV * coroae_coro_new(CV *block) {
}
static int coroae_wait_milliseconds(int timeout) {
int ret = -1;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(newSVnv(((double)timeout)/1000.0));
PUTBACK;
call_pv("Coro::AnyEvent::sleep", G_SCALAR|G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV));
}
else {
SV *p_ret = POPs;
if (SvTRUE(p_ret)) {
ret = 0;
}
}
PUTBACK;
FREETMPS;
LEAVE;
return ret;
char buf[256];
double d = ((double)timeout)/1000.0;
int ret = snprintf(buf, 256, "Coro::AnyEvent::sleep %f", d);
if (ret <= 0 || ret > 256) return -1;
perl_eval_pv(buf, 0);
return 0;
}
static int coroae_wait_fd_read(int fd, int timeout) {
int ret = 0;
dSP;
+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) {
+54 -2
View File
@@ -10,6 +10,10 @@ struct uwsgi_emperor_mongodb_state {
char *address;
char *collection;
char *json;
char *database;
char *username;
char *password;
char *predigest;
};
@@ -20,7 +24,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
try {
// requested fields
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 );
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 );
mongo::BSONObj q = mongo::fromjson(uems->json);
// the connection object (will be automatically destroyed at each cycle)
mongo::DBClientConnection c;
@@ -29,9 +33,17 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
// connect
c.connect(uems->address);
if (uems->database && uems->username && uems->password) {
std::string err;
if (c.auth(uems->database, uems->username, uems->password, err, uems->predigest ? false : true) == false) {
uwsgi_log_verbose("[emperor-mongodb] unable to authenticate to db %s: %s\n", uems->database, err.c_str());
return;
}
}
// run the query
std::auto_ptr<mongo::DBClientCursor> cursor = c.query(uems->collection, q, 0, 0, &p);
while( cursor->more() ) {
while(cursor.get() && cursor->more() ) {
mongo::BSONObj p = cursor->next();
// checking for an empty string is not required, but we reduce the load
@@ -40,6 +52,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
if (strlen(name) == 0) continue;
const char *config = p.getStringField("config");
if (strlen(config) == 0) config = NULL;
time_t vassal_ts = 0;
// ts must be a Date object !!!
@@ -61,6 +74,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
}
const char *socket_name = p.getStringField("socket");
if (strlen(socket_name) == 0) socket_name = NULL;
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
}
@@ -76,6 +90,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
b.append("name", c_ui->name);
mongo::BSONObj q2 = b.obj();
cursor = c.query(uems->collection, q2, 0, 0, &p);
if (!cursor.get()) return;
#ifdef UWSGI_DEBUG
uwsgi_log("JSON: %s\n", q2.toString().c_str());
#endif
@@ -121,3 +136,40 @@ done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
// setup a new mongodb imperial monitor (keyval based)
extern "C" void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *ues) {
// allocate a new state
ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state));
size_t arg_len = strlen(ues->arg);
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
// parse args/ set defaults
uems->address = (char *) "127.0.0.1:27017";
uems->collection = (char *) "uwsgi.emperor.vassals";
uems->json = (char *) "";
char *args = NULL;
if (arg_len <= 11) goto done;
args = ues->arg+11;
if (uwsgi_kvlist_parse(args, strlen(args), ',', '=',
"addr", &uems->address,
"address", &uems->address,
"server", &uems->address,
"collection", &uems->collection,
"coll", &uems->collection,
"json", &uems->json,
"database", &uems->database,
"db", &uems->database,
"username", &uems->username,
"password", &uems->password,
"predigest", &uems->predigest,
NULL)) {
uwsgi_log("[emperor-mongodb] invalid keyval syntax !\n");
exit(1);
}
done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
+2
View File
@@ -2,9 +2,11 @@
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *);
void emperor_mongodb_init(void) {
uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb);
uwsgi_register_imperial_monitor("mongodb2", uwsgi_imperial_monitor_mongodb_init2, uwsgi_imperial_monitor_mongodb);
}
struct uwsgi_plugin emperor_mongodb_plugin = {
+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->in->buf[0] = peer->modifier1;
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;
+5 -3
View File
@@ -8,18 +8,20 @@ struct uwsgi_geoip {
char *city_db;
GeoIP *country;
GeoIP *city;
int use_disk;
} ugeoip;
struct uwsgi_option uwsgi_geoip_options[] = {
{"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0},
{"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
{"geoip-use-disk", no_argument, 0, "do not cache geoip databases in memory", uwsgi_opt_true, &ugeoip.use_disk, 0},
UWSGI_END_OF_OPTIONS
};
static int uwsgi_geoip_init() {
if (ugeoip.country_db) {
ugeoip.country = GeoIP_open(ugeoip.country_db, GEOIP_MEMORY_CACHE);
ugeoip.country = GeoIP_open(ugeoip.country_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
if (!ugeoip.country) {
uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db);
exit(1);
@@ -27,7 +29,7 @@ static int uwsgi_geoip_init() {
}
if (ugeoip.city_db) {
ugeoip.city = GeoIP_open(ugeoip.city_db, GEOIP_MEMORY_CACHE);
ugeoip.city = GeoIP_open(ugeoip.city_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
if (!ugeoip.city) {
uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db);
exit(1);
+45
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() {
@@ -345,6 +371,9 @@ static void gil_gevent_release() {
static void gevent_loop() {
// ensure SIGPIPE is ignored
signal(SIGPIPE, SIG_IGN);
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
@@ -485,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) {
+6 -4
View File
@@ -4,6 +4,8 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
#define is_not_python(x) strcmp(uwsgi.p[x]->name, "python")
struct ugreenlet {
int enabled;
PyObject *callable;
@@ -69,7 +71,7 @@ static void greenlet_schedule_to_req() {
}
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
if (is_not_python(modifier1) && uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
@@ -81,7 +83,7 @@ static void greenlet_schedule_to_req() {
}
Py_DECREF(ret);
if (uwsgi.p[modifier1]->resume) {
if (is_not_python(modifier1) && uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
@@ -93,7 +95,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
// ensure gil
UWSGI_GET_GIL
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL);
@@ -103,7 +105,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
exit(1);
}
Py_DECREF(ret);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
+9 -1
View File
@@ -42,6 +42,12 @@ struct uwsgi_http {
int server_name_as_http_host;
int headers_timeout;
int connect_timeout;
int manage_source;
int enable_proxy_protocol;
int chunked_input;
int manage_rtsp;
};
struct http_session {
@@ -130,6 +136,8 @@ struct http_session {
ssize_t (*func_write)(struct corerouter_peer *);
int is_rtsp;
};
@@ -154,7 +162,7 @@ void hr_session_ssl_close(struct corerouter_session *);
ssize_t hr_ssl_read(struct corerouter_peer *);
ssize_t hr_ssl_write(struct corerouter_peer *);
int hr_https_add_vars(struct http_session *, struct uwsgi_buffer *);
int hr_https_add_vars(struct http_session *, struct corerouter_peer *, struct uwsgi_buffer *);
void hr_setup_ssl(struct http_session *, struct uwsgi_gateway_socket *);
#endif
+215 -58
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},
@@ -60,43 +62,60 @@ struct uwsgi_option http_options[] = {
{"http-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &uhttp.cr.buffer_size, 0},
{"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0},
{"http-headers-timeout", required_argument, 0, "set internal http socket timeout for headers", uwsgi_opt_set_int, &uhttp.headers_timeout, 0},
{"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},
};
int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen) {
static void http_set_timeout(struct corerouter_peer *peer, int timeout) {
if (peer->current_timeout == timeout) return;
peer->current_timeout = timeout;
peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer);
}
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
size_t i;
char *val = hh;
int status = 0;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
*keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
*vallen+=1;
}
else if (status == 2) {
*vallen+=1;
}
}
if (!(*keylen))
return NULL;
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
*has_prefix = 0x02;
}
return val;
}
static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t keylen, char *val, size_t vallen, int prefix) {
struct uwsgi_buffer *out = peer->out;
struct http_session *hr = (struct http_session *) peer->session;
int i;
int status = 0;
char *val = hh;
uint16_t keylen = 0, vallen = 0;
int prefix = 0;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
vallen++;
}
else if (status == 2) {
vallen++;
}
}
if (!keylen)
return -1;
if (hr->websockets) {
if (!uwsgi_strncmp("UPGRADE", 7, hh, keylen)) {
if (!uwsgi_strnicmp(val, vallen, "websocket", 9)) {
@@ -122,9 +141,14 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
}
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)) {
@@ -134,13 +158,24 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
// 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)) {
if (!uwsgi_strnicmp(val, vallen, "close", 5)) {
if (!uwsgi_strnicmp(val, vallen, "close", 5) || !uwsgi_strnicmp(val, vallen, "upgrade", 7)) {
hr->session.can_keepalive = 0;
}
}
else if (peer->key == uwsgi.hostname && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) {
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
}
#ifdef UWSGI_ZLIB
else if (uhttp.auto_gzip && !uwsgi_strncmp("ACCEPT_ENCODING", 15, hh, keylen)) {
@@ -151,11 +186,7 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
#endif
done:
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
keylen += 5;
prefix = 1;
}
if (prefix) keylen += 5;
if (uwsgi_buffer_u16le(out, keylen)) return -1;
@@ -163,7 +194,7 @@ done:
if (uwsgi_buffer_append(out, "HTTP_", 5)) return -1;
}
if (uwsgi_buffer_append(out, hh, keylen - (prefix * 5))) return -1;
if (uwsgi_buffer_append(out, hh, keylen - (prefix ? 5 : 0))) return -1;
if (uwsgi_buffer_u16le(out, vallen)) return -1;
if (uwsgi_buffer_append(out, val, vallen)) return -1;
@@ -180,6 +211,14 @@ int http_headers_parse(struct corerouter_peer *peer) {
char *watermark = ptr + hr->headers_size;
char *base = ptr;
char *query_string = NULL;
char *proxy_src = NULL;
char *proxy_dst = NULL;
char *proxy_src_port = NULL;
char *proxy_dst_port = NULL;
uint16_t proxy_src_len = 0;
uint16_t proxy_dst_len = 0;
uint16_t proxy_src_port_len = 0;
uint16_t proxy_dst_port_len = 0;
peer->out = uwsgi_buffer_new(uwsgi.page_size);
// force this buffer to be destroyed as soon as possibile
@@ -192,10 +231,19 @@ int http_headers_parse(struct corerouter_peer *peer) {
struct uwsgi_buffer *out = peer->out;
int found = 0;
if (uwsgi.enable_proxy_protocol || uhttp.enable_proxy_protocol) {
ptr = proxy1_parse(ptr, watermark, &proxy_src, &proxy_src_len, &proxy_dst, &proxy_dst_len, &proxy_src_port, &proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len);
base = ptr;
}
// REQUEST_METHOD
while (ptr < watermark) {
if (*ptr == ' ') {
if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1;
// on SOURCE METHOD, force raw body
if (uhttp.manage_source && !uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) {
hr->raw_body = 1;
}
ptr++;
found = 1;
break;
@@ -283,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;
@@ -300,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
@@ -315,16 +367,27 @@ int http_headers_parse(struct corerouter_peer *peer) {
}
#ifdef UWSGI_SSL
if (hr_https_add_vars(hr, out)) return -1;
if (hr_https_add_vars(hr, peer, out)) return -1;
#endif
// REMOTE_ADDR
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1;
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1;
if (proxy_src) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, proxy_src, proxy_src_len)) return -1;
if (proxy_src_port) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len)) return -1;
}
}
else
{
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1;
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1;
}
//HEADERS
base = ptr;
struct uwsgi_string_list *headers = NULL, *usl = NULL;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
@@ -345,13 +408,53 @@ int http_headers_parse(struct corerouter_peer *peer) {
hr->send_expect_100 = 1;
}
}
if (http_add_uwsgi_header(peer, base, ptr - base)) return -1;
size_t key_len = 0, value_len = 0;
int has_prefix = 0;
// last line, do not waste time
if (ptr - base == 0) break;
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
if (!value) goto clear;
usl = uwsgi_string_list_has_item(headers, base, key_len);
// there is already a HTTP header with the same name, let's merge them
if (usl) {
char *old_value = usl->custom_ptr;
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
usl->custom += 2 + value_len;
if (usl->custom2 & 0x01) free(old_value);
usl->custom2 |= 0x01;
}
else {
// add an entry
usl = uwsgi_string_new_list(&headers, NULL);
usl->value = base;
usl->len = key_len;
usl->custom_ptr = value;
usl->custom = value_len;
usl->custom2 = has_prefix;
}
ptr++;
base = ptr + 1;
}
ptr++;
}
usl = headers;
int broken = 0;
while(usl) {
if (!broken) {
if (http_add_uwsgi_header(peer, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02)) broken = 1;
}
if (usl->custom2 & 0x01) {
free(usl->custom_ptr);
}
struct uwsgi_string_list *tmp_usl = usl;
usl = usl->next;
free(tmp_usl);
}
if (broken) return -1;
struct uwsgi_string_list *hv = uhttp.http_vars;
while (hv) {
char *equal = strchr(hv->value, '=');
@@ -361,8 +464,33 @@ 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:
usl = headers;
while(usl) {
if (usl->custom2 & 0x01) {
free(usl->custom_ptr);
}
struct uwsgi_string_list *tmp_usl = usl;
usl = usl->next;
free(tmp_usl);
}
return -1;
}
@@ -446,6 +574,7 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
return 0;
}
if (main_peer->session->connect_peer_after_write) {
http_set_timeout(main_peer->session->connect_peer_after_write, uhttp.connect_timeout);
cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected);
main_peer->session->connect_peer_after_write = NULL;
return len;
@@ -459,6 +588,9 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
ssize_t hr_instance_connected(struct corerouter_peer* peer) {
cr_peer_connected(peer, "hr_instance_connected()");
// set the default timeout
http_set_timeout(peer, uhttp.cr.socket_timeout);
// we are connected, we cannot retry anymore
peer->can_retry = 0;
@@ -523,10 +655,7 @@ ssize_t hr_instance_read(struct corerouter_peer *peer) {
hr->has_gzip = 0;
#endif
if (uhttp.keepalive > 1) {
int orig_timeout = peer->session->corerouter->socket_timeout;
peer->session->corerouter->socket_timeout = uhttp.keepalive;
peer->session->main_peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer->session->main_peer);
peer->session->corerouter->socket_timeout = orig_timeout;
http_set_timeout(peer->session->main_peer, uhttp.keepalive);
}
}
#ifdef UWSGI_ZLIB
@@ -655,6 +784,9 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
return 1;
}
// ensure the headers timeout is honoured
http_set_timeout(main_peer, uhttp.headers_timeout);
// read until \r\n\r\n is found
size_t j;
size_t len = main_peer->in->pos;
@@ -708,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);
@@ -729,6 +867,19 @@ 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;
}
// on raw body, ensure keepalive is disabled
if (hr->raw_body) hr->session.can_keepalive = 0;
if (hr->session.can_keepalive && hr->content_length == 0) {
main_peer->disabled = 1;
// stop reading from the client
@@ -740,10 +891,12 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
break;
}
if (hr->websockets > 2 && hr->websocket_key_len > 0) {
hr->raw_body = 1;
}
new_peer->can_retry = 1;
// reset main timeout
http_set_timeout(main_peer, uhttp.cr.socket_timeout);
// set peer timeout
http_set_timeout(new_peer, uhttp.connect_timeout);
cr_connect(new_peer, hr_instance_connected);
break;
}
@@ -830,21 +983,26 @@ static int hr_retry(struct corerouter_peer *peer) {
retry:
// start async connect (again)
http_set_timeout(peer, uhttp.connect_timeout);
cr_connect(peer, hr_instance_connected);
return 0;
}
int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) {
if (!uhttp.headers_timeout) uhttp.headers_timeout = uhttp.cr.socket_timeout;
if (!uhttp.connect_timeout) uhttp.connect_timeout = uhttp.cr.socket_timeout;
// 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;
// headers timeout
cs->main_peer->current_timeout = uhttp.headers_timeout;
if (uhttp.raw_body) {
hr->raw_body = 1;
}
@@ -906,7 +1064,6 @@ int http_init() {
uhttp.cr.socket_num = 0;
}
uwsgi_corerouter_init((struct uwsgi_corerouter *) &uhttp);
return 0;
}
+68 -4
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;
@@ -166,10 +174,17 @@ void uwsgi_opt_http_to_https(char *opt, char *value, void *cr) {
ucr->has_sockets++;
}
int hr_https_add_vars(struct http_session *hr, struct uwsgi_buffer *out) {
int hr_https_add_vars(struct http_session *hr, struct corerouter_peer *peer, struct uwsgi_buffer *out) {
// HTTPS (adapted from nginx)
if (hr->session.ugs->mode == UWSGI_HTTP_SSL) {
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 && 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);
if (hr->ssl_client_cert) {
X509_NAME *name = X509_get_subject_name(hr->ssl_client_cert);
@@ -227,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);
}
@@ -263,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;
@@ -287,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;
@@ -315,6 +334,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);
@@ -343,9 +364,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;
@@ -367,6 +390,46 @@ ssize_t hr_ssl_read(struct corerouter_peer *main_peer) {
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) {
uwsgi_cr_error(peer, "hr_ssl_shutdown()");
}
else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
ERR_print_errors_fp(stderr);
}
return -1;
}
void hr_setup_ssl(struct http_session *hr, struct uwsgi_gateway_socket *ugs) {
hr->ssl = SSL_new(ugs->ctx);
SSL_set_fd(hr->ssl, hr->session.main_peer->fd);
@@ -375,6 +438,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;
}
+6
View File
@@ -59,6 +59,7 @@ int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t
uint32_t h_len = 0;
int has_size = 0;
int has_connection = 0;
for(i=next;i<len;i++) {
if (key) {
@@ -73,6 +74,7 @@ int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t
if (hr->session.can_keepalive) {
#endif
if (!uwsgi_strnicmp(key, colon-key, "Connection", 10)) {
has_connection = 1;
if (!uwsgi_strnicmp(colon+2, h_len-((colon-key)+2), "close", 5)) {
goto end;
}
@@ -169,6 +171,10 @@ int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t
return 0;
}
}
// avoid iOS making mess...
if (!has_connection) {
if (uwsgi_buffer_insert(ub, len-2, "Connection: close\r\n", 19)) return -1;
}
hr->session.can_keepalive = 0;
}
}
+50 -7
View File
@@ -180,8 +180,10 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
if (!key) return ub;
uint32_t h_len = 0;
// headers (key lowercase...)
// merge header values and ensure keys are all lowercase
struct uwsgi_string_list *hr=NULL, *usl=NULL;
char *line_value;
size_t line_key_len, line_value_len;
for(i=next;i<len;i++) {
if (key) {
if (buf[i] == '\r' || buf[i] == '\n') {
@@ -192,10 +194,37 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
// tolower !!!
size_t j;
for(j=0;j<h_len;j++) {
key[j] = tolower((int) key[j]);
// don't lowercase values, only keys
if (key[j] == ':') break;
key[j] = tolower((int) key[j]);
}
line_key_len = colon - key;
key[line_key_len] = 0;
line_value_len = h_len - 2 - line_key_len;
line_value = uwsgi_strncopy(colon+2, line_value_len);
if (hr) {
// check if we already store values for this key
usl = uwsgi_string_list_has_item(hr, key, line_key_len);
if (usl) {
// we have this key, append new value
char *oldval = usl->custom_ptr;
usl->custom_ptr = uwsgi_concat3n(usl->custom_ptr, usl->custom, "\0", 1, line_value, line_value_len);
usl->custom = usl->custom + 1 + line_value_len;
free(oldval);
}
else {
// this key is new
usl = uwsgi_string_new_list(&hr, key);
usl->custom_ptr = line_value;
usl->custom = line_value_len;
}
}
else {
// this is first key
usl = uwsgi_string_new_list(&hr, key);
usl->custom_ptr = line_value;
usl->custom = line_value_len;
}
if (uwsgi_buffer_append_keyval32(ub, key, colon-key, colon+2, h_len-((colon-key)+2))) goto end;
*hh+=1;
key = NULL;
h_len = 0;
}
@@ -210,6 +239,18 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
}
}
}
// append all merged header lines to buffer and free memory
struct uwsgi_string_list *ohr;
while (hr) {
if (uwsgi_buffer_append_keyval32(ub, hr->value, hr->len, hr->custom_ptr, hr->custom)) goto end;
*hh+=1;
ohr = hr;
hr = hr->next;
free(ohr->custom_ptr);
free(ohr);
}
return ub;
end:
@@ -515,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) {
-1
View File
@@ -28,7 +28,6 @@ static ssize_t uwsgi_pipe_logger(struct uwsgi_logger *ul, char *message, size_t
}
else {
// child
setsid();
if (setsid() < 0) {
uwsgi_error("setsid()");
exit(1);
+19 -2
View File
@@ -811,8 +811,25 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
lua_pushnil(L);
while(lua_next(L, -3) != 0) {
http = lua_tolstring(L, -2, &slen);
http2 = lua_tolstring(L, -1, &slen2);
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
if (lua_type(L, -1) == LUA_TTABLE) {
for (i = 1; /*empty*/ ; ++i) {
lua_rawgeti(L, -1, i);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
http2 = lua_tolstring(L, -1, &slen2);
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
lua_pop(L, 1);
}
}
else {
http2 = lua_tolstring(L, -1, &slen2);
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
}
lua_pop(L, 1);
}
+46 -33
View File
@@ -102,6 +102,10 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
}
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val));
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) {
char *colon = strchr(json_val, ':');
if (colon) {
@@ -210,6 +214,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen);
}
}
else if (!uwsgi_strncmp("URL_SCHEME", 10, key, keylen)) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, val, vallen);
}
}
else {
// add header
@@ -299,6 +306,13 @@ void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_
// fake function, the body is in a file or completely in memory
ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_status;
if (remains > 0) {
if (len > remains) len = remains;
memcpy(buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size + wsgi_req->proto_parser_status, len);
wsgi_req->proto_parser_status += len;
return len;
}
return 0;
}
@@ -410,7 +424,8 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
}
// pre-build the mongrel2 response_header
wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1);
wsgi_req->proto_parser_buf_size = req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1;
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_buf_size);
memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len);
((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' ';
resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1);
@@ -422,13 +437,22 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
// handle post data (in memory)
// reallocate wsgi_req->proto_parser_buf and change its size to be able to store request body
// the parser status holds the current position for read_body hook
if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) {
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
char *tmp = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + wsgi_req->post_cl);
if (!tmp) {
uwsgi_error("realloc()");
exit(1);
}
wsgi_req->proto_parser_buf = tmp;
// status is an offset...
wsgi_req->proto_parser_status = 0;
#ifdef UWSGI_DEBUG
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
#endif
wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl);
memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl);
memcpy(wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size, message_ptr, wsgi_req->post_cl);
}
}
@@ -452,33 +476,7 @@ retry:
return -1;
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
zmq_msg_t reply;
// check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos
if (!wsgi_req->proto_parser_pos)
return;
// no need to pass a free function (the buffer will be freed during cloe_request)
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()");
#else
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()");
#endif
}
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
}
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
static int uwsgi_proto_zeromq_write_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
zmq_msg_t reply;
if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) {
@@ -489,7 +487,8 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
char *zmq_body = zmq_msg_data(&reply);
memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos);
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
if (len > 0)
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
@@ -510,6 +509,18 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
return UWSGI_OK;
}
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
int ret = uwsgi_proto_zeromq_write_do(wsgi_req, buf, len);
if (ret == UWSGI_OK) {
wsgi_req->write_pos += len;
}
return ret;
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
uwsgi_proto_zeromq_write_do(wsgi_req, "", 0);
}
/*
we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of
@@ -532,7 +543,7 @@ int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t po
return -1;
}
wsgi_req->write_pos += rlen;
if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) {
if (uwsgi_proto_zeromq_write_do(wsgi_req, tmp_buf, rlen) < 0) {
free(tmp_buf);
return -1;
}
@@ -574,6 +585,7 @@ static void mongrel2_register_proto() {
static void mongrel2_connect() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->proto != uwsgi_proto_zeromq_parser) goto next;
uwsgi_sock->ctx = zmq_init(1);
if (!uwsgi_sock->ctx) {
uwsgi_error("mongrel2_connect()/zmq_init()");
@@ -581,7 +593,7 @@ static void mongrel2_connect() {
}
char *responder = strchr(uwsgi_sock->name, ',');
if (!responder) {
uwsgi_log("invalid zeromq address\n");
uwsgi_log("invalid zeromq address: %s\n", uwsgi_sock->name);
exit(1);
}
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
@@ -653,6 +665,7 @@ static void mongrel2_connect() {
#else
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
#endif
next:
uwsgi_sock = uwsgi_sock->next;
}
}
+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) {
+12
View File
@@ -0,0 +1,12 @@
#include "php.h"
#include "SAPI.h"
#include "php_main.h"
#include "php_variables.h"
#include "ext/standard/php_smart_str.h"
#include "ext/standard/info.h"
#include "ext/session/php_session.h"
#include <uwsgi.h>
+72 -41
View File
@@ -1,12 +1,4 @@
#include "php.h"
#include "SAPI.h"
#include "php_main.h"
#include "php_variables.h"
#include "ext/standard/php_smart_str.h"
#include "ext/standard/info.h"
#include "../../uwsgi.h"
#include "common.h"
extern struct uwsgi_server uwsgi;
@@ -31,6 +23,11 @@ struct uwsgi_php {
int dump_config;
char *server_software;
size_t server_software_len;
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) {
@@ -59,8 +56,12 @@ struct uwsgi_option uwsgi_php_options[] = {
#endif
{"php-var", required_argument, 0, "add/overwrite a CGI variable at each request", uwsgi_opt_add_string_list, &uphp.vars, 0},
{"php-dump-config", no_argument, 0, "dump php config (if modified via --php-set or append options)", uwsgi_opt_true, &uphp.dump_config, 0},
{0, 0, 0, 0, 0, 0, 0},
{"php-exec-before", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
{"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
};
@@ -76,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;
@@ -134,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);
@@ -178,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);
@@ -227,8 +228,9 @@ void uwsgi_php_set(char *opt) {
uwsgi_sapi_module.ini_entries[uphp.ini_size] = 0;
}
// future implementation...
extern ps_module ps_mod_uwsgi;
PHP_MINIT_FUNCTION(uwsgi_php_minit) {
php_session_register_module(&ps_mod_uwsgi);
return SUCCESS;
}
@@ -252,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();
}
@@ -267,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();
}
@@ -285,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();
}
@@ -302,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();
}
@@ -327,15 +333,16 @@ 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();
}
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
RETURN_TRUE;
}
RETURN_NULL();
@@ -349,15 +356,16 @@ 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();
}
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
RETURN_TRUE;
}
RETURN_NULL();
@@ -510,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);
}
@@ -551,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
@@ -579,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;
@@ -649,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;
}
@@ -714,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;
}
@@ -734,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);
@@ -847,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);
@@ -890,8 +910,19 @@ secure3:
return -1;
}
struct uwsgi_string_list *usl=NULL;
uwsgi_foreach(usl, uphp.exec_before) {
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec before", 1 TSRMLS_CC) == FAILURE) goto end;
}
php_execute_script(&file_handle TSRMLS_CC);
uwsgi_foreach(usl, uphp.exec_after) {
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec after", 1 TSRMLS_CC) == FAILURE) goto end;
}
end:
php_request_shutdown(NULL);
return 0;
+50
View File
@@ -0,0 +1,50 @@
#include "common.h"
PS_OPEN_FUNC(uwsgi) {
PS_SET_MOD_DATA((char *)save_path);
return SUCCESS;
}
PS_CLOSE_FUNC(uwsgi) {
return SUCCESS;
}
PS_READ_FUNC(uwsgi) {
char *cache = PS_GET_MOD_DATA();
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get((char *)key, strlen(key), &valsize, NULL, cache);
if (!value) return FAILURE;
char *new_val = emalloc(valsize);
memcpy(new_val, value, valsize);
free(value);
*val = new_val;
*vallen = valsize;
return SUCCESS;
}
PS_WRITE_FUNC(uwsgi) {
char *cache = PS_GET_MOD_DATA();
if (vallen == 0) return SUCCESS;
if (!uwsgi_cache_magic_set((char *)key, strlen(key), (char *)val, vallen, 0, UWSGI_CACHE_FLAG_UPDATE, cache)) {
return SUCCESS;
}
return FAILURE;
}
PS_DESTROY_FUNC(uwsgi) {
char *cache = PS_GET_MOD_DATA();
if (!uwsgi_cache_magic_del((char *)key, strlen(key), cache)) {
return SUCCESS;
}
return FAILURE;
}
PS_GC_FUNC(uwsgi) {
return SUCCESS;
}
ps_module ps_mod_uwsgi = {
PS_MOD(uwsgi)
};
+1 -1
View File
@@ -25,4 +25,4 @@ phplibdir = os.environ.get('UWSGICONFIG_PHPLIBDIR')
if phplibdir:
LIBS.append('-Wl,-rpath=%s' % phplibdir)
GCC_LIST = ['php_plugin']
GCC_LIST = ['php_plugin', 'session']
+2
View File
@@ -65,6 +65,8 @@ struct uwsgi_perl {
int shell_oneshot;
CV *spooler;
int no_plack;
};
void init_perl_embedded_module(void);
+106 -45
View File
@@ -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);
}
@@ -54,7 +56,7 @@ XS(XS_psgix_logger) {
psgi_check_args(1);
HV *hv_args = (HV *) (SvRV(ST(0)));
if (!hv_exists(hv_args, "level", 5) || !hv_exists(hv_args, "message", 7)) {
Perl_croak(aTHX_ "psgix.logger requires bot level and message items");
Perl_croak(aTHX_ "psgix.logger requires both level and message items");
}
char *level = SvPV_nolen(*(hv_fetch(hv_args, "level", 5, 0)));
char *message = SvPV_nolen(*(hv_fetch(hv_args, "message", 7, 0)));
@@ -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 {
@@ -108,7 +111,7 @@ XS(XS_input_read) {
unsigned long arg_len = SvIV(ST(2));
long offset = 0;
if (items > 2) {
if (items > 3) {
offset = (long) SvIV(ST(3));
}
@@ -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 (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));
}
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) {
hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newSViv(1), 0);
}
else {
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();
}
@@ -313,9 +361,6 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
char *app_name = uwsgi_concat2n(app, app_len, "", 0);
size_t size;
char *buf = uwsgi_open_and_read(app_name, &size, 1, NULL);
if (uwsgi_file_exists(app_name)) {
// prepare for $0 (if the file is local)
uperl.embedding[1] = app_name;
@@ -368,38 +413,34 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
uperl.tmp_current_i = i;
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
uperl.embedding[2] = app_name;
if (perl_parse(interpreters[i], xs_init, 3, uperl.embedding, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(uperl.embedding[1]);
uperl.embedding[1] = app_name;
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
free(uperl.embedding[1]);
uperl.embedding[1] = app_name;
}
else {
if (perl_parse(interpreters[i], xs_init, 2, uperl.embedding, NULL)) {
// We need to initialize the interpreter to execute
// our xs_init hook, but we're *not* calling it with
// uperl.embedding as an argument so we won't execute
// BEGIN blocks in app_name twice.
{
char *perl_e_arg = uwsgi_concat2("#line 0 ", app_name);
char *perl_init_arg[] = { "", "-e", perl_e_arg };
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(callables);
free(perl_e_arg);
uwsgi_perl_free_stashes();
goto clear;
}
} else {
free(perl_e_arg);
}
}
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
char *local_lib_use = uwsgi_concat3("use local::lib qw(", uperl.locallib, ");");
perl_eval_pv(local_lib_use, 1);
free(local_lib_use);
}
perl_eval_pv("use IO::Handle;", 1);
perl_eval_pv("use IO::File;", 1);
perl_eval_pv("use IO::Socket;", 1);
perl_eval_pv("use Scalar::Util;", 1);
if (!uperl.no_die_catch) {
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
}
if (uperl.argv_items || uperl.argv_item) {
AV *uperl_argv = GvAV(PL_argvgv);
@@ -417,12 +458,32 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
}
}
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(app, app_len));
callables[i] = perl_eval_pv(uwsgi_concat4("#line 1 ", app_name, "\n", buf), 0);
if (!callables[i]) {
SV *has_plack = NULL;
if (!uperl.no_plack) {
has_plack = perl_eval_pv("use Plack::Util;", 0);
}
if (!has_plack || SvTRUE(ERRSV)) {
if (!uperl.no_plack) {
uwsgi_log("Plack::Util is not installed, using \"do\" instead of \"load_psgi\"\n");
}
char *code = uwsgi_concat3("my $app = do '", app_name, "'; if ( !$app && ( my $error = $@ || $! )) { die $error; }; $app");
callables[i] = perl_eval_pv(code, 0);
free(code);
}
else {
char *code = uwsgi_concat3("Plack::Util::load_psgi '", app_name , "';");
callables[i] = perl_eval_pv(code, 0);
free(code);
}
if (!callables[i] || SvTYPE(callables[i]) == SVt_NULL || SvTRUE(ERRSV)) {
if (SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
}
uwsgi_log("unable to find PSGI function entry point.\n");
// what to do here ? i hope no-one will use threads with dynamic apps...
free(callables);
@@ -430,18 +491,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
goto clear;
}
if (!uperl.no_die_catch) {
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
}
}
PERL_SET_CONTEXT(interpreters[0]);
}
free(buf);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
goto clear;
@@ -504,6 +563,8 @@ void uwsgi_psgi_preinit_apps() {
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec) {
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
uwsgi_perl_exec(usl->value);
}
}
+35 -10
View File
@@ -44,6 +44,8 @@ struct uwsgi_option uwsgi_perl_options[] = {
{"plshell", optional_argument, 0, "run a perl interactive shell", uwsgi_opt_plshell, NULL, 0},
{"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0},
{"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -112,7 +114,7 @@ SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
SPAGAIN;
newobj = POPs;
newobj = SvREFCNT_inc(POPs);
PUTBACK;
FREETMPS;
LEAVE;
@@ -659,15 +661,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();
@@ -705,6 +713,8 @@ void uwsgi_perl_post_fork() {
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec_post_fork) {
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
uwsgi_perl_exec(usl->value);
}
@@ -799,24 +809,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;}
+35 -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;
@@ -768,6 +775,9 @@ XS(XS_sharedarea_wait) {
id = SvIV(ST(0));
if (items > 1) {
freq = SvIV(ST(1));
if (items > 2) {
timeout = SvIV(ST(2));
}
}
if (uwsgi_sharedarea_wait(id, freq, timeout)) {
@@ -943,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));
@@ -955,6 +965,27 @@ XS(XS_spool) {
XSRETURN_UNDEF;
}
XS(XS_add_var) {
dXSARGS;
psgi_check_args(2);
struct wsgi_request *wsgi_req = current_wsgi_req();
STRLEN keylen;
char *key = SvPV(ST(0), keylen);
STRLEN vallen;
char *val = SvPV(ST(1), vallen);
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
croak("unable to add request var, check your buffer size");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
void init_perl_embedded_module() {
psgi_xs(reload);
@@ -1016,5 +1047,8 @@ void init_perl_embedded_module() {
psgi_xs(spooler);
psgi_xs(spool);
psgi_xs(add_var);
psgi_xs(worker_id);
}
+44 -30
View File
@@ -35,6 +35,7 @@ void (*u_pypy_thread_attach)(void);
void (*u_pypy_init_threads)(void);
// the hooks you can override with pypy
void (*uwsgi_pypy_hook_execute_source)(char *);
void (*uwsgi_pypy_hook_loader)(char *);
void (*uwsgi_pypy_hook_file_loader)(char *);
void (*uwsgi_pypy_hook_paste_loader)(char *);
@@ -65,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) {
@@ -186,23 +204,21 @@ ready:
static void uwsgi_pypy_preinit_apps() {
struct uwsgi_string_list *usl = upypy.eval;
while(usl) {
if (u_pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
if (!uwsgi_pypy_hook_execute_source) {
uwsgi_log("*** WARNING your pypy setup code does not expose a callback for \"execute_source\" ***\n");
return;
}
usl = upypy.exec;
while(usl) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, upypy.eval) {
uwsgi_pypy_hook_execute_source(usl->value);
}
uwsgi_foreach(usl, upypy.exec) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (u_pypy_execute_source(buffer)) {
exit(1);
}
uwsgi_pypy_hook_execute_source(buffer);
free(buffer);
usl = usl->next;
}
}
@@ -305,22 +321,15 @@ static uint64_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t a
static void uwsgi_pypy_post_fork() {
pthread_mutex_init(&upypy.attach_thread_lock, NULL);
struct uwsgi_string_list *usl = upypy.eval_post_fork;
while(usl) {
if (u_pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, upypy.eval_post_fork) {
uwsgi_pypy_hook_execute_source(usl->value);
}
usl = upypy.exec_post_fork;
while(usl) {
uwsgi_foreach(usl, upypy.exec_post_fork) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (u_pypy_execute_source(buffer)) {
exit(1);
}
uwsgi_pypy_hook_execute_source(buffer);
free(buffer);
usl = usl->next;
}
if (uwsgi_pypy_post_fork_hook) {
@@ -337,10 +346,15 @@ static void uwsgi_pypy_onload() {
static int uwsgi_pypy_mule(char *opt) {
if (!uwsgi_pypy_hook_execute_source) {
uwsgi_log("!!! no \"execute_source\" callback in your pypy setup code !!!\n");
exit(1);
}
if (uwsgi_endswith(opt, ".py")) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(opt, &rlen, 1, NULL);
u_pypy_execute_source(buffer);
uwsgi_pypy_hook_execute_source(buffer);
free(buffer);
return 1;
}
+10
View File
@@ -24,6 +24,7 @@ ssize_t read(int, void *, size_t);
ssize_t write(int, const void *, size_t);
int close(int);
void (*uwsgi_pypy_hook_execute_source)(char *);
void (*uwsgi_pypy_hook_loader)(char *);
void (*uwsgi_pypy_hook_file_loader)(char *);
void (*uwsgi_pypy_hook_paste_loader)(char *);
@@ -277,6 +278,14 @@ wsgi_application = None
if len(sys.argv) == 0:
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
"""
execute source, we expose it as cffi callback to avoid deadlocks
after GIL initialization
"""
@ffi.callback("void(char *)")
def uwsgi_pypy_execute_source(s):
source = ffi.string(s)
exec(source)
"""
load a wsgi module
@@ -480,6 +489,7 @@ def uwsgi_pypy_wsgi_handler(wsgi_req):
if hasattr(response, 'close'):
response.close()
lib.uwsgi_pypy_hook_execute_source = uwsgi_pypy_execute_source
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
lib.uwsgi_pypy_hook_paste_loader = uwsgi_pypy_paste_loader
+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) );
}
+57 -23
View File
@@ -168,6 +168,8 @@ struct uwsgi_option uwsgi_python_options[] = {
{"py-sharedarea", required_argument, 0, "create a sharedarea from a python bytearray object of the specified size", uwsgi_opt_add_string_list, &up.sharedarea, 0},
#endif
{"py-call-osafterfork", no_argument, 0, "enable child processes running cpython to trap OS signals", uwsgi_opt_true, &up.call_osafterfork, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -197,6 +199,12 @@ int uwsgi_python_init() {
uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
}
if (Py_IsInitialized()) {
uwsgi_log("--- Python VM already initialized ---\n");
PyGILState_Ensure();
goto ready;
}
if (up.home != NULL) {
#ifdef PYTHREE
// check for PEP 405 virtualenv (starting from python 3.3)
@@ -251,6 +259,8 @@ pep405:
Py_Initialize();
ready:
if (!uwsgi.has_threads) {
uwsgi_log_initial("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
}
@@ -369,6 +379,11 @@ void uwsgi_python_post_fork() {
UWSGI_GET_GIL
}
// reset python signal flags so child processes can trap signals
if (up.call_osafterfork) {
PyOS_AfterFork();
}
uwsgi_python_reset_random_seed();
// call the post_fork_hook
@@ -382,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;
@@ -905,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;
@@ -1251,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
@@ -1267,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;
@@ -1399,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;
}
+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) {
+182 -11
View File
@@ -4,6 +4,29 @@ extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern struct uwsgi_plugin python_plugin;
static PyObject *py_uwsgi_add_var(PyObject * self, PyObject * args) {
char *key = NULL;
Py_ssize_t keylen = 0;
char *val = NULL;
Py_ssize_t vallen = 0;
struct wsgi_request *wsgi_req = py_current_wsgi_req();
if (!PyArg_ParseTuple(args, "s#s#", &key, &keylen, &val, &vallen)) {
return NULL;
}
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
return PyErr_Format(PyExc_ValueError, "unable to add request var, check your buffer size");
}
Py_INCREF(Py_True);
return Py_True;
}
static PyObject *py_uwsgi_micros(PyObject * self, PyObject * args) {
return PyLong_FromUnsignedLongLong(uwsgi_micros());
}
static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
struct wsgi_request *wsgi_req = py_current_wsgi_req();
@@ -359,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);
@@ -1403,7 +1431,7 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
uint64_t pos = 0;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "il|l:sharedarea_inc64", &id, &pos, &value)) {
if (!PyArg_ParseTuple(args, "iL|l:sharedarea_inc64", &id, &pos, &value)) {
return NULL;
}
@@ -1420,12 +1448,56 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_sharedarea_write32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int32_t value = 0;
if (!PyArg_ParseTuple(args, "iLI:sharedarea_write32", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_write32(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write32()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_write16(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int16_t value = 0;
if (!PyArg_ParseTuple(args, "iLI:sharedarea_write16", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_write16(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write16()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_write64(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int64_t value = 0;
if (!PyArg_ParseTuple(args, "ill:sharedarea_write64", &id, &pos, &value)) {
if (!PyArg_ParseTuple(args, "iLL:sharedarea_write64", &id, &pos, &value)) {
return NULL;
}
@@ -1447,7 +1519,7 @@ PyObject *py_uwsgi_sharedarea_write(PyObject * self, PyObject * args) {
char *value;
Py_ssize_t value_len = 0;
if (!PyArg_ParseTuple(args, "ils#:sharedarea_write", &id, &pos, &value, &value_len)) {
if (!PyArg_ParseTuple(args, "iLs#:sharedarea_write", &id, &pos, &value, &value_len)) {
return NULL;
}
@@ -1547,7 +1619,7 @@ PyObject *py_uwsgi_sharedarea_write8(PyObject * self, PyObject * args) {
uint64_t pos = 0;
int8_t value;
if (!PyArg_ParseTuple(args, "ilb:sharedarea_write8", &id, &pos, &value)) {
if (!PyArg_ParseTuple(args, "iLb:sharedarea_write8", &id, &pos, &value)) {
return NULL;
}
@@ -1569,7 +1641,7 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
uint64_t pos = 0;
int64_t value;
if (!PyArg_ParseTuple(args, "il:sharedarea_read64", &id, &pos)) {
if (!PyArg_ParseTuple(args, "iL:sharedarea_read64", &id, &pos)) {
return NULL;
}
@@ -1581,16 +1653,59 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read64()");
}
return PyLong_FromLong(value);
return PyLong_FromLongLong(value);
}
PyObject *py_uwsgi_sharedarea_read32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int32_t value;
if (!PyArg_ParseTuple(args, "iL:sharedarea_read32", &id, &pos)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_read32(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read32()");
}
return PyInt_FromLong(value);
}
PyObject *py_uwsgi_sharedarea_read16(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int16_t value;
if (!PyArg_ParseTuple(args, "iL:sharedarea_read16", &id, &pos)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_read16(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read16()");
}
return PyInt_FromLong(value);
}
PyObject *py_uwsgi_sharedarea_read8(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int8_t byte;
if (!PyArg_ParseTuple(args, "il:sharedarea_read8", &id, &pos)) {
if (!PyArg_ParseTuple(args, "iL:sharedarea_read8", &id, &pos)) {
return NULL;
}
@@ -1610,7 +1725,7 @@ PyObject *py_uwsgi_sharedarea_read(PyObject * self, PyObject * args) {
uint64_t pos = 0;
uint64_t len = 0;
if (!PyArg_ParseTuple(args, "il|l:sharedarea_read", &id, &pos, &len)) {
if (!PyArg_ParseTuple(args, "iL|L:sharedarea_read", &id, &pos, &len)) {
return NULL;
}
@@ -1745,7 +1860,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;
@@ -1846,7 +1960,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
@@ -1878,6 +1993,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) {
@@ -2130,7 +2255,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) {
@@ -2309,6 +2435,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},
};
@@ -2417,6 +2544,10 @@ static PyMethodDef uwsgi_advanced_methods[] = {
{"ready_fd", py_uwsgi_ready_fd, METH_VARARGS, ""},
{"add_var", py_uwsgi_add_var, METH_VARARGS, ""},
{"micros", py_uwsgi_micros, METH_VARARGS, ""},
{NULL, NULL},
};
@@ -2432,6 +2563,10 @@ static PyMethodDef uwsgi_sa_methods[] = {
{"sharedarea_writelong", py_uwsgi_sharedarea_write64, METH_VARARGS, ""},
{"sharedarea_read64", py_uwsgi_sharedarea_read64, METH_VARARGS, ""},
{"sharedarea_write64", py_uwsgi_sharedarea_write64, METH_VARARGS, ""},
{"sharedarea_read32", py_uwsgi_sharedarea_read32, METH_VARARGS, ""},
{"sharedarea_write32", py_uwsgi_sharedarea_write32, METH_VARARGS, ""},
{"sharedarea_read16", py_uwsgi_sharedarea_read16, METH_VARARGS, ""},
{"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_rlock", py_uwsgi_sharedarea_rlock, METH_VARARGS, ""},
@@ -3164,6 +3299,40 @@ PyObject *py_uwsgi_metric_get(PyObject * self, PyObject * args) {
return PyLong_FromLongLong(value);
}
PyObject *py_uwsgi_metric_set_max(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_set_max", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_set_max(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_set_min(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_set_min", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_set_min(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
static PyMethodDef uwsgi_metrics_methods[] = {
{"metric_inc", py_uwsgi_metric_inc, METH_VARARGS, ""},
@@ -3172,6 +3341,8 @@ static PyMethodDef uwsgi_metrics_methods[] = {
{"metric_div", py_uwsgi_metric_div, METH_VARARGS, ""},
{"metric_get", py_uwsgi_metric_get, METH_VARARGS, ""},
{"metric_set", py_uwsgi_metric_set, METH_VARARGS, ""},
{"metric_set_max", py_uwsgi_metric_set_max, METH_VARARGS, ""},
{"metric_set_min", py_uwsgi_metric_set_min, METH_VARARGS, ""},
{NULL, NULL},
};
+4
View File
@@ -197,6 +197,8 @@ struct uwsgi_python {
PyObject *raw_callable;
struct uwsgi_string_list *sharedarea;
int call_osafterfork;
};
@@ -297,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");\
+2 -1
View File
@@ -21,12 +21,13 @@ int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) {
char *content = NULL;
size_t content_len = 0;
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
Py_buffer pbuf;
int has_buffer = 0;
#endif
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
if (PyObject_CheckBuffer(chunk)) {
if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) {
+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
+38 -2
View File
@@ -13,6 +13,26 @@ pthread_mutex_t ur_basicauth_crypt_mutex;
extern struct uwsgi_server uwsgi;
static char *htpasswd_check_sha1(char *pwd) {
#ifdef UWSGI_SSL
char sha1[20];
uwsgi_sha1(pwd, strlen(pwd), sha1);
size_t len = 0;
char *b64 = uwsgi_base64_encode(sha1, 20, &len);
if (!b64) return NULL;
// we add a new line for being fgets-friendly
char *crypted = uwsgi_concat3n("{SHA}", 5, b64, len, "\n", 1);
free(b64);
return crypted;
#else
uwsgi_log("*** WARNING, rebuild uWSGI with SSL support for htpasswd sha1 feature ***\n");
return NULL;
#endif
}
static uint16_t htpasswd_check(char *filename, char *auth) {
char line[1024];
@@ -25,11 +45,23 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
return 0;
}
while(fgets(line, 1024, htpasswd)) {
char *crypted = NULL;
int need_free = 0;
char *colon2 = strchr(line, ':');
if (!colon2) break;
char *cpwd = colon2+1;
size_t clen = strlen(cpwd);
// now we check which algo to use
// {SHA} ?
if (!uwsgi_starts_with(cpwd, clen, "{SHA}", 5)) {
crypted = htpasswd_check_sha1(colon+1);
if (crypted) need_free = 1;
goto check;
}
if (clen < 13) break;
if (clen > 13) cpwd[13] = 0;
@@ -39,20 +71,24 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
cd.initialized = 0;
// we do as nginx here
cd.current_salt[0] = ~cpwd[0];
char *crypted = crypt_r( colon+1, cpwd, &cd);
crypted = crypt_r( colon+1, cpwd, &cd);
#else
if (uwsgi.threads > 1) pthread_mutex_lock(&ur_basicauth_crypt_mutex);
char *crypted = crypt( colon+1, cpwd);
crypted = crypt( colon+1, cpwd);
if (uwsgi.threads > 1) pthread_mutex_unlock(&ur_basicauth_crypt_mutex);
#endif
check:
if (!crypted) continue;
if (!strcmp( crypted, cpwd )) {
if (!uwsgi_strncmp(auth, colon-auth, line, colon2-line)) {
fclose(htpasswd);
if (need_free) free(crypted);
return colon-auth;
}
}
if (need_free) free(crypted);
}
fclose(htpasswd);
+42 -4
View File
@@ -5,6 +5,8 @@
extern struct uwsgi_server uwsgi;
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = NULL;
// mark a route request
wsgi_req->via = UWSGI_VIA_ROUTE;
@@ -24,9 +26,17 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
}
}
// convert the wsgi_request to an http proxy request
struct uwsgi_buffer *ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
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);
}
if (!ub) {
if (ub_url) uwsgi_buffer_destroy(ub_url);
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
@@ -46,11 +56,12 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_NEXT;
}
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
wsgi_req->proto_parser_remains = 0;
}
// ok now if have offload threads, directly use them
if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
// append buffered body
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
@@ -60,6 +71,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
return UWSGI_ROUTE_NEXT;
}
}
// if we have a CONNECT request, let's confirm it to the client
if (ur->custom & 0x02) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
// no need to check for return value
uwsgi_response_write_headers_do(wsgi_req);
}
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
@@ -72,6 +91,7 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
}
end:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_addr);
@@ -102,15 +122,33 @@ static int uwsgi_router_http(struct uwsgi_route *ur, char *args) {
}
static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
ur->custom = 0x1;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_proxyhttp_connect(struct uwsgi_route *ur, char *args) {
ur->custom = 0x1|0x02;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) {
ur->custom = 0x02;
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);
}
struct uwsgi_plugin router_http_plugin = {
+26 -1
View File
@@ -18,6 +18,8 @@ struct uwsgi_router_file_conf {
char *mime;
char *no_cl;
char *no_headers;
};
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -38,6 +40,7 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
char buf[32768];
struct stat st;
int ret = UWSGI_ROUTE_BREAK;
size_t remains = 0;
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
@@ -61,6 +64,11 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
if (urfc->no_headers) goto send;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
@@ -82,8 +90,10 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
else {
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
send:
size_t remains = st.st_size;
remains = st.st_size;
while(remains) {
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
if (rlen <= 0) goto end2;
@@ -125,6 +135,11 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
if (urfc->no_headers) goto send;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
@@ -145,6 +160,8 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
send:
if (!wsgi_req->headers_sent) {
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
}
@@ -188,6 +205,11 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
if (urfc->no_headers) goto send;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
@@ -208,6 +230,8 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
send:
if (!wsgi_req->headers_sent) {
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
}
@@ -256,6 +280,7 @@ static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
"no_cl", &urfc->no_cl,
"no_content_length", &urfc->no_cl,
"mime", &urfc->mime,
"no_headers", &urfc->no_headers,
NULL)) {
uwsgi_log("invalid file route syntax: %s\n", args);
return -1;
+13 -4
View File
@@ -35,7 +35,13 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
struct uwsgi_header *uh = (struct uwsgi_header *) ur->data;
char *addr = ur->data + sizeof(struct uwsgi_header);
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, addr, strlen(addr));
if (!ub_addr) return UWSGI_ROUTE_BREAK;
// mark a route request
wsgi_req->via = UWSGI_VIA_ROUTE;
@@ -54,6 +60,7 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
goto end;
}
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
wsgi_req->proto_parser_remains = 0;
}
@@ -65,18 +72,20 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
goto end;
}
}
if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) {
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
}
if (uwsgi_proxy_nb(wsgi_req, addr, ub, remains, uwsgi.socket_timeout)) {
uwsgi_log("error routing request to uwsgi server %s\n", addr);
if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) {
uwsgi_log("error routing request to uwsgi server %s\n", ub_addr->buf);
}
end:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
+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]);
+5
View File
@@ -150,6 +150,11 @@ static void rrdtool_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, c
uwsgi_rlock(uwsgi.metrics_lock);
int ret = snprintf(buf, 1024, "N:%lld", (long long) (*um->value));
uwsgi_rwunlock(uwsgi.metrics_lock);
if (um->reset_after_push){
uwsgi_wlock(uwsgi.metrics_lock);
*um->value = um->initial_value;
uwsgi_rwunlock(uwsgi.metrics_lock);
}
if (ret < 3 || ret >= 1024) {
uwsgi_log("unable to update rrdtool metric for %s\n", um->name);
goto next;

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