about summary refs log tree commit homepage
path: root/ext/unicorn/http11/http11_parser.rl
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-02-25 12:38:47 -0800
committerEric Wong <normalperson@yhbt.net>2009-02-25 12:39:33 -0800
commitd120ffad9716fbb83806d9755b7b5fd28fdb758b (patch)
tree6c2fde419978edb8d420dbb352c74746626f6fdc /ext/unicorn/http11/http11_parser.rl
parent1f29d32cb095cbc21a095772db2fbaf216781f97 (diff)
downloadunicorn-d120ffad9716fbb83806d9755b7b5fd28fdb758b.tar.gz
rename http11 => unicorn/http11
Avoid conflicting with existing (and future) Mongrel installs in
case either changes.  Of course, this also allows us more
freedom to experiment and break the API if needed...
However, I'm only planning on making minor changes to
remove the amount of C code we have to maintain and
possibly some minor performance improvements.
Diffstat (limited to 'ext/unicorn/http11/http11_parser.rl')
-rw-r--r--ext/unicorn/http11/http11_parser.rl153
1 files changed, 153 insertions, 0 deletions
diff --git a/ext/unicorn/http11/http11_parser.rl b/ext/unicorn/http11/http11_parser.rl
new file mode 100644
index 0000000..c3c4b1f
--- /dev/null
+++ b/ext/unicorn/http11/http11_parser.rl
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2005 Zed A. Shaw
+ * You can redistribute it and/or modify it under the same terms as Ruby.
+ */
+#include "http11_parser.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+/*
+ * capitalizes all lower-case ASCII characters,
+ * converts dashes to underscores.
+ */
+static void snake_upcase_char(char *c)
+{
+    if (*c >= 'a' && *c <= 'z')
+      *c &= ~0x20;
+    else if (*c == '-')
+      *c = '_';
+}
+
+#define LEN(AT, FPC) (FPC - buffer - parser->AT)
+#define MARK(M,FPC) (parser->M = (FPC) - buffer)
+#define PTR_TO(F) (buffer + parser->F)
+
+/** Machine **/
+
+%%{
+  
+  machine http_parser;
+
+  action mark {MARK(mark, fpc); }
+
+
+  action start_field { MARK(field_start, fpc); }
+  action snake_upcase_field { snake_upcase_char((char *)fpc); }
+  action write_field {
+    parser->field_len = LEN(field_start, fpc);
+  }
+
+  action start_value { MARK(mark, fpc); }
+  action write_value {
+    if(parser->http_field != NULL) {
+      parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
+    }
+  }
+  action request_method {
+    if(parser->request_method != NULL)
+      parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  }
+  action request_uri {
+    if(parser->request_uri != NULL)
+      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  }
+  action fragment {
+    if(parser->fragment != NULL)
+      parser->fragment(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  }
+
+  action start_query {MARK(query_start, fpc); }
+  action query_string {
+    if(parser->query_string != NULL)
+      parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
+  }
+
+  action http_version {        
+    if(parser->http_version != NULL)
+      parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  }
+
+  action request_path {
+    if(parser->request_path != NULL)
+      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
+  }
+
+  action done {
+    parser->body_start = fpc - buffer + 1;
+    if(parser->header_done != NULL)
+      parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
+    fbreak;
+  }
+
+  include http_parser_common "http11_parser_common.rl";
+
+}%%
+
+/** Data **/
+%% write data;
+
+int http_parser_init(http_parser *parser)  {
+  int cs = 0;
+  %% write init;
+  parser->cs = cs;
+  parser->body_start = 0;
+  parser->content_len = 0;
+  parser->mark = 0;
+  parser->nread = 0;
+  parser->field_len = 0;
+  parser->field_start = 0;    
+
+  return(1);
+}
+
+
+/** exec **/
+size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off)  {
+  const char *p, *pe;
+  int cs = parser->cs;
+
+  assert(off <= len && "offset past end of buffer");
+
+  p = buffer+off;
+  pe = buffer+len;
+
+  assert(*pe == '\0' && "pointer does not end on NUL");
+  assert(pe - p == len - off && "pointers aren't same distance");
+
+  %% write exec;
+
+  if (!http_parser_has_error(parser))
+    parser->cs = cs;
+  parser->nread += p - (buffer + off);
+
+  assert(p <= pe && "buffer overflow after parsing execute");
+  assert(parser->nread <= len && "nread longer than length");
+  assert(parser->body_start <= len && "body starts after buffer end");
+  assert(parser->mark < len && "mark is after buffer end");
+  assert(parser->field_len <= len && "field has length longer than whole buffer");
+  assert(parser->field_start < len && "field starts after buffer end");
+
+  return(parser->nread);
+}
+
+int http_parser_finish(http_parser *parser)
+{
+  if (http_parser_has_error(parser) ) {
+    return -1;
+  } else if (http_parser_is_finished(parser) ) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int http_parser_has_error(http_parser *parser) {
+  return parser->cs == http_parser_error;
+}
+
+int http_parser_is_finished(http_parser *parser) {
+  return parser->cs == http_parser_first_final;
+}