/test-server/test-server-http.c

https://gitlab.com/libwebsockets/libwebsockets · C · 475 lines · 255 code · 77 blank · 143 comment · 52 complexity · b342591154b3a2857b63b31bec7613f6 MD5 · raw file

  1. /*
  2. * libwebsockets-test-server - libwebsockets test implementation
  3. *
  4. * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation:
  9. * version 2.1 of the License.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301 USA
  20. */
  21. #include "test-server.h"
  22. /*
  23. * This demo server shows how to use libwebsockets for one or more
  24. * websocket protocols in the same server
  25. *
  26. * It defines the following websocket protocols:
  27. *
  28. * dumb-increment-protocol: once the socket is opened, an incrementing
  29. * ascii string is sent down it every 50ms.
  30. * If you send "reset\n" on the websocket, then
  31. * the incrementing number is reset to 0.
  32. *
  33. * lws-mirror-protocol: copies any received packet to every connection also
  34. * using this protocol, including the sender
  35. */
  36. enum demo_protocols {
  37. /* always first */
  38. PROTOCOL_HTTP = 0,
  39. PROTOCOL_DUMB_INCREMENT,
  40. PROTOCOL_LWS_MIRROR,
  41. /* always last */
  42. DEMO_PROTOCOL_COUNT
  43. };
  44. /*
  45. * We take a strict whitelist approach to stop ../ attacks
  46. */
  47. struct serveable {
  48. const char *urlpath;
  49. const char *mimetype;
  50. };
  51. /*
  52. * this is just an example of parsing handshake headers, you don't need this
  53. * in your code unless you will filter allowing connections by the header
  54. * content
  55. */
  56. void
  57. dump_handshake_info(struct lws *wsi)
  58. {
  59. int n = 0;
  60. char buf[256];
  61. const unsigned char *c;
  62. do {
  63. c = lws_token_to_string(n);
  64. if (!c) {
  65. n++;
  66. continue;
  67. }
  68. if (!lws_hdr_total_length(wsi, n)) {
  69. n++;
  70. continue;
  71. }
  72. lws_hdr_copy(wsi, buf, sizeof buf, n);
  73. fprintf(stderr, " %s = %s\n", (char *)c, buf);
  74. n++;
  75. } while (c);
  76. }
  77. const char * get_mimetype(const char *file)
  78. {
  79. int n = strlen(file);
  80. if (n < 5)
  81. return NULL;
  82. if (!strcmp(&file[n - 4], ".ico"))
  83. return "image/x-icon";
  84. if (!strcmp(&file[n - 4], ".png"))
  85. return "image/png";
  86. if (!strcmp(&file[n - 5], ".html"))
  87. return "text/html";
  88. return NULL;
  89. }
  90. /* this protocol server (always the first one) handles HTTP,
  91. *
  92. * Some misc callbacks that aren't associated with a protocol also turn up only
  93. * here on the first protocol server.
  94. */
  95. int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
  96. void *in, size_t len)
  97. {
  98. struct per_session_data__http *pss =
  99. (struct per_session_data__http *)user;
  100. static unsigned char buffer[4096];
  101. unsigned long amount, file_len;
  102. char leaf_path[1024];
  103. const char *mimetype;
  104. char *other_headers;
  105. unsigned char *end;
  106. struct timeval tv;
  107. unsigned char *p;
  108. char buf[256];
  109. char b64[64];
  110. int n, m;
  111. #ifdef EXTERNAL_POLL
  112. struct lws_pollargs *pa = (struct lws_pollargs *)in;
  113. #endif
  114. switch (reason) {
  115. case LWS_CALLBACK_HTTP:
  116. dump_handshake_info(wsi);
  117. /* dump the individual URI Arg parameters */
  118. n = 0;
  119. while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf),
  120. WSI_TOKEN_HTTP_URI_ARGS, n) > 0) {
  121. lwsl_info("URI Arg %d: %s\n", ++n, buf);
  122. }
  123. if (len < 1) {
  124. lws_return_http_status(wsi,
  125. HTTP_STATUS_BAD_REQUEST, NULL);
  126. goto try_to_reuse;
  127. }
  128. /* this example server has no concept of directories */
  129. if (strchr((const char *)in + 1, '/')) {
  130. lws_return_http_status(wsi,
  131. HTTP_STATUS_FORBIDDEN, NULL);
  132. goto try_to_reuse;
  133. }
  134. /* if a legal POST URL, let it continue and accept data */
  135. if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
  136. return 0;
  137. /* check for the "send a big file by hand" example case */
  138. if (!strcmp((const char *)in, "/leaf.jpg")) {
  139. if (strlen(resource_path) > sizeof(leaf_path) - 10)
  140. return -1;
  141. sprintf(leaf_path, "%s/leaf.jpg", resource_path);
  142. /* well, let's demonstrate how to send the hard way */
  143. p = buffer + LWS_SEND_BUFFER_PRE_PADDING;
  144. end = p + sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
  145. pss->fd = lws_plat_file_open(wsi, leaf_path, &file_len,
  146. LWS_O_RDONLY);
  147. if (pss->fd == LWS_INVALID_FILE)
  148. return -1;
  149. /*
  150. * we will send a big jpeg file, but it could be
  151. * anything. Set the Content-Type: appropriately
  152. * so the browser knows what to do with it.
  153. *
  154. * Notice we use the APIs to build the header, which
  155. * will do the right thing for HTTP 1/1.1 and HTTP2
  156. * depending on what connection it happens to be working
  157. * on
  158. */
  159. if (lws_add_http_header_status(wsi, 200, &p, end))
  160. return 1;
  161. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
  162. (unsigned char *)"libwebsockets",
  163. 13, &p, end))
  164. return 1;
  165. if (lws_add_http_header_by_token(wsi,
  166. WSI_TOKEN_HTTP_CONTENT_TYPE,
  167. (unsigned char *)"image/jpeg",
  168. 10, &p, end))
  169. return 1;
  170. if (lws_add_http_header_content_length(wsi,
  171. file_len, &p,
  172. end))
  173. return 1;
  174. if (lws_finalize_http_header(wsi, &p, end))
  175. return 1;
  176. /*
  177. * send the http headers...
  178. * this won't block since it's the first payload sent
  179. * on the connection since it was established
  180. * (too small for partial)
  181. *
  182. * Notice they are sent using LWS_WRITE_HTTP_HEADERS
  183. * which also means you can't send body too in one step,
  184. * this is mandated by changes in HTTP2
  185. */
  186. n = lws_write(wsi, buffer + LWS_SEND_BUFFER_PRE_PADDING,
  187. p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
  188. LWS_WRITE_HTTP_HEADERS);
  189. if (n < 0) {
  190. lws_plat_file_close(wsi, pss->fd);
  191. return -1;
  192. }
  193. /*
  194. * book us a LWS_CALLBACK_HTTP_WRITEABLE callback
  195. */
  196. lws_callback_on_writable(wsi);
  197. break;
  198. }
  199. /* if not, send a file the easy way */
  200. strcpy(buf, resource_path);
  201. if (strcmp(in, "/")) {
  202. if (*((const char *)in) != '/')
  203. strcat(buf, "/");
  204. strncat(buf, in, sizeof(buf) - strlen(resource_path));
  205. } else /* default file to serve */
  206. strcat(buf, "/test.html");
  207. buf[sizeof(buf) - 1] = '\0';
  208. /* refuse to serve files we don't understand */
  209. mimetype = get_mimetype(buf);
  210. if (!mimetype) {
  211. lwsl_err("Unknown mimetype for %s\n", buf);
  212. lws_return_http_status(wsi,
  213. HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
  214. return -1;
  215. }
  216. /* demonstrates how to set a cookie on / */
  217. other_headers = NULL;
  218. n = 0;
  219. if (!strcmp((const char *)in, "/") &&
  220. !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
  221. /* this isn't very unguessable but it'll do for us */
  222. gettimeofday(&tv, NULL);
  223. n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000",
  224. (unsigned int)tv.tv_sec,
  225. (unsigned int)tv.tv_usec);
  226. p = (unsigned char *)leaf_path;
  227. if (lws_add_http_header_by_name(wsi,
  228. (unsigned char *)"set-cookie:",
  229. (unsigned char *)b64, n, &p,
  230. (unsigned char *)leaf_path + sizeof(leaf_path)))
  231. return 1;
  232. n = (char *)p - leaf_path;
  233. other_headers = leaf_path;
  234. }
  235. n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n);
  236. if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
  237. return -1; /* error or can't reuse connection: close the socket */
  238. /*
  239. * notice that the sending of the file completes asynchronously,
  240. * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
  241. * it's done
  242. */
  243. break;
  244. case LWS_CALLBACK_HTTP_BODY:
  245. strncpy(buf, in, 20);
  246. buf[20] = '\0';
  247. if (len < 20)
  248. buf[len] = '\0';
  249. lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n",
  250. (const char *)buf, (int)len);
  251. break;
  252. case LWS_CALLBACK_HTTP_BODY_COMPLETION:
  253. lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
  254. /* the whole of the sent body arrived, close or reuse the connection */
  255. lws_return_http_status(wsi, HTTP_STATUS_OK, NULL);
  256. goto try_to_reuse;
  257. case LWS_CALLBACK_HTTP_FILE_COMPLETION:
  258. goto try_to_reuse;
  259. case LWS_CALLBACK_HTTP_WRITEABLE:
  260. /*
  261. * we can send more of whatever it is we were sending
  262. */
  263. do {
  264. /* we'd like the send this much */
  265. n = sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
  266. /* but if the peer told us he wants less, we can adapt */
  267. m = lws_get_peer_write_allowance(wsi);
  268. /* -1 means not using a protocol that has this info */
  269. if (m == 0)
  270. /* right now, peer can't handle anything */
  271. goto later;
  272. if (m != -1 && m < n)
  273. /* he couldn't handle that much */
  274. n = m;
  275. n = lws_plat_file_read(wsi, pss->fd,
  276. &amount, buffer +
  277. LWS_SEND_BUFFER_PRE_PADDING, n);
  278. /* problem reading, close conn */
  279. if (n < 0)
  280. goto bail;
  281. n = (int)amount;
  282. /* sent it all, close conn */
  283. if (n == 0)
  284. goto flush_bail;
  285. /*
  286. * To support HTTP2, must take care about preamble space
  287. *
  288. * identification of when we send the last payload frame
  289. * is handled by the library itself if you sent a
  290. * content-length header
  291. */
  292. m = lws_write(wsi, buffer + LWS_SEND_BUFFER_PRE_PADDING,
  293. n, LWS_WRITE_HTTP);
  294. if (m < 0)
  295. /* write failed, close conn */
  296. goto bail;
  297. /*
  298. * http2 won't do this
  299. */
  300. if (m != n)
  301. /* partial write, adjust */
  302. if (lws_plat_file_seek_cur(wsi, pss->fd, m - n) ==
  303. (unsigned long)-1)
  304. goto bail;
  305. if (m) /* while still active, extend timeout */
  306. lws_set_timeout(wsi,
  307. PENDING_TIMEOUT_HTTP_CONTENT, 5);
  308. /* if we have indigestion, let him clear it
  309. * before eating more */
  310. if (lws_partial_buffered(wsi))
  311. break;
  312. } while (!lws_send_pipe_choked(wsi));
  313. later:
  314. lws_callback_on_writable(wsi);
  315. break;
  316. flush_bail:
  317. /* true if still partial pending */
  318. if (lws_partial_buffered(wsi)) {
  319. lws_callback_on_writable(wsi);
  320. break;
  321. }
  322. lws_plat_file_close(wsi, pss->fd);
  323. goto try_to_reuse;
  324. bail:
  325. lws_plat_file_close(wsi, pss->fd);
  326. return -1;
  327. /*
  328. * callback for confirming to continue with client IP appear in
  329. * protocol 0 callback since no websocket protocol has been agreed
  330. * yet. You can just ignore this if you won't filter on client IP
  331. * since the default uhandled callback return is 0 meaning let the
  332. * connection continue.
  333. */
  334. case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
  335. /* if we returned non-zero from here, we kill the connection */
  336. break;
  337. /*
  338. * callbacks for managing the external poll() array appear in
  339. * protocol 0 callback
  340. */
  341. case LWS_CALLBACK_LOCK_POLL:
  342. /*
  343. * lock mutex to protect pollfd state
  344. * called before any other POLL related callback
  345. * if protecting wsi lifecycle change, len == 1
  346. */
  347. test_server_lock(len);
  348. break;
  349. case LWS_CALLBACK_UNLOCK_POLL:
  350. /*
  351. * unlock mutex to protect pollfd state when
  352. * called after any other POLL related callback
  353. * if protecting wsi lifecycle change, len == 1
  354. */
  355. test_server_unlock(len);
  356. break;
  357. #ifdef EXTERNAL_POLL
  358. case LWS_CALLBACK_ADD_POLL_FD:
  359. if (count_pollfds >= max_poll_elements) {
  360. lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
  361. return 1;
  362. }
  363. fd_lookup[pa->fd] = count_pollfds;
  364. pollfds[count_pollfds].fd = pa->fd;
  365. pollfds[count_pollfds].events = pa->events;
  366. pollfds[count_pollfds++].revents = 0;
  367. break;
  368. case LWS_CALLBACK_DEL_POLL_FD:
  369. if (!--count_pollfds)
  370. break;
  371. m = fd_lookup[pa->fd];
  372. /* have the last guy take up the vacant slot */
  373. pollfds[m] = pollfds[count_pollfds];
  374. fd_lookup[pollfds[count_pollfds].fd] = m;
  375. break;
  376. case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
  377. pollfds[fd_lookup[pa->fd]].events = pa->events;
  378. break;
  379. #endif
  380. case LWS_CALLBACK_GET_THREAD_ID:
  381. /*
  382. * if you will call "lws_callback_on_writable"
  383. * from a different thread, return the caller thread ID
  384. * here so lws can use this information to work out if it
  385. * should signal the poll() loop to exit and restart early
  386. */
  387. /* return pthread_getthreadid_np(); */
  388. break;
  389. default:
  390. break;
  391. }
  392. return 0;
  393. /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */
  394. try_to_reuse:
  395. if (lws_http_transaction_completed(wsi))
  396. return -1;
  397. return 0;
  398. }