From 4cae518fd0b2ba81114ed4cc26eb1704a1f71e28 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 29 Aug 2009 13:39:58 -0700 Subject: Log bad/invalid app responses as 500 errors Some misbehaved apps can do this to us, and we don't want the C extension to segfault when this happens. --- ext/clogger_ext/clogger.c | 25 ++++++++++++++++++++++++- lib/clogger/pure.rb | 7 ++++++- test/test_clogger.rb | 11 +++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/ext/clogger_ext/clogger.c b/ext/clogger_ext/clogger.c index c639567..493f5ae 100644 --- a/ext/clogger_ext/clogger.c +++ b/ext/clogger_ext/clogger.c @@ -104,6 +104,7 @@ static VALUE g_empty; static VALUE g_space; static VALUE g_question_mark; static VALUE g_rack_request_cookie_hash; +static VALUE g_bad_app_response; #define LOG_BUF_INIT_SIZE 128 @@ -722,10 +723,21 @@ static VALUE clogger_fileno(VALUE self) static void ccall(struct clogger *c, VALUE env) { + VALUE rv; + gettimeofday(&c->tv_start, NULL); c->env = env; c->cookies = Qfalse; - c->response = rb_funcall(c->app, call_id, 1, env); + rv = rb_funcall(c->app, call_id, 1, env); + if (TYPE(rv) == T_ARRAY && RARRAY_LEN(rv) == 3) { + c->response = rv; + } else { + c->response = g_bad_app_response; + cwrite(c); + rb_raise(rb_eTypeError, + "app response not a 3 element Array: %s", + RSTRING_PTR(rb_inspect(rv))); + } } /* @@ -782,6 +794,16 @@ static VALUE clogger_init_copy(VALUE clone, VALUE orig) #define CONST_GLOBAL_STR(val) CONST_GLOBAL_STR2(val, #val) +static void init_bad_response(void) +{ + g_bad_app_response = rb_ary_new(); + rb_ary_store(g_bad_app_response, 0, INT2NUM(500)); + rb_ary_store(g_bad_app_response, 1, rb_obj_freeze(rb_hash_new())); + rb_ary_store(g_bad_app_response, 2, rb_obj_freeze(rb_ary_new())); + rb_obj_freeze(g_bad_app_response); + rb_global_variable(&g_bad_app_response); +} + void Init_clogger_ext(void) { ltlt_id = rb_intern("<<"); @@ -817,4 +839,5 @@ void Init_clogger_ext(void) CONST_GLOBAL_STR2(space, " "); CONST_GLOBAL_STR2(question_mark, "?"); CONST_GLOBAL_STR2(rack_request_cookie_hash, "rack.request.cookie_hash"); + init_bad_response(); } diff --git a/lib/clogger/pure.rb b/lib/clogger/pure.rb index 85c6777..f593af0 100644 --- a/lib/clogger/pure.rb +++ b/lib/clogger/pure.rb @@ -16,7 +16,12 @@ class Clogger def call(env) @start = Time.now - status, headers, body = @app.call(env) + resp = @app.call(env) + unless resp.instance_of?(Array) && resp.size == 3 + log(env, 500, {}) + raise TypeError, "app response not a 3 element Array: #{resp.inspect}" + end + status, headers, body = resp if wrap_body? @reentrant = env['rack.multithread'] @env, @status, @headers, @body = env, status, headers, body diff --git a/test/test_clogger.rb b/test/test_clogger.rb index c3ae93c..d2121da 100644 --- a/test/test_clogger.rb +++ b/test/test_clogger.rb @@ -362,4 +362,15 @@ class TestClogger < Test::Unit::TestCase status, headers, body = cl.call(req) assert_equal "bar h&m\n", str.string end + + def test_bogus_app_response + str = StringIO.new + app = lambda { |env| 302 } + cl = Clogger.new(app, :logger => str) + assert_raise(TypeError) { cl.call(@req) } + str = str.string + e = Regexp.quote " \"GET /hello?goodbye=true HTTP/1.0\" 500 -" + assert_match %r{#{e}$}m, str + end + end -- cgit v1.2.3-24-ge0c7