| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- /*
- Tests for high-level HTTP interface (ne_basic.h)
- Copyright (C) 2002-2008, 2012, Joe Orton <[email protected]>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include "config.h"
- #include <sys/types.h>
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <fcntl.h>
- #include "ne_basic.h"
- #include "tests.h"
- #include "child.h"
- #include "utils.h"
- static int content_type(void)
- {
- int n;
- static const struct {
- const char *value, *type, *subtype, *charset;
- } ctypes[] = {
- { "foo/bar", "foo", "bar", NULL },
- { "foo/bar ", "foo", "bar", NULL },
- { "application/xml", "application", "xml", NULL },
- /* text/ subtypes default to charset ISO-8859-1, per 2616. */
- { "text/lemon", "text", "lemon", "ISO-8859-1" },
- /* text/xml defaults to charset us-ascii, per 3280 */
- { "text/xml", "text", "xml", "us-ascii" },
- #undef TXU
- #define TXU "text", "xml", "utf-8"
- /* 2616 doesn't *say* that charset can be quoted, but bets are
- * that some servers do it anyway. */
- { "text/xml; charset=utf-8", TXU },
- { "text/xml; charset=utf-8; foo=bar", TXU },
- { "text/xml;charset=utf-8", TXU },
- { "text/xml ;charset=utf-8", TXU },
- { "text/xml;charset=utf-8;foo=bar", TXU },
- { "text/xml; foo=bar; charset=utf-8", TXU },
- { "text/xml; foo=bar; charset=utf-8; bar=foo", TXU },
- { "text/xml; charset=\"utf-8\"", TXU },
- { "text/xml; charset='utf-8'", TXU },
- { "text/xml; foo=bar; charset=\"utf-8\"; bar=foo", TXU },
- #undef TXU
- /* badly quoted charset should come out as NULL */
- { "foo/lemon; charset=\"utf-8", "foo", "lemon", NULL },
- { NULL }
- };
- for (n = 0; ctypes[n].value != NULL; n++) {
- ne_content_type ct;
- ne_session *sess;
- ne_request *req;
- char resp[200];
- int rv;
- ct.type = ct.subtype = ct.charset = ct.value = "unset";
- ne_snprintf(resp, sizeof resp,
- "HTTP/1.0 200 OK\r\n" "Content-Length: 0\r\n"
- "Content-Type: %s\r\n" "\r\n", ctypes[n].value);
-
- CALL(make_session(&sess, single_serve_string, resp));
- req = ne_request_create(sess, "GET", "/anyfoo");
- ONREQ(ne_request_dispatch(req));
- rv = ne_get_content_type(req, &ct);
-
- ONV(rv == 0 && !ctypes[n].type,
- ("expected c-t parse failure for %s", ctypes[n].value));
- ONV(rv != 0 && ctypes[n].type,
- ("c-t parse failure %d for %s", rv, ctypes[n].value));
- ne_request_destroy(req);
- ne_session_destroy(sess);
- CALL(await_server());
- if (rv) continue;
- ONV(strcmp(ct.type, ctypes[n].type),
- ("for `%s': type was `%s'", ctypes[n].value, ct.type));
- ONV(strcmp(ct.subtype, ctypes[n].subtype),
- ("for `%s': subtype was `%s'", ctypes[n].value, ct.subtype));
- ONV(ctypes[n].charset && ct.charset == NULL,
- ("for `%s': charset unset", ctypes[n].value));
-
- ONV(ctypes[n].charset == NULL && ct.charset != NULL,
- ("for `%s': unexpected charset `%s'", ctypes[n].value,
- ct.charset));
- ONV(ctypes[n].charset && ct.charset &&
- strcmp(ctypes[n].charset, ct.charset),
- ("for `%s': charset was `%s'", ctypes[n].value, ct.charset));
- ne_free(ct.value);
- }
- return OK;
- }
- /* Do ranged GET for range 'start' to 'end'; with 'resp' as response.
- * If 'fail' is non-NULL, expect ne_get_range to fail, and fail the
- * test with given message if it doesn't. */
- static int do_range(off_t start, off_t end, const char *fail,
- char *resp)
- {
- ne_session *sess;
- ne_content_range range = {0};
- int fd, ret;
- CALL(make_session(&sess, single_serve_string, resp));
-
- range.start = start;
- range.end = end;
-
- fd = open("/dev/null", O_WRONLY);
-
- ret = ne_get_range(sess, "/foo", &range, fd);
- close(fd);
- ne_close_connection(sess);
- CALL(await_server());
-
- if (fail) {
- #if 0
- t_warning("error was %s", ne_get_error(sess));
- #endif
- ONV(ret == NE_OK, ("%s", fail));
- } else {
- ONREQ(ret);
- }
-
- ne_session_destroy(sess);
- return OK;
- }
- static int get_range(void)
- {
- return do_range(1, 10, NULL,
- "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
- "Content-Range: bytes 1-10/10\r\n"
- "Content-Length: 10\r\n\r\nabcdefghij");
- }
- static int get_eof_range(void)
- {
- return do_range(1, -1, NULL,
- "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
- "Content-Range: bytes 1-10/10\r\n"
- "Content-Length: 10\r\n\r\nabcdefghij");
- }
- static int fail_range_length(void)
- {
- return do_range(1, 10, "range response length mismatch should fail",
- "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
- "Content-Range: bytes 1-2/2\r\n"
- "Content-Length: 2\r\n\r\nab");
- }
- static int fail_range_units(void)
- {
- return do_range(1, 2, "range response units check should fail",
- "HTTP/1.1 206 Widgets\r\n" "Connection: close\r\n"
- "Content-Range: fish 1-2/2\r\n"
- "Content-Length: 2\r\n\r\nab");
- }
- static int fail_range_notrange(void)
- {
- return do_range(1, 2, "non-ranged response should fail",
- "HTTP/1.1 200 Widgets\r\n" "Connection: close\r\n"
- "Content-Range: bytes 1-2/2\r\n"
- "Content-Length: 2\r\n\r\nab");
- }
- static int fail_range_unsatify(void)
- {
- return do_range(1, 2, "unsatisfiable range should fail",
- "HTTP/1.1 416 No Go\r\n" "Connection: close\r\n"
- "Content-Length: 2\r\n\r\nab");
- }
- static int dav_capabilities(void)
- {
- static const struct {
- const char *hdrs;
- unsigned int class1, class2, exec;
- } caps[] = {
- { "DAV: 1,2\r\n", 1, 1, 0 },
- { "DAV: 1 2\r\n", 0, 0, 0 },
- /* these aren't strictly legal DAV: headers: */
- { "DAV: 2,1\r\n", 1, 1, 0 },
- { "DAV: 1, 2 \r\n", 1, 1, 0 },
- { "DAV: 1\r\nDAV:2\r\n", 1, 1, 0 },
- { NULL, 0, 0, 0 }
- };
- char resp[BUFSIZ];
- int n;
- for (n = 0; caps[n].hdrs != NULL; n++) {
- ne_server_capabilities c = {0};
- ne_session *sess;
- ne_snprintf(resp, BUFSIZ, "HTTP/1.0 200 OK\r\n"
- "Connection: close\r\n"
- "%s" "\r\n", caps[n].hdrs);
- CALL(make_session(&sess, single_serve_string, resp));
- ONREQ(ne_options(sess, "/foo", &c));
- ONV(c.dav_class1 != caps[n].class1,
- ("class1 was %d not %d", c.dav_class1, caps[n].class1));
- ONV(c.dav_class2 != caps[n].class2,
- ("class2 was %d not %d", c.dav_class2, caps[n].class2));
- ONV(c.dav_executable != caps[n].exec,
- ("class2 was %d not %d", c.dav_executable, caps[n].exec));
- CALL(destroy_and_wait(sess));
- }
- return OK;
- }
- static int get(void)
- {
- ne_session *sess;
- int fd;
-
- CALL(make_session(&sess, single_serve_string,
- "HTTP/1.0 200 OK\r\n"
- "Content-Length: 5\r\n"
- "\r\n"
- "abcde"));
-
- fd = open("/dev/null", O_WRONLY);
- ONREQ(ne_get(sess, "/getit", fd));
- close(fd);
- return destroy_and_wait(sess);
- }
- #define CLASS_12 (NE_CAP_DAV_CLASS1 | NE_CAP_DAV_CLASS2)
- static int options2(void)
- {
- static const struct {
- const char *hdrs;
- unsigned int caps;
- } ts[] = {
- { "1,2\r\n", CLASS_12 },
- { "1 2\r\n", 0 },
- /* these aren't strictly legal headers: */
- { "2,1\r\n", CLASS_12 },
- { " 1, 2 \r\n", CLASS_12 },
- { "1\r\nDAV:2\r\n", CLASS_12 },
- /* extended types */
- { "1, 2, extended-mkcol", CLASS_12 | NE_CAP_EXT_MKCOL },
- { NULL, 0 }
- };
- char resp[BUFSIZ];
- int n;
- for (n = 0; ts[n].hdrs != NULL; n++) {
- ne_session *sess;
- unsigned int caps;
- ne_snprintf(resp, BUFSIZ, "HTTP/1.0 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 0\r\n"
- "DAV: %s" "\r\n\r\n", ts[n].hdrs);
- CALL(make_session(&sess, single_serve_string, resp));
- ONREQ(ne_options2(sess, "/foo", &caps));
- ONV(caps != ts[n].caps,
- ("capabilities for 'DAV: %s' were 0x%x, expected 0x%x",
- ts[n].hdrs, caps, ts[n].caps));
- CALL(destroy_and_wait(sess));
- }
- return OK;
- }
- static int put(void)
- {
- ne_session *sess;
-
- CALL(make_session(&sess, single_serve_string, "HTTP/1.1 204 OK\r\n"
- "Content-Length: 200\r\n"
- "\r\n"));
-
- ONREQ(ne_putbuf(sess, "/foo", "foobar", 6));
- return destroy_and_wait(sess);
- }
- ne_test tests[] = {
- T(lookup_localhost),
- T(content_type),
- T(get_range),
- T(get_eof_range),
- T(fail_range_length),
- T(fail_range_units),
- T(fail_range_notrange),
- T(fail_range_unsatify),
- T(dav_capabilities),
- T(get),
- T(options2),
- T(put),
- T(NULL)
- };
|