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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a11d937822d71f87cd78734c038f1a73a25af902b142958208af81b3397f3be
4
- data.tar.gz: 21d3337883257c321b37c602d52c7ab68896343d856bfafaec329476b43c35fe
3
+ metadata.gz: 3b357892a265429f3731c5cc68f56aaa3649b1f346a9c86f021bb67be2e601ac
4
+ data.tar.gz: 7a499b9fe596ee583c238956d66f05f3ff6caeabd0594a5db1d0f3c1b6d3e023
5
5
  SHA512:
6
- metadata.gz: 5e73eead0ddf6378830a445562e827a77f235e1f26d37d18c7956ec790652c9f8efb23b82385d90c512dc47a864b796b8f9f7c2826e5f724dcaae63d45c39d43
7
- data.tar.gz: 92893c74ac27005fc38891c49ce4c2a5c72e0f7fd453fce38871ab5b626db8cc10f000263c01573b7cceac331dbf4f5089ee413ec71f3839cede7fa0bc29693e
6
+ metadata.gz: 704efdbcbd2daab576977d4f2857307a7de44a41b5785cc6d215886777b7d97e3e3ba257670e40afd4c0b49f05024c8e1b26f1a8a41864e5b70393736a26fe6a
7
+ data.tar.gz: 7318f991db2981ed09349edfd907141342121fa65f3a45fa0e51dc2503b973b1c83681356eacad29fd1f95c44af130ad1eb0952e52ae04e4a139678bf172d016
@@ -2,7 +2,7 @@
2
2
  #include "picohttpparser.h"
3
3
 
4
4
  #define MAX_HEADER_NAME_LEN 256
5
- #define ENV_HASH_INITIAL_CAPACITY 64
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
- // Special cases for Content-Type and Content-Length (no HTTP_ prefix)
39
- if (name_len == 12 && strncasecmp(name, "content-type", 12) == 0) {
40
- return rb_interned_str_cstr("CONTENT_TYPE");
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[100];
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[100];
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
- #ifdef HAVE_RB_HASH_NEW_CAPA
129
- VALUE env = rb_hash_new_capa(ENV_HASH_INITIAL_CAPACITY);
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
- rb_hash_aset(env, rb_str_request_method, rb_str_new(method, method_len));
136
- rb_hash_aset(env, rb_str_server_protocol, http_version_string(minor_version));
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
- rb_hash_aset(env, rb_str_path_info, rb_str_new(path, path_info_len));
144
- rb_hash_aset(env, rb_str_query_string, rb_str_new(query_start + 1, query_len));
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
- rb_hash_aset(env, rb_str_path_info, rb_str_new(path, path_len));
147
- rb_hash_aset(env, rb_str_query_string, rb_str_empty);
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
- VALUE header_name = header_name_to_env_key(headers[i].name, headers[i].name_len);
157
- VALUE header_value = rb_str_new(headers[i].value, headers[i].value_len);
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
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Picohttp
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -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.1.1
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: 3.6.9
57
+ rubygems_version: 4.0.2
56
58
  specification_version: 4
57
59
  summary: Fast HTTP request parser using picohttpparser
58
60
  test_files: []