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.
Files changed (47) hide show
  1. data/Gemfile.lock +16 -16
  2. data/LICENSE-MIT +20 -0
  3. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +68 -11
  4. data/ext/ruby_http_parser/ruby_http_parser.c +74 -6
  5. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +26 -1
  6. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +23 -143
  7. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +3 -0
  8. data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +74 -0
  9. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +115 -61
  10. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +19 -3
  11. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java +8 -0
  12. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +34 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +12 -0
  14. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +4 -2
  15. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +64 -52
  16. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +5 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +323 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/{lolevel/Util.java → Util.java} +27 -28
  19. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +259 -85
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +324 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +69 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +51 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +15 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +47 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +183 -447
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +61 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +2 -1
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +26 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +165 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +58 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +232 -29
  33. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -1
  34. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -1
  35. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +1 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +154 -7
  37. data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +17 -0
  38. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
  39. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +52 -10
  40. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +3 -1
  41. data/ext/ruby_http_parser/vendor/http-parser/test.c +89 -3
  42. data/http_parser.rb.gemspec +8 -2
  43. data/lib/http_parser.rb +17 -0
  44. data/spec/parser_spec.rb +97 -6
  45. data/tasks/compile.rake +3 -1
  46. metadata +83 -20
  47. 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
+ }
@@ -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 main (String [] args) {
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 2009,2010 Ryan Dahl <ry@tinyclouds.org>
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 10
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 home.netscape.com:443 HTTP/1.0\r\n"
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= "home.netscape.com:443"
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: 219\r\n"
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= 7
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: printf("method: HTTP_DELETE\n");break;
1582
- case HTTP_GET: printf("method: HTTP_GET\n");break;
1583
- case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
1584
- case HTTP_POST: printf("method: HTTP_POST\n");break;
1585
- case HTTP_PUT: printf("method: HTTP_PUT\n");break;
1586
- case HTTP_CONNECT: printf("method: HTTP_CONNECT\n");break;
1587
- case HTTP_OPTIONS: printf("method: HTTP_OPTIONS\n");break;
1588
- case HTTP_TRACE: printf("method: HTTP_TRACE\n");break;
1589
- case HTTP_COPY: printf("method: HTTP_COPY\n");break;
1590
- case HTTP_LOCK: printf("method: HTTP_LOCK\n");break;
1591
- case HTTP_MKCOL: printf("method: HTTP_MKCOL\n");break;
1592
- case HTTP_MOVE: printf("method: HTTP_MOVE\n");break;
1593
- case HTTP_PROPFIND: printf("method: HTTP_PROPFIND\n");break;
1594
- case HTTP_PROPPATCH: printf("method: HTTP_PROPPATCH\n");break;
1595
- case HTTP_UNLOCK: printf("method: HTTP_UNLOCK\n");break;
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: printf("method: REPORT\n"); break;
1598
- case HTTP_MKACTIVITY: printf("method: MKACTIVITY\n"); break;
1599
- case HTTP_CHECKOUT: printf("method: CHECKOUT\n"); break;
1600
- case HTTP_MERGE: printf("method: MERGE\n"); break;
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",