picohttp 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/picohttp/picohttp.c +81 -20
- data/ext/picohttp/string_lookup.inc +122 -76
- data/lib/picohttp/version.rb +1 -1
- data/tool/generate_lookup.rb +45 -5
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cd749cf10a5d5718c50fee68b7598b44cf01e3709789931d2ed8ee6c8d69adb0
|
|
4
|
+
data.tar.gz: 664f012d7379f4c4ae09213f6fc68aa7152ce86f1ba1e7138eddbb17a7e56864
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c3af0a35ffd06aefd5bb57f993394c775030aecd60c9dea69e9deb9c0342d1c4d8db89e3c722b68c7a7839fd02c0458f92613e66dcd115ac0153525f3695828
|
|
7
|
+
data.tar.gz: 719f7c6ded60d90a21e14cf9f3c9220fda942f79a2d2a73be1a16dfb90a14ee95dabddf55b37ca176460abd33874064a2f0838992b44f2781676106172a489c2
|
data/ext/picohttp/picohttp.c
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
#include "picohttpparser.h"
|
|
3
3
|
|
|
4
4
|
#define MAX_HEADER_NAME_LEN 256
|
|
5
|
-
#define
|
|
5
|
+
#define MAX_HTTP_HEADERS 100
|
|
6
|
+
#define EXTRA_RACK_HEADERS 8
|
|
6
7
|
|
|
7
8
|
VALUE rb_mPicohttp;
|
|
8
9
|
VALUE rb_ePicohttpParseError;
|
|
@@ -12,6 +13,10 @@ static VALUE rb_str_request_method;
|
|
|
12
13
|
static VALUE rb_str_server_protocol;
|
|
13
14
|
static VALUE rb_str_path_info;
|
|
14
15
|
static VALUE rb_str_query_string;
|
|
16
|
+
static VALUE rb_str_request_uri;
|
|
17
|
+
static VALUE rb_str_script_name;
|
|
18
|
+
static VALUE rb_str_server_name;
|
|
19
|
+
static VALUE rb_str_server_port;
|
|
15
20
|
static VALUE rb_str_empty;
|
|
16
21
|
static VALUE rb_str_http_1_0;
|
|
17
22
|
static VALUE rb_str_http_1_1;
|
|
@@ -78,7 +83,7 @@ picohttp_parse_request(VALUE self, VALUE str)
|
|
|
78
83
|
|
|
79
84
|
const char *method, *path;
|
|
80
85
|
int minor_version;
|
|
81
|
-
struct phr_header headers[
|
|
86
|
+
struct phr_header headers[MAX_HTTP_HEADERS];
|
|
82
87
|
size_t method_len, path_len, num_headers = sizeof(headers) / sizeof(headers[0]);
|
|
83
88
|
|
|
84
89
|
int result = phr_parse_request(buf, len, &method, &method_len, &path, &path_len,
|
|
@@ -109,6 +114,24 @@ picohttp_parse_request(VALUE self, VALUE str)
|
|
|
109
114
|
INT2FIX(result));
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
static VALUE
|
|
118
|
+
build_hash_with_combined_duplicates(VALUE *header_values, int count)
|
|
119
|
+
{
|
|
120
|
+
VALUE env = rb_hash_new();
|
|
121
|
+
for (int i = 0; i < count; i += 2) {
|
|
122
|
+
VALUE key = header_values[i];
|
|
123
|
+
VALUE val = header_values[i + 1];
|
|
124
|
+
VALUE existing = rb_hash_aref(env, key);
|
|
125
|
+
if (existing == Qnil) {
|
|
126
|
+
rb_hash_aset(env, key, val);
|
|
127
|
+
} else {
|
|
128
|
+
rb_str_cat2(existing, ", ");
|
|
129
|
+
rb_str_cat(existing, RSTRING_PTR(val), RSTRING_LEN(val));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return env;
|
|
133
|
+
}
|
|
134
|
+
|
|
112
135
|
static VALUE
|
|
113
136
|
picohttp_parse_request_env(VALUE self, VALUE str)
|
|
114
137
|
{
|
|
@@ -119,7 +142,7 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
119
142
|
|
|
120
143
|
const char *method, *path;
|
|
121
144
|
int minor_version;
|
|
122
|
-
struct phr_header headers[
|
|
145
|
+
struct phr_header headers[MAX_HTTP_HEADERS];
|
|
123
146
|
size_t method_len, path_len, num_headers = sizeof(headers) / sizeof(headers[0]);
|
|
124
147
|
|
|
125
148
|
int result = phr_parse_request(buf, len, &method, &method_len, &path, &path_len,
|
|
@@ -132,7 +155,7 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
132
155
|
rb_raise(rb_ePicohttpParseError, "Invalid HTTP request");
|
|
133
156
|
}
|
|
134
157
|
|
|
135
|
-
VALUE header_values[
|
|
158
|
+
VALUE header_values[(MAX_HTTP_HEADERS + EXTRA_RACK_HEADERS) * 2];
|
|
136
159
|
int idx = 0;
|
|
137
160
|
|
|
138
161
|
// Standard CGI/Rack environment variables
|
|
@@ -161,6 +184,14 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
161
184
|
header_values[idx++] = rb_str_empty;
|
|
162
185
|
}
|
|
163
186
|
|
|
187
|
+
// REQUEST_URI is the full path including query string
|
|
188
|
+
header_values[idx++] = rb_str_request_uri;
|
|
189
|
+
header_values[idx++] = rb_str_new(path, path_len);
|
|
190
|
+
|
|
191
|
+
// SCRIPT_NAME is always empty
|
|
192
|
+
header_values[idx++] = rb_str_script_name;
|
|
193
|
+
header_values[idx++] = rb_str_empty;
|
|
194
|
+
|
|
164
195
|
// Convert headers to HTTP_ prefixed environment variables
|
|
165
196
|
for (size_t i = 0; i < num_headers; i++) {
|
|
166
197
|
if (headers[i].name == NULL) {
|
|
@@ -169,6 +200,27 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
169
200
|
|
|
170
201
|
header_values[idx++] = header_name_to_env_key(headers[i].name, headers[i].name_len);
|
|
171
202
|
header_values[idx++] = rb_str_new(headers[i].value, headers[i].value_len);
|
|
203
|
+
|
|
204
|
+
// Extract SERVER_NAME/SERVER_PORT from Host header
|
|
205
|
+
if (headers[i].name_len == 4 &&
|
|
206
|
+
(headers[i].name[0] | 0x20) == 'h' &&
|
|
207
|
+
(headers[i].name[1] | 0x20) == 'o' &&
|
|
208
|
+
(headers[i].name[2] | 0x20) == 's' &&
|
|
209
|
+
(headers[i].name[3] | 0x20) == 't') {
|
|
210
|
+
const char *host = headers[i].value;
|
|
211
|
+
size_t host_len = headers[i].value_len;
|
|
212
|
+
const char *colon = memchr(host, ':', host_len);
|
|
213
|
+
|
|
214
|
+
if (colon) {
|
|
215
|
+
header_values[idx++] = rb_str_server_name;
|
|
216
|
+
header_values[idx++] = rb_str_new(host, colon - host);
|
|
217
|
+
header_values[idx++] = rb_str_server_port;
|
|
218
|
+
header_values[idx++] = rb_str_new(colon + 1, host_len - (colon - host) - 1);
|
|
219
|
+
} else {
|
|
220
|
+
header_values[idx++] = rb_str_server_name;
|
|
221
|
+
header_values[idx++] = rb_str_new(host, host_len);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
172
224
|
}
|
|
173
225
|
|
|
174
226
|
#ifdef HAVE_RB_HASH_NEW_CAPA
|
|
@@ -179,9 +231,22 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
179
231
|
|
|
180
232
|
rb_hash_bulk_insert(idx, header_values, env);
|
|
181
233
|
|
|
234
|
+
// Handle duplicate headers per RFC 7230
|
|
235
|
+
if (RHASH_SIZE(env) != (size_t)(idx / 2)) {
|
|
236
|
+
return build_hash_with_combined_duplicates(header_values, idx);
|
|
237
|
+
}
|
|
238
|
+
|
|
182
239
|
return env;
|
|
183
240
|
}
|
|
184
241
|
|
|
242
|
+
static VALUE
|
|
243
|
+
register_interned_string(const char *str)
|
|
244
|
+
{
|
|
245
|
+
VALUE val = rb_interned_str_cstr(str);
|
|
246
|
+
rb_gc_register_mark_object(val);
|
|
247
|
+
return val;
|
|
248
|
+
}
|
|
249
|
+
|
|
185
250
|
RUBY_FUNC_EXPORTED void
|
|
186
251
|
Init_picohttp(void)
|
|
187
252
|
{
|
|
@@ -196,20 +261,16 @@ Init_picohttp(void)
|
|
|
196
261
|
|
|
197
262
|
// Initialize interned string constants
|
|
198
263
|
init_string_lookup();
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
rb_gc_register_address(&rb_str_query_string);
|
|
212
|
-
rb_gc_register_address(&rb_str_empty);
|
|
213
|
-
rb_gc_register_address(&rb_str_http_1_0);
|
|
214
|
-
rb_gc_register_address(&rb_str_http_1_1);
|
|
264
|
+
|
|
265
|
+
rb_str_request_method = register_interned_string("REQUEST_METHOD");
|
|
266
|
+
rb_str_server_protocol = register_interned_string("SERVER_PROTOCOL");
|
|
267
|
+
rb_str_path_info = register_interned_string("PATH_INFO");
|
|
268
|
+
rb_str_query_string = register_interned_string("QUERY_STRING");
|
|
269
|
+
rb_str_request_uri = register_interned_string("REQUEST_URI");
|
|
270
|
+
rb_str_script_name = register_interned_string("SCRIPT_NAME");
|
|
271
|
+
rb_str_server_name = register_interned_string("SERVER_NAME");
|
|
272
|
+
rb_str_server_port = register_interned_string("SERVER_PORT");
|
|
273
|
+
rb_str_empty = register_interned_string("");
|
|
274
|
+
rb_str_http_1_0 = register_interned_string("HTTP/1.0");
|
|
275
|
+
rb_str_http_1_1 = register_interned_string("HTTP/1.1");
|
|
215
276
|
}
|
|
@@ -1,54 +1,56 @@
|
|
|
1
1
|
/* This file is auto-generated by tool/generate_lookup.rb */
|
|
2
2
|
|
|
3
|
-
static
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
static struct string_lookup_t {
|
|
4
|
+
VALUE http_host; /* "HTTP_HOST" */
|
|
5
|
+
VALUE http_accept; /* "HTTP_ACCEPT" */
|
|
6
|
+
VALUE http_cookie; /* "HTTP_COOKIE" */
|
|
7
|
+
VALUE http_referer; /* "HTTP_REFERER" */
|
|
8
|
+
VALUE http_user_agent; /* "HTTP_USER_AGENT" */
|
|
9
|
+
VALUE http_connection; /* "HTTP_CONNECTION" */
|
|
10
|
+
VALUE content_type; /* "CONTENT_TYPE" */
|
|
11
|
+
VALUE http_cache_control; /* "HTTP_CACHE_CONTROL" */
|
|
12
|
+
VALUE http_authorization; /* "HTTP_AUTHORIZATION" */
|
|
13
|
+
VALUE content_length; /* "CONTENT_LENGTH" */
|
|
14
|
+
VALUE http_accept_encoding; /* "HTTP_ACCEPT_ENCODING" */
|
|
15
|
+
VALUE http_accept_language; /* "HTTP_ACCEPT_LANGUAGE" */
|
|
16
|
+
VALUE get; /* "GET" */
|
|
17
|
+
VALUE put; /* "PUT" */
|
|
18
|
+
VALUE post; /* "POST" */
|
|
19
|
+
VALUE head; /* "HEAD" */
|
|
20
|
+
VALUE patch; /* "PATCH" */
|
|
21
|
+
VALUE delete; /* "DELETE" */
|
|
22
|
+
VALUE options; /* "OPTIONS" */
|
|
23
|
+
} string_lookup;
|
|
22
24
|
|
|
23
25
|
static VALUE lookup_header(const char *s, size_t len) {
|
|
24
26
|
switch (len) {
|
|
25
27
|
case 4:
|
|
26
|
-
if ((s[0] | 32) == 'h' && (s[1] | 32) == 'o' && (s[2] | 32) == 's' && (s[3] | 32) == 't') return
|
|
28
|
+
if ((s[0] | 32) == 'h' && (s[1] | 32) == 'o' && (s[2] | 32) == 's' && (s[3] | 32) == 't') return string_lookup.http_host;
|
|
27
29
|
break;
|
|
28
30
|
case 6:
|
|
29
|
-
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'c' && (s[2] | 32) == 'c' && (s[3] | 32) == 'e' && (s[4] | 32) == 'p' && (s[5] | 32) == 't') return
|
|
30
|
-
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'o' && (s[3] | 32) == 'k' && (s[4] | 32) == 'i' && (s[5] | 32) == 'e') return
|
|
31
|
+
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'c' && (s[2] | 32) == 'c' && (s[3] | 32) == 'e' && (s[4] | 32) == 'p' && (s[5] | 32) == 't') return string_lookup.http_accept;
|
|
32
|
+
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'o' && (s[3] | 32) == 'k' && (s[4] | 32) == 'i' && (s[5] | 32) == 'e') return string_lookup.http_cookie;
|
|
31
33
|
break;
|
|
32
34
|
case 7:
|
|
33
|
-
if ((s[0] | 32) == 'r' && (s[1] | 32) == 'e' && (s[2] | 32) == 'f' && (s[3] | 32) == 'e' && (s[4] | 32) == 'r' && (s[5] | 32) == 'e' && (s[6] | 32) == 'r') return
|
|
35
|
+
if ((s[0] | 32) == 'r' && (s[1] | 32) == 'e' && (s[2] | 32) == 'f' && (s[3] | 32) == 'e' && (s[4] | 32) == 'r' && (s[5] | 32) == 'e' && (s[6] | 32) == 'r') return string_lookup.http_referer;
|
|
34
36
|
break;
|
|
35
37
|
case 10:
|
|
36
|
-
if ((s[0] | 32) == 'u' && (s[1] | 32) == 's' && (s[2] | 32) == 'e' && (s[3] | 32) == 'r' && (s[4] | 32) == '-' && (s[5] | 32) == 'a' && (s[6] | 32) == 'g' && (s[7] | 32) == 'e' && (s[8] | 32) == 'n' && (s[9] | 32) == 't') return
|
|
37
|
-
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'n' && (s[3] | 32) == 'n' && (s[4] | 32) == 'e' && (s[5] | 32) == 'c' && (s[6] | 32) == 't' && (s[7] | 32) == 'i' && (s[8] | 32) == 'o' && (s[9] | 32) == 'n') return
|
|
38
|
+
if ((s[0] | 32) == 'u' && (s[1] | 32) == 's' && (s[2] | 32) == 'e' && (s[3] | 32) == 'r' && (s[4] | 32) == '-' && (s[5] | 32) == 'a' && (s[6] | 32) == 'g' && (s[7] | 32) == 'e' && (s[8] | 32) == 'n' && (s[9] | 32) == 't') return string_lookup.http_user_agent;
|
|
39
|
+
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'n' && (s[3] | 32) == 'n' && (s[4] | 32) == 'e' && (s[5] | 32) == 'c' && (s[6] | 32) == 't' && (s[7] | 32) == 'i' && (s[8] | 32) == 'o' && (s[9] | 32) == 'n') return string_lookup.http_connection;
|
|
38
40
|
break;
|
|
39
41
|
case 12:
|
|
40
|
-
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'n' && (s[3] | 32) == 't' && (s[4] | 32) == 'e' && (s[5] | 32) == 'n' && (s[6] | 32) == 't' && (s[7] | 32) == '-' && (s[8] | 32) == 't' && (s[9] | 32) == 'y' && (s[10] | 32) == 'p' && (s[11] | 32) == 'e') return
|
|
42
|
+
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'n' && (s[3] | 32) == 't' && (s[4] | 32) == 'e' && (s[5] | 32) == 'n' && (s[6] | 32) == 't' && (s[7] | 32) == '-' && (s[8] | 32) == 't' && (s[9] | 32) == 'y' && (s[10] | 32) == 'p' && (s[11] | 32) == 'e') return string_lookup.content_type;
|
|
41
43
|
break;
|
|
42
44
|
case 13:
|
|
43
|
-
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'a' && (s[2] | 32) == 'c' && (s[3] | 32) == 'h' && (s[4] | 32) == 'e' && (s[5] | 32) == '-' && (s[6] | 32) == 'c' && (s[7] | 32) == 'o' && (s[8] | 32) == 'n' && (s[9] | 32) == 't' && (s[10] | 32) == 'r' && (s[11] | 32) == 'o' && (s[12] | 32) == 'l') return
|
|
44
|
-
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'u' && (s[2] | 32) == 't' && (s[3] | 32) == 'h' && (s[4] | 32) == 'o' && (s[5] | 32) == 'r' && (s[6] | 32) == 'i' && (s[7] | 32) == 'z' && (s[8] | 32) == 'a' && (s[9] | 32) == 't' && (s[10] | 32) == 'i' && (s[11] | 32) == 'o' && (s[12] | 32) == 'n') return
|
|
45
|
+
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'a' && (s[2] | 32) == 'c' && (s[3] | 32) == 'h' && (s[4] | 32) == 'e' && (s[5] | 32) == '-' && (s[6] | 32) == 'c' && (s[7] | 32) == 'o' && (s[8] | 32) == 'n' && (s[9] | 32) == 't' && (s[10] | 32) == 'r' && (s[11] | 32) == 'o' && (s[12] | 32) == 'l') return string_lookup.http_cache_control;
|
|
46
|
+
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'u' && (s[2] | 32) == 't' && (s[3] | 32) == 'h' && (s[4] | 32) == 'o' && (s[5] | 32) == 'r' && (s[6] | 32) == 'i' && (s[7] | 32) == 'z' && (s[8] | 32) == 'a' && (s[9] | 32) == 't' && (s[10] | 32) == 'i' && (s[11] | 32) == 'o' && (s[12] | 32) == 'n') return string_lookup.http_authorization;
|
|
45
47
|
break;
|
|
46
48
|
case 14:
|
|
47
|
-
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'n' && (s[3] | 32) == 't' && (s[4] | 32) == 'e' && (s[5] | 32) == 'n' && (s[6] | 32) == 't' && (s[7] | 32) == '-' && (s[8] | 32) == 'l' && (s[9] | 32) == 'e' && (s[10] | 32) == 'n' && (s[11] | 32) == 'g' && (s[12] | 32) == 't' && (s[13] | 32) == 'h') return
|
|
49
|
+
if ((s[0] | 32) == 'c' && (s[1] | 32) == 'o' && (s[2] | 32) == 'n' && (s[3] | 32) == 't' && (s[4] | 32) == 'e' && (s[5] | 32) == 'n' && (s[6] | 32) == 't' && (s[7] | 32) == '-' && (s[8] | 32) == 'l' && (s[9] | 32) == 'e' && (s[10] | 32) == 'n' && (s[11] | 32) == 'g' && (s[12] | 32) == 't' && (s[13] | 32) == 'h') return string_lookup.content_length;
|
|
48
50
|
break;
|
|
49
51
|
case 15:
|
|
50
|
-
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'c' && (s[2] | 32) == 'c' && (s[3] | 32) == 'e' && (s[4] | 32) == 'p' && (s[5] | 32) == 't' && (s[6] | 32) == '-' && (s[7] | 32) == 'e' && (s[8] | 32) == 'n' && (s[9] | 32) == 'c' && (s[10] | 32) == 'o' && (s[11] | 32) == 'd' && (s[12] | 32) == 'i' && (s[13] | 32) == 'n' && (s[14] | 32) == 'g') return
|
|
51
|
-
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'c' && (s[2] | 32) == 'c' && (s[3] | 32) == 'e' && (s[4] | 32) == 'p' && (s[5] | 32) == 't' && (s[6] | 32) == '-' && (s[7] | 32) == 'l' && (s[8] | 32) == 'a' && (s[9] | 32) == 'n' && (s[10] | 32) == 'g' && (s[11] | 32) == 'u' && (s[12] | 32) == 'a' && (s[13] | 32) == 'g' && (s[14] | 32) == 'e') return
|
|
52
|
+
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'c' && (s[2] | 32) == 'c' && (s[3] | 32) == 'e' && (s[4] | 32) == 'p' && (s[5] | 32) == 't' && (s[6] | 32) == '-' && (s[7] | 32) == 'e' && (s[8] | 32) == 'n' && (s[9] | 32) == 'c' && (s[10] | 32) == 'o' && (s[11] | 32) == 'd' && (s[12] | 32) == 'i' && (s[13] | 32) == 'n' && (s[14] | 32) == 'g') return string_lookup.http_accept_encoding;
|
|
53
|
+
if ((s[0] | 32) == 'a' && (s[1] | 32) == 'c' && (s[2] | 32) == 'c' && (s[3] | 32) == 'e' && (s[4] | 32) == 'p' && (s[5] | 32) == 't' && (s[6] | 32) == '-' && (s[7] | 32) == 'l' && (s[8] | 32) == 'a' && (s[9] | 32) == 'n' && (s[10] | 32) == 'g' && (s[11] | 32) == 'u' && (s[12] | 32) == 'a' && (s[13] | 32) == 'g' && (s[14] | 32) == 'e') return string_lookup.http_accept_language;
|
|
52
54
|
break;
|
|
53
55
|
}
|
|
54
56
|
return Qnil;
|
|
@@ -57,64 +59,108 @@ static VALUE lookup_header(const char *s, size_t len) {
|
|
|
57
59
|
static VALUE lookup_method(const char *s, size_t len) {
|
|
58
60
|
switch (len) {
|
|
59
61
|
case 3:
|
|
60
|
-
if (s[0] == 'G' && s[1] == 'E' && s[2] == 'T') return
|
|
61
|
-
if (s[0] == 'P' && s[1] == 'U' && s[2] == 'T') return
|
|
62
|
+
if (s[0] == 'G' && s[1] == 'E' && s[2] == 'T') return string_lookup.get;
|
|
63
|
+
if (s[0] == 'P' && s[1] == 'U' && s[2] == 'T') return string_lookup.put;
|
|
62
64
|
break;
|
|
63
65
|
case 4:
|
|
64
|
-
if (s[0] == 'P' && s[1] == 'O' && s[2] == 'S' && s[3] == 'T') return
|
|
65
|
-
if (s[0] == 'H' && s[1] == 'E' && s[2] == 'A' && s[3] == 'D') return
|
|
66
|
+
if (s[0] == 'P' && s[1] == 'O' && s[2] == 'S' && s[3] == 'T') return string_lookup.post;
|
|
67
|
+
if (s[0] == 'H' && s[1] == 'E' && s[2] == 'A' && s[3] == 'D') return string_lookup.head;
|
|
66
68
|
break;
|
|
67
69
|
case 5:
|
|
68
|
-
if (s[0] == 'P' && s[1] == 'A' && s[2] == 'T' && s[3] == 'C' && s[4] == 'H') return
|
|
70
|
+
if (s[0] == 'P' && s[1] == 'A' && s[2] == 'T' && s[3] == 'C' && s[4] == 'H') return string_lookup.patch;
|
|
69
71
|
break;
|
|
70
72
|
case 6:
|
|
71
|
-
if (s[0] == 'D' && s[1] == 'E' && s[2] == 'L' && s[3] == 'E' && s[4] == 'T' && s[5] == 'E') return
|
|
73
|
+
if (s[0] == 'D' && s[1] == 'E' && s[2] == 'L' && s[3] == 'E' && s[4] == 'T' && s[5] == 'E') return string_lookup.delete;
|
|
72
74
|
break;
|
|
73
75
|
case 7:
|
|
74
|
-
if (s[0] == 'O' && s[1] == 'P' && s[2] == 'T' && s[3] == 'I' && s[4] == 'O' && s[5] == 'N' && s[6] == 'S') return
|
|
76
|
+
if (s[0] == 'O' && s[1] == 'P' && s[2] == 'T' && s[3] == 'I' && s[4] == 'O' && s[5] == 'N' && s[6] == 'S') return string_lookup.options;
|
|
75
77
|
break;
|
|
76
78
|
}
|
|
77
79
|
return Qnil;
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
static void string_lookup_mark(void *ptr) {
|
|
83
|
+
struct string_lookup_t *s = ptr;
|
|
84
|
+
rb_gc_mark_movable(s->http_host);
|
|
85
|
+
rb_gc_mark_movable(s->http_accept);
|
|
86
|
+
rb_gc_mark_movable(s->http_cookie);
|
|
87
|
+
rb_gc_mark_movable(s->http_referer);
|
|
88
|
+
rb_gc_mark_movable(s->http_user_agent);
|
|
89
|
+
rb_gc_mark_movable(s->http_connection);
|
|
90
|
+
rb_gc_mark_movable(s->content_type);
|
|
91
|
+
rb_gc_mark_movable(s->http_cache_control);
|
|
92
|
+
rb_gc_mark_movable(s->http_authorization);
|
|
93
|
+
rb_gc_mark_movable(s->content_length);
|
|
94
|
+
rb_gc_mark_movable(s->http_accept_encoding);
|
|
95
|
+
rb_gc_mark_movable(s->http_accept_language);
|
|
96
|
+
rb_gc_mark_movable(s->get);
|
|
97
|
+
rb_gc_mark_movable(s->put);
|
|
98
|
+
rb_gc_mark_movable(s->post);
|
|
99
|
+
rb_gc_mark_movable(s->head);
|
|
100
|
+
rb_gc_mark_movable(s->patch);
|
|
101
|
+
rb_gc_mark_movable(s->delete);
|
|
102
|
+
rb_gc_mark_movable(s->options);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static void string_lookup_compact(void *ptr) {
|
|
106
|
+
struct string_lookup_t *s = ptr;
|
|
107
|
+
s->http_host = rb_gc_location(s->http_host);
|
|
108
|
+
s->http_accept = rb_gc_location(s->http_accept);
|
|
109
|
+
s->http_cookie = rb_gc_location(s->http_cookie);
|
|
110
|
+
s->http_referer = rb_gc_location(s->http_referer);
|
|
111
|
+
s->http_user_agent = rb_gc_location(s->http_user_agent);
|
|
112
|
+
s->http_connection = rb_gc_location(s->http_connection);
|
|
113
|
+
s->content_type = rb_gc_location(s->content_type);
|
|
114
|
+
s->http_cache_control = rb_gc_location(s->http_cache_control);
|
|
115
|
+
s->http_authorization = rb_gc_location(s->http_authorization);
|
|
116
|
+
s->content_length = rb_gc_location(s->content_length);
|
|
117
|
+
s->http_accept_encoding = rb_gc_location(s->http_accept_encoding);
|
|
118
|
+
s->http_accept_language = rb_gc_location(s->http_accept_language);
|
|
119
|
+
s->get = rb_gc_location(s->get);
|
|
120
|
+
s->put = rb_gc_location(s->put);
|
|
121
|
+
s->post = rb_gc_location(s->post);
|
|
122
|
+
s->head = rb_gc_location(s->head);
|
|
123
|
+
s->patch = rb_gc_location(s->patch);
|
|
124
|
+
s->delete = rb_gc_location(s->delete);
|
|
125
|
+
s->options = rb_gc_location(s->options);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static const rb_data_type_t string_lookup_type = {
|
|
129
|
+
.wrap_struct_name = "picohttp_string_lookup",
|
|
130
|
+
.function = {
|
|
131
|
+
.dmark = string_lookup_mark,
|
|
132
|
+
.dfree = NULL,
|
|
133
|
+
.dsize = NULL,
|
|
134
|
+
.dcompact = string_lookup_compact,
|
|
135
|
+
},
|
|
136
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
static void intern_str(VALUE wrapper, VALUE *field, const char *str) {
|
|
140
|
+
RB_OBJ_WRITE(wrapper, field, rb_interned_str_cstr(str));
|
|
141
|
+
}
|
|
142
|
+
|
|
80
143
|
static void init_string_lookup(void) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
rb_s_HTTP_ACCEPT_ENCODING = rb_interned_str_cstr("HTTP_ACCEPT_ENCODING");
|
|
103
|
-
rb_gc_register_address(&rb_s_HTTP_ACCEPT_LANGUAGE);
|
|
104
|
-
rb_s_HTTP_ACCEPT_LANGUAGE = rb_interned_str_cstr("HTTP_ACCEPT_LANGUAGE");
|
|
105
|
-
rb_gc_register_address(&rb_s_GET);
|
|
106
|
-
rb_s_GET = rb_interned_str_cstr("GET");
|
|
107
|
-
rb_gc_register_address(&rb_s_PUT);
|
|
108
|
-
rb_s_PUT = rb_interned_str_cstr("PUT");
|
|
109
|
-
rb_gc_register_address(&rb_s_POST);
|
|
110
|
-
rb_s_POST = rb_interned_str_cstr("POST");
|
|
111
|
-
rb_gc_register_address(&rb_s_HEAD);
|
|
112
|
-
rb_s_HEAD = rb_interned_str_cstr("HEAD");
|
|
113
|
-
rb_gc_register_address(&rb_s_PATCH);
|
|
114
|
-
rb_s_PATCH = rb_interned_str_cstr("PATCH");
|
|
115
|
-
rb_gc_register_address(&rb_s_DELETE);
|
|
116
|
-
rb_s_DELETE = rb_interned_str_cstr("DELETE");
|
|
117
|
-
rb_gc_register_address(&rb_s_OPTIONS);
|
|
118
|
-
rb_s_OPTIONS = rb_interned_str_cstr("OPTIONS");
|
|
144
|
+
VALUE wrapper = TypedData_Wrap_Struct(0, &string_lookup_type, &string_lookup);
|
|
145
|
+
rb_gc_register_mark_object(wrapper);
|
|
146
|
+
intern_str(wrapper, &string_lookup.http_host, "HTTP_HOST");
|
|
147
|
+
intern_str(wrapper, &string_lookup.http_accept, "HTTP_ACCEPT");
|
|
148
|
+
intern_str(wrapper, &string_lookup.http_cookie, "HTTP_COOKIE");
|
|
149
|
+
intern_str(wrapper, &string_lookup.http_referer, "HTTP_REFERER");
|
|
150
|
+
intern_str(wrapper, &string_lookup.http_user_agent, "HTTP_USER_AGENT");
|
|
151
|
+
intern_str(wrapper, &string_lookup.http_connection, "HTTP_CONNECTION");
|
|
152
|
+
intern_str(wrapper, &string_lookup.content_type, "CONTENT_TYPE");
|
|
153
|
+
intern_str(wrapper, &string_lookup.http_cache_control, "HTTP_CACHE_CONTROL");
|
|
154
|
+
intern_str(wrapper, &string_lookup.http_authorization, "HTTP_AUTHORIZATION");
|
|
155
|
+
intern_str(wrapper, &string_lookup.content_length, "CONTENT_LENGTH");
|
|
156
|
+
intern_str(wrapper, &string_lookup.http_accept_encoding, "HTTP_ACCEPT_ENCODING");
|
|
157
|
+
intern_str(wrapper, &string_lookup.http_accept_language, "HTTP_ACCEPT_LANGUAGE");
|
|
158
|
+
intern_str(wrapper, &string_lookup.get, "GET");
|
|
159
|
+
intern_str(wrapper, &string_lookup.put, "PUT");
|
|
160
|
+
intern_str(wrapper, &string_lookup.post, "POST");
|
|
161
|
+
intern_str(wrapper, &string_lookup.head, "HEAD");
|
|
162
|
+
intern_str(wrapper, &string_lookup.patch, "PATCH");
|
|
163
|
+
intern_str(wrapper, &string_lookup.delete, "DELETE");
|
|
164
|
+
intern_str(wrapper, &string_lookup.options, "OPTIONS");
|
|
119
165
|
}
|
|
120
166
|
|
data/lib/picohttp/version.rb
CHANGED
data/tool/generate_lookup.rb
CHANGED
|
@@ -15,9 +15,12 @@ class StringLookup
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def generate
|
|
18
|
+
# Generate the struct to hold all strings
|
|
19
|
+
puts "static struct string_lookup_t {"
|
|
18
20
|
@string_table.each do |v, name|
|
|
19
|
-
puts "
|
|
21
|
+
puts " VALUE #{name}; /* #{v.inspect} */"
|
|
20
22
|
end
|
|
23
|
+
puts "} string_lookup;"
|
|
21
24
|
puts
|
|
22
25
|
|
|
23
26
|
@functions.each do |code|
|
|
@@ -25,17 +28,54 @@ class StringLookup
|
|
|
25
28
|
puts
|
|
26
29
|
end
|
|
27
30
|
|
|
31
|
+
# Generate mark function
|
|
32
|
+
puts "static void string_lookup_mark(void *ptr) {"
|
|
33
|
+
puts " struct string_lookup_t *s = ptr;"
|
|
34
|
+
@string_table.each do |v, name|
|
|
35
|
+
puts " rb_gc_mark_movable(s->#{name});"
|
|
36
|
+
end
|
|
37
|
+
puts "}"
|
|
38
|
+
puts
|
|
39
|
+
|
|
40
|
+
# Generate compact function
|
|
41
|
+
puts "static void string_lookup_compact(void *ptr) {"
|
|
42
|
+
puts " struct string_lookup_t *s = ptr;"
|
|
43
|
+
@string_table.each do |v, name|
|
|
44
|
+
puts " s->#{name} = rb_gc_location(s->#{name});"
|
|
45
|
+
end
|
|
46
|
+
puts "}"
|
|
47
|
+
puts
|
|
48
|
+
|
|
49
|
+
# Generate TypedData type
|
|
50
|
+
puts "static const rb_data_type_t string_lookup_type = {"
|
|
51
|
+
puts " .wrap_struct_name = \"picohttp_string_lookup\","
|
|
52
|
+
puts " .function = {"
|
|
53
|
+
puts " .dmark = string_lookup_mark,"
|
|
54
|
+
puts " .dfree = NULL,"
|
|
55
|
+
puts " .dsize = NULL,"
|
|
56
|
+
puts " .dcompact = string_lookup_compact,"
|
|
57
|
+
puts " },"
|
|
58
|
+
puts " .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,"
|
|
59
|
+
puts "};"
|
|
60
|
+
puts
|
|
61
|
+
|
|
62
|
+
puts "static void intern_str(VALUE wrapper, VALUE *field, const char *str) {"
|
|
63
|
+
puts " RB_OBJ_WRITE(wrapper, field, rb_interned_str_cstr(str));"
|
|
64
|
+
puts "}"
|
|
65
|
+
puts
|
|
66
|
+
|
|
28
67
|
puts "static void init_string_lookup(void) {"
|
|
68
|
+
puts " VALUE wrapper = TypedData_Wrap_Struct(0, &string_lookup_type, &string_lookup);"
|
|
69
|
+
puts " rb_gc_register_mark_object(wrapper);"
|
|
29
70
|
@string_table.each do |v, name|
|
|
30
|
-
puts "
|
|
31
|
-
puts " #{name} = rb_interned_str_cstr(#{v.dump});"
|
|
71
|
+
puts " intern_str(wrapper, &string_lookup.#{name}, #{v.dump});"
|
|
32
72
|
end
|
|
33
73
|
puts "}"
|
|
34
74
|
puts
|
|
35
75
|
end
|
|
36
76
|
|
|
37
77
|
def name_for_string(string)
|
|
38
|
-
|
|
78
|
+
string.gsub(/[^a-z0-9]/i, "_").downcase
|
|
39
79
|
end
|
|
40
80
|
|
|
41
81
|
def generate_comparison(var, string, ignore_case: false)
|
|
@@ -66,7 +106,7 @@ class StringLookup
|
|
|
66
106
|
code << " case #{len}:"
|
|
67
107
|
strs.each do |match, target|
|
|
68
108
|
name = @string_table[target]
|
|
69
|
-
code << " if (#{generate_comparison("s", match, ignore_case:)}) return
|
|
109
|
+
code << " if (#{generate_comparison("s", match, ignore_case:)}) return string_lookup.#{name};"
|
|
70
110
|
end
|
|
71
111
|
code << " break;"
|
|
72
112
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: picohttp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Hawthorn
|
|
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
55
|
version: '0'
|
|
56
56
|
requirements: []
|
|
57
|
-
rubygems_version: 4.0.
|
|
57
|
+
rubygems_version: 4.0.3
|
|
58
58
|
specification_version: 4
|
|
59
59
|
summary: Fast HTTP request parser using picohttpparser
|
|
60
60
|
test_files: []
|