http_parser.rb 0.5.1-x86-mswin32-60 → 0.5.2-x86-mswin32-60
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.
- data/Gemfile.lock +16 -16
- 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 +83 -20
- data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +0 -4
@@ -0,0 +1,61 @@
|
|
1
|
+
package http_parser.lolevel;
|
2
|
+
|
3
|
+
import java.nio.*;
|
4
|
+
|
5
|
+
import static http_parser.lolevel.Util.*;
|
6
|
+
|
7
|
+
public class TestNoOverflowLongBody {
|
8
|
+
|
9
|
+
public static void test (http_parser.ParserType type, int len) {
|
10
|
+
HTTPParser parser = new HTTPParser(type);
|
11
|
+
ByteBuffer buf = getBytes(type, len);
|
12
|
+
|
13
|
+
int buflen = buf.limit();
|
14
|
+
|
15
|
+
parser.execute(Util.SETTINGS_NULL, buf);
|
16
|
+
|
17
|
+
check(buflen == buf.position());
|
18
|
+
|
19
|
+
buf = buffer("a");
|
20
|
+
buflen = buf.limit();
|
21
|
+
|
22
|
+
for (int i = 0; i!= len; ++i) {
|
23
|
+
parser.execute(Util.SETTINGS_NULL, buf);
|
24
|
+
check(buflen == buf.position());
|
25
|
+
buf.rewind();
|
26
|
+
}
|
27
|
+
|
28
|
+
buf = getBytes(type, len);
|
29
|
+
buflen = buf.limit();
|
30
|
+
|
31
|
+
parser.execute(Util.SETTINGS_NULL, buf);
|
32
|
+
|
33
|
+
check(buflen == buf.position());
|
34
|
+
|
35
|
+
}
|
36
|
+
|
37
|
+
static ByteBuffer getBytes (http_parser.ParserType type, int length) {
|
38
|
+
if (http_parser.ParserType.HTTP_BOTH == type) {
|
39
|
+
throw new RuntimeException("only HTTP_REQUEST and HTTP_RESPONSE");
|
40
|
+
}
|
41
|
+
|
42
|
+
String template = "%s\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n";
|
43
|
+
String str = null;
|
44
|
+
if (http_parser.ParserType.HTTP_REQUEST == type) {
|
45
|
+
str = String.format(template, "GET / HTTP/1.1", length);
|
46
|
+
} else {
|
47
|
+
str = String.format(template, "HTTP/1.0 200 OK", length);
|
48
|
+
}
|
49
|
+
return buffer(str);
|
50
|
+
}
|
51
|
+
|
52
|
+
public static void test () {
|
53
|
+
test(http_parser.ParserType.HTTP_REQUEST, 1000);
|
54
|
+
test(http_parser.ParserType.HTTP_REQUEST, 100000);
|
55
|
+
test(http_parser.ParserType.HTTP_RESPONSE, 1000);
|
56
|
+
test(http_parser.ParserType.HTTP_RESPONSE, 100000);
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
}
|
data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java
CHANGED
@@ -2,6 +2,7 @@ package http_parser.lolevel;
|
|
2
2
|
|
3
3
|
import java.nio.ByteBuffer;
|
4
4
|
import http_parser.HTTPException;
|
5
|
+
import http_parser.Util;
|
5
6
|
|
6
7
|
public class UnitTest {
|
7
8
|
|
@@ -108,7 +109,7 @@ public class UnitTest {
|
|
108
109
|
}
|
109
110
|
|
110
111
|
|
111
|
-
public static void
|
112
|
+
public static void test () {
|
112
113
|
testErrorFormat();
|
113
114
|
testErrorCallback();
|
114
115
|
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
package http_parser.lolevel;
|
2
|
+
|
3
|
+
import java.nio.*;
|
4
|
+
import java.util.*;
|
5
|
+
|
6
|
+
import http_parser.ParserType;
|
7
|
+
|
8
|
+
import static http_parser.lolevel.Util.*;
|
9
|
+
|
10
|
+
public class Upgrade {
|
11
|
+
static final String upgrade = "GET /demo HTTP/1.1\r\n" +
|
12
|
+
"Connection: Upgrade\r\n" +
|
13
|
+
"Upgrade: WebSocket\r\n\r\n" +
|
14
|
+
"third key data";
|
15
|
+
static void test () {
|
16
|
+
HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST);
|
17
|
+
ByteBuffer buf = buffer(upgrade);
|
18
|
+
|
19
|
+
int read = parser.execute(Util.SETTINGS_NULL, buf);
|
20
|
+
check (63 == read);
|
21
|
+
String s = str(buf);
|
22
|
+
check ("third key data".equals(str(buf)));
|
23
|
+
|
24
|
+
}
|
25
|
+
|
26
|
+
}
|
@@ -0,0 +1,165 @@
|
|
1
|
+
package http_parser.lolevel;
|
2
|
+
|
3
|
+
import java.nio.*;
|
4
|
+
import java.util.*;
|
5
|
+
|
6
|
+
import primitive.collection.ByteList;
|
7
|
+
|
8
|
+
import http_parser.*;
|
9
|
+
|
10
|
+
public class Util {
|
11
|
+
|
12
|
+
static final ParserSettings SETTINGS_NULL = new ParserSettings();
|
13
|
+
|
14
|
+
static String str (ByteBuffer b, int pos, int len) {
|
15
|
+
byte [] by = new byte[len];
|
16
|
+
int saved = b.position();
|
17
|
+
b.position(pos);
|
18
|
+
b.get(by);
|
19
|
+
b.position(saved);
|
20
|
+
return new String(by);
|
21
|
+
}
|
22
|
+
static String str (ByteBuffer b) {
|
23
|
+
int len = b.limit() - b.position();
|
24
|
+
byte [] by = new byte[len];
|
25
|
+
int saved = b.position();
|
26
|
+
b.get(by);
|
27
|
+
b.position(saved);
|
28
|
+
return new String(by);
|
29
|
+
}
|
30
|
+
|
31
|
+
static ByteBuffer buffer(String str) {
|
32
|
+
return ByteBuffer.wrap(str.getBytes());
|
33
|
+
}
|
34
|
+
|
35
|
+
static ByteBuffer empty() {
|
36
|
+
return ByteBuffer.wrap(new byte[0]);
|
37
|
+
}
|
38
|
+
|
39
|
+
static void check(boolean betterBtrue) {
|
40
|
+
if (!betterBtrue) {
|
41
|
+
throw new RuntimeException("!");
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
static void test_message(Message mes) {
|
46
|
+
int raw_len = mes.raw.length;
|
47
|
+
for (int msg1len = 0; msg1len != raw_len; ++msg1len) {
|
48
|
+
mes.reset();
|
49
|
+
ByteBuffer msg1 = ByteBuffer.wrap(mes.raw, 0, msg1len);
|
50
|
+
ByteBuffer msg2 = ByteBuffer.wrap(mes.raw, msg1len, mes.raw.length - msg1len);
|
51
|
+
|
52
|
+
HTTPParser parser = new HTTPParser(mes.type);
|
53
|
+
ParserSettings settings = mes.settings();
|
54
|
+
|
55
|
+
int read = 0;
|
56
|
+
if (msg1len !=0) {
|
57
|
+
read = parser.execute(settings, msg1);
|
58
|
+
if (mes.upgrade && parser.upgrade) {
|
59
|
+
// Messages have a settings() that checks itself...
|
60
|
+
check(1 == mes.num_called);
|
61
|
+
continue;
|
62
|
+
}
|
63
|
+
check(read == msg1len);
|
64
|
+
}
|
65
|
+
|
66
|
+
read = parser.execute(settings, msg2);
|
67
|
+
if (mes.upgrade && parser.upgrade) {
|
68
|
+
check(1 == mes.num_called);
|
69
|
+
continue;
|
70
|
+
}
|
71
|
+
|
72
|
+
check(read == mes.raw.length - msg1len);
|
73
|
+
|
74
|
+
ByteBuffer empty = Util.empty();
|
75
|
+
read = parser.execute(settings, empty);
|
76
|
+
|
77
|
+
if (mes.upgrade && parser.upgrade) {
|
78
|
+
check(1 == mes.num_called);
|
79
|
+
continue;
|
80
|
+
}
|
81
|
+
check(empty.position() == empty.limit());
|
82
|
+
check(0 == read);
|
83
|
+
check(1 == mes.num_called);
|
84
|
+
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
static void test_multiple3(Message r1, Message r2, Message r3) {
|
89
|
+
int message_count = 1;
|
90
|
+
if (!r1.upgrade) {
|
91
|
+
message_count++;
|
92
|
+
if (!r2.upgrade) {
|
93
|
+
message_count++;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
boolean has_upgrade = (message_count < 3 || r3.upgrade);
|
97
|
+
|
98
|
+
ByteList blist = new ByteList();
|
99
|
+
blist.addAll(r1.raw);
|
100
|
+
blist.addAll(r2.raw);
|
101
|
+
blist.addAll(r3.raw);
|
102
|
+
|
103
|
+
byte [] raw = blist.toArray();
|
104
|
+
ByteBuffer buf = ByteBuffer.wrap(raw);
|
105
|
+
|
106
|
+
Util.Settings settings = Util.settings();
|
107
|
+
HTTPParser parser = new HTTPParser(r1.type);
|
108
|
+
|
109
|
+
int read = parser.execute(settings, buf);
|
110
|
+
if (has_upgrade && parser.upgrade) {
|
111
|
+
check(settings.numCalled == message_count);
|
112
|
+
return;
|
113
|
+
}
|
114
|
+
|
115
|
+
check(read == raw.length);
|
116
|
+
|
117
|
+
buf = Util.empty();
|
118
|
+
read = parser.execute(settings, buf);
|
119
|
+
if (has_upgrade && parser.upgrade) {
|
120
|
+
check(settings.numCalled == message_count);
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
|
124
|
+
check(0 == read);
|
125
|
+
check(settings.numCalled == message_count);
|
126
|
+
}
|
127
|
+
static void p (Object o) {
|
128
|
+
System.out.println(o);
|
129
|
+
}
|
130
|
+
|
131
|
+
static Settings settings() {
|
132
|
+
return new Settings();
|
133
|
+
}
|
134
|
+
static Message find(List<Message> list, String name) {
|
135
|
+
for (Message m : list) {
|
136
|
+
if (name.equals(m.name)) {
|
137
|
+
return m;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
return null;
|
141
|
+
}
|
142
|
+
|
143
|
+
static class Settings extends ParserSettings {
|
144
|
+
public int numCalled;
|
145
|
+
public int bodyCount;
|
146
|
+
Settings() {
|
147
|
+
this.on_message_complete = new HTTPCallback() {
|
148
|
+
public int cb (HTTPParser parser) {
|
149
|
+
numCalled++;
|
150
|
+
return 0;
|
151
|
+
}
|
152
|
+
};
|
153
|
+
this.on_body = new HTTPDataCallback() {
|
154
|
+
public int cb (HTTPParser p, ByteBuffer b, int pos, int len) {
|
155
|
+
bodyCount += len;
|
156
|
+
return 0;
|
157
|
+
}
|
158
|
+
};
|
159
|
+
}
|
160
|
+
|
161
|
+
int numCalled () {
|
162
|
+
return this.numCalled;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
package http_parser.lolevel;
|
2
|
+
|
3
|
+
import java.nio.*;
|
4
|
+
import java.util.*;
|
5
|
+
|
6
|
+
import http_parser.ParserType;
|
7
|
+
|
8
|
+
import static http_parser.lolevel.Util.*;
|
9
|
+
|
10
|
+
public class WrongContentLength {
|
11
|
+
static final String contentLength = "GET / HTTP/1.0\r\n" +
|
12
|
+
"Content-Length: 5\r\n" +
|
13
|
+
"\r\n" +
|
14
|
+
"hello" +
|
15
|
+
"hello_again";
|
16
|
+
static void test () {
|
17
|
+
HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST);
|
18
|
+
ByteBuffer buf = buffer(contentLength);
|
19
|
+
|
20
|
+
Settings settings = new Settings();
|
21
|
+
|
22
|
+
int read = parser.execute(settings, buf);
|
23
|
+
check (settings.msg_cmplt_called);
|
24
|
+
check ("invalid method".equals(settings.err));
|
25
|
+
|
26
|
+
}
|
27
|
+
public static void main(String [] args) {
|
28
|
+
test();
|
29
|
+
}
|
30
|
+
|
31
|
+
static class Settings extends ParserSettings {
|
32
|
+
public int bodyCount;
|
33
|
+
public boolean msg_cmplt_called;
|
34
|
+
public String err;
|
35
|
+
Settings () {
|
36
|
+
this.on_message_complete = new HTTPCallback () {
|
37
|
+
public int cb (HTTPParser p) {
|
38
|
+
check (5 == bodyCount);
|
39
|
+
msg_cmplt_called = true;
|
40
|
+
return 0;
|
41
|
+
}
|
42
|
+
};
|
43
|
+
this.on_body = new HTTPDataCallback() {
|
44
|
+
public int cb (HTTPParser p, ByteBuffer b, int pos, int len) {
|
45
|
+
bodyCount += len;
|
46
|
+
p(str(b, pos, len));
|
47
|
+
return 0;
|
48
|
+
}
|
49
|
+
};
|
50
|
+
this.on_error = new HTTPErrorCallback() {
|
51
|
+
public void cb (HTTPParser p, String mes, ByteBuffer b, int i) {
|
52
|
+
err = mes;
|
53
|
+
}
|
54
|
+
};
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/* Copyright
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
2
2
|
*
|
3
3
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
* of this software and associated documentation files (the "Software"), to
|
@@ -31,7 +31,7 @@
|
|
31
31
|
#undef FALSE
|
32
32
|
#define FALSE 0
|
33
33
|
|
34
|
-
#define MAX_HEADERS
|
34
|
+
#define MAX_HEADERS 13
|
35
35
|
#define MAX_ELEMENT_SIZE 500
|
36
36
|
|
37
37
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
@@ -498,7 +498,7 @@ const struct message requests[] =
|
|
498
498
|
#define CONNECT_REQUEST 17
|
499
499
|
, {.name = "connect request"
|
500
500
|
,.type= HTTP_REQUEST
|
501
|
-
,.raw= "CONNECT
|
501
|
+
,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n"
|
502
502
|
"User-agent: Mozilla/1.1N\r\n"
|
503
503
|
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
504
504
|
"\r\n"
|
@@ -510,7 +510,7 @@ const struct message requests[] =
|
|
510
510
|
,.query_string= ""
|
511
511
|
,.fragment= ""
|
512
512
|
,.request_path= ""
|
513
|
-
,.request_url= "
|
513
|
+
,.request_url= "home0.netscape.com:443"
|
514
514
|
,.num_headers= 2
|
515
515
|
,.upgrade=1
|
516
516
|
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
@@ -538,6 +538,128 @@ const struct message requests[] =
|
|
538
538
|
,.body= ""
|
539
539
|
}
|
540
540
|
|
541
|
+
#define NO_HTTP_VERSION 19
|
542
|
+
, {.name= "request with no http version"
|
543
|
+
,.type= HTTP_REQUEST
|
544
|
+
,.raw= "GET /\r\n"
|
545
|
+
"\r\n"
|
546
|
+
,.should_keep_alive= FALSE
|
547
|
+
,.message_complete_on_eof= FALSE
|
548
|
+
,.http_major= 0
|
549
|
+
,.http_minor= 9
|
550
|
+
,.method= HTTP_GET
|
551
|
+
,.query_string= ""
|
552
|
+
,.fragment= ""
|
553
|
+
,.request_path= "/"
|
554
|
+
,.request_url= "/"
|
555
|
+
,.num_headers= 0
|
556
|
+
,.headers= {}
|
557
|
+
,.body= ""
|
558
|
+
}
|
559
|
+
|
560
|
+
#define MSEARCH_REQ 20
|
561
|
+
, {.name= "m-search request"
|
562
|
+
,.type= HTTP_REQUEST
|
563
|
+
,.raw= "M-SEARCH * HTTP/1.1\r\n"
|
564
|
+
"HOST: 239.255.255.250:1900\r\n"
|
565
|
+
"MAN: \"ssdp:discover\"\r\n"
|
566
|
+
"ST: \"ssdp:all\"\r\n"
|
567
|
+
"\r\n"
|
568
|
+
,.should_keep_alive= TRUE
|
569
|
+
,.message_complete_on_eof= FALSE
|
570
|
+
,.http_major= 1
|
571
|
+
,.http_minor= 1
|
572
|
+
,.method= HTTP_MSEARCH
|
573
|
+
,.query_string= ""
|
574
|
+
,.fragment= ""
|
575
|
+
,.request_path= "*"
|
576
|
+
,.request_url= "*"
|
577
|
+
,.num_headers= 3
|
578
|
+
,.headers= { { "HOST", "239.255.255.250:1900" }
|
579
|
+
, { "MAN", "\"ssdp:discover\"" }
|
580
|
+
, { "ST", "\"ssdp:all\"" }
|
581
|
+
}
|
582
|
+
,.body= ""
|
583
|
+
}
|
584
|
+
|
585
|
+
#define UTF8_PATH_REQ 21
|
586
|
+
, {.name= "utf-8 path request"
|
587
|
+
,.type= HTTP_REQUEST
|
588
|
+
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
|
589
|
+
"Host: github.com\r\n"
|
590
|
+
"\r\n"
|
591
|
+
,.should_keep_alive= TRUE
|
592
|
+
,.message_complete_on_eof= FALSE
|
593
|
+
,.http_major= 1
|
594
|
+
,.http_minor= 1
|
595
|
+
,.method= HTTP_GET
|
596
|
+
,.query_string= "q=1"
|
597
|
+
,.fragment= "narf"
|
598
|
+
,.request_path= "/δ¶/δt/pope"
|
599
|
+
,.request_url= "/δ¶/δt/pope?q=1#narf"
|
600
|
+
,.num_headers= 1
|
601
|
+
,.headers= { {"Host", "github.com" }
|
602
|
+
}
|
603
|
+
,.body= ""
|
604
|
+
}
|
605
|
+
|
606
|
+
#define QUERY_TERMINATED_HOST 22
|
607
|
+
, {.name= "host terminated by a query string"
|
608
|
+
,.type= HTTP_REQUEST
|
609
|
+
,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
|
610
|
+
"\r\n"
|
611
|
+
,.should_keep_alive= TRUE
|
612
|
+
,.message_complete_on_eof= FALSE
|
613
|
+
,.http_major= 1
|
614
|
+
,.http_minor= 1
|
615
|
+
,.method= HTTP_GET
|
616
|
+
,.query_string= "hail=all"
|
617
|
+
,.fragment= ""
|
618
|
+
,.request_path= ""
|
619
|
+
,.request_url= "http://hypnotoad.org?hail=all"
|
620
|
+
,.num_headers= 0
|
621
|
+
,.headers= { }
|
622
|
+
,.body= ""
|
623
|
+
}
|
624
|
+
|
625
|
+
#define QUERY_TERMINATED_HOSTPORT 23
|
626
|
+
, {.name= "host:port terminated by a query string"
|
627
|
+
,.type= HTTP_REQUEST
|
628
|
+
,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
|
629
|
+
"\r\n"
|
630
|
+
,.should_keep_alive= TRUE
|
631
|
+
,.message_complete_on_eof= FALSE
|
632
|
+
,.http_major= 1
|
633
|
+
,.http_minor= 1
|
634
|
+
,.method= HTTP_GET
|
635
|
+
,.query_string= "hail=all"
|
636
|
+
,.fragment= ""
|
637
|
+
,.request_path= ""
|
638
|
+
,.request_url= "http://hypnotoad.org:1234?hail=all"
|
639
|
+
,.num_headers= 0
|
640
|
+
,.headers= { }
|
641
|
+
,.body= ""
|
642
|
+
}
|
643
|
+
|
644
|
+
#define SPACE_TERMINATED_HOSTPORT 24
|
645
|
+
, {.name= "host:port terminated by a space"
|
646
|
+
,.type= HTTP_REQUEST
|
647
|
+
,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
|
648
|
+
"\r\n"
|
649
|
+
,.should_keep_alive= TRUE
|
650
|
+
,.message_complete_on_eof= FALSE
|
651
|
+
,.http_major= 1
|
652
|
+
,.http_minor= 1
|
653
|
+
,.method= HTTP_GET
|
654
|
+
,.query_string= ""
|
655
|
+
,.fragment= ""
|
656
|
+
,.request_path= ""
|
657
|
+
,.request_url= "http://hypnotoad.org:1234"
|
658
|
+
,.num_headers= 0
|
659
|
+
,.headers= { }
|
660
|
+
,.body= ""
|
661
|
+
}
|
662
|
+
|
541
663
|
, {.name= NULL } /* sentinel */
|
542
664
|
};
|
543
665
|
|
@@ -551,9 +673,10 @@ const struct message responses[] =
|
|
551
673
|
"Content-Type: text/html; charset=UTF-8\r\n"
|
552
674
|
"Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
|
553
675
|
"Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
|
676
|
+
"X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
|
554
677
|
"Cache-Control: public, max-age=2592000\r\n"
|
555
678
|
"Server: gws\r\n"
|
556
|
-
"Content-Length:
|
679
|
+
"Content-Length: 219 \r\n"
|
557
680
|
"\r\n"
|
558
681
|
"<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
559
682
|
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
@@ -566,15 +689,16 @@ const struct message responses[] =
|
|
566
689
|
,.http_major= 1
|
567
690
|
,.http_minor= 1
|
568
691
|
,.status_code= 301
|
569
|
-
,.num_headers=
|
692
|
+
,.num_headers= 8
|
570
693
|
,.headers=
|
571
694
|
{ { "Location", "http://www.google.com/" }
|
572
695
|
, { "Content-Type", "text/html; charset=UTF-8" }
|
573
696
|
, { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
|
574
697
|
, { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
|
698
|
+
, { "X-$PrototypeBI-Version", "1.6.0.3" }
|
575
699
|
, { "Cache-Control", "public, max-age=2592000" }
|
576
700
|
, { "Server", "gws" }
|
577
|
-
, { "Content-Length", "219" }
|
701
|
+
, { "Content-Length", "219 " }
|
578
702
|
}
|
579
703
|
,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
580
704
|
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
@@ -833,6 +957,71 @@ const struct message responses[] =
|
|
833
957
|
,.body= "<xml>hello</xml>"
|
834
958
|
}
|
835
959
|
|
960
|
+
|
961
|
+
#define RES_FIELD_UNDERSCORE 10
|
962
|
+
/* Should handle spaces in header fields */
|
963
|
+
, {.name= "field underscore"
|
964
|
+
,.type= HTTP_RESPONSE
|
965
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
966
|
+
"Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
|
967
|
+
"Server: Apache\r\n"
|
968
|
+
"Cache-Control: no-cache, must-revalidate\r\n"
|
969
|
+
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
|
970
|
+
".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
|
971
|
+
"Vary: Accept-Encoding\r\n"
|
972
|
+
"_eep-Alive: timeout=45\r\n" /* semantic value ignored */
|
973
|
+
"_onnection: Keep-Alive\r\n" /* semantic value ignored */
|
974
|
+
"Transfer-Encoding: chunked\r\n"
|
975
|
+
"Content-Type: text/html\r\n"
|
976
|
+
"Connection: close\r\n"
|
977
|
+
"\r\n"
|
978
|
+
"0\r\n\r\n"
|
979
|
+
,.should_keep_alive= FALSE
|
980
|
+
,.message_complete_on_eof= FALSE
|
981
|
+
,.http_major= 1
|
982
|
+
,.http_minor= 1
|
983
|
+
,.status_code= 200
|
984
|
+
,.num_headers= 11
|
985
|
+
,.headers=
|
986
|
+
{ { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
|
987
|
+
, { "Server", "Apache" }
|
988
|
+
, { "Cache-Control", "no-cache, must-revalidate" }
|
989
|
+
, { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
|
990
|
+
, { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
|
991
|
+
, { "Vary", "Accept-Encoding" }
|
992
|
+
, { "_eep-Alive", "timeout=45" }
|
993
|
+
, { "_onnection", "Keep-Alive" }
|
994
|
+
, { "Transfer-Encoding", "chunked" }
|
995
|
+
, { "Content-Type", "text/html" }
|
996
|
+
, { "Connection", "close" }
|
997
|
+
}
|
998
|
+
,.body= ""
|
999
|
+
}
|
1000
|
+
|
1001
|
+
#define NON_ASCII_IN_STATUS_LINE 11
|
1002
|
+
/* Should handle non-ASCII in status line */
|
1003
|
+
, {.name= "non-ASCII in status line"
|
1004
|
+
,.type= HTTP_RESPONSE
|
1005
|
+
,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
|
1006
|
+
"Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
|
1007
|
+
"Content-Length: 0\r\n"
|
1008
|
+
"Connection: close\r\n"
|
1009
|
+
"\r\n"
|
1010
|
+
,.should_keep_alive= FALSE
|
1011
|
+
,.message_complete_on_eof= FALSE
|
1012
|
+
,.http_major= 1
|
1013
|
+
,.http_minor= 1
|
1014
|
+
,.status_code= 500
|
1015
|
+
,.num_headers= 3
|
1016
|
+
,.headers=
|
1017
|
+
{ { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
|
1018
|
+
, { "Content-Length", "0" }
|
1019
|
+
, { "Connection", "close" }
|
1020
|
+
}
|
1021
|
+
,.body= ""
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
|
836
1025
|
, {.name= NULL } /* sentinel */
|
837
1026
|
};
|
838
1027
|
|
@@ -1538,8 +1727,8 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
|
1538
1727
|
char *
|
1539
1728
|
quote(const char * orig) {
|
1540
1729
|
size_t j, i, len = strlen(orig);
|
1541
|
-
char * quoted = malloc(len*2); // hm..
|
1542
|
-
bzero(quoted, len*2);
|
1730
|
+
char * quoted = malloc(len == 0 ? 1 : len*2); // hm..
|
1731
|
+
bzero(quoted, len == 0 ? 1 : len*2);
|
1543
1732
|
for (i=0, j=0; i!=len; ++i) {
|
1544
1733
|
switch (orig[i]){
|
1545
1734
|
case '\n':
|
@@ -1578,27 +1767,33 @@ dump_message(const struct message * m)
|
|
1578
1767
|
printf("type :HTTP_BOTH\n");
|
1579
1768
|
}
|
1580
1769
|
switch (m->method) {
|
1581
|
-
case HTTP_DELETE:
|
1582
|
-
case HTTP_GET:
|
1583
|
-
case HTTP_HEAD:
|
1584
|
-
case HTTP_POST:
|
1585
|
-
case HTTP_PUT:
|
1586
|
-
case HTTP_CONNECT:
|
1587
|
-
case HTTP_OPTIONS:
|
1588
|
-
case HTTP_TRACE:
|
1589
|
-
case HTTP_COPY:
|
1590
|
-
case HTTP_LOCK:
|
1591
|
-
case HTTP_MKCOL:
|
1592
|
-
case HTTP_MOVE:
|
1593
|
-
case HTTP_PROPFIND:
|
1594
|
-
case HTTP_PROPPATCH:
|
1595
|
-
case HTTP_UNLOCK:
|
1770
|
+
case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
|
1771
|
+
case HTTP_GET: printf("method: HTTP_GET\n");break;
|
1772
|
+
case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
|
1773
|
+
case HTTP_POST: printf("method: HTTP_POST\n");break;
|
1774
|
+
case HTTP_PUT: printf("method: HTTP_PUT\n");break;
|
1775
|
+
case HTTP_CONNECT: printf("method: HTTP_CONNECT\n");break;
|
1776
|
+
case HTTP_OPTIONS: printf("method: HTTP_OPTIONS\n");break;
|
1777
|
+
case HTTP_TRACE: printf("method: HTTP_TRACE\n");break;
|
1778
|
+
case HTTP_COPY: printf("method: HTTP_COPY\n");break;
|
1779
|
+
case HTTP_LOCK: printf("method: HTTP_LOCK\n");break;
|
1780
|
+
case HTTP_MKCOL: printf("method: HTTP_MKCOL\n");break;
|
1781
|
+
case HTTP_MOVE: printf("method: HTTP_MOVE\n");break;
|
1782
|
+
case HTTP_PROPFIND: printf("method: HTTP_PROPFIND\n");break;
|
1783
|
+
case HTTP_PROPPATCH: printf("method: HTTP_PROPPATCH\n");break;
|
1784
|
+
case HTTP_UNLOCK: printf("method: HTTP_UNLOCK\n");break;
|
1596
1785
|
/* subversion */
|
1597
|
-
case HTTP_REPORT:
|
1598
|
-
case HTTP_MKACTIVITY:
|
1599
|
-
case HTTP_CHECKOUT:
|
1600
|
-
case HTTP_MERGE:
|
1786
|
+
case HTTP_REPORT: printf("method: HTTP_REPORT\n"); break;
|
1787
|
+
case HTTP_MKACTIVITY: printf("method: HTTP_MKACTIVITY\n"); break;
|
1788
|
+
case HTTP_CHECKOUT: printf("method: HTTP_CHECKOUT\n"); break;
|
1789
|
+
case HTTP_MERGE: printf("method: HTTP_MERGE\n"); break;
|
1790
|
+
|
1791
|
+
case HTTP_MSEARCH: printf("method: HTTP_MSEARCH\n"); break;
|
1792
|
+
case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
|
1793
|
+
case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
|
1794
|
+
case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
|
1601
1795
|
default:
|
1796
|
+
printf("method: UNKNOWN\n"); break;
|
1602
1797
|
break;
|
1603
1798
|
}
|
1604
1799
|
printf("status_code :%d\n", m->status_code);
|
@@ -1734,14 +1929,22 @@ main (int argc, char * argv[])
|
|
1734
1929
|
|
1735
1930
|
/// REQUESTS
|
1736
1931
|
|
1737
|
-
|
1738
1932
|
test_simple("hello world", 0);
|
1739
1933
|
test_simple("GET / HTP/1.1\r\n\r\n", 0);
|
1740
1934
|
|
1935
|
+
|
1741
1936
|
test_simple("ASDF / HTTP/1.1\r\n\r\n", 0);
|
1742
1937
|
test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", 0);
|
1743
1938
|
test_simple("GETA / HTTP/1.1\r\n\r\n", 0);
|
1744
1939
|
|
1940
|
+
// Well-formed but incomplete
|
1941
|
+
test_simple("GET / HTTP/1.1\r\n"
|
1942
|
+
"Content-Type: text/plain\r\n"
|
1943
|
+
"Content-Length: 6\r\n"
|
1944
|
+
"\r\n"
|
1945
|
+
"fooba",
|
1946
|
+
0);
|
1947
|
+
|
1745
1948
|
static const char *all_methods[] = {
|
1746
1949
|
"DELETE",
|
1747
1950
|
"GET",
|