A clone of btpd with my configuration changes.
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

427 рядки
9.4 KiB

  1. /*
  2. * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. The name of the author may not be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifdef WIN32
  28. #include <winsock2.h>
  29. #include <windows.h>
  30. #endif
  31. #ifdef HAVE_CONFIG_H
  32. #include "config.h"
  33. #endif
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #ifdef HAVE_SYS_TIME_H
  37. #include <sys/time.h>
  38. #endif
  39. #include <sys/queue.h>
  40. #ifndef WIN32
  41. #include <sys/socket.h>
  42. #include <sys/signal.h>
  43. #include <unistd.h>
  44. #endif
  45. #include <netdb.h>
  46. #include <fcntl.h>
  47. #include <stdlib.h>
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <errno.h>
  51. #include "event.h"
  52. #include "evhttp.h"
  53. #include "log.h"
  54. #include "http-internal.h"
  55. extern int pair[];
  56. extern int test_ok;
  57. static struct evhttp *http;
  58. void http_basic_cb(struct evhttp_request *req, void *arg);
  59. void http_post_cb(struct evhttp_request *req, void *arg);
  60. struct evhttp *
  61. http_setup(short *pport)
  62. {
  63. int i;
  64. struct evhttp *myhttp;
  65. short port = -1;
  66. /* Try a few different ports */
  67. for (i = 0; i < 50; ++i) {
  68. myhttp = evhttp_start("127.0.0.1", 8080 + i);
  69. if (myhttp != NULL) {
  70. port = 8080 + i;
  71. break;
  72. }
  73. }
  74. if (port == -1)
  75. event_errx(1, "Could not start web server");
  76. /* Register a callback for certain types of requests */
  77. evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
  78. evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
  79. *pport = port;
  80. return (myhttp);
  81. }
  82. int
  83. http_connect(const char *address, u_short port)
  84. {
  85. /* Stupid code for connecting */
  86. struct addrinfo ai, *aitop;
  87. char strport[NI_MAXSERV];
  88. int fd;
  89. memset(&ai, 0, sizeof (ai));
  90. ai.ai_family = AF_INET;
  91. ai.ai_socktype = SOCK_STREAM;
  92. snprintf(strport, sizeof (strport), "%d", port);
  93. if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
  94. event_warn("getaddrinfo");
  95. return (-1);
  96. }
  97. fd = socket(AF_INET, SOCK_STREAM, 0);
  98. if (fd == -1)
  99. event_err(1, "socket failed");
  100. if (connect(fd, aitop->ai_addr, aitop->ai_addrlen) == -1)
  101. event_err(1, "connect failed");
  102. freeaddrinfo(aitop);
  103. return (fd);
  104. }
  105. void
  106. http_readcb(struct bufferevent *bev, void *arg)
  107. {
  108. const char *what = "This is funny";
  109. event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
  110. if (evbuffer_find(bev->input, what, strlen(what)) != NULL) {
  111. struct evhttp_request *req = evhttp_request_new(NULL, NULL);
  112. req->kind = EVHTTP_RESPONSE;
  113. int done = evhttp_parse_lines(req, bev->input);
  114. if (done == 1 &&
  115. evhttp_find_header(req->input_headers,
  116. "Content-Type") != NULL)
  117. test_ok++;
  118. evhttp_request_free(req);
  119. bufferevent_disable(bev, EV_READ);
  120. event_loopexit(NULL);
  121. }
  122. }
  123. void
  124. http_writecb(struct bufferevent *bev, void *arg)
  125. {
  126. if (EVBUFFER_LENGTH(bev->output) == 0) {
  127. /* enable reading of the reply */
  128. bufferevent_enable(bev, EV_READ);
  129. test_ok++;
  130. }
  131. }
  132. void
  133. http_errorcb(struct bufferevent *bev, short what, void *arg)
  134. {
  135. test_ok = -2;
  136. event_loopexit(NULL);
  137. }
  138. void
  139. http_basic_cb(struct evhttp_request *req, void *arg)
  140. {
  141. event_debug((stderr, "%s: called\n", __func__));
  142. struct evbuffer *evb = evbuffer_new();
  143. evbuffer_add_printf(evb, "This is funny");
  144. evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
  145. evbuffer_free(evb);
  146. }
  147. void
  148. http_basic_test(void)
  149. {
  150. struct bufferevent *bev;
  151. int fd;
  152. char *http_request;
  153. short port = -1;
  154. test_ok = 0;
  155. fprintf(stdout, "Testing Basic HTTP Server: ");
  156. http = http_setup(&port);
  157. fd = http_connect("127.0.0.1", port);
  158. /* Stupid thing to send a request */
  159. bev = bufferevent_new(fd, http_readcb, http_writecb,
  160. http_errorcb, NULL);
  161. http_request =
  162. "GET /test HTTP/1.1\r\n"
  163. "Host: somehost \r\n"
  164. "\r\n";
  165. bufferevent_write(bev, http_request, strlen(http_request));
  166. event_dispatch();
  167. bufferevent_free(bev);
  168. close(fd);
  169. evhttp_free(http);
  170. if (test_ok != 2) {
  171. fprintf(stdout, "FAILED\n");
  172. exit(1);
  173. }
  174. fprintf(stdout, "OK\n");
  175. }
  176. void http_request_done(struct evhttp_request *, void *);
  177. void
  178. http_connection_test(void)
  179. {
  180. short port = -1;
  181. struct evhttp_connection *evcon = NULL;
  182. struct evhttp_request *req = NULL;
  183. test_ok = 0;
  184. fprintf(stdout, "Testing Basic HTTP Connection: ");
  185. http = http_setup(&port);
  186. evcon = evhttp_connection_new("127.0.0.1", port);
  187. if (evcon == NULL) {
  188. fprintf(stdout, "FAILED\n");
  189. exit(1);
  190. }
  191. /*
  192. * At this point, we want to schedule a request to the HTTP
  193. * server using our make request method.
  194. */
  195. req = evhttp_request_new(http_request_done, NULL);
  196. /* Add the information that we care about */
  197. evhttp_add_header(req->output_headers, "Host", "somehost");
  198. /* We give ownership of the request to the connection */
  199. if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  200. fprintf(stdout, "FAILED\n");
  201. exit(1);
  202. }
  203. event_dispatch();
  204. evhttp_connection_free(evcon);
  205. evhttp_free(http);
  206. if (test_ok != 1) {
  207. fprintf(stdout, "FAILED\n");
  208. exit(1);
  209. }
  210. fprintf(stdout, "OK\n");
  211. }
  212. void
  213. http_request_done(struct evhttp_request *req, void *arg)
  214. {
  215. const char *what = "This is funny";
  216. if (req->response_code != HTTP_OK) {
  217. fprintf(stderr, "FAILED\n");
  218. exit(1);
  219. }
  220. if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
  221. fprintf(stderr, "FAILED\n");
  222. exit(1);
  223. }
  224. if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
  225. fprintf(stderr, "FAILED\n");
  226. exit(1);
  227. }
  228. if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
  229. fprintf(stderr, "FAILED\n");
  230. exit(1);
  231. }
  232. test_ok = 1;
  233. event_loopexit(NULL);
  234. }
  235. /*
  236. * HTTP POST test.
  237. */
  238. void http_postrequest_done(struct evhttp_request *, void *);
  239. #define POST_DATA "Okay. Not really printf"
  240. void
  241. http_post_test(void)
  242. {
  243. short port = -1;
  244. struct evhttp_connection *evcon = NULL;
  245. struct evhttp_request *req = NULL;
  246. test_ok = 0;
  247. fprintf(stdout, "Testing HTTP POST Request: ");
  248. http = http_setup(&port);
  249. evcon = evhttp_connection_new("127.0.0.1", port);
  250. if (evcon == NULL) {
  251. fprintf(stdout, "FAILED\n");
  252. exit(1);
  253. }
  254. /*
  255. * At this point, we want to schedule an HTTP POST request
  256. * server using our make request method.
  257. */
  258. req = evhttp_request_new(http_postrequest_done, NULL);
  259. if (req == NULL) {
  260. fprintf(stdout, "FAILED\n");
  261. exit(1);
  262. }
  263. /* Add the information that we care about */
  264. evhttp_add_header(req->output_headers, "Host", "somehost");
  265. evbuffer_add_printf(req->output_buffer, POST_DATA);
  266. if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
  267. fprintf(stdout, "FAILED\n");
  268. exit(1);
  269. }
  270. event_dispatch();
  271. evhttp_connection_free(evcon);
  272. evhttp_free(http);
  273. if (test_ok != 1) {
  274. fprintf(stdout, "FAILED: %d\n", test_ok);
  275. exit(1);
  276. }
  277. fprintf(stdout, "OK\n");
  278. }
  279. void
  280. http_post_cb(struct evhttp_request *req, void *arg)
  281. {
  282. event_debug((stderr, "%s: called\n", __func__));
  283. /* Yes, we are expecting a post request */
  284. if (req->type != EVHTTP_REQ_POST) {
  285. fprintf(stdout, "FAILED (post type)\n");
  286. exit(1);
  287. }
  288. if (EVBUFFER_LENGTH(req->input_buffer) != strlen(POST_DATA)) {
  289. fprintf(stdout, "FAILED (length: %ld vs %ld)\n",
  290. EVBUFFER_LENGTH(req->input_buffer), strlen(POST_DATA));
  291. exit(1);
  292. }
  293. if (memcmp(EVBUFFER_DATA(req->input_buffer), POST_DATA,
  294. strlen(POST_DATA))) {
  295. fprintf(stdout, "FAILED (data)\n");
  296. fprintf(stdout, "Got :%s\n", EVBUFFER_DATA(req->input_buffer));
  297. fprintf(stdout, "Want:%s\n", POST_DATA);
  298. exit(1);
  299. }
  300. struct evbuffer *evb = evbuffer_new();
  301. evbuffer_add_printf(evb, "This is funny");
  302. evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
  303. evbuffer_free(evb);
  304. }
  305. void
  306. http_postrequest_done(struct evhttp_request *req, void *arg)
  307. {
  308. const char *what = "This is funny";
  309. if (req->response_code != HTTP_OK) {
  310. fprintf(stderr, "FAILED (response code)\n");
  311. exit(1);
  312. }
  313. if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
  314. fprintf(stderr, "FAILED (content type)\n");
  315. exit(1);
  316. }
  317. if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
  318. fprintf(stderr, "FAILED (length %ld vs %ld)\n",
  319. EVBUFFER_LENGTH(req->input_buffer), strlen(what));
  320. exit(1);
  321. }
  322. if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
  323. fprintf(stderr, "FAILED (data)\n");
  324. exit(1);
  325. }
  326. test_ok = 1;
  327. event_loopexit(NULL);
  328. }
  329. void
  330. http_suite(void)
  331. {
  332. http_basic_test();
  333. http_connection_test();
  334. http_post_test();
  335. }