test_proto_http.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* Copyright (c) 2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_proto_http.c
  5. * \brief Tests for our HTTP protocol parser code
  6. */
  7. #include "or.h"
  8. #include "test.h"
  9. #include "buffers.h"
  10. #include "proto_http.h"
  11. #include "log_test_helpers.h"
  12. #define S(str) str, sizeof(str)-1
  13. static void
  14. test_proto_http_peek(void *arg)
  15. {
  16. (void) arg;
  17. const struct {
  18. int is_http;
  19. const char *message;
  20. size_t len;
  21. } cases[] = {
  22. { 1, S("GET /index HTTP/1.0\r\n") },
  23. { 1, S("GET /index HTTP/1.1\r\n") },
  24. { 1, S("GET ") },
  25. { 0, S("GIT ") },
  26. { 0, S("GET") },
  27. { 0, S("get ") },
  28. { 0, S("GETAWAY") },
  29. };
  30. unsigned i;
  31. buf_t *buf = buf_new();
  32. for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
  33. TT_BLATHER(("Trying case %u", i));
  34. buf_add(buf, cases[i].message, cases[i].len);
  35. tt_int_op(cases[i].is_http, OP_EQ, peek_buf_has_http_command(buf));
  36. buf_clear(buf);
  37. }
  38. done:
  39. buf_free(buf);
  40. }
  41. static void
  42. test_proto_http_valid(void *arg)
  43. {
  44. (void) arg;
  45. const struct {
  46. const char *message;
  47. size_t len;
  48. const char *headers;
  49. const char *body;
  50. size_t bodylen;
  51. int should_detect_truncated;
  52. int bytes_left_over;
  53. } cases[] = {
  54. { S("GET /index.html HTTP/1.0\r\n\r\n"),
  55. "GET /index.html HTTP/1.0\r\n\r\n",
  56. S(""),
  57. 1, 0,
  58. },
  59. { S("PUT /tor/foo HTTP/1.1\r\n"
  60. "Content-Length: 51\r\n\r\n"
  61. "this is a test of the http parsing system . test te"),
  62. "PUT /tor/foo HTTP/1.1\r\n" "Content-Length: 51\r\n\r\n",
  63. S("this is a test of the http parsing system . test te"),
  64. 1, 0,
  65. },
  66. { S("PUT /tor/foo HTTP/1.1\r\n"
  67. "Content-Length: 5\r\n\r\n"
  68. "there are more than 5 characters in this body."),
  69. "PUT /tor/foo HTTP/1.1\r\n" "Content-Length: 5\r\n\r\n",
  70. S("there"),
  71. 0, 41,
  72. },
  73. { S("PUT /tor/bar HTTP/1.1\r\n\r\n"
  74. "this is another \x00test"),
  75. "PUT /tor/bar HTTP/1.1\r\n\r\n",
  76. S("this is another \x00test"),
  77. 0, 0,
  78. }
  79. };
  80. unsigned i;
  81. buf_t *buf = buf_new();
  82. char *h = NULL, *b = NULL;
  83. for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
  84. TT_BLATHER(("Trying case %u", i));
  85. size_t bl = 0;
  86. // truncate by 2 chars
  87. buf_add(buf, cases[i].message, cases[i].len - 2);
  88. if (cases[i].should_detect_truncated) {
  89. tt_int_op(0, OP_EQ, fetch_from_buf_http(buf, &h, 1024*16,
  90. &b, &bl, 1024*16, 0));
  91. tt_ptr_op(h, OP_EQ, NULL);
  92. tt_ptr_op(b, OP_EQ, NULL);
  93. tt_u64_op(bl, OP_EQ, 0);
  94. tt_int_op(buf_datalen(buf), OP_EQ, cases[i].len - 2);
  95. }
  96. // add the rest.
  97. buf_add(buf, cases[i].message+cases[i].len-2, 2);
  98. tt_int_op(1, OP_EQ, fetch_from_buf_http(buf, &h, 1024*16,
  99. &b, &bl, 1024*16, 0));
  100. tt_str_op(h, OP_EQ, cases[i].headers);
  101. tt_u64_op(bl, OP_EQ, cases[i].bodylen);
  102. tt_mem_op(b, OP_EQ, cases[i].body, bl);
  103. tt_int_op(buf_datalen(buf), OP_EQ, cases[i].bytes_left_over);
  104. buf_clear(buf);
  105. tor_free(h);
  106. tor_free(b);
  107. }
  108. done:
  109. tor_free(h);
  110. tor_free(b);
  111. buf_free(buf);
  112. }
  113. static void
  114. test_proto_http_invalid(void *arg)
  115. {
  116. (void) arg;
  117. const struct {
  118. const char *message;
  119. size_t len;
  120. const char *expect;
  121. } cases[] = {
  122. /* Overlong headers, headers not finished. */
  123. { S("GET /index.xhml HTTP/1.0\r\n"
  124. "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
  125. "X-My-headers-are-too-long: normal under other circumstances, but\r\n"
  126. "X-My-headers-are-too-long: the 128-byte limit makes them bad\r\n"),
  127. "headers too long." },
  128. /* Overlong finished headers. */
  129. { S("GET /index.xhml HTTP/1.0\r\n"
  130. "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
  131. "X-My-headers-are-too-long: normal under other circumstances, but\r\n"
  132. "X-My-headers-are-too-long: the 128-byte limit makes them bad\r\n"
  133. "\r\n"),
  134. "headers too long." },
  135. /* Exactly too long finished headers. */
  136. { S("GET /index.xhml HTTP/1.0\r\n"
  137. "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
  138. "X-My-headers-are-too-long: normal un\r\n\r\n"),
  139. "headerlen 129 larger than 127. Failing." },
  140. /* Body too long, with content-length */
  141. { S("GET /index.html HTTP/1.0\r\n"
  142. "Content-Length: 129\r\n\r\n"
  143. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  144. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  145. "xxxxxxxxxxxxxxxxxxx"),
  146. "bodylen 129 larger than 127" },
  147. /* Body too long, with content-length lying */
  148. { S("GET /index.html HTTP/1.0\r\n"
  149. "Content-Length: 99999\r\n\r\n"
  150. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  151. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  152. "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
  153. "bodylen 138 larger than 127" },
  154. /* Body too long, no content-length. */
  155. { S("GET /index.html HTTP/1.0\r\n\r\n"
  156. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  157. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  158. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxz"),
  159. "bodylen 139 larger than 127" },
  160. /* Content-Length is junk. */
  161. { S("GET /index.html HTTP/1.0\r\n"
  162. "Content-Length: Cheese\r\n\r\n"
  163. "foo"),
  164. "Content-Length is bogus; maybe someone is trying to crash us." },
  165. };
  166. unsigned i;
  167. buf_t *buf = buf_new();
  168. char *h = NULL, *b = NULL;
  169. setup_capture_of_logs(LOG_DEBUG);
  170. for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
  171. TT_BLATHER(("Trying case %u", i));
  172. size_t bl = 0;
  173. buf_add(buf, cases[i].message, cases[i].len);
  174. /* Use low body limits here so we can force over-sized object warnings */
  175. tt_int_op(-1, OP_EQ, fetch_from_buf_http(buf, &h, 128,
  176. &b, &bl, 128, 0));
  177. tt_ptr_op(h, OP_EQ, NULL);
  178. tt_ptr_op(b, OP_EQ, NULL);
  179. tt_u64_op(bl, OP_EQ, 0);
  180. expect_log_msg_containing(cases[i].expect);
  181. buf_clear(buf);
  182. tor_free(h);
  183. tor_free(b);
  184. mock_clean_saved_logs();
  185. }
  186. done:
  187. tor_free(h);
  188. tor_free(b);
  189. buf_free(buf);
  190. teardown_capture_of_logs();
  191. }
  192. struct testcase_t proto_http_tests[] = {
  193. { "peek", test_proto_http_peek, 0, NULL, NULL },
  194. { "valid", test_proto_http_valid, 0, NULL, NULL },
  195. { "invalid", test_proto_http_invalid, 0, NULL, NULL },
  196. END_OF_TESTCASES
  197. };