porte the ruby/rack plugin to the new exception api

This commit is contained in:
Unbit
2013-02-17 16:18:12 +01:00
parent 8e6b810df8
commit 609b5aeb0a
3 changed files with 164 additions and 37 deletions
+11 -7
View File
@@ -81,9 +81,11 @@ static void append_backtrace_to_ubuf(uint16_t pos, char *value, uint16_t len, vo
break;
// text
case 3:
if (uwsgi_buffer_append(ub, "text/code: \"", 12)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
if (len > 0) {
if (uwsgi_buffer_append(ub, "text/code: \"", 12)) return;
if (uwsgi_buffer_append(ub, value, len)) return;
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
}
break;
// custom
case 4:
@@ -234,14 +236,16 @@ void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) {
int do_exit = 0;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].exceptions++;
uwsgi_apps[wsgi_req->app_id].exceptions++;
if (uwsgi.reload_on_exception) {
do_exit = 1;
goto check_catch;
}
if (!wsgi_req) goto log;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].exceptions++;
uwsgi_apps[wsgi_req->app_id].exceptions++;
if (uwsgi.reload_on_exception_type && uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
if (ub) {
@@ -291,7 +295,7 @@ void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) {
}
check_catch:
if (catch) {
if (catch && wsgi_req) {
if (uwsgi_exceptions_catch(wsgi_req)) {
// for now, just goto, new features could be added
goto log;
+153 -29
View File
@@ -41,21 +41,139 @@ struct uwsgi_option uwsgi_rack_options[] = {
};
void uwsgi_ruby_exception(void) {
static struct uwsgi_buffer *uwsgi_ruby_exception_class(struct wsgi_request *wsgi_req) {
VALUE err = rb_errinfo();
VALUE e = rb_class_name(rb_class_of(err));
struct uwsgi_buffer *ub = uwsgi_buffer_new(RSTRING_LEN(e));
if (uwsgi_buffer_append(ub, RSTRING_PTR(e), RSTRING_LEN(e))) {
uwsgi_buffer_destroy(ub);
return NULL;
}
return ub;
}
VALUE lasterr = rb_gv_get("$!");
VALUE message = rb_obj_as_string(lasterr);
uwsgi_log("%s\n", RSTRING_PTR(message));
if(!NIL_P(rb_errinfo())) {
VALUE ary = rb_funcall(rb_errinfo(), rb_intern("backtrace"), 0);
int i;
for (i=0; i<RARRAY_LEN(ary); i++) {
uwsgi_log("%s\n", RSTRING_PTR(RARRAY_PTR(ary)[i]));
}
static struct uwsgi_buffer *uwsgi_ruby_exception_msg(struct wsgi_request *wsgi_req) {
VALUE err = rb_errinfo();
VALUE e = rb_funcall(err, rb_intern("message"), 0, 0);
struct uwsgi_buffer *ub = uwsgi_buffer_new(RSTRING_LEN(e));
if (uwsgi_buffer_append(ub, RSTRING_PTR(e), RSTRING_LEN(e))) {
uwsgi_buffer_destroy(ub);
return NULL;
}
return ub;
}
static struct uwsgi_buffer *uwsgi_ruby_exception_repr(struct wsgi_request *wsgi_req) {
struct uwsgi_buffer *ub_class = uwsgi_ruby_exception_class(wsgi_req);
if (!ub_class) return NULL;
struct uwsgi_buffer *ub_msg = uwsgi_ruby_exception_msg(wsgi_req);
if (!ub_msg) {
uwsgi_buffer_destroy(ub_class);
return NULL;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(ub_class->pos + 3 + ub_msg->pos);
if (uwsgi_buffer_append(ub, ub_msg->buf, ub_msg->pos)) goto error;
if (uwsgi_buffer_append(ub, " (", 2)) goto error;
if (uwsgi_buffer_append(ub, ub_class->buf, ub_class->pos)) goto error;
if (uwsgi_buffer_append(ub, ")", 1)) goto error;
uwsgi_buffer_destroy(ub_class);
uwsgi_buffer_destroy(ub_msg);
return ub;
error:
uwsgi_buffer_destroy(ub_class);
uwsgi_buffer_destroy(ub_msg);
uwsgi_buffer_destroy(ub);
return NULL;
}
// simulate ruby_error_print (this is sad... but it works well)
static void uwsgi_ruby_exception_log(struct wsgi_request *wsgi_req) {
VALUE err = rb_errinfo();
VALUE eclass = rb_class_name(rb_class_of(err));
VALUE msg = rb_funcall(err, rb_intern("message"), 0, 0);
VALUE ary = rb_funcall(err, rb_intern("backtrace"), 0);
int i;
for (i=0; i<RARRAY_LEN(ary); i++) {
if (i == 0) {
uwsgi_log("%s: %s (%s)\n", RSTRING_PTR(RARRAY_PTR(ary)[i]), RSTRING_PTR(msg), RSTRING_PTR(eclass));
}
else {
uwsgi_log("\tfrom %s\n", RSTRING_PTR(RARRAY_PTR(ary)[i]));
}
}
}
static struct uwsgi_buffer *uwsgi_ruby_backtrace(struct wsgi_request *wsgi_req) {
VALUE err = rb_errinfo();
VALUE ary = rb_funcall(err, rb_intern("backtrace"), 0);
int i;
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
char *filename = NULL;
char *function = NULL;
for (i=0; i<RARRAY_LEN(ary); i++) {
char *bt = RSTRING_PTR(RARRAY_PTR(ary)[i]);
// ok let's start the C dance to parse the backtrace
char *colon = strchr(bt, ':');
if (!colon) continue;
filename = uwsgi_concat2n(bt, colon-bt, "", 0);
uint16_t filename_len = colon-bt;
colon++; if (*colon == 0) goto error;
char *lineno_ptr = colon;
colon = strchr(lineno_ptr, ':');
if (!colon) goto error;
int64_t lineno = uwsgi_str_num(lineno_ptr, colon-lineno_ptr);
colon++; if (*colon == 0) goto error;
colon = strchr(lineno_ptr, '`');
if (!colon) goto error;
colon++; if (*colon == 0) goto error;
char *function_ptr = colon;
char *function_end = strchr(function_ptr, '\'');
if (!function_end) goto error;
function = uwsgi_concat2n(function_ptr, function_end-function_ptr, "", 0);
uint16_t function_len = function_end-function_ptr;
if (uwsgi_buffer_u16le(ub, filename_len)) goto error;
if (uwsgi_buffer_append(ub, filename, filename_len)) goto error;
if (uwsgi_buffer_append_valnum(ub, lineno)) goto error;
if (uwsgi_buffer_u16le(ub, function_len)) goto error;
if (uwsgi_buffer_append(ub, function, function_len)) goto error;
// in ruby we do not have text/code nor custom
if (uwsgi_buffer_u16le(ub, 0)) goto error;
if (uwsgi_buffer_append(ub, "", 0)) goto error;
if (uwsgi_buffer_u16le(ub, 0)) goto error;
if (uwsgi_buffer_append(ub, "", 0)) goto error;
free(filename);
filename = NULL;
free(function);
function = NULL;
}
return ub;
error:
uwsgi_buffer_destroy(ub);
if (filename) {
free(filename);
}
if (function) {
free(function);
}
return NULL;
}
VALUE rb_uwsgi_io_new(VALUE class, VALUE wr) {
@@ -200,7 +318,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
return 0;
}
@@ -369,7 +487,7 @@ void uwsgi_rack_preinit_apps() {
int error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(NULL, 0);
}
usl = usl->next;
}
@@ -399,7 +517,7 @@ void uwsgi_rack_init_apps(void) {
error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(NULL, 0);
}
usl = usl->next;
}
@@ -407,7 +525,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
exit(1);
}
if (ur.dispatcher == Qnil) {
@@ -431,7 +549,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
exit(1);
}
uwsgi_log("rails app %s ready\n", ur.rails);
@@ -453,7 +571,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
exit(1);
}
}
@@ -463,7 +581,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
exit(1);
}
VALUE thin_rack = rb_const_get(rb_cObject, rb_intern("Rack"));
@@ -471,7 +589,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
exit(1);
}
}
@@ -734,7 +852,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
else {
ret = rb_protect( call_dispatch, env, &error);
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions);
goto clear;
}
}
@@ -757,7 +875,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
if (rb_respond_to( headers, rb_intern("each") )) {
rb_protect( iterate_headers, headers, &error);
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions);
goto clear;
}
}
@@ -767,7 +885,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
if (rb_respond_to( body, rb_intern("to_path") )) {
VALUE sendfile_path = rb_protect( body_to_path, body, &error);
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions);
}
else {
int fd = open(RSTRING_PTR(sendfile_path), O_RDONLY);
@@ -783,7 +901,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
else {
rb_protect( iterate_body, body, &error);
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions);
}
}
}
@@ -792,7 +910,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
//uwsgi_log("calling close\n");
rb_protect( close_body, body, &error);
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions);
}
}
@@ -843,7 +961,7 @@ VALUE init_rack_app( VALUE script ) {
#endif
rb_protect( require_rack, 0, &error ) ;
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(NULL, 0);
return Qnil;
}
@@ -918,7 +1036,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
return 0;
}
return 1;
@@ -943,7 +1061,7 @@ void uwsgi_rb_post_fork() {
// call the post_fork_hook
rb_protect(uwsgi_rb_pfh, 0, &error);
if (error) {
uwsgi_ruby_exception();
uwsgi_manage_exception(NULL, 0);
}
}
@@ -961,7 +1079,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
}
return 1;
}
@@ -987,7 +1105,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
rb_gc();
return -1;
}
@@ -1035,7 +1153,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_ruby_exception();
uwsgi_manage_exception(NULL, 0);
rb_gc();
return -1;
}
@@ -1101,5 +1219,11 @@ struct uwsgi_plugin rack_plugin = {
.suspend = uwsgi_rack_suspend,
.resume = uwsgi_rack_resume,
.exception_class = uwsgi_ruby_exception_class,
.exception_msg = uwsgi_ruby_exception_msg,
.exception_repr = uwsgi_ruby_exception_repr,
.exception_log = uwsgi_ruby_exception_log,
.backtrace = uwsgi_ruby_backtrace,
};
-1
View File
@@ -60,5 +60,4 @@ struct uwsgi_rack {
};
void uwsgi_ruby_exception(void);
void uwsgi_rack_init_api(void);