Compare commits

..
20 Commits
Author SHA1 Message Date
Unbit 2c9ebdaa69 updated gemspec for 1.9.10 2013-05-11 17:12:00 +02:00
Unbit fbd9e5b4d7 goroutines support must be completely rewritten :( 2013-05-11 16:57:41 +02:00
unbit b9a3425b6d Merge pull request #276 from prymitive/build_fixes
better check for default value, this allows using false or empty string ...
2013-05-11 02:53:56 -07:00
Łukasz Mierzwa d4742c611b better check for default value, this allows using false or empty string as defaults 2013-05-11 11:43:29 +02:00
Unbit c645a590aa added goroutine reference to gccgo 2013-05-11 08:43:46 +02:00
Unbit 275a7fe63f added --go-args 2013-05-11 08:26:02 +02:00
unbit 0ff16d8312 Merge pull request #275 from prymitive/df
fixed legion-smart-attach-daemon2
2013-05-10 14:21:42 -07:00
Łukasz Mierzwa 1cb31d6c7e fixed legion-smart-attach-daemon2 2013-05-10 20:51:39 +02:00
Unbit 8a6eb553df fixed attach-daemon 2013-05-10 17:20:44 +02:00
Unbit 946af8b9ee added errorlimiter.ini example config 2013-05-10 15:15:51 +02:00
Unbit 098a1f647e added final routes or running rules at the end of the request 2013-05-10 15:08:33 +02:00
Unbit c9681dc430 Merge branch 'master' of github.com:unbit/uwsgi 2013-05-10 08:18:33 +02:00
Unbit ff0b8b2d53 fixed #274 2013-05-10 08:17:54 +02:00
unbit 75f520d43a Merge pull request #255 from prymitive/airbrake_fixes
few airbrake fixes
2013-05-09 11:52:29 -07:00
Unbit 65209748ba completed the first phase of the gccgo plugin 2013-05-09 19:55:27 +02:00
Unbit cd604ef07b extended the build system to support .o files and added preliminary gccgo plugin 2013-05-09 18:38:53 +02:00
Łukasz Mierzwa 51da8bc531 * report more data in airbrake plugin
* preserve text version of backtrace (there might be multiple alarm handlers for any segfault)
* fix reload errors
2013-05-09 15:44:29 +02:00
Unbit 2374ba12bd better file descriptor management for alarm threads 2013-05-09 15:17:57 +02:00
Unbit 0a75aaec25 added the uwsgi_takeover commodity function 2013-05-09 13:53:22 +02:00
Unbit a8c286ae83 prepare for gccgo integration 2013-05-09 11:43:01 +02:00
19 changed files with 615 additions and 116 deletions
+2 -2
View File
@@ -181,6 +181,7 @@ void uwsgi_daemons_spawn_all() {
continue;
}
#endif
ud->registered = 1;
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
@@ -194,7 +195,6 @@ void uwsgi_daemons_spawn_all() {
else {
uwsgi_spawn_daemon(ud);
}
ud->registered = 1;
}
ud = ud->next;
}
@@ -366,7 +366,7 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
freq = atoi(comma + 1);
}
command = space + 1;
if (!strcmp(opt, "smart-attach-daemon2")) {
if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) {
daemonize = 1;
}
}
+2 -1
View File
@@ -348,7 +348,8 @@ void uwsgi_setup_workers() {
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
#ifdef UWSGI_ROUTING
uwsgi_fixup_routes();
uwsgi_fixup_routes(uwsgi.routes);
uwsgi_fixup_routes(uwsgi.final_routes);
#endif
}
+1
View File
@@ -853,6 +853,7 @@ next:
// 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) {
if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now();
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;
+6
View File
@@ -388,6 +388,12 @@ void uwsgi_reload(char **argv) {
}
}
if (uwsgi.alarm_thread) {
if (i == uwsgi.alarm_thread->queue) continue;
if (i == uwsgi.alarm_thread->pipe[0]) continue;
if (i == uwsgi.alarm_thread->pipe[1]) continue;
}
if (uwsgi.log_master) {
if (uwsgi.original_log_fd > -1) {
if (i == uwsgi.original_log_fd) {
+18 -12
View File
@@ -77,19 +77,8 @@ void uwsgi_mule(int id) {
}
}
uwsgi_mule_run();
if (uwsgi.mules[id - 1].patch) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->mule) {
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
// never here ?
end_me(1);
}
}
}
}
uwsgi_mule_handler();
}
else if (pid > 0) {
uwsgi.mules[id - 1].id = id;
@@ -98,6 +87,23 @@ void uwsgi_mule(int id) {
}
}
void uwsgi_mule_run() {
int id = uwsgi.muleid;
int i;
if (uwsgi.mules[id - 1].patch) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->mule) {
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
// never here ?
end_me(1);
}
}
}
}
uwsgi_mule_handler();
}
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
struct uwsgi_mule_farm *umf = farm->mules;
+53 -7
View File
@@ -166,9 +166,8 @@ static void uwsgi_routing_reset_memory(struct wsgi_request *wsgi_req, struct uws
}
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
int uwsgi_apply_routes_do(struct uwsgi_route *routes, struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
struct uwsgi_route *routes = uwsgi.routes;
int n = -1;
char *orig_subject = subject;
@@ -268,9 +267,22 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
return UWSGI_ROUTE_CONTINUE;
}
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
return uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0);
}
void uwsgi_apply_final_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.final_routes) return;
// avoid loops
if (wsgi_req->is_routing) return;
wsgi_req->is_final_routing = 1;
uwsgi_apply_routes_do(uwsgi.final_routes, wsgi_req, NULL, 0);
}
static void *uwsgi_route_get_condition_func(char *name) {
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
while(urc) {
@@ -286,7 +298,10 @@ 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;
struct uwsgi_route *old_ur = NULL, *ur = uwsgi.routes;
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
ur = uwsgi.final_routes;
}
uint64_t pos = 0;
while(ur) {
old_ur = ur;
@@ -298,7 +313,12 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
old_ur->next = ur;
}
else {
uwsgi.routes = ur;
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
uwsgi.final_routes = ur;
}
else {
uwsgi.routes = ur;
}
}
ur->pos = pos;
@@ -409,8 +429,7 @@ done:
exit(1);
}
void uwsgi_fixup_routes() {
struct uwsgi_route *ur = uwsgi.routes;
void uwsgi_fixup_routes(struct uwsgi_route *ur) {
while(ur) {
// prepare the main pointers
ur->ovn = uwsgi_calloc(sizeof(int) * uwsgi.cores);
@@ -612,6 +631,9 @@ static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_ro
// find the label
struct uwsgi_route *routes = uwsgi.routes;
if (wsgi_req->is_final_routing) {
routes = uwsgi.final_routes;
}
while(routes) {
if (!routes->label) goto next;
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
@@ -1291,6 +1313,14 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
uwsgi_uuid(ret);
*vallen = 36;
}
else if (!uwsgi_strncmp(key, keylen, "status", 6)) {
ret = uwsgi_num2str(wsgi_req->status);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "rtime", 5)) {
ret = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
*vallen = strlen(ret);
}
return ret;
}
@@ -1537,5 +1567,21 @@ void uwsgi_routing_dump() {
routes = routes->next;
}
uwsgi_log("*** end of the internal routing table ***\n");
routes = uwsgi.final_routes;
if (!routes) return;
uwsgi_log("*** dumping internal final routing table ***\n");
while(routes) {
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);
}
routes = routes->next;
}
uwsgi_log("*** end of the internal final routing table ***\n");
}
#endif
+21 -15
View File
@@ -122,21 +122,7 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
}
}
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->spooler_init) {
uwsgi.p[i]->spooler_init();
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->spooler_init) {
uwsgi.gp[i]->spooler_init();
}
}
spooler(uspool);
uwsgi_spooler_run();
}
else if (pid > 0) {
uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid);
@@ -145,6 +131,26 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
return pid;
}
void uwsgi_spooler_run() {
int i;
struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler;
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->spooler_init) {
uwsgi.p[i]->spooler_init();
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->spooler_init) {
uwsgi.gp[i]->spooler_init();
}
}
spooler(uspool);
}
void destroy_spool(char *dir, char *file) {
if (chdir(dir)) {
+1 -1
View File
@@ -644,7 +644,7 @@ safe:
#ifdef UWSGI_ROUTING
// before sending the file, we need to check if some rule applies
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
return 0;
}
wsgi_req->routes_applied = 1;
+26 -9
View File
@@ -607,6 +607,20 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uwsgi.workers[uwsgi.mywid].rss_size = rss;
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
// this is used for MAX_REQUESTS
uwsgi.workers[uwsgi.mywid].delta_requests++;
}
#ifdef UWSGI_ROUTING
// apply final routes after accounting
uwsgi_apply_final_routes(wsgi_req);
#endif
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
@@ -629,15 +643,6 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
free(wsgi_req->proto_parser_buf);
}
if (!wsgi_req->do_not_account) {
uwsgi.workers[0].requests++;
uwsgi.workers[uwsgi.mywid].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
// this is used for MAX_REQUESTS
uwsgi.workers[uwsgi.mywid].delta_requests++;
}
// after_request hook
if (uwsgi.p[wsgi_req->uh->modifier1]->after_request)
uwsgi.p[wsgi_req->uh->modifier1]->after_request(wsgi_req);
@@ -2225,6 +2230,7 @@ struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **list,
uwsgi_string->next = NULL;
uwsgi_string->custom = 0;
uwsgi_string->custom2 = 0;
uwsgi_string->custom_ptr = NULL;
return uwsgi_string;
}
@@ -3939,3 +3945,14 @@ void http_url_encode(char *buf, uint16_t *len, char *dst) {
}
void uwsgi_takeover() {
if (uwsgi.i_am_a_spooler) {
uwsgi_spooler_run();
}
else if (uwsgi.muleid) {
uwsgi_mule_run();
}
else {
uwsgi_worker_run();
}
}
+26
View File
@@ -531,6 +531,22 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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},
{"final-route", required_argument, 0, "add a final route", uwsgi_opt_add_route, "path_info", 0},
{"final-route-host", required_argument, 0, "add a final route based on Host header", uwsgi_opt_add_route, "http_host", 0},
{"final-route-uri", required_argument, 0, "add a final route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
{"final-route-qs", required_argument, 0, "add a final route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
{"final-route-remote-addr", required_argument, 0, "add a final route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
{"final-route-user-agent", required_argument, 0, "add a final route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
{"final-route-remote-user", required_argument, 0, "add a final route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
{"final-route-referer", required_argument, 0, "add a final route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
{"final-route-label", required_argument, 0, "add a final routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
{"final-route-if", required_argument, 0, "add a final route based on condition", uwsgi_opt_add_route, "if", 0},
{"final-route-if-not", required_argument, 0, "add a final route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"final-route-run", required_argument, 0, "always run the specified final 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
@@ -2790,6 +2806,16 @@ next2:
}
}
uwsgi_worker_run();
// never here
_exit(0);
}
void uwsgi_worker_run() {
int i;
if (uwsgi.lazy || uwsgi.lazy_apps) {
uwsgi_init_all_apps();
}
+85 -58
View File
@@ -8,6 +8,7 @@ struct uwsgi_airbrake_config {
int first;
char *arg;
char *apikey;
char *env;
};
struct uwsgi_airbrake_opt {
@@ -28,9 +29,14 @@ static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg,
uacc->apikey = arg;
}
static void uwsgi_airbrake_set_env(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
uacc->env = arg;
}
static struct uwsgi_airbrake_opt uaco[] = {
{"url", CURLOPT_URL, NULL},
{"apikey", 0, uwsgi_airbrake_set_apikey},
{"env", 0, uwsgi_airbrake_set_env},
{"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl},
{"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int},
{"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int},
@@ -65,78 +71,89 @@ end:
*equal = '=';
}
static size_t uwsgi_airbrake_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
size_t full_size = size * nmemb;
size_t remains = ut->len - ut->pos;
char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) {
if (remains == 0) return 0;
if (ut->custom0 == 0) {
size_t newline = 0;
size_t required = 1;
char *addr = ptr;
if (required > full_size) goto skip;
skip:
if (newline > 0) {
*addr = '\n';
}
ut->custom0 = 1;
return required;
}
if (full_size < remains) {
remains = full_size;
}
memcpy(ptr, ut->buf + ut->pos, remains);
ut->pos += remains;
return remains;
}
static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apikey) {
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
xmlChar *xmlbuff;
int buffersize;
xmlDocPtr doc = NULL;
xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL;
char *msg = uwsgi_str("uWSGI segfault");
char *msg = NULL;
doc = xmlNewDoc(BAD_CAST "1.0");
notice_node = xmlNewNode(NULL, BAD_CAST "notice");
xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3");
xmlDocSetRootElement(doc, notice_node);
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST apikey);
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey);
node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL);
xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI");
xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION);
xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi");
// request env
node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL);
node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL);
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version");
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version");
struct utsname uuts;
#ifdef __sun__
if (uname(&uuts) < 0) {
#else
if (uname(&uuts)) {
#endif
uwsgi_error("uname()");
}
else {
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname");
char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version);
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version");
free(os_version);
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine");
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename);
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename");
}
// end request env
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
if (uacc->env) {
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env);
}
else {
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
}
errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL);
xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError");
node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL);
char *p = strtok(ut->buf, "\n");
int i = 0;
char *ctx = NULL;
char *text = uwsgi_str(ut->buf);
char *p = strtok_r(text, "\n", &ctx);
while (p) {
// skip log messages
if (!uwsgi_startswith(p, "***", 3))
goto next;
i++;
// skip last 2 backtrace lines, real bt starts after them
if (i <= 2) {
goto next;
}
// backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555]
// we take binary/lib as filename
// and extract method name from remaining string
char *n = strchr(p, '(');
if (n) {
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
*n = 0;
char *pls = strchr(n+1, '+');
@@ -144,8 +161,15 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike
*pls = 0;
}
if (i == 3) {
free(msg);
if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) {
goto next;
}
else if (!strcmp("uwsgi_fpe", n+1)) {
msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p);
goto next;
}
if (!msg) {
if (strlen(n+1)) {
msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p);
}
@@ -155,6 +179,12 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike
}
}
// skip empty lines
if (!p)
goto next;
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
if ((n+1)[0] == ')') {
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()");
}
@@ -164,28 +194,23 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike
xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p);
xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
//xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
}
next:
p = strtok(NULL, "\n");
p = strtok_r(NULL, "\n", &ctx);
}
xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg);
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
xmlFreeDoc(doc);
xmlCleanupParser();
xmlMemoryDump();
free(ut->buf);
free(msg);
ut->buf = (char *) xmlbuff;
ut->len = strlen(ut->buf);
free(text);
return (char *) xmlbuff;
}
@@ -199,7 +224,7 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_airbrake_read_callback);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
@@ -218,7 +243,8 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret <= 0) continue;
if (ret < 0) return;
if (ret == 0) continue;
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
@@ -226,19 +252,20 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
ut->len = (size_t) rlen;
ut->custom0 = 0;
uwsgi_format_airbrake_backtrace(ut, uacc->apikey);
char *notice = uwsgi_format_airbrake_backtrace(ut);
curl_slist_append(expect, "Accept: */*");
curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ut->buf);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, ut->len);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice));
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
free(notice);
}
}
+3 -2
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include <curl/curl.h>
extern struct uwsgi_server uwsgi;
@@ -168,7 +168,8 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret <= 0) continue;
if (ret < 0) return;
if (ret == 0) continue;
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
+196
View File
@@ -0,0 +1,196 @@
#include <uwsgi.h>
/*
Soon before official Go 1.1, we understand supporting Go in a fork() heavy
environment was not blessed by the Go community.
Instead of completely dropping support for Go, we studied how the gccgo project works and we
decided it was a better approach for uWSGI.
This new plugin works by initializing a new "go runtime" after each fork().
The runtime calls the Go main function (developed by the user), and pass the whole
uWSGI control to it.
the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically
manages mules, spoolers and workers)
As well as before each core maps to a goroutine mapped to a real pthread. (goroutines called
from your apps are native goroutines)
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_plugin gccgo_plugin;
struct uwsgi_gccgo{
struct uwsgi_string_list *libs;
char *args;
} ugccgo;
/*
static void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
// set loop engine
uwsgi.loop = "goroutines";
}
*/
struct uwsgi_option uwsgi_gccgo_options[] = {
{"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
{"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
{"go-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
{"gccgo-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
// {"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
// no_split_stack is the key to avoid crashing !!!
void* runtime_m(void) __attribute__ ((noinline, no_split_stack));
void runtime_check(void);
void runtime_args(int, char **);
void runtime_osinit(void);
void runtime_schedinit(void);
void *__go_go(void *, void *);
void runtime_main(void);
void runtime_mstart(void *);
extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler");
extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env");
extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd");
extern void uwsgigo_run_core(int) __asm__ ("go.uwsgi.RunCore");
extern void uwsgigo_signal_handler(void *, uint8_t) __asm__ ("go.uwsgi.SignalHandler");
//extern void uwsgigo_loop(void) __asm__ ("go.uwsgi.Loop");
static void mainstart(void *arg __attribute__((unused))) {
runtime_main();
}
void uwsgigo_main_main(void) __asm__ ("main.main");
void uwsgigo_main_init(void) __asm__ ("__go_init_main");
void (*uwsgigo_hook_init)(void);
void (*uwsgigo_hook_main)(void);
void uwsgigo_main_init(void) {
uwsgigo_hook_init();
}
void uwsgigo_main_main(void) {
uwsgigo_hook_main();
}
int uwsgi_gccgo_helper_request_body_read(struct wsgi_request *wsgi_req, char *p, uint64_t len) {
ssize_t rlen = 0;
char *buf = uwsgi_request_body_read(wsgi_req, len, &rlen);
if (buf == uwsgi.empty) {
return 0;
}
else if (buf == NULL) {
return -1;
}
memcpy(p, buf, rlen);
return (int) rlen;
}
int uwsgi_gccgo_helper_register_signal(uint8_t signum, char *receiver, void *handler) {
return uwsgi_register_signal(signum, receiver, handler, gccgo_plugin.modifier1);
}
static void uwsgi_gccgo_initialize() {
struct uwsgi_string_list *usl = ugccgo.libs;
while(usl) {
void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
uwsgi_log("unable to open go shared library: %s\n", dlerror());
exit(1);
}
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
uwsgigo_hook_init = dlsym(handle, "__go_init_main");
uwsgigo_hook_main = dlsym(handle, "main.main");
usl = usl->next;
}
if (!uwsgigo_hook_init || !uwsgigo_hook_main) {
return;
}
// Go runtime initialization
int argc = 0;
if (ugccgo.args) {
char *argv_list = uwsgi_str(ugccgo.args);
char *p = strtok(argv_list, " ");
while(p) {
argc++;
p = strtok(NULL, " ");
}
free(argv_list);
}
runtime_check();
if (argc > 0) {
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 1));
char *argv_list = uwsgi_str(ugccgo.args);
char *p = strtok(argv_list, " ");
int n = 0;
while(p) {
argv[n] = p;
n++;
p = strtok(NULL, " ");
}
runtime_args(argc, argv);
}
else {
char *argv[2] = {0,0};
runtime_args(0, argv);
}
runtime_osinit();
runtime_schedinit();
__go_go(mainstart, NULL);
runtime_mstart(runtime_m());
// never here
}
static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
/* Standard GO request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log("Empty GO request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
wsgi_req->async_environ = uwsgigo_env(wsgi_req);
int i;
for(i=0;i<wsgi_req->var_cnt;i++) {
uwsgigo_env_add(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
i++;
}
uwsgigo_request(wsgi_req->async_environ, wsgi_req);
return UWSGI_OK;
}
static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_gccgo_signal_handler(uint8_t signum, void *handler) {
uwsgigo_signal_handler(handler, signum);
return 0;
}
struct uwsgi_plugin gccgo_plugin = {
.name = "gccgo",
.modifier1 = 11,
.options = uwsgi_gccgo_options,
//.on_load = uwsgi_gccgo_on_load,
.request = uwsgi_gccgo_request,
.after_request = uwsgi_gccgo_after_request,
.post_fork = uwsgi_gccgo_initialize,
.signal_handler = uwsgi_gccgo_signal_handler,
};
+118
View File
@@ -0,0 +1,118 @@
package uwsgi
import (
"strings"
"net/http"
"net/http/cgi"
"io"
)
//extern uwsgi_takeover
func uwsgi_takeover()
//extern uwsgi_response_write_body_do
func uwsgi_response_write_body_do(*interface{}, *byte, uint64) int
//extern uwsgi_response_prepare_headers_int
func uwsgi_response_prepare_headers_int(*interface{}, int) int
//extern uwsgi_response_add_header
func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int
//extern uwsgi_gccgo_helper_request_body_read
func uwsgi_request_body_read(*interface{}, *byte, uint64) int
//extern uwsgi_gccgo_helper_register_signal
func uwsgi_register_signal(uint8, *byte, func(uint8)) int
var uwsgi_signals_gc [256]func(uint8)
func Env(wsgi_req *interface{}) *map[string]string {
var env map[string]string
env = make(map[string]string)
return &env
}
func EnvAdd(env *map[string]string, k *[65536]byte, kl uint16, v *[65536]byte, vl uint16) {
(*env)[ string((*k)[0:kl]) ] = string((*v)[0:vl])
}
type ResponseWriter struct {
r *http.Request
wsgi_req *interface{}
headers http.Header
wroteHeader bool
}
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
uwsgi_response_write_body_do(w.wsgi_req, &p[0], uint64(len(p)))
return len(p), err
}
func (w *ResponseWriter) WriteHeader(status int) {
uwsgi_response_prepare_headers_int(w.wsgi_req, status )
if w.headers.Get("Content-Type") == "" {
w.headers.Set("Content-Type", "text/html; charset=utf-8")
}
for k := range w.headers {
for _, v := range w.headers[k] {
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
v = strings.TrimSpace(v)
kb := []byte(k)
vb := []byte(v)
uwsgi_response_add_header(w.wsgi_req, &kb[0], uint16(len(k)), &vb[0], uint16(len(v)))
}
}
w.wroteHeader = true
}
func (w *ResponseWriter) Header() http.Header {
return w.headers
}
type BodyReader struct {
wsgi_req *interface{}
}
// there is no close in request body
func (br *BodyReader) Close() error {
return nil
}
func (br *BodyReader) Read(p []byte) (n int, err error) {
var rlen int = uwsgi_request_body_read(br.wsgi_req, &p[0], uint64(len(p)))
if (rlen == 0) {
err = io.EOF;
return 0, err
} else if (rlen == -1) {
err = io.ErrUnexpectedEOF
return 0, err
}
return rlen, err
}
func RequestHandler(env *map[string]string, wsgi_req *interface{}) {
httpReq, err := cgi.RequestFromMap(*env)
if err == nil {
httpReq.Body = &BodyReader{wsgi_req}
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
http.DefaultServeMux.ServeHTTP(&w, httpReq)
}
}
func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool {
var b []byte = []byte(receiver)
if (uwsgi_register_signal(signum, &b[0], handler) < 0) {
return false
}
uwsgi_signals_gc[signum] = handler
return true
}
func SignalHandler(handler func(uint8), signum uint8) {
handler(signum)
}
func Run() {
uwsgi_takeover()
}
+2
View File
@@ -4,6 +4,7 @@ import "uwsgi"
import "net/http"
import "fmt"
import "io/ioutil"
import "os"
func viewHandler(w http.ResponseWriter, r *http.Request) {
@@ -24,6 +25,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
}
func main() {
fmt.Println(os.Args)
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/post/", postHandler)
uwsgi.Run()
+35
View File
@@ -0,0 +1,35 @@
[uwsgi]
plugins = geoip, router_cache
http-socket = :9090
; 8 bytes blocksize is the right thing to do
cache2 = name=limiter,items=1000,blocksize=8
; allows expiring items
master = true
; get the cache value for the current ip (if any)
route-run = cachevar:key=${REMOTE_ADDR},as_num=1,var=LIMIT
; block the peer if it did more than 10 404 requests in the last 30 seconds
route-if = >:${LIMIT};10 goto:blockit
; end of routing
route-run = last:
module = werkzeug.testapp:test_app
threads = 10
; track the user if a 404 is returned
final-route-if = equal:${uwsgi[status]};404 goto:trackit
; end of final routing
final-route-run = last:
final-route-label = trackit
; increase the value in the 'limiter' cache
final-route-run = cacheinc:key=${REMOTE_ADDR},expires=30
; increase the value if the connection is from italy !!!
final-route-if = equal:${geoip[country_name]};Italy cacheinc:key=${REMOTE_ADDR},expires=30
; block the client
route-label = blockit
route-run = log:STOP YOU BASTARD !!!
route-run = break:503
+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-05-08'
s.date = '2013-05-11'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+11 -2
View File
@@ -1425,6 +1425,7 @@ struct wsgi_request {
// avoid routing loops
int is_routing;
int is_final_routing;
int routes_applied;
// internal routing vm program counter
uint32_t route_pc;
@@ -2113,6 +2114,7 @@ struct uwsgi_server {
#ifdef UWSGI_ROUTING
struct uwsgi_router *routers;
struct uwsgi_route *routes;
struct uwsgi_route *final_routes;
struct uwsgi_route_condition *route_conditions;
struct uwsgi_route_var *route_vars;
#endif
@@ -3327,13 +3329,14 @@ char *uwsgi_tmpname(char *, char *);
struct uwsgi_router *uwsgi_register_router(char *, int (*)(struct uwsgi_route *, char *));
void uwsgi_opt_add_route(char *, char *, void *);
int uwsgi_apply_routes(struct wsgi_request *);
int uwsgi_apply_routes_do(struct wsgi_request *, char *, uint16_t);
void uwsgi_apply_final_routes(struct wsgi_request *);
int uwsgi_apply_routes_do(struct uwsgi_route *, struct wsgi_request *, char *, uint16_t);
void uwsgi_register_embedded_routers(void);
void uwsgi_routing_dump();
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *, struct uwsgi_route *, char *, uint16_t, char *, size_t);
int uwsgi_route_api_func(struct wsgi_request *, char *, char *);
struct uwsgi_route_condition *uwsgi_register_route_condition(char *, int (*) (struct wsgi_request *, struct uwsgi_route *));
void uwsgi_fixup_routes(void);
void uwsgi_fixup_routes(struct uwsgi_route *);
#endif
void uwsgi_reload(char **);
@@ -3993,6 +3996,12 @@ void uwsgi_add_safe_fd(int);
void uwsgi_ipcsem_clear(void);
char *uwsgi_str_to_hex(char *, size_t);
// this 3 functions have been added 1.9.10 to allow plugins take the control over processes
void uwsgi_worker_run(void);
void uwsgi_mule_run(void);
void uwsgi_spooler_run(void);
void uwsgi_takeover(void);
void uwsgi_check_emperor(void);
#ifdef UWSGI_AS_SHARED_LIBRARY
int uwsgi_init(int, char **, char **);
+8 -6
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '1.9.9'
uwsgi_version = '1.9.10'
import os
import re
@@ -153,7 +153,7 @@ def spcall3(cmd):
def add_o(x):
if x == 'uwsgi':
x = 'main'
elif x.endswith('.a'):
elif x.endswith('.a') or x.endswith('.o'):
return x
x = x + '.o'
return x
@@ -277,7 +277,7 @@ def build_uwsgi(uc, print_only=False):
objfile = file
if objfile == 'uwsgi':
objfile = 'main'
if not objfile.endswith('.a'):
if not objfile.endswith('.a') and not objfile.endswith('.o'):
compile(' '.join(cflags), last_cflags_ts, objfile + '.o', file + '.c')
if uc.get('embedded_plugins'):
@@ -346,6 +346,8 @@ def build_uwsgi(uc, print_only=False):
for cfile in up['GCC_LIST']:
if cfile.endswith('.a'):
gcc_list.append(cfile)
elif cfile.endswith('.o'):
gcc_list.append('%s/%s' % (path, cfile))
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts,
path + '/' + cfile + '.o', path + '/' + cfile + '.c')
@@ -471,7 +473,7 @@ class uConf(object):
self.gcc_list.append('proto/scgi')
self.include_path = []
self.cflags = ['-O2', '-I.', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split()
self.cflags = ['-O2', '-I.', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split() + self.get('cflags','').split()
report['kernel'] = uwsgi_os
@@ -568,7 +570,7 @@ class uConf(object):
return None
return value
except:
if default:
if default is not None:
return default
return None
@@ -1122,7 +1124,7 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
for cfile in up['GCC_LIST']:
if cfile.endswith('.a'):
gcc_list.append(cfile)
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m') and not cfile.endswith('.o'):
gcc_list.append(path + '/' + cfile + '.c')
else:
gcc_list.append(path + '/' + cfile)