about summary refs log tree commit homepage
path: root/http_parser.rl
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2012-01-31 19:36:50 -0800
committerEric Wong <normalperson@yhbt.net>2012-01-31 19:43:47 -0800
commit97ecfeb02dac5721db0b651336fddd2810d916f0 (patch)
tree7a8605692b385fff2a0ef478794fa1d809db51d8 /http_parser.rl
parentd0686790881292dcefe4d8d4d9922866d4955a04 (diff)
downloadcmogstored-97ecfeb02dac5721db0b651336fddd2810d916f0.tar.gz
This means we can move towards avoid needing to buffer
data for many common cases.
Diffstat (limited to 'http_parser.rl')
-rw-r--r--http_parser.rl43
1 files changed, 36 insertions, 7 deletions
diff --git a/http_parser.rl b/http_parser.rl
index 17df0a1..5cd1586 100644
--- a/http_parser.rl
+++ b/http_parser.rl
@@ -5,6 +5,22 @@
 #include "cmogstored.h"
 #include "http_util.h"
 
+static bool length_incr(off_t *len, unsigned c)
+{
+        off_t prev = *len;
+
+        *len *= 10;
+        *len += c - '0';
+
+        if (*len >= prev)
+                return true;
+
+        errno = ERANGE;
+        *len = -1;
+
+        return false;
+}
+
 %%{
         machine http_parser;
         include http_common "http_common.rl";
@@ -28,13 +44,25 @@
                 ('0'|'1'> { http->persistent = 1; }) '\r'LF;
 
         content_length = "Content-Length:"i sep
-                (digit+) > { http->tmp_tip = to_u16(fpc - buf); }
-                eor > { http->content_len = http_digit(http, buf, fpc); };
+                (digit+) $ {
+                        if (!length_incr(&http->content_len, fc))
+                                fbreak;
+                }
+                $! { errno = EINVAL; fbreak; }
+                eor;
         content_range = "Content-Range:"i sep "bytes"LWS+
-                (digit+) > { http->tmp_tip = to_u16(fpc - buf); }
-                "-" >  { http->range_beg = http_digit(http, buf, fpc); }
-                (digit+) > { http->tmp_tip = to_u16(fpc - buf); }
-                "/*" > { http->range_end = http_digit(http, buf, fpc); }
+                (digit+) $ {
+                        if (!length_incr(&http->range_beg, fc))
+                                fbreak;
+                }
+                $! { errno = EINVAL; fbreak; }
+                "-"
+                (digit+) $ {
+                        if (!length_incr(&http->range_end, fc))
+                                fbreak;
+                }
+                $! { errno = EINVAL; fbreak; }
+                "/*"
                 eor > { http->has_content_range = 1; };
         transfer_encoding_chunked = "Transfer-Encoding:"i sep
                 "chunked"i eor > { http->chunked = 1; };
@@ -102,6 +130,7 @@ mog_http_parse(struct mog_http *http, char *buf, size_t len)
         assert((void *)(pe - p) == (void *)(len - off) &&
                "pointers aren't same distance");
 
+        errno = 0;
         %% write exec;
 
         if (really_done)
@@ -110,7 +139,7 @@ mog_http_parse(struct mog_http *http, char *buf, size_t len)
         http->cs = cs;
         http->offset = p - buf;
 
-        if (cs == http_parser_error)
+        if (cs == http_parser_error || errno)
                 return MOG_PARSER_ERROR;
 
         assert(p <= pe && "buffer overflow after http parse");