http_parser.rb 0.5.0-x86-mingw32

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.
Files changed (57) hide show
  1. data/.gitignore +11 -0
  2. data/.gitmodules +6 -0
  3. data/README.md +45 -0
  4. data/Rakefile +6 -0
  5. data/bench/thin.rb +57 -0
  6. data/ext/ruby_http_parser/.gitignore +1 -0
  7. data/ext/ruby_http_parser/RubyHttpParserService.java +18 -0
  8. data/ext/ruby_http_parser/ext_help.h +18 -0
  9. data/ext/ruby_http_parser/extconf.rb +16 -0
  10. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +403 -0
  11. data/ext/ruby_http_parser/ruby_http_parser.c +474 -0
  12. data/ext/ruby_http_parser/vendor/.gitkeep +0 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +4 -0
  14. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +19 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +171 -0
  16. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +19 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/compile +1 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1590 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +167 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +7 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +90 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +31 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java +13 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java +5 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java +25 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java +7 -0
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +1894 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +78 -0
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/Util.java +112 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +487 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +115 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1865 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -0
  34. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +539 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb +6 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb +13 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb +15 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb +33 -0
  40. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +4 -0
  41. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +19 -0
  42. data/ext/ruby_http_parser/vendor/http-parser/README.md +171 -0
  43. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1590 -0
  44. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +167 -0
  45. data/ext/ruby_http_parser/vendor/http-parser/test.c +1755 -0
  46. data/http_parser.rb.gemspec +15 -0
  47. data/lib/http/parser.rb +1 -0
  48. data/lib/http_parser.rb +4 -0
  49. data/lib/ruby_http_parser.rb +2 -0
  50. data/spec/parser_spec.rb +187 -0
  51. data/spec/spec_helper.rb +2 -0
  52. data/spec/support/requests.json +381 -0
  53. data/spec/support/responses.json +186 -0
  54. data/tasks/compile.rake +39 -0
  55. data/tasks/spec.rake +5 -0
  56. data/tasks/submodules.rake +7 -0
  57. metadata +124 -0
@@ -0,0 +1,78 @@
1
+ package http_parser.lolevel;
2
+ import java.nio.ByteBuffer;
3
+ import http_parser.HTTPException;
4
+ public class ParserSettings {
5
+
6
+ public HTTPCallback on_message_begin;
7
+ public HTTPDataCallback on_path;
8
+ public HTTPDataCallback on_query_string;
9
+ public HTTPDataCallback on_url;
10
+ public HTTPDataCallback on_fragment;
11
+ public HTTPDataCallback on_header_field;
12
+ public HTTPDataCallback on_header_value;
13
+ public HTTPCallback on_headers_complete;
14
+ public HTTPDataCallback on_body;
15
+ public HTTPCallback on_message_complete;
16
+ public HTTPErrorCallback on_error;
17
+
18
+ void call_on_message_begin (HTTPParser p) {
19
+ call_on(on_message_begin, p);
20
+ }
21
+
22
+ void call_on_message_complete (HTTPParser p) {
23
+ call_on(on_message_complete, p);
24
+ }
25
+
26
+ // this one is a little bit different:
27
+ // the current `position` of the buffer is the location of the
28
+ // error, `ini_pos` indicates where the position of
29
+ // the buffer when it was passed to the `execute` method of the parser, i.e.
30
+ // using this information and `limit` we'll know all the valid data
31
+ // in the buffer around the error we can use to print pretty error
32
+ // messages.
33
+ void call_on_error (HTTPParser p, String mes, ByteBuffer buf, int ini_pos) {
34
+ if (null != on_error) {
35
+ on_error.cb(p, mes, buf, ini_pos);
36
+ }
37
+ // if on_error gets called it MUST throw an exception, else the parser
38
+ // will attempt to continue parsing, which it can't because it's
39
+ // in an invalid state.
40
+ throw new HTTPException(mes);
41
+ }
42
+
43
+ void call_on_header_field (HTTPParser p, ByteBuffer buf, int pos, int len) {
44
+ call_on(on_header_field, p, buf, pos, len);
45
+ }
46
+ void call_on_query_string (HTTPParser p, ByteBuffer buf, int pos, int len) {
47
+ call_on(on_query_string, p, buf, pos, len);
48
+ }
49
+ void call_on_fragment (HTTPParser p, ByteBuffer buf, int pos, int len) {
50
+ call_on(on_fragment, p, buf, pos, len);
51
+ }
52
+ void call_on_path (HTTPParser p, ByteBuffer buf, int pos, int len) {
53
+ call_on(on_path, p, buf, pos, len);
54
+ }
55
+ void call_on_header_value (HTTPParser p, ByteBuffer buf, int pos, int len) {
56
+ call_on(on_header_value, p, buf, pos, len);
57
+ }
58
+ void call_on_url (HTTPParser p, ByteBuffer buf, int pos, int len) {
59
+ call_on(on_url, p, buf, pos, len);
60
+ }
61
+ void call_on_body(HTTPParser p, ByteBuffer buf, int pos, int len) {
62
+ call_on(on_body, p, buf, pos, len);
63
+ }
64
+ void call_on_headers_complete(HTTPParser p) {
65
+ call_on(on_headers_complete, p);
66
+ }
67
+ void call_on (HTTPCallback cb, HTTPParser p) {
68
+ // cf. CALLBACK2 macro
69
+ if (null != cb) {
70
+ cb.cb(p);
71
+ }
72
+ }
73
+ void call_on (HTTPDataCallback cb, HTTPParser p, ByteBuffer buf, int pos, int len) {
74
+ if (null != cb && -1 != pos) {
75
+ cb.cb(p,buf,pos,len);
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,112 @@
1
+ package http_parser.lolevel;
2
+
3
+ import java.nio.ByteBuffer;
4
+ import http_parser.HTTPException;
5
+
6
+ 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
+ }
33
+
34
+ public static String error (String mes, ByteBuffer b, int begining) {
35
+ // the error message should look like this:
36
+ //
37
+ // Bla expected something, but it's not there (mes)
38
+ // GEt / HTTP 1_1
39
+ // ............^.
40
+ //
41
+ // |----------------- 72 -------------------------|
42
+
43
+ // This is ridiculously complicated and probably riddled with
44
+ // off-by-one errors, should be moved into high level interface.
45
+ // TODO.
46
+
47
+ // also: need to keep track of the initial buffer position in
48
+ // execute so that we don't screw up any `mark()` that may have
49
+ // been set outside of our control to be nice.
50
+
51
+ final int mes_width = 72;
52
+ int p = b.position(); // error position
53
+ int end = b.limit(); // this is the end
54
+ int m = end - begining; // max mes length
55
+
56
+ StringBuilder builder = new StringBuilder();
57
+ int p_adj = p;
58
+
59
+ byte [] orig = new byte[0];
60
+ if (m <= mes_width) {
61
+ orig = new byte[m];
62
+ b.position(begining);
63
+ b.get(orig, 0, m);
64
+ p_adj = p-begining;
65
+
66
+
67
+ } else {
68
+ // we'll need to trim bit off the beginning and/or end
69
+ orig = new byte[mes_width];
70
+ // three possibilities:
71
+ // a.) plenty of stuff around p
72
+ // b.) plenty of stuff in front of p
73
+ // c.) plenty of stuff behind p
74
+ // CAN'T be not enough stuff aorund p in total, because
75
+ // m>meswidth (see if to this else)
76
+
77
+ int before = p-begining;
78
+ int after = end - p;
79
+ if ( (before > mes_width/2) && (after > mes_width/2)) {
80
+ // plenty of stuff in front of and behind error
81
+ p_adj = mes_width/2;
82
+ b.position(p - mes_width/2);
83
+ b.get(orig, 0, mes_width);
84
+ } else if (before <= mes_width/2) {
85
+ // take all of the begining.
86
+ b.position(begining);
87
+ // and as much of the rest as possible
88
+
89
+ b.get(orig, 0, mes_width);
90
+
91
+ } else {
92
+ // plenty of stuff before
93
+ before = end-mes_width;
94
+ b.position(before);
95
+ p_adj = p - before;
96
+ b.get(orig, 0, mes_width);
97
+ }
98
+ }
99
+
100
+ builder.append(new String(orig));
101
+ builder.append("\n");
102
+ for (int i = 0; i!= p_adj; ++i) {
103
+ builder.append(".");
104
+ }
105
+ builder.append("^");
106
+
107
+
108
+ b.position(p); // restore position
109
+ return builder.toString();
110
+
111
+ }
112
+ }
@@ -0,0 +1,487 @@
1
+ package http_parser.lolevel;
2
+ // name : 200 trailing space on chunked body
3
+ // raw : "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n25 \r\nThis is the data in the first chunk\r\n\r\n1C\r\nand this is the second one\r\n\r\n0 \r\n\r\n"
4
+ // type : HTTP_RESPONSE
5
+ // method: HTTP_DELETE
6
+ // status code :200
7
+ // request_path:
8
+ // request_url :
9
+ // fragment :
10
+ // query_string:
11
+ // body :"This is the data in the first chunk\r\nand this is the second one\r\n"
12
+ // body_size :65
13
+ // header_0 :{ "Content-Type": "text/plain"}
14
+ // header_1 :{ "Transfer-Encoding": "chunked"}
15
+ // should_keep_alive :1
16
+ // upgrade :0
17
+ // http_major :1
18
+ // http_minor :1
19
+
20
+
21
+ import java.io.FileReader;
22
+ import java.io.BufferedReader;
23
+
24
+ import java.util.*;
25
+ import java.util.regex.*;
26
+
27
+ import java.nio.ByteBuffer;
28
+
29
+ import http_parser.HTTPMethod;
30
+ import http_parser.ParserType;
31
+
32
+ public class TestLoaderNG {
33
+ String fn;
34
+ public TestLoaderNG(String filename) {
35
+ this.fn = filename;
36
+ }
37
+ static void p(Object o) {
38
+ System.out.println(o);
39
+ }
40
+ public List<Test> load () throws Throwable {
41
+ List<Test> list = new LinkedList<Test>();
42
+ BufferedReader buf = new BufferedReader(new FileReader(fn));
43
+ String line = null;
44
+ Test curr = new Test();
45
+ Pattern pattern = Pattern.compile("(\\S+)\\s*:(.*)");
46
+ while (null != (line = buf.readLine()) ){
47
+ if ("".equals(line.trim())) {
48
+ list.add (curr);
49
+ curr = new Test();
50
+ continue;
51
+ }
52
+ Matcher m = pattern.matcher(line);
53
+ if (m.matches()) {
54
+ // you can not be fucking serious!?
55
+ // this has got to be the most retarded regex
56
+ // interface in the history of the world ...
57
+ // (though I'm sure there's worse c++ regexp libs...)
58
+ MatchResult r = m.toMatchResult();
59
+ String key = r.group(1).trim();
60
+ String value = r.group(2).trim();
61
+ if ("name".equals(key)) {curr.name = value;}
62
+ else if ("raw".equals(key)) {curr.raw = toByteArray(value);} //!
63
+ else if ("type".equals(key)) {curr.type = ParserType.parse(value);}
64
+ else if ("method".equals(key)) {curr.method = HTTPMethod.parse(value);}
65
+ else if ("status_code".equals(key)) {curr.status_code = Integer.parseInt(value);}
66
+ else if ("request_path".equals(key)) {curr.request_path = value;}
67
+ else if ("request_url".equals(key)) {curr.request_url = value;}
68
+
69
+ else if ("fragment".equals(key)) {curr.fragment = value;}
70
+ else if ("query_string".equals(key)) {curr.query_string = value;}
71
+ else if ("body".equals(key)) {curr.body = toByteArray(value);} //!
72
+ else if ("body_size".equals(key)) {curr.body_size = Integer.parseInt(value);}
73
+ else if (key.startsWith("header")) {
74
+ String [] h = getHeader(value);
75
+ curr.header.put(h[0], h[1]);
76
+ }
77
+ else if ("should_keep_alive".equals(key))
78
+ {curr.should_keep_alive = (1 == Integer.parseInt(value));}
79
+ else if ("upgrade".equals(key)) {curr.upgrade = (1 == Integer.parseInt(value));}
80
+ else if ("http_major".equals(key)) {curr.http_major = Integer.parseInt(value);}
81
+ else if ("http_minor".equals(key)) {curr.http_minor = Integer.parseInt(value);}
82
+ } else {
83
+ p("WTF?"+line);
84
+ }
85
+
86
+ }
87
+ return list;
88
+ }
89
+
90
+ String [] getHeader(String value) {
91
+ // { "Host": "0.0.0.0=5000"}
92
+ Pattern p = Pattern.compile("\\{ ?\"([^\"]*)\": ?\"([^\"]*)\"}");
93
+ Matcher m = p.matcher(value);
94
+ if (!m.matches()) {
95
+ p(value);
96
+ throw new RuntimeException("something wrong");
97
+ }
98
+ String [] result = new String[2];
99
+ MatchResult r = m.toMatchResult();
100
+ result[0] = r.group(1).trim();
101
+ result[1] = r.group(2).trim();
102
+ return result;
103
+ }
104
+
105
+ static final byte BSLASH = 0x5c;
106
+ static final byte QUOT = 0x22;
107
+ static final byte CR = 0x0d;
108
+ static final byte LF = 0x0a;
109
+ static final byte n = 0x6e;
110
+ static final byte r = 0x72;
111
+
112
+ static final Byte[] JAVA_GENERICS_ROCK_HARD = new Byte[0];
113
+
114
+
115
+ static byte [] toByteArray (String quotedString) {
116
+ ArrayList<Byte> bytes = new ArrayList<Byte>();
117
+ String s = quotedString.substring(1, quotedString.length()-1);
118
+ byte [] byts = s.getBytes(java.nio.charset.Charset.forName("ASCII"));
119
+ boolean escaped = false;
120
+ for (byte b : byts) {
121
+ switch (b) {
122
+ case BSLASH:
123
+ escaped = true;
124
+ break;
125
+ case n:
126
+ if (escaped) {
127
+ bytes.add(LF);
128
+ escaped = false;
129
+ } else {
130
+ bytes.add(b);
131
+ }
132
+ break;
133
+ case r:
134
+ if (escaped) {
135
+ escaped = false;
136
+ bytes.add(CR);
137
+ } else {
138
+ bytes.add(b);
139
+ }
140
+ break;
141
+ case QUOT:
142
+ escaped = false;
143
+ bytes.add(QUOT);
144
+ break;
145
+ default:
146
+ bytes.add(b);
147
+ }
148
+
149
+ }
150
+ //Byte [] fuckyou = bytes.toArray(JAVA_GENERICS_ROCK_HARD);
151
+ //return (byte[])fuckyou;
152
+ byts = new byte[bytes.size()];
153
+ int i = 0;
154
+ for (Byte b : bytes) {
155
+ byts[i++]=b;
156
+ // OMG, WFTBBQ!?
157
+ }
158
+ return byts;
159
+ }
160
+
161
+ public static void main(String [] args) throws Throwable {
162
+ TestLoaderNG l = new TestLoaderNG(args[0]);
163
+ List<Test> ts = l.load();
164
+
165
+ for (Test t : ts) {
166
+ t.execute_permutations();
167
+ // t.execute();
168
+ // System.exit(0);
169
+ }
170
+ }
171
+
172
+
173
+ class Test {
174
+ String name;
175
+ byte [] raw;
176
+ ParserType type;
177
+ HTTPMethod method;
178
+ int status_code;
179
+ String request_path; // byte [] ?
180
+ String request_url;
181
+ String fragment ;
182
+ String query_string;
183
+ byte [] body;
184
+ int body_size;
185
+ Map<String,String> header;
186
+ boolean should_keep_alive;
187
+ boolean upgrade;
188
+ int http_major;
189
+ int http_minor;
190
+
191
+ boolean message_begin_called;
192
+ boolean message_complete_called;
193
+ boolean headers_complete_called;
194
+
195
+
196
+ Map<String,String> parsed_header;
197
+ String currHField;
198
+ String currHValue;
199
+ byte [] pbody;
200
+
201
+ public String toString() {
202
+ StringBuilder b = new StringBuilder();
203
+ b.append("type: "); b.append(type);b.append("\n");
204
+ b.append("method: "); b.append(method);b.append("\n");
205
+ b.append("status_code: "); b.append(status_code);b.append("\n");
206
+ b.append("request_path: "); b.append(request_path);b.append("\n");
207
+ b.append("request_url: "); b.append(request_url);b.append("\n");
208
+ b.append("fragment: "); b.append(fragment);b.append("\n");
209
+ b.append("query_string: "); b.append(query_string);b.append("\n");
210
+ b.append("body:\n"); b.append(new String(body));b.append("\n");
211
+ b.append("should_keep_alive: "); b.append(should_keep_alive);b.append("\n");
212
+ b.append("upgrade: "); b.append(upgrade);b.append("\n");
213
+ b.append("http_major: "); b.append(http_major);b.append("\n");
214
+ b.append("http_minor: "); b.append(http_minor);b.append("\n");
215
+ b.append("message_complete_called: "); b.append(message_complete_called);b.append("\n");
216
+ return b.toString();
217
+ }
218
+
219
+ Test () {
220
+ this.header = new HashMap<String, String>();
221
+ reset();
222
+ }
223
+ /*
224
+ *prepare this Test Instance for reuse.
225
+ * */
226
+ void reset () {
227
+ this.parsed_header = new HashMap<String, String>();
228
+ this.pbody = null;
229
+
230
+ }
231
+ void check (boolean val, String mes) {
232
+ if (!val) {
233
+ //p(name+" : "+mes);
234
+ throw new RuntimeException(name+" : "+mes);
235
+ }
236
+ }
237
+
238
+ String str (ByteBuffer b, int pos, int len) {
239
+ byte [] by = new byte[len];
240
+ int saved = b.position();
241
+ b.position(pos);
242
+ b.get(by);
243
+ b.position(saved);
244
+ return new String(by);
245
+ }
246
+
247
+ HTTPDataCallback getCB (final String value, final String mes, final TestSettings settings) {
248
+ return new HTTPDataCallback() {
249
+ public int cb (HTTPParser p, ByteBuffer b, int pos, int len){
250
+ // if ("url".equals(mes)){
251
+ // p("pos"+pos);
252
+ // p("len"+len);
253
+ // if (8==pos && 5 == len && "connect request".equals(name)) {
254
+ // //throw new RuntimeException(name);
255
+ // }
256
+ // }
257
+ String str = str(b, pos, len);
258
+ String prev_val = settings.map.get(mes);
259
+ settings.map.put(mes, prev_val + str);
260
+ //check(value.equals(str), "incorrect "+mes+": "+str);
261
+ if (-1 == pos) {
262
+ throw new RuntimeException("he?");
263
+ }
264
+ return 0;
265
+ }
266
+ };
267
+ }
268
+
269
+ void execute () {
270
+ p(name);
271
+ ByteBuffer buf = ByteBuffer.wrap(raw);
272
+ HTTPParser p = new HTTPParser();
273
+ TestSettings s = settings();
274
+
275
+
276
+
277
+ p.execute(s, buf);
278
+ if (!s.success) {
279
+ throw new RuntimeException("Test: "+name+"failed");
280
+ }
281
+ } // execute
282
+
283
+ void execute_permutations() {
284
+ /*
285
+ |-|---------------|
286
+ |--|--------------|
287
+ |---|-------------|
288
+ (...)
289
+ |---------------|-|
290
+ |-----------------|
291
+ */
292
+ p(name);
293
+ for (int i = 2; i != raw.length; ++i) {
294
+ // p(i);
295
+ HTTPParser p = new HTTPParser();
296
+ TestSettings s = settings();
297
+ ByteBuffer buf = ByteBuffer.wrap(raw);
298
+ int olimit = buf.limit();
299
+ buf.limit(i);
300
+
301
+ parse(p,s,buf);
302
+
303
+ buf.position(i);
304
+ buf.limit(olimit);
305
+
306
+ parse(p,s,buf);
307
+ parse(p,s,buf);
308
+
309
+ if (!s.success) {
310
+ p(this);
311
+ throw new RuntimeException("Test: "+name+" failed");
312
+ }
313
+ reset();
314
+ }
315
+ //System.exit(0);
316
+ } // execute_permutations
317
+ void parse(HTTPParser p, ParserSettings s, ByteBuffer b) {
318
+ //p("About to parse: "+b.position() + "->" + b.limit());
319
+ p.execute(s, b);
320
+ }
321
+
322
+ TestSettings settings() {
323
+ final TestSettings s = new TestSettings();
324
+ s.on_path = getCB(request_path, "path", s);
325
+ s.on_query_string = getCB(query_string, "query_string", s);
326
+ s.on_url = getCB(request_url, "url", s);
327
+ s.on_fragment = getCB(fragment, "fragment", s);
328
+ s.on_message_begin = new HTTPCallback() {
329
+ public int cb (HTTPParser p) {
330
+ message_begin_called = true;
331
+ return -1;
332
+ }
333
+ };
334
+ s.on_header_field = new HTTPDataCallback() {
335
+ public int cb (HTTPParser p, ByteBuffer b, int pos, int len){
336
+ if (null != currHValue && null == currHField) {
337
+ throw new RuntimeException(name+": shouldn't happen");
338
+ }
339
+ if (null != currHField) {
340
+ if (null == currHValue) {
341
+ currHField += str(b,pos,len);
342
+ return 0;
343
+ } else {
344
+ parsed_header.put(currHField, currHValue);
345
+ currHField = null;
346
+ currHValue = null;
347
+ }
348
+ }
349
+ currHField = str(b,pos,len);
350
+ return 0;
351
+ }
352
+ };
353
+ s.on_header_value = new HTTPDataCallback() {
354
+ public int cb (HTTPParser p, ByteBuffer b, int pos, int len){
355
+ if (null == currHField) {
356
+ throw new RuntimeException(name+" :shouldn't happen field");
357
+ }
358
+ if (null == currHValue) {
359
+ currHValue = str(b,pos,len);
360
+ } else {
361
+ currHValue += str(b, pos, len);
362
+ }
363
+ return 0;
364
+ }
365
+ };
366
+ s.on_headers_complete = new HTTPCallback() {
367
+ public int cb (HTTPParser p) {
368
+ headers_complete_called = true;
369
+ String parsed_path = s.map.get("path");
370
+ String parsed_query = s.map.get("query_string");
371
+ String parsed_url = s.map.get("url");
372
+ String parsed_frag = s.map.get("fragment");
373
+
374
+ if (!request_path.equals(parsed_path)) {
375
+ throw new RuntimeException(name+": invalid path: "+parsed_path+" should be: "+request_path);
376
+ }
377
+ if (!query_string.equals(parsed_query)) {
378
+ throw new RuntimeException(name+": invalid query: "+parsed_query+" should be: "+query_string);
379
+ }
380
+ if (!request_url.equals(parsed_url)) {
381
+ throw new RuntimeException(">"+name+"<: invalid url: >"+parsed_url+"< should be: >"+request_url+"<");
382
+ }
383
+ if (!fragment.equals(parsed_frag)) {
384
+ throw new RuntimeException(name+": invalid fragement: "+parsed_frag+" should be: "+fragment);
385
+ }
386
+ if (null != currHValue || null != currHField) {
387
+ if (null == currHField || null == currHValue) {
388
+ throw new RuntimeException("shouldn't happen");
389
+ }
390
+ }
391
+ if (null != currHField) {
392
+ parsed_header.put(currHField, currHValue);
393
+ currHField = null;
394
+ currHValue = null;
395
+ }
396
+
397
+
398
+ return 0;
399
+ }
400
+ };
401
+ // s.on_headers_complete = new HTTPCallback() {
402
+ // public int cb (HTTPParser p) {
403
+ // p("Complete:"+name);
404
+ // return 0;
405
+ // }
406
+ // };
407
+
408
+ s.on_body = new HTTPDataCallback() {
409
+ public int cb (HTTPParser p, ByteBuffer b, int pos, int len){
410
+ int l = pbody == null ? len : len + pbody.length;
411
+ int off = pbody == null ? 0 : pbody.length;
412
+ byte [] nbody = new byte[l];
413
+
414
+ if (null != pbody) {
415
+ System.arraycopy(pbody, 0, nbody, 0, pbody.length);
416
+ }
417
+
418
+ int saved = b.position();
419
+ b.position(pos);
420
+ b.get(nbody, off, len);
421
+ b.position(saved);
422
+ pbody = nbody;
423
+ return 0;
424
+ }
425
+ };
426
+
427
+ s.on_message_complete = new HTTPCallback() {
428
+ public int cb(HTTPParser p) {
429
+ message_complete_called = true;
430
+ if ( p.http_minor != http_minor
431
+ || p.http_major != http_major
432
+ || p.status_code != status_code ) {
433
+
434
+ throw new RuntimeException("major/minor/status_code mismatch");
435
+ }
436
+
437
+ //check headers
438
+
439
+ if (header.keySet().size() != parsed_header.keySet().size()) {
440
+ p(parsed_header);
441
+ throw new RuntimeException(name+": different amount of headers");
442
+ }
443
+ for (String key : header.keySet()) {
444
+ String pvalue = parsed_header.get(key);
445
+ if (!header.get(key).equals(pvalue)) {
446
+ throw new RuntimeException(name+" : different values for :"+key+" is >"+pvalue+"< should: >"+header.get(key)+"<");
447
+ }
448
+ }
449
+ //check body
450
+ if (null == pbody && (null == body || body.length == 0 || body.length == 1)) {
451
+ s.success = true;
452
+ return 0;
453
+ }
454
+ if (null == pbody) {
455
+ throw new RuntimeException(name+": no body, should be: "+new String(body));
456
+ }
457
+ if (pbody.length != body.length) {
458
+ p(pbody.length);
459
+ p(body.length);
460
+ p(new String(pbody));
461
+ p(new String(body));
462
+ throw new RuntimeException(name+": incorrect body length");
463
+ }
464
+ for (int i = 0 ; i!= body.length; ++i) {
465
+ if (pbody[i] != body[i]) {
466
+ throw new RuntimeException("different body");
467
+ }
468
+ }
469
+ s.success = true;
470
+ return 0;
471
+ }
472
+ };
473
+ return s;
474
+ } // settings
475
+ }
476
+ class TestSettings extends ParserSettings {
477
+ public boolean success;
478
+ Map<String, String> map;
479
+ TestSettings () {
480
+ map = new HashMap<String, String>();
481
+ map.put("path", "");
482
+ map.put("query_string", "");
483
+ map.put("url", "");
484
+ map.put("fragment", "");
485
+ }
486
+ }
487
+ }