Compare commits

...
168 Commits
Author SHA1 Message Date
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
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
78 changed files with 2857 additions and 1275 deletions
+2 -1
View File
@@ -1,7 +1,7 @@
- this is a incomplete list of all the contributors of the project -
Roberto De Ioris, Unbit, <roberto@unbit.it>
Riccardo Magliocchetti, Unbit, <riccardo@unbit.it>
Riccardo Magliocchetti
Yann Malet, Lincoln Loop
Simon Litchfield
Masahiro Honma, <hiratara@cpan.org>
@@ -28,3 +28,4 @@ Ryan Petrello
Danila Shtan <danila@shtan.ru>
Ævar Arnfjörð Bjarmason
Yu Zhao (getcwd)
Mathieu Dupuy
+70 -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);
@@ -325,8 +369,8 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
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))) {
if (mode == APR_NONBLOCK_READ && (APR_STATUS_IS_EAGAIN(rv)
|| (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 +386,37 @@ 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);
ap_pass_brigade(r->output_filters, pass_bb);
apr_brigade_cleanup(bb);
apr_brigade_cleanup(pass_bb);
}
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(bb);
return OK;
if (c->aborted || backend_broke) {
return DONE;
}
return OK;
}
static int uwsgi_handler(request_rec *r, proxy_worker *worker,
Binary file not shown.
+22 -23
View File
@@ -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) {
+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] == '\\') {
+43 -17
View File
@@ -331,6 +331,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);
@@ -476,17 +484,17 @@ static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *next, *curr = cache_item(index);
if (curr->next) {
next = cache_item(curr->next);
next->prev = curr->prev;
if (curr->lru_next) {
next = cache_item(curr->lru_next);
next->lru_prev = curr->lru_prev;
} else
uc->lru_tail = curr->prev;
uc->lru_tail = curr->lru_prev;
if (curr->prev) {
prev = cache_item(curr->prev);
prev->next = curr->next;
if (curr->lru_prev) {
prev = cache_item(curr->lru_prev);
prev->lru_next = curr->lru_next;
} else
uc->lru_head = curr->next;
uc->lru_head = curr->lru_next;
}
static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
@@ -495,12 +503,12 @@ static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
if (uc->lru_tail) {
prev = cache_item(uc->lru_tail);
prev->next = index;
prev->lru_next = index;
} else
uc->lru_head = index;
curr->next = 0;
curr->prev = uc->lru_tail;
curr->lru_next = 0;
curr->lru_prev = uc->lru_tail;
uc->lru_tail = index;
}
@@ -733,16 +741,22 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
else {
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
if (uci->first_block == 0xffffffffffffffffLLU) {
if (!uc->ignore_full)
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
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++;
uc->unused_blocks_stack_ptr++;
if (uc->purge_lru && uc->lru_head)
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
goto end;
}
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
if (uci->first_block + needed_blocks >= uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
@@ -837,16 +851,22 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uint64_t old_first_block = uci->first_block;
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
if (uci->first_block == 0xffffffffffffffffLLU) {
if (!uc->ignore_full)
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
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++;
uci->first_block = old_first_block;
if (uc->purge_lru && uc->lru_head)
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
goto end;
}
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
if (uci->first_block + needed_blocks >= uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
@@ -1212,6 +1232,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_keysize = NULL;
char *c_store = NULL;
char *c_store_sync = NULL;
char *c_store_delete = NULL;
char *c_nodes = NULL;
char *c_sync = NULL;
char *c_udp_servers = NULL;
@@ -1236,6 +1257,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,
@@ -1249,6 +1272,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"math_initial", &c_math_initial,
"ignore_full", &c_ignore_full,
"purge_lru", &c_purge_lru,
"lru", &c_purge_lru,
NULL)) {
uwsgi_log("unable to parse cache definition\n");
exit(1);
@@ -1298,6 +1322,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
if (c_use_last_modified) uc->use_last_modified = 1;
if (c_ignore_full) uc->ignore_full = 1;
if (c_store_delete) uc->store_delete = 1;
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
uc->store_sync = uwsgi.cache_store_sync;
+36
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;
@@ -816,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);
}
+12 -1
View File
@@ -292,11 +292,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 +504,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 +526,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 +574,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);
+700 -588
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;
+6 -5
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) {
+2
View File
@@ -80,6 +80,7 @@ void uwsgi_master_fifo_prepare() {
uwsgi_fifo_table['-'] = uwsgi_cheaper_decrease;
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
uwsgi_fifo_table['B'] = vassal_sos;
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
uwsgi_fifo_table['E'] = emperor_rescan;
@@ -131,6 +132,7 @@ int uwsgi_master_fifo_manage(int fd) {
}
// fifo destroyed, recreate it
else if (rlen == 0) {
event_queue_del_fd(uwsgi.master_queue, uwsgi.master_fifo_fd, event_queue_read());
close(fd);
uwsgi.master_fifo_fd = uwsgi_master_fifo();
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
+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);
+21
View File
@@ -392,6 +392,26 @@ static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) {
return buffer;
}
static char *uwsgi_scheme_callint(char *url, size_t *size, int add_zero) {
int (*func)(void) = dlsym(RTLD_DEFAULT, url);
if (!func) {
uwsgi_log("unable to find symbol %s\n", url);
exit(1);
}
char *s = uwsgi_num2str(func());
*size = strlen(s);
if (add_zero) {
*size += 1;
}
char *buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, s, strlen(s));
free(s);
return buffer;
}
static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) {
void *sym_start_ptr = NULL, *sym_end_ptr = NULL;
@@ -1249,6 +1269,7 @@ void uwsgi_setup_schemes() {
uwsgi_register_scheme("fd", uwsgi_scheme_fd);
uwsgi_register_scheme("exec", uwsgi_scheme_exec);
uwsgi_register_scheme("call", uwsgi_scheme_call);
uwsgi_register_scheme("callint", uwsgi_scheme_callint);
}
struct uwsgi_string_list *uwsgi_check_scheme(char *file) {
+99 -85
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) {
@@ -511,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() {
@@ -1845,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);
@@ -1854,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);
@@ -1875,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);
+42 -7
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;
@@ -907,6 +932,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 +980,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 +1000,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));
+41 -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);
}
+19 -12
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;
@@ -53,15 +62,6 @@ 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);
@@ -796,7 +796,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);
@@ -913,7 +913,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;
@@ -1145,6 +1145,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;
@@ -1206,9 +1208,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;
@@ -1284,7 +1289,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);
@@ -1714,6 +1719,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) {
@@ -1772,6 +1778,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);
+7 -4
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,9 +329,11 @@ next:
}
}
int ret = poll(mulepoll, count + farms_count, timeout);
int ret = -1;
retry:
ret = poll(mulepoll, count + farms_count, timeout);
if (ret < 0) {
uwsgi_error("poll");
uwsgi_error("uwsgi_mule_get_msg()/poll()");
}
else if (ret > 0 ) {
if (mulepoll[0].revents & POLLIN) {
@@ -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;
}
+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 ?
+66
View File
@@ -583,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);
@@ -1086,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);
@@ -1694,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;
}
@@ -1761,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);
@@ -1783,6 +1848,7 @@ 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);
+2 -1
View File
@@ -193,12 +193,13 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
close(fd);
*len = rlen;
if (*len == 0) {
goto error;
goto error2;
}
return buffer;
error:
close(fd);
error2:
free(buffer);
return NULL;
+10 -1
View File
@@ -20,9 +20,18 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
return -1;
#elif defined(__linux__) || defined(__sun__) || defined(__GNU_kFreeBSD__)
#elif defined(__linux__) || defined(__GNU_kFreeBSD__)
off_t off = pos;
return sendfile(sockfd, filefd, &off, len);
#elif defined(__sun__)
off_t off = pos;
ssize_t wlen = sendfile(sockfd, filefd, &off, len);
if (wlen < 0 && uwsgi_is_again()) {
if (off - pos > 0) {
return off-pos;
}
}
return wlen;
#endif
no_sendfile:
+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;
}
+25 -7
View File
@@ -1733,13 +1733,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 +1753,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 +1805,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) {
+6 -8
View File
@@ -200,11 +200,13 @@ static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, ui
}
}
/*
CHANGED in 2.0.7: wsgi_req is useless !
*/
char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) {
struct timeval tv;
static uint64_t internal_counter = 0;
int core_id = 0;
int fd = -1;
struct spooler_req sr;
@@ -232,10 +234,6 @@ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len,
}
}
if (wsgi_req) {
core_id = wsgi_req->async_id;
}
// this lock is for threads, the pid value in filename will avoid multiprocess races
uwsgi_lock(uspool->lock);
@@ -260,7 +258,7 @@ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len,
// no need to check for errors...
(void) mkdir(filename, 0777);
ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(),
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
if (ret <= 0 || ret >=(int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
@@ -272,8 +270,8 @@ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len,
else {
filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256;
filename = uwsgi_malloc(filename_len);
int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter,
rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
if (ret <= 0 || ret >= (int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
free(filename);
+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;
}
+6
View File
@@ -1072,6 +1072,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) {
+23 -7
View File
@@ -1019,8 +1019,14 @@ void uwsgi_destroy_request(struct wsgi_request *wsgi_req) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
}
memset(wsgi_req, 0, sizeof(struct wsgi_request));
// reset for avoiding following requests to fail on non-uwsgi protocols
// thanks Marko Tiikkaja for catching it
wsgi_req->uh->pktsize = 0;
// some plugins expected async_id to be defined before setup
int tmp_id = wsgi_req->async_id;
memset(wsgi_req, 0, sizeof(struct wsgi_request));
wsgi_req->async_id = tmp_id;
}
// finalize/close/free a request
@@ -1051,10 +1057,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) {
@@ -1165,8 +1172,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;
@@ -3155,6 +3162,10 @@ void escape_json(char *src, size_t len, char *dst) {
*ptr++ = '\\';
*ptr++ = '"';
}
else if (src[i] == '\\') {
*ptr++ = '\\';
*ptr++ = '\\';
}
else {
*ptr++ = src[i];
}
@@ -3752,7 +3763,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));
@@ -3769,6 +3780,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);
@@ -3788,6 +3800,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;
+68 -20
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},
@@ -560,6 +568,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 +579,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},
@@ -672,6 +683,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 +703,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},
@@ -1247,6 +1259,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 +1285,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 +1331,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 +1383,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() {
@@ -1551,25 +1584,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) {
@@ -2198,7 +2246,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
// setup master logging
if (uwsgi.log_master && !uwsgi.daemonize2 && !uwsgi.logto2)
if (uwsgi.log_master)
uwsgi_setup_log_master();
// setup offload engines
@@ -2481,7 +2529,6 @@ int uwsgi_start(void *v_argv) {
if (uwsgi.logto2) {
if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
logto(uwsgi.logto2);
uwsgi_setup_log_master();
}
}
@@ -3751,7 +3798,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)
@@ -3780,7 +3828,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)
@@ -3827,7 +3876,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) {
@@ -3845,7 +3895,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) {
@@ -4146,15 +4197,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;
}
@@ -4201,8 +4250,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) {
+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;
+1 -1
View File
@@ -353,7 +353,7 @@ static void asyncio_loop() {
// call add_handler on each socket
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOi", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
uwsgi_pyexit;
}
uwsgi_sock = uwsgi_sock->next;
+5
View File
@@ -380,6 +380,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;
}
-1
View File
@@ -310,7 +310,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));
+1 -1
View File
@@ -271,7 +271,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
+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;
+1 -1
View File
@@ -36,7 +36,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
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] unabel to authenticate to db %s: %s\n", uems->database, err.c_str());
uwsgi_log_verbose("[emperor-mongodb] unable to authenticate to db %s: %s\n", uems->database, err.c_str());
return;
}
}
+1 -1
View File
@@ -2,6 +2,6 @@
NAME='emperor_zeromq'
CFLAGS = []
LDFLAGS = []
LIBS = []
LIBS = ['-lzmq']
GCC_LIST = ['emperor_zeromq']
+9 -1
View File
@@ -55,6 +55,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},
};
@@ -226,8 +227,15 @@ 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;
}
new_peer->can_retry = 1;
+3
View File
@@ -345,6 +345,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");
}
+3 -1
View File
@@ -44,6 +44,8 @@ struct uwsgi_http {
int headers_timeout;
int connect_timeout;
int manage_source;
int enable_proxy_protocol;
};
struct http_session {
@@ -156,7 +158,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
+45 -7
View File
@@ -62,6 +62,9 @@ struct uwsgi_option http_options[] = {
{"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-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},
};
@@ -150,10 +153,14 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t
}
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)) {
peer->key = val;
peer->key_len = vallen;
}
#ifdef UWSGI_ZLIB
else if (uhttp.auto_gzip && !uwsgi_strncmp("ACCEPT_ENCODING", 15, hh, keylen)) {
@@ -189,6 +196,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
@@ -201,10 +216,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;
@@ -324,12 +348,21 @@ 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;
@@ -796,6 +829,13 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
if (uwsgi_buffer_append(new_peer->out, main_peer->in->buf + hr->headers_size + 1, hr->remains)) return -1;
}
if (hr->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
@@ -807,9 +847,7 @@ 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);
+8 -1
View File
@@ -166,10 +166,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) {
peer->key = (char *) servername;
peer->key_len = strlen(servername);
}
#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);
+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;
}
}
+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) {
+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);
}
+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)
+30 -25
View File
@@ -26,6 +26,8 @@ struct uwsgi_php {
struct uwsgi_string_list *exec_before;
struct uwsgi_string_list *exec_after;
char *sapi_name;
} uphp;
void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
@@ -58,6 +60,7 @@ struct uwsgi_option uwsgi_php_options[] = {
{"php-exec-begin", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
{"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-sapi-name", required_argument, 0, "hack the sapi name (required for enabling zend opcode cache)", uwsgi_opt_set_str, &uphp.sapi_name, 0},
UWSGI_END_OF_OPTIONS
};
@@ -176,11 +179,11 @@ static void sapi_uwsgi_register_variables(zval *track_vars_array TSRMLS_DC)
php_register_variable_safe("DOCUMENT_ROOT", wsgi_req->document_root, wsgi_req->document_root_len, track_vars_array TSRMLS_CC);
if (wsgi_req->path_info_len) {
char *path_translated = ecalloc(1, (wsgi_req->file_len - wsgi_req->script_name_len) + wsgi_req->path_info_len + 1);
char *path_translated = ecalloc(1, wsgi_req->file_len + wsgi_req->path_info_len + 1);
memcpy(path_translated, wsgi_req->file, (wsgi_req->file_len - wsgi_req->script_name_len));
memcpy(path_translated + (wsgi_req->file_len - wsgi_req->script_name_len), wsgi_req->path_info, wsgi_req->path_info_len);
php_register_variable_safe("PATH_TRANSLATED", path_translated, (wsgi_req->file_len - wsgi_req->script_name_len) + wsgi_req->path_info_len , track_vars_array TSRMLS_CC);
memcpy(path_translated, wsgi_req->file, wsgi_req->file_len);
memcpy(path_translated + wsgi_req->file_len, wsgi_req->path_info, wsgi_req->path_info_len);
php_register_variable_safe("PATH_TRANSLATED", path_translated, wsgi_req->file_len + wsgi_req->path_info_len , track_vars_array TSRMLS_CC);
}
else {
php_register_variable_safe("PATH_TRANSLATED", "", 0, track_vars_array TSRMLS_CC);
@@ -251,8 +254,9 @@ PHP_FUNCTION(uwsgi_cache_exists) {
char *key = NULL;
int keylen = 0;
char *cache = NULL;
int cachelen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -266,8 +270,9 @@ PHP_FUNCTION(uwsgi_cache_exists) {
PHP_FUNCTION(uwsgi_cache_clear) {
char *cache = NULL;
int cachelen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -284,8 +289,9 @@ PHP_FUNCTION(uwsgi_cache_del) {
char *key = NULL;
int keylen = 0;
char *cache = NULL;
int cachelen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -301,12 +307,13 @@ PHP_FUNCTION(uwsgi_cache_get) {
char *key = NULL;
int keylen = 0;
char *cache = NULL;
int cachelen = 0;
uint64_t valsize;
if (!uwsgi.caches)
RETURN_NULL();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -326,11 +333,12 @@ PHP_FUNCTION(uwsgi_cache_set) {
int vallen;
uint64_t expires = 0;
char *cache = NULL;
int cachelen = 0;
if (!uwsgi.caches)
RETURN_NULL();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -348,11 +356,12 @@ PHP_FUNCTION(uwsgi_cache_update) {
int vallen;
uint64_t expires = 0;
char *cache = NULL;
int cachelen = 0;
if (!uwsgi.caches)
RETURN_NULL();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache, &cachelen) == FAILURE) {
RETURN_NULL();
}
@@ -578,8 +587,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;
@@ -657,6 +668,9 @@ int uwsgi_php_request(struct wsgi_request *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;
}
@@ -733,10 +747,6 @@ oldstyle:
}
}
char *orig_path_info = wsgi_req->path_info;
uint16_t orig_path_info_len = wsgi_req->path_info_len;
if (path_info) {
wsgi_req->path_info = path_info;
wsgi_req->path_info_len = orig_path_info_len - (path_info - orig_path_info);
@@ -846,24 +856,19 @@ 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);
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 = real_filename + wsgi_req->document_root_len;
}
wsgi_req->script_name_len = strlen(wsgi_req->script_name);
wsgi_req->script_name_len = orig_path_info_len;
}
#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);
+4 -1
View File
@@ -768,6 +768,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 +946,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));
+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) );
}
+11
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},
};
@@ -377,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
@@ -913,12 +920,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;
+144 -11
View File
@@ -382,6 +382,11 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
if (PyString_Check(py_node)) {
node = PyString_AsString(py_node);
}
#ifdef PYTHREE
else if (PyUnicode_Check(py_node)) {
node = PyBytes_AsString(PyUnicode_AsLatin1String(py_node));
}
#endif
py_func = PyTuple_GetItem(args, 1);
@@ -1426,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;
}
@@ -1443,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;
}
@@ -1470,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;
}
@@ -1570,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;
}
@@ -1592,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;
}
@@ -1604,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;
}
@@ -1633,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;
}
@@ -1768,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;
@@ -1869,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
@@ -2153,7 +2245,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) {
@@ -2459,6 +2552,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, ""},
@@ -3191,6 +3288,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, ""},
@@ -3199,6 +3330,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},
};
+2
View File
@@ -197,6 +197,8 @@ struct uwsgi_python {
PyObject *raw_callable;
struct uwsgi_string_list *sharedarea;
int call_osafterfork;
};
+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(ctx, key, body, body_len, off) < 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(ctx, key, comp, body, body_len, off) < 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;
}
+9
View File
@@ -64,6 +64,9 @@ 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)) {
@@ -132,6 +135,9 @@ 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)) {
@@ -199,6 +205,9 @@ 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)) {
+12 -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;
@@ -66,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;
+1 -1
View File
@@ -23,7 +23,7 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
return -1;
}
char *filename = uwsgi_spool_request(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0);
char *filename = uwsgi_spool_request(NULL, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0);
uh.modifier1 = 255;
uh.pktsize = 0;
if (filename) {
+5
View File
@@ -92,6 +92,11 @@ static void stats_pusher_socket(struct uwsgi_stats_pusher_instance *uspi, time_t
uwsgi_rlock(uwsgi.metrics_lock);
socket_send_metric(ub, uspi, um);
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);
}
um = um->next;
}
uwsgi_buffer_destroy(ub);
+6 -1
View File
@@ -92,9 +92,14 @@ static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g");
}
else {
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|m");
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|c");
}
uwsgi_rwunlock(uwsgi.metrics_lock);
if (um->reset_after_push){
uwsgi_wlock(uwsgi.metrics_lock);
*um->value = um->initial_value;
uwsgi_rwunlock(uwsgi.metrics_lock);
}
um = um->next;
}
uwsgi_buffer_destroy(ub);
+7
View File
@@ -94,6 +94,13 @@ static void stats_pusher_zabbix(struct uwsgi_stats_pusher_instance *uspi, time_t
if (uwsgi_buffer_append(zn->ub, "\",\"value\":\"", 11)) { error = 1; goto end;}
if (uwsgi_buffer_num64(zn->ub, *um->value)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, "\"}", 2)) { error = 1; goto end;}
if (um->reset_after_push){
uwsgi_rwunlock(uwsgi.metrics_lock);
uwsgi_wlock(uwsgi.metrics_lock);
*um->value = um->initial_value;
uwsgi_rwunlock(uwsgi.metrics_lock);
uwsgi_rlock(uwsgi.metrics_lock);
}
um = um->next;
if (um) {
if (uwsgi_buffer_append(zn->ub, ",", 1)) { error = 1; goto end;}
+178 -149
View File
@@ -8,12 +8,12 @@ extern struct uwsgi_server uwsgi;
struct fcgi_record {
uint8_t version;
uint8_t type;
uint8_t req1;
uint8_t req0;
uint8_t type;
uint8_t req1;
uint8_t req0;
uint8_t cl1;
uint8_t cl0;
uint8_t pad;
uint8_t pad;
uint8_t reserved;
} __attribute__ ((__packed__));
@@ -24,39 +24,45 @@ int fastcgi_to_uwsgi(struct wsgi_request *wsgi_req, char *buf, size_t len) {
uint8_t octet;
uint32_t keylen, vallen;
for (j = 0; j < len; j++) {
octet = (uint8_t) buf[j];
if (octet > 127) {
if (j + 4 >= len) return -1;
octet = (uint8_t) buf[j];
if (octet > 127) {
if (j + 4 >= len)
return -1;
keylen = uwsgi_be32(&buf[j]) ^ 0x80000000;
j += 4;
j += 4;
}
else {
if (j+1 >= len) return -1;
if (j + 1 >= len)
return -1;
keylen = octet;
j++;
}
octet = (uint8_t) buf[j];
if (octet > 127) {
if (j + 4 >= len) return -1;
octet = (uint8_t) buf[j];
if (octet > 127) {
if (j + 4 >= len)
return -1;
vallen = uwsgi_be32(&buf[j]) ^ 0x80000000;
j += 4;
j += 4;
}
else {
if (j+1 >= len) return -1;
if (j + 1 >= len)
return -1;
vallen = octet;
j++;
}
if (j + (keylen + vallen) > len) {
if (j + (keylen + vallen) > len) {
return -1;
}
if (keylen > 0xffff || vallen > 0xffff) return -1;
if (keylen > 0xffff || vallen > 0xffff)
return -1;
uint16_t pktsize = proto_base_add_uwsgi_var(wsgi_req, buf + j, keylen, buf + j + keylen, vallen);
if (pktsize == 0) return -1;
wsgi_req->uh->pktsize += pktsize;
if (pktsize == 0)
return -1;
wsgi_req->uh->pktsize += pktsize;
// -1 here as the for() will increment j again
j += (keylen + vallen) - 1;
j += (keylen + vallen) - 1;
}
return 0;
@@ -66,7 +72,7 @@ int fastcgi_to_uwsgi(struct wsgi_request *wsgi_req, char *buf, size_t len) {
/*
each fastcgi packet is composed by a header and a body
the parser rebuild a whole packet until it find a 0 PARAMS or a STDIN one
the parser rebuild a whole packet until it finds a 0 STDIN
*/
@@ -78,38 +84,40 @@ int uwsgi_proto_fastcgi_parser(struct wsgi_request *wsgi_req) {
wsgi_req->proto_parser_buf_size = uwsgi.buffer_size;
}
ssize_t len = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
ssize_t len = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
if (len > 0) {
goto parse;
}
}
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
uwsgi_error("uwsgi_proto_fastcgi_parser()");
return -1;
}
// mute on 0 len...
if (wsgi_req->proto_parser_pos > 0) {
uwsgi_error("uwsgi_proto_fastcgi_parser()");
}
return -1;
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
uwsgi_error("uwsgi_proto_fastcgi_parser()");
return -1;
}
// mute on 0 len...
if (wsgi_req->proto_parser_pos > 0) {
uwsgi_error("uwsgi_proto_fastcgi_parser()");
}
return -1;
parse:
wsgi_req->proto_parser_pos += len;
// ok let's see what we need to do
for(;;) {
for (;;) {
if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) {
struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
uint16_t fcgi_len = uwsgi_be16((char *)&fr->cl1);
uint16_t fcgi_len = uwsgi_be16((char *) &fr->cl1);
uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad;
uint8_t fcgi_type = fr->type;
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
uint8_t *sid = (uint8_t *) & wsgi_req->stream_id;
sid[0] = fr->req0;
sid[1] = fr->req1;
// if STDIN, end of the loop
if (fcgi_type == 5) {
wsgi_req->uh->modifier1 = uwsgi.fastcgi_modifier1;
wsgi_req->uh->modifier2 = uwsgi.fastcgi_modifier2;
// does the request stream ended ?
if (fcgi_len == 0) wsgi_req->proto_parser_eof = 1;
return UWSGI_OK;
}
// if we have a full packet, parse it and reset the memory
@@ -122,12 +130,6 @@ parse:
}
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
wsgi_req->proto_parser_pos -= fcgi_all_len;
// end of PARAMS
if (fcgi_type == 4 && fcgi_len == 0) {
wsgi_req->uh->modifier1 = uwsgi.fastcgi_modifier1;
wsgi_req->uh->modifier2 = uwsgi.fastcgi_modifier2;
return UWSGI_OK;
}
}
else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) {
char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos));
@@ -152,33 +154,41 @@ parse:
}
ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request * wsgi_req, char *buf, size_t len) {
int has_read = 0;
if (wsgi_req->proto_parser_remains > 0) {
size_t remains = UMIN(wsgi_req->proto_parser_remains, len);
memcpy(buf, wsgi_req->proto_parser_remains_buf, remains);
wsgi_req->proto_parser_remains -= remains;
wsgi_req->proto_parser_remains_buf += remains;
size_t remains = UMIN(wsgi_req->proto_parser_remains, len);
memcpy(buf, wsgi_req->proto_parser_remains_buf, remains);
wsgi_req->proto_parser_remains -= remains;
wsgi_req->proto_parser_remains_buf += remains;
// we consumed all of the body, we can safely move the memory
if (wsgi_req->proto_parser_remains == 0 && wsgi_req->proto_parser_move) {
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_move, wsgi_req->proto_parser_pos);
if (wsgi_req->proto_parser_remains == 0 && wsgi_req->proto_parser_move) {
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_move, wsgi_req->proto_parser_pos);
wsgi_req->proto_parser_move = 0;
}
return remains;
}
}
return remains;
}
// if we already have seen eof, return 0
if (wsgi_req->proto_parser_eof) return 0;
ssize_t rlen;
for(;;) {
if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) {
struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
uint16_t fcgi_len = uwsgi_be16((char *)&fr->cl1);
for (;;) {
if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) {
struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
uint16_t fcgi_len = uwsgi_be16((char *) &fr->cl1);
uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad;
uint8_t fcgi_type = fr->type;
// if we have a full packet, parse it and reset the memory
if (wsgi_req->proto_parser_pos >= fcgi_all_len) {
// STDIN ? (ignore other types)
if (fcgi_type == 5) {
uint8_t fcgi_type = fr->type;
// if we have a full packet, parse it and reset the memory
if (wsgi_req->proto_parser_pos >= fcgi_all_len) {
// STDIN ? (ignore other types)
if (fcgi_type == 5) {
// EOF ?
if (fcgi_len == 0) {
wsgi_req->proto_parser_eof = 1;
return 0;
}
// copy data to the buf
size_t remains = UMIN(fcgi_len, len);
memcpy(buf, wsgi_req->proto_parser_buf + sizeof(struct fcgi_record), remains);
@@ -187,45 +197,46 @@ ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request *wsgi_req, char *buf,
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf + sizeof(struct fcgi_record) + remains;
// we consumed all of the body, we can safely move the memory
if (wsgi_req->proto_parser_remains == 0) {
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
}
else {
// postpone memory move
wsgi_req->proto_parser_move = fcgi_all_len;
}
wsgi_req->proto_parser_pos -= fcgi_all_len;
wsgi_req->proto_parser_pos -= fcgi_all_len;
return remains;
}
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
wsgi_req->proto_parser_pos -= fcgi_all_len;
}
else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) {
char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos));
if (!tmp_buf) {
uwsgi_error("uwsgi_proto_fastcgi_read_body()/realloc()");
return -1;
}
wsgi_req->proto_parser_buf = tmp_buf;
wsgi_req->proto_parser_buf_size += fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
}
if (!has_read) goto gather;
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
wsgi_req->proto_parser_pos -= fcgi_all_len;
}
else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) {
char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos));
if (!tmp_buf) {
uwsgi_error("uwsgi_proto_fastcgi_read_body()/realloc()");
return -1;
}
wsgi_req->proto_parser_buf = tmp_buf;
wsgi_req->proto_parser_buf_size += fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
}
if (!has_read)
goto gather;
errno = EAGAIN;
return -1;
}
else {
}
else {
gather:
rlen = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
rlen = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
if (rlen > 0) {
has_read = 1;
wsgi_req->proto_parser_pos += rlen;
continue;
}
return rlen;
}
}
}
}
return -1;
}
// write a STDOUT packet
@@ -233,12 +244,12 @@ int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t l
// fastcgi packets are limited to 64k
if (wsgi_req->proto_parser_status == 0) {
uint16_t fcgi_len = UMIN(len-wsgi_req->write_pos, 0xffff);
uint16_t fcgi_len = UMIN(len - wsgi_req->write_pos, 0xffff);
wsgi_req->proto_parser_status = fcgi_len;
struct fcgi_record fr;
fr.version = 1;
fr.type = 6;
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
uint8_t *sid = (uint8_t *) & wsgi_req->stream_id;
fr.req1 = sid[1];
fr.req0 = sid[0];
fr.pad = 0;
@@ -250,25 +261,42 @@ int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t l
}
}
ssize_t wlen = write(wsgi_req->fd, buf+wsgi_req->write_pos, wsgi_req->proto_parser_status);
if (wlen > 0) {
wsgi_req->write_pos += wlen;
ssize_t wlen = write(wsgi_req->fd, buf + wsgi_req->write_pos, wsgi_req->proto_parser_status);
if (wlen > 0) {
wsgi_req->write_pos += wlen;
wsgi_req->proto_parser_status -= wlen;
if (wsgi_req->write_pos == len) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
if (wlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
}
return -1;
if (wsgi_req->write_pos == len) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
if (wlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
}
return -1;
}
void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
// before sending the END_REQUEST and closing the connection we need to check for EOF
if (!wsgi_req->proto_parser_eof) {
// we use a custom tiny buffer, all the data will be discarded...
char buf[4096];
for(;;) {
ssize_t rlen = uwsgi_proto_fastcgi_read_body(wsgi_req, buf, 4096);
if (rlen < 0) {
if (uwsgi_is_again()) {
int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout);
if (ret <= 0) goto end;
continue;
}
goto end;
}
if (rlen == 0) break;
}
}
// special case here, we run in void context, so we need to wait directly here
char end_request[24];
memcpy(end_request, FCGI_END_REQUEST, 24);
@@ -279,69 +307,70 @@ void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
end_request[10] = sid[1];
end_request[11] = sid[0];
(void) uwsgi_write_true_nb(wsgi_req->fd, end_request, 24, uwsgi.socket_timeout);
end:
uwsgi_proto_base_close(wsgi_req);
}
int uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
// fastcgi packets are limited to 64k
if (wsgi_req->proto_parser_status == 0) {
uint16_t fcgi_len = (uint16_t) UMIN(len-wsgi_req->write_pos, 0xffff);
wsgi_req->proto_parser_status = fcgi_len;
struct fcgi_record fr;
fr.version = 1;
fr.type = 6;
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
fr.req1 = sid[1];
fr.req0 = sid[0];
fr.pad = 0;
fr.reserved = 0;
fr.cl0 = (uint8_t) (fcgi_len & 0xff);
fr.cl1 = (uint8_t) ((fcgi_len >> 8) & 0xff);
if (uwsgi_write_true_nb(wsgi_req->fd, (char *) &fr, sizeof(struct fcgi_record), uwsgi.socket_timeout)) {
return -1;
}
}
if (wsgi_req->proto_parser_status == 0) {
uint16_t fcgi_len = (uint16_t) UMIN(len - wsgi_req->write_pos, 0xffff);
wsgi_req->proto_parser_status = fcgi_len;
struct fcgi_record fr;
fr.version = 1;
fr.type = 6;
uint8_t *sid = (uint8_t *) & wsgi_req->stream_id;
fr.req1 = sid[1];
fr.req0 = sid[0];
fr.pad = 0;
fr.reserved = 0;
fr.cl0 = (uint8_t) (fcgi_len & 0xff);
fr.cl1 = (uint8_t) ((fcgi_len >> 8) & 0xff);
if (uwsgi_write_true_nb(wsgi_req->fd, (char *) &fr, sizeof(struct fcgi_record), uwsgi.socket_timeout)) {
return -1;
}
}
ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos+wsgi_req->write_pos, wsgi_req->proto_parser_status);
if (wlen > 0) {
wsgi_req->write_pos += wlen;
ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos + wsgi_req->write_pos, wsgi_req->proto_parser_status);
if (wlen > 0) {
wsgi_req->write_pos += wlen;
wsgi_req->proto_parser_status -= wlen;
if (wsgi_req->write_pos == len) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
if (wlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
}
return -1;
if (wsgi_req->write_pos == len) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
if (wlen < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
}
return -1;
}
void uwsgi_proto_fastcgi_setup(struct uwsgi_socket *uwsgi_sock) {
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
}
void uwsgi_proto_fastcgi_nph_setup(struct uwsgi_socket *uwsgi_sock) {
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
}
+2 -2
View File
@@ -79,7 +79,7 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, s
return 2 + keylen + 2 + hvlen;
}
static char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len) {
char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len) {
// check for PROXY header
if (watermark - ptr > 6) {
if (memcmp(ptr, "PROXY ", 6)) return ptr;
@@ -423,7 +423,7 @@ static int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
}
// mute on 0 len...
if (wsgi_req->proto_parser_pos > 0) {
uwsgi_log("uwsgi_proto_http_parser() -> client closed connection");
uwsgi_log("uwsgi_proto_http_parser() -> client closed connection\n");
}
return -1;
+1
View File
@@ -9,4 +9,5 @@ cache2 = name=items_17,blocks=17,items=17,bitmap=1,blocksize=1
cache2 = name=items_4_10,blocks=5,items=5,bitmap=1,blocksize=10
cache2 = name=items_1_100000,blocks=1000,items=2,bitmap=1,blocksize=100
cache2 = name=items_non_bitmap,items=2,blocksize=20
cache2 = name=items_lru,items=3,blocksize=20,purge_lru=1
pyrun = t/cachebitmap.py
+11 -1
View File
@@ -5,7 +5,7 @@ import string
class BitmapTest(unittest.TestCase):
__caches__ = ['items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap']
__caches__ = ['items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap', 'items_lru']
def setUp(self):
for cache in self.__caches__:
@@ -103,4 +103,14 @@ class BitmapTest(unittest.TestCase):
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 21, 0, 'items_non_bitmap'))
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
def test_lru(self):
self.assertTrue(uwsgi.cache_set('KEY1', 'X' * 20, 0, 'items_lru'))
self.assertTrue(uwsgi.cache_set('KEY2', 'X' * 20, 0, 'items_lru'))
self.assertTrue(uwsgi.cache_set('KEY3', 'Y' * 20, 0, 'items_lru'))
self.assertIsNone(uwsgi.cache_get('KEY1', 'items_lru'))
second_item = uwsgi.cache_get('KEY3', 'items_lru')
for i in range(4,100):
self.assertTrue(uwsgi.cache_set('KEY%d' % i, 'Y' * 20, 0, 'items_lru'))
self.assertIsNone(uwsgi.cache_get('KEY%d' % (i-2), 'items_lru'))
unittest.main()
+14
View File
@@ -0,0 +1,14 @@
function hello(wsapi_env)
local headers = { ["Content-type"] = "text/html", ["set-cookie"] = {"foo=bar", "bar=baz"} }
local function hello_text()
coroutine.yield("<html><body>")
coroutine.yield("<p>Hello Wsapi!</p>")
coroutine.yield("<p>PATH_INFO: " .. wsapi_env.PATH_INFO .. "</p>")
coroutine.yield("<p>SCRIPT_NAME: " .. wsapi_env.SCRIPT_NAME .. "</p>")
coroutine.yield("<p>QUERY_STRING: " .. wsapi_env.QUERY_STRING .. "</p>")
coroutine.yield("</body></html>")
end
return 200, headers, coroutine.wrap(hello_text)
end
return hello
+58
View File
@@ -0,0 +1,58 @@
use v5.10.0;
use strict;
use warnings;
use Time::HiRes qw(sleep);
use autodie qw(:all);
my $psgi = $ARGV[0] || 't/perl/test_hello.psgi';
for my $use_thunder_lock (0,1) {
for my $cpu_multiplier (1,2,4,8,16,32,64) {
my $procs = 16 * $cpu_multiplier;
my $desc = sprintf "%3d procs %2s/TL", $procs, ($use_thunder_lock ? "w" : "wo");
my $tl_cl = $use_thunder_lock ? "--thunder-lock --lock-engine ipcsem --ftok $psgi" : "";
#say STDERR "Now testing $desc";
system q[for p in $(ps auxf|grep uwsgi.*--disable-logging|grep -v grep|awk '{print $2}'); do kill $p; done];
system qq[./uwsgi --http 127.0.0.1:8080 --processes $procs --psgi $psgi --disable-logging $tl_cl >/dev/null 2>&1 &];
sleep 0.5;
chomp(my $ab = qx[http_proxy= ab -n 10000 -c 32 http://localhost:8080/ 2>&1]);
my ($seconds) = $ab =~ m[Time taken for tests:\s+([0-9.]+) seconds];
say STDERR "$seconds\t$desc";
system q[for p in $(ps auxf|grep uwsgi.*--disable-logging|grep -v grep|awk '{print $2}'); do kill $p; done];
sleep 0.5;
}
}
__END__
$ perl t/perl/test_benchmark.pl t/perl/test_sleepy.psgi
7.128 16 procs wo/TL
3.547 32 procs wo/TL
2.038 64 procs wo/TL
2.880 128 procs wo/TL
4.578 256 procs wo/TL
8.199 512 procs wo/TL
13.379 1024 procs wo/TL
7.123 16 procs w/TL
3.559 32 procs w/TL
2.036 64 procs w/TL
1.972 128 procs w/TL
2.026 256 procs w/TL
2.172 512 procs w/TL
2.412 1024 procs w/TL
$ perl t/perl/test_benchmark.pl t/perl/test_hello.psgi
1.392 16 procs wo/TL
1.743 32 procs wo/TL
2.374 64 procs wo/TL
3.530 128 procs wo/TL
4.984 256 procs wo/TL
8.258 512 procs wo/TL
9.343 1024 procs wo/TL
1.134 16 procs w/TL
1.284 32 procs w/TL
1.152 64 procs w/TL
1.084 128 procs w/TL
1.286 256 procs w/TL
1.559 512 procs w/TL
1.537 1024 procs w/TL
+8
View File
@@ -0,0 +1,8 @@
use strict;
use warnings;
sub {
my $env = shift;
return [200, [], [ "Hello, world!" ]];
}
+20
View File
@@ -0,0 +1,20 @@
use strict;
use warnings;
use Time::HiRes qw(usleep);
sub {
my $env = shift;
die "PANIC: We are expecting to support psgix.cleanup" unless $env->{'psgix.cleanup'};
my $msleep = 2 * 1000 + int rand 7 * 1000; # 2..10ms
my $csleep = 2 * 1000 + int rand 7 * 1000; # 2..10ms
push @{$env->{'psgix.cleanup.handlers'}} => sub { usleep($csleep) };
usleep($msleep);
return [
200,
[],
[ "Responding. Slept $msleep us in the main phase, sleeping $csleep us in the cleanup phase" ],
];
}
+1 -1
View File
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = 'uwsgi'
s.license = 'GPL-2'
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
s.date = '2014-04-22'
s.date = '2014-09-05'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+49 -1
View File
@@ -6,6 +6,8 @@
extern "C" {
#endif
#define UWSGI_PLUGIN_API 1
#define UMAX16 65536
#define UMAX8 256
@@ -604,6 +606,8 @@ struct uwsgi_daemon {
int ns_pid;
int throttle;
char *chdir;
};
struct uwsgi_logger {
@@ -830,6 +834,8 @@ struct uwsgi_cache {
int purge_lru;
uint64_t lru_head;
uint64_t lru_tail;
int store_delete;
};
struct uwsgi_option {
@@ -897,6 +903,7 @@ struct uwsgi_opt {
#define UWSGI_EXCEPTION_CODE 5
#define UWSGI_QUIET_CODE 29
#define UWSGI_BRUTAL_RELOAD_CODE 31
#define UWSGI_GO_CHEAP_CODE 15
#define MAX_VARS 64
@@ -995,6 +1002,7 @@ struct uwsgi_protocol {
};
struct uwsgi_server;
struct uwsgi_instance;
struct uwsgi_plugin {
@@ -1053,6 +1061,9 @@ struct uwsgi_plugin {
struct uwsgi_buffer* (*exception_msg)(struct wsgi_request *);
struct uwsgi_buffer* (*exception_repr)(struct wsgi_request *);
void (*exception_log)(struct wsgi_request *);
void (*vassal)(struct uwsgi_instance *);
void (*vassal_before_exec)(struct uwsgi_instance *);
};
#ifdef UWSGI_PCRE
@@ -1566,6 +1577,11 @@ struct wsgi_request {
#ifdef UWSGI_SSL
SSL *ssl;
#endif
// do not update avg_rt after request
int do_not_account_avg_rt;
// used for protocol parsers requiring EOF signaling
int proto_parser_eof;
};
@@ -2706,6 +2722,20 @@ struct uwsgi_server {
char *notify_socket;
int notify_socket_fd;
char *subscription_notify_socket;
//uWSGI 2.0.5
int mule_reload_mercy;
int alarm_cheap;
int emperor_no_blacklist;
int metrics_no_cores;
int stats_no_cores;
int stats_no_metrics;
// uWSGI 2.0.7
int vassal_sos;
};
struct uwsgi_rpc {
@@ -2939,6 +2969,9 @@ struct uwsgi_mule {
time_t user_harakiri;
char name[0xff];
time_t cursed_at;
time_t no_mercy_at;
};
struct uwsgi_mule_farm {
@@ -2994,6 +3027,7 @@ void uwsgi_xml_config(char *, struct wsgi_request *, char *[]);
void uwsgi_500(struct wsgi_request *);
void uwsgi_403(struct wsgi_request *);
void uwsgi_404(struct wsgi_request *);
void uwsgi_405(struct wsgi_request *);
void uwsgi_redirect_to_slash(struct wsgi_request *);
void manage_snmp(int, uint8_t *, int, struct sockaddr_in *);
@@ -3006,6 +3040,7 @@ void spooler(struct uwsgi_spooler *);
pid_t spooler_start(struct uwsgi_spooler *);
void uwsgi_curse(int, int);
void uwsgi_curse_mule(int, int);
void uwsgi_destroy_processes(void);
void set_harakiri(int);
@@ -3769,8 +3804,12 @@ int uwsgi_logic_opt_if_reload(char *, char *);
int uwsgi_logic_opt_if_not_reload(char *, char *);
int uwsgi_logic_opt_if_plugin(char *, char *);
int uwsgi_logic_opt_if_not_plugin(char *, char *);
int uwsgi_logic_opt_if_hostname(char *, char *);
int uwsgi_logic_opt_if_not_hostname(char *, char *);
void uwsgi_opt_resolve(char *, char *, void *);
#ifdef UWSGI_CAP
void uwsgi_opt_set_cap(char *, char *, void *);
void uwsgi_opt_set_emperor_cap(char *, char *, void *);
@@ -4143,7 +4182,6 @@ char *uwsgi_elf_section(char *, char *, size_t *);
void uwsgi_alarm_log_check(char *, size_t);
void uwsgi_alarm_run(struct uwsgi_alarm_instance *, char *, size_t);
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *, char *, size_t);
void uwsgi_register_alarm(char *, void (*)(struct uwsgi_alarm_instance *), void (*)(struct uwsgi_alarm_instance *, char *, size_t));
void uwsgi_register_embedded_alarms();
void uwsgi_alarms_init();
@@ -4169,6 +4207,7 @@ struct uwsgi_thread {
void (*func) (struct uwsgi_thread *);
};
struct uwsgi_thread *uwsgi_thread_new(void (*)(struct uwsgi_thread *));
struct uwsgi_thread *uwsgi_thread_new_with_data(void (*)(struct uwsgi_thread *), void *data);
struct uwsgi_offload_request {
// the request socket
@@ -4421,6 +4460,7 @@ int uwsgi_exceptions_catch(struct wsgi_request *);
uint64_t uwsgi_worker_exceptions(int);
struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *, int (*)(struct uwsgi_exception_handler_instance *, char *, size_t));
char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len);
void uwsgi_async_queue_is_full(time_t);
char *uwsgi_get_header(struct wsgi_request *, char *, uint16_t, uint16_t *);
@@ -4561,6 +4601,7 @@ void uwsgi_master_fifo_prepare();
int uwsgi_master_fifo();
int uwsgi_master_fifo_manage(int);
void uwsgi_log_do_rotate(char *, char *, off_t, int);
void uwsgi_log_rotate();
void uwsgi_log_reopen();
void uwsgi_reload_workers();
@@ -4663,6 +4704,9 @@ struct uwsgi_metric {
struct uwsgi_metric_threshold *thresholds;
struct uwsgi_metric *next;
// allow to reset metrics after each push
uint8_t reset_after_push;
};
struct uwsgi_metric_child {
@@ -4680,6 +4724,8 @@ int uwsgi_metric_mul(char *, char *, int64_t);
int uwsgi_metric_div(char *, char *, int64_t);
int64_t uwsgi_metric_get(char *, char *);
int64_t uwsgi_metric_getn(char *, size_t, char *, size_t);
int uwsgi_metric_set_max(char *, char *, int64_t);
int uwsgi_metric_set_min(char *, char *, int64_t);
struct uwsgi_metric_collector *uwsgi_register_metric_collector(char *, int64_t (*)(struct uwsgi_metric *));
struct uwsgi_metric *uwsgi_register_metric(char *, char *, uint8_t, char *, void *, uint32_t, void *);
@@ -4707,6 +4753,7 @@ void uwsgi_sharedareas_init();
struct uwsgi_sharedarea *uwsgi_sharedarea_init(int);
struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *, uint64_t);
struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int, uint64_t, off_t);
int64_t uwsgi_sharedarea_read(int, uint64_t, char *, uint64_t);
int uwsgi_sharedarea_write(int, uint64_t, char *, uint64_t);
@@ -4753,6 +4800,7 @@ mode_t uwsgi_mode_t(char *, int *);
int uwsgi_notify_socket_manage(int);
int uwsgi_notify_msg(char *, char *, size_t);
void vassal_sos();
#ifdef __cplusplus
}
+7 -2
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '2.0.4'
uwsgi_version = '2.0.7'
import os
import re
@@ -53,6 +53,11 @@ if CPUCOUNT < 1:
except:
CPUCOUNT = 1
# force single cpu in cygwin mode
if uwsgi_os.startswith('CYGWIN'):
CPUCOUNT=1
binary_list = []
started_at = time.time()
@@ -1058,7 +1063,7 @@ class uConf(object):
self.embed_config = None
if uwsgi_os in ('Linux','FreeBSD'):
if uwsgi_os not in ('Darwin',):
self.embed_config = os.environ.get('UWSGI_EMBED_CONFIG')
if not self.embed_config:
self.embed_config = self.get('embed_config')