basic.c 9.1 KB

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