about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-08-29 13:39:58 -0700
committerEric Wong <normalperson@yhbt.net>2009-08-29 13:40:05 -0700
commit4cae518fd0b2ba81114ed4cc26eb1704a1f71e28 (patch)
treebacdbf5c3d8dffbeb81db74651742e42e3519618
parentc03045ecde0f3270d7458ba7ac0d76a25afc6fb2 (diff)
downloadclogger-4cae518fd0b2ba81114ed4cc26eb1704a1f71e28.tar.gz
Some misbehaved apps can do this to us, and we don't want
the C extension to segfault when this happens.
-rw-r--r--ext/clogger_ext/clogger.c25
-rw-r--r--lib/clogger/pure.rb7
-rw-r--r--test/test_clogger.rb11
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