picohttp 0.1.1 → 0.2.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 +45 -23
- data/ext/picohttp/string_lookup.inc +120 -0
- data/lib/picohttp/version.rb +1 -1
- data/tool/generate_lookup.rb +98 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b357892a265429f3731c5cc68f56aaa3649b1f346a9c86f021bb67be2e601ac
|
|
4
|
+
data.tar.gz: 7a499b9fe596ee583c238956d66f05f3ff6caeabd0594a5db1d0f3c1b6d3e023
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 704efdbcbd2daab576977d4f2857307a7de44a41b5785cc6d215886777b7d97e3e3ba257670e40afd4c0b49f05024c8e1b26f1a8a41864e5b70393736a26fe6a
|
|
7
|
+
data.tar.gz: 7318f991db2981ed09349edfd907141342121fa65f3a45fa0e51dc2503b973b1c83681356eacad29fd1f95c44af130ad1eb0952e52ae04e4a139678bf172d016
|
data/ext/picohttp/picohttp.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#include "picohttpparser.h"
|
|
3
3
|
|
|
4
4
|
#define MAX_HEADER_NAME_LEN 256
|
|
5
|
-
#define
|
|
5
|
+
#define MAX_HEADERS 100
|
|
6
6
|
|
|
7
7
|
VALUE rb_mPicohttp;
|
|
8
8
|
VALUE rb_ePicohttpParseError;
|
|
@@ -16,6 +16,8 @@ static VALUE rb_str_empty;
|
|
|
16
16
|
static VALUE rb_str_http_1_0;
|
|
17
17
|
static VALUE rb_str_http_1_1;
|
|
18
18
|
|
|
19
|
+
#include "string_lookup.inc"
|
|
20
|
+
|
|
19
21
|
static VALUE
|
|
20
22
|
http_version_string(int minor_version)
|
|
21
23
|
{
|
|
@@ -28,6 +30,14 @@ http_version_string(int minor_version)
|
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
static VALUE
|
|
34
|
+
http_method_string(const char *method, size_t method_len)
|
|
35
|
+
{
|
|
36
|
+
VALUE str = lookup_method(method, method_len);
|
|
37
|
+
if (str == Qnil) str = rb_str_new(method, method_len);
|
|
38
|
+
return str;
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
static VALUE
|
|
32
42
|
header_name_to_env_key(const char *name, size_t name_len)
|
|
33
43
|
{
|
|
@@ -35,12 +45,9 @@ header_name_to_env_key(const char *name, size_t name_len)
|
|
|
35
45
|
rb_raise(rb_ePicohttpParseError, "Header name too long");
|
|
36
46
|
}
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
if (name_len == 14 && strncasecmp(name, "content-length", 14) == 0) {
|
|
43
|
-
return rb_interned_str_cstr("CONTENT_LENGTH");
|
|
48
|
+
VALUE str = lookup_header(name, name_len);
|
|
49
|
+
if (str != Qnil) {
|
|
50
|
+
return str;
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
char env_name[MAX_HEADER_NAME_LEN + 6]; // "HTTP_" + name + null terminator
|
|
@@ -71,7 +78,7 @@ picohttp_parse_request(VALUE self, VALUE str)
|
|
|
71
78
|
|
|
72
79
|
const char *method, *path;
|
|
73
80
|
int minor_version;
|
|
74
|
-
struct phr_header headers[
|
|
81
|
+
struct phr_header headers[MAX_HEADERS];
|
|
75
82
|
size_t method_len, path_len, num_headers = sizeof(headers) / sizeof(headers[0]);
|
|
76
83
|
|
|
77
84
|
int result = phr_parse_request(buf, len, &method, &method_len, &path, &path_len,
|
|
@@ -112,7 +119,7 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
112
119
|
|
|
113
120
|
const char *method, *path;
|
|
114
121
|
int minor_version;
|
|
115
|
-
struct phr_header headers[
|
|
122
|
+
struct phr_header headers[MAX_HEADERS];
|
|
116
123
|
size_t method_len, path_len, num_headers = sizeof(headers) / sizeof(headers[0]);
|
|
117
124
|
|
|
118
125
|
int result = phr_parse_request(buf, len, &method, &method_len, &path, &path_len,
|
|
@@ -125,26 +132,33 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
125
132
|
rb_raise(rb_ePicohttpParseError, "Invalid HTTP request");
|
|
126
133
|
}
|
|
127
134
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
#else
|
|
131
|
-
VALUE env = rb_hash_new();
|
|
132
|
-
#endif
|
|
135
|
+
VALUE header_values[MAX_HEADERS * 2];
|
|
136
|
+
int idx = 0;
|
|
133
137
|
|
|
134
138
|
// Standard CGI/Rack environment variables
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
header_values[idx++] = rb_str_request_method;
|
|
140
|
+
header_values[idx++] = http_method_string(method, method_len);
|
|
141
|
+
|
|
142
|
+
header_values[idx++] = rb_str_server_protocol;
|
|
143
|
+
header_values[idx++] = http_version_string(minor_version);
|
|
137
144
|
|
|
138
145
|
// Parse path and query string in C
|
|
139
146
|
const char *query_start = memchr(path, '?', path_len);
|
|
140
147
|
if (query_start) {
|
|
141
148
|
size_t path_info_len = query_start - path;
|
|
142
149
|
size_t query_len = path_len - path_info_len - 1;
|
|
143
|
-
|
|
144
|
-
|
|
150
|
+
|
|
151
|
+
header_values[idx++] = rb_str_path_info;
|
|
152
|
+
header_values[idx++] = rb_str_new(path, path_info_len);
|
|
153
|
+
|
|
154
|
+
header_values[idx++] = rb_str_query_string;
|
|
155
|
+
header_values[idx++] = rb_str_new(query_start + 1, query_len);
|
|
145
156
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
header_values[idx++] = rb_str_path_info;
|
|
158
|
+
header_values[idx++] = rb_str_new(path, path_len);
|
|
159
|
+
|
|
160
|
+
header_values[idx++] = rb_str_query_string;
|
|
161
|
+
header_values[idx++] = rb_str_empty;
|
|
148
162
|
}
|
|
149
163
|
|
|
150
164
|
// Convert headers to HTTP_ prefixed environment variables
|
|
@@ -153,11 +167,18 @@ picohttp_parse_request_env(VALUE self, VALUE str)
|
|
|
153
167
|
rb_raise(rb_ePicohttpParseError, "HTTP line folding not supported");
|
|
154
168
|
}
|
|
155
169
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
rb_hash_aset(env, header_name, header_value);
|
|
170
|
+
header_values[idx++] = header_name_to_env_key(headers[i].name, headers[i].name_len);
|
|
171
|
+
header_values[idx++] = rb_str_new(headers[i].value, headers[i].value_len);
|
|
159
172
|
}
|
|
160
173
|
|
|
174
|
+
#ifdef HAVE_RB_HASH_NEW_CAPA
|
|
175
|
+
VALUE env = rb_hash_new_capa(idx / 2);
|
|
176
|
+
#else
|
|
177
|
+
VALUE env = rb_hash_new();
|
|
178
|
+
#endif
|
|
179
|
+
|
|
180
|
+
rb_hash_bulk_insert(idx, header_values, env);
|
|
181
|
+
|
|
161
182
|
return env;
|
|
162
183
|
}
|
|
163
184
|
|
|
@@ -174,6 +195,7 @@ Init_picohttp(void)
|
|
|
174
195
|
rb_define_module_function(rb_mPicohttp, "parse_request_env", picohttp_parse_request_env, 1);
|
|
175
196
|
|
|
176
197
|
// Initialize interned string constants
|
|
198
|
+
init_string_lookup();
|
|
177
199
|
rb_str_request_method = rb_interned_str_cstr("REQUEST_METHOD");
|
|
178
200
|
rb_str_server_protocol = rb_interned_str_cstr("SERVER_PROTOCOL");
|
|
179
201
|
rb_str_path_info = rb_interned_str_cstr("PATH_INFO");
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* This file is auto-generated by tool/generate_lookup.rb */
|
|
2
|
+
|
|
3
|
+
static VALUE rb_s_HTTP_HOST; /* "HTTP_HOST" */
|
|
4
|
+
static VALUE rb_s_HTTP_ACCEPT; /* "HTTP_ACCEPT" */
|
|
5
|
+
static VALUE rb_s_HTTP_COOKIE; /* "HTTP_COOKIE" */
|
|
6
|
+
static VALUE rb_s_HTTP_REFERER; /* "HTTP_REFERER" */
|
|
7
|
+
static VALUE rb_s_HTTP_USER_AGENT; /* "HTTP_USER_AGENT" */
|
|
8
|
+
static VALUE rb_s_HTTP_CONNECTION; /* "HTTP_CONNECTION" */
|
|
9
|
+
static VALUE rb_s_CONTENT_TYPE; /* "CONTENT_TYPE" */
|
|
10
|
+
static VALUE rb_s_HTTP_CACHE_CONTROL; /* "HTTP_CACHE_CONTROL" */
|
|
11
|
+
static VALUE rb_s_HTTP_AUTHORIZATION; /* "HTTP_AUTHORIZATION" */
|
|
12
|
+
static VALUE rb_s_CONTENT_LENGTH; /* "CONTENT_LENGTH" */
|
|
13
|
+
static VALUE rb_s_HTTP_ACCEPT_ENCODING; /* "HTTP_ACCEPT_ENCODING" */
|
|
14
|
+
static VALUE rb_s_HTTP_ACCEPT_LANGUAGE; /* "HTTP_ACCEPT_LANGUAGE" */
|
|
15
|
+
static VALUE rb_s_GET; /* "GET" */
|
|
16
|
+
static VALUE rb_s_PUT; /* "PUT" */
|
|
17
|
+
static VALUE rb_s_POST; /* "POST" */
|
|
18
|
+
static VALUE rb_s_HEAD; /* "HEAD" */
|
|
19
|
+
static VALUE rb_s_PATCH; /* "PATCH" */
|
|
20
|
+
static VALUE rb_s_DELETE; /* "DELETE" */
|
|
21
|
+
static VALUE rb_s_OPTIONS; /* "OPTIONS" */
|
|
22
|
+
|
|
23
|
+
static VALUE lookup_header(const char *s, size_t len) {
|
|
24
|
+
switch (len) {
|
|
25
|
+
case 4:
|
|
26
|
+
if ((s[0] | 32) == 'h' && (s[1] | 32) == 'o' && (s[2] | 32) == 's' && (s[3] | 32) == 't') return rb_s_HTTP_HOST;
|
|
27
|
+
break;
|
|
28
|
+
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 rb_s_HTTP_ACCEPT;
|
|
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 rb_s_HTTP_COOKIE;
|
|
31
|
+
break;
|
|
32
|
+
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 rb_s_HTTP_REFERER;
|
|
34
|
+
break;
|
|
35
|
+
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 rb_s_HTTP_USER_AGENT;
|
|
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 rb_s_HTTP_CONNECTION;
|
|
38
|
+
break;
|
|
39
|
+
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 rb_s_CONTENT_TYPE;
|
|
41
|
+
break;
|
|
42
|
+
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 rb_s_HTTP_CACHE_CONTROL;
|
|
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 rb_s_HTTP_AUTHORIZATION;
|
|
45
|
+
break;
|
|
46
|
+
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 rb_s_CONTENT_LENGTH;
|
|
48
|
+
break;
|
|
49
|
+
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 rb_s_HTTP_ACCEPT_ENCODING;
|
|
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 rb_s_HTTP_ACCEPT_LANGUAGE;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
return Qnil;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static VALUE lookup_method(const char *s, size_t len) {
|
|
58
|
+
switch (len) {
|
|
59
|
+
case 3:
|
|
60
|
+
if (s[0] == 'G' && s[1] == 'E' && s[2] == 'T') return rb_s_GET;
|
|
61
|
+
if (s[0] == 'P' && s[1] == 'U' && s[2] == 'T') return rb_s_PUT;
|
|
62
|
+
break;
|
|
63
|
+
case 4:
|
|
64
|
+
if (s[0] == 'P' && s[1] == 'O' && s[2] == 'S' && s[3] == 'T') return rb_s_POST;
|
|
65
|
+
if (s[0] == 'H' && s[1] == 'E' && s[2] == 'A' && s[3] == 'D') return rb_s_HEAD;
|
|
66
|
+
break;
|
|
67
|
+
case 5:
|
|
68
|
+
if (s[0] == 'P' && s[1] == 'A' && s[2] == 'T' && s[3] == 'C' && s[4] == 'H') return rb_s_PATCH;
|
|
69
|
+
break;
|
|
70
|
+
case 6:
|
|
71
|
+
if (s[0] == 'D' && s[1] == 'E' && s[2] == 'L' && s[3] == 'E' && s[4] == 'T' && s[5] == 'E') return rb_s_DELETE;
|
|
72
|
+
break;
|
|
73
|
+
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 rb_s_OPTIONS;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
return Qnil;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static void init_string_lookup(void) {
|
|
81
|
+
rb_gc_register_address(&rb_s_HTTP_HOST);
|
|
82
|
+
rb_s_HTTP_HOST = rb_interned_str_cstr("HTTP_HOST");
|
|
83
|
+
rb_gc_register_address(&rb_s_HTTP_ACCEPT);
|
|
84
|
+
rb_s_HTTP_ACCEPT = rb_interned_str_cstr("HTTP_ACCEPT");
|
|
85
|
+
rb_gc_register_address(&rb_s_HTTP_COOKIE);
|
|
86
|
+
rb_s_HTTP_COOKIE = rb_interned_str_cstr("HTTP_COOKIE");
|
|
87
|
+
rb_gc_register_address(&rb_s_HTTP_REFERER);
|
|
88
|
+
rb_s_HTTP_REFERER = rb_interned_str_cstr("HTTP_REFERER");
|
|
89
|
+
rb_gc_register_address(&rb_s_HTTP_USER_AGENT);
|
|
90
|
+
rb_s_HTTP_USER_AGENT = rb_interned_str_cstr("HTTP_USER_AGENT");
|
|
91
|
+
rb_gc_register_address(&rb_s_HTTP_CONNECTION);
|
|
92
|
+
rb_s_HTTP_CONNECTION = rb_interned_str_cstr("HTTP_CONNECTION");
|
|
93
|
+
rb_gc_register_address(&rb_s_CONTENT_TYPE);
|
|
94
|
+
rb_s_CONTENT_TYPE = rb_interned_str_cstr("CONTENT_TYPE");
|
|
95
|
+
rb_gc_register_address(&rb_s_HTTP_CACHE_CONTROL);
|
|
96
|
+
rb_s_HTTP_CACHE_CONTROL = rb_interned_str_cstr("HTTP_CACHE_CONTROL");
|
|
97
|
+
rb_gc_register_address(&rb_s_HTTP_AUTHORIZATION);
|
|
98
|
+
rb_s_HTTP_AUTHORIZATION = rb_interned_str_cstr("HTTP_AUTHORIZATION");
|
|
99
|
+
rb_gc_register_address(&rb_s_CONTENT_LENGTH);
|
|
100
|
+
rb_s_CONTENT_LENGTH = rb_interned_str_cstr("CONTENT_LENGTH");
|
|
101
|
+
rb_gc_register_address(&rb_s_HTTP_ACCEPT_ENCODING);
|
|
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");
|
|
119
|
+
}
|
|
120
|
+
|
data/lib/picohttp/version.rb
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Generates fast C lookup code for known string sets
|
|
5
|
+
|
|
6
|
+
puts "/* This file is auto-generated by #{__FILE__} */"
|
|
7
|
+
puts
|
|
8
|
+
|
|
9
|
+
class StringLookup
|
|
10
|
+
def initialize
|
|
11
|
+
@string_table = Hash.new do |h, k|
|
|
12
|
+
h[k] = name_for_string(k)
|
|
13
|
+
end
|
|
14
|
+
@functions = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def generate
|
|
18
|
+
@string_table.each do |v, name|
|
|
19
|
+
puts "static VALUE #{name}; /* #{v.inspect} */"
|
|
20
|
+
end
|
|
21
|
+
puts
|
|
22
|
+
|
|
23
|
+
@functions.each do |code|
|
|
24
|
+
puts code
|
|
25
|
+
puts
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
puts "static void init_string_lookup(void) {"
|
|
29
|
+
@string_table.each do |v, name|
|
|
30
|
+
puts " rb_gc_register_address(&#{name});"
|
|
31
|
+
puts " #{name} = rb_interned_str_cstr(#{v.dump});"
|
|
32
|
+
end
|
|
33
|
+
puts "}"
|
|
34
|
+
puts
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def name_for_string(string)
|
|
38
|
+
"rb_s_#{string.gsub(/[^a-z0-9]/i, "_")}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def generate_comparison(var, string, ignore_case: false)
|
|
42
|
+
0.upto(string.length - 1).map do |i|
|
|
43
|
+
if ignore_case
|
|
44
|
+
"(#{var}[#{i}] | 32) == '#{string[i].downcase}'"
|
|
45
|
+
else
|
|
46
|
+
"#{var}[#{i}] == '#{string[i]}'"
|
|
47
|
+
end
|
|
48
|
+
end.join(" && ")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def add_function(function, mapping, ignore_case: false)
|
|
52
|
+
if mapping.is_a?(Array)
|
|
53
|
+
mapping = mapping.map do |str|
|
|
54
|
+
[str, str]
|
|
55
|
+
end.to_h
|
|
56
|
+
end
|
|
57
|
+
by_length = mapping.group_by do |(k,v)|
|
|
58
|
+
k.length
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
code = []
|
|
62
|
+
code << "static VALUE lookup_#{function}(const char *s, size_t len) {"
|
|
63
|
+
code << " switch (len) {"
|
|
64
|
+
|
|
65
|
+
by_length.sort.each do |len, strs|
|
|
66
|
+
code << " case #{len}:"
|
|
67
|
+
strs.each do |match, target|
|
|
68
|
+
name = @string_table[target]
|
|
69
|
+
code << " if (#{generate_comparison("s", match, ignore_case:)}) return #{name};"
|
|
70
|
+
end
|
|
71
|
+
code << " break;"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
code << " }"
|
|
75
|
+
code << " return Qnil;"
|
|
76
|
+
code << "}"
|
|
77
|
+
|
|
78
|
+
@functions << code.join("\n")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
HEADERS = %w[Content-Type Content-Length Host User-Agent Accept Accept-Encoding
|
|
83
|
+
Accept-Language Connection Cache-Control Cookie Authorization Referer]
|
|
84
|
+
|
|
85
|
+
METHODS = %w[GET POST PUT DELETE HEAD OPTIONS PATCH]
|
|
86
|
+
|
|
87
|
+
lookup = StringLookup.new
|
|
88
|
+
header_mapping = HEADERS.map do |header|
|
|
89
|
+
header = header.downcase
|
|
90
|
+
rack_key = header.upcase.gsub("-", "_")
|
|
91
|
+
unless header == "content-type" || header == "content-length"
|
|
92
|
+
rack_key = "HTTP_#{rack_key}"
|
|
93
|
+
end
|
|
94
|
+
[header, rack_key]
|
|
95
|
+
end.to_h
|
|
96
|
+
lookup.add_function("header", header_mapping, ignore_case: true)
|
|
97
|
+
lookup.add_function("method", METHODS)
|
|
98
|
+
lookup.generate
|
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.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Hawthorn
|
|
@@ -27,8 +27,10 @@ files:
|
|
|
27
27
|
- ext/picohttp/picohttp.h
|
|
28
28
|
- ext/picohttp/picohttpparser.c
|
|
29
29
|
- ext/picohttp/picohttpparser.h
|
|
30
|
+
- ext/picohttp/string_lookup.inc
|
|
30
31
|
- lib/picohttp.rb
|
|
31
32
|
- lib/picohttp/version.rb
|
|
33
|
+
- tool/generate_lookup.rb
|
|
32
34
|
homepage: https://github.com/jhawthorn/picohttp
|
|
33
35
|
licenses:
|
|
34
36
|
- MIT
|
|
@@ -52,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
52
54
|
- !ruby/object:Gem::Version
|
|
53
55
|
version: '0'
|
|
54
56
|
requirements: []
|
|
55
|
-
rubygems_version:
|
|
57
|
+
rubygems_version: 4.0.2
|
|
56
58
|
specification_version: 4
|
|
57
59
|
summary: Fast HTTP request parser using picohttpparser
|
|
58
60
|
test_files: []
|