about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-03-21 01:29:18 -0700
committerEric Wong <normalperson@yhbt.net>2009-03-21 01:46:12 -0700
commit3fc10e70bf3b6aa0d670d2248e801d8745e7c0d2 (patch)
tree2ac70e72b015acad83ec6aa437ed541e1266bdaa /ext
parentff6b50fdf49f47befd22d2ad779f01d69c1f4570 (diff)
downloadunicorn-3fc10e70bf3b6aa0d670d2248e801d8745e7c0d2.tar.gz
Fix the logic in HttpParser up front so we don't have
to mess around with the following convoluted steps:

  1. setting the HTTP_CONTENT_{LENGTH,TYPE} headers
  2. reading the HTTP_CONTENT_{LENGTH,TYPE} headers again
  3. setting the CONTENT_{LENGTH,TYPE} based on the
     HTTP_-prefixed one
  4. deleting the HTTP_CONTENT_{LENGTH,TYPE} headers
     (since Rack doesn't like them)

1, 2, 3 were in the C code, 4 was in Ruby.

Now the logic is:

  1. if CONTENT_{LENGTH,TYPE} headers are seen, don't prefix
     with "HTTP_".

All the branch logic for the new code is done at init time, too
so there's no additional overhead in the HTTP parsing phase.
There's also no additional overhead of hash lookups in the extra
steps.
Diffstat (limited to 'ext')
-rw-r--r--ext/unicorn/http11/http11.c28
1 files changed, 10 insertions, 18 deletions
diff --git a/ext/unicorn/http11/http11.c b/ext/unicorn/http11/http11.c
index ec6b8d9..0b96099 100644
--- a/ext/unicorn/http11/http11.c
+++ b/ext/unicorn/http11/http11.c
@@ -28,10 +28,8 @@ static VALUE global_fragment;
 static VALUE global_query_string;
 static VALUE global_http_version;
 static VALUE global_content_length;
-static VALUE global_http_content_length;
 static VALUE global_request_path;
 static VALUE global_content_type;
-static VALUE global_http_content_type;
 static VALUE global_http_body;
 static VALUE global_server_name;
 static VALUE global_server_port;
@@ -127,6 +125,7 @@ static int common_field_cmp(const void *a, const void *b)
 }
 #endif /* HAVE_QSORT_BSEARCH */
 
+/* this function is not performance-critical */
 static void init_common_fields(void)
 {
   int i;
@@ -135,8 +134,15 @@ static void init_common_fields(void)
   memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
 
   for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
-    memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
-    cf->value = rb_obj_freeze(rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len));
+    /* Rack doesn't like certain headers prefixed with "HTTP_" */
+    if (!strcmp("CONTENT_LENGTH", cf->name) ||
+        !strcmp("CONTENT_TYPE", cf->name)) {
+      cf->value = rb_str_new(cf->name, cf->len);
+    } else {
+      memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
+      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
+    }
+    cf->value = rb_obj_freeze(cf->value);
     rb_global_variable(&cf->value);
   }
 
@@ -273,20 +279,8 @@ static void header_done(void *data, const char *at, size_t length)
 {
   VALUE req = (VALUE)data;
   VALUE temp = Qnil;
-  VALUE ctype = Qnil;
-  VALUE clen = Qnil;
   char *colon = NULL;
 
-  clen = rb_hash_aref(req, global_http_content_length);
-  if(clen != Qnil) {
-    rb_hash_aset(req, global_content_length, clen);
-  }
-
-  ctype = rb_hash_aref(req, global_http_content_type);
-  if(ctype != Qnil) {
-    rb_hash_aset(req, global_content_type, ctype);
-  }
-
   if((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
     colon = memchr(RSTRING_PTR(temp), ':', RSTRING_LEN(temp));
     if(colon != NULL) {
@@ -494,10 +488,8 @@ void Init_http11()
   DEF_GLOBAL(http_version, "HTTP_VERSION");
   DEF_GLOBAL(request_path, "REQUEST_PATH");
   DEF_GLOBAL(content_length, "CONTENT_LENGTH");
-  DEF_GLOBAL(http_content_length, "HTTP_CONTENT_LENGTH");
   DEF_GLOBAL(http_body, "HTTP_BODY");
   DEF_GLOBAL(content_type, "CONTENT_TYPE");
-  DEF_GLOBAL(http_content_type, "HTTP_CONTENT_TYPE");
   DEF_GLOBAL(server_name, "SERVER_NAME");
   DEF_GLOBAL(server_port, "SERVER_PORT");
   DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");