Compare commits

..
130 Commits
Author SHA1 Message Date
Unbit fe8ee7c7b3 uWSGI 1.9.4 2013-03-30 16:29:51 +01:00
Unbit cd382c6bc0 added rpcblob/rpcnext 2013-03-30 16:06:47 +01:00
Unbit e68296c293 a bit of cosmetic for uwsgi.h 2013-03-30 09:28:06 +01:00
Unbit cc189feae5 added uwsgi_register_signal to v8 2013-03-30 09:25:50 +01:00
unbit 18e19027a1 Merge pull request #207 from prymitive/legion_api
refactored legion opt functions to be more plugin friendly
2013-03-30 00:58:46 -07:00
Łukasz Mierzwa 2d2e0e4757 refactored legion opt functions to be more plugin friendly 2013-03-29 23:33:33 +01:00
Unbit a9f50d79f9 start 1.9.4 2013-03-29 21:24:56 +01:00
Unbit 0ccd31bee0 fixed reloading when in Go mode 2013-03-29 21:24:41 +01:00
Unbit 3ea82b2bcd do not differentiate reload when uWSGI is build as shared library 2013-03-29 21:21:46 +01:00
Unbit 6dad7b3ced ported the cplusplus plugin to the new api 2013-03-29 19:43:03 +01:00
Unbit f96ebd2b07 Merge branch 'master' of github.com:unbit/uwsgi 2013-03-29 19:37:53 +01:00
Unbit b8d0e7a3ac beta quality v8 plugin 2013-03-29 19:37:33 +01:00
unbit 14cca3d497 Merge pull request #204 from prymitive/legion_join_hook
legion join hook
2013-03-29 06:02:42 -07:00
Łukasz Mierzwa c343ca0cc3 legion join hook 2013-03-29 14:01:02 +01:00
Unbit 527d371bda fixed multiple mules event handling 2013-03-29 13:34:48 +01:00
Unbit b87a800a9a avoid resetting uwsgi.mywid in the master 2013-03-29 13:24:33 +01:00
Unbit e406993ed1 fixed typo 2013-03-29 12:51:52 +01:00
Unbit eeff935fc9 fixed signal handling in non-workers 2013-03-29 12:50:56 +01:00
Unbit 0791394f1a official support for SmartOS 2013-03-29 08:12:58 +00:00
unbit 082a407b06 Merge pull request #201 from prymitive/cache_restore_items_count
update cache items count after restore
2013-03-28 15:23:22 -07:00
Łukasz Mierzwa 8a89b49df1 update cache items count after restore 2013-03-28 23:20:17 +01:00
unbit 2314b9cbab Merge pull request #200 from jbert/master
Fix segfault in psgi plugin
2013-03-28 15:02:26 -07:00
John Berthels d0cca85c83 fix segfault in psgi handler after taking early-exit error path in coroae_accept_request 2013-03-28 17:29:00 +00:00
unbit 6a7a5cbcba Merge pull request #199 from prymitive/cache_stats_missin_list_close
missing list close in cache stats
2013-03-28 09:28:02 -07:00
Łukasz Mierzwa ecccc82cc8 missing list close 2013-03-28 16:56:31 +01:00
Unbit 02693489fe fixed php headers generation 2013-03-28 12:13:23 +01:00
Unbit 0f5dba5828 apache 2.4 support in mod_proxy_uwsgi 2013-03-28 11:19:13 +01:00
Unbit e528d4c4b7 implemented --emperor-tyrant-nofollow 2013-03-28 10:18:01 +01:00
Unbit 52a3af6acf prepare for uWSGI 1.9.3 2013-03-28 10:05:24 +01:00
Unbit dcefea9958 added rpcret routing action 2013-03-28 10:03:33 +01:00
Unbit 59121ff834 added --lua-load, fixed lua rpc memory leak 2013-03-28 09:21:47 +01:00
Unbit 7f5bb6d472 allows usage of configurators in the emperor 2013-03-28 09:07:15 +01:00
Unbit 639c1a508c support for lua ordered arrays in configurations 2013-03-28 09:00:10 +01:00
Unbit 417a26fc64 added config.lua example 2013-03-28 08:02:32 +01:00
Unbit 210ccd0063 allows configuration via lua 2013-03-28 08:02:07 +01:00
unbit 1bf0162d38 Merge pull request #196 from ryankask/jvm-plugin-import
Fix imports for the JVM plugin
2013-03-27 02:53:03 -07:00
Ryan Kaskel e93027fd7e Fix imports for JVM plugin. 2013-03-27 09:48:14 +00:00
Unbit 807060706f prepare for 1.9.2 2013-03-26 20:05:33 +01:00
Unbit a317f88d3c added the cache command to the ssi plugin 2013-03-26 20:03:37 +01:00
Unbit e17a7f0701 fixed a typo 2013-03-26 19:53:32 +01:00
Unbit db325eb9fe fixed readline() + post_buffering 2013-03-26 17:54:42 +01:00
Unbit b41a4c8c3b fixed python3 headers management 2013-03-26 16:45:57 +01:00
Unbit 73b4d11d18 added ssi router 2013-03-26 15:38:45 +01:00
Unbit 8162b87287 beta quality ssi plugin 2013-03-26 15:19:23 +01:00
Unbit 70e9e4f3ee added printenv 2013-03-26 12:24:17 +01:00
Unbit e61ae376b3 other improvements in the ssi plugin 2013-03-26 11:48:51 +01:00
Unbit 2d57b0e926 added preliminary ssi support 2013-03-26 11:33:00 +01:00
Unbit ae683af07a completed the geoip plugin [2] 2013-03-26 07:11:27 +01:00
Unbit 3c4f6a9171 completed the geoip plugin 2013-03-26 07:05:02 +01:00
Unbit 39986e546c fixed GeoIP plugin 2013-03-26 06:47:18 +01:00
Unbit 2e81a80f7b added preliminary geoip plugin 2013-03-25 19:11:20 +01:00
Unbit fcb3aa38c8 allows freeing route vars 2013-03-25 18:15:29 +01:00
Unbit 00a38d8ec5 fixed routing vars management 2013-03-25 18:10:41 +01:00
Unbit 07a0ab4227 pluggable routing vars 2013-03-25 18:05:57 +01:00
Unbit d4a9a2c543 fixed exceptions in the fiber plugin 2013-03-25 17:46:29 +01:00
Unbit 2b523fc60d added query string management functions 2013-03-25 10:21:20 +01:00
Unbit 0c26928236 added cookie management and --route-run 2013-03-25 09:56:53 +01:00
Unbit 8401e56a22 added 'empty' internal routing condition 2013-03-25 09:04:30 +01:00
Unbit 5109f9ae0b back to libxml2 default 2013-03-25 08:47:22 +01:00
Unbit c9bc06669a .ini file can backreference themselves 2013-03-25 08:47:00 +01:00
unbit a83fb2672c Merge pull request #189 from xtfxme/enhance/189-dashful-endif-endfor
Routing table appear to go nuts when used within a FOR loop
2013-03-24 23:18:50 -07:00
C Anthony Risinger 8f9ecb44d9 [#189] endfor/endif => end-for/end-if ...i know i'm not alone 2013-03-24 15:45:04 -05:00
Unbit bfcc09a8de prepare for cookie management in internal routing 2013-03-24 21:05:21 +01:00
Unbit f8a8c997db removed cache type in routing instruction 2013-03-24 20:30:56 +01:00
Unbit 132b996f30 added cachestore routing instruction 2013-03-24 19:43:41 +01:00
Unbit 12f970cdfb prepare for routing-governed caching 2013-03-24 19:24:13 +01:00
Unbit 9afa963225 prepare for gem 1.9.1 2013-03-24 11:39:44 +01:00
Unbit ed368d0d51 fixed signal copy on write 2013-03-24 10:30:01 +01:00
Unbit 21f21d34ba fixed legion scrolls api 2013-03-24 09:52:16 +01:00
Unbit f37823c809 completed --emperor-on-demand-dir 2013-03-23 10:34:36 +01:00
Unbit 6eaefcff5e added build profile for ubuntu ppa 2013-03-23 06:15:55 +01:00
Unbit 79235c1cc3 another memory report fix for Unbit 2013-03-23 04:41:58 +01:00
Unbit 29135f014b Unbit fixes 2013-03-23 04:11:33 +01:00
Unbit 13c998fb8d added uwsgi_main.c 2013-03-23 03:56:56 +01:00
Unbit 71bfd0d636 prepare for uWSGI 1.9.1 2013-03-23 03:52:19 +01:00
Unbit 51e99e0f5a removed UWSGI_INI 2013-03-23 03:15:33 +01:00
Unbit 66e7beefc4 fixed rack exceptions management 2013-03-22 19:53:47 +01:00
Unbit f2b10c35b7 fixed build without pcre 2013-03-22 11:15:13 +01:00
Unbit e951eba96c improved emperor on demand mode 2013-03-22 14:56:49 +01:00
Unbit 9fe18da7a3 added startswith endswith and regexp/re routing instructions 2013-03-22 10:14:34 +01:00
Unbit a14fdead14 added rpc router instruction 2013-03-22 09:26:11 +01:00
Unbit 9a671a4991 added %V magic var (contains UWSGI_VERSION) 2013-03-21 17:18:41 +01:00
Unbit 8f5e7b124a added --emperor-on-demand-exec 2013-03-21 16:55:23 +01:00
Unbit 5f7464d015 implemented --emperor-on-demand-ext 2013-03-21 16:42:24 +01:00
Unbit 238dd6c1d0 added a commodity mongodb plugin for system without mongoclient shared library 2013-03-21 15:18:09 +01:00
Roberta Giordano 82e4e54edc removed some unbit useless definition 2013-03-21 07:59:45 +01:00
Unbit 9946cbb9da added 'equal' routing func 2013-03-21 06:54:36 +01:00
Unbit 2474adb23a completed routing cache instruction 2013-03-21 06:31:26 +01:00
Unbit f40757bb67 free carbon_address memory 2013-03-21 06:19:31 +01:00
unbit bc29479930 Merge pull request #188 from prymitive/carbon_resolve_hostnames
allow connecting to carbon server using hostname resolved on every cycle...
2013-03-20 22:04:50 -07:00
Łukasz Mierzwa 4ec78edaa3 allow connecting to carbon server using hostname resolved on every cycle, fixes #186 2013-03-20 21:47:56 +01:00
Unbit aa0271158d allows build profiles to be stored on http/https/ftp 2013-03-20 19:44:46 +01:00
Unbit c0aa5bfe17 added the crypto logger 2013-03-20 16:22:40 +01:00
Unbit 3f8e6a8cc8 completed xslt plugin 2013-03-19 17:53:12 +01:00
Unbit ef0316fc2e Merge branch 'master' of github.com:unbit/uwsgi 2013-03-19 15:18:33 +01:00
Unbit 7274efab15 added xslt plugin 2013-03-19 15:18:03 +01:00
Unbit e44b62b6b2 on demand vassals 2013-03-18 15:42:34 +01:00
Unbit 31c041d435 added --exec-post-app 2013-03-18 13:32:09 +01:00
Unbit 35f47371ed first part of uwsgi_legion_scrolls() function api 2013-03-18 13:22:10 +01:00
unbit c5412e1620 Merge pull request #185 from guokr/master
Supporting JVM/Ring installing in Virtualenv
2013-03-18 03:09:03 -07:00
Mingli a9b4c52811 supporting virtualenv 2013-03-18 17:53:04 +08:00
Roberto De Ioris 5ce40b6ac8 fixed --req-logger after reload 2013-03-18 09:19:25 +01:00
Unbit b93dcbf46f removed download_url from setup.py 2013-03-17 08:10:12 +01:00
Unbit 8051a2bc98 prepare for 1.9 release 2013-03-17 07:15:24 +01:00
Unbit 78d8b221fc added --gevent-monkey-patch 2013-03-17 07:14:54 +01:00
Unbit d51cada284 second (and last i hope) part of mongrel2 support refactoring 2013-03-16 18:24:25 +01:00
Unbit 389eef9e88 first part of mongrel2 support refactoring 2013-03-16 18:02:11 +01:00
Unbit 270fb0c50d avoid routing loop 2013-03-16 16:48:26 +01:00
Unbit e7e9dfee88 fixed DragonFlyBSD support 2013-03-16 15:45:49 +01:00
Unbit 3bafae276d improved binary detection path on cygwin 2013-03-16 12:33:00 +01:00
Unbit cfebe2927d fixed lazy mode 2013-03-15 13:47:29 +01:00
Unbit 1d4294a845 added some comment for the statsd plugin 2013-03-15 11:34:19 +01:00
Unbit 12cfdd9864 added stats_pusher_statsd plugin 2013-03-15 11:32:08 +01:00
Unbit add930c517 fixed uuid support in cygwin 2013-03-15 07:31:41 +01:00
Unbit 32972978be added java support for cygwin 2013-03-13 17:50:56 +01:00
Unbit c8bad3550e added proper locking to windows 2013-03-13 15:51:14 +01:00
Unbit ecc55d789d added proper-locking to poll event mode 2013-03-13 15:03:30 +01:00
Unbit 88555e2c20 improved poll() support 2013-03-13 14:33:38 +01:00
Unbit ec2bfcd302 allows building router basicauth on cygwin 2013-03-13 11:14:32 +01:00
Unbit f1f81ed4c4 fixed python3 build 2013-03-13 11:00:05 +01:00
Unbit 87933cca26 another series of cygwin fixes 2013-03-13 10:51:33 +01:00
Unbit 2dcd8624a2 psgi support for windows 2013-03-13 10:12:24 +01:00
Unbit 7fcef76bbe experimental windows/cygwin support 2013-03-13 09:44:32 +01:00
Unbit 2a5c4e938d fixed requets overwrite in PATH_INFO rewrite (fixed typo) 2013-03-12 15:57:44 +01:00
Unbit 274eae27ef fixed requets overwrite in PATH_INFO rewrite 2013-03-12 15:56:30 +01:00
Unbit 207220bc50 fixed #180 2013-03-12 11:45:03 +01:00
Unbit fb8c4439c7 the whole ring test suite passes 2013-03-12 11:15:45 +01:00
Roberto De Ioris 894be9c41e let the /sequence ring test pass 2013-03-12 09:42:13 +01:00
unbit 0a4bff8963 Merge pull request #182 from guokr/master
Ring plugin tests
2013-03-12 00:27:11 -07:00
Mingli d515f3e279 add tests for ring plugin 2013-03-12 14:47:51 +08:00
103 changed files with 6145 additions and 2155 deletions
+4
View File
@@ -1,5 +1,9 @@
*.o
*.py[co]
*.class
*.jar
/uwsgi
/uwsgibuild.*
/t/ring/target
+43
View File
@@ -217,6 +217,45 @@ static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
return OK;
}
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
{
apr_pool_t *pool;
request_rec *rp;
apr_pool_create(&pool, c->pool);
rp = apr_pcalloc(pool, sizeof(*r));
rp->pool = pool;
rp->status = HTTP_OK;
rp->headers_in = apr_table_make(pool, 50);
rp->subprocess_env = apr_table_make(pool, 50);
rp->headers_out = apr_table_make(pool, 12);
rp->err_headers_out = apr_table_make(pool, 5);
rp->notes = apr_table_make(pool, 5);
rp->server = r->server;
rp->log = r->log;
rp->proxyreq = r->proxyreq;
rp->request_time = r->request_time;
rp->connection = c;
rp->output_filters = c->output_filters;
rp->input_filters = c->input_filters;
rp->proto_output_filters = c->output_filters;
rp->proto_input_filters = c->input_filters;
rp->useragent_ip = c->client_ip;
rp->useragent_addr = c->client_addr;
rp->request_config = ap_create_request_config(pool);
proxy_run_create_req(r, rp);
return rp;
}
#endif
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
{
@@ -337,7 +376,11 @@ static int uwsgi_handler(request_rec *r, proxy_worker *worker,
}
// ADD PATH_INFO
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
size_t w_len = strlen(worker->s->name);
#else
size_t w_len = strlen(worker->name);
#endif
char *u_path_info = r->filename + 6 + w_len;
int delta = 0;
if (u_path_info[0] != '/') {
-1
View File
@@ -1 +0,0 @@
object file for embedded files will be put here
-5
View File
@@ -1,18 +1,13 @@
[uwsgi]
xml = auto
ini = true
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
snmp = true
ssl = auto
async = true
ldap = auto
pcre = auto
routing = auto
alarm = auto
ipv6 = false
debug = false
unbit = false
xml_implementation = libxml2
+34
View File
@@ -0,0 +1,34 @@
[uwsgi]
xml = true
yaml = true
json = true
sqlite3 = true
zeromq = true
ssl = true
ldap = true
pcre = true
routing = true
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = libyaml
malloc_implementation = libc
extras =
plugins =
bin_name = /usr/lib/libuwsgi.so
append_version = ubuntu
plugin_dir = /usr/lib/uwsgi
embedded_plugins =
as_shared_library = true
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
+6
View File
@@ -0,0 +1,6 @@
[uwsgi]
main_plugin = python,gevent
inherit = base
plugins = jvm,ring
plugin_dir = .
+13 -5
View File
@@ -1,26 +1,34 @@
[uwsgi]
xml = true
ini = true
yaml = true
json = false
sqlite3 = false
zeromq = false
ldap = true
ssl = true
ldap = false
pcre = true
routing = true
alarm = true
debug = false
unbit = true
xml_implementation = expat
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
bin_name = /opt/unbit/bin/uwsgi
bin_name = /opt/unbit/uwsgi19/lib/libuwsgi.so
append_version = unbit
plugin_dir = /opt/unbit/uwsgi_plugins
plugin_dir = /opt/unbit/uwsgi19/plugins
embedded_plugins =
as_shared_library = true
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
-1
View File
@@ -1,6 +1,5 @@
[uwsgi]
inherit = unbit
json = false
embedded_plugins = python
bin_name = ../bin/uwsgi
plugin_dir = ../bin/uwsgi_plugins
+24
View File
@@ -0,0 +1,24 @@
require 'socket'
require 'openssl'
secret = 'ciaociao'
iv = ''
address = '127.0.0.1'
port = 1717
algo = 'bf-cbc'
s = UDPSocket.new
s.bind(address, port)
cipher = OpenSSL::Cipher.new(algo)
cipher.decrypt
cipher.key = secret + ("\0" * (cipher.key_len - secret.length))
cipher.iv = iv + ("0" * (cipher.iv_len - iv.length))
loop do
msg, sender = s.recvfrom(8192)
cipher.reset
begin
puts cipher.update(msg) + cipher.final
rescue
end
end
+26
View File
@@ -328,3 +328,29 @@ int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modi
ub->buf[3] = modifier2;
return 0;
}
struct uwsgi_buffer *uwsgi_buffer_from_file(char *filename) {
struct stat st;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
return NULL;
}
if (fstat(fd, &st)) {
close(fd);
return NULL;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(st.st_size);
ssize_t len = read(fd, ub->buf, st.st_size);
close(fd);
if (len != st.st_size) {
uwsgi_buffer_destroy(ub);
return NULL;
}
ub->pos = len;
return ub;
}
+2 -1
View File
@@ -533,7 +533,8 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
}
}
uwsgi_log("[uwsgi-cache] restored %llu items\n", restored);
uc->n_items = restored;
uwsgi_log("[uwsgi-cache] restored %llu items\n", uc->n_items);
}
int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *val, uint64_t vallen, uint64_t expires, uint64_t flags) {
+33
View File
@@ -0,0 +1,33 @@
#include <uwsgi.h>
/*
pluggable configuration system
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) {
struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators;
while(uc) {
if (!strcmp(uc->name, name)) {
return uc;
}
old_uc = uc;
uc = uc->next;
}
uc = uwsgi_calloc(sizeof(struct uwsgi_configurator));
uc->name = name;
uc->func = func;
if (old_uc) {
old_uc->next = uc;
}
else {
uwsgi.configurators = uc;
}
return uc;
}
+81
View File
@@ -0,0 +1,81 @@
#include <uwsgi.h>
/*
cookie management functions (mainly used by the internal routing subsystem)
*/
static char *check_cookie(char *cookie, uint16_t cookie_len, char *key, uint16_t keylen, uint16_t *vallen) {
uint16_t orig_cookie_len = cookie_len-1;
// first lstrip white spaces
char *ptr = cookie;
uint16_t i;
for(i=0;i<cookie_len;i++) {
if (isspace((int)ptr[i])) {
cookie++;
cookie_len--;
}
else {
break;
}
}
// then rstrip (skipping the first char...)
for(i=orig_cookie_len;i>0;i--) {
if (isspace((int)ptr[i])) {
cookie_len--;
}
else {
break;
}
}
// now search for the first equal sign
char *equal = memchr(cookie, '=', cookie_len);
if (!equal) return NULL;
if (uwsgi_strncmp(key, keylen, cookie, equal-cookie)) {
return NULL;
}
cookie_len -= (equal-cookie)+1;
if (cookie_len == 0) return NULL;
*vallen = cookie_len;
return equal+1;
}
char *uwsgi_get_cookie(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
uint16_t i;
char *cookie = wsgi_req->cookie;
uint16_t cookie_len = 0;
char *ptr = wsgi_req->cookie;
//start splitting by ;
for(i=0;i<wsgi_req->cookie_len;i++) {
if (!cookie) {
cookie = ptr + i;
}
if (ptr[i] == ';') {
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
if (value) {
return value;
}
cookie_len = 0;
cookie = NULL;
}
else {
cookie_len++;
}
}
if (cookie_len > 0) {
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
if (value) {
return value;
}
}
return NULL;
}
+276 -55
View File
@@ -122,19 +122,101 @@ void uwsgi_emperor_blacklist_remove(char *id) {
struct uwsgi_emperor_scanner *emperor_scanners;
static int has_extra_extension(char *name) {
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while(usl) {
if (uwsgi_endswith(name, usl->value)) {
return 1;
}
usl = usl->next;
}
return 0;
}
int uwsgi_emperor_is_valid(char *name) {
if (uwsgi_endswith(name, ".xml") || uwsgi_endswith(name, ".ini") || uwsgi_endswith(name, ".yml") || uwsgi_endswith(name, ".yaml") || uwsgi_endswith(name, ".js") || uwsgi_endswith(name, ".json")) {
if (uwsgi_endswith(name, ".xml") || uwsgi_endswith(name, ".ini") || uwsgi_endswith(name, ".yml") || uwsgi_endswith(name, ".yaml") || uwsgi_endswith(name, ".js") || uwsgi_endswith(name, ".json") || has_extra_extension(name)) {
if (strlen(name) < 0xff) {
return 1;
}
}
return 0;
}
static char *emperor_check_on_demand_socket(char *filename) {
size_t len = 0;
if (uwsgi.emperor_on_demand_extension) {
char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension);
int fd = open(tmp, O_RDONLY);
free(tmp);
if (fd < 0) return NULL;
char *ret = uwsgi_read_fd(fd, &len, 1);
close(fd);
// change the first non prinabel character to 0
size_t i;
for(i=0;i<len;i++) {
if (ret[i] < 32) {
ret[i] = 0;
break;
}
}
if (ret[0] == 0) {
free(ret);
return NULL;
}
return ret;
}
else if (uwsgi.emperor_on_demand_directory) {
// we need to build the socket path automagically
char *start_of_vassal_name = uwsgi_get_last_char(filename, '/');
if (!start_of_vassal_name) {
start_of_vassal_name = filename;
}
else {
start_of_vassal_name++;
}
char *last_dot = uwsgi_get_last_char(filename, '.');
if (!last_dot) return NULL;
return uwsgi_concat4n(uwsgi.emperor_on_demand_directory, strlen(uwsgi.emperor_on_demand_directory), "/", 1, start_of_vassal_name, last_dot - start_of_vassal_name, ".socket", 7);
}
else if (uwsgi.emperor_on_demand_exec) {
int cpipe[2];
if (pipe(cpipe)) {
uwsgi_error("emperor_check_on_demand_socket()pipe()");
return NULL;
}
char *cmd = uwsgi_concat4(uwsgi.emperor_on_demand_exec, " \"", filename, "\"");
int r = uwsgi_run_command(cmd, NULL, cpipe[1]);
free(cmd);
if (r < 0) {
close(cpipe[0]);
close(cpipe[1]);
return NULL;
}
char *ret = uwsgi_read_fd(cpipe[0], &len, 1);
close(cpipe[0]);
close(cpipe[1]);
// change the first non prinabel character to 0
size_t i;
for(i=0;i<len;i++) {
if (ret[i] < 32) {
ret[i] = 0;
break;
}
}
if (ret[0] == 0) {
free(ret);
return NULL;
}
return ret;
}
return NULL;
}
// this is the monitor for non-glob directories
void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
struct uwsgi_instance *ui_current;
@@ -160,10 +242,27 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
ui_current = emperor_get(de->d_name);
uid_t t_uid = st.st_uid;
gid_t t_gid = st.st_gid;
if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) {
struct stat lst;
if (lstat(de->d_name, &lst)) {
uwsgi_error("[emperor-tyrant]/lstat()");
if (ui_current) {
uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", de->d_name);
emperor_stop(ui_current);
}
continue;
}
t_uid = lst.st_uid;
t_gid = lst.st_gid;
}
if (ui_current) {
// check if uid or gid are changed, in such case, stop the instance
if (uwsgi.emperor_tyrant) {
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
if (t_uid != ui_current->uid || t_gid != ui_current->gid) {
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", de->d_name);
emperor_stop(ui_current);
continue;
@@ -175,7 +274,9 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
}
}
else {
emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
char *socket_name = emperor_check_on_demand_socket(de->d_name);
emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name);
if (socket_name) free(socket_name);
}
}
closedir(dir);
@@ -235,10 +336,27 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
ui_current = emperor_get(g.gl_pathv[i]);
uid_t t_uid = st.st_uid;
gid_t t_gid = st.st_gid;
if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) {
struct stat lst;
if (lstat(g.gl_pathv[i], &lst)) {
uwsgi_error("[emperor-tyrant]/lstat()");
if (ui_current) {
uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
emperor_stop(ui_current);
}
continue;
}
t_uid = lst.st_uid;
t_gid = lst.st_gid;
}
if (ui_current) {
// check if uid or gid are changed, in such case, stop the instance
if (uwsgi.emperor_tyrant) {
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
if (t_uid != ui_current->uid || t_gid != ui_current->gid) {
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
emperor_stop(ui_current);
continue;
@@ -250,7 +368,9 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
}
}
else {
emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]);
emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name);
if (socket_name) free(socket_name);
}
}
@@ -377,6 +497,22 @@ struct uwsgi_instance *emperor_get_by_fd(int fd) {
return NULL;
}
struct uwsgi_instance *emperor_get_by_socket_fd(int fd) {
struct uwsgi_instance *c_ui = ui;
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
// over engineering...
if (c_ui->on_demand_fd != -1 && c_ui->on_demand_fd == fd) {
return c_ui;
}
}
return NULL;
}
struct uwsgi_instance *emperor_get(char *name) {
@@ -430,6 +566,10 @@ void emperor_del(struct uwsgi_instance *c_ui) {
uwsgi.emperor_broodlord_count--;
}
if (c_ui->socket_name) {
free(c_ui->socket_name);
}
free(c_ui);
}
@@ -478,17 +618,10 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
uwsgi_log("[emperor] reload the uwsgi instance %s\n", c_ui->name);
}
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) {
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name) {
struct uwsgi_instance *c_ui = ui;
struct uwsgi_instance *n_ui = NULL;
pid_t pid;
char **vassal_argv;
char *uef;
char **uenvs;
int counter;
char *colon = NULL;
int i;
struct timeval tv;
#ifdef UWSGI_DEBUG
@@ -544,8 +677,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
c_ui = c_ui->ui_next;
}
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
memset(n_ui, 0, sizeof(struct uwsgi_instance));
n_ui = uwsgi_calloc(sizeof(struct uwsgi_instance));
if (config) {
n_ui->use_config = 1;
@@ -576,10 +708,60 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
n_ui->first_run = uwsgi_now();
n_ui->last_run = n_ui->first_run;
n_ui->on_demand_fd = -1;
if (socket_name) {
n_ui->socket_name = uwsgi_str(socket_name);
}
n_ui->pid = -1;
// ok here we check if we need to bind to the specified socket or continue with the activation
if (socket_name) {
char *tcp_port = strchr(socket_name, ':');
if (tcp_port) {
// disable deferred accept for this socket
int current_defer_accept = uwsgi.no_defer_accept;
uwsgi.no_defer_accept = 1;
n_ui->on_demand_fd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port);
uwsgi.no_defer_accept = current_defer_accept;
}
else {
n_ui->on_demand_fd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
if (n_ui->on_demand_fd < 0) {
uwsgi_error("emperor_add()/bind()");
free(n_ui);
c_ui->ui_next = NULL;
return;
}
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd);
uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name);
return;
}
if (uwsgi_emperor_vassal_start(n_ui)) {
// clear the vassal
free(n_ui);
c_ui->ui_next = NULL;
}
}
int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
int i;
char *colon = NULL;
int counter;
char **uenvs;
char *uef;
char **vassal_argv;
pid_t pid;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
uwsgi_error("socketpair()");
goto clear;
return -1;
}
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]);
@@ -587,7 +769,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
if (n_ui->use_config) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
uwsgi_error("socketpair()");
goto clear;
return -1;
}
}
@@ -606,6 +788,11 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
n_ui->pid = pid;
// close the right side of the pipe
close(n_ui->pipe[1]);
// close the "on demand" socket
if (n_ui->on_demand_fd > -1) {
close(n_ui->on_demand_fd);
n_ui->on_demand_fd = -1;
}
if (n_ui->use_config) {
close(n_ui->pipe_config[1]);
}
@@ -625,13 +812,13 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
}
return;
return 0;
}
else {
if (uwsgi.emperor_tyrant) {
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name);
if (setgid(gid)) {
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name);
if (setgid(n_ui->gid)) {
uwsgi_error("setgid()");
exit(1);
}
@@ -640,7 +827,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
exit(1);
}
if (setuid(uid)) {
if (setuid(n_ui->uid)) {
uwsgi_error("setuid()");
exit(1);
}
@@ -720,7 +907,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
vassal_argv[0] = uwsgi.binary_path;
if (uwsgi.emperor_broodlord) {
colon = strchr(name, ':');
colon = strchr(n_ui->name, ':');
if (colon) {
colon[0] = 0;
}
@@ -728,34 +915,43 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
// initialize to a default value
vassal_argv[1] = "--inherit";
if (!strcmp(name + (strlen(name) - 4), ".xml"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml"))
vassal_argv[1] = "--xml";
if (!strcmp(name + (strlen(name) - 4), ".ini"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini"))
vassal_argv[1] = "--ini";
if (!strcmp(name + (strlen(name) - 4), ".yml"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml"))
vassal_argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml"))
vassal_argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 3), ".js"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js"))
vassal_argv[1] = "--json";
if (!strcmp(name + (strlen(name) - 5), ".json"))
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json"))
vassal_argv[1] = "--json";
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while(usl) {
if (uwsgi_endswith(n_ui->name, usl->value)) {
vassal_argv[1] = "--config";
break;
}
usl = usl->next;
}
if (colon) {
colon[0] = ':';
}
vassal_argv[2] = name;
vassal_argv[2] = n_ui->name;
if (uwsgi.emperor_magic_exec) {
if (!access(name, R_OK | X_OK)) {
vassal_argv[2] = uwsgi_concat2("exec://", name);
if (!access(n_ui->name, R_OK | X_OK)) {
vassal_argv[2] = uwsgi_concat2("exec://", n_ui->name);
}
}
if (n_ui->use_config) {
vassal_argv[2] = uwsgi_concat2("emperor://", name);
vassal_argv[2] = uwsgi_concat2("emperor://", n_ui->name);
}
counter = 3;
@@ -768,18 +964,29 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
vassal_argv[counter] = NULL;
// disable stdin
int stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
// disable stdin OR map it to the "on demand" socket
if (n_ui->on_demand_fd > -1) {
if (n_ui->on_demand_fd != 0) {
if (dup2(n_ui->on_demand_fd, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(n_ui->on_demand_fd);
}
}
if (stdin_fd != 0) {
if (dup2(stdin_fd, 0) < 0) {
uwsgi_error("dup2()");
else {
int stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
close(stdin_fd);
if (stdin_fd != 0) {
if (dup2(stdin_fd, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(stdin_fd);
}
}
// close all of the unneded fd
@@ -813,11 +1020,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
exit(UWSGI_EXILE_CODE);
}
clear:
free(n_ui);
c_ui->ui_next = NULL;
return -1;
}
void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *ues) {
@@ -975,6 +1178,8 @@ void emperor_loop() {
char notification_message[64];
struct rlimit rl;
uwsgi.disable_nuclear_blast = 1;
uwsgi.emperor_stats_fd = -1;
if (uwsgi.emperor_pidfile) {
@@ -1087,14 +1292,24 @@ void emperor_loop() {
else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
char *zerg_name = uwsgi_concat3(ui_current->name, ":", "zerg");
emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid);
// here we discard socket name as broodlord/zerg cannot be on demand
emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid, NULL);
free(zerg_name);
}
}
}
else {
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
close(interesting_fd);
ui_current = emperor_get_by_socket_fd(interesting_fd);
if (ui_current) {
event_queue_del_fd(uwsgi.emperor_queue, ui_current->on_demand_fd, event_queue_read());
if (uwsgi_emperor_vassal_start(ui_current)) {
emperor_del(ui_current);
}
}
else {
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
close(interesting_fd);
}
}
}
@@ -1120,7 +1335,9 @@ void emperor_loop() {
has_children = 0;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
has_children++;
if (ui_current->pid > -1) {
has_children++;
}
}
if (uwsgi.notify) {
@@ -1172,7 +1389,7 @@ void emperor_loop() {
}
else {
// UNSAFE
emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid);
emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, ui_current->socket_name);
emperor_del(ui_current);
}
break;
@@ -1266,7 +1483,7 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keyval_comma(us, "id", c_ui->name))
goto end0;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) c_ui->pid))
if (uwsgi_stats_keyslong_comma(us, "pid", (long long) c_ui->pid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "born", (unsigned long long) c_ui->born))
goto end0;
@@ -1285,6 +1502,9 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keylong_comma(us, "zerg", (unsigned long long) c_ui->zerg))
goto end0;
if (uwsgi_stats_keyval_comma(us, "on_demand", c_ui->socket_name ? c_ui->socket_name : ""))
goto end0;
if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) c_ui->uid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid))
@@ -1403,6 +1623,7 @@ void uwsgi_emperor_start() {
else {
uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor");
}
if (uwsgi.emperor_pid < 0) {
uwsgi_error("pid()");
exit(1);
@@ -1436,7 +1657,7 @@ void uwsgi_check_emperor() {
}
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid) {
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) {
if (!uwsgi_emperor_is_valid(name))
return;
@@ -1473,6 +1694,6 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
new_config = uwsgi_str(config);
new_config_len = strlen(new_config);
}
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid);
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name);
}
}
+241 -14
View File
@@ -2,6 +2,233 @@
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_EVENT_USE_POLL
#define UWSGI_EVENT_IN POLLIN
#define UWSGI_EVENT_OUT POLLOUT
int uwsgi_poll_event_queue_max = 0;
struct uwsgi_poll_event {
int nevents;
int max_events;
pthread_mutex_t lock;
struct pollfd *poll;
};
struct uwsgi_poll_event **uwsgi_poll_event_queue;
// all of the public functions must be heavy locked
static int uwsgi_poll_fd_is_registered(struct uwsgi_poll_event *upe, int fd) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
return 1;
}
}
return 0;
}
static int uwsgi_poll_fd_add(struct uwsgi_poll_event *upe, int fd, int event) {
int pos = upe->nevents;
if (pos > upe->max_events) return -1;
upe->poll[pos].fd = fd;
upe->poll[pos].events = event;
upe->nevents++;
return 0;
}
static int uwsgi_poll_fd_del(struct uwsgi_poll_event *upe, int fd) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
if (i < upe->nevents-1) {
memcpy(&upe->poll[i], &upe->poll[i+1], sizeof(struct uwsgi_poll_event) * (upe->nevents - (i+1)));
}
upe->nevents--;
return 0;
}
}
return -1;
}
static void uwsgi_poll_queue_rebuild(struct uwsgi_poll_event *upe) {
// we need to check if some file descriptor is no more valid
int i;
for(i=0;i<upe->nevents;i++) {
if (!uwsgi_valid_fd(upe->poll[i].fd)) {
uwsgi_poll_fd_del(upe, upe->poll[i].fd);
}
}
}
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
uwsgi_poll_queue_rebuild(upe);
int ret = poll(upe->poll, upe->nevents, timeout * 1000);
if (ret > 0) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].revents) {
*interesting_fd = upe->poll[i].fd;
pthread_mutex_unlock(&upe->lock);
return 1;
}
}
}
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_init() {
if (!uwsgi_poll_event_queue) {
uwsgi_poll_event_queue = uwsgi_calloc(sizeof(struct uwsgi_poll_event *) * uwsgi.max_fd);
}
int eq = uwsgi_poll_event_queue_max;
uwsgi_poll_event_queue[eq] = uwsgi_calloc(sizeof(struct uwsgi_poll_event));
uwsgi_poll_event_queue_max++;
uwsgi_poll_event_queue[eq]->poll = uwsgi_malloc(sizeof(struct pollfd) * uwsgi.max_fd);
uwsgi_poll_event_queue[eq]->max_events = uwsgi.max_fd;
pthread_mutex_init(&uwsgi_poll_event_queue[eq]->lock, NULL);
return eq;
}
void *event_queue_alloc(int nevents) {
return uwsgi_calloc(sizeof(struct pollfd) * nevents);
}
int event_queue_interesting_fd_is_read(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
if (upoll->revents & POLLIN) {
return 1;
}
return 0;
}
int event_queue_fd_write_to_readwrite(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
upe->poll[i].events = POLLIN|POLLOUT;
pthread_mutex_unlock(&upe->lock);
return 0;
}
}
pthread_mutex_unlock(&upe->lock);
return -1;
}
int event_queue_fd_read_to_readwrite(int eq, int fd) {
return event_queue_fd_write_to_readwrite(eq, fd);
}
int event_queue_interesting_fd_is_write(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
if (upoll->revents & POLLOUT) {
return 1;
}
return 0;
}
int event_queue_add_fd_read(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
if (uwsgi_poll_fd_is_registered(upe, fd)) {
pthread_mutex_unlock(&upe->lock);
return 0;
}
int ret = uwsgi_poll_fd_add(upe, fd, POLLIN);
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_add_fd_write(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
if (uwsgi_poll_fd_is_registered(upe, fd)) {
pthread_mutex_unlock(&upe->lock);
return 0;
}
int ret = uwsgi_poll_fd_add(upe, fd, POLLOUT);
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_del_fd(int eq, int fd, int event) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int ret = uwsgi_poll_fd_del(upe, fd);
pthread_mutex_unlock(&upe->lock);
return ret;
}
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
uwsgi_poll_queue_rebuild(upe);
int ret = poll(upe->poll, upe->nevents, timeout * 1000);
int cnt = 0;
if (ret > 0) {
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].revents) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[cnt];
upoll->fd = upe->poll[i].fd;
upoll->revents = upe->poll[i].revents;
upoll->events = upe->poll[i].events;
cnt++;
}
}
}
pthread_mutex_unlock(&upe->lock);
if (ret <= 0) return ret;
return cnt;
}
int event_queue_interesting_fd_has_error(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
if (upoll->revents & POLLERR || upoll->revents & POLLHUP || upoll->revents & POLLNVAL) {
return 1;
}
return 0;
}
int event_queue_interesting_fd(void *events, int id) {
struct pollfd *pevents = (struct pollfd *)events;
struct pollfd *upoll = &pevents[id];
return upoll->fd;
}
int event_queue_fd_write_to_read(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
upe->poll[i].events = POLLIN;
pthread_mutex_unlock(&upe->lock);
return 0;
}
}
pthread_mutex_unlock(&upe->lock);
return -1;
}
int event_queue_fd_read_to_write(int eq, int fd) {
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
pthread_mutex_lock(&upe->lock);
int i;
for(i=0;i<upe->nevents;i++) {
if (upe->poll[i].fd == fd) {
upe->poll[i].events = POLLOUT;
pthread_mutex_unlock(&upe->lock);
return 0;
}
}
pthread_mutex_unlock(&upe->lock);
return -1;
}
#endif
#ifdef UWSGI_EVENT_USE_PORT
#include <port.h>
@@ -33,7 +260,7 @@ int event_queue_del_fd(int eq, int fd, int event) {
int event_queue_fd_write_to_read(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -44,7 +271,7 @@ int event_queue_fd_write_to_read(int eq, int fd) {
int event_queue_fd_read_to_write(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -55,7 +282,7 @@ int event_queue_fd_read_to_write(int eq, int fd) {
int event_queue_fd_readwrite_to_read(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -66,7 +293,7 @@ int event_queue_fd_readwrite_to_read(int eq, int fd) {
int event_queue_fd_readwrite_to_write(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -77,7 +304,7 @@ int event_queue_fd_readwrite_to_write(int eq, int fd) {
int event_queue_fd_write_to_readwrite(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -88,7 +315,7 @@ int event_queue_fd_write_to_readwrite(int eq, int fd) {
int event_queue_fd_read_to_readwrite(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -124,7 +351,7 @@ int event_queue_interesting_fd_is_write(void *events, int id) {
int event_queue_add_fd_read(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -134,7 +361,7 @@ int event_queue_add_fd_read(int eq, int fd) {
int event_queue_add_fd_write(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) {
uwsgi_error("port_associate");
return -1;
}
@@ -154,7 +381,7 @@ int event_queue_interesting_fd(void *events, int id) {
}
int fd = (int) pe[id].portev_object;
int eq = (int) pe[id].portev_user;
int eq = (long) pe[id].portev_user;
if (pe[id].portev_events == POLLOUT) {
event_queue_add_fd_write(eq, fd);
@@ -196,7 +423,7 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
port_event_t *pe_i = &pe[i];
if (pe_i->portev_source == PORT_SOURCE_FD) {
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, NULL)) {
if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, (void *)((long) eq))) {
uwsgi_error("port_associate");
}
}
@@ -222,16 +449,16 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
ret = port_get(eq, &pe, NULL);
}
if (ret < 0) {
if (errno != ETIME) {
if (errno == ETIME) return 0;
if (errno != EINTR) {
uwsgi_error("port_get()");
return -1;
}
return 0;
return -1;
}
if (pe.portev_source == PORT_SOURCE_FD) {
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
if (port_associate(eq, pe.portev_source, pe.portev_object, pe.portev_events, NULL)) {
if (port_associate(eq, pe.portev_source, pe.portev_object, pe.portev_events, (void *)((long) eq))) {
uwsgi_error("port_associate");
}
}
+14 -6
View File
@@ -1,6 +1,4 @@
#ifdef UWSGI_INI
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -9,6 +7,8 @@ extern struct uwsgi_server uwsgi;
This memory must not be freed for all the server lifecycle
*/
static char *last_file = NULL;
void ini_rstrip(char *line) {
off_t i;
@@ -106,13 +106,23 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
if (colon[1] != 0) {
section_asked = colon + 1;
}
if (colon == file) {
file = last_file;
}
}
if (file[0] != 0) {
if (file[0] != 0 && file != last_file) {
uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file);
}
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
if (file != last_file) {
if (last_file) {
free(last_file);
}
last_file = uwsgi_str(file);
}
while (len) {
ini_line = ini_get_line(ini, len);
@@ -157,5 +167,3 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
}
#endif
+3 -3
View File
@@ -770,10 +770,10 @@ timeout:
// check if an fd is valid
int uwsgi_valid_fd(int fd) {
int ret = fcntl(fd, F_GETFL);
if (ret == 0) {
return 1;
if (ret == -1) {
return 0;
}
return 0;
return 1;
}
void uwsgi_close_all_fds(void) {
+118 -24
View File
@@ -81,6 +81,37 @@ void uwsgi_parse_legion(char *key, uint16_t keylen, char *value, uint16_t vallen
}
}
// this function is called when a node is added or removed (heavy locking is needed)
static void legion_rebuild_scrolls(struct uwsgi_legion *ul) {
uint64_t max_size = ul->scrolls_max_size;
// first, try to add myself
if (ul->scroll_len + (uint64_t) 2 > max_size) {
uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n");
ul->scroll_len = 0;
return;
}
char *ptr = ul->scrolls;
*ptr ++= (uint8_t) (ul->scroll_len & 0xff);
*ptr ++= (uint8_t) ((ul->scroll_len >> 8) &0xff);
memcpy(ptr, ul->scroll, ul->scroll_len); ptr += ul->scroll_len;
ul->scrolls_len = 2 + ul->scroll_len;
// ok start adding nodes;
struct uwsgi_legion_node *uln = ul->nodes_head;
while(uln) {
if (ul->scrolls_len + 2 + uln->scroll_len > max_size) {
uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n");
return;
}
*ptr ++= (uint8_t) (uln->scroll_len & 0xff);
*ptr ++= (uint8_t) ((uln->scroll_len >> 8) &0xff);
memcpy(ptr, uln->scroll, uln->scroll_len); ptr += uln->scroll_len;
ul->scrolls_len += 2 + uln->scroll_len;
uln = uln->next;
}
}
// critical section (remember to lock when you use it)
struct uwsgi_legion_node *uwsgi_legion_add_node(struct uwsgi_legion *ul, uint16_t valor, char *name, uint16_t name_len, char *uuid) {
@@ -104,6 +135,7 @@ struct uwsgi_legion_node *uwsgi_legion_add_node(struct uwsgi_legion *ul, uint16_
ul->nodes_head = node;
}
return node;
@@ -141,6 +173,8 @@ void uwsgi_legion_remove_node(struct uwsgi_legion *ul, struct uwsgi_legion_node
}
free(node);
legion_rebuild_scrolls(ul);
}
struct uwsgi_legion_node *uwsgi_legion_get_node(struct uwsgi_legion *ul, uint64_t valor, char *name, uint16_t name_len, char *uuid) {
@@ -169,7 +203,6 @@ static void legions_check_nodes() {
struct uwsgi_legion_node *node = legion->nodes_head;
while (node) {
if (now - node->last_seen > uwsgi.legion_tolerance) {
struct uwsgi_legion_node *tmp_node = node;
node = node->next;
@@ -268,6 +301,18 @@ static void legions_check_nodes_step2() {
// we have quorum !!!
if (votes > 0 && votes >= ul->quorum) {
if (!ul->joined) {
// triggering join hooks
struct uwsgi_string_list *usl = ul->join_hooks;
while (usl) {
int ret = uwsgi_legion_action_call("join", ul, usl);
if (ret) {
uwsgi_log("[uwsgi-legion] ERROR, join hook returned: %d\n", ret);
}
usl = usl->next;
}
ul->joined = 1;
}
// something changed ???
if (ul->changed) {
legions_report_quorum(ul, best_valor, best_uuid, votes);
@@ -521,6 +566,8 @@ static void *legion_loop(void *foobar) {
node->scroll_len = legion_msg.scroll_len;
memcpy(node->scroll, legion_msg.scroll, node->scroll_len);
}
// we are still locked (and safe), let's rebuild the scrolls list
legion_rebuild_scrolls(ul);
uwsgi_rwunlock(ul->lock);
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
}
@@ -727,15 +774,20 @@ void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) {
exit(1);
}
struct uwsgi_string_list *usl = uwsgi_string_new_list(&ul->nodes, space + 1);
char *port = strchr(usl->value, ':');
uwsgi_legion_register_node(ul, space + 1);
}
void uwsgi_legion_register_node(struct uwsgi_legion *ul, char *addr) {
struct uwsgi_string_list *usl = uwsgi_string_new_list(&ul->nodes, addr);
char *port = strchr(addr, ':');
if (!port) {
uwsgi_log("[uwsgi-legion] invalid udp address: %s\n", usl->value);
uwsgi_log("[uwsgi-legion] invalid udp address: %s\n", addr);
exit(1);
}
// no need to zero the memory, socket_to_in_addr will do that
struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in));
usl->custom = socket_to_in_addr(usl->value, port, 0, sin);
usl->custom = socket_to_in_addr(addr, port, 0, sin);
usl->custom_ptr = sin;
}
@@ -787,51 +839,69 @@ void uwsgi_opt_legion_scroll(char *opt, char *value, void *foobar) {
void uwsgi_opt_legion_hook(char *opt, char *value, void *foobar) {
char *event = strchr(opt, '-');
if (!event) {
uwsgi_log("[uwsgi-legion] invalid option name (%s), this should not happen (possible bug)\n", opt);
exit(1);
}
char *legion = uwsgi_str(value);
char *space = strchr(legion, ' ');
if (!space) {
uwsgi_log("invalid %s syntax, must be <legion> <action>\n", opt);
uwsgi_log("[uwsgi-legion] invalid %s syntax, must be <legion> <action>\n", opt);
exit(1);
}
*space = 0;
struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
if (!ul) {
uwsgi_log("unknown legion: %s\n", legion);
uwsgi_log("[uwsgi-legion] unknown legion: %s\n", legion);
exit(1);
}
uwsgi_legion_register_hook(ul, event + 1, space + 1);
}
void uwsgi_legion_register_hook(struct uwsgi_legion *ul, char *event, char *action) {
struct uwsgi_string_list *usl = NULL;
if (!strcmp(opt, "legion-lord")) {
usl = uwsgi_string_new_list(&ul->lord_hooks, space + 1);
if (!strcmp(event, "lord")) {
usl = uwsgi_string_new_list(&ul->lord_hooks, action);
}
else if (!strcmp(opt, "legion-unlord")) {
usl = uwsgi_string_new_list(&ul->unlord_hooks, space + 1);
else if (!strcmp(event, "unlord")) {
usl = uwsgi_string_new_list(&ul->unlord_hooks, action);
}
else if (!strcmp(opt, "legion-setup")) {
usl = uwsgi_string_new_list(&ul->setup_hooks, space + 1);
else if (!strcmp(event, "setup")) {
usl = uwsgi_string_new_list(&ul->setup_hooks, action);
}
else if (!strcmp(opt, "legion-death")) {
usl = uwsgi_string_new_list(&ul->death_hooks, space + 1);
else if (!strcmp(event, "death")) {
usl = uwsgi_string_new_list(&ul->death_hooks, action);
}
else if (!strcmp(event, "join")) {
usl = uwsgi_string_new_list(&ul->join_hooks, action);
}
else {
uwsgi_log("[uwsgi-legion] invalid event: %s\n", event);
exit(1);
}
if (!usl)
return;
char *port = strchr(usl->value, ':');
if (!port) {
uwsgi_log("[uwsgi-legion] invalid %s action: %s\n", opt, usl->value);
char *hook = strchr(action, ':');
if (!hook) {
uwsgi_log("[uwsgi-legion] invalid %s action: %s\n", event, action);
exit(1);
}
// pointer to action plugin
usl->custom_ptr = uwsgi_concat2n(usl->value, port - usl->value, "", 0);
usl->custom_ptr = uwsgi_concat2n(action, hook - action, "", 0);;
// add that to check the plugin value
usl->custom = port - usl->value + 1;
}
usl->custom = hook - action + 1;
}
void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
@@ -869,6 +939,10 @@ void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
*colon = 0;
char *secret = colon + 1;
uwsgi_legion_register(legion, addr, valor, algo_secret, secret);
}
struct uwsgi_legion *uwsgi_legion_register(char *legion, char *addr, char *valor, char *algo, char *secret) {
char *iv = strchr(secret, ' ');
if (iv) {
*iv = 0;
@@ -882,9 +956,9 @@ void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
EVP_CIPHER_CTX *ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
const EVP_CIPHER *cipher = EVP_get_cipherbyname(algo_secret);
const EVP_CIPHER *cipher = EVP_get_cipherbyname(algo);
if (!cipher) {
uwsgi_log("[uwsgi-legion] unable to find algorithm/cipher %s\n", algo_secret);
uwsgi_log("[uwsgi-legion] unable to find algorithm/cipher %s\n", algo);
exit(1);
}
@@ -937,10 +1011,18 @@ void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
uwsgi.legion_scroll_max_size = 4096;
}
if (!uwsgi.legion_scroll_list_max_size) {
uwsgi.legion_scroll_list_max_size = 32768;
}
ul->lord_scroll_size = uwsgi.legion_scroll_max_size;
ul->lord_scroll = uwsgi_calloc_shared(ul->lord_scroll_size);
ul->scrolls_max_size = uwsgi.legion_scroll_list_max_size;
ul->scrolls = uwsgi_calloc_shared(ul->scrolls_max_size);
uwsgi_legion_add(ul);
return ul;
}
struct uwsgi_legion_action *uwsgi_legion_action_get(char *name) {
@@ -1020,3 +1102,15 @@ char *uwsgi_legion_lord_scroll(char *name, uint16_t *rlen) {
uwsgi_rwunlock(legion->lock);
return buf;
}
char *uwsgi_legion_scrolls(char *name, uint64_t *rlen) {
char *buf = NULL;
struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
if (!legion) return NULL;
uwsgi_rlock(legion->lock);
buf = uwsgi_malloc(legion->scrolls_len);
memcpy(buf, legion->scrolls, legion->scrolls_len);
*rlen = legion->scrolls_len;
uwsgi_rwunlock(legion->lock);
return buf;
}
+54
View File
@@ -401,6 +401,60 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_unlock_fast(uli);
}
#elif defined(UWSGI_LOCK_USE_WINDOWS_MUTEX)
#define UWSGI_LOCK_ENGINE_NAME "windows mutexes"
#define UWSGI_LOCK_SIZE sizeof(HANDLE)
#define UWSGI_RWLOCK_SIZE sizeof(HANDLE)
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
struct _SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(struct _SECURITY_ATTRIBUTES));
sa.bInheritHandle = 1;
uli->lock_ptr = CreateMutex(&sa, FALSE, NULL);
return uli;
}
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
WaitForSingleObject(uli->lock_ptr, INFINITE);
uli->pid = uwsgi.mypid;
}
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
ReleaseMutex(uli->lock_ptr);
uli->pid = 0;
}
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
if (WaitForSingleObject(uli->lock_ptr, 0) == WAIT_TIMEOUT) {
return 0;
}
return uli->pid;
}
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
return uwsgi_lock_fast_init(id);
}
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_lock_fast(uli);
}
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_lock_fast(uli);
}
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
return uwsgi_lock_fast_check(uli);
}
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
uwsgi_unlock_fast(uli);
}
#else
#define uwsgi_lock_fast_init uwsgi_lock_ipcsem_init
+33 -12
View File
@@ -1,9 +1,9 @@
#define _NO_UWSGI_RB
#include "uwsgi.h"
#ifndef __DragonFly__
#include <uwsgi.h>
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#include <kvm.h>
#include <sys/user.h>
#include <kvm.h>
#elif defined(__sun__)
/* Terrible Hack !!! */
#ifndef _LP64
@@ -17,6 +17,10 @@
#include <sys/sysctl.h>
#endif
#ifdef __DragonFly__
#include <uwsgi.h>
#endif
extern struct uwsgi_server uwsgi;
//use this instead of fprintf to avoid buffering mess with udp logging
@@ -314,7 +318,7 @@ static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl)
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum(name[i])) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
@@ -638,12 +642,8 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1) {
#ifndef UNBIT
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
#else
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
#endif
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024,
(unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
logvec[logvecpos].iov_base = mempkt;
logvec[logvecpos].iov_len = rlen;
logvecpos++;
@@ -673,7 +673,11 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
void get_memusage(uint64_t * rss, uint64_t * vsz) {
#ifdef UNBIT
*vsz = syscall(356);
uint64_t ret[2];
ret[0] = 0; ret[1] = 0;
syscall(358, ret);
*vsz = ret[0];
*rss = ret[1] * uwsgi.page_size;
#elif defined(__linux__)
FILE *procfile;
int i;
@@ -686,6 +690,18 @@ void get_memusage(uint64_t * rss, uint64_t * vsz) {
fclose(procfile);
}
*rss = *rss * uwsgi.page_size;
#elif defined(__CYGWIN__)
// same as Linux but rss is not in pages...
FILE *procfile;
int i;
procfile = fopen("/proc/self/stat", "r");
if (procfile) {
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) vsz, (unsigned long long *) rss);
if (i != 2) {
uwsgi_log("warning: invalid record in /proc/self/stat\n");
}
fclose(procfile);
}
#elif defined (__sun__)
psinfo_t info;
int procfd;
@@ -725,8 +741,13 @@ void get_memusage(uint64_t * rss, uint64_t * vsz) {
struct kinfo_proc *kproc;
kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, &cnt);
if (kproc && cnt > 0) {
#if defined(__FreeBSD__)
*vsz = kproc->ki_size;
*rss = kproc->ki_rssize * uwsgi.page_size;
#elif defined(__DragonFly__)
*vsz = kproc->kp_vm_map_size;
*rss = kproc->kp_vm_rssize * uwsgi.page_size;
#endif
}
#elif defined(UWSGI_NEW_OPENBSD)
struct kinfo_proc *kproc;
+19 -19
View File
@@ -798,8 +798,8 @@ int master_loop(char **argv, char **environ) {
*/
uwsgi.mywid = find_worker_id(diedpid);
if (uwsgi.mywid <= 0) {
int thewid = find_worker_id(diedpid);
if (thewid <= 0) {
// check spooler, mules, gateways and daemons
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
@@ -842,50 +842,50 @@ next:
// ok a worker died...
uwsgi.workers[uwsgi.mywid].pid = 0;
uwsgi.workers[thewid].pid = 0;
// only to be safe :P
uwsgi.workers[uwsgi.mywid].harakiri = 0;
uwsgi.workers[thewid].harakiri = 0;
// ok, if we are reloading or dying, just continue the master loop
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) {
uwsgi_log("worker %d buried after %d seconds\n", uwsgi.mywid, (int) (uwsgi_now()-uwsgi.workers[uwsgi.mywid].cursed_at));
uwsgi.workers[uwsgi.mywid].cursed_at = 0;
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now()-uwsgi.workers[thewid].cursed_at));
uwsgi.workers[thewid].cursed_at = 0;
continue;
}
// if we are stopping workers, just end here
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", uwsgi.mywid, (int) diedpid);
uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid);
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) {
uwsgi_log("...restoring worker %d (pid: %d)...\n", uwsgi.mywid, (int) diedpid);
uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid);
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXCEPTION_CODE) {
uwsgi_log("... monitored exception detected, respawning worker %d (pid: %d)...\n", uwsgi.mywid, (int) diedpid);
uwsgi_log("... monitored exception detected, respawning worker %d (pid: %d)...\n", thewid, (int) diedpid);
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_QUIET_CODE) {
// noop
}
else if (uwsgi.workers[uwsgi.mywid].manage_next_request) {
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", uwsgi.mywid, (int) diedpid, (int) WTERMSIG(waitpid_status));
uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
}
else {
uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", uwsgi.mywid, (int) diedpid);
uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", thewid, (int) diedpid);
}
}
else if (uwsgi.workers[uwsgi.mywid].cursed_at > 0) {
uwsgi_log("worker %d killed successfully (pid: %d)\n", uwsgi.mywid, (int) diedpid);
else if (uwsgi.workers[thewid].cursed_at > 0) {
uwsgi_log("worker %d killed successfully (pid: %d)\n", thewid, (int) diedpid);
}
// manage_next_request is zero, but killed by signal...
else if (WIFSIGNALED(waitpid_status)) {
uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY killed by signal %d :( trying respawn ...\n", uwsgi.mywid, (int) diedpid, (int) WTERMSIG(waitpid_status));
uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
}
if (uwsgi.workers[uwsgi.mywid].cheaped == 1) {
uwsgi_log("uWSGI worker %d cheaped.\n", uwsgi.mywid);
if (uwsgi.workers[thewid].cheaped == 1) {
uwsgi_log("uWSGI worker %d cheaped.\n", thewid);
continue;
}
@@ -909,12 +909,12 @@ next:
uwsgi.respawn_delta = last_respawn.tv_sec;
// are we chain reloading it ?
if (uwsgi.status.chain_reloading == uwsgi.mywid) {
if (uwsgi.status.chain_reloading == thewid) {
uwsgi.status.chain_reloading++;
}
// respawn the worker (if needed)
if (uwsgi_respawn_worker(uwsgi.mywid))
if (uwsgi_respawn_worker(thewid))
return 0;
// end of the loop
+3 -4
View File
@@ -413,9 +413,6 @@ void uwsgi_reload(char **argv) {
#endif
}
#ifdef UWSGI_AS_SHARED_LIBRARY
return;
#else
uwsgi_log("running %s\n", uwsgi.binary_path);
uwsgi_flush_logs();
argv[0] = uwsgi.binary_path;
@@ -436,7 +433,6 @@ void uwsgi_reload(char **argv) {
uwsgi_error("execvp()");
// never here
exit(1);
#endif
}
@@ -957,6 +953,9 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
uc = uc->next;
}
if (uwsgi_stats_list_close(us))
goto end;
if (uwsgi_stats_comma(us))
goto end;
}
+6 -2
View File
@@ -184,6 +184,7 @@ void uwsgi_mule_handler() {
if (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket || farm_has_signaled(interesting_fd)) {
len = read(interesting_fd, &uwsgi_signal, 1);
if (len <= 0) {
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) continue;
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
@@ -197,7 +198,9 @@ void uwsgi_mule_handler() {
else if (interesting_fd == uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) {
len = read(interesting_fd, message, 65536);
if (len < 0) {
uwsgi_error("read()");
if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
uwsgi_error("uwsgi_mule_handler/read()");
}
}
else {
int i, found = 0;
@@ -343,6 +346,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;
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
@@ -350,7 +354,7 @@ next:
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.mywid);
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
}
// set the error condition
len = -1;
+31
View File
@@ -354,6 +354,13 @@ static int uwsgi_proto_check_11(struct wsgi_request *wsgi_req, char *key, char *
return 0;
}
if (!uwsgi_proto_key("HTTP_COOKIE", 11)) {
wsgi_req->cookie = buf;
wsgi_req->cookie_len = len;
return 0;
}
if (!uwsgi_proto_key("UWSGI_APPID", 11)) {
wsgi_req->appid = buf;
wsgi_req->appid_len = len;
@@ -961,9 +968,24 @@ int uwsgi_hooked_parse_array(char *buffer, size_t len, void (*hook) (uint16_t, c
}
/*
the following functions need to take in account that POST data could be already available in wsgi_req->buffer (generally when uwsgi protocol is in use)
In such a case, allocate a proto_parser_buf and move data there
*/
char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
if (!wsgi_req->proto_parser_buf) {
if (wsgi_req->proto_parser_remains > 0) {
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains);
memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains);
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf;
}
}
if ((wsgi_req->uh->pktsize + (2 + keylen + 2 + vallen)) > uwsgi.buffer_size) {
uwsgi_log("not enough buffer space to add %.*s variable, consider increasing it with the --buffer-size option\n", keylen, key);
return NULL;
@@ -1001,6 +1023,15 @@ char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen
}
int uwsgi_req_append_path_info_with_index(struct wsgi_request *wsgi_req, char *index, uint16_t index_len) {
if (!wsgi_req->proto_parser_buf) {
if (wsgi_req->proto_parser_remains > 0) {
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains);
memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains);
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf;
}
}
uint8_t need_slash = 0;
if (wsgi_req->path_info_len > 0) {
if (wsgi_req->path_info[wsgi_req->path_info_len-1] != '/') {
+57
View File
@@ -0,0 +1,57 @@
#include <uwsgi.h>
/*
QUERY_STRING management functions (mainly used by the internal routing subsystem)
*/
static char *check_qs(char *qs, uint16_t qs_len, char *key, uint16_t keylen, uint16_t *vallen) {
// search for the equal sign
char *equal = memchr(qs, '=', qs_len);
if (!equal) return NULL;
if (uwsgi_strncmp(key, keylen, qs, equal-qs)) {
return NULL;
}
qs_len -= (equal-qs)+1;
if (qs_len == 0) return NULL;
*vallen = qs_len;
return equal+1;
}
char *uwsgi_get_qs(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
uint16_t i;
char *qs = wsgi_req->query_string;
uint16_t qs_len = 0;
char *ptr = wsgi_req->query_string;
//start splitting by ;
for(i=0;i<wsgi_req->query_string_len;i++) {
if (!qs) {
qs = ptr + i;
}
if (ptr[i] == '&') {
char *value = check_qs(qs, qs_len, key, keylen, vallen);
if (value) {
return value;
}
qs_len = 0;
qs = NULL;
}
else {
qs_len++;
}
}
if (qs_len > 0) {
char *value = check_qs(qs, qs_len, key, keylen, vallen);
if (value) {
return value;
}
}
return NULL;
}
+14 -14
View File
@@ -108,64 +108,65 @@ static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
}
}
remains = UMIN(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, wsgi_req->post_cl - wsgi_req->post_pos);
// read from a file
if (wsgi_req->post_file) {
size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, 1, wsgi_req->post_file);
size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, remains, 1, wsgi_req->post_file);
if (ret == 0) {
uwsgi_error("consume_body_for_readline()/fread()");
return -1;
}
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
wsgi_req->post_pos += remains;
wsgi_req->post_readline_watermark += remains;
return 0;
}
// read from post_buffering memory
if (uwsgi.post_buffering) {
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, remains);
wsgi_req->post_pos += remains;
wsgi_req->post_readline_watermark += remains;
return 0;
}
// read from socket
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
if (len > 0) {
wsgi_req->post_pos += len;
wsgi_req->post_readline_watermark += len;
return 0;
}
if (len == 0) {
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
wait:
ret = uwsgi_wait_read_req(wsgi_req);
if (ret > 0) {
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
if (len > 0) {
wsgi_req->post_pos += len;
wsgi_req->post_readline_watermark += len;
return 0;
}
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
// 0 means timeout
else if (ret == 0) {
uwsgi_read_timeout(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_timeout(remains);
return -1;
}
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
uwsgi_read_error(remains);
return -1;
}
@@ -347,7 +348,6 @@ char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize
if (wsgi_req->post_file) {
if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) {
*rlen = -1;
uwsgi_log("%llu\n", remains);
uwsgi_error("uwsgi_request_body_read()/fread()");
return NULL;
}
+224 -5
View File
@@ -3,6 +3,43 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_route_var *uwsgi_register_route_var(char *name, char *(*func)(struct wsgi_request *, char *, uint16_t, uint16_t *)) {
struct uwsgi_route_var *old_urv = NULL,*urv = uwsgi.route_vars;
while(urv) {
if (!strcmp(urv->name, name)) {
return urv;
}
old_urv = urv;
urv = urv->next;
}
urv = uwsgi_calloc(sizeof(struct uwsgi_route_var));
urv->name = name;
urv->name_len = strlen(name);
urv->func = func;
if (old_urv) {
old_urv->next = urv;
}
else {
uwsgi.route_vars = urv;
}
return urv;
}
struct uwsgi_route_var *uwsgi_get_route_var(char *name, uint16_t name_len) {
struct uwsgi_route_var *urv = uwsgi.route_vars;
while(urv) {
if (!uwsgi_strncmp(urv->name, urv->name_len, name, name_len)) {
return urv;
}
urv = urv->next;
}
return NULL;
}
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *subject, uint16_t subject_len, char *data, size_t data_len) {
char *pass1 = data;
@@ -44,9 +81,32 @@ struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, stru
case 2:
if (pass1[i] == '}') {
uint16_t vallen = 0;
char *value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
int need_free = 0;
char *value = NULL;
char *bracket = memchr(key, '[', keylen);
if (bracket && keylen > 0 && key[keylen-1] == ']') {
struct uwsgi_route_var *urv = uwsgi_get_route_var(key, bracket - key);
if (urv) {
need_free = urv->need_free;
value = urv->func(wsgi_req, bracket + 1, keylen - (urv->name_len+2), &vallen);
}
else {
value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
}
}
else {
value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
}
if (value) {
if (uwsgi_buffer_append(ub, value, vallen)) goto error;
if (uwsgi_buffer_append(ub, value, vallen)) {
if (need_free) {
free(value);
}
goto error;
}
if (need_free) {
free(value);
}
}
status = 0;
key = NULL;
@@ -97,6 +157,8 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
while (routes) {
if (routes->label) goto next;
if (wsgi_req->route_goto > 0 && wsgi_req->route_pc < wsgi_req->route_goto) {
goto next;
}
@@ -108,6 +170,11 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
wsgi_req->route_goto = 0;
if (!routes->if_func) {
// could be a "run"
if (!routes->subject) {
n = 0;
goto run;
}
if (!subject) {
char **subject2 = (char **) (((char *) (wsgi_req)) + routes->subject);
uint16_t *subject_len2 = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
@@ -137,6 +204,7 @@ int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t
}
}
run:
if (n >= 0) {
wsgi_req->is_routing = 1;
int ret = routes->func(wsgi_req, routes);
@@ -176,7 +244,7 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
return UWSGI_ROUTE_BREAK;
}
// in case ogf static files serving previous rules could be applied
// in case of static files serving previous rules could be applied
if (wsgi_req->routes_applied) {
return UWSGI_ROUTE_CONTINUE;
}
@@ -197,6 +265,8 @@ static void *uwsgi_route_get_condition_func(char *name) {
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
char *space = NULL;
char *command = NULL;
struct uwsgi_route *old_ur = NULL,*ur = uwsgi.routes;
uint64_t pos = 0;
while(ur) {
@@ -223,7 +293,12 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
char *route = uwsgi_str(value);
char *space = strchr(route, ' ');
if (!strcmp(foobar, "run")) {
command = route;
goto done;
}
space = strchr(route, ' ');
if (!space) {
uwsgi_log("invalid route syntax\n");
exit(1);
@@ -299,7 +374,8 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
}
}
char *command = space + 1;
command = space + 1;
done:
ur->action = uwsgi_str(command);
char *colon = strchr(command, ':');
@@ -628,6 +704,133 @@ static int uwsgi_route_condition_isfile(struct wsgi_request *wsgi_req, struct uw
return 0;
}
static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
pcre *pattern;
pcre_extra *pattern_extra;
char *re = uwsgi_concat2n(semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str), "", 0);
if (uwsgi_regexp_build(re, &pattern, &pattern_extra)) {
free(re);
uwsgi_buffer_destroy(ub);
return -1;
}
free(re);
if (uwsgi_regexp_match(pattern, pattern_extra, ub->buf, ub->pos) >= 0) {
uwsgi_buffer_destroy(ub);
pcre_free(pattern);
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_free_study(pattern_extra);
#else
pcre_free(pattern_extra);
#endif
return 1;
}
uwsgi_buffer_destroy(ub);
pcre_free(pattern);
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_free_study(pattern_extra);
#else
pcre_free(pattern_extra);
#endif
return 0;
}
static int uwsgi_route_condition_empty(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
if (ub->pos == 0) {
uwsgi_buffer_destroy(ub);
return 1;
}
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_route_condition_equal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if(!uwsgi_strncmp(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_startswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if(!uwsgi_starts_with(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
if (ub2->pos < ub->pos) goto zero;
if(!uwsgi_strncmp(ub->buf + (ub->pos - ub2->pos), ub2->pos, ub2->buf, ub2->pos)) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
zero:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_isdir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
@@ -685,6 +888,19 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
uwsgi_register_route_condition("islink", uwsgi_route_condition_islink);
uwsgi_register_route_condition("isexec", uwsgi_route_condition_isexec);
uwsgi_register_route_condition("equal", uwsgi_route_condition_equal);
uwsgi_register_route_condition("isequal", uwsgi_route_condition_equal);
uwsgi_register_route_condition("eq", uwsgi_route_condition_equal);
uwsgi_register_route_condition("==", uwsgi_route_condition_equal);
uwsgi_register_route_condition("startswith", uwsgi_route_condition_startswith);
uwsgi_register_route_condition("endswith", uwsgi_route_condition_endswith);
uwsgi_register_route_condition("regexp", uwsgi_route_condition_regexp);
uwsgi_register_route_condition("re", uwsgi_route_condition_regexp);
uwsgi_register_route_condition("empty", uwsgi_route_condition_empty);
uwsgi_register_route_var("cookie", uwsgi_get_cookie);
uwsgi_register_route_var("qs", uwsgi_get_qs);
}
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
@@ -743,6 +959,9 @@ void uwsgi_routing_dump() {
if (routes->label) {
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
}
else if (!routes->subject_str && !routes->if_func) {
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
}
else {
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
}
+10
View File
@@ -123,6 +123,16 @@ void uwsgi_setup_inherited_sockets() {
continue;
}
if (uwsgi.shared->worker_req_log_pipe[0] > -1) {
if (j == uwsgi.shared->worker_req_log_pipe[0])
continue;
}
if (uwsgi.shared->worker_req_log_pipe[1] > -1) {
if (j == uwsgi.shared->worker_req_log_pipe[1])
continue;
}
if (uwsgi.original_log_fd > -1) {
if (j == uwsgi.original_log_fd)
continue;
+4 -2
View File
@@ -137,7 +137,7 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
int i;
for(i=1;i<=uwsgi.numproc;i++) {
int pos = (i * 256);
memcpy(&uwsgi.shared->signal_table[pos], use, sizeof(struct uwsgi_signal_entry) * 256);
memcpy(&uwsgi.shared->signal_table[pos], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256);
}
}
@@ -260,6 +260,8 @@ int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq)
int uwsgi_add_timer(uint8_t sig, int secs) {
if (!uwsgi.master_process) return -1;
uwsgi_lock(uwsgi.timer_table_lock);
if (ushared->timers_cnt < 64) {
@@ -595,7 +597,7 @@ void uwsgi_receive_signal(int fd, char *name, int id) {
if (ret == 0) {
goto destroy;
}
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
uwsgi_error("[uwsgi-signal] read()");
goto destroy;
}
+33 -1
View File
@@ -2,6 +2,23 @@
extern struct uwsgi_server uwsgi;
static int uwsgi_socket_strcmp(char *sock1, char *sock2) {
size_t sock1_len = strlen(sock1);
size_t sock2_len = strlen(sock2);
if (!uwsgi_starts_with(sock1, sock1_len, "0.0.0.0:", 8)) {
sock1 += 7;
sock1_len = strlen(sock1);
}
if (!uwsgi_starts_with(sock2, sock2_len, "0.0.0.0:", 8)) {
sock2 += 7;
sock2_len = strlen(sock2);
}
return uwsgi_strncmp(sock1, sock1_len, sock2, sock2_len);
}
char *uwsgi_getsockname(int fd) {
socklen_t socket_type_len = sizeof(struct sockaddr_un);
@@ -49,6 +66,7 @@ int bind_to_unix_dgram(char *socket_name) {
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (unlink(socket_name) != 0 && errno != ENOENT) {
@@ -68,6 +86,7 @@ int bind_to_unix_dgram(char *socket_name) {
#endif
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
return serverfd;
@@ -83,6 +102,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
if (strlen(socket_name) > 102) {
uwsgi_log("invalid socket name\n");
uwsgi_nuclear_blast();
return -1;
}
if (socket_name[0] == '@') {
@@ -96,6 +116,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
if (uws_addr == NULL) {
uwsgi_error("malloc()");
uwsgi_nuclear_blast();
return -1;
}
memset(uws_addr, 0, sizeof(struct sockaddr_un));
@@ -103,6 +124,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (abstract_socket == 0) {
if (unlink(socket_name) != 0 && errno != ENOENT) {
@@ -140,12 +162,14 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
#endif
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
return -1;
}
// chmod unix socket for lazy users
@@ -561,11 +585,13 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEADDR setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
#ifdef __linux__
@@ -576,6 +602,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) {
uwsgi_error("IP_FREEBIND setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
#endif
@@ -585,6 +612,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEPORT setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
#else
uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n");
@@ -611,6 +639,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(struct timeval)) < 0) {
uwsgi_error("SO_SNDTIMEO setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
@@ -645,6 +674,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
}
uwsgi_error("bind()");
uwsgi_nuclear_blast();
return -1;
}
#ifdef __linux__
@@ -652,12 +682,14 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
uwsgi_nuclear_blast();
return -1;
}
#endif
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
return -1;
}
@@ -1476,7 +1508,7 @@ void uwsgi_setup_shared_sockets() {
for (i = 3; i < (int) uwsgi.max_fd; i++) {
char *sock = uwsgi_getsockname(i);
if (sock) {
if (!strcmp(sock, shared_sock->name)) {
if (!uwsgi_socket_strcmp(sock, shared_sock->name)) {
if (strchr(sock, ':')) {
uwsgi_log("uwsgi shared socket %d inherited TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i);
shared_sock->family = AF_INET;
-1
View File
@@ -108,7 +108,6 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
uwsgi.mywid = -1;
uwsgi.mypid = getpid();
uspool->pid = uwsgi.mypid;
// avoid race conditions !!!
+1 -1
View File
@@ -609,7 +609,7 @@ safe:
#ifdef UWSGI_ROUTING
// before sending the file, we need to check if some rule applies
if (uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
return 0;
}
wsgi_req->routes_applied = 1;
+43 -1
View File
@@ -315,6 +315,45 @@ int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long l
return uwsgi_stats_comma(us);
}
int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) {
if (uwsgi_stats_apply_tabs(us))
return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
if (ret < 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base)
return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
if (ret < 0)
return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keyslong_comma(struct uwsgi_stats *us, char *key, long long num) {
int ret = uwsgi_stats_keyslong(us, key, num);
if (ret)
return -1;
return uwsgi_stats_comma(us);
}
void uwsgi_send_stats(int fd, struct uwsgi_stats *(*func) (void)) {
struct sockaddr_un client_src;
@@ -383,7 +422,10 @@ struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pu
uspi = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_instance));
uspi->pusher = pusher;
uspi->arg = arg;
if (arg) {
uspi->arg = uwsgi_str(arg);
}
uspi->raw = pusher->raw;
if (old_uspi) {
old_uspi->next = uspi;
}
+28 -1
View File
@@ -622,6 +622,25 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
free(wsgi_req->proto_parser_buf);
}
// do we need to store the response in the cache
if (wsgi_req->cache_it) {
// only response with a body and a status code of 200 can be cached (TODO allows it to be configurable)
if (wsgi_req->cached_response && wsgi_req->status == 200 && wsgi_req->response_size > 0) {
uwsgi_cache_magic_set(wsgi_req->cache_it->buf, wsgi_req->cache_it->pos,
wsgi_req->cached_response->buf, wsgi_req->cached_response->pos, wsgi_req->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, wsgi_req->cache_it_to ? wsgi_req->cache_it_to->buf : NULL);
}
uwsgi_buffer_destroy(wsgi_req->cache_it);
}
if (wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it_to);
}
if (wsgi_req->cached_response) {
uwsgi_buffer_destroy(wsgi_req->cached_response);
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
@@ -2470,13 +2489,19 @@ void uwsgi_chown(char *filename, char *owner) {
char *uwsgi_get_binary_path(char *argvzero) {
#if defined(__linux__)
#if defined(__linux__) || defined(__CYGWIN__)
char *buf = uwsgi_calloc(PATH_MAX + 1);
ssize_t len = readlink("/proc/self/exe", buf, PATH_MAX);
if (len > 0) {
return buf;
}
free(buf);
#elif defined(_WIN32)
char *buf = uwsgi_calloc(PATH_MAX + 1);
if (GetModuleFileName(NULL, buf, PATH_MAX) > 0) {
return buf;
}
free(buf);
#elif defined(__NetBSD__)
char *buf = uwsgi_calloc(PATH_MAX + 1);
ssize_t len = readlink("/proc/curproc/exe", buf, PATH_MAX);
@@ -2941,11 +2966,13 @@ pid_t uwsgi_fork(char *name) {
pid_t pid = fork();
if (pid == 0) {
#ifndef __CYGWIN__
if (uwsgi.never_swap) {
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
uwsgi_error("mlockall()");
}
}
#endif
#if defined(__linux__) || defined(__sun__)
int i;
+127 -14
View File
@@ -70,6 +70,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
{"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE},
{"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0},
@@ -80,6 +81,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
{"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"if-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_opt, UWSGI_OPT_IMMEDIATE},
{"if-not-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_opt, UWSGI_OPT_IMMEDIATE},
@@ -108,6 +110,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"if-directory", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE},
{"endif", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"end-if", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"blacklist", required_argument, 0, "set options blacklist context", uwsgi_opt_set_str, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE},
{"end-blacklist", no_argument, 0, "clear options blacklist context", uwsgi_opt_set_null, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE},
@@ -169,6 +172,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-required-heartbeat", required_argument, 0, "set the Emperor tolerance about heartbeats", uwsgi_opt_set_int, &uwsgi.emperor_heartbeat, 0},
{"emperor-pidfile", required_argument, 0, "write the Emperor pid in the specified file", uwsgi_opt_set_str, &uwsgi.emperor_pidfile, 0},
{"emperor-tyrant", no_argument, 0, "put the Emperor in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant, 0},
{"emperor-tyrant-nofollow", no_argument, 0, "do not follow symlinks when checking for uid/gid in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant_nofollow, 0},
{"emperor-stats", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0},
{"emperor-stats-server", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0},
{"early-emperor", no_argument, 0, "spawn the emperor as soon as possibile", uwsgi_opt_true, &uwsgi.early_emperor, 0},
@@ -176,6 +180,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-throttle", required_argument, 0, "set throttling level (in milliseconds) for bad behaving vassals (default 1000)", uwsgi_opt_set_int, &uwsgi.emperor_throttle, 0},
{"emperor-max-throttle", required_argument, 0, "set max throttling level (in milliseconds) for bad behaving vassals (default 3 minutes)", uwsgi_opt_set_int, &uwsgi.emperor_max_throttle, 0},
{"emperor-magic-exec", no_argument, 0, "prefix vassals config files with exec:// if they have the executable bit", uwsgi_opt_true, &uwsgi.emperor_magic_exec, 0},
{"emperor-on-demand-extension", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0},
{"emperor-on-demand-ext", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0},
{"emperor-on-demand-directory", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0},
{"emperor-on-demand-dir", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0},
{"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
{"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"vassals-inherit", required_argument, 0, "add config templates to vassals config", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
@@ -256,6 +267,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"chroot", required_argument, 0, "chroot() to the specified directory", uwsgi_opt_set_str, &uwsgi.chroot, 0},
{"uid", required_argument, 0, "setuid to the specified user/uid", uwsgi_opt_set_uid, NULL, 0},
{"gid", required_argument, 0, "setgid to the specified group/gid", uwsgi_opt_set_gid, NULL, 0},
{"immediate-uid", required_argument, 0, "setuid to the specified user/uid IMMEDIATELY", uwsgi_opt_set_immediate_uid, NULL, UWSGI_OPT_IMMEDIATE},
{"immediate-gid", required_argument, 0, "setgid to the specified group/gid IMMEDIATELY", uwsgi_opt_set_immediate_gid, NULL, UWSGI_OPT_IMMEDIATE},
{"no-initgroups", no_argument, 0, "disable additional groups set via initgroups()", uwsgi_opt_true, &uwsgi.no_initgroups, 0},
#ifdef UWSGI_CAP
{"cap", required_argument, 0, "set process capability", uwsgi_opt_set_cap, NULL, 0},
@@ -270,9 +283,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"exec-as-user", required_argument, 0, "run the specified command after privileges drop", uwsgi_opt_add_string_list, &uwsgi.exec_as_user, 0},
{"exec-as-user-atexit", required_argument, 0, "run the specified command before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.exec_as_user_atexit, 0},
{"exec-pre-app", required_argument, 0, "run the specified command before app loading", uwsgi_opt_add_string_list, &uwsgi.exec_pre_app, 0},
#ifdef UWSGI_INI
{"exec-post-app", required_argument, 0, "run the specified command after app loading", uwsgi_opt_add_string_list, &uwsgi.exec_post_app, 0},
{"ini", required_argument, 0, "load config from ini file", uwsgi_opt_load_ini, NULL, UWSGI_OPT_IMMEDIATE},
#endif
#ifdef UWSGI_YAML
{"yaml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
{"yal", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
@@ -371,10 +383,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"legion-unlord", required_argument, 0, "action to call on Lord dismiss", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-setup", required_argument, 0, "action to call on legion setup", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-death", required_argument, 0, "action to call on legion death (shutdown of the instance)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-join", required_argument, 0, "action to call on legion join (first time quorum is reached)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-quorum", required_argument, 0, "set the quorum of a legion", uwsgi_opt_legion_quorum, NULL, UWSGI_OPT_MASTER},
{"legion-scroll", required_argument, 0, "set the scroll of a legion", uwsgi_opt_legion_scroll, NULL, UWSGI_OPT_MASTER},
{"legion-scroll", required_argument, 0, "set the scroll of a legion", uwsgi_opt_legion_scroll, NULL, UWSGI_OPT_MASTER},
{"legion-scroll-max-size", required_argument, 0, "set max size of legion scroll buffer", uwsgi_opt_set_16bit, &uwsgi.legion_scroll_max_size, 0},
{"legion-scroll-list-max-size", required_argument, 0, "set max size of legion scroll list buffer", uwsgi_opt_set_64bit, &uwsgi.legion_scroll_list_max_size, 0},
{"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
{"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
#endif
@@ -506,6 +519,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"route-label", required_argument, 0, "add a routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
{"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0},
{"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0},
{"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
{"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
#endif
@@ -779,8 +793,12 @@ void config_magic_table_fill(char *filename, char **magic_table) {
char *section = uwsgi_get_last_char(filename, ':');
if (section) {
*section = 0;
if (section == filename) {
goto reuse;
}
}
// we have a special case for symlinks
if (uwsgi_is_link(filename)) {
if (filename[0] != '/') {
@@ -834,6 +852,7 @@ void config_magic_table_fill(char *filename, char **magic_table) {
if (uwsgi_get_last_char(magic_table['s'], '.'))
magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.') - magic_table['s'], "", 0);
reuse:
if (section) {
magic_table['x'] = section+1;
*section = ':';
@@ -976,9 +995,18 @@ void grace_them_all(int signum) {
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying)
return;
int i;
if (uwsgi.lazy) {
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi_curse(i, SIGHUP);
}
return;
}
uwsgi.status.gracefully_reloading = 1;
int i;
int waitpid_status;
@@ -1011,8 +1039,6 @@ void grace_them_all(int signum) {
}
}
else if (uwsgi.workers[i].pid > 0) {
if (uwsgi.lazy)
uwsgi.workers[i].destroy = 1;
uwsgi_curse(i, SIGHUP);
}
}
@@ -1027,6 +1053,9 @@ void grace_them_all(int signum) {
void uwsgi_nuclear_blast() {
// the Emperor (as an example) cannot nuke itself
if (uwsgi.disable_nuclear_blast) return;
if (!uwsgi.workers) {
reap_them_all(0);
}
@@ -1596,10 +1625,6 @@ int main(int argc, char *argv[], char *envp[]) {
int i;
#ifdef UNBIT
//struct uidsec_struct us;
#endif
struct utsname uuts;
// signal mask is inherited, and sme process manager could make a real mess...
@@ -1701,7 +1726,13 @@ int main(int argc, char *argv[], char *envp[]) {
// count/set the current reload status
uwsgi_setup_reload();
#ifdef __CYGWIN__
SYSTEM_INFO si;
GetSystemInfo(&si);
uwsgi.page_size = si.dwPageSize;
#else
uwsgi.page_size = getpagesize();
#endif
uwsgi.binary_path = uwsgi_get_binary_path(argv[0]);
// ok we can now safely play with argv and environ
@@ -1737,6 +1768,7 @@ int main(int argc, char *argv[], char *envp[]) {
// set a couple of 'static' magic vars
uwsgi.magic_table['v'] = uwsgi.cwd;
uwsgi.magic_table['h'] = uwsgi.hostname;
uwsgi.magic_table['V'] = UWSGI_VERSION;
// you can embed a ini file in the uWSGi binary with default options
#ifdef UWSGI_EMBED_CONFIG
@@ -1785,12 +1817,14 @@ int main(int argc, char *argv[], char *envp[]) {
// initial log setup (files and daemonization)
uwsgi_setup_log();
#ifndef __CYGWIN__
// enable never-swap mode
if (uwsgi.never_swap) {
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
uwsgi_error("mlockall()");
}
}
#endif
if (uwsgi.flock2)
uwsgi_opt_flock(NULL, uwsgi.flock2, NULL);
@@ -3104,6 +3138,18 @@ void uwsgi_init_all_apps() {
}
}
usl = uwsgi.exec_post_app;
while (usl) {
uwsgi_log("running \"%s\" (post app)...\n", usl->value);
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
exit(1);
}
usl = usl->next;
}
}
void uwsgi_init_worker_mount_apps() {
@@ -3146,6 +3192,59 @@ void uwsgi_opt_true(char *opt, char *value, void *key) {
}
}
void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
gid_t gid = atoi(value);
if (gid == 0) {
struct group *ugroup = getgrnam(value);
if (ugroup)
gid = ugroup->gr_gid;
}
if (gid <= 0) {
uwsgi_log("uwsgi_opt_set_immediate_gid(): invalid gid %d\n", (int) gid);
exit(1);
}
if (setgid(gid)) {
uwsgi_error("uwsgi_opt_set_immediate_gid()/setgid()");
exit(1);
}
if (setgroups(0, NULL)) {
uwsgi_error("uwsgi_opt_set_immediate_gid()/setgroups()");
exit(1);
}
gid = getgid();
if (!gid) {
exit(1);
}
uwsgi_log("immediate gid: %d\n", (int) gid);
}
void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) {
uid_t uid = atoi(value);
if (uid == 0) {
struct passwd *upasswd = getpwnam(value);
if (upasswd)
uid = upasswd->pw_uid;
}
if (uid <= 0) {
uwsgi_log("uwsgi_opt_set_immediate_uid(): invalid uid %d\n", uid);
exit(1);
}
if (setuid(uid)) {
uwsgi_error("uwsgi_opt_set_immediate_uid()/setuid()");
exit(1);
}
uid = getuid();
if (!uid) {
exit(1);
}
uwsgi_log("immediate uid: %d\n", (int) uid);
}
void uwsgi_opt_set_int(char *opt, char *value, void *key) {
int *ptr = (int *) key;
if (value) {
@@ -3695,12 +3794,10 @@ void uwsgi_opt_deprecated(char *opt, char *value, void *message) {
void uwsgi_opt_load(char *opt, char *filename, void *none) {
#ifdef UWSGI_INI
if (uwsgi_endswith(filename, ".ini")) {
uwsgi_opt_load_ini(opt, filename, none);
return;
}
#endif
#ifdef UWSGI_XML
if (uwsgi_endswith(filename, ".xml")) {
uwsgi_opt_load_xml(opt, filename, none);
@@ -3727,6 +3824,9 @@ void uwsgi_opt_load(char *opt, char *filename, void *none) {
return;
}
#endif
// fallback to pluggable system
uwsgi_opt_load_config(opt, filename, none);
}
void uwsgi_opt_logic(char *opt, char *arg, void *func) {
@@ -3748,12 +3848,25 @@ void uwsgi_opt_logic(char *opt, char *arg, void *func) {
void uwsgi_opt_noop(char *opt, char *foo, void *bar) {
}
#ifdef UWSGI_INI
void uwsgi_opt_load_ini(char *opt, char *filename, void *none) {
config_magic_table_fill(filename, uwsgi.magic_table);
uwsgi_ini_config(filename, uwsgi.magic_table);
}
#endif
void uwsgi_opt_load_config(char *opt, char *filename, void *none) {
struct uwsgi_configurator *uc = uwsgi.configurators;
while(uc) {
if (uwsgi_endswith(filename, uc->name)) {
config_magic_table_fill(filename, uwsgi.magic_table);
uc->func(filename, uwsgi.magic_table);
return;
}
uc = uc->next;
}
uwsgi_log("unable to load configuration from %s\n", filename);
exit(1);
}
#ifdef UWSGI_XML
void uwsgi_opt_load_xml(char *opt, char *filename, void *none) {
+13
View File
@@ -141,6 +141,7 @@ int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
// this is the function called by all request plugins to send chunks to the client
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
if (wsgi_req->write_errors) return -1;
@@ -182,6 +183,18 @@ sendbody:
// reset for the next write
wsgi_req->write_pos = 0;
// now we need to check if the chunk must be stored
if (wsgi_req->cache_it) {
if (!wsgi_req->cached_response) {
wsgi_req->cached_response = uwsgi_buffer_new(len);
}
// if we are unable to append the buffer, we just stop caching it
if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
}
return UWSGI_OK;
}
+9
View File
@@ -0,0 +1,9 @@
config = {}
config['immediate-uid'] = 'roberto'
config['immediate-gid'] = 'roberto'
config['http-socket'] = ':9090'
config['env'] = { 'FOO=bar', 'TEST=topogigio' }
config['module'] = 'werkzeug.testapp:test_app'
return config
+8
View File
@@ -0,0 +1,8 @@
config = {}
config[1] = { ['http-socket']=':9090' }
config[2] = { ['env']='FOO=bar' }
config[3] = { ['env']='TEST=topogigio' }
config[4] = { ['module']='werkzeug.testapp:test_app' }
return config
+46 -10
View File
@@ -9,9 +9,10 @@
extern struct uwsgi_server uwsgi;
struct carbon_server_list {
char *value; // server address
int healthy;
int errors;
char *hostname;
char *port;
struct carbon_server_list *next;
};
@@ -33,6 +34,7 @@ struct uwsgi_carbon {
char *root_node;
char *hostname_dot_replacement;
char *hostname;
int resolve_hostname;
struct uwsgi_stats_pusher *pusher;
} u_carbon;
@@ -46,6 +48,8 @@ static struct uwsgi_option carbon_options[] = {
{"carbon-retry-delay", required_argument, 0, "set connection retry delay in seconds (default 7)", uwsgi_opt_set_int, &u_carbon.retry_delay, 0},
{"carbon-root", required_argument, 0, "set carbon metrics root node (default 'uwsgi')", uwsgi_opt_set_str, &u_carbon.root_node, 0},
{"carbon-hostname-dots", required_argument, 0, "set char to use as a replacement for dots in hostname (dots are not replaced by default)", uwsgi_opt_set_str, &u_carbon.hostname_dot_replacement, 0},
{"carbon-name-resolve", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{"carbon-resolve-names", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -59,15 +63,32 @@ static void carbon_post_init() {
while(usl) {
struct carbon_server_list *u_server = uwsgi_calloc(sizeof(struct carbon_server_list));
u_server->value = usl->value;
u_server->healthy = 1;
u_server->errors = 0;
char *p = strtok(usl->value, ":");
while (p) {
if (!u_server->hostname) {
u_server->hostname = uwsgi_str(p);
}
else if (!u_server->port) {
u_server->port = uwsgi_str(p);
}
else break;
p = strtok(NULL, ":");
}
if (!u_server->hostname || !u_server->port) {
uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value);
usl = usl->next;
continue;
}
if (u_carbon.servers_data) {
u_server->next = u_carbon.servers_data;
}
u_carbon.servers_data = u_server;
uwsgi_log("[carbon] added server %s\n", usl->value);
uwsgi_log("[carbon] added server %s:%s\n", u_server->hostname, u_server->port);
usl = usl->next;
}
@@ -80,7 +101,7 @@ static void carbon_post_init() {
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
if (u_carbon.max_retries <= 0) u_carbon.max_retries = 1;
if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7;
if (!u_carbon.id) {
if (!u_carbon.id) {
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
for(i=0;i<(int)strlen(u_carbon.id);i++) {
@@ -145,6 +166,8 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
int i;
int fd;
int wok;
char *ip;
char *carbon_address = NULL;
for (i = 0; i < uwsgi.numproc; i++) {
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
@@ -157,31 +180,44 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
if (retry_cycle && usl->healthy)
// skip healthy servers during retry cycle
goto nxt;
if (retry_cycle && usl->healthy == 0)
uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->value, usl->errors);
uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->hostname, usl->errors);
if (!retry_cycle) {
usl->healthy = 1;
usl->errors = 0;
}
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
if (u_carbon.resolve_hostname) {
ip = uwsgi_resolve_ip(usl->hostname);
if (!ip) {
uwsgi_log("[carbon] Could not resolve hostname %s\n", usl->hostname);
goto nxt;
}
carbon_address = uwsgi_concat3(ip, ":", usl->port);
}
else {
carbon_address = uwsgi_concat3(usl->hostname, ":", usl->port);
}
fd = uwsgi_connect(carbon_address, u_carbon.timeout, 0);
if (fd < 0) {
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", usl->value);
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", carbon_address);
if (usl->errors < u_carbon.max_retries) {
u_carbon.need_retry = 1;
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
} else {
uwsgi_log("[carbon] Maximum number of retries for %s (%d)\n",
usl->value, u_carbon.max_retries);
carbon_address, u_carbon.max_retries);
usl->healthy = 0;
usl->errors = 0;
}
usl->healthy = 0;
usl->errors++;
free(carbon_address);
goto nxt;
}
free(carbon_address);
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
+6 -4
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -13,8 +13,9 @@ class FakeClass {
void FakeClass::hello_world(struct wsgi_request *wsgi_req) {
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, (char *) "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n", 44);
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, foobar, foobar_len);
uwsgi_response_prepare_headers(wsgi_req, (char *)"200 OK", 6);
uwsgi_response_add_content_type(wsgi_req, (char *)"text/html", 9);
uwsgi_response_write_body_do(wsgi_req, foobar, foobar_len);
}
extern "C" int uwsgi_cplusplus_init(){
@@ -27,7 +28,7 @@ extern "C" int uwsgi_cplusplus_request(struct wsgi_request *wsgi_req) {
FakeClass *fc;
// empty request ?
if (!wsgi_req->uh.pktsize) {
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Invalid request. skip.\n");
goto clear;
}
@@ -55,6 +56,7 @@ clear:
extern "C" void uwsgi_cplusplus_after_request(struct wsgi_request *wsgi_req) {
// call log_request(wsgi_req) if you want a standard logline
uwsgi_log("logging c++ request\n");
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
int uwsgi_cplusplus_init(void);
+2 -2
View File
@@ -49,7 +49,7 @@ void uwsgi_imperial_monitor_amqp_event(struct uwsgi_emperor_scanner *ues) {
}
if (msgsize > 0) {
emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0);
emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0, NULL);
}
end0:
@@ -88,7 +88,7 @@ end0:
emperor_respawn(ui_current, uwsgi_now());
}
else {
emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0);
emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0, NULL);
}
free(config_file);
+4 -2
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include "client/dbclient.h"
@@ -60,7 +60,9 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
vassal_gid = tmp_gid;
}
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid);
const char *socket_name = p.getStringField("socket");
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
+8 -1
View File
@@ -1,7 +1,14 @@
import os
NAME='emperor_mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
LIBS = []
if not 'UWSGI_MONGODB_NOLIB' in os.environ:
LIBS.append('-lmongoclient')
LIBS.append('-lboost_thread')
LIBS.append('-lboost_filesystem')
GCC_LIST = ['plugin', 'emperor_mongodb.cc']
+5 -1
View File
@@ -68,7 +68,11 @@ void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) {
vassal_uid = uwsgi_str_num(q_uid, strlen(q_uid));
vassal_gid = uwsgi_str_num(q_gid, strlen(q_gid));
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid);
char *socket_name = NULL;
if (PQnfields(res) > 5) {
socket_name = PQgetvalue(res, i, 5);
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid, socket_name);
}
}
+23 -4
View File
@@ -64,15 +64,16 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
int64_t more = 0;
size_t more_size = sizeof(more);
int i;
zmq_msg_t msg[5];
zmq_msg_t msg[6];
zmq_msg_init(&msg[0]);
zmq_msg_init(&msg[1]);
zmq_msg_init(&msg[2]);
zmq_msg_init(&msg[3]);
zmq_msg_init(&msg[4]);
zmq_msg_init(&msg[5]);
for(i=0;i<5;i++) {
for(i=0;i<6;i++) {
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
zmq_recvmsg(ues->data, &msg[i], ZMQ_DONTWAIT);
#else
@@ -105,6 +106,11 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
char *ez_gid = NULL;
size_t ez_gid_len = 0;
char *ez_socket_name = NULL;
size_t ez_socket_name_len = 0;
char *socket_name = NULL;
// config
if (i > 1) {
ez_config = zmq_msg_data(&msg[2]);
@@ -123,6 +129,12 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
ez_gid_len = zmq_msg_size(&msg[4]);
}
// gid
if (i > 4) {
ez_socket_name = zmq_msg_data(&msg[5]);
ez_socket_name_len = zmq_msg_size(&msg[5]);
}
char *name = uwsgi_concat2n(ez_name, ez_name_len, "", 0);
// ok let's start checking commands
@@ -142,10 +154,16 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
vassal_gid = uwsgi_str_num(ez_gid, ez_gid_len);
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid);
if (ez_socket_name) {
socket_name = uwsgi_concat2n(ez_socket_name, ez_socket_name_len, "", 0);
}
uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid, socket_name);
if (config) {
free(config);
}
if (socket_name) {
free(socket_name);
}
}
// destroy an instance
else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 6)) {
@@ -158,7 +176,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
}
}
else {
uwsgi_log("[emperor-zeromq] unkonwn command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd);
uwsgi_log("[emperor-zeromq] unknown command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd);
}
free(name);
@@ -168,6 +186,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
zmq_msg_close(&msg[2]);
zmq_msg_close(&msg[3]);
zmq_msg_close(&msg[4]);
zmq_msg_close(&msg[5]);
}
// this is the event manager
+2 -1
View File
@@ -2,6 +2,7 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_rack ur;
extern struct uwsgi_plugin rack_plugin;
struct ufib {
int enabled;
@@ -45,7 +46,7 @@ static void fiber_schedule_to_req() {
int error = 0;
rb_protect(rb_fiber_schedule_to_req, 0, &error);
if (error) {
uwsgi_ruby_exception();
rack_plugin.exception_log(NULL);
rb_gc_unregister_address(&ufiber.fib[id]);
uwsgi.wsgi_req->async_status = UWSGI_OK;
}
+141
View File
@@ -0,0 +1,141 @@
#include <uwsgi.h>
#include <GeoIP.h>
#include <GeoIPCity.h>
struct uwsgi_geoip {
char *country_db;
char *city_db;
GeoIP *country;
GeoIP *city;
} ugeoip;
struct uwsgi_option uwsgi_geoip_options[] = {
{"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0},
{"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
};
static int uwsgi_geoip_init() {
if (ugeoip.country_db) {
ugeoip.country = GeoIP_open(ugeoip.country_db, GEOIP_MEMORY_CACHE);
if (!ugeoip.country) {
uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db);
exit(1);
}
}
if (ugeoip.city_db) {
ugeoip.city = GeoIP_open(ugeoip.city_db, GEOIP_MEMORY_CACHE);
if (!ugeoip.city) {
uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db);
exit(1);
}
}
return 0;
}
static char *uwsgi_route_var_geoip(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
uint32_t ip;
char ip_str[16];
// should be enough for geo coords
char lonlat[64];
memset(ip_str, 0, 16);
memcpy(ip_str, wsgi_req->remote_addr, wsgi_req->remote_addr_len);
if (inet_pton(AF_INET, ip_str, &ip) <= 0) {
return NULL;
}
ip = htonl(ip);
char *value = NULL;
// always prefer the city database;
GeoIP *g = ugeoip.city;
if (!g) {
g = ugeoip.country;
if (g) {
if (!uwsgi_strncmp(key, keylen, "country_code", 12)) {
value = (char *) GeoIP_country_code_by_ipnum(g, ip);
}
else if (!uwsgi_strncmp(key, keylen, "country_code3", 13)) {
value = (char *) GeoIP_country_code3_by_ipnum(g, ip);
}
else if (!uwsgi_strncmp(key, keylen, "country_name", 12)) {
value = (char *) GeoIP_country_name_by_ipnum(g, ip);
}
if (value) {
*vallen = strlen(value);
return uwsgi_str(value);
}
}
return NULL;
}
GeoIPRecord *gr = GeoIP_record_by_ipnum(g, ip);
if (!gr) return NULL;
// ok let's generate the output
if (!uwsgi_strncmp(key, keylen, "continent", 9)) {
value = gr->continent_code;
}
else if (!uwsgi_strncmp(key, keylen, "country_code", 12)) {
value = gr->country_code;
}
else if (!uwsgi_strncmp(key, keylen, "country_code3", 13)) {
value = gr->country_code3;
}
else if (!uwsgi_strncmp(key, keylen, "country_name", 12)) {
value = gr->country_name;
}
else if (!uwsgi_strncmp(key, keylen, "region", 6)) {
value = gr->region;
}
else if (!uwsgi_strncmp(key, keylen, "region_name", 11)) {
value = (char *) GeoIP_region_name_by_code(gr->country_code, gr->region);
}
else if (!uwsgi_strncmp(key, keylen, "city", 4)) {
value = gr->city;
}
else if (!uwsgi_strncmp(key, keylen, "postal_code", 11)) {
value = gr->postal_code;
}
else if (!uwsgi_strncmp(key, keylen, "latitude", 8) || !uwsgi_strncmp(key, keylen, "lat", 3)) {
snprintf(lonlat, 64, "%f", gr->latitude);
value = lonlat;
}
else if (!uwsgi_strncmp(key, keylen, "longitude", 9) || !uwsgi_strncmp(key, keylen, "lon", 3)) {
snprintf(lonlat, 64, "%f", gr->longitude);
value = lonlat;
}
else if (!uwsgi_strncmp(key, keylen, "dma", 3)) {
snprintf(lonlat, 64, "%d", gr->dma_code);
value = lonlat;
}
else if (!uwsgi_strncmp(key, keylen, "area", 4)) {
snprintf(lonlat, 64, "%d", gr->area_code);
value = lonlat;
}
if (value) {
*vallen = strlen(value);
char *ret = uwsgi_str(value);
GeoIPRecord_delete(gr);
return ret;
}
GeoIPRecord_delete(gr);
return NULL;
}
static void register_route_vars_geoip() {
struct uwsgi_route_var *urv = uwsgi_register_route_var("geoip", uwsgi_route_var_geoip);
urv->need_free = 1;
}
struct uwsgi_plugin geoip_plugin = {
.name = "geoip",
.options = uwsgi_geoip_options,
.init = uwsgi_geoip_init,
.on_load = register_route_vars_geoip,
};
+8
View File
@@ -0,0 +1,8 @@
NAME='geoip'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lGeoIP']
GCC_LIST = ['geoip']
+11 -1
View File
@@ -18,6 +18,7 @@ static void uwsgi_opt_setup_gevent(char *opt, char *value, void *null) {
static struct uwsgi_option gevent_options[] = {
{"gevent", required_argument, 0, "a shortcut enabling gevent loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_gevent, NULL, UWSGI_OPT_THREADS},
{"gevent-monkey-patch", no_argument, 0, "call gevent.monkey.patch_all() automatically on startup", uwsgi_opt_true, &ugevent.monkey, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -317,6 +318,16 @@ static void gevent_loop() {
exit(1);
}
// call gevent.monkey.patch_all() if requested
if (ugevent.monkey) {
PyObject *gevent_monkey_dict = get_uwsgi_pydict("gevent.monkey");
if (!gevent_monkey_dict) uwsgi_pyexit;
PyObject *gevent_monkey_patch_all = PyDict_GetItemString(gevent_monkey_dict, "patch_all");
if (!gevent_monkey_patch_all) uwsgi_pyexit;
PyObject *ret = python_call(gevent_monkey_patch_all, PyTuple_New(0), 0, NULL);
if (!ret) uwsgi_pyexit;
}
ugevent.spawn = PyDict_GetItemString(gevent_dict, "spawn");
if (!ugevent.spawn) uwsgi_pyexit;
@@ -329,7 +340,6 @@ static void gevent_loop() {
ugevent.greenlet_switch_args = PyTuple_New(0);
Py_INCREF(ugevent.greenlet_switch_args);
PyObject *gevent_get_hub = PyDict_GetItemString(gevent_dict, "get_hub");
ugevent.hub = python_call(gevent_get_hub, PyTuple_New(0), 0, NULL);
+1
View File
@@ -52,5 +52,6 @@ struct uwsgi_gevent {
PyObject *signal_watcher;
PyObject **watchers;
int destroy;
int monkey;
};
+2 -2
View File
@@ -587,6 +587,8 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
size_t len = main_peer->in->pos;
char *ptr = main_peer->in->buf;
hr->rnrn = 0;
for (j = 0; j < len; j++) {
if (*ptr == '\r' && (hr->rnrn == 0 || hr->rnrn == 2)) {
hr->rnrn++;
@@ -770,8 +772,6 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
}
hr->rnrn = 0;
hr->port = ugs->port;
hr->port_len = ugs->port_len;
switch(ugs->mode) {
+2
View File
@@ -108,3 +108,5 @@ int uwsgi_jvm_object_to_response_body(struct wsgi_request *, jobject);
jobject uwsgi_jvm_bytearray(char *, size_t);
char *uwsgi_jvm_bytearray2c(jobject);
void uwsgi_jvm_release_bytearray(jobject, char *);
jobject uwsgi_jvm_to_string(jobject);
+31 -8
View File
@@ -243,6 +243,15 @@ jobject uwsgi_jvm_entryset(jobject o) {
return uwsgi_jvm_call_object(o, mid);
}
jobject uwsgi_jvm_to_string(jobject o) {
jclass c = uwsgi_jvm_class_from_object(o);
if (!c) return NULL;
jmethodID mid = uwsgi_jvm_get_method_id_quiet(c, "toString", "()Ljava/lang/String;");
uwsgi_jvm_local_unref(c);
if (!mid) return NULL;
return uwsgi_jvm_call_object(o, mid);
}
int uwsgi_jvm_object_to_response_body(struct wsgi_request *wsgi_req, jobject body) {
// check for string
@@ -297,20 +306,35 @@ int uwsgi_jvm_object_to_response_body(struct wsgi_request *wsgi_req, jobject bod
ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len);
uwsgi_jvm_release_chars(chunk, c_body);
uwsgi_jvm_local_unref(chunk);
if (ret) goto done;
continue;
}
else if (uwsgi_jvm_object_is_instance(chunk, ujvm.bytearray_class)) {
if (uwsgi_jvm_object_is_instance(chunk, ujvm.bytearray_class)) {
char *c_body = uwsgi_jvm_bytearray2c(chunk);
size_t c_body_len = uwsgi_jvm_array_len(chunk);
ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len);
uwsgi_jvm_release_bytearray(chunk, c_body);
uwsgi_jvm_local_unref(chunk);
if (ret) goto done;
continue;
}
else {
uwsgi_log("body iterable item must be java/lang/String or array of bytes!!!\n");
uwsgi_jvm_local_unref(chunk);
goto done;
jobject str_o = uwsgi_jvm_to_string(chunk);
if (str_o) {
char *c_body = uwsgi_jvm_str2c(str_o);
size_t c_body_len = uwsgi_jvm_strlen(str_o);
ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len);
uwsgi_jvm_release_chars(str_o, c_body);
uwsgi_jvm_local_unref(str_o);
uwsgi_jvm_local_unref(chunk);
if (ret) goto done;
continue;
}
if (ret) goto done;
uwsgi_log("body iterable item must be java/lang/String or array of bytes!!!\n");
uwsgi_jvm_local_unref(chunk);
goto done;
}
done:
uwsgi_jvm_local_unref(chunks);
@@ -592,11 +616,10 @@ int uwsgi_jvm_consume_input_stream(struct wsgi_request *wsgi_req, size_t chunk,
break;
}
// get the body of the array
size_t buf_len = uwsgi_jvm_array_len(byte_buffer);
char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, byte_buffer, JNI_FALSE);
if (!buf) { ret = -1; break; }
//send
if (uwsgi_response_write_body_do(wsgi_req, buf, buf_len)) {
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) {
(*ujvm_env)->ReleaseByteArrayElements(ujvm_env, byte_buffer, (jbyte *) buf, 0);
ret = -1; break;
}
+27 -9
View File
@@ -1,4 +1,5 @@
import os,sys
import os
import shutil
NAME='jvm'
@@ -20,6 +21,9 @@ if operating_system == 'darwin':
if os.path.exists(jvm):
JVM_INCPATH = ["-Wno-deprecated-declarations", "-I%s" % jvm]
JVM_LIBPATH = ["-framework JavaVM"]
elif operating_system.startswith('cygwin'):
JVM_INCPATH = ['-I"/cygdrive/c/Program Files/Java/jdk1.7.0_17/include"', '-I"/cygdrive/c/Program Files/Java/jdk1.7.0_17/include/win32"']
JVM_LIBPATH = ['-L"/cygdrive/c/Program Files/Java/jdk1.7.0_17/jre/bin/server"']
else:
known_jvms = ('/usr/lib/jvm/java-7-openjdk', '/usr/local/openjdk7', '/usr/lib/jvm/java-6-openjdk', '/usr/local/openjdk', '/usr/java', '/usr/lib/jvm/java/')
for jvm in known_jvms:
@@ -33,15 +37,15 @@ else:
JVM_LIBPATH = ["-L%s/jre/lib/%s/server" % (jvm, arch)]
break
try:
JVM_INCPATH = os.environ['UWSGICONFIG_JVM_INCPATH']
except:
pass
try:
JVM_INCPATH = ['-I"' + os.environ['UWSGICONFIG_JVM_INCPATH'] + '"']
except:
pass
try:
JVM_LIBPATH = os.environ['UWSGICONFIG_JVM_LIBPATH']
except:
pass
try:
JVM_LIBPATH = ['-L"' + os.environ['UWSGICONFIG_JVM_LIBPATH'] + '"']
except:
pass
if not JVM_INCPATH or not JVM_LIBPATH:
print("unable to autodetect the JVM path, please specify UWSGICONFIG_JVM_INCPATH and UWSGICONFIG_JVM_LIBPATH environment vars")
@@ -66,3 +70,17 @@ def post_build(config):
if os.system("cd %s/plugins/jvm ; jar cvf uwsgi.jar *.class" % os.getcwd()) != 0:
os._exit(1)
print("*** uwsgi.jar available in %s/plugins/jvm/uwsgi.jar ***" % os.getcwd())
env = os.environ.get('VIRTUAL_ENV')
if env:
src = "%s/plugins/jvm/uwsgi.jar" % os.getcwd()
tgt = "%s/lib/uwsgi.jar" % env
shutil.copyfile(src, tgt)
print("*** uwsgi.jar had been copied to %s" % tgt)
plugin = "%s/jvm_plugin.so" % os.getcwd()
if os.path.exists(plugin):
tgt = "%s/bin/jvm_plugin.so" % env
shutil.copyfile(plugin, tgt)
print("*** jvm_plugin.so had been copied to %s" % tgt)
+173
View File
@@ -0,0 +1,173 @@
#include <uwsgi.h>
/*
this is an UDP logger encrypting each packet with the choosen algo, key and iv.
It is useful in cloud services without persistent storage for which you want to send logs to an external system.
Syntax: --logger/--req-logger crypto:addr=<udp_address>,algo=<algorithm>,secret=<key>,iv=<iv>,prefix=<prefix>
example:
uwsgi --plugin logcrypto --logger crypto:addr=127.0.0.1:1717,algo=bf-cbc,secret=ciaociao -M -p 4 -s :3031
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_crypto_logger_conf {
EVP_CIPHER_CTX *encrypt_ctx;
char *addr;
char *algo;
char *secret;
char *iv;
char *prefix;
size_t prefix_len;
};
static void uwsgi_crypto_logger_setup_encryption(struct uwsgi_crypto_logger_conf *uclc) {
if (!uwsgi.ssl_initialized) {
uwsgi_ssl_init();
}
uclc->encrypt_ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(uclc->encrypt_ctx);
const EVP_CIPHER *cipher = EVP_get_cipherbyname(uclc->algo);
if (!cipher) {
uwsgi_log_safe("[uwsgi-logcrypto] unable to find algorithm/cipher\n");
exit(1);
}
int cipher_len = EVP_CIPHER_key_length(cipher);
size_t s_len = strlen(uclc->secret);
if ((unsigned int) cipher_len > s_len) {
char *secret_tmp = uwsgi_malloc(cipher_len);
memcpy(secret_tmp, uclc->secret, s_len);
memset(secret_tmp + s_len, 0, cipher_len - s_len);
uclc->secret = secret_tmp;
}
int iv_len = EVP_CIPHER_iv_length(cipher);
size_t s_iv_len = 0;
if (uclc->iv) {
s_iv_len = strlen(uclc->iv);
}
if ((unsigned int) iv_len > s_iv_len) {
char *secret_tmp = uwsgi_malloc(iv_len);
memcpy(secret_tmp, uclc->iv, s_iv_len);
memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len);
uclc->iv = secret_tmp;
}
if (EVP_EncryptInit_ex(uclc->encrypt_ctx, cipher, NULL, (const unsigned char *) uclc->secret, (const unsigned char *) uclc->iv) <= 0) {
uwsgi_error_safe("uwsgi_crypto_logger_setup_encryption()/EVP_EncryptInit_ex()");
exit(1);
}
}
static ssize_t uwsgi_crypto_logger(struct uwsgi_logger *ul, char *message, size_t len) {
struct uwsgi_crypto_logger_conf *uclc = (struct uwsgi_crypto_logger_conf *) ul->data;
if (!ul->configured) {
uclc = uwsgi_calloc(sizeof(struct uwsgi_crypto_logger_conf));
if (uwsgi_kvlist_parse(ul->arg, strlen(ul->arg), ',', '=',
"addr", &uclc->addr,
"algo", &uclc->algo,
"secret", &uclc->secret,
"iv", &uclc->iv,
"prefix", &uclc->prefix,
NULL)) {
uwsgi_log_safe("[uwsgi-logcrypto] unable to parse options\n");
exit(1);
}
if (!uclc->addr || !uclc->algo || !uclc->secret) {
uwsgi_log_safe("[uwsgi-logcrypto] you have to specify at least addr,algo and secret options\n");
exit(1);
}
if (uclc->prefix) {
uclc->prefix_len = strlen(uclc->prefix);
}
char *colon = strchr(uclc->addr, ':');
if (!colon) {
uwsgi_log_safe("[uwsgi-logcrypto] invalid UDP address\n");
exit(1);
}
ul->addr_len = socket_to_in_addr(uclc->addr, colon, 0, &ul->addr.sa_in);
ul->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (ul->fd < 0) {
uwsgi_error_safe("uwsgi_crypto_logger()/socket()");
exit(1);
}
uwsgi_crypto_logger_setup_encryption(uclc);
ul->data = uclc;
ul->configured = 1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto error;
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
if (uclc->prefix) {
if (uwsgi_buffer_append(ub, uclc->prefix, uclc->prefix_len)) goto error;
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
}
if (uwsgi_buffer_append(ub, message, len)) goto error;
// let's encrypt the message
unsigned char *encrypted = uwsgi_malloc(ub->pos + EVP_MAX_BLOCK_LENGTH);
if (EVP_EncryptInit_ex(uclc->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
uwsgi_error_safe("[uwsgi-logcrypto] EVP_EncryptInit_ex()");
free(encrypted);
goto error;
}
int e_len = 0;
if (EVP_EncryptUpdate(uclc->encrypt_ctx, encrypted, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) {
uwsgi_error("[uwsgi-logcrypto] EVP_EncryptUpdate()");
free(encrypted);
goto error;
}
int tmplen = 0;
if (EVP_EncryptFinal_ex(uclc->encrypt_ctx, encrypted + e_len, &tmplen) <= 0) {
uwsgi_error("[uwsgi-logcrypto] EVP_EncryptFinal_ex()");
free(encrypted);
goto error;
}
uwsgi_buffer_destroy(ub);
ssize_t rlen = sendto(ul->fd, encrypted, e_len + tmplen, 0, (struct sockaddr *) &ul->addr.sa_in, ul->addr_len);
free(encrypted);
return rlen;
error:
uwsgi_buffer_destroy(ub);
return -1;
}
static void uwsgi_logcrypto_register() {
uwsgi_register_logger("crypto", uwsgi_crypto_logger);
}
struct uwsgi_plugin logcrypto_plugin = {
.name = "logcrypto",
.on_load = uwsgi_logcrypto_register,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='logcrypto'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['logcrypto']
+116 -22
View File
@@ -10,6 +10,7 @@ struct uwsgi_lua {
struct lua_State **L;
char *filename;
struct uwsgi_string_list *load;
} ulua;
#define lca(L, n) ulua_check_args(L, __FUNCTION__, n)
@@ -17,6 +18,7 @@ struct uwsgi_lua {
static struct uwsgi_option uwsgi_lua_options[] = {
{"lua", required_argument, 0, "load lua wsapi app", uwsgi_opt_set_str, &ulua.filename, 0},
{"lua-load", required_argument, 0, "load a lua file", uwsgi_opt_add_string_list, &ulua.load, 0},
{0, 0, 0, 0},
@@ -69,7 +71,7 @@ static int uwsgi_api_register_rpc(lua_State *L) {
lua_pushvalue(L, 2);
func = luaL_ref(L, LUA_REGISTRYINDEX);
uwsgi_log("registered function %d in global table\n", func);
uwsgi_log("registered function %d in Lua global table\n", func);
lfunc = func;
if (uwsgi_register_rpc((char *)name, 6, 0, (void *) lfunc)) {
@@ -387,36 +389,48 @@ static int uwsgi_lua_init(){
static void uwsgi_lua_app() {
int i;
if (ulua.filename) {
if (!ulua.filename && !ulua.load) return;
for(i=0;i<uwsgi.cores;i++) {
ulua.L[i] = luaL_newstate();
luaL_openlibs(ulua.L[i]);
luaL_register(ulua.L[i], "uwsgi", uwsgi_api);
if (luaL_loadfile(ulua.L[i], ulua.filename)) {
uwsgi_log("unable to load file %s: %s\n", ulua.filename, lua_tostring(ulua.L[i], -1));
exit(1);
struct uwsgi_string_list *usl = ulua.load;
while(usl) {
if (luaL_dofile(ulua.L[i], usl->value)) {
uwsgi_log("unable to load Lua file %s: %s\n", usl->value, lua_tostring(ulua.L[i], -1));
exit(1);
}
usl = usl->next;
}
if (ulua.filename) {
if (luaL_loadfile(ulua.L[i], ulua.filename)) {
uwsgi_log("unable to load Lua file %s: %s\n", ulua.filename, lua_tostring(ulua.L[i], -1));
exit(1);
}
// use a pcall
//lua_call(ulua.L[i], 0, 1);
if (lua_pcall(ulua.L[i], 0, 1, 0) != 0) {
uwsgi_log("%s\n", lua_tostring(ulua.L[i], -1));
exit(1);
}
// use a pcall
//lua_call(ulua.L[i], 0, 1);
if (lua_pcall(ulua.L[i], 0, 1, 0) != 0) {
uwsgi_log("%s\n", lua_tostring(ulua.L[i], -1));
exit(1);
}
// if the loaded lua app returns as a table, fetch the
// run function.
if (lua_istable(ulua.L[i], 2)) {
lua_pushstring(ulua.L[i], "run" );
lua_gettable(ulua.L[i], 2);
lua_replace(ulua.L[i], 2);
}
// if the loaded lua app returns as a table, fetch the
// run function.
if (lua_istable(ulua.L[i], 2)) {
lua_pushstring(ulua.L[i], "run" );
lua_gettable(ulua.L[i], 2);
lua_replace(ulua.L[i], 2);
}
if (! lua_isfunction(ulua.L[i], 2)) {
uwsgi_log("Can't find WSAPI entry point (no function, nor a table with function'run').\n");
exit(1);
if (! lua_isfunction(ulua.L[i], 2)) {
uwsgi_log("Can't find WSAPI entry point (no function, nor a table with function'run').\n");
exit(1);
}
}
}
}
}
@@ -665,13 +679,92 @@ static uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t a
#endif
if (sl <= 0xffff) {
memcpy(buffer, sv, sl);
lua_pop(L, 1);
return sl;
}
lua_pop(L, 1);
return 0;
}
static void uwsgi_lua_configurator_array(lua_State *L) {
int i;
int n = luaL_getn(L, -3);
for(i=1;i<=n;i++) {
lua_rawgeti(L, 1, i);
if (lua_istable(L, -1)) {
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
char *key = uwsgi_str((char *)lua_tostring(L, -2));
char *value = uwsgi_str((char *)lua_tostring(L, -1));
add_exported_option(key, value, 0);
lua_pop(L, 1);
}
}
}
}
static void uwsgi_lua_configurator(char *filename, char *magic_table[]) {
size_t len = 0;
uwsgi_log_initial("[uWSGI] getting Lua configuration from %s\n", filename);
char *code = uwsgi_open_and_read(filename, &len, 1, magic_table);
lua_State *L = luaL_newstate();
if (!L) {
uwsgi_log("unable to initialize Lua state for configuration\n");
exit(1);
}
luaL_openlibs(L);
if (luaL_dostring(L, code) != 0) {
uwsgi_log("error running Lua configurator: %s\n", lua_tostring(L, -1));
exit(1);
}
free(code);
if (!lua_istable(L, -1)) {
uwsgi_log("Lua configurator has to return a table !!!\n");
exit(1);
}
lua_pushnil(L);
// we always use uwsgi_str to avoid GC destroying our strings
// and to be able to call lua_close at the end
while (lua_next(L, -2) != 0) {
// array ?
if (lua_isnumber(L, -2)) {
uwsgi_lua_configurator_array(L);
break;
}
// dictionary
else {
char *key = uwsgi_str((char *)lua_tostring(L, -2));
if (lua_istable(L, -1)) {
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
char *value = uwsgi_str((char *)lua_tostring(L, -1));
add_exported_option(key, value, 0);
lua_pop(L, 1);
}
}
else {
char *value = uwsgi_str((char *)lua_tostring(L, -1));
add_exported_option(key, value, 0);
}
}
lua_pop(L, 1);
}
// this will destroy the whole Lua state
lua_close(L);
}
static void uwsgi_register_lua_features() {
uwsgi_register_configurator(".lua", uwsgi_lua_configurator);
}
struct uwsgi_plugin lua_plugin = {
@@ -688,5 +781,6 @@ struct uwsgi_plugin lua_plugin = {
.code_string = uwsgi_lua_code_string,
.rpc = uwsgi_lua_rpc,
.on_load = uwsgi_register_lua_features,
};
+9
View File
@@ -0,0 +1,9 @@
#include <uwsgi.h>
#include "client/dbclient.h"
extern "C" int uwsgi_mongodb_version() {
// this is only a hack to force the linked to embed libmongoclient.a
mongo::DBClientConnection c;
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
#include <uwsgi.h>
/*
a fake plugin used for preloading mongodb library when only available as static.
*/
int uwsgi_mongodb_version(void);
struct uwsgi_plugin mongodb_plugin = {
.name = "mongodb",
.init = uwsgi_mongodb_version,
};
+8
View File
@@ -0,0 +1,8 @@
NAME='mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
GCC_LIST = ['plugin', 'foobar.cc']
+1 -1
View File
@@ -96,7 +96,7 @@ static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
}
else {
char *sl = SG(sapi_headers).http_status_line;
uwsgi_response_prepare_headers(wsgi_req, sl, strlen(sl));
uwsgi_response_prepare_headers(wsgi_req, sl + 8 , strlen(sl) - 8);
}
h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
+5 -1
View File
@@ -513,6 +513,10 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
// We may be called after an early exit in XS_coroae_accept_request,
// before the environ is set up.
if (!wsgi_req->async_environ) return;
// dereference %env
SV *env = SvRV((SV *) wsgi_req->async_environ);
@@ -664,7 +668,7 @@ void uwsgi_perl_run_hook(SV *hook) {
}
static void uwsgi_perl_atexit() {
if (uwsgi.mywid == -1) goto realstuff;
if (uwsgi.mywid == 0) goto realstuff;
// if hijacked do not run atexit hooks
if (uwsgi.workers[uwsgi.mywid].hijacked)
+3 -5
View File
@@ -55,7 +55,6 @@ void uwsgi_opt_pyver(char *opt, char *foo, void *bar) {
}
#ifdef UWSGI_INI
void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) {
uwsgi_opt_load_ini(opt, value, NULL);
@@ -72,7 +71,6 @@ void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) {
}
}
#endif
struct uwsgi_option uwsgi_python_options[] = {
{"wsgi-file", required_argument, 0, "load .wsgi file", uwsgi_opt_set_str, &up.file_config, 0},
@@ -121,13 +119,13 @@ struct uwsgi_option uwsgi_python_options[] = {
{"web3", required_argument, 0, "load a web3 app", uwsgi_opt_set_str, &up.web3, 0},
{"pump", required_argument, 0, "load a pump app", uwsgi_opt_set_str, &up.pump, 0},
{"wsgi-lite", required_argument, 0, "load a wsgi-lite app", uwsgi_opt_set_str, &up.wsgi_lite, 0},
#ifdef UWSGI_INI
{"ini-paste", required_argument, 0, "load a paste.deploy config file containing uwsgi section", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
{"ini-paste-logged", required_argument, 0, "load a paste.deploy config file containing uwsgi section (load loggers too)", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"reload-os-env", no_argument, 0, "force reload of os.environ at each request", uwsgi_opt_true, &up.reload_os_env, 0},
#ifndef __CYGWIN__
#ifndef UWSGI_PYPY
{"no-site", no_argument, 0, "do not import site module", uwsgi_opt_true, &Py_NoSiteFlag, 0},
#endif
#endif
{"pyshell", no_argument, 0, "run an interactive python shell in the uWSGI environment", uwsgi_opt_pyshell, NULL, 0},
{"pyshell-oneshot", no_argument, 0, "run an interactive python shell in the uWSGI environment (one-shot variant)", uwsgi_opt_pyshell, NULL, 0},
@@ -292,7 +290,7 @@ void uwsgi_python_reset_random_seed() {
void uwsgi_python_atexit() {
if (uwsgi.mywid == -1) goto realstuff;
if (uwsgi.mywid == 0) goto realstuff;
// if hijacked do not run atexit hooks
if (uwsgi.workers[uwsgi.mywid].hijacked)
+32
View File
@@ -474,6 +474,37 @@ PyObject *py_uwsgi_lord_scroll(PyObject * self, PyObject * args) {
return ret;
}
static void scrolls_items(uint16_t pos, char *key, uint16_t keylen, void *data) {
PyObject *list = (PyObject *) data;
PyObject *zero = PyString_FromStringAndSize(key, keylen);
PyList_Append(list, zero);
Py_DECREF(zero);
}
PyObject *py_uwsgi_scrolls(PyObject * self, PyObject * args) {
char *legion_name = NULL;
if (!PyArg_ParseTuple(args, "s:scrolls", &legion_name)) {
return NULL;
}
uint64_t rlen = 0;
char *buf = uwsgi_legion_scrolls(legion_name, &rlen);
if (!buf) goto end;
PyObject *list = PyList_New(0);
if (uwsgi_hooked_parse_array(buf, rlen, scrolls_items, list)) {
goto error;
}
free(buf);
return list;
error:
free(buf);
end:
Py_INCREF(Py_None);
return Py_None;
}
#endif
PyObject *py_uwsgi_register_signal(PyObject * self, PyObject * args) {
@@ -2434,6 +2465,7 @@ static PyMethodDef uwsgi_advanced_methods[] = {
#ifdef UWSGI_SSL
{"i_am_the_lord", py_uwsgi_i_am_the_lord, METH_VARARGS, ""},
{"lord_scroll", py_uwsgi_lord_scroll, METH_VARARGS, ""},
{"scrolls", py_uwsgi_scrolls, METH_VARARGS, ""},
#endif
{"async_sleep", py_uwsgi_async_sleep, METH_VARARGS, ""},
{"async_connect", py_uwsgi_async_connect, METH_VARARGS, ""},
+22 -8
View File
@@ -58,11 +58,12 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
char *status_line = NULL;
size_t status_line_len = 0;
#ifdef PYTHREE
PyObject *zero = NULL;
PyObject *zero2 = NULL;
if (self != Py_None) {
PyObject *zero = PyUnicode_AsASCIIString(head);
zero = PyUnicode_AsASCIIString(head);
status_line = PyBytes_AsString(zero);
status_line_len = PyBytes_Size(zero);
Py_DECREF(zero);
}
else {
status_line = PyBytes_AsString(head);
@@ -73,9 +74,15 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
status_line_len = PyString_Size(head);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, status_line, status_line_len)) {
#ifdef PYTHREE
Py_DECREF(zero);
#endif
return PyErr_Format(PyExc_TypeError, "unable to set HTTP status line");
}
#ifdef PYTHREE
Py_DECREF(zero);
#endif
headers = PyTuple_GetItem(args, 1);
if (!headers) {
@@ -125,10 +132,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
PyObject *zero = PyUnicode_AsASCIIString(h_key);
zero = PyUnicode_AsASCIIString(h_key);
k = PyBytes_AsString(zero);
kl = PyBytes_Size(zero);
Py_DECREF(zero);
}
else {
k = PyBytes_AsString(h_key);
@@ -141,10 +147,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
PyObject *zero = PyUnicode_AsASCIIString(h_value);
v = PyBytes_AsString(zero);
vl = PyBytes_Size(zero);
Py_DECREF(zero);
zero2 = PyUnicode_AsASCIIString(h_value);
v = PyBytes_AsString(zero2);
vl = PyBytes_Size(zero2);
}
else {
v = PyBytes_AsString(h_value);
@@ -156,9 +161,18 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#endif
if (uwsgi_response_add_header(wsgi_req, k, kl, v, vl)) {
#ifdef PYTHREE
Py_DECREF(zero);
Py_DECREF(zero2);
#endif
return PyErr_Format(PyExc_TypeError, "unable to add header to the response");
}
#ifdef PYTHREE
Py_DECREF(zero);
Py_DECREF(zero2);
#endif
}
if (up.start_response_nodelay) {
+14 -14
View File
@@ -320,7 +320,7 @@ uint16_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[],
ret = rb_protect(rack_call_rpc_handler, rb_args, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
return 0;
}
@@ -489,7 +489,7 @@ void uwsgi_rack_preinit_apps() {
int error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
usl = usl->next;
}
@@ -519,7 +519,7 @@ void uwsgi_rack_init_apps(void) {
error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
usl = usl->next;
}
@@ -527,7 +527,7 @@ void uwsgi_rack_init_apps(void) {
if (ur.rack) {
ur.dispatcher = rb_protect(init_rack_app, rb_str_new2(ur.rack), &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
if (ur.dispatcher == Qnil) {
@@ -551,7 +551,7 @@ void uwsgi_rack_init_apps(void) {
uwsgi_log("loading rails app %s\n", ur.rails);
rb_protect( require_rails, 0, &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
uwsgi_log("rails app %s ready\n", ur.rails);
@@ -573,7 +573,7 @@ void uwsgi_rack_init_apps(void) {
if (acim_call == Qtrue) {
ur.dispatcher = rb_protect(uwsgi_rb_call_new, ac_dispatcher, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
}
@@ -583,7 +583,7 @@ void uwsgi_rack_init_apps(void) {
uwsgi_log("non-rack rails version detected...loading thin adapter...\n");
rb_protect( require_thin, 0, &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
VALUE thin_rack = rb_const_get(rb_cObject, rb_intern("Rack"));
@@ -591,7 +591,7 @@ void uwsgi_rack_init_apps(void) {
VALUE thin_rack_adapter_rails = rb_const_get(thin_rack_adapter, rb_intern("Rails"));
ur.dispatcher = rb_protect( uwsgi_rb_call_new, thin_rack_adapter_rails, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
exit(1);
}
}
@@ -963,7 +963,7 @@ VALUE init_rack_app( VALUE script ) {
#endif
rb_protect( require_rack, 0, &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
return Qnil;
}
@@ -1038,7 +1038,7 @@ int uwsgi_rack_mule(char *opt) {
if (uwsgi_endswith(opt, (char *)".rb")) {
rb_protect( uwsgi_require_file, rb_str_new2(opt), &error ) ;
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
return 0;
}
return 1;
@@ -1063,7 +1063,7 @@ void uwsgi_rb_post_fork() {
// call the post_fork_hook
rb_protect(uwsgi_rb_pfh, 0, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
}
@@ -1081,7 +1081,7 @@ int uwsgi_rack_mule_msg(char *message, size_t len) {
VALUE arg = rb_str_new(message, len);
rb_protect(uwsgi_rb_mmh, arg, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
}
return 1;
}
@@ -1107,7 +1107,7 @@ int uwsgi_rack_signal_handler(uint8_t sig, void *handler) {
rb_ary_store(args, 1, rbsig);
rb_protect(rack_call_signal_handler, args, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
rb_gc();
return -1;
}
@@ -1155,7 +1155,7 @@ int uwsgi_rack_spooler(char *filename, char *buf, uint16_t len, char *body, size
VALUE ret = rb_protect(uwsgi_rb_do_spooler, spool_dict, &error);
if (error) {
uwsgi_manage_exception(NULL, 0);
uwsgi_ruby_exception_log(NULL);
rb_gc();
return -1;
}
+7 -4
View File
@@ -244,7 +244,7 @@ static int uwsgi_ring_request(struct wsgi_request *wsgi_req) {
// *** REQUEST GENERATION ***
if (uwsgi_ring_request_item_add_keyword(hm, "request-method", 14, wsgi_req->method, wsgi_req->method_len)) goto end;
if (uwsgi_ring_request_item_add(hm, "uri", 3, wsgi_req->uri, wsgi_req->uri_len)) goto end;
if (uwsgi_ring_request_item_add(hm, "uri", 3, wsgi_req->path_info, wsgi_req->path_info_len)) goto end;
if (uwsgi_ring_request_item_add(hm, "server-name", 11, wsgi_req->host, wsgi_req->host_len)) goto end;
// server-port is required !!!
@@ -450,10 +450,13 @@ static int uwsgi_ring_setup() {
}
char *namespace = uwsgi_str(uring.app);
char *colon = strchr(namespace, ':');
char *colon = strchr(namespace, '/');
if (!colon) {
uwsgi_log("invalid ring application namespace/handler\n");
exit(1);
colon = strchr(namespace, ':');
if (!colon) {
uwsgi_log("invalid ring application namespace/handler\n");
exit(1);
}
}
*colon = 0;
uring.handler = uwsgi_jvm_call_object_static(clojure, clojure_var, uwsgi_jvm_str(namespace, 0), uwsgi_jvm_str(colon+1, 0));
+13
View File
@@ -1,3 +1,6 @@
import os
import shutil
jvm_path = 'plugins/jvm'
up = {}
@@ -14,3 +17,13 @@ CFLAGS.append('-I%s' % jvm_path)
LDFLAGS = []
LIBS = []
GCC_LIST = ['ring_plugin']
def post_build(config):
env = os.environ.get('VIRTUAL_ENV')
if env:
plugin = "%s/ring_plugin.so" % os.getcwd()
if os.path.exists(plugin):
tgt = "%s/bin/ring_plugin.so" % env
shutil.copyfile(plugin, tgt)
print("*** ring_plugin.so had been copied to %s" % tgt)
@@ -4,6 +4,9 @@
#ifdef __linux__
#include <crypt.h>
#elif defined(__CYGWIN__)
#include <crypt.h>
pthread_mutex_t ur_basicauth_crypt_mutex;
#else
pthread_mutex_t ur_basicauth_crypt_mutex;
#endif
+97 -66
View File
@@ -10,83 +10,133 @@ extern struct uwsgi_server uwsgi;
syntax:
route = /^foobar1(.*)/ cache:key=foo$1poo,type=body
route = /^foobar1 cache:var=PATH_INFO,type=body
route = /^foobar2 cache:var=REQUEST_URI,type=full
route = /^foobar3 cache:var=REQUEST_URI,type=body,content_type=text/html
route = /^foobar1(.*)/ cache:key=foo$1poo,content_type=text/html,name=foobar
*/
struct uwsgi_router_cache_conf {
// the name of the cache
char *name;
size_t name_len;
char *key;
size_t key_len;
char *var;
char *type;
long var_offset;
long var_offset_len;
char *content_type;
char *name;
size_t content_type_len;
// 0 -> full, 1 -> body
int type_num;
struct uwsgi_cache *cache;
char *expires_str;
uint64_t expires;
};
// be tolerant on errors
static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
// overwrite previous run
if (wsgi_req->cache_it) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
if (wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it_to);
wsgi_req->cache_it_to = NULL;
}
// build key and name
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
wsgi_req->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!wsgi_req->cache_it) return UWSGI_ROUTE_NEXT;
if (urcc->name) {
wsgi_req->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len);
if (!wsgi_req->cache_it_to) {
uwsgi_buffer_destroy(wsgi_req->cache_it);
wsgi_req->cache_it = NULL;
}
}
wsgi_req->cache_it_expires = urcc->expires;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;
if (!uwsgi.cache_max_items) return UWSGI_ROUTE_NEXT;
char *c_k = NULL;
uint16_t c_k_len = 0;
int k_need_free = 0;
if (urcc->key) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
c_k = uwsgi_regexp_apply_ovec(*subject, *subject_len, urcc->key, urcc->key_len, ur->ovector, ur->ovn);
c_k_len = strlen(c_k);
k_need_free = 1;
}
else {
char **key = (char **) (((char *) wsgi_req) + urcc->var_offset);
uint16_t *keylen = (uint16_t *) (((char *) wsgi_req) + urcc->var_offset_len);
c_k = *key;
c_k_len = *keylen;
}
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint64_t valsize = 0;
char *value = uwsgi_cache_magic_get(c_k, c_k_len, &valsize, urcc->name);
char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, urcc->name);
uwsgi_buffer_destroy(ub);
if (value) {
if (urcc->type_num == 1) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
}
// body only
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
uwsgi_response_write_body_do(wsgi_req, value, valsize);
free(value);
if (k_need_free) free(c_k);
if (ur->custom)
return UWSGI_ROUTE_NEXT;
return UWSGI_ROUTE_BREAK;
}
if (k_need_free) free(c_k);
return UWSGI_ROUTE_NEXT;
error:
free(value);
if (k_need_free) free(c_k);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cache_store;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"name", &urcc->name,
"expires", &urcc->expires_str, NULL)) {
uwsgi_log("invalid cachestore route syntax: %s\n", args);
goto error;
}
if (urcc->key) {
urcc->key_len = strlen(urcc->key);
}
if (urcc->name) {
urcc->name_len = strlen(urcc->name);
}
if (!urcc->key) {
uwsgi_log("invalid cachestore route syntax: you need to specify a cache key\n");
goto error;
}
if (urcc->expires_str) {
urcc->expires = strtoul(urcc->expires_str, NULL, 10);
}
ur->data2 = urcc;
return 0;
error:
if (urcc->key) free(urcc->key);
if (urcc->name) free(urcc->name);
if (urcc->expires_str) free(urcc->expires_str);
return -1;
}
static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cache;
ur->data = args;
@@ -94,10 +144,9 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urcc->key,
"var", &urcc->var,
"content_type", &urcc->content_type,
"name", &urcc->name,
"type", &urcc->type, NULL)) {
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
@@ -106,35 +155,15 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
urcc->key_len = strlen(urcc->key);
}
if (!urcc->key && !urcc->var) {
uwsgi_log("invalid route syntax: you need to specify a cache key or var\n");
if (!urcc->key) {
uwsgi_log("invalid route syntax: you need to specify a cache key\n");
exit(1);
}
if (!urcc->type) urcc->type = "full";
if (!urcc->content_type) urcc->content_type = "text/html";
urcc->content_type_len = strlen(urcc->content_type);
if (urcc->var) {
if (!strcmp(urcc->var, "REQUEST_URI")) {
urcc->var_offset = offsetof(struct wsgi_request, uri);
urcc->var_offset_len = offsetof(struct wsgi_request, uri_len);
}
else if (!strcmp(urcc->var, "PATH_INFO")) {
urcc->var_offset = offsetof(struct wsgi_request, path_info);
urcc->var_offset_len = offsetof(struct wsgi_request, path_info_len);
}
else {
urcc->var_offset = offsetof(struct wsgi_request, uri);
urcc->var_offset_len = offsetof(struct wsgi_request, uri_len);
}
}
if (!strcmp(urcc->type, "body")) {
urcc->type_num = 1;
}
ur->data2 = urcc;
return 0;
}
@@ -148,6 +177,8 @@ static int uwsgi_router_cache_continue(struct uwsgi_route *ur, char *args) {
static void router_cache_register() {
uwsgi_register_router("cache", uwsgi_router_cache);
uwsgi_register_router("cache-continue", uwsgi_router_cache_continue);
uwsgi_register_router("cachestore", uwsgi_router_cache_store);
uwsgi_register_router("cache-store", uwsgi_router_cache_store);
}
struct uwsgi_plugin router_cache_plugin = {
+272
View File
@@ -40,10 +40,282 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
#ifdef UWSGI_ROUTING
static int uwsgi_routing_func_rpc(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
char *argv[UMAX8];
// this is the size of each argument
uint16_t argvs[UMAX8];
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
uint16_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
ret = UWSGI_ROUTE_BREAK;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;}
if (uwsgi_response_add_content_length(wsgi_req, size)) {free(response) ; goto end;}
uwsgi_response_write_body_do(wsgi_req, response, size);
free(response);
end:
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
}
}
return ret;
}
static int uwsgi_routing_func_rpc_blob(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
char *argv[UMAX8];
// this is the size of each argument
uint16_t argvs[UMAX8];
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
uint16_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
ret = UWSGI_ROUTE_NEXT;
// optimization
if (!wsgi_req->headers_sent) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;}
if (uwsgi_response_add_connection_close(wsgi_req)) {free(response) ; goto end;}
}
uwsgi_response_write_body_do(wsgi_req, response, size);
free(response);
end:
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
}
}
return ret;
}
// "next" || "continue" || "break(.*)" || "goon" || "goto .+"
static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
char *argv[UMAX8];
// this is the size of each argument
uint16_t argvs[UMAX8];
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
uint16_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
ret = UWSGI_ROUTE_CONTINUE;
if (!uwsgi_strncmp(response, size, "next", 4 )) {
ret = UWSGI_ROUTE_NEXT;
}
else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
ret = UWSGI_ROUTE_CONTINUE;
}
else if (!uwsgi_strncmp(response, size, "goon", 4 )) {
ret = UWSGI_ROUTE_GOON;
}
else if (!uwsgi_starts_with(response, size, "break", 5 )) {
ret = UWSGI_ROUTE_BREAK;
if (size > 6) {
if (uwsgi_response_prepare_headers(wsgi_req, response+6, size-6)) goto end0;
if (uwsgi_response_add_connection_close(wsgi_req)) goto end0;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end0;
// no need to check for return value
uwsgi_response_write_headers_do(wsgi_req);
}
}
else if (!uwsgi_starts_with(response, size, "goto ", 5)) {
ret = UWSGI_ROUTE_BREAK;
if (size > 5) {
// find the label
struct uwsgi_route *routes = uwsgi.routes;
while(routes) {
if (!routes->label) goto next;
if (!uwsgi_strncmp(routes->label, routes->label_len, response+5, size-5)) {
ret = UWSGI_ROUTE_NEXT;
wsgi_req->route_goto = routes->pos;
goto found;
}
next:
routes = routes->next;
}
goto end0;
found:
if (wsgi_req->route_goto <= wsgi_req->route_pc) {
wsgi_req->route_goto = 0;
uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
ret = UWSGI_ROUTE_BREAK;
}
}
}
end0:
free(response);
end:
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
}
}
return ret;
}
/*
ur->data = the func name
ur->custom = the number of arguments
ur->data2 = the pointer to the args
ur->data3 = the pointer to the args sizes
*/
static int uwsgi_router_rpc_base(struct uwsgi_route *ur, char *args) {
ur->custom = 0;
ur->data2 = uwsgi_calloc(sizeof(char *) * UMAX8);
ur->data3 = uwsgi_calloc(sizeof(uint16_t) * UMAX8);
char *p = strtok(args, " ");
while(p) {
if (!ur->data) {
ur->data = p;
}
else {
if (ur->custom >= UMAX8) {
uwsgi_log("unable to register route: maximum number of rpc args reached\n");
free(ur->data2);
free(ur->data3);
return -1;
}
char **argv = (char **) ur->data2;
uint16_t *argvs = (uint16_t *) ur->data3;
argv[ur->custom] = p;
argvs[ur->custom] = strlen(p);
ur->custom++;
}
p = strtok(NULL, " ");
}
if (!ur->data) {
uwsgi_log("unable to register route: you need to specify an rpc function\n");
free(ur->data2);
free(ur->data3);
return -1;
}
return 0;
}
static int uwsgi_router_rpc(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_rpc;
return uwsgi_router_rpc_base(ur, args);
}
static int uwsgi_router_rpc_ret(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_rpc_ret;
return uwsgi_router_rpc_base(ur, args);
}
static int uwsgi_router_rpc_blob(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_rpc_blob;
return uwsgi_router_rpc_base(ur, args);
}
static void router_rpc_register() {
uwsgi_register_router("call", uwsgi_router_rpc);
uwsgi_register_router("rpc", uwsgi_router_rpc);
uwsgi_register_router("rpcret", uwsgi_router_rpc_ret);
uwsgi_register_router("rpcblob", uwsgi_router_rpc_blob);
uwsgi_register_router("rpcnext", uwsgi_router_rpc_blob);
}
#endif
struct uwsgi_plugin rpc_plugin = {
.name = "rpc",
.modifier1 = 173,
.request = uwsgi_rpc_request,
#ifdef UWSGI_ROUTING
.on_load = router_rpc_register,
#endif
};
+526
View File
@@ -0,0 +1,526 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
#define UWSGI_SSI_MAX_ARGS 8
/*
uWSGI server side includes implementation
*/
struct uwsgi_ssi_arg {
char *key;
size_t key_len;
char *value;
size_t val_len;
};
struct uwsgi_ssi_cmd {
char *name;
size_t name_len;
struct uwsgi_buffer *(*func)(struct wsgi_request *, struct uwsgi_ssi_arg *, int);
struct uwsgi_ssi_cmd *next;
};
struct uwsgi_ssi_cmd *uwsgi_ssi_commands = NULL;
static struct uwsgi_ssi_cmd* uwsgi_ssi_get_cmd(char *name, size_t name_len) {
struct uwsgi_ssi_cmd *usc = uwsgi_ssi_commands;
while(usc) {
if (!uwsgi_strncmp(usc->name, usc->name_len, name, name_len)) {
return usc;
}
usc = usc->next;
}
return NULL;
}
static struct uwsgi_ssi_cmd *uwsgi_register_ssi_command(char *name, struct uwsgi_buffer *(*func)(struct wsgi_request *, struct uwsgi_ssi_arg *, int)) {
struct uwsgi_ssi_cmd *old_usc = NULL,*usc = uwsgi_ssi_commands;
while(usc) {
if (!strcmp(usc->name, name)) {
return usc;
}
old_usc = usc;
usc = usc->next;
}
usc = uwsgi_calloc(sizeof(struct uwsgi_ssi_cmd));
usc->name = name;
usc->name_len = strlen(name);
usc->func = func;
if (old_usc) {
old_usc->next = usc;
}
else {
uwsgi_ssi_commands = usc;
}
return usc;
}
static int uwsgi_ssi_parse_args(struct wsgi_request *wsgi_req, char *buf, size_t len, struct uwsgi_ssi_arg *argv, int *argc) {
// status [0]null/= [1]" [2]" [3]\s
size_t i;
uint8_t status = 0;
char *key = buf;
size_t key_len = 0;
char *value = NULL;
size_t val_len = 0;
for(i=0;i<len;i++) {
switch(status) {
case 0:
if (buf[i] == '=') {
status = 1;
}
else {
key_len++;
}
break;
case 1:
if (buf[i] == '"') {
status = 2;
}
else {
return -1;
}
break;
case 2:
if (buf[i] == '"') {
status = 3;
argv[*argc].key = key; argv[*argc].key_len = key_len;
argv[*argc].value = value; argv[*argc].val_len = val_len;
*argc = *argc+1;
if (*argc >= UWSGI_SSI_MAX_ARGS) {
return -1;
}
key = NULL;
key_len = 0;
value = NULL;
val_len = 0;
}
else {
if (!value) {
value = buf + i;
}
val_len++;
}
break;
case 3:
if (!isspace((int)buf[i])) {
key = buf + i;
key_len = 1;
status = 0;
}
break;
default:
return -1;
}
}
return 0;
}
static struct uwsgi_buffer *uwsgi_ssi_parse_command(struct wsgi_request *wsgi_req, char *buf, size_t len) {
// storage for arguments
struct uwsgi_ssi_arg argv[UWSGI_SSI_MAX_ARGS];
int argc = 0;
// first remove white spaces from the begin and the end
char *cmd = buf;
size_t cmd_len = len;
size_t i;
for(i=0;i<len;i++) {
if (isspace((int)buf[i])) {
cmd++;
cmd_len--;
}
else {
break;
}
}
// then rstrip (skipping the first char...)
for(i=(len-1);i>0;i--) {
if (isspace((int)buf[i])) {
cmd_len--;
}
else {
break;
}
}
// now get the command
char *ssi_cmd = cmd;
size_t ssi_cmd_len = 0;
int found = 0;
for(i=0;i<cmd_len;i++) {
if (isspace(cmd[i])) {
found = 1;
break;
}
ssi_cmd_len++;
}
struct uwsgi_ssi_cmd *usc = uwsgi_ssi_get_cmd(ssi_cmd, ssi_cmd_len);
if (!usc) return NULL ;
if (!found) goto run;
// now split the args
char *cmd_args = cmd + ssi_cmd_len + 1;
size_t cmd_args_len = cmd_len - (ssi_cmd_len + 1);
for(i=(ssi_cmd_len + 1);i<cmd_len;i++) {
if (isspace((int)cmd[i])) {
cmd_args++;
cmd_args_len--;
}
else {
break;
}
}
if (uwsgi_ssi_parse_args(wsgi_req, cmd_args, cmd_args_len, argv, &argc)) {
return NULL;
}
run:
return usc->func(wsgi_req, argv, argc);
}
static struct uwsgi_buffer *uwsgi_ssi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t i;
uint8_t status = 0;
char *cmd = NULL;
size_t cmd_len = 0;
struct uwsgi_buffer *ub = uwsgi_buffer_new(len);
// parsing status 0[null] 1[<] 2[!] 3[-] 4[-] 5[#/-] 6[-] 7[>]
// on status 6-7-8 the reset action come back to 5 instead of 0
for(i=0;i<len;i++) {
switch(status) {
case 0:
if (buf[i] == '<') {
status = 1;
}
else {
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 1:
status = 0;
if (buf[i] == '!') {
status = 2;
}
else {
if (uwsgi_buffer_append(ub, "<", 1)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 2:
status = 0;
if (buf[i] == '-') {
status = 3;
}
else {
if (uwsgi_buffer_append(ub, "<!", 2)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 3:
status = 0;
if (buf[i] == '-') {
status = 4;
}
else {
if (uwsgi_buffer_append(ub, "<!-", 3)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 4:
status = 0;
if (buf[i] == '#') {
status = 5;
}
else {
if (uwsgi_buffer_append(ub, "<!--", 4)) goto error;
if (uwsgi_buffer_append(ub, &buf[i], 1)) goto error;
}
break;
case 5:
if (buf[i] == '-') {
status = 6;
break;
}
if (!cmd) {
cmd = buf+i;
}
cmd_len++;
break;
case 6:
status = 5;
if (buf[i] == '-') {
status = 7;
}
else {
cmd_len+=2;
}
break;
case 7:
status = 5;
if (buf[i] == '>') {
status = 0;
struct uwsgi_buffer *ub_cmd = uwsgi_ssi_parse_command(wsgi_req, cmd, cmd_len);
if (ub_cmd) {
if (uwsgi_buffer_append(ub, ub_cmd->buf, ub_cmd->pos)) {
uwsgi_buffer_destroy(ub_cmd);
goto error;
}
uwsgi_buffer_destroy(ub_cmd);
}
cmd = NULL;
cmd_len = 0;
}
else {
cmd_len+=3;
}
break;
default:
goto error;
}
}
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
static int uwsgi_ssi_request(struct wsgi_request *wsgi_req) {
struct uwsgi_buffer *ub = NULL;
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
if (!wsgi_req->document_root_len || !wsgi_req->path_info_len) {
uwsgi_log("[uwsgi-ssi] DOCUMENT_ROOT and PATH_INFO must be defined !!!\n");
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
char *filename = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
size_t filename_len = wsgi_req->document_root_len + 1 + wsgi_req->path_info_len;
// we expand the path for future security implementations
char *real_filename = uwsgi_expand_path(filename, filename_len, NULL);
free(filename);
if (!real_filename) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(real_filename);
free(real_filename);
if (!ub_ssi) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos);
uwsgi_buffer_destroy(ub_ssi);
if (!ub) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
// prepare headers
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_length
if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_type
if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) {
uwsgi_500(wsgi_req);
goto end;
}
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
if (ub) {
uwsgi_buffer_destroy(ub);
}
return UWSGI_OK;
}
static char *uwsgi_ssi_get_arg(struct uwsgi_ssi_arg *argv, int argc, char *key, size_t key_len, size_t *val_len) {
int i;
for(i=0;i<argc;i++) {
struct uwsgi_ssi_arg *arg = &argv[i];
if (!uwsgi_strncmp(arg->key, arg->key_len, key, key_len)) {
*val_len = arg->val_len;
return arg->value;
}
}
return NULL;
}
// echo command
static struct uwsgi_buffer *ssi_cmd_echo(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
size_t var_len = 0;
char *var = uwsgi_ssi_get_arg(argv, argc, "var", 3, &var_len);
if (!var || var_len == 0) return NULL;
uint16_t rlen = 0;
char *value = uwsgi_get_var(wsgi_req, var, var_len, &rlen);
if (!value) return NULL;
if (rlen == 0) return NULL;
struct uwsgi_buffer *ub = uwsgi_buffer_new(rlen);
if (uwsgi_buffer_append(ub, value, rlen)) {
uwsgi_buffer_destroy(ub);
return NULL;
}
return ub;
};
// printenv command
static struct uwsgi_buffer *ssi_cmd_printenv(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
int i;
for (i = 0; i < wsgi_req->var_cnt; i += 2) {
if (uwsgi_buffer_append(ub, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) goto error;
if (uwsgi_buffer_append(ub, "=", 1)) goto error;
if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto error;
if (uwsgi_buffer_append(ub, "\n", 1)) goto error;
}
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
};
// include command
static struct uwsgi_buffer *ssi_cmd_include(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
size_t var_len = 0;
char *var = uwsgi_ssi_get_arg(argv, argc, "file", 4, &var_len);
if (!var || var_len == 0) return NULL;
char *filename = uwsgi_concat2n(var, var_len, "", 0);
struct uwsgi_buffer *ub = uwsgi_buffer_from_file(filename);
free(filename);
return ub;
}
// cache command (uWSGI specific)
static struct uwsgi_buffer *ssi_cmd_cache(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) {
size_t var_len = 0;
char *var = uwsgi_ssi_get_arg(argv, argc, "key", 3, &var_len);
if (!var || var_len == 0) return NULL;
size_t cache_len = 0;
char *cache = uwsgi_ssi_get_arg(argv, argc, "name", 4, &cache_len);
char *cache_name = NULL;
if (cache && cache_len) {
cache_name = uwsgi_concat2n(cache, cache_len, "", 0);
}
uint64_t rlen = 0;
char *value = uwsgi_cache_magic_get(var, var_len, &rlen, cache_name);
if (cache_name) free(cache_name);
struct uwsgi_buffer *ub = NULL;
if (value) {
ub = uwsgi_buffer_new(rlen);
if (uwsgi_buffer_append(ub, value, rlen)) {
free(value);
uwsgi_buffer_destroy(ub);
return NULL;
}
free(value);
}
return ub;
}
static int uwsgi_routing_func_ssi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_buffer *ub = NULL;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub_filename) goto end;
struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(ub_filename->buf);
uwsgi_buffer_destroy(ub_filename);
if (!ub_ssi) goto end;
ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos);
uwsgi_buffer_destroy(ub_ssi);
if (!ub) goto end;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end;
if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
if (ub) uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_ssi(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_ssi;
ur->data = args;
ur->data_len = strlen(args);
return 0;
}
static int uwsgi_ssi_init() {
uwsgi_register_ssi_command("echo", ssi_cmd_echo);
uwsgi_register_ssi_command("printenv", ssi_cmd_printenv);
uwsgi_register_ssi_command("include", ssi_cmd_include);
uwsgi_register_ssi_command("cache", ssi_cmd_cache);
return 0;
}
static void uwsgi_ssi_register_router() {
uwsgi_register_router("ssi", uwsgi_router_ssi);
}
static void uwsgi_ssi_log(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
struct uwsgi_plugin ssi_plugin = {
.name = "ssi",
.modifier1 = 19,
.init = uwsgi_ssi_init,
.request = uwsgi_ssi_request,
.after_request = uwsgi_ssi_log,
.on_load = uwsgi_ssi_register_router,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='ssi'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['ssi']
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
void stats_pusher_mongodb(struct uwsgi_stats_pusher_instance *, time_t, char *, size_t);
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include "client/dbclient.h"
+8 -1
View File
@@ -1,7 +1,14 @@
import os
NAME='stats_pusher_mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
LIBS = []
if not 'UWSGI_MONGODB_NOLIB' in os.environ:
LIBS.append('-lmongoclient')
LIBS.append('-lboost_thread')
LIBS.append('-lboost_filesystem')
GCC_LIST = ['plugin', 'stats_pusher_mongodb.cc']
+137
View File
@@ -0,0 +1,137 @@
#include <uwsgi.h>
/*
this is a stats pusher plugin for the statsd server:
--stats-push statsd:address[,prefix]
example:
--stats-push statsd:127.0.0.1:8125,myinstance
it is pretty minimal, but will be extended after the 2.0 metric subsystem will be released
*/
extern struct uwsgi_server uwsgi;
// configuration of a statsd node
struct statsd_node {
int fd;
union uwsgi_sockaddr addr;
socklen_t addr_len;
char *prefix;
uint16_t prefix_len;
};
static int statsd_send_worker_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, char *metric, uint16_t metric_len, int64_t value) {
struct statsd_node *sn = (struct statsd_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
if (uwsgi_buffer_num64(ub, wid)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_num64(ub, value)) return -1;
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("stats_pusher_statsd()/sendto()");
}
return 0;
}
static int statsd_send_core_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, int coreid, char *metric, uint16_t metric_len, int64_t value) {
struct statsd_node *sn = (struct statsd_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
if (uwsgi_buffer_num64(ub, wid)) return -1;
if (uwsgi_buffer_append(ub, ".core", 5)) return -1;
if (uwsgi_buffer_num64(ub, coreid)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_num64(ub, value)) return -1;
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("stats_pusher_statsd()/sendto()");
}
return 0;
}
static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
if (!uspi->configured) {
struct statsd_node *sn = uwsgi_calloc(sizeof(struct statsd_node));
char *comma = strchr(uspi->arg, ',');
if (comma) {
sn->prefix = comma+1;
sn->prefix_len = strlen(sn->prefix);
*comma = 0;
}
else {
sn->prefix = "uwsgi";
sn->prefix_len = 5;
}
char *colon = strchr(uspi->arg, ':');
if (!colon) {
uwsgi_log("invalid statsd address %s\n", uspi->arg);
if (comma) *comma = ',';
free(sn);
return;
}
sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in);
sn->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sn->fd < 0) {
uwsgi_error("stats_pusher_statsd()/socket()");
if (comma) *comma = ',';
free(sn);
return;
}
uwsgi_socket_nb(sn->fd);
if (comma) *comma = ',';
uspi->data = sn;
uspi->configured = 1;
}
// we use the same buffer for all of the packets
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
int i, j;
// send workers metrics
for(i=1;i<=uwsgi.numproc;i++) {
if (statsd_send_worker_gauge(ub, uspi, i, "requests", 8, uwsgi.workers[i].requests)) goto end;
for(j=0;j<uwsgi.cores;j++) {
if (statsd_send_core_gauge(ub, uspi, i, j, "exceptions", 10, uwsgi.workers[i].cores[j].exceptions)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "requests", 8, uwsgi.workers[i].cores[j].requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "routed_requests", 15, uwsgi.workers[i].cores[j].routed_requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "static_requests", 15, uwsgi.workers[i].cores[j].static_requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "offloaded_requests", 18, uwsgi.workers[i].cores[j].offloaded_requests)) goto end;
}
}
end:
uwsgi_buffer_destroy(ub);
}
static void stats_pusher_statsd_init(void) {
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("statsd", stats_pusher_statsd);
// we use a custom format not the JSON one
usp->raw = 1;
}
struct uwsgi_plugin stats_pusher_statsd_plugin = {
.name = "stats_pusher_statsd",
.on_load = stats_pusher_statsd_init,
};
@@ -0,0 +1,7 @@
NAME='stats_pusher_statsd'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['plugin']
+29
View File
@@ -0,0 +1,29 @@
#include <uwsgi.h>
int uwsgi_v8_init(void);
void uwsgi_v8_apps(void);
void uwsgi_v8_configurator(char *, char **);
uint16_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char *);
int uwsgi_v8_signal_handler(uint8_t, void *);
static void uwsgi_v8_register(void) {
uwsgi_register_configurator(".js", uwsgi_v8_configurator);
}
extern struct uwsgi_option uwsgi_v8_options[];
static int uwsgi_v8_request(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
struct uwsgi_plugin v8_plugin = {
.name = "v8",
.modifier1 = 24,
.init = uwsgi_v8_init,
.init_apps = uwsgi_v8_apps,
.options = uwsgi_v8_options,
.on_load = uwsgi_v8_register,
.rpc = uwsgi_v8_rpc,
.request = uwsgi_v8_request,
.signal_handler = uwsgi_v8_signal_handler,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='v8'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lv8']
GCC_LIST = ['plugin', 'v8_uwsgi.cc']
+237
View File
@@ -0,0 +1,237 @@
#include <uwsgi.h>
#include <v8.h>
struct uwsgi_v8 {
v8::Persistent<v8::Context> *contexts;
struct uwsgi_string_list *load;
} uv8;
extern struct uwsgi_server uwsgi;
extern struct uwsgi_plugin v8_plugin;
struct uwsgi_option uwsgi_v8_options[] = {
{(char *)"v8-load", required_argument, 0, (char *)"load a javascript file", uwsgi_opt_add_string_list, &uv8.load, 0},
{0, 0, 0, 0},
};
static v8::Handle<v8::Value> uwsgi_v8_api_register_signal(const v8::Arguments& args) {
if (args.Length() > 2) {
uint8_t uwsgi_signal = args[0]->Uint32Value();
v8::String::Utf8Value signal_kind(args[1]->ToString());
v8::Persistent<v8::Function> func = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(args[2]));
if (uwsgi_register_signal(uwsgi_signal, *signal_kind, *func, v8_plugin.modifier1)) {
uwsgi_log("[uwsgi-v8] unable to register signal %d\n", uwsgi_signal);
return v8::Undefined();
}
return v8::True();
}
return v8::Undefined();
}
static v8::Handle<v8::Value> uwsgi_v8_api_register_rpc(const v8::Arguments& args) {
if (args.Length() > 1) {
v8::String::Utf8Value name(args[0]->ToString());
uint8_t j_argc = 0;
if (args.Length() > 2) {
j_argc = args[2]->Uint32Value();
}
v8::Persistent<v8::Function> func = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(args[1]));
if (uwsgi_register_rpc(*name, v8_plugin.modifier1, j_argc, *func)) {
uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name);
return v8::Undefined();
}
return v8::True();
}
return v8::Undefined();
}
static void uwsgi_v8_load_file(v8::Persistent<v8::Context> context, char *filename) {
v8::HandleScope handle_scope;
v8::Context::Scope context_scope(context);
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
// we do not use TryCatch as we directly use stderr and simply exit with error code 1
v8::Handle<v8::Script> script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) );
free(code);
if (script.IsEmpty()) {
exit(1);
}
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
exit(1);
}
}
extern "C" int uwsgi_v8_init(){
uwsgi_log("Initializing V8 %s environment... (%d Isolates)\n", v8::V8::GetVersion(), uwsgi.cores);
uv8.contexts = (v8::Persistent<v8::Context> *) uwsgi_malloc( sizeof(v8::Persistent<v8::Context>*) * uwsgi.cores );
return 0;
}
static v8::Handle<v8::Value> uwsgi_v8_api_log(const v8::Arguments& args) {
if (args.Length() > 0) {
v8::String::Utf8Value str(args[0]->ToString());
size_t slen = strlen(*str);
if ((*str)[slen-1] == '\n') {
uwsgi_log("%s", *str);
}
else {
uwsgi_log("%s\n", *str);
}
}
return v8::Undefined();
}
static v8::Persistent<v8::Context> uwsgi_v8_new_isolate(int core) {
v8::HandleScope handle_scope;
if (core > 0) {
// create a new isolate
v8::Isolate *isolate = v8::Isolate::New();
// set as the current isolate
v8::Isolate::Scope iscope(isolate);
}
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// print alias is always handy
global->Set(v8::String::New("uwsgi_log"), v8::FunctionTemplate::New(uwsgi_v8_api_log));
global->Set(v8::String::New("uwsgi_register_rpc"), v8::FunctionTemplate::New(uwsgi_v8_api_register_rpc));
global->Set(v8::String::New("uwsgi_register_signal"), v8::FunctionTemplate::New(uwsgi_v8_api_register_signal));
// create a new context
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
return context;
}
extern "C" void uwsgi_v8_apps() {
if (!uv8.load) return;
int i;
for(i=0;i<uwsgi.cores;i++) {
uv8.contexts[i] = uwsgi_v8_new_isolate(i);
struct uwsgi_string_list *usl = uv8.load;
while(usl) {
uwsgi_v8_load_file(uv8.contexts[i], usl->value);
usl = usl->next;
}
}
}
extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) {
v8::HandleScope handle_scope;
uwsgi_log_initial("[uWSGI] getting javascript (V8) configuration from %s\n", filename);
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
v8::Handle<v8::Context> context = v8::Context::New();
v8::Context::Scope context_scope(context);
// we do not use TryCatch as we directly use stderr and simply exit with error code 1
v8::Handle<v8::Script> script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) );
if (script.IsEmpty()) {
exit(1);
}
free(code);
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
exit(1);
}
if (!result->IsArray() && !result->IsObject()) {
uwsgi_log("javascript return value must be an object or an array !!!\n");
exit(1);
}
uint32_t i;
const v8::Local<v8::Array> props = result->ToObject()->GetPropertyNames();
const uint32_t l = props->Length();
for(i=0;i<l;i++) {
const v8::Local<v8::Value> key = props->Get(i);
const v8::Local<v8::Value> value = result->ToObject()->Get(key);
v8::String::Utf8Value c_key(key->ToString());
if (value->IsArray()) {
uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value();
uint32_t j;
for(j=0;j<opt_l;j++) {
v8::String::Utf8Value c_value(value->ToObject()->Get(j)->ToString());
add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0);
}
}
else {
v8::String::Utf8Value c_value(value->ToString());
add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0);
}
}
}
extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
v8::HandleScope handle_scope;
v8::Handle<v8::Value> argj[256];
struct wsgi_request *wsgi_req = current_wsgi_req();
v8::Context::Scope context_scope(uv8.contexts[wsgi_req->async_id]);
v8::Persistent<v8::Function> l_func = static_cast<v8::Function*> (func);
uint8_t i;
for(i=0;i<argc;i++) {
argj[i] = v8::String::New(argv[i], argvs[i]);
}
v8::Handle<v8::Value> result = l_func->Call(l_func, argc, argj);
if (result.IsEmpty()) return 0;
v8::Handle<v8::String> robj = result->ToString();
v8::String::Utf8Value r_value(robj);
if (!*robj) return 0;
uint16_t rlen = robj->Length();
memcpy(buffer, *r_value, rlen);
// call GC every time, could be overkill, we should allow to tune that choice
while(!v8::V8::IdleNotification()) {};
return rlen;
}
extern "C" int uwsgi_v8_signal_handler(uint8_t sig, void *handler) {
int ret = 0;
v8::HandleScope handle_scope;
struct wsgi_request *wsgi_req = current_wsgi_req();
v8::Context::Scope context_scope(uv8.contexts[wsgi_req->async_id]);
v8::Persistent<v8::Function> l_func = static_cast<v8::Function*> (handler);
v8::Handle<v8::Value> argj[1];
argj[0] = v8::Number::New(sig);
v8::Handle<v8::Value> result = l_func->Call(l_func, 1, argj);
if (result.IsEmpty()) ret = -1;
while(!v8::V8::IdleNotification()) {};
return ret;
}
+8
View File
@@ -0,0 +1,8 @@
import os
NAME='xslt'
CFLAGS = os.popen('xslt-config --cflags').read().rstrip().split()
LDFLAGS = os.popen('xslt-config --libs').read().rstrip().split()
LIBS = []
GCC_LIST = ['xslt']
+406
View File
@@ -0,0 +1,406 @@
#include <uwsgi.h>
#include <libxslt/xsltutils.h>
#include <libxslt/transform.h>
/*
XSLT request plugin
it takes an XML file as input (taken from DOCUMENT_ROOT + PATH_INFO by default)
it search for an XSLT stylesheet (by default in DOCUMENT_ROOT + PATH_INFO - ext + .xsl|.xslt)
it applies params (by default taken from the QUERY_STRING)
XSLT routing instruction
xslt:doc=<path1>,stylesheet=<path2>,params=<params>
*/
struct uwsgi_xslt_config {
struct uwsgi_string_list *docroot;
struct uwsgi_string_list *ext;
struct uwsgi_string_list *var;
struct uwsgi_string_list *stylesheet;
char *content_type;
uint16_t content_type_len;
} uxslt;
struct uwsgi_router_xslt_conf {
char *doc;
uint16_t doc_len;
char *stylesheet;
uint16_t stylesheet_len;
char *params;
uint16_t params_len;
char *content_type;
uint16_t content_type_len;
};
struct uwsgi_option uwsgi_xslt_options[] = {
{"xslt-docroot", required_argument, 0, "add a document_root for xslt processing", uwsgi_opt_add_string_list, &uxslt.docroot, 0},
{"xslt-ext", required_argument, 0, "search for xslt stylesheets with the specified extension", uwsgi_opt_add_string_list, &uxslt.ext, 0},
{"xslt-var", required_argument, 0, "get the xslt stylesheet path from the specified request var", uwsgi_opt_add_string_list, &uxslt.var, 0},
{"xslt-stylesheet", required_argument, 0, "if no xslt stylesheet file can be found, use the specified one", uwsgi_opt_add_string_list, &uxslt.stylesheet, 0},
{"xslt-content-type", required_argument, 0, "set the content-type for the xslt rsult (default: text/html)", uwsgi_opt_set_str, &uxslt.content_type, 0},
{NULL, 0, 0, NULL, NULL, NULL, 0},
};
static char *uwsgi_xslt_apply(char *xmlfile, char *xsltfile, char *params, int *rlen) {
char **vparams = NULL;
char *tmp_params = NULL;
uint16_t count = 0;
if (params) {
// first count the number of items
size_t i;
size_t params_len = strlen(params);
for(i=0;i<params_len;i++) {
if (params[i] == '=') {
count++;
}
}
vparams = uwsgi_calloc( sizeof(char *) * ((count * 2) + 1));
tmp_params = uwsgi_str(params);
char *p = strtok(tmp_params, "&");
int pos = 0;
while(p) {
char *equal = strchr(p, '=');
if (equal) {
*equal = 0;
vparams[pos] = p; pos++;
vparams[pos] = uwsgi_concat3("\"", equal+1, "\""); pos++;
}
p = strtok(NULL, "&");
}
}
// we reset them every time to avoid collision with other xml engines
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
xmlDocPtr doc = xmlParseFile(xmlfile);
if (!doc) {
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
return NULL;
}
xsltStylesheetPtr ss = xsltParseStylesheetFile((const xmlChar *) xsltfile);
if (!ss) {
xmlFreeDoc(doc);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
return NULL;
}
xmlDocPtr res = xsltApplyStylesheet(ss, doc, (const char **) vparams);
if (!res) {
xsltFreeStylesheet(ss);
xmlFreeDoc(doc);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
return NULL;
}
xmlChar *output;
int ret = xsltSaveResultToString(&output, rlen, res, ss);
xsltFreeStylesheet(ss);
xmlFreeDoc(res);
xmlFreeDoc(doc);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
if (ret < 0) return NULL;
return (char *) output;
}
static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
char *xmlfile = NULL;
char *output = NULL;
int output_rlen = 0;
char filename[PATH_MAX+1];
size_t filename_len = 0;
char stylesheet[PATH_MAX+1];
size_t stylesheet_len = 0;
char *params = NULL;
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
// set default values
if (!uxslt.content_type_len) {
if (!uxslt.content_type) {
uxslt.content_type = "text/html";
}
uxslt.content_type_len = strlen(uxslt.content_type);
}
struct uwsgi_string_list *usl = uxslt.docroot;
// first check for static docroots
if (usl) {
while(usl) {
xmlfile = uwsgi_concat3n(usl->value, usl->len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
if (uwsgi_is_file(xmlfile)) {
break;
}
free(xmlfile);
xmlfile = NULL;
usl = usl->next;
}
}
// fallback to DOCUMENT_ROOT
else {
if (wsgi_req->document_root_len == 0) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
xmlfile = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len);
}
if (!xmlfile) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
// we have the full path, check if it is valid
if (!uwsgi_expand_path(xmlfile, strlen(xmlfile), filename)) {
free(xmlfile);
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
free(xmlfile);
if (!uwsgi_is_file(filename)) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
filename_len = strlen(filename);
// now search for the xslt file
int found = 0;
// first check for specific vars
usl = uxslt.var;
while(usl) {
uint16_t rlen;
char *value = uwsgi_get_var(wsgi_req, usl->value, usl->len, &rlen);
if (value) {
memcpy(stylesheet, value, rlen);
stylesheet[rlen] = 0;
stylesheet_len = rlen;
found = 1;
break;
}
usl = usl->next;
}
if (found) goto apply;
// then check for custom extensions
if (uxslt.ext) {
usl = uxslt.ext;
while(usl) {
char *tmp_path = uwsgi_concat2n(filename, filename_len, usl->value, usl->len);
if (uwsgi_is_file(tmp_path)) {
stylesheet_len = filename_len + usl->len;
memcpy(stylesheet, tmp_path, stylesheet_len);
stylesheet[stylesheet_len] = 0;
free(tmp_path);
found = 1;
break;
}
free(tmp_path);
usl = usl->next;
}
}
// use default extensions .xsl/.xslt
else {
char *tmp_path = uwsgi_concat2n(filename, filename_len, ".xsl", 4);
if (uwsgi_is_file(tmp_path)) {
stylesheet_len = filename_len + 4;
memcpy(stylesheet, tmp_path, stylesheet_len);
stylesheet[stylesheet_len] = 0;
free(tmp_path);
goto apply;
}
free(tmp_path);
tmp_path = uwsgi_concat2n(filename, filename_len, ".xslt", 5);
if (uwsgi_is_file(tmp_path)) {
stylesheet_len = filename_len + 5;
memcpy(stylesheet, tmp_path, stylesheet_len);
stylesheet[stylesheet_len] = 0;
found = 1;
}
free(tmp_path);
}
if (found) goto apply;
// finally check for static stylesheets
usl = uxslt.stylesheet;
while(usl) {
if (uwsgi_is_file(usl->value)) {
memcpy(stylesheet, usl->value, usl->len);
stylesheet_len = usl->len;
stylesheet[stylesheet_len] = 0;
found = 1;
break;
}
usl = usl->next;
}
if (found) goto apply;
uwsgi_404(wsgi_req);
return UWSGI_OK;
apply:
if (wsgi_req->query_string_len > 0) {
params = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0);
}
// we have both the file and the stylesheet, let's run the engine
output = uwsgi_xslt_apply(filename, stylesheet, params, &output_rlen);
if (params) free(params);
if (!output) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
// prepare headers
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_length
if (uwsgi_response_add_content_length(wsgi_req, output_rlen)) {
uwsgi_500(wsgi_req);
goto end;
}
// content_type
if (uwsgi_response_add_content_type(wsgi_req, uxslt.content_type, uxslt.content_type_len)) {
uwsgi_500(wsgi_req);
goto end;
}
uwsgi_response_write_body_do(wsgi_req, output, output_rlen);
end:
xmlFree(output);
return UWSGI_OK;
}
static void uwsgi_xslt_log(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_xslt_conf *urxc = (struct uwsgi_router_xslt_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_doc = NULL;
struct uwsgi_buffer *ub_stylesheet = NULL;
struct uwsgi_buffer *ub_params = NULL;
struct uwsgi_buffer *ub_content_type = NULL;
ub_doc = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->doc, urxc->doc_len);
if (!ub_doc) goto end;
ub_stylesheet = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->stylesheet, urxc->stylesheet_len);
if (!ub_stylesheet) goto end;
if (urxc->params) {
ub_params = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->params, urxc->params_len);
if (!ub_params) goto end;
}
if (urxc->content_type) {
ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len);
if (!ub_content_type) goto end;
}
int rlen;
char *output = uwsgi_xslt_apply( ub_doc->buf, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen);
if (!output) goto end;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, rlen)) goto end;
if (uwsgi_response_add_content_type(wsgi_req, urxc->content_type, urxc->content_type_len)) goto end;
uwsgi_response_write_body_do(wsgi_req, output, rlen);
xmlFree(output);
end:
if (ub_doc) uwsgi_buffer_destroy(ub_doc);
if (ub_stylesheet) uwsgi_buffer_destroy(ub_stylesheet);
if (ub_params) uwsgi_buffer_destroy(ub_params);
if (ub_content_type) uwsgi_buffer_destroy(ub_content_type);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_xslt(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_xslt;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_xslt_conf *urxc = uwsgi_calloc(sizeof(struct uwsgi_router_xslt_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"doc", &urxc->doc,
"stylesheet", &urxc->stylesheet,
"content_type", &urxc->content_type,
"params", &urxc->params,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urxc->doc && !urxc->stylesheet) {
uwsgi_log("invalid route syntax: you need to specify a doc and a stylesheet\n");
exit(1);
}
urxc->doc_len = strlen(urxc->doc);
urxc->stylesheet_len = strlen(urxc->stylesheet);
if (urxc->params) urxc->params_len = strlen(urxc->params);
if (!urxc->content_type) urxc->content_type = "text/html";
urxc->content_type_len = strlen(urxc->content_type);
ur->data2 = urxc;
return 0;
}
static void router_xslt_register() {
uwsgi_register_router("xslt", uwsgi_router_xslt);
}
struct uwsgi_plugin xslt_plugin = {
.name = "xslt",
.modifier1 = 23,
.options = uwsgi_xslt_options,
.request = uwsgi_request_xslt,
.after_request = uwsgi_xslt_log,
.on_load = router_xslt_register,
};
+203 -194
View File
@@ -1,32 +1,37 @@
#include "../uwsgi.h"
/*
generic ZeroMQ functions + Mongrel2 protocol parser
*/
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
void *uwsgi_zeromq_init() {
if (!uwsgi.zmq_context) {
uwsgi.zmq_context = zmq_init(1);
if (uwsgi.zmq_context == NULL) {
uwsgi_error("zmq_init()");
exit(1);
}
if (uwsgi.zmq_context == NULL) {
uwsgi_error("zmq_init()");
exit(1);
}
}
return uwsgi.zmq_context;
}
void uwsgi_zeromq_init_sockets() {
uwsgi_zeromq_init();
uwsgi_zeromq_init();
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (!uwsgi_sock->proto_name || strcmp(uwsgi_sock->proto_name, "zmq")) {
goto zmq_next;
}
uwsgi_proto_zeromq_setup(uwsgi_sock);
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (!uwsgi_sock->proto_name || strcmp(uwsgi_sock->proto_name, "zmq")) {
goto zmq_next;
}
uwsgi_proto_zeromq_setup(uwsgi_sock);
zmq_next:
uwsgi_sock = uwsgi_sock->next;
uwsgi_sock = uwsgi_sock->next;
}
}
}
@@ -80,6 +85,7 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val));
}
// pretty easy, we get the file and we map it to wsgi_req->post_file, uWSGI read api will automatically use this
if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) {
wsgi_req->post_file = fopen(json_val, "r");
if (!wsgi_req->post_file) {
@@ -126,12 +132,12 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-forwarded-for"))) {
char *colon = strchr(json_val, ',');
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val));
}
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val));
}
}
@@ -228,7 +234,7 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
if (!uwsgi_strncmp("host", 4, key, keylen)) {
char *colon = memchr(val, ':', vallen);
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1)-val));
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1) - val));
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
@@ -250,11 +256,11 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) {
char *colon = memchr(val, ',', vallen);
if (colon) {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen);
}
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val);
}
else {
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen);
}
}
else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) {
async_upload += 1;
@@ -266,9 +272,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
if (query_string == NULL) {
// always set QUERY_STRING
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
}
// always set QUERY_STRING
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
}
// reject uncomplete upload
if (async_upload == 1) {
@@ -277,6 +283,7 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
return 0;
}
// fake function, we parse requests in the accept phase
int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
@@ -284,130 +291,35 @@ int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) {
void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_id) {
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull);
#ifdef ZMQ_FD
if (uwsgi.threads > 1) {
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd_threads[async_id], &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd_threads[async_id], &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
}
uwsgi_sock->retry[async_id] = 1;
}
#endif
}
void uwsgi_proto_zeromq_setup(struct uwsgi_socket *uwsgi_sock) {
char *responder = strchr(uwsgi_sock->name, ',');
if (!responder) {
uwsgi_log("invalid zeromq address\n");
exit(1);
}
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
responder++;
uwsgi_sock->pub = zmq_socket(uwsgi.zmq_context, ZMQ_PUB);
if (uwsgi_sock->pub == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
// generate uuid
uuid_t uuid_zmq;
uuid_generate(uuid_zmq);
uuid_unparse(uuid_zmq, uwsgi_sock->uuid);
if (zmq_setsockopt(uwsgi_sock->pub, ZMQ_IDENTITY, uwsgi_sock->uuid, 36) < 0) {
uwsgi_error("zmq_setsockopt()");
exit(1);
}
if (zmq_connect(uwsgi_sock->pub, responder) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
uwsgi_log("zeromq UUID for responder %s on worker %d: %.*s\n", responder, uwsgi.mywid, 36, uwsgi_sock->uuid);
uwsgi_sock->proto = uwsgi_proto_zeromq_parser;
uwsgi_sock->proto_accept = uwsgi_proto_zeromq_accept;
uwsgi_sock->proto_close = uwsgi_proto_zeromq_close;
/*
uwsgi_sock->proto_write = uwsgi_proto_zeromq_write;
uwsgi_sock->proto_write_header = uwsgi_proto_zeromq_write_header;
uwsgi_sock->proto_sendfile = uwsgi_proto_zeromq_sendfile;
*/
uwsgi_sock->proto_thread_fixup = uwsgi_proto_zeromq_thread_fixup;
uwsgi_sock->edge_trigger = 1;
uwsgi_sock->retry = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->retry[0] = 1;
// inform loop engine about edge trigger status
uwsgi.is_et = 1;
// initialize a lock for multithread usage
if (uwsgi.threads > 1) {
pthread_mutex_init(&uwsgi_sock->lock, NULL);
}
// one pull per-thread
if (pthread_key_create(&uwsgi_sock->key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull);
#ifdef ZMQ_FD
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd, &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
}
if (uwsgi.threads > 1) {
uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->fd_threads[0] = uwsgi_sock->fd;
}
#else
uwsgi_sock->fd = -1;
#endif
uwsgi_sock->bound = 1;
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
uwsgi_sock->recv_flag = ZMQ_DONTWAIT;
#else
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
#endif
// fake function, the bosy is i na file or completely in memory
ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
return 0;
}
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
zmq_msg_t message;
@@ -527,19 +439,14 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2);
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
// handle post data
// handle post data (in memory)
if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) {
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
#ifdef UWSGI_DEBUG
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
#endif
wsgi_req->post_file = tmpfile();
if (fwrite(message_ptr, wsgi_req->post_cl, 1, wsgi_req->post_file) != 1) {
uwsgi_error("fwrite()");
zmq_msg_close(&message);
goto retry;
}
rewind(wsgi_req->post_file);
wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl);
memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl);
}
}
@@ -563,10 +470,6 @@ retry:
return -1;
}
static void uwsgi_proto_zeromq_free(void *data, void *hint) {
free(data);
}
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
zmq_msg_t reply;
@@ -574,82 +477,188 @@ void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
if (!wsgi_req->proto_parser_pos)
return;
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, uwsgi_proto_zeromq_free, NULL);
if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock);
// no need to pass a free function (the buffer will be freed during cloe_request)
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()");
#else
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()");
#endif
uwsgi_error("zmq_send()");
}
if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
}
ssize_t uwsgi_proto_zeromq_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
zmq_msg_t reply;
char *zmq_body;
if (len == 0)
return 0;
if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) {
uwsgi_error("uwsgi_proto_zeromq_write()/zmq_msg_init_size()");
return -1;
}
zmq_body = uwsgi_concat2n(wsgi_req->proto_parser_buf, (int) wsgi_req->proto_parser_pos, buf, (int) len);
//uwsgi_log("|%.*s|\n", (int)wsgi_req->proto_parser_pos+len, zmq_body);
char *zmq_body = zmq_msg_data(&reply);
memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos);
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
zmq_msg_init_data(&reply, zmq_body, wsgi_req->proto_parser_pos + len, uwsgi_proto_zeromq_free, NULL);
if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_lock(&wsgi_req->socket->lock);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
#else
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
#endif
if (!uwsgi.ignore_write_errors) {
uwsgi_error("zmq_send()");
}
wsgi_req->write_errors++;
if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
return 0;
return -1;
}
if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock);
if (uwsgi.threads > 1)
pthread_mutex_unlock(&wsgi_req->socket->lock);
zmq_msg_close(&reply);
return len;
return UWSGI_OK;
}
ssize_t uwsgi_proto_zeromq_sendfile(struct wsgi_request * wsgi_req) {
/*
ssize_t len;
char buf[65536];
size_t remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of
messages mongrel2 is able to manage). If we send a big static file we can fill that buffer immediately. How to deal with this ? We know that the
message ring can contains a fixed amount of messages. We could try to split the file in chunks (upto the maximum number supported by a specific mongrel2 instance).
This is suboptimal, but there are no better solutions for now. Before you ask: do you really think that sending a single message with a 2GB file is a good approach ?????
By the way, for now, waiting for a better approach, we use a 2MB buffer. Should support flawlessly files up to 32MB without being rejected by mongrel2. For bigger files you
can tune it to higher values (or increase the mongrel2 ring buffer)
wsgi_req->sendfile_fd_chunk = 65536;
*/
if (uwsgi.async > 1) {
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
return uwsgi_proto_zeromq_write(wsgi_req, buf, len);
#define UWSGI_MONGREL2_MAX_MSGSIZE 2*1024*1024
int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
size_t chunk_size = UMIN( len - wsgi_req->write_pos, UWSGI_MONGREL2_MAX_MSGSIZE);
char *tmp_buf = uwsgi_malloc(chunk_size);
ssize_t rlen = read(fd, tmp_buf, chunk_size);
if (rlen <= 0) {
free(tmp_buf);
return -1;
}
wsgi_req->write_pos += rlen;
if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) {
free(tmp_buf);
return -1;
}
while (remains) {
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
uwsgi_error("read()");
return -1;
}
wsgi_req->sendfile_fd_pos += len;
len = uwsgi_proto_zeromq_write(wsgi_req, buf, len);
remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
free(tmp_buf);
if (wsgi_req->write_pos == len) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
return wsgi_req->sendfile_fd_pos;
void uwsgi_proto_zeromq_setup(struct uwsgi_socket *uwsgi_sock) {
char *responder = strchr(uwsgi_sock->name, ',');
if (!responder) {
uwsgi_log("invalid zeromq address\n");
exit(1);
}
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
responder++;
uwsgi_sock->pub = zmq_socket(uwsgi.zmq_context, ZMQ_PUB);
if (uwsgi_sock->pub == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
// generate uuid
uuid_t uuid_zmq;
uuid_generate(uuid_zmq);
uuid_unparse(uuid_zmq, uwsgi_sock->uuid);
if (zmq_setsockopt(uwsgi_sock->pub, ZMQ_IDENTITY, uwsgi_sock->uuid, 36) < 0) {
uwsgi_error("zmq_setsockopt()");
exit(1);
}
if (zmq_connect(uwsgi_sock->pub, responder) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
uwsgi_log("zeromq UUID for responder %s on worker %d: %.*s\n", responder, uwsgi.mywid, 36, uwsgi_sock->uuid);
uwsgi_sock->proto = uwsgi_proto_zeromq_parser;
uwsgi_sock->proto_accept = uwsgi_proto_zeromq_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_zeromq_read_body;
uwsgi_sock->proto_write = uwsgi_proto_zeromq_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_zeromq_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_zeromq_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_zeromq_close;
uwsgi_sock->proto_thread_fixup = uwsgi_proto_zeromq_thread_fixup;
uwsgi_sock->edge_trigger = 1;
uwsgi_sock->retry = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->retry[0] = 1;
// inform loop engine about edge trigger status
uwsgi.is_et = 1;
// initialize a lock for multithread usage
if (uwsgi.threads > 1) {
pthread_mutex_init(&uwsgi_sock->lock, NULL);
}
// one pull per-thread
if (pthread_key_create(&uwsgi_sock->key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull);
#ifdef ZMQ_FD
size_t zmq_socket_len = sizeof(int);
if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd, &zmq_socket_len) < 0) {
uwsgi_error("zmq_getsockopt()");
exit(1);
}
if (uwsgi.threads > 1) {
uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.threads);
uwsgi_sock->fd_threads[0] = uwsgi_sock->fd;
}
#else
uwsgi_sock->fd = -1;
#endif
uwsgi_sock->bound = 1;
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
uwsgi_sock->recv_flag = ZMQ_DONTWAIT;
#else
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
#endif
}
-2
View File
@@ -91,8 +91,6 @@ setup(name='uWSGI',
description='The uWSGI server',
author='Unbit',
author_email='info@unbit.it',
download_url='http://projects.unbit.it/downloads/uwsgi-%s.tar.gz'
% (uc.uwsgi_version),
license='GPL2',
py_modules=['uwsgidecorators'],
distclass=uWSGIDistribution,
+21
View File
@@ -0,0 +1,21 @@
Ring Test Suite
================
how to build and run
---------------------
* cd UWSGIROOT
* cd t/ring
* lein uberjar
* cd ../..
* uwsgi t/ring/config.ini
* open http://localhost:9090 in your browser
run cases in jetty
-------------------
* lein ring server
* open http://localhost:3000 in your browser
+11
View File
@@ -0,0 +1,11 @@
[uwsgi]
http-socket = :9090
http-socket-modifier1 = 8
http-socket-modifier2 = 1
jvm-classpath = plugins/jvm/uwsgi.jar
jvm-classpath = t/ring/target/uwsgi-ring-tests-0.0.1-standalone.jar
jvm-class = uwsgi/ring/tests/app
ring-app = uwsgi.ring.tests.app/app
+10
View File
@@ -0,0 +1,10 @@
(defproject unbit/uwsgi-ring-tests "0.0.1"
:description "uwsgi-ring-tests: test cases for uwsgi ring server"
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.5"]
[ring/ring "1.1.0"]]
:source-paths ["src"]
:aot [uwsgi.ring.tests.app]
)
+29
View File
@@ -0,0 +1,29 @@
(ns uwsgi.ring.tests.app
(:use compojure.core)
(:use [ring.middleware params
keyword-params
nested-params
multipart-params])
(:require [compojure.route :as route]
[uwsgi.ring.tests.basic :as basic]
[uwsgi.ring.tests.body :as body]
[uwsgi.ring.tests.simple :as simple]
[uwsgi.ring.tests.upload :as upload])
(:gen-class
:main true))
(defn app-routes [req]
(if (= (get req :uri) "/")
(basic/index-page req)
((routes simple/app-routes body/app-routes upload/app-routes (route/not-found "<h1>Page not found</h1>")) req)))
(def app
(-> app-routes
wrap-keyword-params
wrap-nested-params
wrap-params
wrap-multipart-params))
(defn -main [& args]
(println "uwsgi ring tests app loaded"))
+30
View File
@@ -0,0 +1,30 @@
(ns uwsgi.ring.tests.basic)
(defn index-page [req] {:status 200
:headers { "Content-Type" "text/html" , "Server" "uWSGI" }
:body (str "<h1>Ring test suites</h1>"
"<h2>Simple tests</h2>"
"<ul>"
"<li><a href='/hello'>hello</a></li>"
"<li><a href='/echo?msg=abc'>echo</a></li>"
"<li><a href='/palindrome?msg=abc'>palindrome</a></li>"
"</ul>"
"<h2>Body type tests</h2>"
"<ul>"
"<li><a href='/sequence'>sequence</a></li>"
"<li><a href='/file'>file</a></li>"
"<li><a href='/stream'>stream</a></li>"
"</ul>"
"<h2>Upload tests</h2>"
"<form action='/upload' enctype='multipart/form-data' method='post'>"
"<p>"
"Please select a file<br>"
"<input type='file' name='file' size='40'>"
"</p>"
"<input type='submit' value='Upload'>"
"</form>"
"<h2>Other tests</h2>"
"<ul>"
"<li>...</li>"
"</ul>")})
+20
View File
@@ -0,0 +1,20 @@
(ns uwsgi.ring.tests.body
(:use [compojure.core]))
; generating primary numbers
; http://clojuredocs.org/clojure_core/clojure.core/lazy-seq#example_1000
(defn sieve [s]
(cons (first s)
(lazy-seq (sieve (filter #(not= 0 (mod % (first s)))
(rest s))))))
(defn numsequence [] (take 20 (sieve (iterate inc 2))))
(defn file [] (java.io.File. "CONTRIBUTORS"))
(defn stream [] (java.io.FileInputStream. (java.io.File. "CONTRIBUTORS")))
(defroutes app-routes
(GET "/sequence" [] (numsequence))
(GET "/file" [] (file))
(GET "/stream" [] (stream)))
+14
View File
@@ -0,0 +1,14 @@
(ns uwsgi.ring.tests.simple
(:use [compojure.core]) )
(defn hello [] "Hello, World!")
(defn echo [msg] msg)
(defn palindrome [msg] (clojure.string/reverse msg) )
(defroutes app-routes
(GET "/hello" [] (hello) )
(GET "/echo" [msg] (echo msg) )
(GET "/palindrome" [msg] (palindrome msg) )
)
+20
View File
@@ -0,0 +1,20 @@
(ns uwsgi.ring.tests.upload
(:use [compojure.core]))
(defn upload-file [fname fsize fbody] {
:status 200
:headers { "Content-Type" "text/html" , "Server" "uWSGI" }
:body (str "<h1>Uploaded file</h1>"
"<ul>"
"<li>" fname "</li>"
"<li>" fsize "</li>"
"</ul>")})
(defroutes app-routes
(POST "/upload" {params :params}
(let [file (params :file)
file-name (file :filename)
file-size (file :size)
file-body (file :tempfile)]
(upload-file file-name file-size file-body))))
+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<!-- Edited by XMLSpy® -->
<catalog>
<cd>
<title>Quintessence</title>
<artist>Borknagar</artist>
</cd>
<cd>
<title>Torn Beyond Reason</title>
<artist>Woods Of Desolation</artist>
</cd>
<cd>
<title>Autumn Aurora</title>
<artist>Drudkh</artist>
</cd>
<cd>
<title>Om</title>
<artist>Negura Bunget</artist>
</cd>
<cd>
<title>Frostnacht</title>
<artist>Helrunar</artist>
</cd>
</catalog>
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Blackmetal albums</h2>
<table border="1">
<tr bgcolor="black">
<th style="color:white">Title</th>
<th style="color:white">Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
<td>-<xsl:value-of select="$foobar"/>-</td>
<td><xsl:value-of select="$agent"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
+5
View File
@@ -0,0 +1,5 @@
[uwsgi]
http-socket = :9090
plugin = xslt
xml_storage = t/xslt
route = /(.*)$ xslt:doc=%(xml_storage)/$1.xml,stylesheet=%(xml_storage)/$1.xml.xslt,content_type=text/html,params=foobar=test&agent=${HTTP_USER_AGENT}
-51
View File
@@ -1,51 +0,0 @@
/* taken from http://wiki.unbit.it/UnbitKernel */
struct uidsec_struct {
/* network limits */
unsigned short ipv4_tcp_port;
unsigned short ipv4_udp_port;
unsigned short ipv4_tcp_control_port;
int ipv4_tcp_socket_protection;
unsigned long long ipv4_firewall_mask;
/* limits */
int fs_readonly;
/* process markers */
int domain_id;
int fcgi_id;
int scgi_id;
int apps_id;
int wapp_id;
int ssh_id;
int cron_id;
/* thread ? */
int cloned_vm;
/* process limit */
int max_dom_proc;
int max_apps_proc;
int max_apps_thread;
int max_ssh_proc;
int max_cron_proc;
/* misc */
int control_uid;
int listen_backlog;
int errors;
/* counters */
int accept_cnt;
int accept_last;
int fork_cnt;
int fork_last;
unsigned long long bio_read;
unsigned long long bio_write;
int memory_errors;
};
+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 = '2013-03-02'
s.date = '2013-03-30'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]

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