puma 7.2.0 → 8.0.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.
@@ -2,6 +2,7 @@ package org.jruby.puma;
2
2
 
3
3
  import org.jruby.Ruby;
4
4
  import org.jruby.RubyHash;
5
+ import org.jruby.RubyString;
5
6
  import org.jruby.util.ByteList;
6
7
 
7
8
  public class Http11Parser {
@@ -12,44 +13,44 @@ public class Http11Parser {
12
13
 
13
14
  machine puma_parser;
14
15
 
15
- action mark {parser.mark = fpc; }
16
+ action mark {this.mark = fpc; }
16
17
 
17
- action start_field { parser.field_start = fpc; }
18
- action snake_upcase_field { /* FIXME stub */ }
18
+ action start_field { this.field_start = fpc; }
19
+ action snake_upcase_field { /* done lazily as needed */ }
19
20
  action write_field {
20
- parser.field_len = fpc-parser.field_start;
21
+ this.field_len = fpc-this.field_start;
21
22
  }
22
23
 
23
- action start_value { parser.mark = fpc; }
24
+ action start_value { this.mark = fpc; }
24
25
  action write_value {
25
- Http11.http_field(runtime, parser.data, parser.buffer, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
26
+ Http11.http_field(runtime, envStrings, this, fpc-this.mark);
26
27
  }
27
28
  action request_method {
28
- Http11.request_method(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
29
+ Http11.request_method(runtime, envStrings, this, fpc-this.mark);
29
30
  }
30
31
  action request_uri {
31
- Http11.request_uri(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
32
+ Http11.request_uri(runtime, envStrings, this, fpc-this.mark);
32
33
  }
33
34
  action fragment {
34
- Http11.fragment(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
35
+ Http11.fragment(runtime, envStrings, this, fpc-this.mark);
35
36
  }
36
37
 
37
- action start_query {parser.query_start = fpc; }
38
+ action start_query {this.query_start = fpc; }
38
39
  action query_string {
39
- Http11.query_string(runtime, parser.data, parser.buffer, parser.query_start, fpc-parser.query_start);
40
+ Http11.query_string(runtime, envStrings, this, fpc-this.query_start);
40
41
  }
41
42
 
42
43
  action server_protocol {
43
- Http11.server_protocol(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
44
+ Http11.server_protocol(runtime, envStrings, this, fpc-this.mark);
44
45
  }
45
46
 
46
47
  action request_path {
47
- Http11.request_path(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
48
+ Http11.request_path(runtime, envStrings, this, fpc-this.mark);
48
49
  }
49
50
 
50
51
  action done {
51
- parser.body_start = fpc + 1;
52
- http.header_done(runtime, parser.data, parser.buffer, fpc + 1, pe - fpc - 1);
52
+ this.body_start = fpc + 1;
53
+ http.header_done(runtime, this, fpc + 1, pe - fpc - 1);
53
54
  fbreak;
54
55
  }
55
56
 
@@ -60,69 +61,54 @@ public class Http11Parser {
60
61
  /** Data **/
61
62
  %% write data noentry;
62
63
 
63
- public static interface ElementCB {
64
- public void call(Ruby runtime, RubyHash data, ByteList buffer, int at, int length);
65
- }
64
+ int cs;
65
+ int body_start;
66
+ int nread;
67
+ int mark;
68
+ int field_start;
69
+ int field_len;
70
+ int query_start;
66
71
 
67
- public static interface FieldCB {
68
- public void call(Ruby runtime, RubyHash data, ByteList buffer, int field, int flen, int value, int vlen);
69
- }
72
+ RubyHash data;
73
+ byte[] buffer;
70
74
 
71
- public static class HttpParser {
72
- int cs;
73
- int body_start;
74
- int content_len;
75
- int nread;
76
- int mark;
77
- int field_start;
78
- int field_len;
79
- int query_start;
80
-
81
- RubyHash data;
82
- ByteList buffer;
83
-
84
- public void init() {
85
- cs = 0;
86
-
87
- %% write init;
88
-
89
- body_start = 0;
90
- content_len = 0;
91
- mark = 0;
92
- nread = 0;
93
- field_len = 0;
94
- field_start = 0;
95
- }
96
- }
75
+ public void init() {
97
76
 
98
- public final HttpParser parser = new HttpParser();
77
+ %% write init;
78
+
79
+ body_start = 0;
80
+ mark = 0;
81
+ nread = 0;
82
+ field_len = 0;
83
+ field_start = 0;
84
+ }
99
85
 
100
86
  public int execute(Ruby runtime, Http11 http, ByteList buffer, int off) {
101
87
  int p, pe;
102
- int cs = parser.cs;
88
+ int cs = this.cs;
103
89
  int len = buffer.length();
90
+ int beg = buffer.begin();
91
+ RubyString[] envStrings = http.envStrings;
104
92
  assert off<=len : "offset past end of buffer";
105
93
 
106
- p = off;
107
- pe = len;
108
- // get a copy of the bytes, since it may not start at 0
109
- // FIXME: figure out how to just use the bytes in-place
110
- byte[] data = buffer.bytes();
111
- parser.buffer = buffer;
94
+ p = beg + off;
95
+ pe = beg + len;
96
+ byte[] data = buffer.unsafeBytes();
97
+ this.buffer = data;
112
98
 
113
99
  %% write exec;
114
100
 
115
- parser.cs = cs;
116
- parser.nread += (p - off);
101
+ this.cs = cs;
102
+ this.nread += (p - off);
117
103
 
118
104
  assert p <= pe : "buffer overflow after parsing execute";
119
- assert parser.nread <= len : "nread longer than length";
120
- assert parser.body_start <= len : "body starts after buffer end";
121
- assert parser.mark < len : "mark is after buffer end";
122
- assert parser.field_len <= len : "field has length longer than whole buffer";
123
- assert parser.field_start < len : "field starts after buffer end";
105
+ assert this.nread <= len : "nread longer than length";
106
+ assert this.body_start <= len : "body starts after buffer end";
107
+ assert this.mark < len : "mark is after buffer end";
108
+ assert this.field_len <= len : "field has length longer than whole buffer";
109
+ assert this.field_start < len : "field starts after buffer end";
124
110
 
125
- return parser.nread;
111
+ return this.nread;
126
112
  }
127
113
 
128
114
  public int finish() {
@@ -136,10 +122,10 @@ public class Http11Parser {
136
122
  }
137
123
 
138
124
  public boolean has_error() {
139
- return parser.cs == puma_parser_error;
125
+ return this.cs == puma_parser_error;
140
126
  }
141
127
 
142
128
  public boolean is_finished() {
143
- return parser.cs == puma_parser_first_final;
129
+ return this.cs == puma_parser_first_final;
144
130
  }
145
131
  }
@@ -0,0 +1,241 @@
1
+ package org.jruby.puma;
2
+
3
+ import org.jruby.util.ByteList;
4
+
5
+ import java.nio.charset.StandardCharsets;
6
+
7
+ /**
8
+ * A set of keys representing HTTP/1.1 header fields and CGI env keys.
9
+ *
10
+ * The set of header fields is derived from RFC 2616 with some additions
11
+ * common to mainstream browsers.
12
+ *
13
+ * This enum is used by {@link Http11 }to access pre-allocated strings for
14
+ * Puma's version of these keys and includes a perfect hash function to quickly
15
+ * find the key for a given range of bytes.
16
+ */
17
+ public enum EnvKey {
18
+ ACCEPT,
19
+ ACCEPT_CHARSET,
20
+ ACCEPT_ENCODING,
21
+ ACCEPT_LANGUAGE,
22
+ ACCEPT_RANGES,
23
+ AGE,
24
+ ALLOW,
25
+ AUTHORIZATION,
26
+ CACHE_CONTROL,
27
+ CONNECTION,
28
+ CONTENT_ENCODING,
29
+ CONTENT_LANGUAGE,
30
+ CONTENT_LENGTH(true),
31
+ CONTENT_LOCATION,
32
+ CONTENT_MD5,
33
+ CONTENT_RANGE,
34
+ CONTENT_TYPE(true),
35
+ DATE,
36
+ ETAG,
37
+ EXPECT,
38
+ EXPIRES,
39
+ FRAGMENT(true),
40
+ FROM,
41
+ HOST,
42
+ IF_MATCH,
43
+ IF_MODIFIED_SINCE,
44
+ IF_NONE_MATCH,
45
+ IF_RANGE,
46
+ IF_UNMODIFIED_SINCE,
47
+ KEEP_ALIVE,
48
+ LAST_MODIFIED,
49
+ LOCATION,
50
+ MAX_FORWARDS,
51
+ PRAGMA,
52
+ PROXY_AUTHENTICATE,
53
+ PROXY_AUTHORIZATION,
54
+ QUERY_STRING(true),
55
+ RANGE,
56
+ REFERER,
57
+ REQUEST_METHOD(true),
58
+ REQUEST_PATH(true),
59
+ REQUEST_URI(true),
60
+ RETRY_AFTER,
61
+ SERVER,
62
+ SERVER_PROTOCOL(true),
63
+ TE,
64
+ TRAILER,
65
+ TRANSFER_ENCODING,
66
+ UPGRADE,
67
+ USER_AGENT,
68
+ VARY,
69
+ VIA,
70
+ X_FORWARDED_FOR,
71
+ X_REAL_IP,
72
+ WARNING,
73
+ WWW_AUTHENTICATE;
74
+
75
+ final ByteList httpName;
76
+
77
+ EnvKey() {
78
+ this(false);
79
+ }
80
+
81
+ EnvKey(boolean raw) {
82
+ String httpName = raw ? name() : "HTTP_" + name();
83
+ this.httpName = new ByteList(ByteList.plain(httpName), false);
84
+ }
85
+
86
+ /**
87
+ * Using a perfect hash, find the EnvKey for a given field name, or null if none matches.
88
+ *
89
+ * Generated by the gperf tool as C and adapted to Java. Must be regenerated if the set of keys changes.
90
+ *
91
+ * @param buffer the buffer containing the field name
92
+ * @param start the starting offset of the field name
93
+ * @param len the length of the field name
94
+ * @return the matching EnvKey, or else null
95
+ */
96
+ public static EnvKey keyForField(byte[] buffer, int start, int len) {
97
+ int key = hash(buffer, start, len);
98
+
99
+ if (key <= MAX_HASH_VALUE) {
100
+ EnvKey match = keyList[key];
101
+
102
+ if (match != null && equalsIgnoreCase(buffer, start, len, match.name())) {
103
+ return match;
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+
109
+ private static boolean equalsIgnoreCase(byte[] buf, int start, int len, String key) {
110
+ int slen = key.length();
111
+ if (len != slen) return false;
112
+ for (int i = 0; i < slen; i++) {
113
+ byte b1 = buf[start + i];
114
+ byte b2 = (byte) key.charAt(i);
115
+ if (Http11.snakeUpcase(b1) != b2) return false;
116
+ }
117
+ return true;
118
+ }
119
+
120
+ private static int hash(byte[] buffer, int start, int len) {
121
+ return len
122
+ + asso_values[Byte.toUnsignedInt(Http11.snakeUpcase(buffer[start + len - 1]))]
123
+ + asso_values[Byte.toUnsignedInt(Http11.snakeUpcase(buffer[start]))];
124
+ }
125
+
126
+ private static final int MAX_HASH_VALUE = 94;
127
+
128
+ private final static int[] asso_values = {
129
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
130
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
131
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
132
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
133
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
134
+ 95, 95, 95, 10, 95, 95, 95, 95, 95, 95,
135
+ 95, 95, 95, 95, 95, 5, 95, 15, 40, 0,
136
+ 0, 10, 10, 15, 95, 0, 20, 5, 25, 95,
137
+ 50, 40, 0, 40, 10, 35, 5, 35, 0, 10,
138
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
139
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
140
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
141
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
142
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
143
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
144
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
145
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
146
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
147
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
148
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
149
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
150
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
151
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
152
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
153
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
154
+ 95, 95, 95, 95, 95, 95
155
+ };
156
+
157
+ private static final EnvKey[] keyList = {
158
+ null, null, null, null, null,
159
+ EnvKey.RANGE,
160
+ null,
161
+ EnvKey.REFERER,
162
+ EnvKey.AGE,
163
+ EnvKey.FROM,
164
+ EnvKey.KEEP_ALIVE,
165
+ EnvKey.RETRY_AFTER,
166
+ EnvKey.TE,
167
+ EnvKey.VIA,
168
+ EnvKey.ETAG,
169
+ EnvKey.X_FORWARDED_FOR,
170
+ EnvKey.EXPECT,
171
+ EnvKey.TRAILER,
172
+ EnvKey.FRAGMENT,
173
+ EnvKey.VARY,
174
+ EnvKey.ACCEPT_LANGUAGE,
175
+ EnvKey.ACCEPT,
176
+ EnvKey.REQUEST_PATH,
177
+ EnvKey.IF_RANGE,
178
+ EnvKey.HOST,
179
+ null,
180
+ EnvKey.REQUEST_URI,
181
+ EnvKey.CONTENT_TYPE,
182
+ EnvKey.CONTENT_RANGE,
183
+ EnvKey.ACCEPT_CHARSET,
184
+ EnvKey.ACCEPT_ENCODING,
185
+ EnvKey.CONTENT_LANGUAGE,
186
+ EnvKey.IF_MODIFIED_SINCE,
187
+ EnvKey.IF_MATCH,
188
+ EnvKey.IF_UNMODIFIED_SINCE,
189
+ null,
190
+ EnvKey.CONTENT_MD5,
191
+ EnvKey.TRANSFER_ENCODING,
192
+ EnvKey.IF_NONE_MATCH,
193
+ EnvKey.CONTENT_LENGTH,
194
+ null,
195
+ EnvKey.CONTENT_ENCODING,
196
+ EnvKey.UPGRADE,
197
+ EnvKey.AUTHORIZATION,
198
+ EnvKey.DATE,
199
+ EnvKey.ALLOW,
200
+ EnvKey.SERVER,
201
+ EnvKey.EXPIRES,
202
+ EnvKey.CACHE_CONTROL,
203
+ null,
204
+ EnvKey.CONNECTION,
205
+ EnvKey.WWW_AUTHENTICATE,
206
+ EnvKey.WARNING,
207
+ EnvKey.LOCATION,
208
+ EnvKey.REQUEST_METHOD,
209
+ EnvKey.USER_AGENT,
210
+ EnvKey.CONTENT_LOCATION,
211
+ EnvKey.MAX_FORWARDS,
212
+ EnvKey.ACCEPT_RANGES,
213
+ EnvKey.X_REAL_IP,
214
+ null,
215
+ EnvKey.PRAGMA,
216
+ EnvKey.QUERY_STRING,
217
+ null, null, null, null, null,
218
+ EnvKey.PROXY_AUTHENTICATE,
219
+ null, null, null, null,
220
+ EnvKey.LAST_MODIFIED,
221
+ null,
222
+ EnvKey.SERVER_PROTOCOL,
223
+ null, null, null, null, null, null, null, null, null,
224
+ null, null, null, null, null, null, null, null, null,
225
+ EnvKey.PROXY_AUTHORIZATION
226
+ };
227
+
228
+ static {
229
+ // The perfect hash function must be regenerated if the list above changes
230
+ for (EnvKey key : values()) {
231
+ EnvKey found;
232
+ assert (found = keyForKey(key)) == key : key + " was not matched by perfect hash and found " + found;
233
+ }
234
+ }
235
+
236
+ // Only used for verification of the perfect hash, at boot with asserts enabled.
237
+ private static EnvKey keyForKey(EnvKey key) {
238
+ byte[] bytes = key.name().getBytes(StandardCharsets.ISO_8859_1);
239
+ return keyList[hash(bytes, 0, bytes.length)];
240
+ }
241
+ }