about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-09-06 14:29:50 -0700
committerEric Wong <normalperson@yhbt.net>2009-09-06 14:31:28 -0700
commit48d5cd51210aa3d9e6efb0989b9a6df1e8623fb3 (patch)
treed801c96755299c54ae9a0f3e9c040b8efdbcf1b9 /ext
parent106b6cd1dd9f541d15b0ced3060362edf968f9a9 (diff)
downloadunicorn-48d5cd51210aa3d9e6efb0989b9a6df1e8623fb3.tar.gz
In case we modify our struct to not use bitflags, this should
make it easier to change the parser code.  This also adds extra
clarification for how we track keepalive and why we only do it
for certain request methods.
Diffstat (limited to 'ext')
-rw-r--r--ext/unicorn_http/unicorn_http.rl42
1 files changed, 36 insertions, 6 deletions
diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl
index 70ba0a6..07a9881 100644
--- a/ext/unicorn_http/unicorn_http.rl
+++ b/ext/unicorn_http/unicorn_http.rl
@@ -22,6 +22,7 @@
 #define UH_FL_KAVERSION 0x80
 #define UH_FL_HASHEADER 0x100
 
+/* both of these flags need to be set for keepalive to be supported */
 #define UH_FL_KEEPALIVE (UH_FL_KAMETHOD | UH_FL_KAVERSION)
 
 struct http_parser {
@@ -57,11 +58,44 @@ static void finalize_header(struct http_parser *hp, VALUE req);
 #define HP_FL_UNSET(hp,fl) ((hp)->flags &= ~(UH_FL_##fl))
 #define HP_FL_ALL(hp,fl) (HP_FL_TEST(hp, fl) == (UH_FL_##fl))
 
+/*
+ * handles values of the "Connection:" header, keepalive is implied
+ * for HTTP/1.1 but needs to be explicitly enabled with HTTP/1.0
+ * Additionally, we require GET/HEAD requests to support keepalive.
+ */
+static void hp_keepalive_connection(struct http_parser *hp, VALUE val)
+{
+  /* REQUEST_METHOD is always set before any headers */
+  if (HP_FL_TEST(hp, KAMETHOD)) {
+    if (STR_CSTR_CASE_EQ(val, "keep-alive")) {
+      /* basically have HTTP/1.0 masquerade as HTTP/1.1+ */
+      HP_FL_SET(hp, KAVERSION);
+    } else if (STR_CSTR_CASE_EQ(val, "close")) {
+      /*
+       * it doesn't matter what HTTP version or request method we have,
+       * if a client says "Connection: close", we disable keepalive
+       */
+      HP_FL_UNSET(hp, KEEPALIVE);
+    } else {
+      /*
+       * client could've sent anything, ignore it for now.  Maybe
+       * "HP_FL_UNSET(hp, KEEPALIVE);" just in case?
+       * Raising an exception might be too mean...
+       */
+    }
+  }
+}
+
 static void
 request_method(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
 {
   VALUE v;
 
+  /*
+   * we only support keepalive for GET and HEAD requests for now other
+   * methods are too rarely seen to be worth optimizing.  POST is unsafe
+   * since some clients send extra bytes after POST bodies.
+   */
   if (CONST_MEM_EQ("GET", ptr, len)) {
     HP_FL_SET(hp, KAMETHOD);
     v = g_GET;
@@ -82,6 +116,7 @@ http_version(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
   HP_FL_SET(hp, HASHEADER);
 
   if (CONST_MEM_EQ("HTTP/1.1", ptr, len)) {
+    /* HTTP/1.1 implies keepalive unless "Connection: close" is set */
     HP_FL_SET(hp, KAVERSION);
     v = g_http_11;
   } else if (CONST_MEM_EQ("HTTP/1.0", ptr, len)) {
@@ -137,12 +172,7 @@ static void write_value(VALUE req, struct http_parser *hp,
     VALIDATE_MAX_LENGTH(hp->s.field_len, FIELD_NAME);
     f = uncommon_field(PTR_TO(start.field), hp->s.field_len);
   } else if (f == g_http_connection) {
-    if (HP_FL_TEST(hp, KAMETHOD)) {
-      if (STR_CSTR_CASE_EQ(v, "keep-alive"))
-        HP_FL_SET(hp, KAVERSION);
-      else if (STR_CSTR_CASE_EQ(v, "close"))
-        HP_FL_UNSET(hp, KEEPALIVE);
-    }
+    hp_keepalive_connection(hp, v);
   } else if (f == g_content_length) {
     hp->len.content = parse_length(RSTRING_PTR(v), RSTRING_LEN(v));
     if (hp->len.content < 0)