extconf: SIZEOF_OFF_T should be a ruby.h macro
[unicorn.git] / ext / unicorn_http / unicorn_http.rl
blob2a56334bc1503e9f6deb3732c5e8c3d1c88e26d9
1 /**
2  * Copyright (c) 2009 Eric Wong (all bugs are Eric's fault)
3  * Copyright (c) 2005 Zed A. Shaw
4  * You can redistribute it and/or modify it under the same terms as Ruby.
5  */
6 #ifndef unicorn_http_h
7 #define unicorn_http_h
9 #include "ruby.h"
10 #include "ext_help.h"
11 #include <sys/types.h>
13 static void http_field(VALUE req, const char *field,
14                        size_t flen, const char *value, size_t vlen);
15 static void request_method(VALUE req, const char *at, size_t length);
16 static void scheme(VALUE req, const char *at, size_t length);
17 static void host(VALUE req, const char *at, size_t length);
18 static void request_uri(VALUE req, const char *at, size_t length);
19 static void fragment(VALUE req, const char *at, size_t length);
20 static void request_path(VALUE req, const char *at, size_t length);
21 static void query_string(VALUE req, const char *at, size_t length);
22 static void http_version(VALUE req, const char *at, size_t length);
23 static void header_done(VALUE req, const char *at, size_t length);
25 struct http_parser {
26   int cs;
27   union {
28     size_t body;
29     size_t field;
30     size_t query;
31     size_t offset;
32   } start;
33   size_t mark;
34   size_t field_len;
37 static int http_parser_has_error(struct http_parser *parser);
38 static int http_parser_is_finished(struct http_parser *parser);
41  * capitalizes all lower-case ASCII characters,
42  * converts dashes to underscores.
43  */
44 static void snake_upcase_char(char *c)
46   if (*c >= 'a' && *c <= 'z')
47     *c &= ~0x20;
48   else if (*c == '-')
49     *c = '_';
52 static void downcase_char(char *c)
54   if (*c >= 'A' && *c <= 'Z')
55     *c |= 0x20;
58 #define LEN(AT, FPC) (FPC - buffer - parser->AT)
59 #define MARK(M,FPC) (parser->M = (FPC) - buffer)
60 #define PTR_TO(F) (buffer + parser->F)
62 /** Machine **/
64 %%{
65   machine http_parser;
67   action mark {MARK(mark, fpc); }
69   action start_field { MARK(start.field, fpc); }
70   action snake_upcase_field { snake_upcase_char((char *)fpc); }
71   action downcase_char { downcase_char((char *)fpc); }
72   action write_field {
73     parser->field_len = LEN(start.field, fpc);
74   }
76   action start_value { MARK(mark, fpc); }
77   action write_value {
78     http_field(req, PTR_TO(start.field), parser->field_len,
79                PTR_TO(mark), LEN(mark, fpc));
80   }
81   action request_method { request_method(req, PTR_TO(mark), LEN(mark, fpc)); }
82   action scheme { scheme(req, PTR_TO(mark), LEN(mark, fpc)); }
83   action host { host(req, PTR_TO(mark), LEN(mark, fpc)); }
84   action request_uri { request_uri(req, PTR_TO(mark), LEN(mark, fpc)); }
85   action fragment { fragment(req, PTR_TO(mark), LEN(mark, fpc)); }
87   action start_query {MARK(start.query, fpc); }
88   action query_string {
89     query_string(req, PTR_TO(start.query), LEN(start.query, fpc));
90   }
92   action http_version { http_version(req, PTR_TO(mark), LEN(mark, fpc)); }
93   action request_path { request_path(req, PTR_TO(mark), LEN(mark,fpc)); }
95   action done {
96     parser->start.body = fpc - buffer + 1;
97     header_done(req, fpc + 1, pe - fpc - 1);
98     fbreak;
99   }
101   include unicorn_http_common "unicorn_http_common.rl";
104 /** Data **/
105 %% write data;
107 static void http_parser_init(struct http_parser *parser) {
108   int cs = 0;
109   memset(parser, 0, sizeof(*parser));
110   %% write init;
111   parser->cs = cs;
114 /** exec **/
115 static void http_parser_execute(
116   struct http_parser *parser, VALUE req, const char *buffer, size_t len)
118   const char *p, *pe;
119   int cs = parser->cs;
120   size_t off = parser->start.offset;
122   assert(off <= len && "offset past end of buffer");
124   p = buffer+off;
125   pe = buffer+len;
127   assert(*pe == '\0' && "pointer does not end on NUL");
128   assert(pe - p == len - off && "pointers aren't same distance");
130   %% write exec;
132   if (!http_parser_has_error(parser))
133     parser->cs = cs;
134   parser->start.offset = p - buffer;
136   assert(p <= pe && "buffer overflow after parsing execute");
137   assert(parser->start.offset <= len && "start.offset longer than length");
138   assert(parser->mark < len && "mark is after buffer end");
139   assert(parser->field_len <= len && "field has length longer than whole buffer");
142 static int http_parser_has_error(struct http_parser *parser) {
143   return parser->cs == http_parser_error;
146 static int http_parser_is_finished(struct http_parser *parser) {
147   return parser->cs == http_parser_first_final;
149 #endif /* unicorn_http_h */