unicorn 0.9.2 → 0.90.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +3 -0
  3. data/GNUmakefile +7 -7
  4. data/Manifest +20 -23
  5. data/README +16 -13
  6. data/TODO +5 -3
  7. data/bin/unicorn +1 -1
  8. data/bin/unicorn_rails +1 -1
  9. data/ext/unicorn_http/c_util.h +107 -0
  10. data/ext/unicorn_http/common_field_optimization.h +110 -0
  11. data/ext/unicorn_http/ext_help.h +41 -5
  12. data/ext/unicorn_http/extconf.rb +3 -1
  13. data/ext/unicorn_http/global_variables.h +93 -0
  14. data/ext/unicorn_http/unicorn_http.c +2123 -326
  15. data/ext/unicorn_http/unicorn_http.rl +488 -87
  16. data/ext/unicorn_http/unicorn_http_common.rl +12 -1
  17. data/lib/unicorn.rb +0 -2
  18. data/lib/unicorn/app/exec_cgi.rb +0 -1
  19. data/lib/unicorn/app/inetd.rb +2 -0
  20. data/lib/unicorn/app/old_rails/static.rb +0 -2
  21. data/lib/unicorn/const.rb +1 -5
  22. data/lib/unicorn/http_request.rb +13 -29
  23. data/lib/unicorn/http_response.rb +1 -1
  24. data/lib/unicorn/tee_input.rb +48 -46
  25. data/lib/unicorn/util.rb +3 -3
  26. data/test/benchmark/README +0 -5
  27. data/test/exec/test_exec.rb +4 -0
  28. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/.gitignore +0 -0
  29. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/Rakefile +0 -0
  30. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/controllers/application_controller.rb +0 -0
  31. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/controllers/foo_controller.rb +0 -0
  32. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/helpers/application_helper.rb +0 -0
  33. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/boot.rb +0 -0
  34. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/database.yml +0 -0
  35. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environment.rb +0 -0
  36. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environments/development.rb +0 -0
  37. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environments/production.rb +0 -0
  38. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/routes.rb +0 -0
  39. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/db/.gitignore +0 -0
  40. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/public/404.html +0 -0
  41. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/public/500.html +0 -0
  42. data/test/unit/test_http_parser.rb +112 -47
  43. data/test/unit/test_http_parser_ng.rb +284 -0
  44. data/test/unit/test_request.rb +25 -7
  45. data/test/unit/test_response.rb +11 -0
  46. data/test/unit/test_server.rb +7 -2
  47. data/test/unit/test_signals.rb +2 -0
  48. data/test/unit/test_tee_input.rb +118 -2
  49. data/test/unit/test_upload.rb +1 -1
  50. data/test/unit/test_util.rb +5 -0
  51. data/unicorn.gemspec +6 -6
  52. metadata +33 -37
  53. data/ext/unicorn_http/unicorn_http.h +0 -1289
  54. data/lib/unicorn/chunked_reader.rb +0 -77
  55. data/lib/unicorn/trailer_parser.rb +0 -52
  56. data/test/benchmark/big_request.rb +0 -44
  57. data/test/benchmark/request.rb +0 -56
  58. data/test/benchmark/response.rb +0 -30
  59. data/test/unit/test_chunked_reader.rb +0 -123
  60. data/test/unit/test_trailer_parser.rb +0 -52
@@ -1,12 +1,48 @@
1
1
  #ifndef ext_help_h
2
2
  #define ext_help_h
3
3
 
4
- #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
4
+ #ifndef RSTRING_PTR
5
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
6
+ #endif
7
+ #ifndef RSTRING_LEN
8
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
9
+ #endif
5
10
 
6
- #ifdef DEBUG
7
- #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
8
- #else
9
- #define TRACE()
11
+ #ifndef HAVE_RB_STR_SET_LEN
12
+ /* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
13
+ static void rb_18_str_set_len(VALUE str, long len)
14
+ {
15
+ RSTRING(str)->len = len;
16
+ RSTRING(str)->ptr[len] = '\0';
17
+ }
18
+ # define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
10
19
  #endif
11
20
 
21
+ static inline int str_cstr_eq(VALUE val, const char *ptr, size_t len)
22
+ {
23
+ return (RSTRING_LEN(val) == len && !memcmp(ptr, RSTRING_PTR(val), len));
24
+ }
25
+
26
+ #define STR_CSTR_EQ(val, const_str) \
27
+ str_cstr_eq(val, const_str, sizeof(const_str) - 1)
28
+
29
+ /* strcasecmp isn't locale independent */
30
+ static int str_cstr_case_eq(VALUE val, const char *ptr, size_t len)
31
+ {
32
+ if (RSTRING_LEN(val) == len) {
33
+ const char *v = RSTRING_PTR(val);
34
+
35
+ for (; len--; ++ptr, ++v) {
36
+ if ((*ptr == *v) || (*v >= 'A' && *v <= 'Z' && (*v | 0x20) == *ptr))
37
+ continue;
38
+ return 0;
39
+ }
40
+ return 1;
41
+ }
42
+ return 0;
43
+ }
44
+
45
+ #define STR_CSTR_CASE_EQ(val, const_str) \
46
+ str_cstr_case_eq(val, const_str, sizeof(const_str) - 1)
47
+
12
48
  #endif
@@ -1,5 +1,7 @@
1
1
  require 'mkmf'
2
2
 
3
3
  dir_config("unicorn_http")
4
- have_library("c", "main")
4
+
5
+ have_macro("SIZEOF_OFF_T", "ruby.h") or check_sizeof("off_t", "sys/types.h")
6
+ have_func("rb_str_set_len", "ruby.h")
5
7
  create_makefile("unicorn_http")
@@ -0,0 +1,93 @@
1
+ #ifndef global_variables_h
2
+ #define global_variables_h
3
+ static VALUE mUnicorn;
4
+ static VALUE cHttpParser;
5
+ static VALUE eHttpParserError;
6
+
7
+ static VALUE g_rack_url_scheme;
8
+ static VALUE g_request_method;
9
+ static VALUE g_request_uri;
10
+ static VALUE g_fragment;
11
+ static VALUE g_query_string;
12
+ static VALUE g_http_version;
13
+ static VALUE g_request_path;
14
+ static VALUE g_path_info;
15
+ static VALUE g_server_name;
16
+ static VALUE g_server_port;
17
+ static VALUE g_server_protocol;
18
+ static VALUE g_http_host;
19
+ static VALUE g_http_x_forwarded_proto;
20
+ static VALUE g_http_transfer_encoding;
21
+ static VALUE g_content_length;
22
+ static VALUE g_http_trailer;
23
+ static VALUE g_http_connection;
24
+ static VALUE g_port_80;
25
+ static VALUE g_port_443;
26
+ static VALUE g_localhost;
27
+ static VALUE g_http;
28
+ static VALUE g_http_11;
29
+ static VALUE g_GET;
30
+ static VALUE g_HEAD;
31
+
32
+ /** Defines common length and error messages for input length validation. */
33
+ #define DEF_MAX_LENGTH(N, length) \
34
+ static const size_t MAX_##N##_LENGTH = length; \
35
+ static const char * const MAX_##N##_LENGTH_ERR = \
36
+ "HTTP element " # N " is longer than the " # length " allowed length."
37
+
38
+ /**
39
+ * Validates the max length of given input and throws an HttpParserError
40
+ * exception if over.
41
+ */
42
+ #define VALIDATE_MAX_LENGTH(len, N) do { \
43
+ if (len > MAX_##N##_LENGTH) \
44
+ rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); \
45
+ } while (0)
46
+
47
+ /** Defines global strings in the init method. */
48
+ #define DEF_GLOBAL(N, val) do { \
49
+ g_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
50
+ rb_global_variable(&g_##N); \
51
+ } while (0)
52
+
53
+ /* Defines the maximum allowed lengths for various input elements.*/
54
+ DEF_MAX_LENGTH(FIELD_NAME, 256);
55
+ DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
56
+ DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
57
+ DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
58
+ DEF_MAX_LENGTH(REQUEST_PATH, 1024);
59
+ DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
60
+ DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
61
+
62
+ void init_globals(void)
63
+ {
64
+ mUnicorn = rb_define_module("Unicorn");
65
+
66
+ DEF_GLOBAL(rack_url_scheme, "rack.url_scheme");
67
+ DEF_GLOBAL(request_method, "REQUEST_METHOD");
68
+ DEF_GLOBAL(request_uri, "REQUEST_URI");
69
+ DEF_GLOBAL(fragment, "FRAGMENT");
70
+ DEF_GLOBAL(query_string, "QUERY_STRING");
71
+ DEF_GLOBAL(http_version, "HTTP_VERSION");
72
+ DEF_GLOBAL(request_path, "REQUEST_PATH");
73
+ DEF_GLOBAL(path_info, "PATH_INFO");
74
+ DEF_GLOBAL(server_name, "SERVER_NAME");
75
+ DEF_GLOBAL(server_port, "SERVER_PORT");
76
+ DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
77
+ DEF_GLOBAL(http_x_forwarded_proto, "HTTP_X_FORWARDED_PROTO");
78
+ DEF_GLOBAL(port_80, "80");
79
+ DEF_GLOBAL(port_443, "443");
80
+ DEF_GLOBAL(localhost, "localhost");
81
+ DEF_GLOBAL(http, "http");
82
+ DEF_GLOBAL(http_11, "HTTP/1.1");
83
+ DEF_GLOBAL(GET, "GET");
84
+ DEF_GLOBAL(HEAD, "HEAD");
85
+
86
+ eHttpParserError =
87
+ rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
88
+ cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
89
+ }
90
+
91
+ #undef DEF_GLOBAL
92
+
93
+ #endif /* global_variables_h */
@@ -1,3 +1,5 @@
1
+
2
+ #line 1 "unicorn_http.rl"
1
3
  /**
2
4
  * Copyright (c) 2009 Eric Wong (all bugs are Eric's fault)
3
5
  * Copyright (c) 2005 Zed A. Shaw
@@ -7,310 +9,2014 @@
7
9
  #include "ext_help.h"
8
10
  #include <assert.h>
9
11
  #include <string.h>
10
- #include "unicorn_http.h"
11
-
12
- static http_parser *data_get(VALUE self)
13
- {
14
- http_parser *http;
15
-
16
- Data_Get_Struct(self, http_parser, http);
17
- if (!http)
18
- rb_raise(rb_eArgError, "NULL found for http when shouldn't be.");
19
- return http;
20
- }
21
-
22
- #ifndef RSTRING_PTR
23
- #define RSTRING_PTR(s) (RSTRING(s)->ptr)
24
- #endif
25
- #ifndef RSTRING_LEN
26
- #define RSTRING_LEN(s) (RSTRING(s)->len)
27
- #endif
28
-
29
- static VALUE mUnicorn;
30
- static VALUE cHttpParser;
31
- static VALUE eHttpParserError;
32
- static VALUE sym_http_body;
33
-
34
- #define HTTP_PREFIX "HTTP_"
35
- #define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
36
-
37
- static VALUE global_rack_url_scheme;
38
- static VALUE global_request_method;
39
- static VALUE global_request_uri;
40
- static VALUE global_fragment;
41
- static VALUE global_query_string;
42
- static VALUE global_http_version;
43
- static VALUE global_request_path;
44
- static VALUE global_path_info;
45
- static VALUE global_server_name;
46
- static VALUE global_server_port;
47
- static VALUE global_server_protocol;
48
- static VALUE global_server_protocol_value;
49
- static VALUE global_http_host;
50
- static VALUE global_http_x_forwarded_proto;
51
- static VALUE global_port_80;
52
- static VALUE global_port_443;
53
- static VALUE global_localhost;
54
- static VALUE global_http;
55
-
56
- /** Defines common length and error messages for input length validation. */
57
- #define DEF_MAX_LENGTH(N, length) \
58
- static const size_t MAX_##N##_LENGTH = length; \
59
- static const char * const MAX_##N##_LENGTH_ERR = \
60
- "HTTP element " # N " is longer than the " # length " allowed length."
61
-
62
- /**
63
- * Validates the max length of given input and throws an HttpParserError
64
- * exception if over.
65
- */
66
- #define VALIDATE_MAX_LENGTH(len, N) do { \
67
- if (len > MAX_##N##_LENGTH) \
68
- rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); \
69
- } while (0)
70
-
71
- /** Defines global strings in the init method. */
72
- #define DEF_GLOBAL(N, val) do { \
73
- global_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
74
- rb_global_variable(&global_##N); \
75
- } while (0)
76
-
77
- /* Defines the maximum allowed lengths for various input elements.*/
78
- DEF_MAX_LENGTH(FIELD_NAME, 256);
79
- DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
80
- DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
81
- DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
82
- DEF_MAX_LENGTH(REQUEST_PATH, 1024);
83
- DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
84
- DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
85
-
86
- struct common_field {
87
- const signed long len;
88
- const char *name;
89
- VALUE value;
12
+ #include <sys/types.h>
13
+ #include "common_field_optimization.h"
14
+ #include "global_variables.h"
15
+ #include "c_util.h"
16
+
17
+ #define UH_FL_CHUNKED 0x1
18
+ #define UH_FL_HASBODY 0x2
19
+ #define UH_FL_INBODY 0x4
20
+ #define UH_FL_HASTRAILER 0x8
21
+ #define UH_FL_INTRAILER 0x10
22
+ #define UH_FL_INCHUNK 0x20
23
+ #define UH_FL_KAMETHOD 0x40
24
+ #define UH_FL_KAVERSION 0x80
25
+
26
+ #define UH_FL_KEEPALIVE (UH_FL_KAMETHOD | UH_FL_KAVERSION)
27
+
28
+ struct http_parser {
29
+ int cs; /* Ragel internal state */
30
+ unsigned int flags;
31
+ size_t mark;
32
+ union { /* these 3 fields don't nest */
33
+ size_t field;
34
+ size_t query;
35
+ size_t offset;
36
+ } start;
37
+ union {
38
+ size_t field_len; /* only used during header processing */
39
+ size_t dest_offset; /* only used during body processing */
40
+ } s;
41
+ union {
42
+ off_t content;
43
+ off_t chunk;
44
+ } len;
90
45
  };
91
46
 
92
- /*
93
- * A list of common HTTP headers we expect to receive.
94
- * This allows us to avoid repeatedly creating identical string
95
- * objects to be used with rb_hash_aset().
96
- */
97
- static struct common_field common_http_fields[] = {
98
- # define f(N) { (sizeof(N) - 1), N, Qnil }
99
- f("ACCEPT"),
100
- f("ACCEPT_CHARSET"),
101
- f("ACCEPT_ENCODING"),
102
- f("ACCEPT_LANGUAGE"),
103
- f("ALLOW"),
104
- f("AUTHORIZATION"),
105
- f("CACHE_CONTROL"),
106
- f("CONNECTION"),
107
- f("CONTENT_ENCODING"),
108
- f("CONTENT_LENGTH"),
109
- f("CONTENT_TYPE"),
110
- f("COOKIE"),
111
- f("DATE"),
112
- f("EXPECT"),
113
- f("FROM"),
114
- f("HOST"),
115
- f("IF_MATCH"),
116
- f("IF_MODIFIED_SINCE"),
117
- f("IF_NONE_MATCH"),
118
- f("IF_RANGE"),
119
- f("IF_UNMODIFIED_SINCE"),
120
- f("KEEP_ALIVE"), /* Firefox sends this */
121
- f("MAX_FORWARDS"),
122
- f("PRAGMA"),
123
- f("PROXY_AUTHORIZATION"),
124
- f("RANGE"),
125
- f("REFERER"),
126
- f("TE"),
127
- f("TRAILER"),
128
- f("TRANSFER_ENCODING"),
129
- f("UPGRADE"),
130
- f("USER_AGENT"),
131
- f("VIA"),
132
- f("X_FORWARDED_FOR"), /* common for proxies */
133
- f("X_FORWARDED_PROTO"), /* common for proxies */
134
- f("X_REAL_IP"), /* common for proxies */
135
- f("WARNING")
136
- # undef f
137
- };
47
+ static void finalize_header(VALUE req);
48
+
49
+ #define REMAINING (unsigned long)(pe - p)
50
+ #define LEN(AT, FPC) (FPC - buffer - hp->AT)
51
+ #define MARK(M,FPC) (hp->M = (FPC) - buffer)
52
+ #define PTR_TO(F) (buffer + hp->F)
53
+ #define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC))
138
54
 
139
- /* this function is not performance-critical */
140
- static void init_common_fields(void)
55
+ static void
56
+ request_method(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
141
57
  {
142
- int i;
143
- struct common_field *cf = common_http_fields;
144
- char tmp[256]; /* MAX_FIELD_NAME_LENGTH */
145
- memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
146
-
147
- for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
148
- /* Rack doesn't like certain headers prefixed with "HTTP_" */
149
- if (!strcmp("CONTENT_LENGTH", cf->name) ||
150
- !strcmp("CONTENT_TYPE", cf->name)) {
151
- cf->value = rb_str_new(cf->name, cf->len);
152
- } else {
153
- memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
154
- cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
155
- }
156
- cf->value = rb_obj_freeze(cf->value);
157
- rb_global_variable(&cf->value);
58
+ VALUE v;
59
+
60
+ if (CONST_MEM_EQ("GET", ptr, len)) {
61
+ hp->flags |= UH_FL_KAMETHOD;
62
+ v = g_GET;
63
+ } else if (CONST_MEM_EQ("HEAD", ptr, len)) {
64
+ hp->flags |= UH_FL_KAMETHOD;
65
+ v = g_HEAD;
66
+ } else {
67
+ v = rb_str_new(ptr, len);
158
68
  }
69
+ rb_hash_aset(req, g_request_method, v);
159
70
  }
160
71
 
161
- static VALUE find_common_field_value(const char *field, size_t flen)
72
+ static void
73
+ http_version(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
162
74
  {
163
- int i;
164
- struct common_field *cf = common_http_fields;
165
- for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
166
- if (cf->len == flen && !memcmp(cf->name, field, flen))
167
- return cf->value;
75
+ VALUE v;
76
+
77
+ if (CONST_MEM_EQ("HTTP/1.1", ptr, len)) {
78
+ hp->flags |= UH_FL_KAVERSION;
79
+ v = g_http_11;
80
+ } else {
81
+ v = rb_str_new(ptr, len);
168
82
  }
169
- return Qnil;
83
+ rb_hash_aset(req, g_http_version, v);
170
84
  }
171
85
 
172
- static void http_field(void *data, const char *field,
173
- size_t flen, const char *value, size_t vlen)
86
+ static void invalid_if_trailer(int flags)
174
87
  {
175
- VALUE req = (VALUE)data;
176
- VALUE f = Qnil;
177
-
178
- VALIDATE_MAX_LENGTH(flen, FIELD_NAME);
179
- VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE);
88
+ if (flags & UH_FL_INTRAILER)
89
+ rb_raise(eHttpParserError, "invalid Trailer");
90
+ }
180
91
 
181
- f = find_common_field_value(field, flen);
92
+ static void write_value(VALUE req, struct http_parser *hp,
93
+ const char *buffer, const char *p)
94
+ {
95
+ VALUE f = find_common_field(PTR_TO(start.field), hp->s.field_len);
96
+ VALUE v;
97
+ VALUE e;
182
98
 
99
+ VALIDATE_MAX_LENGTH(LEN(mark, p), FIELD_VALUE);
100
+ v = STR_NEW(mark, p);
183
101
  if (f == Qnil) {
184
- /*
185
- * We got a strange header that we don't have a memoized value for.
186
- * Fallback to creating a new string to use as a hash key.
187
- *
188
- * using rb_str_new(NULL, len) here is faster than rb_str_buf_new(len)
189
- * in my testing, because: there's no minimum allocation length (and
190
- * no check for it, either), RSTRING_LEN(f) does not need to be
191
- * written twice, and and RSTRING_PTR(f) will already be
192
- * null-terminated for us.
193
- */
194
- f = rb_str_new(NULL, HTTP_PREFIX_LEN + flen);
195
- memcpy(RSTRING_PTR(f), HTTP_PREFIX, HTTP_PREFIX_LEN);
196
- memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen);
197
- assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0'); /* paranoia */
198
- /* fprintf(stderr, "UNKNOWN HEADER <%s>\n", RSTRING_PTR(f)); */
199
- } else if (f == global_http_host && rb_hash_aref(req, f) != Qnil) {
200
- return;
102
+ VALIDATE_MAX_LENGTH(hp->s.field_len, FIELD_NAME);
103
+ f = uncommon_field(PTR_TO(start.field), hp->s.field_len);
104
+ } else if (f == g_http_connection) {
105
+ if (hp->flags & UH_FL_KAMETHOD) {
106
+ if (STR_CSTR_CASE_EQ(v, "keep-alive"))
107
+ hp->flags |= UH_FL_KAVERSION;
108
+ else if (STR_CSTR_CASE_EQ(v, "close"))
109
+ hp->flags &= ~UH_FL_KEEPALIVE;
110
+ }
111
+ } else if (f == g_content_length) {
112
+ hp->len.content = parse_length(RSTRING_PTR(v), RSTRING_LEN(v));
113
+ if (hp->len.content < 0)
114
+ rb_raise(eHttpParserError, "invalid Content-Length");
115
+ hp->flags |= UH_FL_HASBODY;
116
+ invalid_if_trailer(hp->flags);
117
+ } else if (f == g_http_transfer_encoding) {
118
+ if (STR_CSTR_CASE_EQ(v, "chunked"))
119
+ hp->flags |= UH_FL_CHUNKED | UH_FL_HASBODY;
120
+ invalid_if_trailer(hp->flags);
121
+ } else if (f == g_http_trailer) {
122
+ hp->flags |= UH_FL_HASTRAILER;
123
+ invalid_if_trailer(hp->flags);
201
124
  }
202
125
 
203
- rb_hash_aset(req, f, rb_str_new(value, vlen));
126
+ e = rb_hash_aref(req, f);
127
+ if (e == Qnil) {
128
+ rb_hash_aset(req, f, v);
129
+ } else if (f != g_http_host) {
130
+ /* full URLs in REQUEST_URI take precedence for the Host: header */
131
+ rb_str_buf_cat(e, ",", 1);
132
+ rb_str_buf_append(e, v);
133
+ }
204
134
  }
205
135
 
206
- static void request_method(void *data, const char *at, size_t length)
207
- {
208
- VALUE req = (VALUE)data;
209
- VALUE val = Qnil;
136
+ /** Machine **/
210
137
 
211
- val = rb_str_new(at, length);
212
- rb_hash_aset(req, global_request_method, val);
213
- }
214
138
 
215
- static void scheme(void *data, const char *at, size_t length)
216
- {
217
- rb_hash_aset((VALUE)data, global_rack_url_scheme, rb_str_new(at, length));
218
- }
139
+ #line 250 "unicorn_http.rl"
219
140
 
220
- static void host(void *data, const char *at, size_t length)
221
- {
222
- rb_hash_aset((VALUE)data, global_http_host, rb_str_new(at, length));
223
- }
224
141
 
225
- static void request_uri(void *data, const char *at, size_t length)
226
- {
227
- VALUE req = (VALUE)data;
228
- VALUE val = Qnil;
142
+ /** Data **/
229
143
 
230
- VALIDATE_MAX_LENGTH(length, REQUEST_URI);
144
+ #line 145 "unicorn_http.c"
145
+ static const int http_parser_start = 1;
146
+ static const int http_parser_first_final = 83;
147
+ static const int http_parser_error = 0;
231
148
 
232
- val = rb_str_new(at, length);
233
- rb_hash_aset(req, global_request_uri, val);
149
+ static const int http_parser_en_ChunkedBody = 63;
150
+ static const int http_parser_en_ChunkedBody_chunk_chunk_end = 69;
151
+ static const int http_parser_en_Trailers = 77;
152
+ static const int http_parser_en_main = 1;
234
153
 
235
- /* "OPTIONS * HTTP/1.1\r\n" is a valid request */
236
- if (length == 1 && *at == '*') {
237
- val = rb_str_new(NULL, 0);
238
- rb_hash_aset(req, global_request_path, val);
239
- rb_hash_aset(req, global_path_info, val);
240
- }
241
- }
242
154
 
243
- static void fragment(void *data, const char *at, size_t length)
155
+ #line 254 "unicorn_http.rl"
156
+
157
+ static void http_parser_init(struct http_parser *hp)
244
158
  {
245
- VALUE req = (VALUE)data;
246
- VALUE val = Qnil;
159
+ int cs = 0;
160
+ memset(hp, 0, sizeof(struct http_parser));
247
161
 
248
- VALIDATE_MAX_LENGTH(length, FRAGMENT);
162
+ #line 163 "unicorn_http.c"
163
+ {
164
+ cs = http_parser_start;
165
+ }
249
166
 
250
- val = rb_str_new(at, length);
251
- rb_hash_aset(req, global_fragment, val);
167
+ #line 260 "unicorn_http.rl"
168
+ hp->cs = cs;
252
169
  }
253
170
 
254
- static void request_path(void *data, const char *at, size_t length)
171
+ /** exec **/
172
+ static void http_parser_execute(struct http_parser *hp,
173
+ VALUE req, const char *buffer, size_t len)
255
174
  {
256
- VALUE req = (VALUE)data;
257
- VALUE val = Qnil;
175
+ const char *p, *pe;
176
+ int cs = hp->cs;
177
+ size_t off = hp->start.offset;
258
178
 
259
- VALIDATE_MAX_LENGTH(length, REQUEST_PATH);
179
+ if (cs == http_parser_first_final)
180
+ return;
260
181
 
261
- val = rb_str_new(at, length);
262
- rb_hash_aset(req, global_request_path, val);
182
+ assert(off <= len && "offset past end of buffer");
263
183
 
264
- /* rack says PATH_INFO must start with "/" or be empty */
265
- if (!(length == 1 && *at == '*'))
266
- rb_hash_aset(req, global_path_info, val);
267
- }
184
+ p = buffer+off;
185
+ pe = buffer+len;
268
186
 
269
- static void query_string(void *data, const char *at, size_t length)
270
- {
271
- VALUE req = (VALUE)data;
272
- VALUE val = Qnil;
187
+ assert(pe - p == len - off && "pointers aren't same distance");
188
+
189
+ if (hp->flags & UH_FL_INCHUNK) {
190
+ hp->flags &= ~(UH_FL_INCHUNK);
191
+ goto skip_chunk_data_hack;
192
+ }
193
+
194
+ #line 195 "unicorn_http.c"
195
+ {
196
+ if ( p == pe )
197
+ goto _test_eof;
198
+ switch ( cs )
199
+ {
200
+ case 1:
201
+ switch( (*p) ) {
202
+ case 36: goto tr0;
203
+ case 95: goto tr0;
204
+ }
205
+ if ( (*p) < 48 ) {
206
+ if ( 45 <= (*p) && (*p) <= 46 )
207
+ goto tr0;
208
+ } else if ( (*p) > 57 ) {
209
+ if ( 65 <= (*p) && (*p) <= 90 )
210
+ goto tr0;
211
+ } else
212
+ goto tr0;
213
+ goto st0;
214
+ st0:
215
+ cs = 0;
216
+ goto _out;
217
+ tr0:
218
+ #line 139 "unicorn_http.rl"
219
+ {MARK(mark, p); }
220
+ goto st2;
221
+ st2:
222
+ if ( ++p == pe )
223
+ goto _test_eof2;
224
+ case 2:
225
+ #line 226 "unicorn_http.c"
226
+ switch( (*p) ) {
227
+ case 32: goto tr2;
228
+ case 36: goto st44;
229
+ case 95: goto st44;
230
+ }
231
+ if ( (*p) < 48 ) {
232
+ if ( 45 <= (*p) && (*p) <= 46 )
233
+ goto st44;
234
+ } else if ( (*p) > 57 ) {
235
+ if ( 65 <= (*p) && (*p) <= 90 )
236
+ goto st44;
237
+ } else
238
+ goto st44;
239
+ goto st0;
240
+ tr2:
241
+ #line 147 "unicorn_http.rl"
242
+ {
243
+ request_method(hp, req, PTR_TO(mark), LEN(mark, p));
244
+ }
245
+ goto st3;
246
+ st3:
247
+ if ( ++p == pe )
248
+ goto _test_eof3;
249
+ case 3:
250
+ #line 251 "unicorn_http.c"
251
+ switch( (*p) ) {
252
+ case 42: goto tr4;
253
+ case 47: goto tr5;
254
+ case 72: goto tr6;
255
+ case 104: goto tr6;
256
+ }
257
+ goto st0;
258
+ tr4:
259
+ #line 139 "unicorn_http.rl"
260
+ {MARK(mark, p); }
261
+ goto st4;
262
+ st4:
263
+ if ( ++p == pe )
264
+ goto _test_eof4;
265
+ case 4:
266
+ #line 267 "unicorn_http.c"
267
+ switch( (*p) ) {
268
+ case 32: goto tr7;
269
+ case 35: goto tr8;
270
+ }
271
+ goto st0;
272
+ tr7:
273
+ #line 156 "unicorn_http.rl"
274
+ {
275
+ size_t len = LEN(mark, p);
276
+ VALUE str;
277
+
278
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
279
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
280
+ /*
281
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
282
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
283
+ */
284
+ if (STR_CSTR_EQ(str, "*")) {
285
+ str = rb_str_new(NULL, 0);
286
+ rb_hash_aset(req, g_path_info, str);
287
+ rb_hash_aset(req, g_request_path, str);
288
+ }
289
+ }
290
+ goto st5;
291
+ tr30:
292
+ #line 139 "unicorn_http.rl"
293
+ {MARK(mark, p); }
294
+ #line 172 "unicorn_http.rl"
295
+ {
296
+ VALIDATE_MAX_LENGTH(LEN(mark, p), FRAGMENT);
297
+ rb_hash_aset(req, g_fragment, STR_NEW(mark, p));
298
+ }
299
+ goto st5;
300
+ tr33:
301
+ #line 172 "unicorn_http.rl"
302
+ {
303
+ VALIDATE_MAX_LENGTH(LEN(mark, p), FRAGMENT);
304
+ rb_hash_aset(req, g_fragment, STR_NEW(mark, p));
305
+ }
306
+ goto st5;
307
+ tr37:
308
+ #line 182 "unicorn_http.rl"
309
+ {
310
+ VALUE val;
311
+ size_t len = LEN(mark, p);
312
+
313
+ VALIDATE_MAX_LENGTH(len, REQUEST_PATH);
314
+ val = rb_hash_aset(req, g_request_path, STR_NEW(mark, p));
315
+
316
+ /* rack says PATH_INFO must start with "/" or be empty */
317
+ if (!STR_CSTR_EQ(val, "*"))
318
+ rb_hash_aset(req, g_path_info, val);
319
+ }
320
+ #line 156 "unicorn_http.rl"
321
+ {
322
+ size_t len = LEN(mark, p);
323
+ VALUE str;
324
+
325
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
326
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
327
+ /*
328
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
329
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
330
+ */
331
+ if (STR_CSTR_EQ(str, "*")) {
332
+ str = rb_str_new(NULL, 0);
333
+ rb_hash_aset(req, g_path_info, str);
334
+ rb_hash_aset(req, g_request_path, str);
335
+ }
336
+ }
337
+ goto st5;
338
+ tr48:
339
+ #line 176 "unicorn_http.rl"
340
+ {MARK(start.query, p); }
341
+ #line 177 "unicorn_http.rl"
342
+ {
343
+ VALIDATE_MAX_LENGTH(LEN(start.query, p), QUERY_STRING);
344
+ rb_hash_aset(req, g_query_string, STR_NEW(start.query, p));
345
+ }
346
+ #line 156 "unicorn_http.rl"
347
+ {
348
+ size_t len = LEN(mark, p);
349
+ VALUE str;
350
+
351
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
352
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
353
+ /*
354
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
355
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
356
+ */
357
+ if (STR_CSTR_EQ(str, "*")) {
358
+ str = rb_str_new(NULL, 0);
359
+ rb_hash_aset(req, g_path_info, str);
360
+ rb_hash_aset(req, g_request_path, str);
361
+ }
362
+ }
363
+ goto st5;
364
+ tr52:
365
+ #line 177 "unicorn_http.rl"
366
+ {
367
+ VALIDATE_MAX_LENGTH(LEN(start.query, p), QUERY_STRING);
368
+ rb_hash_aset(req, g_query_string, STR_NEW(start.query, p));
369
+ }
370
+ #line 156 "unicorn_http.rl"
371
+ {
372
+ size_t len = LEN(mark, p);
373
+ VALUE str;
374
+
375
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
376
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
377
+ /*
378
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
379
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
380
+ */
381
+ if (STR_CSTR_EQ(str, "*")) {
382
+ str = rb_str_new(NULL, 0);
383
+ rb_hash_aset(req, g_path_info, str);
384
+ rb_hash_aset(req, g_request_path, str);
385
+ }
386
+ }
387
+ goto st5;
388
+ st5:
389
+ if ( ++p == pe )
390
+ goto _test_eof5;
391
+ case 5:
392
+ #line 393 "unicorn_http.c"
393
+ if ( (*p) == 72 )
394
+ goto tr9;
395
+ goto st0;
396
+ tr9:
397
+ #line 139 "unicorn_http.rl"
398
+ {MARK(mark, p); }
399
+ goto st6;
400
+ st6:
401
+ if ( ++p == pe )
402
+ goto _test_eof6;
403
+ case 6:
404
+ #line 405 "unicorn_http.c"
405
+ if ( (*p) == 84 )
406
+ goto st7;
407
+ goto st0;
408
+ st7:
409
+ if ( ++p == pe )
410
+ goto _test_eof7;
411
+ case 7:
412
+ if ( (*p) == 84 )
413
+ goto st8;
414
+ goto st0;
415
+ st8:
416
+ if ( ++p == pe )
417
+ goto _test_eof8;
418
+ case 8:
419
+ if ( (*p) == 80 )
420
+ goto st9;
421
+ goto st0;
422
+ st9:
423
+ if ( ++p == pe )
424
+ goto _test_eof9;
425
+ case 9:
426
+ if ( (*p) == 47 )
427
+ goto st10;
428
+ goto st0;
429
+ st10:
430
+ if ( ++p == pe )
431
+ goto _test_eof10;
432
+ case 10:
433
+ if ( 48 <= (*p) && (*p) <= 57 )
434
+ goto st11;
435
+ goto st0;
436
+ st11:
437
+ if ( ++p == pe )
438
+ goto _test_eof11;
439
+ case 11:
440
+ if ( (*p) == 46 )
441
+ goto st12;
442
+ if ( 48 <= (*p) && (*p) <= 57 )
443
+ goto st11;
444
+ goto st0;
445
+ st12:
446
+ if ( ++p == pe )
447
+ goto _test_eof12;
448
+ case 12:
449
+ if ( 48 <= (*p) && (*p) <= 57 )
450
+ goto st13;
451
+ goto st0;
452
+ st13:
453
+ if ( ++p == pe )
454
+ goto _test_eof13;
455
+ case 13:
456
+ if ( (*p) == 13 )
457
+ goto tr17;
458
+ if ( 48 <= (*p) && (*p) <= 57 )
459
+ goto st13;
460
+ goto st0;
461
+ tr17:
462
+ #line 181 "unicorn_http.rl"
463
+ { http_version(hp, req, PTR_TO(mark), LEN(mark, p)); }
464
+ goto st14;
465
+ tr25:
466
+ #line 145 "unicorn_http.rl"
467
+ { MARK(mark, p); }
468
+ #line 146 "unicorn_http.rl"
469
+ { write_value(req, hp, buffer, p); }
470
+ goto st14;
471
+ tr28:
472
+ #line 146 "unicorn_http.rl"
473
+ { write_value(req, hp, buffer, p); }
474
+ goto st14;
475
+ st14:
476
+ if ( ++p == pe )
477
+ goto _test_eof14;
478
+ case 14:
479
+ #line 480 "unicorn_http.c"
480
+ if ( (*p) == 10 )
481
+ goto st15;
482
+ goto st0;
483
+ st15:
484
+ if ( ++p == pe )
485
+ goto _test_eof15;
486
+ case 15:
487
+ switch( (*p) ) {
488
+ case 13: goto st16;
489
+ case 33: goto tr20;
490
+ case 124: goto tr20;
491
+ case 126: goto tr20;
492
+ }
493
+ if ( (*p) < 45 ) {
494
+ if ( (*p) > 39 ) {
495
+ if ( 42 <= (*p) && (*p) <= 43 )
496
+ goto tr20;
497
+ } else if ( (*p) >= 35 )
498
+ goto tr20;
499
+ } else if ( (*p) > 46 ) {
500
+ if ( (*p) < 65 ) {
501
+ if ( 48 <= (*p) && (*p) <= 57 )
502
+ goto tr20;
503
+ } else if ( (*p) > 90 ) {
504
+ if ( 94 <= (*p) && (*p) <= 122 )
505
+ goto tr20;
506
+ } else
507
+ goto tr20;
508
+ } else
509
+ goto tr20;
510
+ goto st0;
511
+ st16:
512
+ if ( ++p == pe )
513
+ goto _test_eof16;
514
+ case 16:
515
+ if ( (*p) == 10 )
516
+ goto tr21;
517
+ goto st0;
518
+ tr21:
519
+ #line 198 "unicorn_http.rl"
520
+ {
521
+ finalize_header(req);
522
+
523
+ cs = http_parser_first_final;
524
+ if (hp->flags & UH_FL_HASBODY) {
525
+ hp->flags |= UH_FL_INBODY;
526
+ if (hp->flags & UH_FL_CHUNKED)
527
+ cs = http_parser_en_ChunkedBody;
528
+ } else {
529
+ assert(!(hp->flags & UH_FL_CHUNKED));
530
+ }
531
+ /*
532
+ * go back to Ruby so we can call the Rack application, we'll reenter
533
+ * the parser iff the body needs to be processed.
534
+ */
535
+ goto post_exec;
536
+ }
537
+ goto st83;
538
+ st83:
539
+ if ( ++p == pe )
540
+ goto _test_eof83;
541
+ case 83:
542
+ #line 543 "unicorn_http.c"
543
+ goto st0;
544
+ tr20:
545
+ #line 141 "unicorn_http.rl"
546
+ { MARK(start.field, p); }
547
+ #line 142 "unicorn_http.rl"
548
+ { snake_upcase_char((char *)p); }
549
+ goto st17;
550
+ tr22:
551
+ #line 142 "unicorn_http.rl"
552
+ { snake_upcase_char((char *)p); }
553
+ goto st17;
554
+ st17:
555
+ if ( ++p == pe )
556
+ goto _test_eof17;
557
+ case 17:
558
+ #line 559 "unicorn_http.c"
559
+ switch( (*p) ) {
560
+ case 33: goto tr22;
561
+ case 58: goto tr23;
562
+ case 124: goto tr22;
563
+ case 126: goto tr22;
564
+ }
565
+ if ( (*p) < 45 ) {
566
+ if ( (*p) > 39 ) {
567
+ if ( 42 <= (*p) && (*p) <= 43 )
568
+ goto tr22;
569
+ } else if ( (*p) >= 35 )
570
+ goto tr22;
571
+ } else if ( (*p) > 46 ) {
572
+ if ( (*p) < 65 ) {
573
+ if ( 48 <= (*p) && (*p) <= 57 )
574
+ goto tr22;
575
+ } else if ( (*p) > 90 ) {
576
+ if ( 94 <= (*p) && (*p) <= 122 )
577
+ goto tr22;
578
+ } else
579
+ goto tr22;
580
+ } else
581
+ goto tr22;
582
+ goto st0;
583
+ tr23:
584
+ #line 144 "unicorn_http.rl"
585
+ { hp->s.field_len = LEN(start.field, p); }
586
+ goto st18;
587
+ tr26:
588
+ #line 145 "unicorn_http.rl"
589
+ { MARK(mark, p); }
590
+ goto st18;
591
+ st18:
592
+ if ( ++p == pe )
593
+ goto _test_eof18;
594
+ case 18:
595
+ #line 596 "unicorn_http.c"
596
+ switch( (*p) ) {
597
+ case 13: goto tr25;
598
+ case 32: goto tr26;
599
+ }
600
+ goto tr24;
601
+ tr24:
602
+ #line 145 "unicorn_http.rl"
603
+ { MARK(mark, p); }
604
+ goto st19;
605
+ st19:
606
+ if ( ++p == pe )
607
+ goto _test_eof19;
608
+ case 19:
609
+ #line 610 "unicorn_http.c"
610
+ if ( (*p) == 13 )
611
+ goto tr28;
612
+ goto st19;
613
+ tr8:
614
+ #line 156 "unicorn_http.rl"
615
+ {
616
+ size_t len = LEN(mark, p);
617
+ VALUE str;
618
+
619
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
620
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
621
+ /*
622
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
623
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
624
+ */
625
+ if (STR_CSTR_EQ(str, "*")) {
626
+ str = rb_str_new(NULL, 0);
627
+ rb_hash_aset(req, g_path_info, str);
628
+ rb_hash_aset(req, g_request_path, str);
629
+ }
630
+ }
631
+ goto st20;
632
+ tr38:
633
+ #line 182 "unicorn_http.rl"
634
+ {
635
+ VALUE val;
636
+ size_t len = LEN(mark, p);
637
+
638
+ VALIDATE_MAX_LENGTH(len, REQUEST_PATH);
639
+ val = rb_hash_aset(req, g_request_path, STR_NEW(mark, p));
640
+
641
+ /* rack says PATH_INFO must start with "/" or be empty */
642
+ if (!STR_CSTR_EQ(val, "*"))
643
+ rb_hash_aset(req, g_path_info, val);
644
+ }
645
+ #line 156 "unicorn_http.rl"
646
+ {
647
+ size_t len = LEN(mark, p);
648
+ VALUE str;
649
+
650
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
651
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
652
+ /*
653
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
654
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
655
+ */
656
+ if (STR_CSTR_EQ(str, "*")) {
657
+ str = rb_str_new(NULL, 0);
658
+ rb_hash_aset(req, g_path_info, str);
659
+ rb_hash_aset(req, g_request_path, str);
660
+ }
661
+ }
662
+ goto st20;
663
+ tr49:
664
+ #line 176 "unicorn_http.rl"
665
+ {MARK(start.query, p); }
666
+ #line 177 "unicorn_http.rl"
667
+ {
668
+ VALIDATE_MAX_LENGTH(LEN(start.query, p), QUERY_STRING);
669
+ rb_hash_aset(req, g_query_string, STR_NEW(start.query, p));
670
+ }
671
+ #line 156 "unicorn_http.rl"
672
+ {
673
+ size_t len = LEN(mark, p);
674
+ VALUE str;
273
675
 
274
- VALIDATE_MAX_LENGTH(length, QUERY_STRING);
676
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
677
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
678
+ /*
679
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
680
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
681
+ */
682
+ if (STR_CSTR_EQ(str, "*")) {
683
+ str = rb_str_new(NULL, 0);
684
+ rb_hash_aset(req, g_path_info, str);
685
+ rb_hash_aset(req, g_request_path, str);
686
+ }
687
+ }
688
+ goto st20;
689
+ tr53:
690
+ #line 177 "unicorn_http.rl"
691
+ {
692
+ VALIDATE_MAX_LENGTH(LEN(start.query, p), QUERY_STRING);
693
+ rb_hash_aset(req, g_query_string, STR_NEW(start.query, p));
694
+ }
695
+ #line 156 "unicorn_http.rl"
696
+ {
697
+ size_t len = LEN(mark, p);
698
+ VALUE str;
275
699
 
276
- val = rb_str_new(at, length);
277
- rb_hash_aset(req, global_query_string, val);
700
+ VALIDATE_MAX_LENGTH(len, REQUEST_URI);
701
+ str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, p));
702
+ /*
703
+ * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
704
+ * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
705
+ */
706
+ if (STR_CSTR_EQ(str, "*")) {
707
+ str = rb_str_new(NULL, 0);
708
+ rb_hash_aset(req, g_path_info, str);
709
+ rb_hash_aset(req, g_request_path, str);
710
+ }
711
+ }
712
+ goto st20;
713
+ st20:
714
+ if ( ++p == pe )
715
+ goto _test_eof20;
716
+ case 20:
717
+ #line 718 "unicorn_http.c"
718
+ switch( (*p) ) {
719
+ case 32: goto tr30;
720
+ case 35: goto st0;
721
+ case 37: goto tr31;
722
+ case 127: goto st0;
723
+ }
724
+ if ( 0 <= (*p) && (*p) <= 31 )
725
+ goto st0;
726
+ goto tr29;
727
+ tr29:
728
+ #line 139 "unicorn_http.rl"
729
+ {MARK(mark, p); }
730
+ goto st21;
731
+ st21:
732
+ if ( ++p == pe )
733
+ goto _test_eof21;
734
+ case 21:
735
+ #line 736 "unicorn_http.c"
736
+ switch( (*p) ) {
737
+ case 32: goto tr33;
738
+ case 35: goto st0;
739
+ case 37: goto st22;
740
+ case 127: goto st0;
741
+ }
742
+ if ( 0 <= (*p) && (*p) <= 31 )
743
+ goto st0;
744
+ goto st21;
745
+ tr31:
746
+ #line 139 "unicorn_http.rl"
747
+ {MARK(mark, p); }
748
+ goto st22;
749
+ st22:
750
+ if ( ++p == pe )
751
+ goto _test_eof22;
752
+ case 22:
753
+ #line 754 "unicorn_http.c"
754
+ if ( (*p) < 65 ) {
755
+ if ( 48 <= (*p) && (*p) <= 57 )
756
+ goto st23;
757
+ } else if ( (*p) > 70 ) {
758
+ if ( 97 <= (*p) && (*p) <= 102 )
759
+ goto st23;
760
+ } else
761
+ goto st23;
762
+ goto st0;
763
+ st23:
764
+ if ( ++p == pe )
765
+ goto _test_eof23;
766
+ case 23:
767
+ if ( (*p) < 65 ) {
768
+ if ( 48 <= (*p) && (*p) <= 57 )
769
+ goto st21;
770
+ } else if ( (*p) > 70 ) {
771
+ if ( 97 <= (*p) && (*p) <= 102 )
772
+ goto st21;
773
+ } else
774
+ goto st21;
775
+ goto st0;
776
+ tr5:
777
+ #line 139 "unicorn_http.rl"
778
+ {MARK(mark, p); }
779
+ goto st24;
780
+ tr65:
781
+ #line 153 "unicorn_http.rl"
782
+ {
783
+ rb_hash_aset(req, g_http_host, STR_NEW(mark, p));
784
+ }
785
+ #line 139 "unicorn_http.rl"
786
+ {MARK(mark, p); }
787
+ goto st24;
788
+ st24:
789
+ if ( ++p == pe )
790
+ goto _test_eof24;
791
+ case 24:
792
+ #line 793 "unicorn_http.c"
793
+ switch( (*p) ) {
794
+ case 32: goto tr37;
795
+ case 35: goto tr38;
796
+ case 37: goto st25;
797
+ case 59: goto tr40;
798
+ case 63: goto tr41;
799
+ case 127: goto st0;
800
+ }
801
+ if ( 0 <= (*p) && (*p) <= 31 )
802
+ goto st0;
803
+ goto st24;
804
+ st25:
805
+ if ( ++p == pe )
806
+ goto _test_eof25;
807
+ case 25:
808
+ if ( (*p) < 65 ) {
809
+ if ( 48 <= (*p) && (*p) <= 57 )
810
+ goto st26;
811
+ } else if ( (*p) > 70 ) {
812
+ if ( 97 <= (*p) && (*p) <= 102 )
813
+ goto st26;
814
+ } else
815
+ goto st26;
816
+ goto st0;
817
+ st26:
818
+ if ( ++p == pe )
819
+ goto _test_eof26;
820
+ case 26:
821
+ if ( (*p) < 65 ) {
822
+ if ( 48 <= (*p) && (*p) <= 57 )
823
+ goto st24;
824
+ } else if ( (*p) > 70 ) {
825
+ if ( 97 <= (*p) && (*p) <= 102 )
826
+ goto st24;
827
+ } else
828
+ goto st24;
829
+ goto st0;
830
+ tr40:
831
+ #line 182 "unicorn_http.rl"
832
+ {
833
+ VALUE val;
834
+ size_t len = LEN(mark, p);
835
+
836
+ VALIDATE_MAX_LENGTH(len, REQUEST_PATH);
837
+ val = rb_hash_aset(req, g_request_path, STR_NEW(mark, p));
838
+
839
+ /* rack says PATH_INFO must start with "/" or be empty */
840
+ if (!STR_CSTR_EQ(val, "*"))
841
+ rb_hash_aset(req, g_path_info, val);
842
+ }
843
+ goto st27;
844
+ st27:
845
+ if ( ++p == pe )
846
+ goto _test_eof27;
847
+ case 27:
848
+ #line 849 "unicorn_http.c"
849
+ switch( (*p) ) {
850
+ case 32: goto tr7;
851
+ case 35: goto tr8;
852
+ case 37: goto st28;
853
+ case 63: goto st30;
854
+ case 127: goto st0;
855
+ }
856
+ if ( 0 <= (*p) && (*p) <= 31 )
857
+ goto st0;
858
+ goto st27;
859
+ st28:
860
+ if ( ++p == pe )
861
+ goto _test_eof28;
862
+ case 28:
863
+ if ( (*p) < 65 ) {
864
+ if ( 48 <= (*p) && (*p) <= 57 )
865
+ goto st29;
866
+ } else if ( (*p) > 70 ) {
867
+ if ( 97 <= (*p) && (*p) <= 102 )
868
+ goto st29;
869
+ } else
870
+ goto st29;
871
+ goto st0;
872
+ st29:
873
+ if ( ++p == pe )
874
+ goto _test_eof29;
875
+ case 29:
876
+ if ( (*p) < 65 ) {
877
+ if ( 48 <= (*p) && (*p) <= 57 )
878
+ goto st27;
879
+ } else if ( (*p) > 70 ) {
880
+ if ( 97 <= (*p) && (*p) <= 102 )
881
+ goto st27;
882
+ } else
883
+ goto st27;
884
+ goto st0;
885
+ tr41:
886
+ #line 182 "unicorn_http.rl"
887
+ {
888
+ VALUE val;
889
+ size_t len = LEN(mark, p);
890
+
891
+ VALIDATE_MAX_LENGTH(len, REQUEST_PATH);
892
+ val = rb_hash_aset(req, g_request_path, STR_NEW(mark, p));
893
+
894
+ /* rack says PATH_INFO must start with "/" or be empty */
895
+ if (!STR_CSTR_EQ(val, "*"))
896
+ rb_hash_aset(req, g_path_info, val);
897
+ }
898
+ goto st30;
899
+ st30:
900
+ if ( ++p == pe )
901
+ goto _test_eof30;
902
+ case 30:
903
+ #line 904 "unicorn_http.c"
904
+ switch( (*p) ) {
905
+ case 32: goto tr48;
906
+ case 35: goto tr49;
907
+ case 37: goto tr50;
908
+ case 127: goto st0;
909
+ }
910
+ if ( 0 <= (*p) && (*p) <= 31 )
911
+ goto st0;
912
+ goto tr47;
913
+ tr47:
914
+ #line 176 "unicorn_http.rl"
915
+ {MARK(start.query, p); }
916
+ goto st31;
917
+ st31:
918
+ if ( ++p == pe )
919
+ goto _test_eof31;
920
+ case 31:
921
+ #line 922 "unicorn_http.c"
922
+ switch( (*p) ) {
923
+ case 32: goto tr52;
924
+ case 35: goto tr53;
925
+ case 37: goto st32;
926
+ case 127: goto st0;
927
+ }
928
+ if ( 0 <= (*p) && (*p) <= 31 )
929
+ goto st0;
930
+ goto st31;
931
+ tr50:
932
+ #line 176 "unicorn_http.rl"
933
+ {MARK(start.query, p); }
934
+ goto st32;
935
+ st32:
936
+ if ( ++p == pe )
937
+ goto _test_eof32;
938
+ case 32:
939
+ #line 940 "unicorn_http.c"
940
+ if ( (*p) < 65 ) {
941
+ if ( 48 <= (*p) && (*p) <= 57 )
942
+ goto st33;
943
+ } else if ( (*p) > 70 ) {
944
+ if ( 97 <= (*p) && (*p) <= 102 )
945
+ goto st33;
946
+ } else
947
+ goto st33;
948
+ goto st0;
949
+ st33:
950
+ if ( ++p == pe )
951
+ goto _test_eof33;
952
+ case 33:
953
+ if ( (*p) < 65 ) {
954
+ if ( 48 <= (*p) && (*p) <= 57 )
955
+ goto st31;
956
+ } else if ( (*p) > 70 ) {
957
+ if ( 97 <= (*p) && (*p) <= 102 )
958
+ goto st31;
959
+ } else
960
+ goto st31;
961
+ goto st0;
962
+ tr6:
963
+ #line 139 "unicorn_http.rl"
964
+ {MARK(mark, p); }
965
+ #line 143 "unicorn_http.rl"
966
+ { downcase_char((char *)p); }
967
+ goto st34;
968
+ st34:
969
+ if ( ++p == pe )
970
+ goto _test_eof34;
971
+ case 34:
972
+ #line 973 "unicorn_http.c"
973
+ switch( (*p) ) {
974
+ case 84: goto tr56;
975
+ case 116: goto tr56;
976
+ }
977
+ goto st0;
978
+ tr56:
979
+ #line 143 "unicorn_http.rl"
980
+ { downcase_char((char *)p); }
981
+ goto st35;
982
+ st35:
983
+ if ( ++p == pe )
984
+ goto _test_eof35;
985
+ case 35:
986
+ #line 987 "unicorn_http.c"
987
+ switch( (*p) ) {
988
+ case 84: goto tr57;
989
+ case 116: goto tr57;
990
+ }
991
+ goto st0;
992
+ tr57:
993
+ #line 143 "unicorn_http.rl"
994
+ { downcase_char((char *)p); }
995
+ goto st36;
996
+ st36:
997
+ if ( ++p == pe )
998
+ goto _test_eof36;
999
+ case 36:
1000
+ #line 1001 "unicorn_http.c"
1001
+ switch( (*p) ) {
1002
+ case 80: goto tr58;
1003
+ case 112: goto tr58;
1004
+ }
1005
+ goto st0;
1006
+ tr58:
1007
+ #line 143 "unicorn_http.rl"
1008
+ { downcase_char((char *)p); }
1009
+ goto st37;
1010
+ st37:
1011
+ if ( ++p == pe )
1012
+ goto _test_eof37;
1013
+ case 37:
1014
+ #line 1015 "unicorn_http.c"
1015
+ switch( (*p) ) {
1016
+ case 58: goto tr59;
1017
+ case 83: goto tr60;
1018
+ case 115: goto tr60;
1019
+ }
1020
+ goto st0;
1021
+ tr59:
1022
+ #line 150 "unicorn_http.rl"
1023
+ {
1024
+ rb_hash_aset(req, g_rack_url_scheme, STR_NEW(mark, p));
1025
+ }
1026
+ goto st38;
1027
+ st38:
1028
+ if ( ++p == pe )
1029
+ goto _test_eof38;
1030
+ case 38:
1031
+ #line 1032 "unicorn_http.c"
1032
+ if ( (*p) == 47 )
1033
+ goto st39;
1034
+ goto st0;
1035
+ st39:
1036
+ if ( ++p == pe )
1037
+ goto _test_eof39;
1038
+ case 39:
1039
+ if ( (*p) == 47 )
1040
+ goto st40;
1041
+ goto st0;
1042
+ st40:
1043
+ if ( ++p == pe )
1044
+ goto _test_eof40;
1045
+ case 40:
1046
+ if ( (*p) == 95 )
1047
+ goto tr63;
1048
+ if ( (*p) < 48 ) {
1049
+ if ( 45 <= (*p) && (*p) <= 46 )
1050
+ goto tr63;
1051
+ } else if ( (*p) > 57 ) {
1052
+ if ( (*p) > 90 ) {
1053
+ if ( 97 <= (*p) && (*p) <= 122 )
1054
+ goto tr63;
1055
+ } else if ( (*p) >= 65 )
1056
+ goto tr63;
1057
+ } else
1058
+ goto tr63;
1059
+ goto st0;
1060
+ tr63:
1061
+ #line 139 "unicorn_http.rl"
1062
+ {MARK(mark, p); }
1063
+ goto st41;
1064
+ st41:
1065
+ if ( ++p == pe )
1066
+ goto _test_eof41;
1067
+ case 41:
1068
+ #line 1069 "unicorn_http.c"
1069
+ switch( (*p) ) {
1070
+ case 47: goto tr65;
1071
+ case 58: goto st42;
1072
+ case 95: goto st41;
1073
+ }
1074
+ if ( (*p) < 65 ) {
1075
+ if ( 45 <= (*p) && (*p) <= 57 )
1076
+ goto st41;
1077
+ } else if ( (*p) > 90 ) {
1078
+ if ( 97 <= (*p) && (*p) <= 122 )
1079
+ goto st41;
1080
+ } else
1081
+ goto st41;
1082
+ goto st0;
1083
+ st42:
1084
+ if ( ++p == pe )
1085
+ goto _test_eof42;
1086
+ case 42:
1087
+ if ( (*p) == 47 )
1088
+ goto tr65;
1089
+ if ( 48 <= (*p) && (*p) <= 57 )
1090
+ goto st42;
1091
+ goto st0;
1092
+ tr60:
1093
+ #line 143 "unicorn_http.rl"
1094
+ { downcase_char((char *)p); }
1095
+ goto st43;
1096
+ st43:
1097
+ if ( ++p == pe )
1098
+ goto _test_eof43;
1099
+ case 43:
1100
+ #line 1101 "unicorn_http.c"
1101
+ if ( (*p) == 58 )
1102
+ goto tr59;
1103
+ goto st0;
1104
+ st44:
1105
+ if ( ++p == pe )
1106
+ goto _test_eof44;
1107
+ case 44:
1108
+ switch( (*p) ) {
1109
+ case 32: goto tr2;
1110
+ case 36: goto st45;
1111
+ case 95: goto st45;
1112
+ }
1113
+ if ( (*p) < 48 ) {
1114
+ if ( 45 <= (*p) && (*p) <= 46 )
1115
+ goto st45;
1116
+ } else if ( (*p) > 57 ) {
1117
+ if ( 65 <= (*p) && (*p) <= 90 )
1118
+ goto st45;
1119
+ } else
1120
+ goto st45;
1121
+ goto st0;
1122
+ st45:
1123
+ if ( ++p == pe )
1124
+ goto _test_eof45;
1125
+ case 45:
1126
+ switch( (*p) ) {
1127
+ case 32: goto tr2;
1128
+ case 36: goto st46;
1129
+ case 95: goto st46;
1130
+ }
1131
+ if ( (*p) < 48 ) {
1132
+ if ( 45 <= (*p) && (*p) <= 46 )
1133
+ goto st46;
1134
+ } else if ( (*p) > 57 ) {
1135
+ if ( 65 <= (*p) && (*p) <= 90 )
1136
+ goto st46;
1137
+ } else
1138
+ goto st46;
1139
+ goto st0;
1140
+ st46:
1141
+ if ( ++p == pe )
1142
+ goto _test_eof46;
1143
+ case 46:
1144
+ switch( (*p) ) {
1145
+ case 32: goto tr2;
1146
+ case 36: goto st47;
1147
+ case 95: goto st47;
1148
+ }
1149
+ if ( (*p) < 48 ) {
1150
+ if ( 45 <= (*p) && (*p) <= 46 )
1151
+ goto st47;
1152
+ } else if ( (*p) > 57 ) {
1153
+ if ( 65 <= (*p) && (*p) <= 90 )
1154
+ goto st47;
1155
+ } else
1156
+ goto st47;
1157
+ goto st0;
1158
+ st47:
1159
+ if ( ++p == pe )
1160
+ goto _test_eof47;
1161
+ case 47:
1162
+ switch( (*p) ) {
1163
+ case 32: goto tr2;
1164
+ case 36: goto st48;
1165
+ case 95: goto st48;
1166
+ }
1167
+ if ( (*p) < 48 ) {
1168
+ if ( 45 <= (*p) && (*p) <= 46 )
1169
+ goto st48;
1170
+ } else if ( (*p) > 57 ) {
1171
+ if ( 65 <= (*p) && (*p) <= 90 )
1172
+ goto st48;
1173
+ } else
1174
+ goto st48;
1175
+ goto st0;
1176
+ st48:
1177
+ if ( ++p == pe )
1178
+ goto _test_eof48;
1179
+ case 48:
1180
+ switch( (*p) ) {
1181
+ case 32: goto tr2;
1182
+ case 36: goto st49;
1183
+ case 95: goto st49;
1184
+ }
1185
+ if ( (*p) < 48 ) {
1186
+ if ( 45 <= (*p) && (*p) <= 46 )
1187
+ goto st49;
1188
+ } else if ( (*p) > 57 ) {
1189
+ if ( 65 <= (*p) && (*p) <= 90 )
1190
+ goto st49;
1191
+ } else
1192
+ goto st49;
1193
+ goto st0;
1194
+ st49:
1195
+ if ( ++p == pe )
1196
+ goto _test_eof49;
1197
+ case 49:
1198
+ switch( (*p) ) {
1199
+ case 32: goto tr2;
1200
+ case 36: goto st50;
1201
+ case 95: goto st50;
1202
+ }
1203
+ if ( (*p) < 48 ) {
1204
+ if ( 45 <= (*p) && (*p) <= 46 )
1205
+ goto st50;
1206
+ } else if ( (*p) > 57 ) {
1207
+ if ( 65 <= (*p) && (*p) <= 90 )
1208
+ goto st50;
1209
+ } else
1210
+ goto st50;
1211
+ goto st0;
1212
+ st50:
1213
+ if ( ++p == pe )
1214
+ goto _test_eof50;
1215
+ case 50:
1216
+ switch( (*p) ) {
1217
+ case 32: goto tr2;
1218
+ case 36: goto st51;
1219
+ case 95: goto st51;
1220
+ }
1221
+ if ( (*p) < 48 ) {
1222
+ if ( 45 <= (*p) && (*p) <= 46 )
1223
+ goto st51;
1224
+ } else if ( (*p) > 57 ) {
1225
+ if ( 65 <= (*p) && (*p) <= 90 )
1226
+ goto st51;
1227
+ } else
1228
+ goto st51;
1229
+ goto st0;
1230
+ st51:
1231
+ if ( ++p == pe )
1232
+ goto _test_eof51;
1233
+ case 51:
1234
+ switch( (*p) ) {
1235
+ case 32: goto tr2;
1236
+ case 36: goto st52;
1237
+ case 95: goto st52;
1238
+ }
1239
+ if ( (*p) < 48 ) {
1240
+ if ( 45 <= (*p) && (*p) <= 46 )
1241
+ goto st52;
1242
+ } else if ( (*p) > 57 ) {
1243
+ if ( 65 <= (*p) && (*p) <= 90 )
1244
+ goto st52;
1245
+ } else
1246
+ goto st52;
1247
+ goto st0;
1248
+ st52:
1249
+ if ( ++p == pe )
1250
+ goto _test_eof52;
1251
+ case 52:
1252
+ switch( (*p) ) {
1253
+ case 32: goto tr2;
1254
+ case 36: goto st53;
1255
+ case 95: goto st53;
1256
+ }
1257
+ if ( (*p) < 48 ) {
1258
+ if ( 45 <= (*p) && (*p) <= 46 )
1259
+ goto st53;
1260
+ } else if ( (*p) > 57 ) {
1261
+ if ( 65 <= (*p) && (*p) <= 90 )
1262
+ goto st53;
1263
+ } else
1264
+ goto st53;
1265
+ goto st0;
1266
+ st53:
1267
+ if ( ++p == pe )
1268
+ goto _test_eof53;
1269
+ case 53:
1270
+ switch( (*p) ) {
1271
+ case 32: goto tr2;
1272
+ case 36: goto st54;
1273
+ case 95: goto st54;
1274
+ }
1275
+ if ( (*p) < 48 ) {
1276
+ if ( 45 <= (*p) && (*p) <= 46 )
1277
+ goto st54;
1278
+ } else if ( (*p) > 57 ) {
1279
+ if ( 65 <= (*p) && (*p) <= 90 )
1280
+ goto st54;
1281
+ } else
1282
+ goto st54;
1283
+ goto st0;
1284
+ st54:
1285
+ if ( ++p == pe )
1286
+ goto _test_eof54;
1287
+ case 54:
1288
+ switch( (*p) ) {
1289
+ case 32: goto tr2;
1290
+ case 36: goto st55;
1291
+ case 95: goto st55;
1292
+ }
1293
+ if ( (*p) < 48 ) {
1294
+ if ( 45 <= (*p) && (*p) <= 46 )
1295
+ goto st55;
1296
+ } else if ( (*p) > 57 ) {
1297
+ if ( 65 <= (*p) && (*p) <= 90 )
1298
+ goto st55;
1299
+ } else
1300
+ goto st55;
1301
+ goto st0;
1302
+ st55:
1303
+ if ( ++p == pe )
1304
+ goto _test_eof55;
1305
+ case 55:
1306
+ switch( (*p) ) {
1307
+ case 32: goto tr2;
1308
+ case 36: goto st56;
1309
+ case 95: goto st56;
1310
+ }
1311
+ if ( (*p) < 48 ) {
1312
+ if ( 45 <= (*p) && (*p) <= 46 )
1313
+ goto st56;
1314
+ } else if ( (*p) > 57 ) {
1315
+ if ( 65 <= (*p) && (*p) <= 90 )
1316
+ goto st56;
1317
+ } else
1318
+ goto st56;
1319
+ goto st0;
1320
+ st56:
1321
+ if ( ++p == pe )
1322
+ goto _test_eof56;
1323
+ case 56:
1324
+ switch( (*p) ) {
1325
+ case 32: goto tr2;
1326
+ case 36: goto st57;
1327
+ case 95: goto st57;
1328
+ }
1329
+ if ( (*p) < 48 ) {
1330
+ if ( 45 <= (*p) && (*p) <= 46 )
1331
+ goto st57;
1332
+ } else if ( (*p) > 57 ) {
1333
+ if ( 65 <= (*p) && (*p) <= 90 )
1334
+ goto st57;
1335
+ } else
1336
+ goto st57;
1337
+ goto st0;
1338
+ st57:
1339
+ if ( ++p == pe )
1340
+ goto _test_eof57;
1341
+ case 57:
1342
+ switch( (*p) ) {
1343
+ case 32: goto tr2;
1344
+ case 36: goto st58;
1345
+ case 95: goto st58;
1346
+ }
1347
+ if ( (*p) < 48 ) {
1348
+ if ( 45 <= (*p) && (*p) <= 46 )
1349
+ goto st58;
1350
+ } else if ( (*p) > 57 ) {
1351
+ if ( 65 <= (*p) && (*p) <= 90 )
1352
+ goto st58;
1353
+ } else
1354
+ goto st58;
1355
+ goto st0;
1356
+ st58:
1357
+ if ( ++p == pe )
1358
+ goto _test_eof58;
1359
+ case 58:
1360
+ switch( (*p) ) {
1361
+ case 32: goto tr2;
1362
+ case 36: goto st59;
1363
+ case 95: goto st59;
1364
+ }
1365
+ if ( (*p) < 48 ) {
1366
+ if ( 45 <= (*p) && (*p) <= 46 )
1367
+ goto st59;
1368
+ } else if ( (*p) > 57 ) {
1369
+ if ( 65 <= (*p) && (*p) <= 90 )
1370
+ goto st59;
1371
+ } else
1372
+ goto st59;
1373
+ goto st0;
1374
+ st59:
1375
+ if ( ++p == pe )
1376
+ goto _test_eof59;
1377
+ case 59:
1378
+ switch( (*p) ) {
1379
+ case 32: goto tr2;
1380
+ case 36: goto st60;
1381
+ case 95: goto st60;
1382
+ }
1383
+ if ( (*p) < 48 ) {
1384
+ if ( 45 <= (*p) && (*p) <= 46 )
1385
+ goto st60;
1386
+ } else if ( (*p) > 57 ) {
1387
+ if ( 65 <= (*p) && (*p) <= 90 )
1388
+ goto st60;
1389
+ } else
1390
+ goto st60;
1391
+ goto st0;
1392
+ st60:
1393
+ if ( ++p == pe )
1394
+ goto _test_eof60;
1395
+ case 60:
1396
+ switch( (*p) ) {
1397
+ case 32: goto tr2;
1398
+ case 36: goto st61;
1399
+ case 95: goto st61;
1400
+ }
1401
+ if ( (*p) < 48 ) {
1402
+ if ( 45 <= (*p) && (*p) <= 46 )
1403
+ goto st61;
1404
+ } else if ( (*p) > 57 ) {
1405
+ if ( 65 <= (*p) && (*p) <= 90 )
1406
+ goto st61;
1407
+ } else
1408
+ goto st61;
1409
+ goto st0;
1410
+ st61:
1411
+ if ( ++p == pe )
1412
+ goto _test_eof61;
1413
+ case 61:
1414
+ switch( (*p) ) {
1415
+ case 32: goto tr2;
1416
+ case 36: goto st62;
1417
+ case 95: goto st62;
1418
+ }
1419
+ if ( (*p) < 48 ) {
1420
+ if ( 45 <= (*p) && (*p) <= 46 )
1421
+ goto st62;
1422
+ } else if ( (*p) > 57 ) {
1423
+ if ( 65 <= (*p) && (*p) <= 90 )
1424
+ goto st62;
1425
+ } else
1426
+ goto st62;
1427
+ goto st0;
1428
+ st62:
1429
+ if ( ++p == pe )
1430
+ goto _test_eof62;
1431
+ case 62:
1432
+ if ( (*p) == 32 )
1433
+ goto tr2;
1434
+ goto st0;
1435
+ st63:
1436
+ if ( ++p == pe )
1437
+ goto _test_eof63;
1438
+ case 63:
1439
+ if ( (*p) == 48 )
1440
+ goto tr85;
1441
+ if ( (*p) < 65 ) {
1442
+ if ( 49 <= (*p) && (*p) <= 57 )
1443
+ goto tr86;
1444
+ } else if ( (*p) > 70 ) {
1445
+ if ( 97 <= (*p) && (*p) <= 102 )
1446
+ goto tr86;
1447
+ } else
1448
+ goto tr86;
1449
+ goto st0;
1450
+ tr85:
1451
+ #line 193 "unicorn_http.rl"
1452
+ {
1453
+ hp->len.chunk = step_incr(hp->len.chunk, (*p), 16);
1454
+ if (hp->len.chunk < 0)
1455
+ rb_raise(eHttpParserError, "invalid chunk size");
1456
+ }
1457
+ goto st64;
1458
+ st64:
1459
+ if ( ++p == pe )
1460
+ goto _test_eof64;
1461
+ case 64:
1462
+ #line 1463 "unicorn_http.c"
1463
+ switch( (*p) ) {
1464
+ case 13: goto st65;
1465
+ case 48: goto tr85;
1466
+ case 59: goto st74;
1467
+ }
1468
+ if ( (*p) < 65 ) {
1469
+ if ( 49 <= (*p) && (*p) <= 57 )
1470
+ goto tr86;
1471
+ } else if ( (*p) > 70 ) {
1472
+ if ( 97 <= (*p) && (*p) <= 102 )
1473
+ goto tr86;
1474
+ } else
1475
+ goto tr86;
1476
+ goto st0;
1477
+ st65:
1478
+ if ( ++p == pe )
1479
+ goto _test_eof65;
1480
+ case 65:
1481
+ if ( (*p) == 10 )
1482
+ goto tr89;
1483
+ goto st0;
1484
+ tr89:
1485
+ #line 221 "unicorn_http.rl"
1486
+ {
1487
+ if (hp->flags & UH_FL_HASTRAILER) {
1488
+ hp->flags |= UH_FL_INTRAILER;
1489
+ cs = http_parser_en_Trailers;
1490
+ } else {
1491
+ cs = http_parser_first_final;
1492
+ }
1493
+ ++p;
1494
+ goto post_exec;
1495
+ }
1496
+ goto st84;
1497
+ st84:
1498
+ if ( ++p == pe )
1499
+ goto _test_eof84;
1500
+ case 84:
1501
+ #line 1502 "unicorn_http.c"
1502
+ goto st0;
1503
+ tr86:
1504
+ #line 193 "unicorn_http.rl"
1505
+ {
1506
+ hp->len.chunk = step_incr(hp->len.chunk, (*p), 16);
1507
+ if (hp->len.chunk < 0)
1508
+ rb_raise(eHttpParserError, "invalid chunk size");
1509
+ }
1510
+ goto st66;
1511
+ st66:
1512
+ if ( ++p == pe )
1513
+ goto _test_eof66;
1514
+ case 66:
1515
+ #line 1516 "unicorn_http.c"
1516
+ switch( (*p) ) {
1517
+ case 13: goto st67;
1518
+ case 59: goto st71;
1519
+ }
1520
+ if ( (*p) < 65 ) {
1521
+ if ( 48 <= (*p) && (*p) <= 57 )
1522
+ goto tr86;
1523
+ } else if ( (*p) > 70 ) {
1524
+ if ( 97 <= (*p) && (*p) <= 102 )
1525
+ goto tr86;
1526
+ } else
1527
+ goto tr86;
1528
+ goto st0;
1529
+ st67:
1530
+ if ( ++p == pe )
1531
+ goto _test_eof67;
1532
+ case 67:
1533
+ if ( (*p) == 10 )
1534
+ goto st68;
1535
+ goto st0;
1536
+ st68:
1537
+ if ( ++p == pe )
1538
+ goto _test_eof68;
1539
+ case 68:
1540
+ goto tr93;
1541
+ tr93:
1542
+ #line 232 "unicorn_http.rl"
1543
+ {
1544
+ skip_chunk_data_hack: {
1545
+ size_t nr = MIN(hp->len.chunk, REMAINING);
1546
+ memcpy(RSTRING_PTR(req) + hp->s.dest_offset, p, nr);
1547
+ hp->s.dest_offset += nr;
1548
+ hp->len.chunk -= nr;
1549
+ p += nr;
1550
+ assert(hp->len.chunk >= 0);
1551
+ if (hp->len.chunk > REMAINING) {
1552
+ hp->flags |= UH_FL_INCHUNK;
1553
+ goto post_exec;
1554
+ } else {
1555
+ p--;
1556
+ {goto st69;}
1557
+ }
1558
+ }}
1559
+ goto st69;
1560
+ st69:
1561
+ if ( ++p == pe )
1562
+ goto _test_eof69;
1563
+ case 69:
1564
+ #line 1565 "unicorn_http.c"
1565
+ if ( (*p) == 13 )
1566
+ goto st70;
1567
+ goto st0;
1568
+ st70:
1569
+ if ( ++p == pe )
1570
+ goto _test_eof70;
1571
+ case 70:
1572
+ if ( (*p) == 10 )
1573
+ goto st63;
1574
+ goto st0;
1575
+ st71:
1576
+ if ( ++p == pe )
1577
+ goto _test_eof71;
1578
+ case 71:
1579
+ switch( (*p) ) {
1580
+ case 13: goto st67;
1581
+ case 32: goto st71;
1582
+ case 33: goto st72;
1583
+ case 59: goto st71;
1584
+ case 61: goto st73;
1585
+ case 124: goto st72;
1586
+ case 126: goto st72;
1587
+ }
1588
+ if ( (*p) < 45 ) {
1589
+ if ( (*p) > 39 ) {
1590
+ if ( 42 <= (*p) && (*p) <= 43 )
1591
+ goto st72;
1592
+ } else if ( (*p) >= 35 )
1593
+ goto st72;
1594
+ } else if ( (*p) > 46 ) {
1595
+ if ( (*p) < 65 ) {
1596
+ if ( 48 <= (*p) && (*p) <= 57 )
1597
+ goto st72;
1598
+ } else if ( (*p) > 90 ) {
1599
+ if ( 94 <= (*p) && (*p) <= 122 )
1600
+ goto st72;
1601
+ } else
1602
+ goto st72;
1603
+ } else
1604
+ goto st72;
1605
+ goto st0;
1606
+ st72:
1607
+ if ( ++p == pe )
1608
+ goto _test_eof72;
1609
+ case 72:
1610
+ switch( (*p) ) {
1611
+ case 13: goto st67;
1612
+ case 33: goto st72;
1613
+ case 59: goto st71;
1614
+ case 61: goto st73;
1615
+ case 124: goto st72;
1616
+ case 126: goto st72;
1617
+ }
1618
+ if ( (*p) < 45 ) {
1619
+ if ( (*p) > 39 ) {
1620
+ if ( 42 <= (*p) && (*p) <= 43 )
1621
+ goto st72;
1622
+ } else if ( (*p) >= 35 )
1623
+ goto st72;
1624
+ } else if ( (*p) > 46 ) {
1625
+ if ( (*p) < 65 ) {
1626
+ if ( 48 <= (*p) && (*p) <= 57 )
1627
+ goto st72;
1628
+ } else if ( (*p) > 90 ) {
1629
+ if ( 94 <= (*p) && (*p) <= 122 )
1630
+ goto st72;
1631
+ } else
1632
+ goto st72;
1633
+ } else
1634
+ goto st72;
1635
+ goto st0;
1636
+ st73:
1637
+ if ( ++p == pe )
1638
+ goto _test_eof73;
1639
+ case 73:
1640
+ switch( (*p) ) {
1641
+ case 13: goto st67;
1642
+ case 33: goto st73;
1643
+ case 59: goto st71;
1644
+ case 124: goto st73;
1645
+ case 126: goto st73;
1646
+ }
1647
+ if ( (*p) < 45 ) {
1648
+ if ( (*p) > 39 ) {
1649
+ if ( 42 <= (*p) && (*p) <= 43 )
1650
+ goto st73;
1651
+ } else if ( (*p) >= 35 )
1652
+ goto st73;
1653
+ } else if ( (*p) > 46 ) {
1654
+ if ( (*p) < 65 ) {
1655
+ if ( 48 <= (*p) && (*p) <= 57 )
1656
+ goto st73;
1657
+ } else if ( (*p) > 90 ) {
1658
+ if ( 94 <= (*p) && (*p) <= 122 )
1659
+ goto st73;
1660
+ } else
1661
+ goto st73;
1662
+ } else
1663
+ goto st73;
1664
+ goto st0;
1665
+ st74:
1666
+ if ( ++p == pe )
1667
+ goto _test_eof74;
1668
+ case 74:
1669
+ switch( (*p) ) {
1670
+ case 13: goto st65;
1671
+ case 32: goto st74;
1672
+ case 33: goto st75;
1673
+ case 59: goto st74;
1674
+ case 61: goto st76;
1675
+ case 124: goto st75;
1676
+ case 126: goto st75;
1677
+ }
1678
+ if ( (*p) < 45 ) {
1679
+ if ( (*p) > 39 ) {
1680
+ if ( 42 <= (*p) && (*p) <= 43 )
1681
+ goto st75;
1682
+ } else if ( (*p) >= 35 )
1683
+ goto st75;
1684
+ } else if ( (*p) > 46 ) {
1685
+ if ( (*p) < 65 ) {
1686
+ if ( 48 <= (*p) && (*p) <= 57 )
1687
+ goto st75;
1688
+ } else if ( (*p) > 90 ) {
1689
+ if ( 94 <= (*p) && (*p) <= 122 )
1690
+ goto st75;
1691
+ } else
1692
+ goto st75;
1693
+ } else
1694
+ goto st75;
1695
+ goto st0;
1696
+ st75:
1697
+ if ( ++p == pe )
1698
+ goto _test_eof75;
1699
+ case 75:
1700
+ switch( (*p) ) {
1701
+ case 13: goto st65;
1702
+ case 33: goto st75;
1703
+ case 59: goto st74;
1704
+ case 61: goto st76;
1705
+ case 124: goto st75;
1706
+ case 126: goto st75;
1707
+ }
1708
+ if ( (*p) < 45 ) {
1709
+ if ( (*p) > 39 ) {
1710
+ if ( 42 <= (*p) && (*p) <= 43 )
1711
+ goto st75;
1712
+ } else if ( (*p) >= 35 )
1713
+ goto st75;
1714
+ } else if ( (*p) > 46 ) {
1715
+ if ( (*p) < 65 ) {
1716
+ if ( 48 <= (*p) && (*p) <= 57 )
1717
+ goto st75;
1718
+ } else if ( (*p) > 90 ) {
1719
+ if ( 94 <= (*p) && (*p) <= 122 )
1720
+ goto st75;
1721
+ } else
1722
+ goto st75;
1723
+ } else
1724
+ goto st75;
1725
+ goto st0;
1726
+ st76:
1727
+ if ( ++p == pe )
1728
+ goto _test_eof76;
1729
+ case 76:
1730
+ switch( (*p) ) {
1731
+ case 13: goto st65;
1732
+ case 33: goto st76;
1733
+ case 59: goto st74;
1734
+ case 124: goto st76;
1735
+ case 126: goto st76;
1736
+ }
1737
+ if ( (*p) < 45 ) {
1738
+ if ( (*p) > 39 ) {
1739
+ if ( 42 <= (*p) && (*p) <= 43 )
1740
+ goto st76;
1741
+ } else if ( (*p) >= 35 )
1742
+ goto st76;
1743
+ } else if ( (*p) > 46 ) {
1744
+ if ( (*p) < 65 ) {
1745
+ if ( 48 <= (*p) && (*p) <= 57 )
1746
+ goto st76;
1747
+ } else if ( (*p) > 90 ) {
1748
+ if ( 94 <= (*p) && (*p) <= 122 )
1749
+ goto st76;
1750
+ } else
1751
+ goto st76;
1752
+ } else
1753
+ goto st76;
1754
+ goto st0;
1755
+ st77:
1756
+ if ( ++p == pe )
1757
+ goto _test_eof77;
1758
+ case 77:
1759
+ switch( (*p) ) {
1760
+ case 13: goto st78;
1761
+ case 33: goto tr101;
1762
+ case 124: goto tr101;
1763
+ case 126: goto tr101;
1764
+ }
1765
+ if ( (*p) < 45 ) {
1766
+ if ( (*p) > 39 ) {
1767
+ if ( 42 <= (*p) && (*p) <= 43 )
1768
+ goto tr101;
1769
+ } else if ( (*p) >= 35 )
1770
+ goto tr101;
1771
+ } else if ( (*p) > 46 ) {
1772
+ if ( (*p) < 65 ) {
1773
+ if ( 48 <= (*p) && (*p) <= 57 )
1774
+ goto tr101;
1775
+ } else if ( (*p) > 90 ) {
1776
+ if ( 94 <= (*p) && (*p) <= 122 )
1777
+ goto tr101;
1778
+ } else
1779
+ goto tr101;
1780
+ } else
1781
+ goto tr101;
1782
+ goto st0;
1783
+ st78:
1784
+ if ( ++p == pe )
1785
+ goto _test_eof78;
1786
+ case 78:
1787
+ if ( (*p) == 10 )
1788
+ goto tr102;
1789
+ goto st0;
1790
+ tr102:
1791
+ #line 216 "unicorn_http.rl"
1792
+ {
1793
+ cs = http_parser_first_final;
1794
+ goto post_exec;
1795
+ }
1796
+ goto st85;
1797
+ st85:
1798
+ if ( ++p == pe )
1799
+ goto _test_eof85;
1800
+ case 85:
1801
+ #line 1802 "unicorn_http.c"
1802
+ goto st0;
1803
+ tr101:
1804
+ #line 141 "unicorn_http.rl"
1805
+ { MARK(start.field, p); }
1806
+ #line 142 "unicorn_http.rl"
1807
+ { snake_upcase_char((char *)p); }
1808
+ goto st79;
1809
+ tr103:
1810
+ #line 142 "unicorn_http.rl"
1811
+ { snake_upcase_char((char *)p); }
1812
+ goto st79;
1813
+ st79:
1814
+ if ( ++p == pe )
1815
+ goto _test_eof79;
1816
+ case 79:
1817
+ #line 1818 "unicorn_http.c"
1818
+ switch( (*p) ) {
1819
+ case 33: goto tr103;
1820
+ case 58: goto tr104;
1821
+ case 124: goto tr103;
1822
+ case 126: goto tr103;
1823
+ }
1824
+ if ( (*p) < 45 ) {
1825
+ if ( (*p) > 39 ) {
1826
+ if ( 42 <= (*p) && (*p) <= 43 )
1827
+ goto tr103;
1828
+ } else if ( (*p) >= 35 )
1829
+ goto tr103;
1830
+ } else if ( (*p) > 46 ) {
1831
+ if ( (*p) < 65 ) {
1832
+ if ( 48 <= (*p) && (*p) <= 57 )
1833
+ goto tr103;
1834
+ } else if ( (*p) > 90 ) {
1835
+ if ( 94 <= (*p) && (*p) <= 122 )
1836
+ goto tr103;
1837
+ } else
1838
+ goto tr103;
1839
+ } else
1840
+ goto tr103;
1841
+ goto st0;
1842
+ tr104:
1843
+ #line 144 "unicorn_http.rl"
1844
+ { hp->s.field_len = LEN(start.field, p); }
1845
+ goto st80;
1846
+ tr107:
1847
+ #line 145 "unicorn_http.rl"
1848
+ { MARK(mark, p); }
1849
+ goto st80;
1850
+ st80:
1851
+ if ( ++p == pe )
1852
+ goto _test_eof80;
1853
+ case 80:
1854
+ #line 1855 "unicorn_http.c"
1855
+ switch( (*p) ) {
1856
+ case 13: goto tr106;
1857
+ case 32: goto tr107;
1858
+ }
1859
+ goto tr105;
1860
+ tr105:
1861
+ #line 145 "unicorn_http.rl"
1862
+ { MARK(mark, p); }
1863
+ goto st81;
1864
+ st81:
1865
+ if ( ++p == pe )
1866
+ goto _test_eof81;
1867
+ case 81:
1868
+ #line 1869 "unicorn_http.c"
1869
+ if ( (*p) == 13 )
1870
+ goto tr109;
1871
+ goto st81;
1872
+ tr106:
1873
+ #line 145 "unicorn_http.rl"
1874
+ { MARK(mark, p); }
1875
+ #line 146 "unicorn_http.rl"
1876
+ { write_value(req, hp, buffer, p); }
1877
+ goto st82;
1878
+ tr109:
1879
+ #line 146 "unicorn_http.rl"
1880
+ { write_value(req, hp, buffer, p); }
1881
+ goto st82;
1882
+ st82:
1883
+ if ( ++p == pe )
1884
+ goto _test_eof82;
1885
+ case 82:
1886
+ #line 1887 "unicorn_http.c"
1887
+ if ( (*p) == 10 )
1888
+ goto st77;
1889
+ goto st0;
1890
+ }
1891
+ _test_eof2: cs = 2; goto _test_eof;
1892
+ _test_eof3: cs = 3; goto _test_eof;
1893
+ _test_eof4: cs = 4; goto _test_eof;
1894
+ _test_eof5: cs = 5; goto _test_eof;
1895
+ _test_eof6: cs = 6; goto _test_eof;
1896
+ _test_eof7: cs = 7; goto _test_eof;
1897
+ _test_eof8: cs = 8; goto _test_eof;
1898
+ _test_eof9: cs = 9; goto _test_eof;
1899
+ _test_eof10: cs = 10; goto _test_eof;
1900
+ _test_eof11: cs = 11; goto _test_eof;
1901
+ _test_eof12: cs = 12; goto _test_eof;
1902
+ _test_eof13: cs = 13; goto _test_eof;
1903
+ _test_eof14: cs = 14; goto _test_eof;
1904
+ _test_eof15: cs = 15; goto _test_eof;
1905
+ _test_eof16: cs = 16; goto _test_eof;
1906
+ _test_eof83: cs = 83; goto _test_eof;
1907
+ _test_eof17: cs = 17; goto _test_eof;
1908
+ _test_eof18: cs = 18; goto _test_eof;
1909
+ _test_eof19: cs = 19; goto _test_eof;
1910
+ _test_eof20: cs = 20; goto _test_eof;
1911
+ _test_eof21: cs = 21; goto _test_eof;
1912
+ _test_eof22: cs = 22; goto _test_eof;
1913
+ _test_eof23: cs = 23; goto _test_eof;
1914
+ _test_eof24: cs = 24; goto _test_eof;
1915
+ _test_eof25: cs = 25; goto _test_eof;
1916
+ _test_eof26: cs = 26; goto _test_eof;
1917
+ _test_eof27: cs = 27; goto _test_eof;
1918
+ _test_eof28: cs = 28; goto _test_eof;
1919
+ _test_eof29: cs = 29; goto _test_eof;
1920
+ _test_eof30: cs = 30; goto _test_eof;
1921
+ _test_eof31: cs = 31; goto _test_eof;
1922
+ _test_eof32: cs = 32; goto _test_eof;
1923
+ _test_eof33: cs = 33; goto _test_eof;
1924
+ _test_eof34: cs = 34; goto _test_eof;
1925
+ _test_eof35: cs = 35; goto _test_eof;
1926
+ _test_eof36: cs = 36; goto _test_eof;
1927
+ _test_eof37: cs = 37; goto _test_eof;
1928
+ _test_eof38: cs = 38; goto _test_eof;
1929
+ _test_eof39: cs = 39; goto _test_eof;
1930
+ _test_eof40: cs = 40; goto _test_eof;
1931
+ _test_eof41: cs = 41; goto _test_eof;
1932
+ _test_eof42: cs = 42; goto _test_eof;
1933
+ _test_eof43: cs = 43; goto _test_eof;
1934
+ _test_eof44: cs = 44; goto _test_eof;
1935
+ _test_eof45: cs = 45; goto _test_eof;
1936
+ _test_eof46: cs = 46; goto _test_eof;
1937
+ _test_eof47: cs = 47; goto _test_eof;
1938
+ _test_eof48: cs = 48; goto _test_eof;
1939
+ _test_eof49: cs = 49; goto _test_eof;
1940
+ _test_eof50: cs = 50; goto _test_eof;
1941
+ _test_eof51: cs = 51; goto _test_eof;
1942
+ _test_eof52: cs = 52; goto _test_eof;
1943
+ _test_eof53: cs = 53; goto _test_eof;
1944
+ _test_eof54: cs = 54; goto _test_eof;
1945
+ _test_eof55: cs = 55; goto _test_eof;
1946
+ _test_eof56: cs = 56; goto _test_eof;
1947
+ _test_eof57: cs = 57; goto _test_eof;
1948
+ _test_eof58: cs = 58; goto _test_eof;
1949
+ _test_eof59: cs = 59; goto _test_eof;
1950
+ _test_eof60: cs = 60; goto _test_eof;
1951
+ _test_eof61: cs = 61; goto _test_eof;
1952
+ _test_eof62: cs = 62; goto _test_eof;
1953
+ _test_eof63: cs = 63; goto _test_eof;
1954
+ _test_eof64: cs = 64; goto _test_eof;
1955
+ _test_eof65: cs = 65; goto _test_eof;
1956
+ _test_eof84: cs = 84; goto _test_eof;
1957
+ _test_eof66: cs = 66; goto _test_eof;
1958
+ _test_eof67: cs = 67; goto _test_eof;
1959
+ _test_eof68: cs = 68; goto _test_eof;
1960
+ _test_eof69: cs = 69; goto _test_eof;
1961
+ _test_eof70: cs = 70; goto _test_eof;
1962
+ _test_eof71: cs = 71; goto _test_eof;
1963
+ _test_eof72: cs = 72; goto _test_eof;
1964
+ _test_eof73: cs = 73; goto _test_eof;
1965
+ _test_eof74: cs = 74; goto _test_eof;
1966
+ _test_eof75: cs = 75; goto _test_eof;
1967
+ _test_eof76: cs = 76; goto _test_eof;
1968
+ _test_eof77: cs = 77; goto _test_eof;
1969
+ _test_eof78: cs = 78; goto _test_eof;
1970
+ _test_eof85: cs = 85; goto _test_eof;
1971
+ _test_eof79: cs = 79; goto _test_eof;
1972
+ _test_eof80: cs = 80; goto _test_eof;
1973
+ _test_eof81: cs = 81; goto _test_eof;
1974
+ _test_eof82: cs = 82; goto _test_eof;
1975
+
1976
+ _test_eof: {}
1977
+ _out: {}
1978
+ }
1979
+
1980
+ #line 286 "unicorn_http.rl"
1981
+ post_exec: /* "_out:" also goes here */
1982
+ if (hp->cs != http_parser_error)
1983
+ hp->cs = cs;
1984
+ hp->start.offset = p - buffer;
1985
+
1986
+ assert(p <= pe && "buffer overflow after parsing execute");
1987
+ assert(hp->start.offset <= len && "start.offset longer than length");
278
1988
  }
279
1989
 
280
- static void http_version(void *data, const char *at, size_t length)
1990
+ static struct http_parser *data_get(VALUE self)
281
1991
  {
282
- VALUE req = (VALUE)data;
283
- VALUE val = rb_str_new(at, length);
284
- rb_hash_aset(req, global_http_version, val);
1992
+ struct http_parser *hp;
1993
+
1994
+ Data_Get_Struct(self, struct http_parser, hp);
1995
+ assert(hp);
1996
+ return hp;
285
1997
  }
286
1998
 
287
- /** Finalizes the request header to have a bunch of stuff that's needed. */
288
- static void header_done(void *data, const char *at, size_t length)
1999
+ static void finalize_header(VALUE req)
289
2000
  {
290
- VALUE req = (VALUE)data;
291
- VALUE server_name = global_localhost;
292
- VALUE server_port = global_port_80;
293
- VALUE temp;
294
-
295
- /* rack requires QUERY_STRING */
296
- if (rb_hash_aref(req, global_query_string) == Qnil)
297
- rb_hash_aset(req, global_query_string, rb_str_new(NULL, 0));
2001
+ VALUE temp = rb_hash_aref(req, g_rack_url_scheme);
2002
+ VALUE server_name = g_localhost;
2003
+ VALUE server_port = g_port_80;
298
2004
 
299
2005
  /* set rack.url_scheme to "https" or "http", no others are allowed by Rack */
300
- if ((temp = rb_hash_aref(req, global_rack_url_scheme)) == Qnil) {
301
- if ((temp = rb_hash_aref(req, global_http_x_forwarded_proto)) != Qnil &&
302
- RSTRING_LEN(temp) == 5 &&
303
- !memcmp("https", RSTRING_PTR(temp), 5))
304
- server_port = global_port_443;
2006
+ if (temp == Qnil) {
2007
+ temp = rb_hash_aref(req, g_http_x_forwarded_proto);
2008
+ if (temp != Qnil && STR_CSTR_EQ(temp, "https"))
2009
+ server_port = g_port_443;
305
2010
  else
306
- temp = global_http;
307
- rb_hash_aset(req, global_rack_url_scheme, temp);
308
- } else if (RSTRING_LEN(temp) == 5 && !memcmp("https", RSTRING_PTR(temp), 5)) {
309
- server_port = global_port_443;
2011
+ temp = g_http;
2012
+ rb_hash_aset(req, g_rack_url_scheme, temp);
2013
+ } else if (STR_CSTR_EQ(temp, "https")) {
2014
+ server_port = g_port_443;
310
2015
  }
311
2016
 
312
2017
  /* parse and set the SERVER_NAME and SERVER_PORT variables */
313
- if ((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
2018
+ temp = rb_hash_aref(req, g_http_host);
2019
+ if (temp != Qnil) {
314
2020
  char *colon = memchr(RSTRING_PTR(temp), ':', RSTRING_LEN(temp));
315
2021
  if (colon) {
316
2022
  long port_start = colon - RSTRING_PTR(temp) + 1;
@@ -322,40 +2028,19 @@ static void header_done(void *data, const char *at, size_t length)
322
2028
  server_name = temp;
323
2029
  }
324
2030
  }
325
- rb_hash_aset(req, global_server_name, server_name);
326
- rb_hash_aset(req, global_server_port, server_port);
327
- rb_hash_aset(req, global_server_protocol, global_server_protocol_value);
328
-
329
- /* grab the initial body and stuff it into the hash */
330
- temp = rb_hash_aref(req, global_request_method);
331
- if (temp != Qnil) {
332
- long len = RSTRING_LEN(temp);
333
- char *ptr = RSTRING_PTR(temp);
334
-
335
- if (memcmp(ptr, "HEAD", len) && memcmp(ptr, "GET", len))
336
- rb_hash_aset(req, sym_http_body, rb_str_new(at, length));
337
- }
338
- }
2031
+ rb_hash_aset(req, g_server_name, server_name);
2032
+ rb_hash_aset(req, g_server_port, server_port);
2033
+ rb_hash_aset(req, g_server_protocol, g_http_11);
339
2034
 
340
- static void HttpParser_free(void *data) {
341
- TRACE();
342
-
343
- if(data) {
344
- free(data);
345
- }
2035
+ /* rack requires QUERY_STRING */
2036
+ if (rb_hash_aref(req, g_query_string) == Qnil)
2037
+ rb_hash_aset(req, g_query_string, rb_str_new(NULL, 0));
346
2038
  }
347
2039
 
348
-
349
2040
  static VALUE HttpParser_alloc(VALUE klass)
350
2041
  {
351
- VALUE obj;
352
- http_parser *hp = ALLOC_N(http_parser, 1);
353
- TRACE();
354
- http_parser_init(hp);
355
-
356
- obj = Data_Wrap_Struct(klass, NULL, HttpParser_free, hp);
357
-
358
- return obj;
2042
+ struct http_parser *hp;
2043
+ return Data_Make_Struct(klass, struct http_parser, NULL, NULL, hp);
359
2044
  }
360
2045
 
361
2046
 
@@ -387,71 +2072,183 @@ static VALUE HttpParser_reset(VALUE self)
387
2072
  return Qnil;
388
2073
  }
389
2074
 
2075
+ static void advance_str(VALUE str, off_t nr)
2076
+ {
2077
+ long len = RSTRING_LEN(str);
2078
+
2079
+ if (len == 0)
2080
+ return;
2081
+
2082
+ assert(nr <= len);
2083
+ len -= nr;
2084
+ if (len > 0) /* unlikely, len is usually 0 */
2085
+ memmove(RSTRING_PTR(str), RSTRING_PTR(str) + nr, len);
2086
+ rb_str_set_len(str, len);
2087
+ }
2088
+
2089
+ static VALUE HttpParser_content_length(VALUE self)
2090
+ {
2091
+ struct http_parser *hp = data_get(self);
2092
+
2093
+ return (hp->flags & UH_FL_CHUNKED) ? Qnil : OFFT2NUM(hp->len.content);
2094
+ }
390
2095
 
391
2096
  /**
392
2097
  * call-seq:
393
- * parser.execute(req_hash, data) -> true/false
2098
+ * parser.headers(req, data) -> req or nil
2099
+ * parser.trailers(req, data) -> req or nil
394
2100
  *
395
2101
  * Takes a Hash and a String of data, parses the String of data filling
396
- * in the Hash returning a boolean to indicate whether or not parsing
397
- * is finished.
398
- *
399
- * This function now throws an exception when there is a parsing error.
400
- * This makes the logic for working with the parser much easier. You
401
- * will need to wrap the parser with an exception handling block.
2102
+ * in the Hash returning the Hash if parsing is finished, nil otherwise
2103
+ * When returning the req Hash, it may modify data to point to where
2104
+ * body processing should begin
2105
+ *
2106
+ * Raises HttpParserError if there are parsing errors
402
2107
  */
2108
+ static VALUE HttpParser_headers(VALUE self, VALUE req, VALUE data)
2109
+ {
2110
+ struct http_parser *hp = data_get(self);
2111
+
2112
+ http_parser_execute(hp, req, RSTRING_PTR(data), RSTRING_LEN(data));
2113
+ VALIDATE_MAX_LENGTH(hp->start.offset, HEADER);
2114
+
2115
+ if (hp->cs == http_parser_first_final ||
2116
+ hp->cs == http_parser_en_ChunkedBody) {
2117
+ advance_str(data, hp->start.offset + 1);
2118
+ hp->start.offset = 0;
2119
+
2120
+ return req;
2121
+ }
403
2122
 
404
- static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data)
2123
+ if (hp->cs == http_parser_error)
2124
+ rb_raise(eHttpParserError, "Invalid HTTP format, parsing fails.");
2125
+
2126
+ return Qnil;
2127
+ }
2128
+
2129
+ static int chunked_eof(struct http_parser *hp)
405
2130
  {
406
- http_parser *http = data_get(self);
2131
+ return ((hp->cs == http_parser_first_final) ||
2132
+ (hp->flags & UH_FL_INTRAILER));
2133
+ }
2134
+
2135
+ static VALUE HttpParser_body_eof(VALUE self)
2136
+ {
2137
+ struct http_parser *hp = data_get(self);
2138
+
2139
+ if (hp->flags & UH_FL_CHUNKED)
2140
+ return chunked_eof(hp) ? Qtrue : Qfalse;
2141
+
2142
+ return hp->len.content == 0 ? Qtrue : Qfalse;
2143
+ }
2144
+
2145
+ static VALUE HttpParser_keepalive(VALUE self)
2146
+ {
2147
+ struct http_parser *hp = data_get(self);
2148
+
2149
+ return (hp->flags & UH_FL_KEEPALIVE) == UH_FL_KEEPALIVE ? Qtrue : Qfalse;
2150
+ }
2151
+
2152
+ /**
2153
+ * call-seq:
2154
+ * parser.filter_body(buf, data) -> nil/data
2155
+ *
2156
+ * Takes a String of +data+, will modify data if dechunking is done.
2157
+ * Returns +nil+ if there is more data left to process. Returns
2158
+ * +data+ if body processing is complete. When returning +data+,
2159
+ * it may modify +data+ so the start of the string points to where
2160
+ * the body ended so that trailer processing can begin.
2161
+ *
2162
+ * Raises HttpParserError if there are dechunking errors
2163
+ * Basically this is a glorified memcpy(3) that copies +data+
2164
+ * into +buf+ while filtering it through the dechunker.
2165
+ */
2166
+ static VALUE HttpParser_filter_body(VALUE self, VALUE buf, VALUE data)
2167
+ {
2168
+ struct http_parser *hp = data_get(self);
407
2169
  char *dptr = RSTRING_PTR(data);
408
2170
  long dlen = RSTRING_LEN(data);
409
2171
 
410
- if (http->nread < dlen) {
411
- http->data = (void *)req_hash;
412
- http_parser_execute(http, dptr, dlen);
2172
+ StringValue(buf);
2173
+ rb_str_resize(buf, dlen); /* we can never copy more than dlen bytes */
2174
+ OBJ_TAINT(buf); /* keep weirdo $SAFE users happy */
413
2175
 
414
- VALIDATE_MAX_LENGTH(http->nread, HEADER);
2176
+ if (hp->flags & UH_FL_CHUNKED) {
2177
+ if (chunked_eof(hp))
2178
+ goto end_of_body;
415
2179
 
416
- if (!http_parser_has_error(http))
417
- return http_parser_is_finished(http) ? Qtrue : Qfalse;
2180
+ hp->s.dest_offset = 0;
2181
+ http_parser_execute(hp, buf, dptr, dlen);
2182
+ if (hp->cs == http_parser_error)
2183
+ rb_raise(eHttpParserError, "Invalid HTTP format, parsing fails.");
418
2184
 
419
- rb_raise(eHttpParserError, "Invalid HTTP format, parsing fails.");
2185
+ assert(hp->s.dest_offset <= hp->start.offset);
2186
+ advance_str(data, hp->start.offset);
2187
+ rb_str_set_len(buf, hp->s.dest_offset);
2188
+
2189
+ if (RSTRING_LEN(buf) == 0 && chunked_eof(hp)) {
2190
+ assert(hp->len.chunk == 0);
2191
+ } else {
2192
+ data = Qnil;
2193
+ }
2194
+ } else {
2195
+ /* no need to enter the Ragel machine for unchunked transfers */
2196
+ assert(hp->len.content >= 0);
2197
+ if (hp->len.content > 0) {
2198
+ long nr = MIN(dlen, hp->len.content);
2199
+
2200
+ memcpy(RSTRING_PTR(buf), dptr, nr);
2201
+ hp->len.content -= nr;
2202
+ if (hp->len.content == 0)
2203
+ hp->cs = http_parser_first_final;
2204
+ advance_str(data, nr);
2205
+ rb_str_set_len(buf, nr);
2206
+ data = Qnil;
2207
+ }
420
2208
  }
421
- rb_raise(eHttpParserError, "Requested start is after data buffer end.");
2209
+ end_of_body:
2210
+ hp->start.offset = 0; /* for trailer parsing */
2211
+ return data;
422
2212
  }
423
2213
 
2214
+ #define SET_GLOBAL(var,str) do { \
2215
+ var = find_common_field(str, sizeof(str) - 1); \
2216
+ assert(var != Qnil); \
2217
+ } while (0)
2218
+
424
2219
  void Init_unicorn_http(void)
425
2220
  {
426
- mUnicorn = rb_define_module("Unicorn");
427
-
428
- DEF_GLOBAL(rack_url_scheme, "rack.url_scheme");
429
- DEF_GLOBAL(request_method, "REQUEST_METHOD");
430
- DEF_GLOBAL(request_uri, "REQUEST_URI");
431
- DEF_GLOBAL(fragment, "FRAGMENT");
432
- DEF_GLOBAL(query_string, "QUERY_STRING");
433
- DEF_GLOBAL(http_version, "HTTP_VERSION");
434
- DEF_GLOBAL(request_path, "REQUEST_PATH");
435
- DEF_GLOBAL(path_info, "PATH_INFO");
436
- DEF_GLOBAL(server_name, "SERVER_NAME");
437
- DEF_GLOBAL(server_port, "SERVER_PORT");
438
- DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
439
- DEF_GLOBAL(server_protocol_value, "HTTP/1.1");
440
- DEF_GLOBAL(http_x_forwarded_proto, "HTTP_X_FORWARDED_PROTO");
441
- DEF_GLOBAL(port_80, "80");
442
- DEF_GLOBAL(port_443, "443");
443
- DEF_GLOBAL(localhost, "localhost");
444
- DEF_GLOBAL(http, "http");
445
-
446
- eHttpParserError = rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
447
-
448
- cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
2221
+ init_globals();
449
2222
  rb_define_alloc_func(cHttpParser, HttpParser_alloc);
450
2223
  rb_define_method(cHttpParser, "initialize", HttpParser_init,0);
451
2224
  rb_define_method(cHttpParser, "reset", HttpParser_reset,0);
452
- rb_define_method(cHttpParser, "execute", HttpParser_execute,2);
453
- sym_http_body = ID2SYM(rb_intern("http_body"));
2225
+ rb_define_method(cHttpParser, "headers", HttpParser_headers, 2);
2226
+ rb_define_method(cHttpParser, "filter_body", HttpParser_filter_body, 2);
2227
+ rb_define_method(cHttpParser, "trailers", HttpParser_headers, 2);
2228
+ rb_define_method(cHttpParser, "content_length", HttpParser_content_length, 0);
2229
+ rb_define_method(cHttpParser, "body_eof?", HttpParser_body_eof, 0);
2230
+ rb_define_method(cHttpParser, "keepalive?", HttpParser_keepalive, 0);
2231
+
2232
+ /*
2233
+ * The maximum size a single chunk when using chunked transfer encoding.
2234
+ * This is only a theoretical maximum used to detect errors in clients,
2235
+ * it is highly unlikely to encounter clients that send more than
2236
+ * several kilobytes at once.
2237
+ */
2238
+ rb_define_const(cHttpParser, "CHUNK_MAX", OFFT2NUM(UH_OFF_T_MAX));
2239
+
2240
+ /*
2241
+ * The maximum size of the body as specified by Content-Length.
2242
+ * This is only a theoretical maximum, the actual limit is subject
2243
+ * to the limits of the file system used for +Dir::tmpdir+
2244
+ */
2245
+ rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX));
2246
+
454
2247
  init_common_fields();
455
- global_http_host = find_common_field_value("HOST", 4);
456
- assert(global_http_host != Qnil);
2248
+ SET_GLOBAL(g_http_host, "HOST");
2249
+ SET_GLOBAL(g_http_trailer, "TRAILER");
2250
+ SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
2251
+ SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
2252
+ SET_GLOBAL(g_http_connection, "CONNECTION");
457
2253
  }
2254
+ #undef SET_GLOBAL