1 /*
2 Tests for high-level HTTP interface (ne_basic.h)
3 Copyright (C) 2002-2008, Joe Orton <joe@manyfish.co.uk>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "config.h"
22
23 #include <sys/types.h>
24
25 #ifdef HAVE_STDLIB_H
26 #include <stdlib.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31
32 #include <fcntl.h>
33
34 #include "ne_basic.h"
35
36 #include "tests.h"
37 #include "child.h"
38 #include "utils.h"
39
content_type(void)40 static int content_type(void)
41 {
42 int n;
43 static const struct {
44 const char *value, *type, *subtype, *charset;
45 } ctypes[] = {
46 { "foo/bar", "foo", "bar", NULL },
47 { "foo/bar ", "foo", "bar", NULL },
48 { "application/xml", "application", "xml", NULL },
49 /* text/ subtypes default to charset ISO-8859-1, per 2616. */
50 { "text/lemon", "text", "lemon", "ISO-8859-1" },
51 /* text/xml defaults to charset us-ascii, per 3280 */
52 { "text/xml", "text", "xml", "us-ascii" },
53 #undef TXU
54 #define TXU "text", "xml", "utf-8"
55 /* 2616 doesn't *say* that charset can be quoted, but bets are
56 * that some servers do it anyway. */
57 { "text/xml; charset=utf-8", TXU },
58 { "text/xml; charset=utf-8; foo=bar", TXU },
59 { "text/xml;charset=utf-8", TXU },
60 { "text/xml ;charset=utf-8", TXU },
61 { "text/xml;charset=utf-8;foo=bar", TXU },
62 { "text/xml; foo=bar; charset=utf-8", TXU },
63 { "text/xml; foo=bar; charset=utf-8; bar=foo", TXU },
64 { "text/xml; charset=\"utf-8\"", TXU },
65 { "text/xml; charset='utf-8'", TXU },
66 { "text/xml; foo=bar; charset=\"utf-8\"; bar=foo", TXU },
67 #undef TXU
68 /* badly quoted charset should come out as NULL */
69 { "foo/lemon; charset=\"utf-8", "foo", "lemon", NULL },
70 { NULL }
71 };
72
73 for (n = 0; ctypes[n].value != NULL; n++) {
74 ne_content_type ct;
75 ne_session *sess;
76 ne_request *req;
77 char resp[200];
78 int rv;
79
80 ct.type = ct.subtype = ct.charset = ct.value = "unset";
81
82 ne_snprintf(resp, sizeof resp,
83 "HTTP/1.0 200 OK\r\n" "Content-Length: 0\r\n"
84 "Content-Type: %s\r\n" "\r\n", ctypes[n].value);
85
86 CALL(make_session(&sess, single_serve_string, resp));
87
88 req = ne_request_create(sess, "GET", "/anyfoo");
89 ONREQ(ne_request_dispatch(req));
90 rv = ne_get_content_type(req, &ct);
91
92 ONV(rv == 0 && !ctypes[n].type,
93 ("expected c-t parse failure for %s", ctypes[n].value));
94
95 ONV(rv != 0 && ctypes[n].type,
96 ("c-t parse failure %d for %s", rv, ctypes[n].value));
97
98 ne_request_destroy(req);
99 ne_session_destroy(sess);
100 CALL(await_server());
101
102 if (rv) continue;
103
104 ONV(strcmp(ct.type, ctypes[n].type),
105 ("for `%s': type was `%s'", ctypes[n].value, ct.type));
106
107 ONV(strcmp(ct.subtype, ctypes[n].subtype),
108 ("for `%s': subtype was `%s'", ctypes[n].value, ct.subtype));
109
110 ONV(ctypes[n].charset && ct.charset == NULL,
111 ("for `%s': charset unset", ctypes[n].value));
112
113 ONV(ctypes[n].charset == NULL && ct.charset != NULL,
114 ("for `%s': unexpected charset `%s'", ctypes[n].value,
115 ct.charset));
116
117 ONV(ctypes[n].charset && ct.charset &&
118 strcmp(ctypes[n].charset, ct.charset),
119 ("for `%s': charset was `%s'", ctypes[n].value, ct.charset));
120
121 ne_free(ct.value);
122 }
123
124 return OK;
125 }
126
127 /* Do ranged GET for range 'start' to 'end'; with 'resp' as response.
128 * If 'fail' is non-NULL, expect ne_get_range to fail, and fail the
129 * test with given message if it doesn't. */
do_range(off_t start,off_t end,const char * fail,char * resp)130 static int do_range(off_t start, off_t end, const char *fail,
131 char *resp)
132 {
133 ne_session *sess;
134 ne_content_range range = {0};
135 int fd, ret;
136
137 CALL(make_session(&sess, single_serve_string, resp));
138
139 range.start = start;
140 range.end = end;
141
142 fd = open("/dev/null", O_WRONLY);
143
144 ret = ne_get_range(sess, "/foo", &range, fd);
145
146 close(fd);
147 CALL(await_server());
148
149 if (fail) {
150 #if 0
151 t_warning("error was %s", ne_get_error(sess));
152 #endif
153 ONV(ret == NE_OK, ("%s", fail));
154 } else {
155 ONREQ(ret);
156 }
157
158 ne_session_destroy(sess);
159 return OK;
160 }
161
get_range(void)162 static int get_range(void)
163 {
164 return do_range(1, 10, NULL,
165 "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
166 "Content-Range: bytes 1-10/10\r\n"
167 "Content-Length: 10\r\n\r\nabcdefghij");
168 }
169
get_eof_range(void)170 static int get_eof_range(void)
171 {
172 return do_range(1, -1, NULL,
173 "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
174 "Content-Range: bytes 1-10/10\r\n"
175 "Content-Length: 10\r\n\r\nabcdefghij");
176 }
177
fail_range_length(void)178 static int fail_range_length(void)
179 {
180 return do_range(1, 10, "range response length mismatch should fail",
181 "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
182 "Content-Range: bytes 1-2/2\r\n"
183 "Content-Length: 2\r\n\r\nab");
184 }
185
fail_range_units(void)186 static int fail_range_units(void)
187 {
188 return do_range(1, 2, "range response units check should fail",
189 "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
190 "Content-Range: fish 1-2/2\r\n"
191 "Content-Length: 2\r\n\r\nab");
192 }
193
fail_range_notrange(void)194 static int fail_range_notrange(void)
195 {
196 return do_range(1, 2, "non-ranged response should fail",
197 "HTTP/1.1 200 Widgets\r\n" "Connection: close\r\n"
198 "Content-Range: bytes 1-2/2\r\n"
199 "Content-Length: 2\r\n\r\nab");
200 }
201
fail_range_unsatify(void)202 static int fail_range_unsatify(void)
203 {
204 return do_range(1, 2, "unsatisfiable range should fail",
205 "HTTP/1.1 416 No Go\r\n" "Connection: close\r\n"
206 "Content-Length: 2\r\n\r\nab");
207 }
208
dav_capabilities(void)209 static int dav_capabilities(void)
210 {
211 static const struct {
212 const char *hdrs;
213 unsigned int class1, class2, exec;
214 } caps[] = {
215 { "DAV: 1,2\r\n", 1, 1, 0 },
216 { "DAV: 1 2\r\n", 0, 0, 0 },
217 /* these aren't strictly legal DAV: headers: */
218 { "DAV: 2,1\r\n", 1, 1, 0 },
219 { "DAV: 1, 2 \r\n", 1, 1, 0 },
220 { "DAV: 1\r\nDAV:2\r\n", 1, 1, 0 },
221 { NULL, 0, 0, 0 }
222 };
223 char resp[BUFSIZ];
224 int n;
225
226 for (n = 0; caps[n].hdrs != NULL; n++) {
227 ne_server_capabilities c = {0};
228 ne_session *sess;
229
230 ne_snprintf(resp, BUFSIZ, "HTTP/1.0 200 OK\r\n"
231 "Connection: close\r\n"
232 "%s" "\r\n", caps[n].hdrs);
233
234 CALL(make_session(&sess, single_serve_string, resp));
235
236 ONREQ(ne_options(sess, "/foo", &c));
237
238 ONV(c.dav_class1 != caps[n].class1,
239 ("class1 was %d not %d", c.dav_class1, caps[n].class1));
240 ONV(c.dav_class2 != caps[n].class2,
241 ("class2 was %d not %d", c.dav_class2, caps[n].class2));
242 ONV(c.dav_executable != caps[n].exec,
243 ("class2 was %d not %d", c.dav_executable, caps[n].exec));
244
245 CALL(await_server());
246
247 ne_session_destroy(sess);
248 }
249
250 return OK;
251 }
252
get(void)253 static int get(void)
254 {
255 ne_session *sess;
256 int fd;
257
258 CALL(make_session(&sess, single_serve_string,
259 "HTTP/1.0 200 OK\r\n"
260 "Content-Length: 5\r\n"
261 "\r\n"
262 "abcde"));
263
264 fd = open("/dev/null", O_WRONLY);
265 ONREQ(ne_get(sess, "/getit", fd));
266 close(fd);
267
268 ne_session_destroy(sess);
269 CALL(await_server());
270
271 return OK;
272 }
273
274 ne_test tests[] = {
275 T(lookup_localhost),
276 T(content_type),
277 T(get_range),
278 T(get_eof_range),
279 T(fail_range_length),
280 T(fail_range_units),
281 T(fail_range_notrange),
282 T(fail_range_unsatify),
283 T(dav_capabilities),
284 T(get),
285 T(NULL)
286 };
287
288