http_parser.rb 0.5.1-java → 0.5.2-java
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +6 -6
- data/LICENSE-MIT +20 -0
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +68 -11
- data/ext/ruby_http_parser/ruby_http_parser.c +74 -6
- data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +26 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/README.md +23 -143
- data/ext/ruby_http_parser/vendor/http-parser-java/TODO +3 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +74 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +115 -61
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +19 -3
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java +8 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +34 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +12 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +4 -2
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +64 -52
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +5 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +323 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/{lolevel/Util.java → Util.java} +27 -28
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +259 -85
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +324 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +69 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +51 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +15 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +47 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +183 -447
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +61 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +26 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +165 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +58 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/test.c +232 -29
- data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +154 -7
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +17 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +52 -10
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +3 -1
- data/ext/ruby_http_parser/vendor/http-parser/test.c +89 -3
- data/http_parser.rb.gemspec +8 -2
- data/lib/http_parser.rb +17 -0
- data/spec/parser_spec.rb +97 -6
- data/tasks/compile.rake +3 -1
- metadata +40 -27
- data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +0 -4
@@ -1,35 +1,34 @@
|
|
1
|
-
package http_parser
|
1
|
+
package http_parser;
|
2
2
|
|
3
3
|
import java.nio.ByteBuffer;
|
4
|
-
import http_parser.HTTPException;
|
5
4
|
|
6
5
|
public class Util {
|
7
|
-
public static String toString(HTTPParser p) {
|
8
|
-
StringBuilder builder = new StringBuilder();
|
9
|
-
|
10
|
-
// the stuff up to the break is ephermeral and only meaningful
|
11
|
-
// while the parser is parsing. In general, this method is
|
12
|
-
// probably only useful during debugging.
|
13
|
-
|
14
|
-
builder.append("state :"); builder.append(p.state); builder.append("\n");
|
15
|
-
builder.append("header_state :"); builder.append(p.header_state); builder.append("\n");
|
16
|
-
builder.append("strict :"); builder.append(p.strict); builder.append("\n");
|
17
|
-
builder.append("index :"); builder.append(p.index); builder.append("\n");
|
18
|
-
builder.append("flags :"); builder.append(p.flags); builder.append("\n");
|
19
|
-
builder.append("nread :"); builder.append(p.nread); builder.append("\n");
|
20
|
-
builder.append("content_length :"); builder.append(p.content_length); builder.append("\n");
|
21
|
-
|
22
|
-
|
23
|
-
builder.append("type :"); builder.append(p.type); builder.append("\n");
|
24
|
-
builder.append("http_major :"); builder.append(p.http_major); builder.append("\n");
|
25
|
-
builder.append("http_minor :"); builder.append(p.http_minor); builder.append("\n");
|
26
|
-
builder.append("status_code :"); builder.append(p.status_code); builder.append("\n");
|
27
|
-
builder.append("method :"); builder.append(p.method); builder.append("\n");
|
28
|
-
builder.append("upgrade :"); builder.append(p.upgrade); builder.append("\n");
|
29
|
-
|
30
|
-
return builder.toString();
|
31
|
-
|
32
|
-
}
|
6
|
+
// public static String toString(http_parser.lolevel.HTTPParser p) {
|
7
|
+
// StringBuilder builder = new StringBuilder();
|
8
|
+
//
|
9
|
+
// // the stuff up to the break is ephermeral and only meaningful
|
10
|
+
// // while the parser is parsing. In general, this method is
|
11
|
+
// // probably only useful during debugging.
|
12
|
+
//
|
13
|
+
// builder.append("state :"); builder.append(p.state); builder.append("\n");
|
14
|
+
// builder.append("header_state :"); builder.append(p.header_state); builder.append("\n");
|
15
|
+
// builder.append("strict :"); builder.append(p.strict); builder.append("\n");
|
16
|
+
// builder.append("index :"); builder.append(p.index); builder.append("\n");
|
17
|
+
// builder.append("flags :"); builder.append(p.flags); builder.append("\n");
|
18
|
+
// builder.append("nread :"); builder.append(p.nread); builder.append("\n");
|
19
|
+
// builder.append("content_length :"); builder.append(p.content_length); builder.append("\n");
|
20
|
+
//
|
21
|
+
//
|
22
|
+
// builder.append("type :"); builder.append(p.type); builder.append("\n");
|
23
|
+
// builder.append("http_major :"); builder.append(p.http_major); builder.append("\n");
|
24
|
+
// builder.append("http_minor :"); builder.append(p.http_minor); builder.append("\n");
|
25
|
+
// builder.append("status_code :"); builder.append(p.status_code); builder.append("\n");
|
26
|
+
// builder.append("method :"); builder.append(p.method); builder.append("\n");
|
27
|
+
// builder.append("upgrade :"); builder.append(p.upgrade); builder.append("\n");
|
28
|
+
//
|
29
|
+
// return builder.toString();
|
30
|
+
//
|
31
|
+
// }
|
33
32
|
|
34
33
|
public static String error (String mes, ByteBuffer b, int begining) {
|
35
34
|
// the error message should look like this:
|
data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java
CHANGED
@@ -22,19 +22,21 @@ public class HTTPParser {
|
|
22
22
|
int nread;
|
23
23
|
int content_length;
|
24
24
|
|
25
|
-
|
25
|
+
int start_position;
|
26
|
+
ByteBuffer data;
|
27
|
+
|
26
28
|
/** READ-ONLY **/
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
public int http_major;
|
30
|
+
public int http_minor;
|
31
|
+
public int status_code; /* responses only */
|
32
|
+
public HTTPMethod method; /* requests only */
|
31
33
|
|
32
34
|
/* true = Upgrade header was present and the parser has exited because of that.
|
33
35
|
* false = No upgrade header present.
|
34
36
|
* Should be checked when http_parser_execute() returns in addition to
|
35
37
|
* error checking.
|
36
38
|
*/
|
37
|
-
|
39
|
+
public boolean upgrade;
|
38
40
|
|
39
41
|
/** PUBLIC **/
|
40
42
|
// TODO : this is used in c to maintain application state.
|
@@ -95,21 +97,39 @@ public class HTTPParser {
|
|
95
97
|
* correctly (obviously) and a will be updated approriately when the
|
96
98
|
* method returns to reflect the consumed data.
|
97
99
|
*/
|
98
|
-
public
|
100
|
+
public int execute(ParserSettings settings, ByteBuffer data) {
|
99
101
|
|
100
102
|
int p = data.position();
|
101
103
|
int p_err = p; // this is used for pretty printing errors.
|
104
|
+
|
105
|
+
this.start_position = p;
|
106
|
+
this.data = data;
|
102
107
|
|
103
108
|
// In case the headers don't provide information about the content
|
104
109
|
// length, `execute` needs to be called with an empty buffer to
|
105
110
|
// indicate that all the data has been send be the client/server,
|
106
111
|
// else there is no way of knowing the message is complete.
|
107
112
|
int len = (data.limit() - data.position());
|
108
|
-
|
109
|
-
if (State.body_identity_eof == state) {
|
110
|
-
settings.call_on_message_complete(this);
|
111
|
-
}
|
112
|
-
|
113
|
+
if (0 == len) {
|
114
|
+
// if (State.body_identity_eof == state) {
|
115
|
+
// settings.call_on_message_complete(this);
|
116
|
+
// }
|
117
|
+
switch (state) {
|
118
|
+
case body_identity_eof:
|
119
|
+
settings.call_on_message_complete(this);
|
120
|
+
return data.position() - start_position;
|
121
|
+
|
122
|
+
case dead:
|
123
|
+
case start_res_or_res:
|
124
|
+
case start_res:
|
125
|
+
case start_req:
|
126
|
+
return data.position() - start_position;
|
127
|
+
|
128
|
+
default:
|
129
|
+
// should we really consider this an error!?
|
130
|
+
throw new HTTPException("empty bytes! "+state); // error
|
131
|
+
}
|
132
|
+
}
|
113
133
|
|
114
134
|
|
115
135
|
// in case the _previous_ call to the parser only has data to get to
|
@@ -151,6 +171,7 @@ public class HTTPParser {
|
|
151
171
|
int pe = data.limit();
|
152
172
|
|
153
173
|
byte ch = data.get(); // the current character to process.
|
174
|
+
int chi = ch & 0xff; // utility, ch without signedness for table lookups.
|
154
175
|
byte c = -1; // utility variably used for up- and downcasing etc.
|
155
176
|
int to_read = 0; // used to keep track of how much of body, etc. is left to read
|
156
177
|
|
@@ -158,9 +179,10 @@ public class HTTPParser {
|
|
158
179
|
++nread;
|
159
180
|
if (nread > HTTP_MAX_HEADER_SIZE) {
|
160
181
|
settings.call_on_error(this, "possible buffer overflow", data, p_err);
|
182
|
+
return error();
|
161
183
|
}
|
162
184
|
}
|
163
|
-
|
185
|
+
//p(state + ":" + ch +":"+p);
|
164
186
|
switch (state) {
|
165
187
|
/*
|
166
188
|
* this state is used after a 'Connection: close' message
|
@@ -168,6 +190,7 @@ public class HTTPParser {
|
|
168
190
|
*/
|
169
191
|
case dead:
|
170
192
|
settings.call_on_error(this, "Connection already closed", data, p_err);
|
193
|
+
return error();
|
171
194
|
|
172
195
|
|
173
196
|
|
@@ -187,6 +210,7 @@ public class HTTPParser {
|
|
187
210
|
method = start_req_method_assign(ch);
|
188
211
|
if (null == method) {
|
189
212
|
settings.call_on_error(this, "invalid method", data, p_err);
|
213
|
+
return error();
|
190
214
|
}
|
191
215
|
index = 1;
|
192
216
|
state = State.req_method;
|
@@ -202,6 +226,7 @@ public class HTTPParser {
|
|
202
226
|
} else {
|
203
227
|
if (E != ch) {
|
204
228
|
settings.call_on_error(this, "not E", data, p_err);
|
229
|
+
return error();
|
205
230
|
}
|
206
231
|
type = ParserType.HTTP_REQUEST;
|
207
232
|
method = HTTPMethod.HTTP_HEAD;
|
@@ -227,6 +252,7 @@ public class HTTPParser {
|
|
227
252
|
break;
|
228
253
|
default:
|
229
254
|
settings.call_on_error(this, "Not H or CR/LF", data, p_err);
|
255
|
+
return error();
|
230
256
|
}
|
231
257
|
break;
|
232
258
|
|
@@ -235,24 +261,28 @@ public class HTTPParser {
|
|
235
261
|
case res_H:
|
236
262
|
if (strict && T != ch) {
|
237
263
|
settings.call_on_error(this, "Not T", data, p_err);
|
264
|
+
return error();
|
238
265
|
}
|
239
266
|
state = State.res_HT;
|
240
267
|
break;
|
241
268
|
case res_HT:
|
242
269
|
if (strict && T != ch) {
|
243
270
|
settings.call_on_error(this, "Not T2", data, p_err);
|
271
|
+
return error();
|
244
272
|
}
|
245
273
|
state = State.res_HTT;
|
246
274
|
break;
|
247
275
|
case res_HTT:
|
248
276
|
if (strict && P != ch) {
|
249
277
|
settings.call_on_error(this, "Not P", data, p_err);
|
278
|
+
return error();
|
250
279
|
}
|
251
280
|
state = State.res_HTTP;
|
252
281
|
break;
|
253
282
|
case res_HTTP:
|
254
283
|
if (strict && SLASH != ch) {
|
255
284
|
settings.call_on_error(this, "Not '/'", data, p_err);
|
285
|
+
return error();
|
256
286
|
}
|
257
287
|
state = State.res_first_http_major;
|
258
288
|
break;
|
@@ -262,6 +292,7 @@ public class HTTPParser {
|
|
262
292
|
case res_first_http_major:
|
263
293
|
if (!isDigit(ch)) {
|
264
294
|
settings.call_on_error(this, "Not a digit", data, p_err);
|
295
|
+
return error();
|
265
296
|
}
|
266
297
|
http_major = (int) ch - 0x30;
|
267
298
|
state = State.res_http_major;
|
@@ -270,17 +301,19 @@ public class HTTPParser {
|
|
270
301
|
/* major HTTP version or dot */
|
271
302
|
case res_http_major:
|
272
303
|
if (DOT == ch) {
|
273
|
-
state = State.
|
304
|
+
state = State.res_first_http_minor;
|
274
305
|
break;
|
275
306
|
}
|
276
307
|
if (!isDigit(ch)) {
|
277
308
|
settings.call_on_error(this, "Not a digit", data, p_err);
|
309
|
+
return error();
|
278
310
|
}
|
279
311
|
http_major *= 10;
|
280
312
|
http_major += (ch - 0x30);
|
281
313
|
|
282
314
|
if (http_major > 999) {
|
283
315
|
settings.call_on_error(this, "invalid http major version: "+http_major, data, p_err);
|
316
|
+
return error();
|
284
317
|
}
|
285
318
|
break;
|
286
319
|
|
@@ -288,6 +321,7 @@ public class HTTPParser {
|
|
288
321
|
case res_first_http_minor:
|
289
322
|
if (!isDigit(ch)) {
|
290
323
|
settings.call_on_error(this, "Not a digit", data, p_err);
|
324
|
+
return error();
|
291
325
|
}
|
292
326
|
http_minor = (int)ch - 0x30;
|
293
327
|
state = State.res_http_minor;
|
@@ -301,12 +335,13 @@ public class HTTPParser {
|
|
301
335
|
}
|
302
336
|
if (!isDigit(ch)) {
|
303
337
|
settings.call_on_error(this, "Not a digit", data, p_err);
|
338
|
+
return error();
|
304
339
|
}
|
305
340
|
http_minor *= 10;
|
306
341
|
http_minor += (ch - 0x30);
|
307
|
-
|
308
342
|
if (http_minor > 999) {
|
309
343
|
settings.call_on_error(this, "invalid http minor version: "+http_minor, data, p_err);
|
344
|
+
return error();
|
310
345
|
}
|
311
346
|
break;
|
312
347
|
|
@@ -318,6 +353,7 @@ public class HTTPParser {
|
|
318
353
|
break;
|
319
354
|
}
|
320
355
|
settings.call_on_error(this, "Not a digit (status code)", data, p_err);
|
356
|
+
return error();
|
321
357
|
}
|
322
358
|
status_code = (int)ch - 0x30;
|
323
359
|
state = State.res_status_code;
|
@@ -337,6 +373,7 @@ public class HTTPParser {
|
|
337
373
|
break;
|
338
374
|
default:
|
339
375
|
settings.call_on_error(this, "not a valid status code", data, p_err);
|
376
|
+
return error();
|
340
377
|
}
|
341
378
|
break;
|
342
379
|
}
|
@@ -344,6 +381,7 @@ public class HTTPParser {
|
|
344
381
|
status_code += (int)ch - 0x30;
|
345
382
|
if (status_code > 999) {
|
346
383
|
settings.call_on_error(this, "ridiculous status code:"+status_code, data, p_err);
|
384
|
+
return error();
|
347
385
|
}
|
348
386
|
break;
|
349
387
|
|
@@ -365,6 +403,7 @@ public class HTTPParser {
|
|
365
403
|
case res_line_almost_done:
|
366
404
|
if (strict && LF != ch) {
|
367
405
|
settings.call_on_error(this, "not LF", data, p_err);
|
406
|
+
return error();
|
368
407
|
}
|
369
408
|
state = State.header_field_start;
|
370
409
|
break;
|
@@ -372,7 +411,7 @@ public class HTTPParser {
|
|
372
411
|
|
373
412
|
|
374
413
|
case start_req:
|
375
|
-
if (CR==ch || LF ==
|
414
|
+
if (CR==ch || LF == ch) {
|
376
415
|
break;
|
377
416
|
}
|
378
417
|
flags = 0;
|
@@ -381,6 +420,7 @@ public class HTTPParser {
|
|
381
420
|
method = start_req_method_assign(ch);
|
382
421
|
if (null == method) {
|
383
422
|
settings.call_on_error(this, "invalid method", data, p_err);
|
423
|
+
return error();
|
384
424
|
}
|
385
425
|
index = 1;
|
386
426
|
state = State.req_method;
|
@@ -391,6 +431,7 @@ public class HTTPParser {
|
|
391
431
|
case req_method:
|
392
432
|
if (0 == ch) {
|
393
433
|
settings.call_on_error(this, "NULL in method", data, p_err);
|
434
|
+
return error();
|
394
435
|
}
|
395
436
|
|
396
437
|
byte [] arr = method.bytes;
|
@@ -410,6 +451,8 @@ public class HTTPParser {
|
|
410
451
|
method = HTTPMethod.HTTP_MOVE;
|
411
452
|
} else if (1 == index && E == ch) {
|
412
453
|
method = HTTPMethod.HTTP_MERGE;
|
454
|
+
} else if (1 == index && DASH == ch) { /* M-SEARCH */
|
455
|
+
method = HTTPMethod.HTTP_MSEARCH;
|
413
456
|
} else if (2 == index && A == ch) {
|
414
457
|
method = HTTPMethod.HTTP_MKACTIVITY;
|
415
458
|
}
|
@@ -417,10 +460,13 @@ public class HTTPParser {
|
|
417
460
|
method = HTTPMethod.HTTP_PROPFIND;
|
418
461
|
} else if (1 == index && HTTPMethod.HTTP_POST == method && U == ch) {
|
419
462
|
method = HTTPMethod.HTTP_PUT;
|
463
|
+
} else if (2 == index && HTTPMethod.HTTP_UNLOCK == method && S == ch) {
|
464
|
+
method = HTTPMethod.HTTP_UNSUBSCRIBE;
|
420
465
|
} else if (4 == index && HTTPMethod.HTTP_PROPFIND == method && P == ch) {
|
421
466
|
method = HTTPMethod.HTTP_PROPPATCH;
|
422
467
|
} else {
|
423
468
|
settings.call_on_error(this, "Invalid HTTP method", data, p_err);
|
469
|
+
return error();
|
424
470
|
}
|
425
471
|
|
426
472
|
++index;
|
@@ -433,7 +479,7 @@ public class HTTPParser {
|
|
433
479
|
if (SPACE == ch) {
|
434
480
|
break;
|
435
481
|
}
|
436
|
-
if (SLASH == ch) {
|
482
|
+
if (SLASH == ch || STAR == ch) {
|
437
483
|
url_mark = p;
|
438
484
|
path_mark = p;
|
439
485
|
state = State.req_path;
|
@@ -445,6 +491,7 @@ public class HTTPParser {
|
|
445
491
|
break;
|
446
492
|
}
|
447
493
|
settings.call_on_error(this, "Invalid something", data, p_err);
|
494
|
+
return error();
|
448
495
|
|
449
496
|
case req_schema:
|
450
497
|
if (isAtoZ(ch)){
|
@@ -453,15 +500,17 @@ public class HTTPParser {
|
|
453
500
|
if (COLON == ch) {
|
454
501
|
state = State.req_schema_slash;
|
455
502
|
break;
|
456
|
-
} else if (DOT == ch) {
|
503
|
+
} else if (DOT == ch || isDigit(ch)) {
|
457
504
|
state = State.req_host;
|
458
505
|
break;
|
459
506
|
}
|
460
507
|
settings.call_on_error(this, "invalid char in schema: "+ch, data, p_err);
|
508
|
+
return error();
|
461
509
|
|
462
510
|
case req_schema_slash:
|
463
511
|
if (strict && SLASH != ch) {
|
464
512
|
settings.call_on_error(this, "invalid char in schema, not /", data, p_err);
|
513
|
+
return error();
|
465
514
|
}
|
466
515
|
state = State.req_schema_slash_slash;
|
467
516
|
break;
|
@@ -469,6 +518,7 @@ public class HTTPParser {
|
|
469
518
|
case req_schema_slash_slash:
|
470
519
|
if (strict && SLASH != ch) {
|
471
520
|
settings.call_on_error(this, "invalid char in schema, not /", data, p_err);
|
521
|
+
return error();
|
472
522
|
}
|
473
523
|
state = State.req_host;
|
474
524
|
break;
|
@@ -494,8 +544,12 @@ public class HTTPParser {
|
|
494
544
|
url_mark = -1;
|
495
545
|
state = State.req_http_start;
|
496
546
|
break;
|
547
|
+
case QMARK:
|
548
|
+
state = State.req_query_string_start;
|
549
|
+
break;
|
497
550
|
default:
|
498
551
|
settings.call_on_error(this, "host error in method line", data, p_err);
|
552
|
+
return error();
|
499
553
|
}
|
500
554
|
break;
|
501
555
|
|
@@ -515,13 +569,17 @@ public class HTTPParser {
|
|
515
569
|
url_mark = -1;
|
516
570
|
state = State.req_http_start;
|
517
571
|
break;
|
572
|
+
case QMARK:
|
573
|
+
state = State.req_query_string_start;
|
574
|
+
break;
|
518
575
|
default:
|
519
576
|
settings.call_on_error(this, "invalid port", data, p_err);
|
577
|
+
return error();
|
520
578
|
}
|
521
579
|
break;
|
522
580
|
|
523
581
|
case req_path:
|
524
|
-
if (normal_url_char[
|
582
|
+
if (normal_url_char[chi]) break;
|
525
583
|
switch (ch) {
|
526
584
|
case SPACE:
|
527
585
|
settings.call_on_url(this,data,url_mark, p-url_mark);
|
@@ -571,11 +629,12 @@ public class HTTPParser {
|
|
571
629
|
|
572
630
|
default:
|
573
631
|
settings.call_on_error(this, "unexpected char in path", data, p_err);
|
632
|
+
return error();
|
574
633
|
}
|
575
634
|
break;
|
576
635
|
|
577
636
|
case req_query_string_start:
|
578
|
-
if (normal_url_char[
|
637
|
+
if (normal_url_char[chi]) {
|
579
638
|
query_string_mark = p;
|
580
639
|
state = State.req_query_string;
|
581
640
|
break;
|
@@ -605,11 +664,12 @@ public class HTTPParser {
|
|
605
664
|
break;
|
606
665
|
default:
|
607
666
|
settings.call_on_error(this, "unexpected char in path", data, p_err);
|
667
|
+
return error();
|
608
668
|
}
|
609
669
|
break;
|
610
670
|
|
611
671
|
case req_query_string:
|
612
|
-
if (normal_url_char[
|
672
|
+
if (normal_url_char[chi]) {
|
613
673
|
break;
|
614
674
|
}
|
615
675
|
|
@@ -652,11 +712,12 @@ public class HTTPParser {
|
|
652
712
|
break;
|
653
713
|
default:
|
654
714
|
settings.call_on_error(this, "unexpected char in path", data, p_err);
|
715
|
+
return error();
|
655
716
|
}
|
656
717
|
break;
|
657
718
|
|
658
719
|
case req_fragment_start:
|
659
|
-
if (normal_url_char[
|
720
|
+
if (normal_url_char[chi]) {
|
660
721
|
fragment_mark = p;
|
661
722
|
state = State.req_fragment;
|
662
723
|
break;
|
@@ -691,11 +752,12 @@ public class HTTPParser {
|
|
691
752
|
break;
|
692
753
|
default:
|
693
754
|
settings.call_on_error(this, "unexpected char in path", data, p_err);
|
755
|
+
return error();
|
694
756
|
}
|
695
757
|
break;
|
696
758
|
|
697
759
|
case req_fragment:
|
698
|
-
if (normal_url_char[
|
760
|
+
if (normal_url_char[chi]) {
|
699
761
|
break;
|
700
762
|
}
|
701
763
|
|
@@ -734,6 +796,7 @@ public class HTTPParser {
|
|
734
796
|
break;
|
735
797
|
default:
|
736
798
|
settings.call_on_error(this, "unexpected char in path", data, p_err);
|
799
|
+
return error();
|
737
800
|
}
|
738
801
|
break;
|
739
802
|
/******************* URL *******************/
|
@@ -750,12 +813,14 @@ public class HTTPParser {
|
|
750
813
|
break;
|
751
814
|
default:
|
752
815
|
settings.call_on_error(this, "error in req_http_H", data, p_err);
|
816
|
+
return error();
|
753
817
|
}
|
754
818
|
break;
|
755
819
|
|
756
820
|
case req_http_H:
|
757
821
|
if (strict && T != ch) {
|
758
822
|
settings.call_on_error(this, "unexpected char", data, p_err);
|
823
|
+
return error();
|
759
824
|
}
|
760
825
|
state = State.req_http_HT;
|
761
826
|
break;
|
@@ -763,6 +828,7 @@ public class HTTPParser {
|
|
763
828
|
case req_http_HT:
|
764
829
|
if (strict && T != ch) {
|
765
830
|
settings.call_on_error(this, "unexpected char", data, p_err);
|
831
|
+
return error();
|
766
832
|
}
|
767
833
|
state = State.req_http_HTT;
|
768
834
|
break;
|
@@ -770,6 +836,7 @@ public class HTTPParser {
|
|
770
836
|
case req_http_HTT:
|
771
837
|
if (strict && P != ch) {
|
772
838
|
settings.call_on_error(this, "unexpected char", data, p_err);
|
839
|
+
return error();
|
773
840
|
}
|
774
841
|
state = State.req_http_HTTP;
|
775
842
|
break;
|
@@ -777,6 +844,7 @@ public class HTTPParser {
|
|
777
844
|
case req_http_HTTP:
|
778
845
|
if (strict && SLASH != ch) {
|
779
846
|
settings.call_on_error(this, "unexpected char", data, p_err);
|
847
|
+
return error();
|
780
848
|
}
|
781
849
|
state = req_first_http_major;
|
782
850
|
break;
|
@@ -785,6 +853,7 @@ public class HTTPParser {
|
|
785
853
|
case req_first_http_major:
|
786
854
|
if (!isDigit(ch)) {
|
787
855
|
settings.call_on_error(this, "non digit in http major", data, p_err);
|
856
|
+
return error();
|
788
857
|
}
|
789
858
|
http_major = (int)ch - 0x30;
|
790
859
|
state = State.req_http_major;
|
@@ -799,6 +868,7 @@ public class HTTPParser {
|
|
799
868
|
|
800
869
|
if (!isDigit(ch)) {
|
801
870
|
settings.call_on_error(this, "non digit in http major", data, p_err);
|
871
|
+
return error();
|
802
872
|
}
|
803
873
|
|
804
874
|
http_major *= 10;
|
@@ -806,6 +876,7 @@ public class HTTPParser {
|
|
806
876
|
|
807
877
|
if (http_major > 999) {
|
808
878
|
settings.call_on_error(this, "ridiculous http major", data, p_err);
|
879
|
+
return error();
|
809
880
|
};
|
810
881
|
break;
|
811
882
|
|
@@ -813,6 +884,7 @@ public class HTTPParser {
|
|
813
884
|
case req_first_http_minor:
|
814
885
|
if (!isDigit(ch)) {
|
815
886
|
settings.call_on_error(this, "non digit in http minor", data, p_err);
|
887
|
+
return error();
|
816
888
|
}
|
817
889
|
http_minor = (int)ch - 0x30;
|
818
890
|
state = State.req_http_minor;
|
@@ -833,6 +905,7 @@ public class HTTPParser {
|
|
833
905
|
|
834
906
|
if (!isDigit(ch)) {
|
835
907
|
settings.call_on_error(this, "non digit in http minor", data, p_err);
|
908
|
+
return error();
|
836
909
|
}
|
837
910
|
|
838
911
|
http_minor *= 10;
|
@@ -841,6 +914,7 @@ public class HTTPParser {
|
|
841
914
|
|
842
915
|
if (http_minor > 999) {
|
843
916
|
settings.call_on_error(this, "ridiculous http minor", data, p_err);
|
917
|
+
return error();
|
844
918
|
};
|
845
919
|
|
846
920
|
break;
|
@@ -850,6 +924,7 @@ public class HTTPParser {
|
|
850
924
|
{
|
851
925
|
if (ch != LF) {
|
852
926
|
settings.call_on_error(this, "missing LF after request line", data, p_err);
|
927
|
+
return error();
|
853
928
|
}
|
854
929
|
state = State.header_field_start;
|
855
930
|
break;
|
@@ -873,14 +948,19 @@ public class HTTPParser {
|
|
873
948
|
state = State.headers_almost_done;
|
874
949
|
if (!headers_almost_done(ch, settings)) {
|
875
950
|
settings.call_on_error(this, "header not properly completed", data, p_err);
|
951
|
+
return error();
|
952
|
+
}
|
953
|
+
if (upgrade) {
|
954
|
+
return data.position() - start_position;
|
876
955
|
}
|
877
956
|
break;
|
878
957
|
}
|
879
958
|
|
880
|
-
c =
|
959
|
+
c = token(ch);
|
881
960
|
|
882
|
-
if (
|
883
|
-
settings.call_on_error(this, "invalid char in header", data, p_err);
|
961
|
+
if (0 == c) {
|
962
|
+
settings.call_on_error(this, "invalid char in header:"+c, data, p_err);
|
963
|
+
return error();
|
884
964
|
};
|
885
965
|
|
886
966
|
header_field_mark = p;
|
@@ -916,7 +996,7 @@ public class HTTPParser {
|
|
916
996
|
|
917
997
|
case header_field:
|
918
998
|
{
|
919
|
-
c = (
|
999
|
+
c = token(ch);
|
920
1000
|
if (0 != c) {
|
921
1001
|
switch (header_state) {
|
922
1002
|
case general:
|
@@ -1011,6 +1091,7 @@ public class HTTPParser {
|
|
1011
1091
|
|
1012
1092
|
default:
|
1013
1093
|
settings.call_on_error(this, "Unknown Header State", data, p_err);
|
1094
|
+
return error();
|
1014
1095
|
} // switch: header_state
|
1015
1096
|
break;
|
1016
1097
|
} // 0 != c
|
@@ -1040,6 +1121,7 @@ public class HTTPParser {
|
|
1040
1121
|
}
|
1041
1122
|
|
1042
1123
|
settings.call_on_error(this, "invalid header field", data, p_err);
|
1124
|
+
return error();
|
1043
1125
|
}
|
1044
1126
|
|
1045
1127
|
|
@@ -1053,30 +1135,27 @@ public class HTTPParser {
|
|
1053
1135
|
state = State.header_value;
|
1054
1136
|
index = 0;
|
1055
1137
|
|
1056
|
-
c = (byte)acceptable_header[ch];
|
1057
|
-
|
1058
|
-
if (c == 0) {
|
1059
|
-
if (CR == ch) {
|
1060
|
-
settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
|
1061
|
-
header_value_mark = -1;
|
1062
1138
|
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
}
|
1067
|
-
|
1068
|
-
if (LF == ch) {
|
1069
|
-
settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
|
1070
|
-
header_value_mark = -1;
|
1071
|
-
|
1072
|
-
state = State.header_field_start;
|
1073
|
-
break;
|
1074
|
-
}
|
1139
|
+
if (CR == ch) {
|
1140
|
+
settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
|
1141
|
+
header_value_mark = -1;
|
1075
1142
|
|
1076
1143
|
header_state = HState.general;
|
1144
|
+
state = State.header_almost_done;
|
1145
|
+
break;
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
if (LF == ch) {
|
1149
|
+
settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
|
1150
|
+
header_value_mark = -1;
|
1151
|
+
|
1152
|
+
state = State.header_field_start;
|
1077
1153
|
break;
|
1078
1154
|
}
|
1079
1155
|
|
1156
|
+
|
1157
|
+
c = upper(ch);
|
1158
|
+
|
1080
1159
|
switch (header_state) {
|
1081
1160
|
case upgrade:
|
1082
1161
|
flags |= F_UPGRADE;
|
@@ -1095,6 +1174,7 @@ public class HTTPParser {
|
|
1095
1174
|
case content_length:
|
1096
1175
|
if (!isDigit(ch)) {
|
1097
1176
|
settings.call_on_error(this, "Content-Length not numeric", data, p_err);
|
1177
|
+
return error();
|
1098
1178
|
}
|
1099
1179
|
content_length = (int)ch - 0x30;
|
1100
1180
|
break;
|
@@ -1122,29 +1202,27 @@ public class HTTPParser {
|
|
1122
1202
|
|
1123
1203
|
case header_value:
|
1124
1204
|
{
|
1125
|
-
c = (byte)acceptable_header[ch];
|
1126
1205
|
|
1127
|
-
if (
|
1128
|
-
|
1129
|
-
|
1130
|
-
header_value_mark = -1;
|
1206
|
+
if (CR == ch) {
|
1207
|
+
settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
|
1208
|
+
header_value_mark = -1;
|
1131
1209
|
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1210
|
+
state = State.header_almost_done;
|
1211
|
+
break;
|
1212
|
+
}
|
1135
1213
|
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
break;
|
1214
|
+
if (LF == ch) {
|
1215
|
+
settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
|
1216
|
+
header_value_mark = -1;
|
1217
|
+
|
1218
|
+
if (!header_almost_done(ch)) {
|
1219
|
+
settings.call_on_error(this,"incorrect header ending, expection LF", data, p_err);
|
1220
|
+
return error();
|
1144
1221
|
}
|
1145
1222
|
break;
|
1146
1223
|
}
|
1147
1224
|
|
1225
|
+
c = upper(ch);
|
1148
1226
|
switch (header_state) {
|
1149
1227
|
case general:
|
1150
1228
|
break;
|
@@ -1152,6 +1230,7 @@ public class HTTPParser {
|
|
1152
1230
|
case connection:
|
1153
1231
|
case transfer_encoding:
|
1154
1232
|
settings.call_on_error(this, "Shouldn't be here", data, p_err);
|
1233
|
+
return error();
|
1155
1234
|
|
1156
1235
|
case content_length:
|
1157
1236
|
if (SPACE == ch) {
|
@@ -1159,6 +1238,7 @@ public class HTTPParser {
|
|
1159
1238
|
}
|
1160
1239
|
if (!isDigit(ch)) {
|
1161
1240
|
settings.call_on_error(this, "Content-Length not numeric", data, p_err);
|
1241
|
+
return error();
|
1162
1242
|
}
|
1163
1243
|
|
1164
1244
|
content_length *= 10;
|
@@ -1214,12 +1294,17 @@ public class HTTPParser {
|
|
1214
1294
|
case header_almost_done:
|
1215
1295
|
if (!header_almost_done(ch)) {
|
1216
1296
|
settings.call_on_error(this,"incorrect header ending, expection LF", data, p_err);
|
1297
|
+
return error();
|
1217
1298
|
}
|
1218
1299
|
break;
|
1219
1300
|
|
1220
1301
|
case headers_almost_done:
|
1221
1302
|
if (!headers_almost_done(ch, settings)) {
|
1222
1303
|
settings.call_on_error(this, "header not properly completed", data, p_err);
|
1304
|
+
return error();
|
1305
|
+
}
|
1306
|
+
if (upgrade) {
|
1307
|
+
return data.position()-start_position ;
|
1223
1308
|
}
|
1224
1309
|
break;
|
1225
1310
|
|
@@ -1258,13 +1343,20 @@ public class HTTPParser {
|
|
1258
1343
|
|
1259
1344
|
/******************* Chunk *******************/
|
1260
1345
|
case chunk_size_start:
|
1346
|
+
if (1 != this.nread) {
|
1347
|
+
settings.call_on_error(this, "nread != 1 (chunking)", data, p_err);
|
1348
|
+
return error();
|
1349
|
+
|
1350
|
+
}
|
1261
1351
|
if (0 == (flags & F_CHUNKED)) {
|
1262
1352
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1353
|
+
return error();
|
1263
1354
|
}
|
1264
1355
|
|
1265
|
-
c = UNHEX[
|
1356
|
+
c = UNHEX[chi];
|
1266
1357
|
if (c == -1) {
|
1267
1358
|
settings.call_on_error(this, "invalid hex char in chunk content length", data, p_err);
|
1359
|
+
return error();
|
1268
1360
|
}
|
1269
1361
|
content_length = c;
|
1270
1362
|
state = State.chunk_size;
|
@@ -1275,6 +1367,7 @@ public class HTTPParser {
|
|
1275
1367
|
case chunk_size:
|
1276
1368
|
if (0 == (flags & F_CHUNKED)) {
|
1277
1369
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1370
|
+
return error();
|
1278
1371
|
}
|
1279
1372
|
|
1280
1373
|
if (CR == ch) {
|
@@ -1282,7 +1375,7 @@ public class HTTPParser {
|
|
1282
1375
|
break;
|
1283
1376
|
}
|
1284
1377
|
|
1285
|
-
c = UNHEX[
|
1378
|
+
c = UNHEX[chi];
|
1286
1379
|
|
1287
1380
|
if (c == -1) {
|
1288
1381
|
if (SEMI == ch || SPACE == ch) {
|
@@ -1290,6 +1383,7 @@ public class HTTPParser {
|
|
1290
1383
|
break;
|
1291
1384
|
}
|
1292
1385
|
settings.call_on_error(this, "invalid hex char in chunk content length", data, p_err);
|
1386
|
+
return error();
|
1293
1387
|
}
|
1294
1388
|
|
1295
1389
|
content_length *= 16;
|
@@ -1301,6 +1395,7 @@ public class HTTPParser {
|
|
1301
1395
|
case chunk_parameters:
|
1302
1396
|
if (0 == (flags & F_CHUNKED)) {
|
1303
1397
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1398
|
+
return error();
|
1304
1399
|
}
|
1305
1400
|
/* just ignore this shit. TODO check for overflow */
|
1306
1401
|
if (CR == ch) {
|
@@ -1314,11 +1409,15 @@ public class HTTPParser {
|
|
1314
1409
|
case chunk_size_almost_done:
|
1315
1410
|
if (0 == (flags & F_CHUNKED)) {
|
1316
1411
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1412
|
+
return error();
|
1317
1413
|
}
|
1318
1414
|
if (strict && LF != ch) {
|
1319
1415
|
settings.call_on_error(this, "expected LF at end of chunk size", data, p_err);
|
1416
|
+
return error();
|
1320
1417
|
}
|
1321
1418
|
|
1419
|
+
this.nread = 0;
|
1420
|
+
|
1322
1421
|
if (0 == content_length) {
|
1323
1422
|
flags |= F_TRAILING;
|
1324
1423
|
state = State.header_field_start;
|
@@ -1333,6 +1432,7 @@ public class HTTPParser {
|
|
1333
1432
|
{
|
1334
1433
|
if (0 == (flags & F_CHUNKED)) {
|
1335
1434
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1435
|
+
return error();
|
1336
1436
|
}
|
1337
1437
|
|
1338
1438
|
to_read = min(pe-p, content_length);
|
@@ -1354,9 +1454,11 @@ public class HTTPParser {
|
|
1354
1454
|
case chunk_data_almost_done:
|
1355
1455
|
if (0 == (flags & F_CHUNKED)) {
|
1356
1456
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1457
|
+
return error();
|
1357
1458
|
}
|
1358
1459
|
if (strict && CR != ch) {
|
1359
1460
|
settings.call_on_error(this, "chunk data terminated incorrectly, expected CR", data, p_err);
|
1461
|
+
return error();
|
1360
1462
|
}
|
1361
1463
|
state = State.chunk_data_done;
|
1362
1464
|
break;
|
@@ -1366,9 +1468,11 @@ public class HTTPParser {
|
|
1366
1468
|
case chunk_data_done:
|
1367
1469
|
if (0 == (flags & F_CHUNKED)) {
|
1368
1470
|
settings.call_on_error(this, "not chunked", data, p_err);
|
1471
|
+
return error();
|
1369
1472
|
}
|
1370
1473
|
if (strict && LF != ch) {
|
1371
1474
|
settings.call_on_error(this, "chunk data terminated incorrectly, expected LF", data, p_err);
|
1475
|
+
return error();
|
1372
1476
|
}
|
1373
1477
|
state = State.chunk_size_start;
|
1374
1478
|
break;
|
@@ -1378,6 +1482,7 @@ public class HTTPParser {
|
|
1378
1482
|
|
1379
1483
|
default:
|
1380
1484
|
settings.call_on_error(this, "unhandled state", data, p_err);
|
1485
|
+
return error();
|
1381
1486
|
|
1382
1487
|
} // switch
|
1383
1488
|
} // while
|
@@ -1394,9 +1499,15 @@ public class HTTPParser {
|
|
1394
1499
|
settings.call_on_query_string(this, data, query_string_mark, p-query_string_mark);
|
1395
1500
|
settings.call_on_path (this, data, path_mark, p-path_mark);
|
1396
1501
|
settings.call_on_url (this, data, url_mark, p-url_mark);
|
1397
|
-
|
1502
|
+
|
1503
|
+
return data.position()-start_position;
|
1398
1504
|
} // execute
|
1399
1505
|
|
1506
|
+
int error () {
|
1507
|
+
this.state = State.dead;
|
1508
|
+
return this.data.position()-start_position;
|
1509
|
+
}
|
1510
|
+
|
1400
1511
|
/* If http_should_keep_alive() in the on_headers_complete or
|
1401
1512
|
* on_message_complete callback returns true, then this will be should be
|
1402
1513
|
* the last message on the connection.
|
@@ -1442,6 +1553,10 @@ public class HTTPParser {
|
|
1442
1553
|
char c = (char)(b);
|
1443
1554
|
return (byte)Character.toUpperCase(c);
|
1444
1555
|
}
|
1556
|
+
|
1557
|
+
byte token(byte b) {
|
1558
|
+
return (byte)tokens[b];
|
1559
|
+
}
|
1445
1560
|
|
1446
1561
|
|
1447
1562
|
HTTPMethod start_req_method_assign(byte c){
|
@@ -1451,12 +1566,14 @@ public class HTTPParser {
|
|
1451
1566
|
case G: return HTTPMethod.HTTP_GET;
|
1452
1567
|
case H: return HTTPMethod.HTTP_HEAD;
|
1453
1568
|
case L: return HTTPMethod.HTTP_LOCK;
|
1454
|
-
case M: return HTTPMethod.HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE */
|
1569
|
+
case M: return HTTPMethod.HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */
|
1570
|
+
case N: return HTTPMethod.HTTP_NOTIFY;
|
1455
1571
|
case O: return HTTPMethod.HTTP_OPTIONS;
|
1456
1572
|
case P: return HTTPMethod.HTTP_POST; /* or PROPFIND, PROPPATH, PUT */
|
1457
1573
|
case R: return HTTPMethod.HTTP_REPORT;
|
1574
|
+
case S: return HTTPMethod.HTTP_SUBSCRIBE;
|
1458
1575
|
case T: return HTTPMethod.HTTP_TRACE;
|
1459
|
-
case U: return HTTPMethod.HTTP_UNLOCK;
|
1576
|
+
case U: return HTTPMethod.HTTP_UNLOCK; /* or UNSUBSCRIBE */
|
1460
1577
|
}
|
1461
1578
|
return null; // ugh.
|
1462
1579
|
}
|
@@ -1489,7 +1606,6 @@ public class HTTPParser {
|
|
1489
1606
|
if (LF != ch) {
|
1490
1607
|
return false;
|
1491
1608
|
}
|
1492
|
-
|
1493
1609
|
if (0 != (flags & F_TRAILING)) {
|
1494
1610
|
/* End of a chunked request */
|
1495
1611
|
|
@@ -1553,6 +1669,7 @@ public class HTTPParser {
|
|
1553
1669
|
// Exit, the rest of the connect is in a different protocol.
|
1554
1670
|
if (upgrade) {
|
1555
1671
|
settings.call_on_message_complete(this);
|
1672
|
+
state = State.body_identity_eof;
|
1556
1673
|
return true;
|
1557
1674
|
}
|
1558
1675
|
|
@@ -1608,10 +1725,6 @@ public class HTTPParser {
|
|
1608
1725
|
boolean parsing_header(State state) {
|
1609
1726
|
|
1610
1727
|
switch (state) {
|
1611
|
-
case chunk_size_start :
|
1612
|
-
case chunk_size :
|
1613
|
-
case chunk_size_almost_done :
|
1614
|
-
case chunk_parameters :
|
1615
1728
|
case chunk_data :
|
1616
1729
|
case chunk_data_almost_done :
|
1617
1730
|
case chunk_data_done :
|
@@ -1620,7 +1733,7 @@ public class HTTPParser {
|
|
1620
1733
|
return false;
|
1621
1734
|
|
1622
1735
|
}
|
1623
|
-
|
1736
|
+
return true;
|
1624
1737
|
}
|
1625
1738
|
|
1626
1739
|
/* "Dial C for Constants" */
|
@@ -1676,12 +1789,16 @@ public class HTTPParser {
|
|
1676
1789
|
static final byte [] CLOSE = {
|
1677
1790
|
0x43, 0x4c, 0x4f, 0x53, 0x45,
|
1678
1791
|
};
|
1679
|
-
|
1680
|
-
|
1681
|
-
*
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1792
|
+
|
1793
|
+
/* Tokens as defined by rfc 2616. Also lowercases them.
|
1794
|
+
* token = 1*<any CHAR except CTLs or separators>
|
1795
|
+
* separators = "(" | ")" | "<" | ">" | "@"
|
1796
|
+
* | "," | ";" | ":" | "\" | <">
|
1797
|
+
* | "/" | "[" | "]" | "?" | "="
|
1798
|
+
* | "{" | "}" | SP | HT
|
1799
|
+
*/
|
1800
|
+
|
1801
|
+
static final char [] tokens = {
|
1685
1802
|
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
|
1686
1803
|
0, 0, 0, 0, 0, 0, 0, 0,
|
1687
1804
|
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
|
@@ -1691,9 +1808,9 @@ public class HTTPParser {
|
|
1691
1808
|
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
|
1692
1809
|
0, 0, 0, 0, 0, 0, 0, 0,
|
1693
1810
|
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
|
1694
|
-
' ',
|
1811
|
+
' ', '!', '"', '#', '$', '%', '&', '\'',
|
1695
1812
|
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
|
1696
|
-
0, 0,
|
1813
|
+
0, 0, '*', '+', 0, '-', '.', '/' ,
|
1697
1814
|
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
|
1698
1815
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
1699
1816
|
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
|
@@ -1713,7 +1830,24 @@ public class HTTPParser {
|
|
1713
1830
|
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
|
1714
1831
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
1715
1832
|
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
|
1716
|
-
'X', 'Y', 'Z', 0,
|
1833
|
+
'X', 'Y', 'Z', 0, '|', '}', 0, 0,
|
1834
|
+
/* hi bit set, not ascii */
|
1835
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1836
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1837
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1838
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1839
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1840
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1841
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1842
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1843
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1844
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1845
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1846
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1847
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1848
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1849
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
1850
|
+
0, 0, 0, 0, 0, 0, 0, 0, };
|
1717
1851
|
|
1718
1852
|
static final byte [] UNHEX =
|
1719
1853
|
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
@@ -1724,6 +1858,14 @@ public class HTTPParser {
|
|
1724
1858
|
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1725
1859
|
,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1726
1860
|
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1861
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1862
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1863
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1864
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1865
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1866
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1867
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1868
|
+
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
1727
1869
|
};
|
1728
1870
|
|
1729
1871
|
static final boolean [] normal_url_char = {
|
@@ -1758,7 +1900,31 @@ public class HTTPParser {
|
|
1758
1900
|
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
|
1759
1901
|
true, true, true, true, true, true, true, true,
|
1760
1902
|
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
|
1761
|
-
true, true, true, true, true, true, true, false
|
1903
|
+
true, true, true, true, true, true, true, false,
|
1904
|
+
|
1905
|
+
/* hi bit set, not ascii */
|
1906
|
+
/* Remainder of non-ASCII range are accepted as-is to support implicitly UTF-8
|
1907
|
+
* encoded paths. This is out of spec, but clients generate this and most other
|
1908
|
+
* HTTP servers support it. We should, too. */
|
1909
|
+
|
1910
|
+
true, true, true, true, true, true, true, true,
|
1911
|
+
true, true, true, true, true, true, true, true,
|
1912
|
+
true, true, true, true, true, true, true, true,
|
1913
|
+
true, true, true, true, true, true, true, true,
|
1914
|
+
true, true, true, true, true, true, true, true,
|
1915
|
+
true, true, true, true, true, true, true, true,
|
1916
|
+
true, true, true, true, true, true, true, true,
|
1917
|
+
true, true, true, true, true, true, true, true,
|
1918
|
+
true, true, true, true, true, true, true, true,
|
1919
|
+
true, true, true, true, true, true, true, true,
|
1920
|
+
true, true, true, true, true, true, true, true,
|
1921
|
+
true, true, true, true, true, true, true, true,
|
1922
|
+
true, true, true, true, true, true, true, true,
|
1923
|
+
true, true, true, true, true, true, true, true,
|
1924
|
+
true, true, true, true, true, true, true, true,
|
1925
|
+
true, true, true, true, true, true, true, true,
|
1926
|
+
|
1927
|
+
};
|
1762
1928
|
|
1763
1929
|
public static final byte A = 0x41;
|
1764
1930
|
public static final byte B = 0x42;
|
@@ -1796,6 +1962,7 @@ public class HTTPParser {
|
|
1796
1962
|
public static final byte QMARK = 0x3f;
|
1797
1963
|
public static final byte SLASH = 0x2f;
|
1798
1964
|
public static final byte DASH = 0x2d;
|
1965
|
+
public static final byte STAR = 0x2a;
|
1799
1966
|
public static final byte NULL = 0x00;
|
1800
1967
|
}
|
1801
1968
|
|
@@ -1851,12 +2018,19 @@ public class HTTPParser {
|
|
1851
2018
|
|
1852
2019
|
, header_almost_done
|
1853
2020
|
|
1854
|
-
, headers_almost_done
|
1855
|
-
|
1856
2021
|
, chunk_size_start
|
1857
2022
|
, chunk_size
|
1858
|
-
, chunk_size_almost_done
|
1859
2023
|
, chunk_parameters
|
2024
|
+
, chunk_size_almost_done
|
2025
|
+
|
2026
|
+
, headers_almost_done
|
2027
|
+
// This space intentionally not left blank, comment from c, for orientation...
|
2028
|
+
// the c version uses <= s_header_almost_done in java, we list the states explicitly
|
2029
|
+
// in `parsing_header()`
|
2030
|
+
/* Important: 's_headers_almost_done' must be the last 'header' state. All
|
2031
|
+
* states beyond this must be 'body' states. It is used for overflow
|
2032
|
+
* checking. See the PARSING_HEADER() macro.
|
2033
|
+
*/
|
1860
2034
|
, chunk_data
|
1861
2035
|
, chunk_data_almost_done
|
1862
2036
|
, chunk_data_done
|