Compare commits

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

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

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

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

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

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

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

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

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

We can retain the bugfix I added in 2.0.1-41-g3480c30 while having a
sensible stacktrace by overriding the file via the #line directive.
2014-03-15 13:10:30 +00:00
Roberto De Ioris 5f74e6d964 fixed stupid bug with python add_var 2014-03-15 12:51:15 +01:00
Roberto De Ioris ae87fdd0f7 added uwsgi.add_var 2014-03-15 12:47:59 +01:00
Roberto De Ioris 36c44c83af added disableheaders routing action 2014-03-15 12:04:01 +01:00
Roberto De Ioris 48e13bfc65 add a check for already initialized python vm 2014-03-15 08:48:07 +01:00
Unbit 16cd55637d added support for mongrel2 URL_SCHEME #562 2014-03-14 11:48:36 +01:00
Unbit 39cf2887c4 added SIGURG to the Emperor 2014-03-14 11:28:53 +01:00
Unbit 671bf8a258 try to avoid vassal pipe to have invalid fd numbers 2014-03-14 11:21:20 +01:00
Unbit 89a8ceea81 allows building plugins from git repositories 2014-03-13 14:11:12 +01:00
Roberto De Ioris 6699f4046e better error reporting on websockets errors 2014-03-13 07:35:18 +01:00
Roberto De Ioris 88474b3d96 do not wait for a whole Emperor cycle before checking for each waitpid 2014-03-13 07:03:50 +01:00
unbit 32b6463d06 Merge pull request #559 from hynek/master
Set ECDHE curve independently from DHE parameters
2014-03-13 06:19:11 +01:00
Hynek Schlawack 63cc29a61d Set ECDHE curve independently from DHE parameters 2014-03-12 21:19:52 +01:00
Unbit d58f79eeab fixed #558 2014-03-11 16:18:32 +01:00
Unbit 7b24d2f5de allows vassals to request a config chunk from the emperor 2014-03-11 07:04:23 +01:00
Unbit a93db73d0c Merge branch 'master' of github.com:unbit/uwsgi 2014-03-10 14:52:35 +01:00
Unbit c118c75bfe beter management of failed emperor kills 2014-03-10 14:52:30 +01:00
Unbit 624631d443 fixed tuntap 2014-03-08 13:57:15 +01:00
Unbit b681eab385 fixed SIGWINCH in emperor and added emperor rescan master fifo command 2014-03-08 08:13:30 +01:00
Unbit 91dfe779ff fixed typo 2014-03-08 06:38:50 +01:00
Unbit 0ad50711c0 report key in corerouters 2014-03-08 06:36:38 +01:00
Unbit df6ed26479 more debug for tuntap 2014-03-08 06:24:45 +01:00
Unbit d08778b39c removed useless tuntap debug 2014-03-08 05:59:59 +01:00
Unbit 0c8c2932cf Merge branch 'master' of https://github.com/unbit/uwsgi 2014-03-08 05:44:05 +01:00
Unbit 131bd7da2f try to improve nb tuntap gateway 2014-03-08 05:43:54 +01:00
Unbit d247424442 more useful log alarm 2014-03-07 16:09:04 +01:00
Roberto De Ioris 332fab2150 hack for avoiding libmongoclient to crash on broken cursor 2014-03-07 07:31:42 +01:00
Roberto De Ioris 62d74951db support for git-based plugins 2014-03-05 08:28:17 +01:00
Roberto De Ioris 839638a0ad report socket name on invalid zeromq syntax 2014-03-04 06:38:42 +01:00
Roberto De Ioris 536ae8d013 fixed mongrel2 post_fork hook 2014-03-04 06:32:40 +01:00
Roberto De Ioris 367c4b9bab added on_demand sockets support to mongodb Emperor plugin 2014-03-04 06:08:16 +01:00
Roberto De Ioris 3965c01880 on __APPLE__ use LOG_NOTICE for syslog plugin 2014-03-04 05:44:18 +01:00
Unbit 7e4341a7cd force on demand unix socket to 666 2014-03-02 10:14:58 +01:00
Unbit 8c118c8f62 fixed (and improved) on demand emperor socket 2014-03-02 09:36:17 +01:00
Unbit 5d76b63fac fixed #555 2014-03-01 08:25:35 +01:00
88 changed files with 3557 additions and 1202 deletions
+1
View File
@@ -7,6 +7,7 @@
/uwsgi
/uwsgibuild.*
/core/config_py.c
/t/ring/target
+2
View File
@@ -26,3 +26,5 @@ Natanael Copa
Roberto Leandrini
Ryan Petrello
Danila Shtan <danila@shtan.ru>
Ævar Arnfjörð Bjarmason
Yu Zhao (getcwd)
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = python,asyncio,greenlet
inherit = base
+26 -27
View File
@@ -18,18 +18,18 @@ void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
if (msg[len-1] != '\n') {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s\n", len, msg);
uwsgi_log_verbose("ALARM: %.*s\n", len, msg);
}
}
else {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s", len, msg);
uwsgi_log_verbose("ALARM: %.*s", len, msg);
}
}
}
@@ -363,6 +363,19 @@ void uwsgi_alarm_thread_start() {
}
}
void uwsgi_alarm_trigger_uai(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
}
#ifdef UWSGI_PCRE
// check if a log should raise an alarm
void uwsgi_alarm_log_check(char *msg, size_t len) {
@@ -372,7 +385,14 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
while (ual) {
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
if (!ual->negate) {
uwsgi_alarm_log_run(ual, msg, len);
struct uwsgi_alarm_ll *uall = ual->alarms;
while (uall) {
if (uwsgi.alarm_cheap)
uwsgi_alarm_trigger_uai(uall->alarm, msg, len);
else
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
else {
break;
@@ -397,18 +417,6 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
uai->last_msg_size = len;
}
#ifdef UWSGI_PCRE
// call the alarms mapped to a log line
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
struct uwsgi_alarm_ll *uall = ual->alarms;
while (uall) {
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
#endif
// this is the api function workers,mules and whatever you want can call from code
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
if (!uwsgi.alarm_thread) return;
@@ -416,16 +424,7 @@ void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
if (!uai) return;
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
uwsgi_alarm_trigger_uai(uai, msg, len);
}
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
+141 -33
View File
@@ -472,6 +472,38 @@ uint32_t uwsgi_cache_exists2(struct uwsgi_cache *uc, char *key, uint16_t keylen)
return uwsgi_cache_get_index(uc, key, keylen);
}
static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *next, *curr = cache_item(index);
if (curr->lru_next) {
next = cache_item(curr->lru_next);
next->lru_prev = curr->lru_prev;
} else
uc->lru_tail = curr->lru_prev;
if (curr->lru_prev) {
prev = cache_item(curr->lru_prev);
prev->lru_next = curr->lru_next;
} else
uc->lru_head = curr->lru_next;
}
static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *curr = cache_item(index);
if (uc->lru_tail) {
prev = cache_item(uc->lru_tail);
prev->lru_next = index;
} else
uc->lru_head = index;
curr->lru_next = 0;
curr->lru_prev = uc->lru_tail;
uc->lru_tail = index;
}
char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
@@ -481,6 +513,10 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
return NULL;
*valsize = uci->valsize;
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
}
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
@@ -520,6 +556,10 @@ char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
*valsize = uci->valsize;
if (expires)
*expires = uci->expires;
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
}
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
@@ -588,6 +628,10 @@ int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_
// reset hashtable entry
uc->hashtable[uci->hash % uc->hashsize] = 0;
}
if (uc->purge_lru)
lru_remove_item(uc, index);
uc->n_items--;
}
@@ -666,9 +710,17 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) {
if (!uc->unused_blocks_stack_ptr) {
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++;
goto end;
if (uc->purge_lru && uc->lru_head)
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
if (!uc->unused_blocks_stack_ptr)
goto end;
}
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
@@ -681,7 +733,8 @@ 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) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
if (!uc->ignore_full)
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
uc->unused_blocks_stack_ptr++;
goto end;
@@ -696,9 +749,13 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
}
}
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
if (uc->purge_lru)
lru_add_item(uc, index);
else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!uc->next_scan || uc->next_scan > expires)
uc->next_scan = expires;
}
uci->expires = expires;
uci->hash = uc->hash->func(key, keylen);
@@ -763,9 +820,16 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
}
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
uci = cache_item(index);
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
} else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!uc->next_scan || uc->next_scan > expires)
uc->next_scan = expires;
}
uci->expires = expires;
}
if (uc->blocks_bitmap) {
@@ -773,7 +837,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uint64_t old_first_block = uci->first_block;
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
if (uci->first_block == 0xffffffffffffffffLLU) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
if (!uc->ignore_full)
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
uci->first_block = old_first_block;
goto end;
@@ -983,39 +1048,66 @@ void *cache_udp_server_loop(void *ucache) {
return NULL;
}
static uint64_t cache_sweeper_free_items(struct uwsgi_cache *uc) {
uint64_t i;
uint64_t freed_items = 0;
if (uc->no_expire || uc->purge_lru)
return 0;
uwsgi_rlock(uc->lock);
if (!uc->next_scan || uc->next_scan > (uint64_t)uwsgi.current_time) {
uwsgi_rwunlock(uc->lock);
return 0;
}
uwsgi_rwunlock(uc->lock);
// skip the first slot
for (i = 1; i < uc->max_items; i++) {
struct uwsgi_cache_item *uci = cache_item(i);
uwsgi_wlock(uc->lock);
// we reset next scan time first, then we find the least
// expiration time from those that are NOT expired yet.
if (i == 1)
uc->next_scan = 0;
if (uci->expires) {
if (uci->expires <= (uint64_t)uwsgi.current_time) {
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
freed_items++;
} else if (!uc->next_scan || uc->next_scan > uci->expires) {
uc->next_scan = uci->expires;
}
}
uwsgi_rwunlock(uc->lock);
}
return freed_items;
}
static void *cache_sweeper_loop(void *ucache) {
uint64_t i;
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
struct uwsgi_cache *uc = (struct uwsgi_cache *) ucache;
if (!uwsgi.cache_expire_freq)
uwsgi.cache_expire_freq = 3;
// remove expired cache items TODO use rb_tree timeouts
for (;;) {
struct uwsgi_cache *uc;
for (uc = (struct uwsgi_cache *)ucache; uc; uc = uc->next) {
uint64_t freed_items = cache_sweeper_free_items(uc);
if (uwsgi.cache_report_freed_items && freed_items)
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long)freed_items, uc->name);
}
sleep(uwsgi.cache_expire_freq);
uint64_t freed_items = 0;
// skip the first slot
for (i = 1; i < uc->max_items; i++) {
uwsgi_wlock(uc->lock);
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->expires) {
if (uci->expires < (uint64_t) uwsgi.current_time) {
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
freed_items++;
}
}
uwsgi_rwunlock(uc->lock);
}
if (uwsgi.cache_report_freed_items && freed_items > 0) {
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long) freed_items, uc->name);
}
};
}
return NULL;
}
@@ -1035,16 +1127,21 @@ void uwsgi_cache_sync_all() {
void uwsgi_cache_start_sweepers() {
struct uwsgi_cache *uc = uwsgi.caches;
if (uwsgi.cache_no_expire)
return;
while(uc) {
pthread_t cache_sweeper;
if (!uwsgi.cache_no_expire && !uc->no_expire) {
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, (void *) uc)) {
if (!uc->no_expire && !uc->purge_lru) {
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) {
uwsgi_error("pthread_create()");
uwsgi_log("unable to run the sweeper for cache \"%s\" !!!\n", uc->name);
uwsgi_log("unable to run the sweeper!!!\n");
}
else {
uwsgi_log("sweeper thread enabled for cache \"%s\"\n", uc->name);
uwsgi_log("sweeper thread enabled\n");
}
break;
}
uc = uc->next;
}
@@ -1121,6 +1218,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_bitmap = NULL;
char *c_use_last_modified = NULL;
char *c_math_initial = NULL;
char *c_ignore_full = NULL;
char *c_purge_lru = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"name", &c_name,
@@ -1148,6 +1247,9 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"bitmap", &c_bitmap,
"lastmod", &c_use_last_modified,
"math_initial", &c_math_initial,
"ignore_full", &c_ignore_full,
"purge_lru", &c_purge_lru,
"lru", &c_purge_lru,
NULL)) {
uwsgi_log("unable to parse cache definition\n");
exit(1);
@@ -1195,6 +1297,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
uc->max_item_size = uc->blocksize * uc->blocks;
}
if (c_use_last_modified) uc->use_last_modified = 1;
if (c_ignore_full) uc->ignore_full = 1;
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
@@ -1229,6 +1332,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
}
}
if (c_purge_lru)
uc->purge_lru = 1;
}
uwsgi_cache_init(uc);
@@ -1484,7 +1589,10 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
// we have a local cache !!!
if (uc) {
uwsgi_rlock(uc->lock);
if (uc->purge_lru)
uwsgi_wlock(uc->lock);
else
uwsgi_rlock(uc->lock);
char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires);
if (!value) {
uwsgi_rwunlock(uc->lock);
+16
View File
@@ -816,3 +816,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);
}
+811 -585
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -48,6 +48,14 @@ static void subscriptions_blocker() {
}
}
static void emperor_rescan() {
if (uwsgi.emperor_pid > 0) {
if (kill(uwsgi.emperor_pid, SIGWINCH)) {
uwsgi_error("emperor_rescan()/kill()");
}
}
}
/*
this is called as soon as possibile allowing plugins (or hooks) to override it
@@ -74,6 +82,7 @@ void uwsgi_master_fifo_prepare() {
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
uwsgi_fifo_table['E'] = emperor_rescan;
uwsgi_fifo_table['f'] = uwsgi_refork_master;
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
+73
View File
@@ -485,6 +485,60 @@ static int uwsgi_hook_callret(char *arg) {
return func();
}
static int uwsgi_hook_rpc(char *arg) {
int ret = -1;
size_t i, argc = 0;
char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
if (!argc) goto end;
if (argc > 256) goto destroy;
char *argv[256];
uint16_t argvs[256];
char *node = NULL;
char *func = rargv[0];
char *at = strchr(func, '@');
if (at) {
*at = 0;
node = at + 1;
}
for(i=0;i<(argc-1);i++) {
size_t a_len = strlen(rargv[i+1]);
if (a_len > 0xffff) goto destroy;
argv[i] = rargv[i+1] ;
argvs[i] = a_len;
}
uint64_t size = 0;
// response must be always freed
char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size);
if (response) {
if (at) *at = '@';
uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response);
free(response);
ret = 0;
}
destroy:
for(i=0;i<argc;i++) {
free(rargv[i]);
}
end:
free(rargv);
return ret;
}
static int uwsgi_hook_retryrpc(char *arg) {
for(;;) {
int ret = uwsgi_hook_rpc(arg);
if (!ret) break;
sleep(2);
}
return 0;
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
@@ -523,6 +577,9 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
@@ -561,6 +618,22 @@ void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
int ret = uh->func(colon+1);
if (fatal && ret != 0) {
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
if (uwsgi.master_process) {
if (uwsgi.workers) {
if (uwsgi.workers[0].pid == getpid()) {
kill_them_all(0);
return;
}
else {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("uwsgi_hooks_run()/kill()");
exit(1);
}
return;
}
}
}
exit(1);
}
}
+4 -3
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 */
@@ -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);
+12 -6
View File
@@ -477,13 +477,19 @@ void uwsgi_check_logrotate(void) {
int need_rotation = 0;
int need_reopen = 0;
off_t logsize;
if (uwsgi.log_master) {
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
}
else {
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
logsize = lseek(2, 0, SEEK_CUR);
}
if (logsize < 0) {
uwsgi_error("uwsgi_check_logrotate()/lseek()");
return;
}
uwsgi.shared->logsize = logsize;
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
need_rotation = 1;
@@ -917,7 +923,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while (ul) {
if (!strcmp(ul->id, id)) {
if (ul->id && !strcmp(ul->id, id)) {
return ul;
}
ul = ul->next;
@@ -1839,7 +1845,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) {
size_t msg_len = len;
if (msg[len-1] == '\n') msg_len--;
char *e_json = uwsgi_malloc(msg_len * 2);
char *e_json = uwsgi_malloc((msg_len * 2)+1);
escape_json(msg, msg_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
@@ -1848,7 +1854,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
free(e_json);
}
else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) {
char *e_json = uwsgi_malloc(len * 2);
char *e_json = uwsgi_malloc((len * 2)+1);
escape_json(msg, len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
@@ -1869,7 +1875,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);
+19
View File
@@ -135,6 +135,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);
}
}
}
}
@@ -907,6 +916,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 +964,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 +984,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));
+5
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;
+26 -13
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);
@@ -412,9 +412,17 @@ void uwsgi_reload(char **argv) {
uwsgi_log("fork()'ing uWSGI...\n");
}
// ask for configuration (if needed)
if (uwsgi.has_emperor && uwsgi.emperor_fd_config > -1) {
char byte = 2;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("uwsgi_reload()/write()");
}
}
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
uwsgi_error("uwsgi_reload()/chdir()");
}
/* check fd table (a module can obviosly open some fd on initialization...) */
@@ -788,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);
@@ -905,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;
@@ -1137,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;
@@ -1198,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;
@@ -1276,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);
+27 -2
View File
@@ -321,6 +321,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
char *m_initial_value = NULL;
char *m_children = NULL;
char *m_alias = NULL;
char *m_reset_after_push = NULL;
if (!strchr(arg, '=')) {
m_name = uwsgi_str(arg);
@@ -340,6 +341,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
"arg3n", &m_arg3n,
"children", &m_children,
"alias", &m_alias,
"reset_after_push", &m_reset_after_push,
NULL)) {
uwsgi_log("invalid metric keyval syntax: %s\n", arg);
exit(1);
@@ -381,6 +383,10 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
struct uwsgi_metric* um = uwsgi_register_metric(m_name, m_oid, type, collector, NULL, freq, NULL);
um->initial_value = initial_value;
if (m_reset_after_push){
um->reset_after_push = 1;
}
if (m_children) {
char *p, *ctx = NULL;
uwsgi_foreach_token(m_children, ";", p, ctx) {
@@ -427,6 +433,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
if (m_initial_value) free(m_initial_value);
if (m_children) free(m_children);
if (m_alias) free(m_alias);
if (m_reset_after_push) free(m_reset_after_push);
return um;
}
@@ -613,7 +620,7 @@ struct uwsgi_metric *uwsgi_metric_find_by_asn(char *asn, size_t len) {
}\
if (!um) return -1;\
if (um->collector || um->type == UWSGI_METRIC_ALIAS) return -1;\
uwsgi_rlock(uwsgi.metrics_lock)
uwsgi_wlock(uwsgi.metrics_lock)
int uwsgi_metric_set(char *name, char *oid, int64_t value) {
um_op;
@@ -694,6 +701,22 @@ int64_t uwsgi_metric_getn(char *name, size_t nlen, char *oid, size_t olen) {
return ret;
}
int uwsgi_metric_set_max(char *name, char *oid, int64_t value) {
um_op;
if (value > *um->value)
*um->value = value;
uwsgi_rwunlock(uwsgi.metrics_lock);
return 0;
}
int uwsgi_metric_set_min(char *name, char *oid, int64_t value) {
um_op;
if ((value > um->initial_value || 0) && value < *um->value)
*um->value = value;
uwsgi_rwunlock(uwsgi.metrics_lock);
return 0;
}
#define uwsgi_metric_name(f, n) ret = snprintf(buf, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
#define uwsgi_metric_name2(f, n, n2) ret = snprintf(buf, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
@@ -768,9 +791,11 @@ void uwsgi_setup_metrics() {
struct uwsgi_metric *vsz = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].vsz_size, 0, NULL);
if (i > 0) uwsgi_metric_add_child(total_vsz, vsz);
// skip core metrics for core 0
// skip core metrics for worker 0
if (i == 0) continue;
if (uwsgi.metrics_no_cores) continue;
int j;
for(j=0;j<uwsgi.cores;j++) {
uwsgi_metric_name2("worker.%d.core.%d.requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.1", i, j);
+9 -6
View File
@@ -43,7 +43,7 @@ void uwsgi_mule(int id) {
#endif
signal(SIGALRM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGHUP, end_me);
signal(SIGINT, end_me);
signal(SIGTERM, end_me);
signal(SIGUSR1, SIG_IGN);
@@ -329,11 +329,13 @@ next:
}
}
int ret = poll(mulepoll, count + farms_count, timeout);
if (ret <= 0) {
uwsgi_error("poll");
int ret = -1;
retry:
ret = poll(mulepoll, count + farms_count, timeout);
if (ret < 0) {
uwsgi_error("uwsgi_mule_get_msg()/poll()");
}
else {
else if (ret > 0 ) {
if (mulepoll[0].revents & POLLIN) {
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
}
@@ -353,7 +355,7 @@ next:
if (interesting_fd > -1) {
len = read(interesting_fd, &uwsgi_signal, 1);
if (len <= 0) {
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) goto clear;
if (uwsgi_is_again()) goto retry;
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
@@ -380,6 +382,7 @@ next:
}
if (len < 0) {
if (uwsgi_is_again()) goto retry;
uwsgi_error("read()");
goto clear;
}
+8
View File
@@ -237,6 +237,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
void *events = event_queue_alloc(uwsgi.offload_threads_events);
for (;;) {
// TODO make timeout tunable
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events);
for (i = 0; i < nevents; i++) {
int interesting_fd = event_queue_interesting_fd(events, i);
@@ -456,6 +457,13 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
// write event (or just connected)
case 1:
if (fd == uor->fd) {
// maybe we want only a connection...
if (uor->ubuf->pos == 0) {
uor->status = 2;
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
return 0;
}
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
if (rlen > 0) {
uor->written += rlen;
+101 -1
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);
@@ -943,6 +976,20 @@ static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) {
return 0;
}
// disable headers
static int uwsgi_router_disableheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->headers_sent = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_disableheaders(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_disableheaders_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// signal route
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
@@ -1072,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);
@@ -1145,6 +1218,26 @@ static int uwsgi_router_setscheme(struct uwsgi_route *ur, char *arg) {
return 0;
}
// setmodifiers
static int uwsgi_router_setmodifier1_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->uh->modifier1 = ur->custom;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setmodifier1(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setmodifier1_func;
ur->custom = atoi(arg);
return 0;
}
static int uwsgi_router_setmodifier2_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->uh->modifier2 = ur->custom;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setmodifier2(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setmodifier2_func;
ur->custom = atoi(arg);
return 0;
}
// setuser route
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -1670,7 +1763,7 @@ static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
if (var_value) {
size_t mime_type_len = 0;
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
ret = uwsgi_get_mime_type(var_value, var_vallen, &mime_type_len);
if (ret) *vallen = mime_type_len;
}
return ret;
@@ -1727,6 +1820,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);
@@ -1737,6 +1832,7 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("remheader", uwsgi_router_remheader);
uwsgi_register_router("clearheaders", uwsgi_router_clearheaders);
uwsgi_register_router("resetheaders", uwsgi_router_clearheaders);
uwsgi_register_router("disableheaders", uwsgi_router_disableheaders);
uwsgi_register_router("signal", uwsgi_router_signal);
uwsgi_register_router("send", uwsgi_router_send);
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
@@ -1748,12 +1844,16 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("setscriptname", uwsgi_router_setscriptname);
uwsgi_register_router("setmethod", uwsgi_router_setmethod);
uwsgi_register_router("seturi", uwsgi_router_seturi);
uwsgi_register_router("setremoteaddr", uwsgi_router_setremoteaddr);
uwsgi_register_router("setpathinfo", uwsgi_router_setpathinfo);
uwsgi_register_router("setdocroot", uwsgi_router_setdocroot);
uwsgi_register_router("setscheme", uwsgi_router_setscheme);
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
uwsgi_register_router("alarm", uwsgi_router_alarm);
uwsgi_register_router("setmodifier1", uwsgi_router_setmodifier1);
uwsgi_register_router("setmodifier2", uwsgi_router_setmodifier2);
uwsgi_register_router("+", uwsgi_router_simple_math_plus);
uwsgi_register_router("-", uwsgi_router_simple_math_minus);
uwsgi_register_router("*", uwsgi_router_simple_math_multiply);
+5 -1
View File
@@ -104,8 +104,12 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
if (node == NULL || !strcmp(node, "")) {
// allocate the whole buffer
if (!uwsgi.rpc_table) {
uwsgi_log("local rpc subsystem is still not initialized !!!\n");
return NULL;
}
*len = uwsgi_rpc(func, argc, argv, argvs, &buffer);
if (*buffer)
if (buffer)
return buffer;
return NULL;
}
+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) {
+5
View File
@@ -190,6 +190,11 @@ static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, ui
}
if (!uwsgi_strncmp(key, key_len, "at", 2)) {
// at can be a float...
char *dot = memchr(value, '.', value_len);
if (dot) {
value_len = dot - value;
}
sr->at = uwsgi_str_num(value, value_len);
return;
}
+11 -7
View File
@@ -243,19 +243,23 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (dh) {
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_tmp_dh(ctx, dh);
DH_free(dh);
}
}
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
#ifdef NID_X9_62_prime256v1
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
#endif
#endif
#endif
}
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ecdh) {
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
}
#endif
#endif
#endif
if (crt_need_free) free(crt);
+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;
}
+2
View File
@@ -427,6 +427,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
return NULL;
}
// eventually the packet could be upgraded to sni...
uwsgi_subscription_sni_check(current_slot, usr);
#endif
// remove death mark and update cores and load
node->death_mark = 0;
+15 -5
View File
@@ -1051,10 +1051,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) {
@@ -3155,6 +3156,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 +3757,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 +3774,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 +3794,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;
+48 -5
View File
@@ -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},
@@ -219,6 +221,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
@@ -243,6 +246,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 +564,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 +575,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 +679,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},
@@ -1247,6 +1255,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 +1281,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 +1327,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 +1379,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() {
@@ -1555,21 +1584,25 @@ next:
}
}
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 +2231,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
// setup master logging
if (uwsgi.log_master && !uwsgi.daemonize2)
if (uwsgi.log_master && !uwsgi.daemonize2 && uwsgi.logfile)
uwsgi_setup_log_master();
// setup offload engines
@@ -2480,7 +2513,11 @@ int uwsgi_start(void *v_argv) {
if (uwsgi.logto2) {
if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
int setup_log = 0;
if (!uwsgi.logfile) setup_log = 1; // logto() will replace uwsgi.logfile and we need to check it later
logto(uwsgi.logto2);
if (setup_log)
uwsgi_setup_log_master();
}
}
@@ -3663,6 +3700,13 @@ void uwsgi_init_all_apps() {
if (uwsgi.need_app) {
if (!uwsgi.lazy)
uwsgi_log("*** no app loaded. GAME OVER ***\n");
if (uwsgi.lazy_apps) {
if (uwsgi.master_process) {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("kill()");
}
}
}
exit(UWSGI_FAILED_APP_CODE);
}
else {
@@ -4193,8 +4237,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) {
+9 -7
View File
@@ -1,4 +1,4 @@
#include "uwsgi.h"
#include <uwsgi.h>
/*
@@ -10,6 +10,8 @@
extern struct uwsgi_server uwsgi;
#define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr
static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf;
if (!ub) {
@@ -61,7 +63,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
// pong not received ?
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance);
return -1;
}
return 0;
@@ -189,7 +191,7 @@ static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb)
}
goto wait;
}
uwsgi_error("uwsgi_websockets_recv_pkt()");
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
return -1;
}
@@ -201,7 +203,7 @@ wait:
if (rlen <= 0) return -1;
}
if (ret < 0) {
uwsgi_error("uwsgi_websockets_recv_pkt()");
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
return -1;
}
// send unsolicited pong
@@ -254,11 +256,11 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
}
else {
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
return NULL;
}
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
return NULL;
}
wsgi_req->websocket_phase = 2;
@@ -312,7 +314,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
break;
// oops
default:
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
return NULL;
}
}
+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;
+378
View File
@@ -0,0 +1,378 @@
#include "../python/uwsgi_python.h"
/*
python >= 3.4 asyncio (PEP 3156) loop engine
EXPERIMENTAL !!!
Author: Roberto De Ioris
*/
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
static struct uwsgi_asyncio {
PyObject *mod;
PyObject *loop;
PyObject *request;
PyObject *hook_fd;
PyObject *hook_timeout;
PyObject *hook_fix;
} uasyncio;
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
static void uwsgi_opt_setup_asyncio(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.socket_timeout < 30) {
uwsgi.socket_timeout = 30;
}
// set loop engine
uwsgi.loop = "asyncio";
}
static struct uwsgi_option asyncio_options[] = {
{"asyncio", required_argument, 0, "a shortcut enabling asyncio loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_asyncio, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
static void gil_asyncio_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
static void gil_asyncio_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static int uwsgi_asyncio_wait_read_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
goto error;
}
// back to loop
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
// back from loop
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static int uwsgi_asyncio_wait_write_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (PyObject_CallMethod(uasyncio.loop, "add_writer", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
goto error;
}
// back to loop
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
// back from loop
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
int timed_out = 0;
if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) {
uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n");
exit(1);
}
struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req = wsgi_req;
PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout;
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
// avoid mess when closing the request
wsgi_req->async_timeout = NULL;
if (timed_out > 0) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
goto end;
}
int status = wsgi_req->socket->proto(wsgi_req);
if (status > 0) {
ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
goto end;
}
// trick for reference counting
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
goto again;
}
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) {
PyErr_Print();
goto end;
}
if (status == 0) {
// we call this two time... overengineering :(
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi.schedule_to_req();
goto again;
}
end:
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi_close_request(uwsgi.wsgi_req);
free_req_queue;
again:
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) {
long uwsgi_sock_ptr = 0;
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_accept", &uwsgi_sock_ptr)) {
return NULL;
}
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
if (wsgi_req == NULL) {
uwsgi_async_queue_is_full(uwsgi_now());
goto end;
}
uwsgi.wsgi_req = wsgi_req;
struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) uwsgi_sock_ptr;
// fill wsgi_request structure
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock );
// mark core as used
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
// in case of errors (or thundering herd, just reset it)
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
free_req_queue;
goto end;
}
wsgi_req->start_of_request = uwsgi_micros();
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
// add callback for protocol
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", wsgi_req->fd, uasyncio.request, (long) wsgi_req) == NULL) {
free_req_queue;
PyErr_Print();
}
// add timeout
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, (long)wsgi_req, 1);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
free_req_queue;
}
else {
// trick for reference counting
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
}
end:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_fd(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_hook_fd", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_timeout(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req->async_timed_out = 1;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_fix(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef uwsgi_asyncio_accept_def[] = { {"uwsgi_asyncio_accept", py_uwsgi_asyncio_accept, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_request_def[] = { {"uwsgi_asyncio_request", py_uwsgi_asyncio_request, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_fd_def[] = { {"uwsgi_asyncio_hook_fd", py_uwsgi_asyncio_hook_fd, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_timeout_def[] = { {"uwsgi_asyncio_hook_timeout", py_uwsgi_asyncio_hook_timeout, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_fix_def[] = { {"uwsgi_asyncio_hook_fix", py_uwsgi_asyncio_hook_fix, METH_VARARGS, ""} };
static void uwsgi_asyncio_schedule_fix(struct wsgi_request *wsgi_req) {
PyObject *cb = PyObject_CallMethod(uasyncio.loop, "call_soon", "Ol", uasyncio.hook_fix, (long) wsgi_req);
if (!cb) goto error;
Py_DECREF(cb);
return;
error:
PyErr_Print();
}
static void asyncio_loop() {
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
if (uwsgi.socket_timeout < 30) {
uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
if (!uwsgi.async_waiting_fd_table)
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_proto_fd_table)
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
// get the GIL
UWSGI_GET_GIL
up.gil_get = gil_asyncio_get;
up.gil_release = gil_asyncio_release;
uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook;
uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook;
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
if (uwsgi.async < 2) {
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
exit(1);
}
if (!uwsgi.schedule_to_main) {
uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n");
}
PyObject *asyncio = PyImport_ImportModule("asyncio");
if (!asyncio) uwsgi_pyexit;
uasyncio.mod = asyncio;
uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL);
if (!uasyncio.loop) uwsgi_pyexit;
// main greenlet waiting for connection (one greenlet per-socket)
PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL);
Py_INCREF(asyncio_accept);
uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL);
if (!uasyncio.request) uwsgi_pyexit;
uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL);
if (!uasyncio.hook_fd) uwsgi_pyexit;
uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL);
if (!uasyncio.hook_timeout) uwsgi_pyexit;
uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL);
if (!uasyncio.hook_fix) uwsgi_pyexit;
Py_INCREF(uasyncio.request);
Py_INCREF(uasyncio.hook_fd);
Py_INCREF(uasyncio.hook_timeout);
Py_INCREF(uasyncio.hook_fix);
// call add_handler on each socket
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
uwsgi_pyexit;
}
uwsgi_sock = uwsgi_sock->next;
}
if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) {
uwsgi_pyexit;
}
// never here ?
}
static void asyncio_init() {
uwsgi_register_loop( (char *) "asyncio", asyncio_loop);
}
struct uwsgi_plugin asyncio_plugin = {
.name = "asyncio",
.options = asyncio_options,
.on_load = asyncio_init,
};
+8
View File
@@ -0,0 +1,8 @@
from distutils import sysconfig
NAME='asyncio'
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
LDFLAGS = []
LIBS = []
GCC_LIST = ['asyncio']
+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;
}
+7 -2
View File
@@ -45,6 +45,7 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
if (!bufsize) bufsize = uwsgi.page_size;
peers->in = uwsgi_buffer_new(bufsize);
// add timeout
peers->current_timeout = cs->corerouter->socket_timeout;
peers->timeout = cr_add_timeout(cs->corerouter, peers);
peers->prev = old_peers;
@@ -582,8 +583,8 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
cs->corerouter = ucr;
cs->ugs = ugs;
// set initial timeout
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
// set initial timeout (could be overridden)
peer->current_timeout = ucr->socket_timeout;
ucr->active_sessions++;
@@ -622,6 +623,10 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
corerouter_close_session(ucr, cs);
cs = NULL;
}
else {
// truly set the timeout
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
}
return cs;
}
+6 -4
View File
@@ -3,12 +3,12 @@
#define COREROUTER_STATUS_RECV_HDR 2
#define COREROUTER_STATUS_RESPONSE 3
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+u->socket_timeout, x)
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+u->socket_timeout, x)
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+x->current_timeout, x)
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+x->current_timeout, x)
#define cr_del_timeout(u, x) uwsgi_del_rb_timer(u->timeouts, x->timeout); free(x->timeout);
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, x->session->client_address, x->session->client_port, __VA_ARGS__)
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, __VA_ARGS__)
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
errno = EINPROGRESS;\
@@ -188,6 +188,8 @@ struct corerouter_peer {
struct corerouter_peer *prev;
struct corerouter_peer *next;
int current_timeout;
};
struct uwsgi_corerouter {
+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;
+54 -2
View File
@@ -10,6 +10,10 @@ struct uwsgi_emperor_mongodb_state {
char *address;
char *collection;
char *json;
char *database;
char *username;
char *password;
char *predigest;
};
@@ -20,7 +24,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
try {
// requested fields
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 );
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 );
mongo::BSONObj q = mongo::fromjson(uems->json);
// the connection object (will be automatically destroyed at each cycle)
mongo::DBClientConnection c;
@@ -29,9 +33,17 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
// connect
c.connect(uems->address);
if (uems->database && uems->username && uems->password) {
std::string err;
if (c.auth(uems->database, uems->username, uems->password, err, uems->predigest ? false : true) == false) {
uwsgi_log_verbose("[emperor-mongodb] unable to authenticate to db %s: %s\n", uems->database, err.c_str());
return;
}
}
// run the query
std::auto_ptr<mongo::DBClientCursor> cursor = c.query(uems->collection, q, 0, 0, &p);
while( cursor->more() ) {
while(cursor.get() && cursor->more() ) {
mongo::BSONObj p = cursor->next();
// checking for an empty string is not required, but we reduce the load
@@ -40,6 +52,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
if (strlen(name) == 0) continue;
const char *config = p.getStringField("config");
if (strlen(config) == 0) config = NULL;
time_t vassal_ts = 0;
// ts must be a Date object !!!
@@ -61,6 +74,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
}
const char *socket_name = p.getStringField("socket");
if (strlen(socket_name) == 0) socket_name = NULL;
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
}
@@ -76,6 +90,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
b.append("name", c_ui->name);
mongo::BSONObj q2 = b.obj();
cursor = c.query(uems->collection, q2, 0, 0, &p);
if (!cursor.get()) return;
#ifdef UWSGI_DEBUG
uwsgi_log("JSON: %s\n", q2.toString().c_str());
#endif
@@ -121,3 +136,40 @@ done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
// setup a new mongodb imperial monitor (keyval based)
extern "C" void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *ues) {
// allocate a new state
ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state));
size_t arg_len = strlen(ues->arg);
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
// parse args/ set defaults
uems->address = (char *) "127.0.0.1:27017";
uems->collection = (char *) "uwsgi.emperor.vassals";
uems->json = (char *) "";
char *args = NULL;
if (arg_len <= 11) goto done;
args = ues->arg+11;
if (uwsgi_kvlist_parse(args, strlen(args), ',', '=',
"addr", &uems->address,
"address", &uems->address,
"server", &uems->address,
"collection", &uems->collection,
"coll", &uems->collection,
"json", &uems->json,
"database", &uems->database,
"db", &uems->database,
"username", &uems->username,
"password", &uems->password,
"predigest", &uems->predigest,
NULL)) {
uwsgi_log("[emperor-mongodb] invalid keyval syntax !\n");
exit(1);
}
done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
+2
View File
@@ -2,9 +2,11 @@
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *);
void emperor_mongodb_init(void) {
uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb);
uwsgi_register_imperial_monitor("mongodb2", uwsgi_imperial_monitor_mongodb_init2, uwsgi_imperial_monitor_mongodb);
}
struct uwsgi_plugin emperor_mongodb_plugin = {
+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");
}
+6 -4
View File
@@ -4,6 +4,8 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
#define is_not_python(x) strcmp(uwsgi.p[x]->name, "python")
struct ugreenlet {
int enabled;
PyObject *callable;
@@ -69,7 +71,7 @@ static void greenlet_schedule_to_req() {
}
// call it in the main core
if (uwsgi.p[modifier1]->suspend) {
if (is_not_python(modifier1) && uwsgi.p[modifier1]->suspend) {
uwsgi.p[modifier1]->suspend(NULL);
}
@@ -81,7 +83,7 @@ static void greenlet_schedule_to_req() {
}
Py_DECREF(ret);
if (uwsgi.p[modifier1]->resume) {
if (is_not_python(modifier1) && uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
}
@@ -93,7 +95,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
// ensure gil
UWSGI_GET_GIL
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL);
@@ -103,7 +105,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
exit(1);
}
Py_DECREF(ret);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
uwsgi.wsgi_req = wsgi_req;
+5 -1
View File
@@ -42,6 +42,10 @@ struct uwsgi_http {
int server_name_as_http_host;
int headers_timeout;
int connect_timeout;
int manage_source;
int enable_proxy_protocol;
};
struct http_session {
@@ -154,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
+165 -49
View File
@@ -60,43 +60,59 @@ struct uwsgi_option http_options[] = {
{"http-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &uhttp.cr.buffer_size, 0},
{"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0},
{"http-headers-timeout", required_argument, 0, "set internal http socket timeout for headers", uwsgi_opt_set_int, &uhttp.headers_timeout, 0},
{"http-connect-timeout", required_argument, 0, "set internal http socket timeout for backend connections", uwsgi_opt_set_int, &uhttp.connect_timeout, 0},
{"http-manage-source", no_argument, 0, "manage the SOURCE HTTP method placing the session in raw mode", uwsgi_opt_true, &uhttp.manage_source, 0},
{"http-enable-proxy-protocol", optional_argument, 0, "manage PROXY protocol requests", uwsgi_opt_true, &uhttp.enable_proxy_protocol, 0},
{0, 0, 0, 0, 0, 0, 0},
};
int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen) {
static void http_set_timeout(struct corerouter_peer *peer, int timeout) {
if (peer->current_timeout == timeout) return;
peer->current_timeout = timeout;
peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer);
}
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
size_t i;
char *val = hh;
int status = 0;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
*keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
*vallen+=1;
}
else if (status == 2) {
*vallen+=1;
}
}
if (!(*keylen))
return NULL;
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
*has_prefix = 0x02;
}
return val;
}
static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t keylen, char *val, size_t vallen, int prefix) {
struct uwsgi_buffer *out = peer->out;
struct http_session *hr = (struct http_session *) peer->session;
int i;
int status = 0;
char *val = hh;
uint16_t keylen = 0, vallen = 0;
int prefix = 0;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
vallen++;
}
else if (status == 2) {
vallen++;
}
}
if (!keylen)
return -1;
if (hr->websockets) {
if (!uwsgi_strncmp("UPGRADE", 7, hh, keylen)) {
if (!uwsgi_strnicmp(val, vallen, "websocket", 9)) {
@@ -137,10 +153,14 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
}
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)) {
@@ -151,11 +171,7 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
#endif
done:
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
keylen += 5;
prefix = 1;
}
if (prefix) keylen += 5;
if (uwsgi_buffer_u16le(out, keylen)) return -1;
@@ -163,7 +179,7 @@ done:
if (uwsgi_buffer_append(out, "HTTP_", 5)) return -1;
}
if (uwsgi_buffer_append(out, hh, keylen - (prefix * 5))) return -1;
if (uwsgi_buffer_append(out, hh, keylen - (prefix ? 5 : 0))) return -1;
if (uwsgi_buffer_u16le(out, vallen)) return -1;
if (uwsgi_buffer_append(out, val, vallen)) return -1;
@@ -180,6 +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
@@ -192,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;
@@ -315,16 +348,27 @@ int http_headers_parse(struct corerouter_peer *peer) {
}
#ifdef UWSGI_SSL
if (hr_https_add_vars(hr, out)) return -1;
if (hr_https_add_vars(hr, peer, out)) return -1;
#endif
// REMOTE_ADDR
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1;
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1;
if (proxy_src) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, proxy_src, proxy_src_len)) return -1;
if (proxy_src_port) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len)) return -1;
}
}
else
{
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1;
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1;
}
//HEADERS
base = ptr;
struct uwsgi_string_list *headers = NULL, *usl = NULL;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
@@ -345,13 +389,53 @@ int http_headers_parse(struct corerouter_peer *peer) {
hr->send_expect_100 = 1;
}
}
if (http_add_uwsgi_header(peer, base, ptr - base)) return -1;
size_t key_len = 0, value_len = 0;
int has_prefix = 0;
// last line, do not waste time
if (ptr - base == 0) break;
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
if (!value) goto clear;
usl = uwsgi_string_list_has_item(headers, base, key_len);
// there is already a HTTP header with the same name, let's merge them
if (usl) {
char *old_value = usl->custom_ptr;
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
usl->custom += 2 + value_len;
if (usl->custom2 & 0x01) free(old_value);
usl->custom2 |= 0x01;
}
else {
// add an entry
usl = uwsgi_string_new_list(&headers, NULL);
usl->value = base;
usl->len = key_len;
usl->custom_ptr = value;
usl->custom = value_len;
usl->custom2 = has_prefix;
}
ptr++;
base = ptr + 1;
}
ptr++;
}
usl = headers;
int broken = 0;
while(usl) {
if (!broken) {
if (http_add_uwsgi_header(peer, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02)) broken = 1;
}
if (usl->custom2 & 0x01) {
free(usl->custom_ptr);
}
struct uwsgi_string_list *tmp_usl = usl;
usl = usl->next;
free(tmp_usl);
}
if (broken) return -1;
struct uwsgi_string_list *hv = uhttp.http_vars;
while (hv) {
char *equal = strchr(hv->value, '=');
@@ -363,6 +447,18 @@ int http_headers_parse(struct corerouter_peer *peer) {
return 0;
clear:
usl = headers;
while(usl) {
if (usl->custom2 & 0x01) {
free(usl->custom_ptr);
}
struct uwsgi_string_list *tmp_usl = usl;
usl = usl->next;
free(tmp_usl);
}
return -1;
}
@@ -446,6 +542,7 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
return 0;
}
if (main_peer->session->connect_peer_after_write) {
http_set_timeout(main_peer->session->connect_peer_after_write, uhttp.connect_timeout);
cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected);
main_peer->session->connect_peer_after_write = NULL;
return len;
@@ -459,6 +556,9 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
ssize_t hr_instance_connected(struct corerouter_peer* peer) {
cr_peer_connected(peer, "hr_instance_connected()");
// set the default timeout
http_set_timeout(peer, uhttp.cr.socket_timeout);
// we are connected, we cannot retry anymore
peer->can_retry = 0;
@@ -523,10 +623,7 @@ ssize_t hr_instance_read(struct corerouter_peer *peer) {
hr->has_gzip = 0;
#endif
if (uhttp.keepalive > 1) {
int orig_timeout = peer->session->corerouter->socket_timeout;
peer->session->corerouter->socket_timeout = uhttp.keepalive;
peer->session->main_peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer->session->main_peer);
peer->session->corerouter->socket_timeout = orig_timeout;
http_set_timeout(peer->session->main_peer, uhttp.keepalive);
}
}
#ifdef UWSGI_ZLIB
@@ -655,6 +752,9 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
return 1;
}
// ensure the headers timeout is honoured
http_set_timeout(main_peer, uhttp.headers_timeout);
// read until \r\n\r\n is found
size_t j;
size_t len = main_peer->in->pos;
@@ -729,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
@@ -740,10 +847,12 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
break;
}
if (hr->websockets > 2 && hr->websocket_key_len > 0) {
hr->raw_body = 1;
}
new_peer->can_retry = 1;
// reset main timeout
http_set_timeout(main_peer, uhttp.cr.socket_timeout);
// set peer timeout
http_set_timeout(new_peer, uhttp.connect_timeout);
cr_connect(new_peer, hr_instance_connected);
break;
}
@@ -830,12 +939,17 @@ static int hr_retry(struct corerouter_peer *peer) {
retry:
// start async connect (again)
http_set_timeout(peer, uhttp.connect_timeout);
cr_connect(peer, hr_instance_connected);
return 0;
}
int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) {
if (!uhttp.headers_timeout) uhttp.headers_timeout = uhttp.cr.socket_timeout;
if (!uhttp.connect_timeout) uhttp.connect_timeout = uhttp.cr.socket_timeout;
// set the retry hook
cs->retry = hr_retry;
struct http_session *hr = (struct http_session *) cs;
@@ -845,6 +959,9 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
// default hook
cs->main_peer->last_hook_read = hr_read;
// headers timeout
cs->main_peer->current_timeout = uhttp.headers_timeout;
if (uhttp.raw_body) {
hr->raw_body = 1;
}
@@ -906,7 +1023,6 @@ int http_init() {
uhttp.cr.socket_num = 0;
}
uwsgi_corerouter_init((struct uwsgi_corerouter *) &uhttp);
return 0;
}
+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;
}
}
+46 -5
View File
@@ -180,8 +180,10 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
if (!key) return ub;
uint32_t h_len = 0;
// headers (key lowercase...)
// merge header values and ensure keys are all lowercase
struct uwsgi_string_list *hr=NULL, *usl=NULL;
char *line_value;
size_t line_key_len, line_value_len;
for(i=next;i<len;i++) {
if (key) {
if (buf[i] == '\r' || buf[i] == '\n') {
@@ -192,10 +194,37 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
// tolower !!!
size_t j;
for(j=0;j<h_len;j++) {
key[j] = tolower((int) key[j]);
// don't lowercase values, only keys
if (key[j] == ':') break;
key[j] = tolower((int) key[j]);
}
line_key_len = colon - key;
key[line_key_len] = 0;
line_value_len = h_len - 2 - line_key_len;
line_value = uwsgi_strncopy(colon+2, line_value_len);
if (hr) {
// check if we already store values for this key
usl = uwsgi_string_list_has_item(hr, key, line_key_len);
if (usl) {
// we have this key, append new value
char *oldval = usl->custom_ptr;
usl->custom_ptr = uwsgi_concat3n(usl->custom_ptr, usl->custom, "\0", 1, line_value, line_value_len);
usl->custom = usl->custom + 1 + line_value_len;
free(oldval);
}
else {
// this key is new
usl = uwsgi_string_new_list(&hr, key);
usl->custom_ptr = line_value;
usl->custom = line_value_len;
}
}
else {
// this is first key
usl = uwsgi_string_new_list(&hr, key);
usl->custom_ptr = line_value;
usl->custom = line_value_len;
}
if (uwsgi_buffer_append_keyval32(ub, key, colon-key, colon+2, h_len-((colon-key)+2))) goto end;
*hh+=1;
key = NULL;
h_len = 0;
}
@@ -210,6 +239,18 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
}
}
}
// append all merged header lines to buffer and free memory
struct uwsgi_string_list *ohr;
while (hr) {
if (uwsgi_buffer_append_keyval32(ub, hr->value, hr->len, hr->custom_ptr, hr->custom)) goto end;
*hh+=1;
ohr = hr;
hr = hr->next;
free(ohr->custom_ptr);
free(ohr);
}
return ub;
end:
+19 -2
View File
@@ -811,8 +811,25 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
lua_pushnil(L);
while(lua_next(L, -3) != 0) {
http = lua_tolstring(L, -2, &slen);
http2 = lua_tolstring(L, -1, &slen2);
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
if (lua_type(L, -1) == LUA_TTABLE) {
for (i = 1; /*empty*/ ; ++i) {
lua_rawgeti(L, -1, i);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
http2 = lua_tolstring(L, -1, &slen2);
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
lua_pop(L, 1);
}
}
else {
http2 = lua_tolstring(L, -1, &slen2);
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
}
lua_pop(L, 1);
}
+46 -33
View File
@@ -102,6 +102,10 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
}
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val));
}
if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) {
char *colon = strchr(json_val, ':');
if (colon) {
@@ -210,6 +214,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen);
}
}
else if (!uwsgi_strncmp("URL_SCHEME", 10, key, keylen)) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, val, vallen);
}
}
else {
// add header
@@ -299,6 +306,13 @@ void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_
// fake function, the body is in a file or completely in memory
ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_status;
if (remains > 0) {
if (len > remains) len = remains;
memcpy(buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size + wsgi_req->proto_parser_status, len);
wsgi_req->proto_parser_status += len;
return len;
}
return 0;
}
@@ -410,7 +424,8 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
}
// pre-build the mongrel2 response_header
wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1);
wsgi_req->proto_parser_buf_size = req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1;
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_buf_size);
memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len);
((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' ';
resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1);
@@ -422,13 +437,22 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
// handle post data (in memory)
// reallocate wsgi_req->proto_parser_buf and change its size to be able to store request body
// the parser status holds the current position for read_body hook
if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) {
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
char *tmp = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + wsgi_req->post_cl);
if (!tmp) {
uwsgi_error("realloc()");
exit(1);
}
wsgi_req->proto_parser_buf = tmp;
// status is an offset...
wsgi_req->proto_parser_status = 0;
#ifdef UWSGI_DEBUG
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
#endif
wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl);
memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl);
memcpy(wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size, message_ptr, wsgi_req->post_cl);
}
}
@@ -452,33 +476,7 @@ retry:
return -1;
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
zmq_msg_t reply;
// check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos
if (!wsgi_req->proto_parser_pos)
return;
// no need to pass a free function (the buffer will be freed during cloe_request)
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()");
#else
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()");
#endif
}
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
}
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
static int uwsgi_proto_zeromq_write_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
zmq_msg_t reply;
if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) {
@@ -489,7 +487,8 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
char *zmq_body = zmq_msg_data(&reply);
memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos);
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
if (len > 0)
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
@@ -510,6 +509,18 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
return UWSGI_OK;
}
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
int ret = uwsgi_proto_zeromq_write_do(wsgi_req, buf, len);
if (ret == UWSGI_OK) {
wsgi_req->write_pos += len;
}
return ret;
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
uwsgi_proto_zeromq_write_do(wsgi_req, "", 0);
}
/*
we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of
@@ -532,7 +543,7 @@ int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t po
return -1;
}
wsgi_req->write_pos += rlen;
if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) {
if (uwsgi_proto_zeromq_write_do(wsgi_req, tmp_buf, rlen) < 0) {
free(tmp_buf);
return -1;
}
@@ -574,6 +585,7 @@ static void mongrel2_register_proto() {
static void mongrel2_connect() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->proto != uwsgi_proto_zeromq_parser) goto next;
uwsgi_sock->ctx = zmq_init(1);
if (!uwsgi_sock->ctx) {
uwsgi_error("mongrel2_connect()/zmq_init()");
@@ -581,7 +593,7 @@ static void mongrel2_connect() {
}
char *responder = strchr(uwsgi_sock->name, ',');
if (!responder) {
uwsgi_log("invalid zeromq address\n");
uwsgi_log("invalid zeromq address: %s\n", uwsgi_sock->name);
exit(1);
}
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
@@ -653,6 +665,7 @@ static void mongrel2_connect() {
#else
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
#endif
next:
uwsgi_sock = uwsgi_sock->next;
}
}
+12
View File
@@ -0,0 +1,12 @@
#include "php.h"
#include "SAPI.h"
#include "php_main.h"
#include "php_variables.h"
#include "ext/standard/php_smart_str.h"
#include "ext/standard/info.h"
#include "ext/session/php_session.h"
#include <uwsgi.h>
+5 -12
View File
@@ -1,12 +1,4 @@
#include "php.h"
#include "SAPI.h"
#include "php_main.h"
#include "php_variables.h"
#include "ext/standard/php_smart_str.h"
#include "ext/standard/info.h"
#include "../../uwsgi.h"
#include "common.h"
extern struct uwsgi_server uwsgi;
@@ -233,8 +225,9 @@ void uwsgi_php_set(char *opt) {
uwsgi_sapi_module.ini_entries[uphp.ini_size] = 0;
}
// future implementation...
extern ps_module ps_mod_uwsgi;
PHP_MINIT_FUNCTION(uwsgi_php_minit) {
php_session_register_module(&ps_mod_uwsgi);
return SUCCESS;
}
@@ -341,7 +334,7 @@ PHP_FUNCTION(uwsgi_cache_set) {
RETURN_NULL();
}
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
RETURN_TRUE;
}
RETURN_NULL();
@@ -363,7 +356,7 @@ PHP_FUNCTION(uwsgi_cache_update) {
RETURN_NULL();
}
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
RETURN_TRUE;
}
RETURN_NULL();
+50
View File
@@ -0,0 +1,50 @@
#include "common.h"
PS_OPEN_FUNC(uwsgi) {
PS_SET_MOD_DATA((char *)save_path);
return SUCCESS;
}
PS_CLOSE_FUNC(uwsgi) {
return SUCCESS;
}
PS_READ_FUNC(uwsgi) {
char *cache = PS_GET_MOD_DATA();
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get((char *)key, strlen(key), &valsize, NULL, cache);
if (!value) return FAILURE;
char *new_val = emalloc(valsize);
memcpy(new_val, value, valsize);
free(value);
*val = new_val;
*vallen = valsize;
return SUCCESS;
}
PS_WRITE_FUNC(uwsgi) {
char *cache = PS_GET_MOD_DATA();
if (vallen == 0) return SUCCESS;
if (!uwsgi_cache_magic_set((char *)key, strlen(key), (char *)val, vallen, 0, UWSGI_CACHE_FLAG_UPDATE, cache)) {
return SUCCESS;
}
return FAILURE;
}
PS_DESTROY_FUNC(uwsgi) {
char *cache = PS_GET_MOD_DATA();
if (!uwsgi_cache_magic_del((char *)key, strlen(key), cache)) {
return SUCCESS;
}
return FAILURE;
}
PS_GC_FUNC(uwsgi) {
return SUCCESS;
}
ps_module ps_mod_uwsgi = {
PS_MOD(uwsgi)
};
+1 -1
View File
@@ -25,4 +25,4 @@ phplibdir = os.environ.get('UWSGICONFIG_PHPLIBDIR')
if phplibdir:
LIBS.append('-Wl,-rpath=%s' % phplibdir)
GCC_LIST = ['php_plugin']
GCC_LIST = ['php_plugin', 'session']
+7 -3
View File
@@ -54,7 +54,7 @@ XS(XS_psgix_logger) {
psgi_check_args(1);
HV *hv_args = (HV *) (SvRV(ST(0)));
if (!hv_exists(hv_args, "level", 5) || !hv_exists(hv_args, "message", 7)) {
Perl_croak(aTHX_ "psgix.logger requires bot level and message items");
Perl_croak(aTHX_ "psgix.logger requires both level and message items");
}
char *level = SvPV_nolen(*(hv_fetch(hv_args, "level", 5, 0)));
char *message = SvPV_nolen(*(hv_fetch(hv_args, "message", 7, 0)));
@@ -108,7 +108,7 @@ XS(XS_input_read) {
unsigned long arg_len = SvIV(ST(2));
long offset = 0;
if (items > 2) {
if (items > 3) {
offset = (long) SvIV(ST(3));
}
@@ -370,12 +370,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
// uperl.embedding as an argument so we won't execute
// BEGIN blocks in app_name twice.
{
char *perl_init_arg[] = { "", "-e", "0" };
char *perl_e_arg = uwsgi_concat2("#line 0 ", app_name);
char *perl_init_arg[] = { "", "-e", perl_e_arg };
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(callables);
free(perl_e_arg);
uwsgi_perl_free_stashes();
goto clear;
} else {
free(perl_e_arg);
}
}
+26
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)) {
@@ -955,6 +958,27 @@ XS(XS_spool) {
XSRETURN_UNDEF;
}
XS(XS_add_var) {
dXSARGS;
psgi_check_args(2);
struct wsgi_request *wsgi_req = current_wsgi_req();
STRLEN keylen;
char *key = SvPV(ST(0), keylen);
STRLEN vallen;
char *val = SvPV(ST(1), vallen);
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
croak("unable to add request var, check your buffer size");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
void init_perl_embedded_module() {
psgi_xs(reload);
@@ -1016,5 +1040,7 @@ void init_perl_embedded_module() {
psgi_xs(spooler);
psgi_xs(spool);
psgi_xs(add_var);
}
+15
View File
@@ -168,6 +168,8 @@ struct uwsgi_option uwsgi_python_options[] = {
{"py-sharedarea", required_argument, 0, "create a sharedarea from a python bytearray object of the specified size", uwsgi_opt_add_string_list, &up.sharedarea, 0},
#endif
{"py-call-osafterfork", no_argument, 0, "enable child processes running cpython to trap OS signals", uwsgi_opt_true, &up.call_osafterfork, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -197,6 +199,12 @@ int uwsgi_python_init() {
uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
}
if (Py_IsInitialized()) {
uwsgi_log("--- Python VM already initialized ---\n");
PyGILState_Ensure();
goto ready;
}
if (up.home != NULL) {
#ifdef PYTHREE
// check for PEP 405 virtualenv (starting from python 3.3)
@@ -251,6 +259,8 @@ pep405:
Py_Initialize();
ready:
if (!uwsgi.has_threads) {
uwsgi_log_initial("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
}
@@ -369,6 +379,11 @@ void uwsgi_python_post_fork() {
UWSGI_GET_GIL
}
// reset python signal flags so child processes can trap signals
if (up.call_osafterfork) {
PyOS_AfterFork();
}
uwsgi_python_reset_random_seed();
// call the post_fork_hook
+162 -8
View File
@@ -4,6 +4,29 @@ extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern struct uwsgi_plugin python_plugin;
static PyObject *py_uwsgi_add_var(PyObject * self, PyObject * args) {
char *key = NULL;
Py_ssize_t keylen = 0;
char *val = NULL;
Py_ssize_t vallen = 0;
struct wsgi_request *wsgi_req = py_current_wsgi_req();
if (!PyArg_ParseTuple(args, "s#s#", &key, &keylen, &val, &vallen)) {
return NULL;
}
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
return PyErr_Format(PyExc_ValueError, "unable to add request var, check your buffer size");
}
Py_INCREF(Py_True);
return Py_True;
}
static PyObject *py_uwsgi_micros(PyObject * self, PyObject * args) {
return PyLong_FromUnsignedLongLong(uwsgi_micros());
}
static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
struct wsgi_request *wsgi_req = py_current_wsgi_req();
@@ -1403,7 +1426,7 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
uint64_t pos = 0;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "il|l:sharedarea_inc64", &id, &pos, &value)) {
if (!PyArg_ParseTuple(args, "iL|l:sharedarea_inc64", &id, &pos, &value)) {
return NULL;
}
@@ -1420,12 +1443,56 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_sharedarea_write32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int32_t value = 0;
if (!PyArg_ParseTuple(args, "iLI:sharedarea_write32", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_write32(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write32()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_write16(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int16_t value = 0;
if (!PyArg_ParseTuple(args, "iLI:sharedarea_write16", &id, &pos, &value)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_write16(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write16()");
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_sharedarea_write64(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int64_t value = 0;
if (!PyArg_ParseTuple(args, "ill:sharedarea_write64", &id, &pos, &value)) {
if (!PyArg_ParseTuple(args, "iLL:sharedarea_write64", &id, &pos, &value)) {
return NULL;
}
@@ -1447,7 +1514,7 @@ PyObject *py_uwsgi_sharedarea_write(PyObject * self, PyObject * args) {
char *value;
Py_ssize_t value_len = 0;
if (!PyArg_ParseTuple(args, "ils#:sharedarea_write", &id, &pos, &value, &value_len)) {
if (!PyArg_ParseTuple(args, "iLs#:sharedarea_write", &id, &pos, &value, &value_len)) {
return NULL;
}
@@ -1547,7 +1614,7 @@ PyObject *py_uwsgi_sharedarea_write8(PyObject * self, PyObject * args) {
uint64_t pos = 0;
int8_t value;
if (!PyArg_ParseTuple(args, "ilb:sharedarea_write8", &id, &pos, &value)) {
if (!PyArg_ParseTuple(args, "iLb:sharedarea_write8", &id, &pos, &value)) {
return NULL;
}
@@ -1569,7 +1636,7 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
uint64_t pos = 0;
int64_t value;
if (!PyArg_ParseTuple(args, "il:sharedarea_read64", &id, &pos)) {
if (!PyArg_ParseTuple(args, "iL:sharedarea_read64", &id, &pos)) {
return NULL;
}
@@ -1581,16 +1648,59 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read64()");
}
return PyLong_FromLong(value);
return PyLong_FromLongLong(value);
}
PyObject *py_uwsgi_sharedarea_read32(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int32_t value;
if (!PyArg_ParseTuple(args, "iL:sharedarea_read32", &id, &pos)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_read32(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read32()");
}
return PyInt_FromLong(value);
}
PyObject *py_uwsgi_sharedarea_read16(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int16_t value;
if (!PyArg_ParseTuple(args, "iL:sharedarea_read16", &id, &pos)) {
return NULL;
}
UWSGI_RELEASE_GIL
int ret = uwsgi_sharedarea_read16(id, pos, &value);
UWSGI_GET_GIL
if (ret) {
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read16()");
}
return PyInt_FromLong(value);
}
PyObject *py_uwsgi_sharedarea_read8(PyObject * self, PyObject * args) {
int id;
uint64_t pos = 0;
int8_t byte;
if (!PyArg_ParseTuple(args, "il:sharedarea_read8", &id, &pos)) {
if (!PyArg_ParseTuple(args, "iL:sharedarea_read8", &id, &pos)) {
return NULL;
}
@@ -1610,7 +1720,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;
}
@@ -2417,6 +2527,10 @@ static PyMethodDef uwsgi_advanced_methods[] = {
{"ready_fd", py_uwsgi_ready_fd, METH_VARARGS, ""},
{"add_var", py_uwsgi_add_var, METH_VARARGS, ""},
{"micros", py_uwsgi_micros, METH_VARARGS, ""},
{NULL, NULL},
};
@@ -2432,6 +2546,10 @@ static PyMethodDef uwsgi_sa_methods[] = {
{"sharedarea_writelong", py_uwsgi_sharedarea_write64, METH_VARARGS, ""},
{"sharedarea_read64", py_uwsgi_sharedarea_read64, METH_VARARGS, ""},
{"sharedarea_write64", py_uwsgi_sharedarea_write64, METH_VARARGS, ""},
{"sharedarea_read32", py_uwsgi_sharedarea_read32, METH_VARARGS, ""},
{"sharedarea_write32", py_uwsgi_sharedarea_write32, METH_VARARGS, ""},
{"sharedarea_read16", py_uwsgi_sharedarea_read16, METH_VARARGS, ""},
{"sharedarea_write16", py_uwsgi_sharedarea_write16, METH_VARARGS, ""},
{"sharedarea_inclong", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""},
{"sharedarea_inc64", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""},
{"sharedarea_rlock", py_uwsgi_sharedarea_rlock, METH_VARARGS, ""},
@@ -3164,6 +3282,40 @@ PyObject *py_uwsgi_metric_get(PyObject * self, PyObject * args) {
return PyLong_FromLongLong(value);
}
PyObject *py_uwsgi_metric_set_max(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_set_max", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_set_max(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_set_min(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_set_min", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_set_min(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
static PyMethodDef uwsgi_metrics_methods[] = {
{"metric_inc", py_uwsgi_metric_inc, METH_VARARGS, ""},
@@ -3172,6 +3324,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;
};
+33 -4
View File
@@ -5,6 +5,8 @@
extern struct uwsgi_server uwsgi;
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = NULL;
// mark a route request
wsgi_req->via = UWSGI_VIA_ROUTE;
@@ -24,9 +26,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
}
}
// convert the wsgi_request to an http proxy request
struct uwsgi_buffer *ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
if (ur->custom & 0x02) {
ub = uwsgi_buffer_new(uwsgi.page_size);
}
else {
ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
}
if (!ub) {
if (ub_url) uwsgi_buffer_destroy(ub_url);
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
@@ -46,11 +53,12 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_NEXT;
}
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
wsgi_req->proto_parser_remains = 0;
}
// ok now if have offload threads, directly use them
if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
// append buffered body
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
@@ -60,6 +68,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
return UWSGI_ROUTE_NEXT;
}
}
// if we have a CONNECT request, let's confirm it to the client
if (ur->custom & 0x02) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
// no need to check for return value
uwsgi_response_write_headers_do(wsgi_req);
}
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
@@ -72,6 +88,7 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
}
end:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_addr);
@@ -102,15 +119,27 @@ static int uwsgi_router_http(struct uwsgi_route *ur, char *args) {
}
static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
ur->custom = 0x1;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_proxyhttp_connect(struct uwsgi_route *ur, char *args) {
ur->custom = 0x1|0x02;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) {
ur->custom = 0x02;
return uwsgi_router_http(ur, args);
}
static void router_http_register(void) {
uwsgi_register_router("http", uwsgi_router_http);
uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp);
uwsgi_register_router("httpconnect", uwsgi_router_http_connect);
uwsgi_register_router("proxyhttpconnect", uwsgi_router_proxyhttp_connect);
}
struct uwsgi_plugin router_http_plugin = {
+26 -1
View File
@@ -18,6 +18,8 @@ struct uwsgi_router_file_conf {
char *mime;
char *no_cl;
char *no_headers;
};
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -38,6 +40,7 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
char buf[32768];
struct stat st;
int ret = UWSGI_ROUTE_BREAK;
size_t remains = 0;
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
@@ -61,6 +64,11 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
if (urfc->no_headers) goto send;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
@@ -82,8 +90,10 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
else {
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
send:
size_t remains = st.st_size;
remains = st.st_size;
while(remains) {
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
if (rlen <= 0) goto end2;
@@ -125,6 +135,11 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
if (urfc->no_headers) goto send;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
@@ -145,6 +160,8 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
send:
if (!wsgi_req->headers_sent) {
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
}
@@ -188,6 +205,11 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
if (!ub_s) goto end2;
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
if (urfc->no_headers) goto send;
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
uwsgi_buffer_destroy(ub_s);
goto end2;
@@ -208,6 +230,8 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
}
send:
if (!wsgi_req->headers_sent) {
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
}
@@ -256,6 +280,7 @@ static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
"no_cl", &urfc->no_cl,
"no_content_length", &urfc->no_cl,
"mime", &urfc->mime,
"no_headers", &urfc->no_headers,
NULL)) {
uwsgi_log("invalid file route syntax: %s\n", args);
return -1;
+13 -4
View File
@@ -35,7 +35,13 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
struct uwsgi_header *uh = (struct uwsgi_header *) ur->data;
char *addr = ur->data + sizeof(struct uwsgi_header);
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, addr, strlen(addr));
if (!ub_addr) return UWSGI_ROUTE_BREAK;
// mark a route request
wsgi_req->via = UWSGI_VIA_ROUTE;
@@ -54,6 +60,7 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
goto end;
}
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
wsgi_req->proto_parser_remains = 0;
}
@@ -65,18 +72,20 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
goto end;
}
}
if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) {
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
}
if (uwsgi_proxy_nb(wsgi_req, addr, ub, remains, uwsgi.socket_timeout)) {
uwsgi_log("error routing request to uwsgi server %s\n", addr);
if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) {
uwsgi_log("error routing request to uwsgi server %s\n", ub_addr->buf);
}
end:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
+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;
+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);
+5
View File
@@ -95,6 +95,11 @@ 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, "|m");
}
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);
+4
View File
@@ -93,7 +93,11 @@ ssize_t uwsgi_syslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
ul->configured = 1;
}
#ifdef __APPLE__
syslog(LOG_NOTICE, "%.*s", (int) len, message);
#else
syslog(LOG_INFO, "%.*s", (int) len, message);
#endif
return 0;
}
+5
View File
@@ -326,6 +326,11 @@ static void tornado_loop() {
uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
if (!uwsgi.async_waiting_fd_table)
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_proto_fd_table)
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
// get the GIL
UWSGI_GET_GIL
+18 -8
View File
@@ -2,6 +2,16 @@
extern struct uwsgi_tuntap utt;
// error reporting
void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *uttp, char *msg, char *file, int line) {
if (uttp) {
uwsgi_log_verbose("[tuntap] peer fd: %d ip: %s %s: %s [%s line %d]\n", uttp->fd, uttp->ip, msg, strerror(errno), file, line);
}
else {
uwsgi_log_verbose("[tuntap] %s: %s [%s line %d]\n", msg, strerror(errno), file, line);
}
}
// create a new peer
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd, int is_router) {
@@ -183,7 +193,7 @@ int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *uttr, struct uwsgi_tu
char ip[INET_ADDRSTRLEN + 1];
memset(ip, 0, INET_ADDRSTRLEN + 1);
if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) {
uwsgi_error("uwsgi_tuntap_register_addr()/inet_ntop()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_register_addr()/inet_ntop()");
return -1;
}
if (uttp != tmp_uttp) {
@@ -205,7 +215,7 @@ int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
if (rlen < 0) {
if (uwsgi_is_again())
return 0;
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()");
return -1;
}
uttp->buf_pos += rlen;
@@ -265,7 +275,7 @@ enqueue:
if (rlen < 0) {
if (uwsgi_is_again())
return 0;
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()");
return -1;
}
uttp->header_pos += rlen;
@@ -282,14 +292,14 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
ssize_t rlen = write(uttp->fd, uttp->write_buf + uttp->written, uttp->write_buf_pktsize - uttp->written);
if (rlen == 0) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()");
return -1;
}
if (rlen < 0) {
if (uwsgi_is_again())
goto retry;
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()");
return -1;
}
@@ -303,13 +313,13 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
if (uttr->wait_for_write) {
uttp->blocked_read = 1;
if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_write())) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
return -1;
}
}
else {
if (event_queue_fd_readwrite_to_read(uttr->queue, uttp->fd)) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
return -1;
}
}
@@ -324,7 +334,7 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
retry:
if (!uttp->wait_for_write) {
if (event_queue_fd_read_to_readwrite(uttr->queue, uttp->fd)) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
return -1;
}
uttp->wait_for_write = 1;
+2
View File
@@ -116,3 +116,5 @@ int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *, struct uwsgi_tuntap
void uwsgi_tuntap_peer_send_rules(int, struct uwsgi_tuntap_peer *);
int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *, char *, size_t, int);
#define uwsgi_tuntap_error(x, y) uwsgi_tuntap_error_do(x, y, __FILE__, __LINE__)
void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *, char *, char *, int);
+24 -5
View File
@@ -1,6 +1,7 @@
#include "common.h"
extern struct uwsgi_tuntap utt;
extern struct uwsgi_server uwsgi;
int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp, char *pkt, size_t len, int direction) {
if (uttp->rules_cnt == 0) return 0;
@@ -51,7 +52,25 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
sin.sin_port = rule->target_port;
sin.sin_addr.s_addr = rule->target;
if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
uwsgi_error("uwsgi_tuntap_route_check()/sendto()");
if (uwsgi_is_again()) {
// suspend and retry
struct pollfd pfd;
memset(&pfd, 0, sizeof(struct pollfd));
pfd.fd = uttr->gateway_fd;
pfd.events = POLLOUT;
int ret = poll(&pfd, 1, uwsgi.socket_timeout * 1000);
if (ret > 0) {
if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()");
}
}
else {
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/poll()");
}
}
else {
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()");
}
}
}
return 2;
@@ -305,7 +324,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
*slash = 0;
}
if (inet_pton(AF_INET, argv[1], &utpr.src) != 1) {
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
exit(1);
}
if (slash) *slash = '/';
@@ -317,7 +336,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
*slash = 0;
}
if (inet_pton(AF_INET, argv[2], &utpr.dst) != 1) {
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
exit(1);
}
if (slash) *slash = '/';
@@ -352,7 +371,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
}
*colon = 0;
if (inet_pton(AF_INET, argv[4], &utpr.target) != 1) {
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
exit(1);
}
*colon = ':';
@@ -370,7 +389,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
size_t len = ub->pos;
uwsgi_buffer_destroy(ub);
if (write(fd,peer->rules, len) != (ssize_t)len) {
uwsgi_error("uwsgi_tuntap_peer_send_rules()/write()");
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/write()");
exit(1);
}
return;
+11 -4
View File
@@ -117,6 +117,13 @@ static void *uwsgi_tuntap_loop(void *arg) {
uwsgi_error("uwsgi_tuntap_loop()/read()");
exit(1);
}
// check for full write buffer
if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) {
uttp->dropped++;
continue;
}
uint16_t pktsize = rlen;
char *ptr = uttp->write_buf + uttp->write_buf_pktsize;
memcpy(ptr + 4, uttr->buf, rlen);
@@ -126,7 +133,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
ptr[3] = 0;
uttp->write_buf_pktsize+= pktsize+4;
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
uwsgi_log("server disconnected...\n");
uwsgi_log_verbose("tuntap server disconnected...\n");
exit(1);
}
continue;
@@ -137,7 +144,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
// read from the client
if (!uttp->wait_for_write) {
if (uwsgi_tuntap_peer_dequeue(uttr, uttp, 0)) {
uwsgi_log("server disconnected...\n");
uwsgi_log_verbose("tuntap server disconnected...\n");
exit(1);
}
}
@@ -149,7 +156,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
// write to the client
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
uwsgi_log("server disconnected...\n");
uwsgi_log_verbose("tuntap server disconnected...\n");
exit(1);
}
}
@@ -507,7 +514,7 @@ void tuntaprouter_send_stats(struct uwsgi_tuntap_router *uttr) {
ssize_t res = write(client_fd, us->base + pos, remains);
if (res <= 0) {
if (res < 0) {
uwsgi_error("write()");
uwsgi_error("tuntaprouter_send_stats()/write()");
}
goto end0;
}
+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;
}
+111 -46
View File
@@ -4,52 +4,55 @@
extern struct uwsgi_server uwsgi;
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, int hhlen) {
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
size_t i;
char *val = hh;
int status = 0;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
*keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
*vallen+=1;
}
else if (status == 2) {
*vallen+=1;
}
}
if (!(*keylen))
return NULL;
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
*has_prefix = 0x02;
}
return val;
}
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, size_t hhlen, char *hv, size_t hvlen, int has_prefix) {
char *buffer = wsgi_req->buffer + wsgi_req->uh->pktsize;
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
int i;
int status = 0;
char *val = hh;
uint16_t keylen = 0, vallen = 0;
int prefix = 0;
char *ptr = buffer;
size_t keylen = hhlen;
for (i = 0; i < hhlen; i++) {
if (!status) {
hh[i] = toupper((int) hh[i]);
if (hh[i] == '-')
hh[i] = '_';
if (hh[i] == ':') {
status = 1;
keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
vallen++;
}
else if (status == 2) {
vallen++;
}
}
if (has_prefix) keylen += 5;
if (!keylen)
return 0;
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen)) {
keylen += 5;
prefix = 1;
}
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
if (prefix) {
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
if (buffer + keylen + hvlen + 2 + 2 >= watermark) {
if (has_prefix) {
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
}
else {
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
}
return 0;
}
@@ -58,7 +61,7 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
*ptr++ = (uint8_t) (keylen & 0xff);
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
if (prefix) {
if (has_prefix) {
memcpy(ptr, "HTTP_", 5);
ptr += 5;
memcpy(ptr, hh, keylen - 5);
@@ -69,14 +72,14 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
ptr += keylen;
}
*ptr++ = (uint8_t) (vallen & 0xff);
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
memcpy(ptr, val, vallen);
*ptr++ = (uint8_t) (hvlen & 0xff);
*ptr++ = (uint8_t) ((hvlen >> 8) & 0xff);
memcpy(ptr, hv, hvlen);
return 2 + keylen + 2 + vallen;
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;
@@ -301,9 +304,15 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
}
}
if (wsgi_req->https_len > 0) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "HTTPS", 5, wsgi_req->https, wsgi_req->https_len);
}
//HEADERS
base = ptr;
struct uwsgi_string_list *headers = NULL, *usl = NULL;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
@@ -317,15 +326,71 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
continue;
}
}
wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, base, ptr - base);
size_t key_len = 0, value_len = 0;
int has_prefix = 0;
// last line, do not waste time
if (ptr - base == 0) break;
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
if (!value) {
uwsgi_log_verbose("invalid HTTP request\n");
goto clear;
}
usl = uwsgi_string_list_has_item(headers, base, key_len);
// there is already a HTTP header with the same name, let's merge them
if (usl) {
char *old_value = usl->custom_ptr;
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
usl->custom += 2 + value_len;
if (usl->custom2 & 0x01) free(old_value);
usl->custom2 |= 0x01;
}
else {
// add an entry
usl = uwsgi_string_new_list(&headers, NULL);
usl->value = base;
usl->len = key_len;
usl->custom_ptr = value;
usl->custom = value_len;
usl->custom2 = has_prefix;
}
ptr++;
base = ptr + 1;
}
ptr++;
}
return 0;
usl = headers;
int broken = 0;
while(usl) {
if (!broken) {
uint16_t old_pktsize = wsgi_req->uh->pktsize;
wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02);
// if the packet remains unchanged, the buffer is full, mark the request as broken
if (old_pktsize == wsgi_req->uh->pktsize) {
broken = 1;
}
}
if (usl->custom2 & 0x01) {
free(usl->custom_ptr);
}
struct uwsgi_string_list *tmp_usl = usl;
usl = usl->next;
free(tmp_usl);
}
return broken;
clear:
usl = headers;
while(usl) {
if (usl->custom2 & 0x01) {
free(usl->custom_ptr);
}
struct uwsgi_string_list *tmp_usl = usl;
usl = usl->next;
free(tmp_usl);
}
return -1;
}
+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
+4
View File
@@ -59,6 +59,10 @@ my $app = sub {
uwsgi::signal(17);
uwsgi::signal(30);
my ($package, $filename, $line) = caller;
die "Expecting reasonable caller() return values, not [$package, $filename, $line]"
unless $package eq 'main' and $filename =~ /\btest\.psgi$/s and $line == 0;
if ($env->{'psgix.cleanup'}) {
print "cleanup supported\n";
push @{$env->{'psgix.cleanup.handlers'}}, $one;
+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!" ]];
}
+3 -1
View File
@@ -20,11 +20,13 @@ push @tests, ['1', 'HELLO', "oHELLOo_three_four"];
push @tests, ['3', 'HELLO', "oneHELLOthree_four"];
push @tests, ['30', 'HELLO', "one_two_three_four\0\0\0\0\0\0\0\0\0\0\0\0HELLO"];
@ARGV or die "You must provide a host to test on, e.g. localhost:8080";
foreach(@tests) {
print "testing: offset(".$_->[0].") body(".$_->[1].")\n";
my $req = "POST /?".$base." HTTP/1.0\r\nContent-Length: ".length($_->[1])."\r\nuWSGI-Offset: ".$_->[0]."\r\n\r\n".$_->[1];
my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]);
my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]) or die "PANIC: Unable to construct socket";
$s->send($req);
my $response = '';
+47
View File
@@ -0,0 +1,47 @@
use strict;
use warnings;
sub {
my $env = shift;
my $cl = $env->{CONTENT_LENGTH};
$env->{'psgi.input'}->seek(0,0);
my $content = '';
while ($cl) {
$env->{'psgi.input'}->read(my $chunk, $cl < 8192 ? $cl : 8192);
my $read = length $chunk;
$cl -= $read;
$content .= $chunk;
}
return [200, [], [ "Your content was: <$content>" ]];
};
__END__
This is a trival test that prints out a POST request, it's here to
test a regression introduced in 2.0-103-gf041d10 where doing reads
without offsets, e.g.:
$ http_proxy= curl -d '{ "what": "ever" }' http://localhost:8080/
Your content was: $VAR1 = '{ "what": "ever" }';
Would result in:
Use of uninitialized value in subroutine entry at
/home/v-perlbrew/perl5/perlbrew/perls/perl-5.19.6/lib/site_perl/5.19.6/Plack/Request.pm
line 280.
Which is due to this commit having a one-off error in counting stack
items.
$ git bisect good
f041d1095ddf7541c4b275e16d2ed3355a8e2be9 is the first bad commit
commit f041d1095ddf7541c4b275e16d2ed3355a8e2be9
Author: Unbit <info@unbit.it>
Date: Wed Feb 5 11:21:01 2014 +0100
perl refactoring
:040000 040000 98a25406b7edb9bd0b9be8bbcd351a99e7ce2d33 0087e3ca4b6bd65a087fade65d43a56085298ef0 M plugins
+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" ],
];
}
+48
View File
@@ -0,0 +1,48 @@
use strict;
use warnings;
sub {
my $env = shift;
return sub {
my $responder = shift;
my $writer = $responder->([ 200, [ 'Content-Type', 'text/plain' ]]);
sleep 3;
$writer->write("hello\n");
sleep 3;
$writer->write("world\n");
$writer->close;
return;
};
}
__END__
Making a request to this will give you:
$ date; curl -s -N -D - 'http://localhost:8080'
Sat Mar 15 14:08:25 UTC 2014
HTTP/1.1 200 OK
Content-Type: text/plain
hello
world
And monitoring it with tcpflow shows how the output (including
headers) is flushed right away:
$ sudo tcpflow -i lo -c port 8080 | perl -pe 's/^/localtime . " "/ge'
Sat Mar 15 14:09:08 2014 127.000.000.001.55058-127.000.000.001.08080: GET / HTTP/1.1
Sat Mar 15 14:09:08 2014 User-Agent: curl/7.35.0
Sat Mar 15 14:09:08 2014 Host: localhost:8080
Sat Mar 15 14:09:08 2014 Accept: */*
Sat Mar 15 14:09:08 2014
Sat Mar 15 14:09:08 2014
Sat Mar 15 14:09:08 2014 127.000.000.001.08080-127.000.000.001.55058: HTTP/1.1 200 OK
Sat Mar 15 14:09:08 2014 Content-Type: text/plain
Sat Mar 15 14:09:08 2014
Sat Mar 15 14:09:08 2014
Sat Mar 15 14:09:11 2014 127.000.000.001.08080-127.000.000.001.55058: hello
Sat Mar 15 14:09:11 2014
Sat Mar 15 14:09:14 2014 127.000.000.001.08080-127.000.000.001.55058: world
Sat Mar 15 14:09:14 2014
+1 -1
View File
@@ -1,4 +1,4 @@
#!./uwsgi --http-socket :9090 --gevent 100 --module tests.websocket_chat --gevent-monkey-patch
#!./uwsgi --http-socket :9090 --gevent 100 --module tests.websockets_chat --gevent-monkey-patch
import uwsgi
import time
import gevent.select
+140
View File
@@ -0,0 +1,140 @@
#!./uwsgi --http-socket :9090 --asyncio 100 --module tests.websockets_chat_asyncio --greenlet
import uwsgi
import asyncio
import asyncio_redis
import time
import greenlet
class GreenFuture(asyncio.Future):
def __init__(self):
super().__init__()
self.greenlet = greenlet.getcurrent()
self.add_done_callback(lambda f: f.greenlet.switch())
def result(self):
while True:
if self.done():
return super().result()
self.greenlet.parent.switch()
@asyncio.coroutine
def redis_open(f):
connection = yield from asyncio_redis.Connection.create(host='localhost', port=6379)
f.set_result(connection)
f.greenlet.switch()
@asyncio.coroutine
def redis_subscribe(f):
connection = yield from asyncio_redis.Connection.create(host='localhost', port=6379)
subscriber = yield from connection.start_subscribe()
yield from subscriber.subscribe([ 'foobar' ])
f.set_result(subscriber)
f.greenlet.switch()
def ws_recv_msg(g):
g.has_ws_msg = True
g.switch()
@asyncio.coroutine
def redis_wait(subscriber, f):
reply = yield from subscriber.next_published()
f.set_result(reply.value)
f.greenlet.switch()
@asyncio.coroutine
def redis_publish(connection, msg):
yield from connection.publish('foobar', msg.decode('utf-8'))
def application(env, sr):
ws_scheme = 'ws'
if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https':
ws_scheme = 'wss'
if env['PATH_INFO'] == '/':
sr('200 OK', [('Content-Type','text/html')])
return ("""
<html>
<head>
<script language="Javascript">
var s = new WebSocket("%s://%s/foobar/");
s.onopen = function() {
alert("connected !!!");
s.send("ciao");
};
s.onmessage = function(e) {
var bb = document.getElementById('blackboard')
var html = bb.innerHTML;
bb.innerHTML = html + '<br/>' + e.data;
};
s.onerror = function(e) {
alert(e);
}
s.onclose = function(e) {
alert("connection closed");
}
function invia() {
var value = document.getElementById('testo').value;
s.send(value);
}
</script>
</head>
<body>
<h1>WebSocket</h1>
<input type="text" id="testo"/>
<input type="button" value="invia" onClick="invia();"/>
<div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto">
</div>
</body>
</html>
""" % (ws_scheme, env['HTTP_HOST'])).encode()
elif env['PATH_INFO'] == '/favicon.ico':
return b""
elif env['PATH_INFO'] == '/foobar/':
uwsgi.websocket_handshake()
print("websockets...")
# a future for waiting for redis connection
f = GreenFuture()
asyncio.Task(redis_subscribe(f))
# the result() method will switch greenlets if needed
subscriber = f.result()
# open another redis connection for publishing messages
f0 = GreenFuture()
t = asyncio.Task(redis_open(f0))
connection = f0.result()
myself = greenlet.getcurrent()
myself.has_ws_msg = False
# start monitoring websocket events
asyncio.get_event_loop().add_reader(uwsgi.connection_fd(), ws_recv_msg, myself)
# add a 4 seconds timer to manage ping/pong
asyncio.get_event_loop().call_later(4, ws_recv_msg, myself)
# add a coroutine for redis messages
f = GreenFuture()
asyncio.Task(redis_wait(subscriber, f))
# switch again
f.greenlet.parent.switch()
while True:
# any redis message in the queue ?
if f.done():
msg = f.result()
uwsgi.websocket_send("[%s] %s" % (time.time(), msg))
# restart coroutine
f = GreenFuture()
asyncio.Task(redis_wait(subscriber, f))
if myself.has_ws_msg:
myself.has_ws_msg = False
msg = uwsgi.websocket_recv_nb()
if msg:
asyncio.Task(redis_publish(connection, msg))
# switch again
f.greenlet.parent.switch()
+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-02-26'
s.date = '2014-06-01'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+43 -1
View File
@@ -765,6 +765,10 @@ struct uwsgi_cache_item {
uint64_t prev;
// next same-hash item
uint64_t next;
// previous lru item
uint64_t lru_prev;
// next lru item
uint64_t lru_next;
// key characters follows...
char key[];
} __attribute__ ((__packed__));
@@ -819,6 +823,13 @@ struct uwsgi_cache {
struct uwsgi_lock_item *lock;
struct uwsgi_cache *next;
int ignore_full;
uint64_t next_scan;
int purge_lru;
uint64_t lru_head;
uint64_t lru_tail;
};
struct uwsgi_option {
@@ -886,6 +897,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
@@ -1555,6 +1567,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;
};
@@ -2695,6 +2712,17 @@ 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;
};
struct uwsgi_rpc {
@@ -2928,6 +2956,9 @@ struct uwsgi_mule {
time_t user_harakiri;
char name[0xff];
time_t cursed_at;
time_t no_mercy_at;
};
struct uwsgi_mule_farm {
@@ -2995,6 +3026,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);
@@ -3760,6 +3792,8 @@ int uwsgi_logic_opt_if_plugin(char *, char *);
int uwsgi_logic_opt_if_not_plugin(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 *);
@@ -4044,6 +4078,7 @@ void emperor_stop(struct uwsgi_instance *);
void emperor_curse(struct uwsgi_instance *);
void emperor_respawn(struct uwsgi_instance *, time_t);
void emperor_add(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *);
void emperor_back_to_ondemand(struct uwsgi_instance *);
void uwsgi_exec_command_with_args(char *);
@@ -4131,7 +4166,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();
@@ -4157,6 +4191,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
@@ -4409,6 +4444,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 *);
@@ -4651,6 +4687,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 {
@@ -4668,6 +4707,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 *);
@@ -4695,6 +4736,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);
+28 -9
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '2.0.2'
uwsgi_version = '2.0.5'
import os
import re
@@ -331,6 +331,13 @@ def build_uwsgi(uc, print_only=False, gcll=None):
uwsgi_config_py = uwsgi_config_py_content.encode('hex')
open('core/config_py.c', 'w').write('char *uwsgi_config_py = "%s";\n' % uwsgi_config_py);
gcc_list.append('core/config_py')
additional_sources = os.environ.get('UWSGI_ADDITIONAL_SOURCES')
if not additional_sources:
additional_sources = uc.get('additional_sources')
if additional_sources:
for item in additional_sources.split(','):
gcc_list.append(item)
cflags.append('-DUWSGI_CFLAGS=\\"%s\\"' % uwsgi_cflags)
cflags.append('-DUWSGI_BUILD_DATE="\\"%s\\""' % time.strftime("%d %B %Y %H:%M:%S"))
@@ -367,6 +374,15 @@ def build_uwsgi(uc, print_only=False, gcll=None):
if len(kv) > 1:
p = kv[1]
p = p.strip()
if p.startswith('http://') or p.startswith('https://') or p.startswith('git://') or p.startswith('ssh://'):
git_dir = p.split('/').pop()
if not os.path.isdir(git_dir):
if os.system('git clone %s' % p) != 0:
sys.exit(1)
else:
if os.system('cd %s ; git pull' % git_dir) != 0:
sys.exit(1)
p = git_dir
path = os.path.abspath(p)
else:
p = kv[0]
@@ -510,13 +526,6 @@ def build_uwsgi(uc, print_only=False, gcll=None):
for ef in binary_list:
gcc_list.append("%s.o" % ef)
additional_sources = os.environ.get('UWSGI_ADDITIONAL_SOURCES')
if not additional_sources:
additional_sources = uc.get('additional_sources')
if additional_sources:
for item in additional_sources.split(','):
gcc_list.append(item)
if compile_queue:
for t in thread_compilers:
compile_queue.put((None, None))
@@ -1049,7 +1058,7 @@ class uConf(object):
self.embed_config = None
if uwsgi_os == 'Linux':
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')
@@ -1275,6 +1284,16 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
up = {}
if path.startswith('http://') or path.startswith('https://') or path.startswith('git://') or path.startswith('ssh://'):
git_dir = path.split('/').pop()
if not os.path.isdir(git_dir):
if os.system('git clone %s' % path) != 0:
sys.exit(1)
else:
if os.system('cd %s ; git pull' % git_dir) != 0:
sys.exit(1)
path = os.path.abspath(git_dir)
if os.path.isfile(path):
bname = os.path.basename(path)
# override path