pico_http_parser 0.0.3 → 0.0.4

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.
@@ -27,6 +27,12 @@
27
27
  #ifndef picohttpparser_h
28
28
  #define picohttpparser_h
29
29
 
30
+ #include <sys/types.h>
31
+
32
+ #ifdef _MSC_VER
33
+ #define ssize_t intptr_t
34
+ #endif
35
+
30
36
  /* $Id$ */
31
37
 
32
38
  #ifdef __cplusplus
@@ -36,25 +42,42 @@ extern "C" {
36
42
  /* contains name and value of a header (name == NULL if is a continuing line
37
43
  * of a multiline header */
38
44
  struct phr_header {
39
- const char* name;
40
- size_t name_len;
41
- const char* value;
42
- size_t value_len;
45
+ const char *name;
46
+ size_t name_len;
47
+ const char *value;
48
+ size_t value_len;
43
49
  };
44
50
 
45
- /* returns number of bytes cosumed if successful, -2 if request is partial,
51
+ /* returns number of bytes consumed if successful, -2 if request is partial,
46
52
  * -1 if failed */
47
- int phr_parse_request(const char* buf, size_t len, const char** method,
48
- size_t* method_len, const char** path,
49
- size_t* path_len, int* minor_version,
50
- struct phr_header* headers, size_t* num_headers,
51
- size_t last_len);
53
+ int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len,
54
+ int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len);
55
+
56
+ /* ditto */
57
+ int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len,
58
+ struct phr_header *headers, size_t *num_headers, size_t last_len);
52
59
 
53
60
  /* ditto */
54
- int phr_parse_response(const char* _buf, size_t len, int *minor_version,
55
- int *status, const char **msg, size_t *msg_len,
56
- struct phr_header* headers, size_t* num_headers,
57
- size_t last_len);
61
+ int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len);
62
+
63
+ /* should be zero-filled before start */
64
+ struct phr_chunked_decoder {
65
+ size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
66
+ char consume_trailer; /* if trailing headers should be consumed */
67
+ char _hex_count;
68
+ char _state;
69
+ };
70
+
71
+ /* the function rewrites the buffer given as (buf, bufsz) removing the chunked-
72
+ * encoding headers. When the function returns without an error, bufsz is
73
+ * updated to the length of the decoded data available. Applications should
74
+ * repeatedly call the function while it returns -2 (incomplete) every time
75
+ * supplying newly arrived data. If the end of the chunked-encoded data is
76
+ * found, the function returns a non-negative number indicating the number of
77
+ * octets left undecoded at the tail of the supplied buffer. Returns -1 on
78
+ * error.
79
+ */
80
+ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *bufsz);
58
81
 
59
82
  #ifdef __cplusplus
60
83
  }
@@ -26,228 +26,390 @@
26
26
  */
27
27
 
28
28
  #include <stdio.h>
29
+ #include <stdlib.h>
29
30
  #include <string.h>
30
31
  #include "picotest/picotest.h"
31
32
  #include "picohttpparser.h"
32
33
 
33
- static int bufis(const char* s, size_t l, const char* t)
34
+ static int bufis(const char *s, size_t l, const char *t)
34
35
  {
35
- return strlen(t) == l && memcmp(s, t, l) == 0;
36
+ return strlen(t) == l && memcmp(s, t, l) == 0;
36
37
  }
37
38
 
38
39
  static void test_request(void)
39
40
  {
40
- const char* method;
41
- size_t method_len;
42
- const char* path;
43
- size_t path_len;
44
- int minor_version;
45
- struct phr_header headers[4];
46
- size_t num_headers;
47
-
48
- #define PARSE(s, last_len, exp, comment) \
49
- do { \
50
- note(comment); \
51
- num_headers = sizeof(headers) / sizeof(headers[0]); \
52
- ok(phr_parse_request(s, sizeof(s) - 1, &method, &method_len, &path, \
53
- &path_len, &minor_version, headers, \
54
- &num_headers, last_len) \
55
- == (exp == 0 ? strlen(s) : exp)); \
56
- } while (0)
57
-
58
- PARSE("GET / HTTP/1.0\r\n\r\n", 0, 0, "simple");
59
- ok(num_headers == 0);
60
- ok(bufis(method, method_len, "GET"));
61
- ok(bufis(path, path_len, "/"));
62
- ok(minor_version == 0);
63
-
64
- PARSE("GET / HTTP/1.0\r\n\r", 0, -2, "partial");
65
-
66
- PARSE("GET /hoge HTTP/1.1\r\nHost: example.com\r\nCookie: \r\n\r\n", 0, 0,
67
- "parse headers");
68
- ok(num_headers == 2);
69
- ok(bufis(method, method_len, "GET"));
70
- ok(bufis(path, path_len, "/hoge"));
71
- ok(minor_version == 1);
72
- ok(bufis(headers[0].name, headers[0].name_len, "Host"));
73
- ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
74
- ok(bufis(headers[1].name, headers[1].name_len, "Cookie"));
75
- ok(bufis(headers[1].value, headers[1].value_len, ""));
76
-
77
- PARSE("GET /hoge HTTP/1.1\r\nHost: example.com\r\nUser-Agent: \343\201\262\343/1.0\r\n\r\n", 0, 0,
78
- "multibyte included");
79
- ok(num_headers == 2);
80
- ok(bufis(method, method_len, "GET"));
81
- ok(bufis(path, path_len, "/hoge"));
82
- ok(minor_version == 1);
83
- ok(bufis(headers[0].name, headers[0].name_len, "Host"));
84
- ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
85
- ok(bufis(headers[1].name, headers[1].name_len, "User-Agent"));
86
- ok(bufis(headers[1].value, headers[1].value_len, "\343\201\262\343/1.0"));
87
-
88
- PARSE("GET / HTTP/1.0\r\nfoo: \r\nfoo: b\r\n \tc\r\n\r\n", 0, 0,
89
- "parse multiline");
90
- ok(num_headers == 3);
91
- ok(bufis(method, method_len, "GET"));
92
- ok(bufis(path, path_len, "/"));
93
- ok(minor_version == 0);
94
- ok(bufis(headers[0].name, headers[0].name_len, "foo"));
95
- ok(bufis(headers[0].value, headers[0].value_len, ""));
96
- ok(bufis(headers[1].name, headers[1].name_len, "foo"));
97
- ok(bufis(headers[1].value, headers[1].value_len, "b"));
98
- ok(headers[2].name == NULL);
99
- ok(bufis(headers[2].value, headers[2].value_len, " \tc"));
100
-
101
- PARSE("GET / HTTP/1.0\r\nfoo : ab\r\n\r\n", 0, 0,
102
- "parse header name with trailing space");
103
- ok(num_headers == 1);
104
- ok(bufis(method, method_len, "GET"));
105
- ok(bufis(path, path_len, "/"));
106
- ok(minor_version == 0);
107
- ok(bufis(headers[0].name, headers[0].name_len, "foo "));
108
- ok(bufis(headers[0].value, headers[0].value_len, "ab"));
109
-
110
- PARSE("GET", 0, -2, "incomplete 1");
111
- ok(method == NULL);
112
- PARSE("GET ", 0, -2, "incomplete 2");
113
- ok(bufis(method, method_len, "GET"));
114
- PARSE("GET /", 0, -2, "incomplete 3");
115
- ok(path == NULL);
116
- PARSE("GET / ", 0, -2, "incomplete 4");
117
- ok(bufis(path, path_len, "/"));
118
- PARSE("GET / H", 0, -2, "incomplete 5");
119
- PARSE("GET / HTTP/1.", 0, -2, "incomplete 6");
120
- PARSE("GET / HTTP/1.0", 0, -2, "incomplete 7");
121
- ok(minor_version == -1);
122
- PARSE("GET / HTTP/1.0\r", 0, -2, "incomplete 8");
123
- ok(minor_version == 0);
124
-
125
- PARSE("GET /hoge HTTP/1.0\r\n\r", strlen("GET /hoge HTTP/1.0\r\n\r") - 1,
126
- -2, "slowloris (incomplete)");
127
- PARSE("GET /hoge HTTP/1.0\r\n\r\n", strlen("GET /hoge HTTP/1.0\r\n\r\n") - 1,
128
- 0, "slowloris (complete)");
129
-
130
- PARSE("GET / HTTP/1.0\r\n:a\r\n\r\n", 0, -1, "empty header name");
131
- PARSE("GET / HTTP/1.0\r\n :a\r\n\r\n", 0, -1, "header name (space only)");
132
-
133
- PARSE("G\0T / HTTP/1.0\r\n\r\n", 0, -1, "NUL in method");
134
- PARSE("G\tT / HTTP/1.0\r\n\r\n", 0, -1, "tab in method");
135
- PARSE("GET /\x7fhello HTTP/1.0\r\n\r\n", 0, -1, "DEL in uri-path");
136
- PARSE("GET / HTTP/1.0\r\na\0b: c\r\n\r\n", 0, -1, "NUL in header name");
137
- PARSE("GET / HTTP/1.0\r\nab: c\0d\r\n\r\n", 0, -1, "NUL in header value");
138
- PARSE("GET / HTTP/1.0\r\na\033b: c\r\n\r\n", 0, -1, "CTL in header name");
139
- PARSE("GET / HTTP/1.0\r\nab: c\033\r\n\r\n", 0, -1, "CTL in header value");
140
- PARSE("GET /\xa0 HTTP/1.0\r\nh: c\xa2y\r\n\r\n", 0, 0, "accept MSB chars");
141
- ok(num_headers == 1);
142
- ok(bufis(method, method_len, "GET"));
143
- ok(bufis(path, path_len, "/\xa0"));
144
- ok(minor_version == 0);
145
- ok(bufis(headers[0].name, headers[0].name_len, "h"));
146
- ok(bufis(headers[0].value, headers[0].value_len, "c\xa2y"));
41
+ const char *method;
42
+ size_t method_len;
43
+ const char *path;
44
+ size_t path_len;
45
+ int minor_version;
46
+ struct phr_header headers[4];
47
+ size_t num_headers;
48
+
49
+ #define PARSE(s, last_len, exp, comment) \
50
+ do { \
51
+ note(comment); \
52
+ num_headers = sizeof(headers) / sizeof(headers[0]); \
53
+ ok(phr_parse_request(s, sizeof(s) - 1, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, \
54
+ last_len) == (exp == 0 ? strlen(s) : exp)); \
55
+ } while (0)
56
+
57
+ PARSE("GET / HTTP/1.0\r\n\r\n", 0, 0, "simple");
58
+ ok(num_headers == 0);
59
+ ok(bufis(method, method_len, "GET"));
60
+ ok(bufis(path, path_len, "/"));
61
+ ok(minor_version == 0);
62
+
63
+ PARSE("GET / HTTP/1.0\r\n\r", 0, -2, "partial");
64
+
65
+ PARSE("GET /hoge HTTP/1.1\r\nHost: example.com\r\nCookie: \r\n\r\n", 0, 0, "parse headers");
66
+ ok(num_headers == 2);
67
+ ok(bufis(method, method_len, "GET"));
68
+ ok(bufis(path, path_len, "/hoge"));
69
+ ok(minor_version == 1);
70
+ ok(bufis(headers[0].name, headers[0].name_len, "Host"));
71
+ ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
72
+ ok(bufis(headers[1].name, headers[1].name_len, "Cookie"));
73
+ ok(bufis(headers[1].value, headers[1].value_len, ""));
74
+
75
+ PARSE("GET /hoge HTTP/1.1\r\nHost: example.com\r\nUser-Agent: \343\201\262\343/1.0\r\n\r\n", 0, 0, "multibyte included");
76
+ ok(num_headers == 2);
77
+ ok(bufis(method, method_len, "GET"));
78
+ ok(bufis(path, path_len, "/hoge"));
79
+ ok(minor_version == 1);
80
+ ok(bufis(headers[0].name, headers[0].name_len, "Host"));
81
+ ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
82
+ ok(bufis(headers[1].name, headers[1].name_len, "User-Agent"));
83
+ ok(bufis(headers[1].value, headers[1].value_len, "\343\201\262\343/1.0"));
84
+
85
+ PARSE("GET / HTTP/1.0\r\nfoo: \r\nfoo: b\r\n \tc\r\n\r\n", 0, 0, "parse multiline");
86
+ ok(num_headers == 3);
87
+ ok(bufis(method, method_len, "GET"));
88
+ ok(bufis(path, path_len, "/"));
89
+ ok(minor_version == 0);
90
+ ok(bufis(headers[0].name, headers[0].name_len, "foo"));
91
+ ok(bufis(headers[0].value, headers[0].value_len, ""));
92
+ ok(bufis(headers[1].name, headers[1].name_len, "foo"));
93
+ ok(bufis(headers[1].value, headers[1].value_len, "b"));
94
+ ok(headers[2].name == NULL);
95
+ ok(bufis(headers[2].value, headers[2].value_len, " \tc"));
96
+
97
+ PARSE("GET / HTTP/1.0\r\nfoo : ab\r\n\r\n", 0, 0, "parse header name with trailing space");
98
+ ok(num_headers == 1);
99
+ ok(bufis(method, method_len, "GET"));
100
+ ok(bufis(path, path_len, "/"));
101
+ ok(minor_version == 0);
102
+ ok(bufis(headers[0].name, headers[0].name_len, "foo "));
103
+ ok(bufis(headers[0].value, headers[0].value_len, "ab"));
104
+
105
+ PARSE("GET", 0, -2, "incomplete 1");
106
+ ok(method == NULL);
107
+ PARSE("GET ", 0, -2, "incomplete 2");
108
+ ok(bufis(method, method_len, "GET"));
109
+ PARSE("GET /", 0, -2, "incomplete 3");
110
+ ok(path == NULL);
111
+ PARSE("GET / ", 0, -2, "incomplete 4");
112
+ ok(bufis(path, path_len, "/"));
113
+ PARSE("GET / H", 0, -2, "incomplete 5");
114
+ PARSE("GET / HTTP/1.", 0, -2, "incomplete 6");
115
+ PARSE("GET / HTTP/1.0", 0, -2, "incomplete 7");
116
+ ok(minor_version == -1);
117
+ PARSE("GET / HTTP/1.0\r", 0, -2, "incomplete 8");
118
+ ok(minor_version == 0);
119
+
120
+ PARSE("GET /hoge HTTP/1.0\r\n\r", strlen("GET /hoge HTTP/1.0\r\n\r") - 1, -2, "slowloris (incomplete)");
121
+ PARSE("GET /hoge HTTP/1.0\r\n\r\n", strlen("GET /hoge HTTP/1.0\r\n\r\n") - 1, 0, "slowloris (complete)");
122
+
123
+ PARSE("GET / HTTP/1.0\r\n:a\r\n\r\n", 0, -1, "empty header name");
124
+ PARSE("GET / HTTP/1.0\r\n :a\r\n\r\n", 0, -1, "header name (space only)");
125
+
126
+ PARSE("G\0T / HTTP/1.0\r\n\r\n", 0, -1, "NUL in method");
127
+ PARSE("G\tT / HTTP/1.0\r\n\r\n", 0, -1, "tab in method");
128
+ PARSE("GET /\x7fhello HTTP/1.0\r\n\r\n", 0, -1, "DEL in uri-path");
129
+ PARSE("GET / HTTP/1.0\r\na\0b: c\r\n\r\n", 0, -1, "NUL in header name");
130
+ PARSE("GET / HTTP/1.0\r\nab: c\0d\r\n\r\n", 0, -1, "NUL in header value");
131
+ PARSE("GET / HTTP/1.0\r\na\033b: c\r\n\r\n", 0, -1, "CTL in header name");
132
+ PARSE("GET / HTTP/1.0\r\nab: c\033\r\n\r\n", 0, -1, "CTL in header value");
133
+ PARSE("GET /\xa0 HTTP/1.0\r\nh: c\xa2y\r\n\r\n", 0, 0, "accept MSB chars");
134
+ ok(num_headers == 1);
135
+ ok(bufis(method, method_len, "GET"));
136
+ ok(bufis(path, path_len, "/\xa0"));
137
+ ok(minor_version == 0);
138
+ ok(bufis(headers[0].name, headers[0].name_len, "h"));
139
+ ok(bufis(headers[0].value, headers[0].value_len, "c\xa2y"));
147
140
 
148
141
  #undef PARSE
149
142
  }
150
143
 
151
144
  static void test_response(void)
152
145
  {
153
- int minor_version;
154
- int status;
155
- const char *msg;
156
- size_t msg_len;
157
- struct phr_header headers[4];
158
- size_t num_headers;
159
-
160
- #define PARSE(s, last_len, exp, comment) \
161
- do { \
162
- note(comment); \
163
- num_headers = sizeof(headers) / sizeof(headers[0]); \
164
- ok(phr_parse_response(s, strlen(s), &minor_version, &status, \
165
- &msg, &msg_len, headers, \
166
- &num_headers, last_len) \
167
- == (exp == 0 ? strlen(s) : exp)); \
168
- } while (0)
169
-
170
- PARSE("HTTP/1.0 200 OK\r\n\r\n", 0, 0, "simple");
171
- ok(num_headers == 0);
172
- ok(status == 200);
173
- ok(minor_version = 1);
174
- ok(bufis(msg, msg_len, "OK"));
175
-
176
- PARSE("HTTP/1.0 200 OK\r\n\r", 0, -2, "partial");
177
-
178
- PARSE("HTTP/1.1 200 OK\r\nHost: example.com\r\nCookie: \r\n\r\n", 0, 0,
179
- "parse headers");
180
- ok(num_headers == 2);
181
- ok(minor_version == 1);
182
- ok(status == 200);
183
- ok(bufis(msg, msg_len, "OK"));
184
- ok(bufis(headers[0].name, headers[0].name_len, "Host"));
185
- ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
186
- ok(bufis(headers[1].name, headers[1].name_len, "Cookie"));
187
- ok(bufis(headers[1].value, headers[1].value_len, ""));
188
-
189
- PARSE("HTTP/1.0 200 OK\r\nfoo: \r\nfoo: b\r\n \tc\r\n\r\n", 0, 0,
190
- "parse multiline");
191
- ok(num_headers == 3);
192
- ok(minor_version == 0);
193
- ok(status == 200);
194
- ok(bufis(msg, msg_len, "OK"));
195
- ok(bufis(headers[0].name, headers[0].name_len, "foo"));
196
- ok(bufis(headers[0].value, headers[0].value_len, ""));
197
- ok(bufis(headers[1].name, headers[1].name_len, "foo"));
198
- ok(bufis(headers[1].value, headers[1].value_len, "b"));
199
- ok(headers[2].name == NULL);
200
- ok(bufis(headers[2].value, headers[2].value_len, " \tc"));
201
-
202
- PARSE("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0, 0,
203
- "internal server error");
204
- ok(num_headers == 0);
205
- ok(minor_version == 0);
206
- ok(status == 500);
207
- ok(bufis(msg, msg_len, "Internal Server Error"));
208
- ok(msg_len == sizeof("Internal Server Error")-1);
209
-
210
- PARSE("H", 0, -2, "incomplete 1");
211
- PARSE("HTTP/1.", 0, -2, "incomplete 2");
212
- PARSE("HTTP/1.1", 0, -2, "incomplete 3");
213
- ok(minor_version == -1);
214
- PARSE("HTTP/1.1 ", 0, -2, "incomplete 4");
215
- ok(minor_version == 1);
216
- PARSE("HTTP/1.1 2", 0, -2, "incomplete 5");
217
- PARSE("HTTP/1.1 200", 0, -2, "incomplete 6");
218
- ok(status == 0);
219
- PARSE("HTTP/1.1 200 ", 0, -2, "incomplete 7");
220
- ok(status == 200);
221
- PARSE("HTTP/1.1 200 O", 0, -2, "incomplete 8");
222
- PARSE("HTTP/1.1 200 OK\r", 0, -2, "incomplete 9");
223
- ok(msg == NULL);
224
- PARSE("HTTP/1.1 200 OK\r\n", 0, -2, "incomplete 10");
225
- ok(bufis(msg, msg_len, "OK"));
226
- PARSE("HTTP/1.1 200 OK\n", 0, -2, "incomplete 11");
227
- ok(bufis(msg, msg_len, "OK"));
228
-
229
- PARSE("HTTP/1.1 200 OK\r\nA: 1\r", 0, -2, "incomplete 11");
230
- ok(num_headers == 0);
231
- PARSE("HTTP/1.1 200 OK\r\nA: 1\r\n", 0, -2, "incomplete 12");
232
- ok(num_headers == 1);
233
- ok(bufis(headers[0].name, headers[0].name_len, "A"));
234
- ok(bufis(headers[0].value, headers[0].value_len, "1"));
235
-
236
- PARSE("HTTP/1.0 200 OK\r\n\r", strlen("GET /hoge HTTP/1.0\r\n\r") - 1,
237
- -2, "slowloris (incomplete)");
238
- PARSE("HTTP/1.0 200 OK\r\n\r\n", strlen("HTTP/1.0 200 OK\r\n\r\n") - 1,
239
- 0, "slowloris (complete)");
240
-
241
- PARSE("HTTP/1. 200 OK\r\n\r\n", 0, -1, "invalid http version");
242
- PARSE("HTTP/1.2z 200 OK\r\n\r\n", 0, -1, "invalid http version 2");
243
- PARSE("HTTP/1.1 OK\r\n\r\n", 0, -1, "no status code");
244
-
146
+ int minor_version;
147
+ int status;
148
+ const char *msg;
149
+ size_t msg_len;
150
+ struct phr_header headers[4];
151
+ size_t num_headers;
152
+
153
+ #define PARSE(s, last_len, exp, comment) \
154
+ do { \
155
+ note(comment); \
156
+ num_headers = sizeof(headers) / sizeof(headers[0]); \
157
+ ok(phr_parse_response(s, strlen(s), &minor_version, &status, &msg, &msg_len, headers, &num_headers, last_len) == \
158
+ (exp == 0 ? strlen(s) : exp)); \
159
+ } while (0)
160
+
161
+ PARSE("HTTP/1.0 200 OK\r\n\r\n", 0, 0, "simple");
162
+ ok(num_headers == 0);
163
+ ok(status == 200);
164
+ ok(minor_version = 1);
165
+ ok(bufis(msg, msg_len, "OK"));
166
+
167
+ PARSE("HTTP/1.0 200 OK\r\n\r", 0, -2, "partial");
168
+
169
+ PARSE("HTTP/1.1 200 OK\r\nHost: example.com\r\nCookie: \r\n\r\n", 0, 0, "parse headers");
170
+ ok(num_headers == 2);
171
+ ok(minor_version == 1);
172
+ ok(status == 200);
173
+ ok(bufis(msg, msg_len, "OK"));
174
+ ok(bufis(headers[0].name, headers[0].name_len, "Host"));
175
+ ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
176
+ ok(bufis(headers[1].name, headers[1].name_len, "Cookie"));
177
+ ok(bufis(headers[1].value, headers[1].value_len, ""));
178
+
179
+ PARSE("HTTP/1.0 200 OK\r\nfoo: \r\nfoo: b\r\n \tc\r\n\r\n", 0, 0, "parse multiline");
180
+ ok(num_headers == 3);
181
+ ok(minor_version == 0);
182
+ ok(status == 200);
183
+ ok(bufis(msg, msg_len, "OK"));
184
+ ok(bufis(headers[0].name, headers[0].name_len, "foo"));
185
+ ok(bufis(headers[0].value, headers[0].value_len, ""));
186
+ ok(bufis(headers[1].name, headers[1].name_len, "foo"));
187
+ ok(bufis(headers[1].value, headers[1].value_len, "b"));
188
+ ok(headers[2].name == NULL);
189
+ ok(bufis(headers[2].value, headers[2].value_len, " \tc"));
190
+
191
+ PARSE("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0, 0, "internal server error");
192
+ ok(num_headers == 0);
193
+ ok(minor_version == 0);
194
+ ok(status == 500);
195
+ ok(bufis(msg, msg_len, "Internal Server Error"));
196
+ ok(msg_len == sizeof("Internal Server Error") - 1);
197
+
198
+ PARSE("H", 0, -2, "incomplete 1");
199
+ PARSE("HTTP/1.", 0, -2, "incomplete 2");
200
+ PARSE("HTTP/1.1", 0, -2, "incomplete 3");
201
+ ok(minor_version == -1);
202
+ PARSE("HTTP/1.1 ", 0, -2, "incomplete 4");
203
+ ok(minor_version == 1);
204
+ PARSE("HTTP/1.1 2", 0, -2, "incomplete 5");
205
+ PARSE("HTTP/1.1 200", 0, -2, "incomplete 6");
206
+ ok(status == 0);
207
+ PARSE("HTTP/1.1 200 ", 0, -2, "incomplete 7");
208
+ ok(status == 200);
209
+ PARSE("HTTP/1.1 200 O", 0, -2, "incomplete 8");
210
+ PARSE("HTTP/1.1 200 OK\r", 0, -2, "incomplete 9");
211
+ ok(msg == NULL);
212
+ PARSE("HTTP/1.1 200 OK\r\n", 0, -2, "incomplete 10");
213
+ ok(bufis(msg, msg_len, "OK"));
214
+ PARSE("HTTP/1.1 200 OK\n", 0, -2, "incomplete 11");
215
+ ok(bufis(msg, msg_len, "OK"));
216
+
217
+ PARSE("HTTP/1.1 200 OK\r\nA: 1\r", 0, -2, "incomplete 11");
218
+ ok(num_headers == 0);
219
+ PARSE("HTTP/1.1 200 OK\r\nA: 1\r\n", 0, -2, "incomplete 12");
220
+ ok(num_headers == 1);
221
+ ok(bufis(headers[0].name, headers[0].name_len, "A"));
222
+ ok(bufis(headers[0].value, headers[0].value_len, "1"));
223
+
224
+ PARSE("HTTP/1.0 200 OK\r\n\r", strlen("HTTP/1.0 200 OK\r\n\r") - 1, -2, "slowloris (incomplete)");
225
+ PARSE("HTTP/1.0 200 OK\r\n\r\n", strlen("HTTP/1.0 200 OK\r\n\r\n") - 1, 0, "slowloris (complete)");
226
+
227
+ PARSE("HTTP/1. 200 OK\r\n\r\n", 0, -1, "invalid http version");
228
+ PARSE("HTTP/1.2z 200 OK\r\n\r\n", 0, -1, "invalid http version 2");
229
+ PARSE("HTTP/1.1 OK\r\n\r\n", 0, -1, "no status code");
230
+
231
+ #undef PARSE
232
+ }
233
+
234
+ static void test_headers(void)
235
+ {
236
+ /* only test the interface; the core parser is tested by the tests above */
237
+
238
+ struct phr_header headers[4];
239
+ size_t num_headers;
240
+
241
+ #define PARSE(s, last_len, exp, comment) \
242
+ do { \
243
+ note(comment); \
244
+ num_headers = sizeof(headers) / sizeof(headers[0]); \
245
+ ok(phr_parse_headers(s, strlen(s), headers, &num_headers, last_len) == (exp == 0 ? strlen(s) : exp)); \
246
+ } while (0)
247
+
248
+ PARSE("Host: example.com\r\nCookie: \r\n\r\n", 0, 0, "simple");
249
+ ok(num_headers == 2);
250
+ ok(bufis(headers[0].name, headers[0].name_len, "Host"));
251
+ ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
252
+ ok(bufis(headers[1].name, headers[1].name_len, "Cookie"));
253
+ ok(bufis(headers[1].value, headers[1].value_len, ""));
254
+
255
+ PARSE("Host: example.com\r\nCookie: \r\n\r\n", 1, 0, "slowloris");
256
+ ok(num_headers == 2);
257
+ ok(bufis(headers[0].name, headers[0].name_len, "Host"));
258
+ ok(bufis(headers[0].value, headers[0].value_len, "example.com"));
259
+ ok(bufis(headers[1].name, headers[1].name_len, "Cookie"));
260
+ ok(bufis(headers[1].value, headers[1].value_len, ""));
261
+
262
+ PARSE("Host: example.com\r\nCookie: \r\n\r", 0, -2, "partial");
263
+
264
+ PARSE("Host: e\7fample.com\r\nCookie: \r\n\r", 0, -1, "error");
265
+
245
266
  #undef PARSE
246
267
  }
247
268
 
269
+ static void test_chunked_at_once(int line, int consume_trailer, const char *encoded, const char *decoded, ssize_t expected)
270
+ {
271
+ struct phr_chunked_decoder dec = {0};
272
+ char *buf;
273
+ size_t bufsz;
274
+ ssize_t ret;
275
+
276
+ dec.consume_trailer = consume_trailer;
277
+
278
+ note("testing at-once, source at line %d", line);
279
+
280
+ buf = strdup(encoded);
281
+ bufsz = strlen(buf);
282
+
283
+ ret = phr_decode_chunked(&dec, buf, &bufsz);
284
+
285
+ ok(ret == expected);
286
+ ok(bufsz == strlen(decoded));
287
+ ok(bufis(buf, bufsz, decoded));
288
+ if (expected >= 0) {
289
+ if (ret == expected)
290
+ ok(bufis(buf + bufsz, ret, encoded + strlen(encoded) - ret));
291
+ else
292
+ ok(0);
293
+ }
294
+
295
+ free(buf);
296
+ }
297
+
298
+ static void test_chunked_per_byte(int line, int consume_trailer, const char *encoded, const char *decoded, ssize_t expected)
299
+ {
300
+ struct phr_chunked_decoder dec = {0};
301
+ char *buf = malloc(strlen(encoded) + 1);
302
+ size_t bytes_to_consume = strlen(encoded) - (expected >= 0 ? expected : 0), bytes_ready = 0, bufsz, i;
303
+ ssize_t ret;
304
+
305
+ dec.consume_trailer = consume_trailer;
306
+
307
+ note("testing per-byte, source at line %d", line);
308
+
309
+ for (i = 0; i < bytes_to_consume - 1; ++i) {
310
+ buf[bytes_ready] = encoded[i];
311
+ bufsz = 1;
312
+ ret = phr_decode_chunked(&dec, buf + bytes_ready, &bufsz);
313
+ if (ret != -2) {
314
+ ok(0);
315
+ return;
316
+ }
317
+ bytes_ready += bufsz;
318
+ }
319
+ strcpy(buf + bytes_ready, encoded + bytes_to_consume - 1);
320
+ bufsz = strlen(buf + bytes_ready);
321
+ ret = phr_decode_chunked(&dec, buf + bytes_ready, &bufsz);
322
+ ok(ret == expected);
323
+ bytes_ready += bufsz;
324
+ ok(bytes_ready == strlen(decoded));
325
+ ok(bufis(buf, bytes_ready, decoded));
326
+ if (expected >= 0) {
327
+ if (ret == expected)
328
+ ok(bufis(buf + bytes_ready, expected, encoded + bytes_to_consume));
329
+ else
330
+ ok(0);
331
+ }
332
+
333
+ free(buf);
334
+ }
335
+
336
+ static void test_chunked_failure(int line, const char *encoded, ssize_t expected)
337
+ {
338
+ struct phr_chunked_decoder dec = {0};
339
+ char *buf = strdup(encoded);
340
+ size_t bufsz, i;
341
+ ssize_t ret;
342
+
343
+ note("testing failure at-once, source at line %d", line);
344
+ bufsz = strlen(buf);
345
+ ret = phr_decode_chunked(&dec, buf, &bufsz);
346
+ ok(ret == expected);
347
+
348
+ note("testing failure per-byte, source at line %d", line);
349
+ memset(&dec, 0, sizeof(dec));
350
+ for (i = 0; encoded[i] != '\0'; ++i) {
351
+ buf[0] = encoded[i];
352
+ bufsz = 1;
353
+ ret = phr_decode_chunked(&dec, buf, &bufsz);
354
+ if (ret == -1) {
355
+ ok(ret == expected);
356
+ return;
357
+ } else if (ret == -2) {
358
+ /* continue */
359
+ } else {
360
+ ok(0);
361
+ return;
362
+ }
363
+ }
364
+ ok(ret == expected);
365
+
366
+ free(buf);
367
+ }
368
+
369
+ static void (*chunked_test_runners[])(int, int, const char *, const char *, ssize_t) = {test_chunked_at_once, test_chunked_per_byte,
370
+ NULL};
371
+
372
+ static void test_chunked(void)
373
+ {
374
+ size_t i;
375
+
376
+ for (i = 0; chunked_test_runners[i] != NULL; ++i) {
377
+ chunked_test_runners[i](__LINE__, 0, "b\r\nhello world\r\n0\r\n", "hello world", 0);
378
+ chunked_test_runners[i](__LINE__, 0, "6\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", 0);
379
+ chunked_test_runners[i](__LINE__, 0, "6;comment=hi\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", 0);
380
+ chunked_test_runners[i](__LINE__, 0, "6\r\nhello \r\n5\r\nworld\r\n0\r\na: b\r\nc: d\r\n\r\n", "hello world",
381
+ sizeof("a: b\r\nc: d\r\n\r\n") - 1);
382
+ chunked_test_runners[i](__LINE__, 0, "b\r\nhello world\r\n0\r\n", "hello world", 0);
383
+ }
384
+
385
+ note("failures");
386
+ test_chunked_failure(__LINE__, "z\r\nabcdefg", -1);
387
+ if (sizeof(size_t) == 8) {
388
+ test_chunked_failure(__LINE__, "6\r\nhello \r\nffffffffffffffff\r\nabcdefg", -2);
389
+ test_chunked_failure(__LINE__, "6\r\nhello \r\nfffffffffffffffff\r\nabcdefg", -1);
390
+ }
391
+ }
392
+
393
+ static void test_chunked_consume_trailer(void)
394
+ {
395
+ size_t i;
396
+
397
+ for (i = 0; chunked_test_runners[i] != NULL; ++i) {
398
+ chunked_test_runners[i](__LINE__, 1, "b\r\nhello world\r\n0\r\n", "hello world", -2);
399
+ chunked_test_runners[i](__LINE__, 1, "6\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", -2);
400
+ chunked_test_runners[i](__LINE__, 1, "6;comment=hi\r\nhello \r\n5\r\nworld\r\n0\r\n", "hello world", -2);
401
+ chunked_test_runners[i](__LINE__, 1, "b\r\nhello world\r\n0\r\n\r\n", "hello world", 0);
402
+ chunked_test_runners[i](__LINE__, 1, "b\nhello world\n0\n\n", "hello world", 0);
403
+ chunked_test_runners[i](__LINE__, 1, "6\r\nhello \r\n5\r\nworld\r\n0\r\na: b\r\nc: d\r\n\r\n", "hello world", 0);
404
+ }
405
+ }
406
+
248
407
  int main(int argc, char **argv)
249
408
  {
250
- subtest("request", test_request);
251
- subtest("response", test_response);
252
- return done_testing();
409
+ subtest("request", test_request);
410
+ subtest("response", test_response);
411
+ subtest("headers", test_headers);
412
+ subtest("chunked", test_chunked);
413
+ subtest("chunked-consume-trailer", test_chunked_consume_trailer);
414
+ return done_testing();
253
415
  }