protocol_post_demo.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * ws protocol handler plugin for "POST demo"
  3. *
  4. * Written in 2010-2019 by Andy Green <[email protected]>
  5. *
  6. * This file is made available under the Creative Commons CC0 1.0
  7. * Universal Public Domain Dedication.
  8. *
  9. * The person who associated a work with this deed has dedicated
  10. * the work to the public domain by waiving all of his or her rights
  11. * to the work worldwide under copyright law, including all related
  12. * and neighboring rights, to the extent allowed by law. You can copy,
  13. * modify, distribute and perform the work, even for commercial purposes,
  14. * all without asking permission.
  15. *
  16. * These test plugins are intended to be adapted for use in your code, which
  17. * may be proprietary. So unlike the library itself, they are licensed
  18. * Public Domain.
  19. */
  20. #if !defined (LWS_PLUGIN_STATIC)
  21. #define LWS_DLL
  22. #define LWS_INTERNAL
  23. #include <libwebsockets.h>
  24. #endif
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <fcntl.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #ifdef WIN32
  31. #include <io.h>
  32. #endif
  33. #include <stdio.h>
  34. struct per_session_data__post_demo {
  35. struct lws_spa *spa;
  36. char result[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE];
  37. char filename[64];
  38. long file_length;
  39. #if !defined(LWS_WITH_ESP32)
  40. lws_filefd_type fd;
  41. #endif
  42. uint8_t completed:1;
  43. uint8_t sent_headers:1;
  44. uint8_t sent_body:1;
  45. };
  46. static const char * const param_names[] = {
  47. "text",
  48. "send",
  49. "file",
  50. "upload",
  51. };
  52. enum enum_param_names {
  53. EPN_TEXT,
  54. EPN_SEND,
  55. EPN_FILE,
  56. EPN_UPLOAD,
  57. };
  58. static int
  59. file_upload_cb(void *data, const char *name, const char *filename,
  60. char *buf, int len, enum lws_spa_fileupload_states state)
  61. {
  62. struct per_session_data__post_demo *pss =
  63. (struct per_session_data__post_demo *)data;
  64. #if !defined(LWS_WITH_ESP32)
  65. int n;
  66. (void)n;
  67. #endif
  68. switch (state) {
  69. case LWS_UFS_OPEN:
  70. lws_strncpy(pss->filename, filename, sizeof(pss->filename));
  71. /* we get the original filename in @filename arg, but for
  72. * simple demo use a fixed name so we don't have to deal with
  73. * attacks */
  74. #if !defined(LWS_WITH_ESP32)
  75. pss->fd = (lws_filefd_type)(lws_intptr_t)lws_open("/tmp/post-file",
  76. O_CREAT | O_TRUNC | O_RDWR, 0600);
  77. #endif
  78. break;
  79. case LWS_UFS_FINAL_CONTENT:
  80. case LWS_UFS_CONTENT:
  81. if (len) {
  82. pss->file_length += len;
  83. /* if the file length is too big, drop it */
  84. if (pss->file_length > 100000)
  85. return 1;
  86. #if !defined(LWS_WITH_ESP32)
  87. n = write((int)(lws_intptr_t)pss->fd, buf, len);
  88. lwsl_info("%s: write %d says %d\n", __func__, len, n);
  89. #else
  90. lwsl_notice("%s: Received chunk size %d\n", __func__, len);
  91. #endif
  92. }
  93. if (state == LWS_UFS_CONTENT)
  94. break;
  95. #if !defined(LWS_WITH_ESP32)
  96. close((int)(lws_intptr_t)pss->fd);
  97. pss->fd = LWS_INVALID_FILE;
  98. #endif
  99. break;
  100. case LWS_UFS_CLOSE:
  101. break;
  102. }
  103. return 0;
  104. }
  105. /*
  106. * returns length in bytes
  107. */
  108. static int
  109. format_result(struct per_session_data__post_demo *pss)
  110. {
  111. unsigned char *p, *start, *end;
  112. int n;
  113. p = (unsigned char *)pss->result + LWS_PRE;
  114. start = p;
  115. end = p + sizeof(pss->result) - LWS_PRE - 1;
  116. p += lws_snprintf((char *)p, end -p,
  117. "<!DOCTYPE html><html lang=\"en\"><head>"
  118. "<meta charset=utf-8 http-equiv=\"Content-Language\" "
  119. "content=\"en\"/>"
  120. "<title>LWS Server Status</title>"
  121. "</head><body><h1>Form results (after urldecoding)</h1>"
  122. "<table><tr><td>Name</td><td>Length</td><td>Value</td></tr>");
  123. for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) {
  124. if (!lws_spa_get_string(pss->spa, n))
  125. p += lws_snprintf((char *)p, end - p,
  126. "<tr><td><b>%s</b></td><td>0"
  127. "</td><td>NULL</td></tr>",
  128. param_names[n]);
  129. else
  130. p += lws_snprintf((char *)p, end - p,
  131. "<tr><td><b>%s</b></td><td>%d"
  132. "</td><td>%s</td></tr>",
  133. param_names[n],
  134. lws_spa_get_length(pss->spa, n),
  135. lws_spa_get_string(pss->spa, n));
  136. }
  137. p += lws_snprintf((char *)p, end - p,
  138. "</table><br><b>filename:</b> %s, "
  139. "<b>length</b> %ld",
  140. pss->filename, pss->file_length);
  141. p += lws_snprintf((char *)p, end - p, "</body></html>");
  142. return (int)lws_ptr_diff(p, start);
  143. }
  144. static int
  145. callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason,
  146. void *user, void *in, size_t len)
  147. {
  148. struct per_session_data__post_demo *pss =
  149. (struct per_session_data__post_demo *)user;
  150. unsigned char *p, *start, *end;
  151. int n;
  152. switch (reason) {
  153. case LWS_CALLBACK_HTTP_BODY:
  154. /* create the POST argument parser if not already existing */
  155. if (!pss->spa) {
  156. pss->spa = lws_spa_create(wsi, param_names,
  157. LWS_ARRAY_SIZE(param_names), 1024,
  158. file_upload_cb, pss);
  159. if (!pss->spa)
  160. return -1;
  161. pss->filename[0] = '\0';
  162. pss->file_length = 0;
  163. }
  164. /* let it parse the POST data */
  165. if (lws_spa_process(pss->spa, in, (int)len))
  166. return -1;
  167. break;
  168. case LWS_CALLBACK_HTTP_BODY_COMPLETION:
  169. lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION: %p\n", wsi);
  170. /* call to inform no more payload data coming */
  171. lws_spa_finalize(pss->spa);
  172. pss->completed = 1;
  173. lws_callback_on_writable(wsi);
  174. break;
  175. case LWS_CALLBACK_HTTP_WRITEABLE:
  176. if (!pss->completed)
  177. break;
  178. p = (unsigned char *)pss->result + LWS_PRE;
  179. start = p;
  180. end = p + sizeof(pss->result) - LWS_PRE - 1;
  181. if (!pss->sent_headers) {
  182. n = format_result(pss);
  183. if (lws_add_http_header_status(wsi, HTTP_STATUS_OK,
  184. &p, end))
  185. goto bail;
  186. if (lws_add_http_header_by_token(wsi,
  187. WSI_TOKEN_HTTP_CONTENT_TYPE,
  188. (unsigned char *)"text/html", 9,
  189. &p, end))
  190. goto bail;
  191. if (lws_add_http_header_content_length(wsi, n, &p, end))
  192. goto bail;
  193. if (lws_finalize_http_header(wsi, &p, end))
  194. goto bail;
  195. /* first send the headers ... */
  196. n = lws_write(wsi, start, lws_ptr_diff(p, start),
  197. LWS_WRITE_HTTP_HEADERS);
  198. if (n < 0)
  199. goto bail;
  200. pss->sent_headers = 1;
  201. lws_callback_on_writable(wsi);
  202. break;
  203. }
  204. if (!pss->sent_body) {
  205. n = format_result(pss);
  206. n = lws_write(wsi, (unsigned char *)start, n,
  207. LWS_WRITE_HTTP_FINAL);
  208. pss->sent_body = 1;
  209. if (n < 0)
  210. return 1;
  211. goto try_to_reuse;
  212. }
  213. break;
  214. case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
  215. /* called when our wsi user_space is going to be destroyed */
  216. if (pss->spa) {
  217. lws_spa_destroy(pss->spa);
  218. pss->spa = NULL;
  219. }
  220. break;
  221. default:
  222. break;
  223. }
  224. return 0;
  225. bail:
  226. return 1;
  227. try_to_reuse:
  228. if (lws_http_transaction_completed(wsi))
  229. return -1;
  230. return 0;
  231. }
  232. #define LWS_PLUGIN_PROTOCOL_POST_DEMO \
  233. { \
  234. "protocol-post-demo", \
  235. callback_post_demo, \
  236. sizeof(struct per_session_data__post_demo), \
  237. 1024, \
  238. 0, NULL, 0 \
  239. }
  240. #if !defined (LWS_PLUGIN_STATIC)
  241. static const struct lws_protocols protocols[] = {
  242. LWS_PLUGIN_PROTOCOL_POST_DEMO
  243. };
  244. LWS_VISIBLE const lws_plugin_protocol_t post_demo = {
  245. .hdr = {
  246. "post demo",
  247. "lws_protocol_plugin",
  248. LWS_PLUGIN_API_MAGIC
  249. },
  250. .protocols = protocols,
  251. .count_protocols = LWS_ARRAY_SIZE(protocols),
  252. .extensions = NULL,
  253. .count_extensions = 0,
  254. };
  255. #endif