about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-04-26 19:18:10 -0700
committerEric Wong <normalperson@yhbt.net>2010-04-26 19:18:10 -0700
commit356435e60da0ffc92b4c7a9eb801255f094b4610 (patch)
tree43f40fca2d768c4ad3f3e6a2b6548143eb300c9b
parent31bd370baef622aaa5dd14084f27baf2fabf506c (diff)
downloadkcar-356435e60da0ffc92b4c7a9eb801255f094b4610.tar.gz
-rw-r--r--ext/kcar/kcar.rl24
1 files changed, 20 insertions, 4 deletions
diff --git a/ext/kcar/kcar.rl b/ext/kcar/kcar.rl
index d2c8f6c..5acaa49 100644
--- a/ext/kcar/kcar.rl
+++ b/ext/kcar/kcar.rl
@@ -38,6 +38,7 @@ DEF_MAX_LENGTH(REASON, 256);
 #define UH_FL_CHUNKED  0x1
 #define UH_FL_HASBODY  0x2
 #define UH_FL_INBODY   0x4
+#define UH_FL_HASTRAILER   0x8
 #define UH_FL_INTRAILER 0x10
 #define UH_FL_INCHUNK  0x20
 #define UH_FL_KEEPALIVE 0x40
@@ -74,6 +75,12 @@ struct http_parser {
 #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))
 
+static void finalize_header(struct http_parser *hp)
+{
+  if ((HP_FL_TEST(hp, HASTRAILER) && ! HP_FL_TEST(hp, CHUNKED)))
+    rb_raise(eParserError, "trailer but not chunked");
+}
+
 /*
  * handles values of the "Connection:" header, keepalive is implied
  * for HTTP/1.1 but needs to be explicitly enabled with HTTP/1.0
@@ -188,7 +195,10 @@ static void write_value(VALUE hdr, struct http_parser *hp,
     hp_keepalive_connection(hp, v);
   } else if (STR_CSTR_CASE_EQ(f, "content-length")) {
     if (! HP_FL_TEST(hp, HASBODY))
-      rb_raise(eParserError, "Content-Length with no body");
+      rb_raise(eParserError, "Content-Length with no body expected");
+    if (HP_FL_TEST(hp, CHUNKED))
+      rb_raise(eParserError,
+               "Content-Length when chunked Transfer-Encoding is set");
     hp->len.content = parse_length(vptr, vlen);
 
     if (hp->len.content < 0)
@@ -198,15 +208,20 @@ static void write_value(VALUE hdr, struct http_parser *hp,
   } else if (STR_CSTR_CASE_EQ(f, "transfer-encoding")) {
     if (STR_CSTR_CASE_EQ(v, "chunked")) {
       if (! HP_FL_TEST(hp, HASBODY))
-        rb_raise(eParserError, "chunked Transfer-Encoding with no body");
+        rb_raise(eParserError,
+                 "chunked Transfer-Encoding with no body expected");
+      if (hp->len.content >= 0)
+        rb_raise(eParserError,
+                 "chunked Transfer-Encoding when Content-Length is set");
 
       hp->len.chunk = 0;
       HP_FL_SET(hp, CHUNKED);
     }
     invalid_if_trailer(hp);
   } else if (STR_CSTR_CASE_EQ(f, "trailer")) {
-      if (! HP_FL_TEST(hp, HASBODY))
-        rb_raise(eParserError, "trailer with no body");
+    if (! HP_FL_TEST(hp, HASBODY))
+      rb_raise(eParserError, "trailer with no body");
+    HP_FL_SET(hp, HASTRAILER);
     invalid_if_trailer(hp);
   }
 
@@ -261,6 +276,7 @@ static void write_value(VALUE hdr, struct http_parser *hp,
       rb_raise(eParserError, "invalid chunk size");
   }
   action header_done {
+    finalize_header(hp);
     cs = http_parser_first_final;
 
     if (HP_FL_TEST(hp, CHUNKED))