protocol_post_demo.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * ws protocol handler plugin for "POST demo"
  3. *
  4. * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
  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 "../lib/libwebsockets.h"
  24. #endif
  25. #include <string.h>
  26. #include <fcntl.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #ifdef WIN32
  30. #include <io.h>
  31. #endif
  32. #include <stdio.h>
  33. struct per_session_data__post_demo {
  34. struct lws_spa *spa;
  35. char result[LWS_PRE + 512];
  36. int result_len;
  37. char filename[64];
  38. long file_length;
  39. #if !defined(LWS_WITH_ESP8266)
  40. lws_filefd_type fd;
  41. #endif
  42. };
  43. static const char * const param_names[] = {
  44. "text",
  45. "send",
  46. "file",
  47. "upload",
  48. };
  49. enum enum_param_names {
  50. EPN_TEXT,
  51. EPN_SEND,
  52. EPN_FILE,
  53. EPN_UPLOAD,
  54. };
  55. static int
  56. file_upload_cb(void *data, const char *name, const char *filename,
  57. char *buf, int len, enum lws_spa_fileupload_states state)
  58. {
  59. struct per_session_data__post_demo *pss =
  60. (struct per_session_data__post_demo *)data;
  61. int n;
  62. switch (state) {
  63. case LWS_UFS_OPEN:
  64. strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
  65. /* we get the original filename in @filename arg, but for
  66. * simple demo use a fixed name so we don't have to deal with
  67. * attacks */
  68. #if !defined(LWS_WITH_ESP8266)
  69. pss->fd = (lws_filefd_type)open("/tmp/post-file",
  70. O_CREAT | O_TRUNC | O_RDWR, 0600);
  71. #endif
  72. break;
  73. case LWS_UFS_FINAL_CONTENT:
  74. case LWS_UFS_CONTENT:
  75. if (len) {
  76. pss->file_length += len;
  77. /* if the file length is too big, drop it */
  78. if (pss->file_length > 100000)
  79. return 1;
  80. #if !defined(LWS_WITH_ESP8266)
  81. n = write((int)pss->fd, buf, len);
  82. lwsl_notice("%s: write %d says %d\n", __func__, len, n);
  83. #else
  84. lwsl_notice("%s: Received chunk size %d\n", __func__, len);
  85. #endif
  86. }
  87. if (state == LWS_UFS_CONTENT)
  88. break;
  89. #if !defined(LWS_WITH_ESP8266)
  90. close((int)pss->fd);
  91. pss->fd = LWS_INVALID_FILE;
  92. #endif
  93. break;
  94. }
  95. return 0;
  96. }
  97. static int
  98. callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason,
  99. void *user, void *in, size_t len)
  100. {
  101. struct per_session_data__post_demo *pss =
  102. (struct per_session_data__post_demo *)user;
  103. unsigned char *buffer;
  104. unsigned char *p, *start, *end;
  105. int n;
  106. switch (reason) {
  107. case LWS_CALLBACK_HTTP_BODY:
  108. /* create the POST argument parser if not already existing */
  109. if (!pss->spa) {
  110. pss->spa = lws_spa_create(wsi, param_names,
  111. ARRAY_SIZE(param_names), 1024,
  112. file_upload_cb, pss);
  113. if (!pss->spa)
  114. return -1;
  115. pss->filename[0] = '\0';
  116. pss->file_length = 0;
  117. }
  118. /* let it parse the POST data */
  119. if (lws_spa_process(pss->spa, in, len))
  120. return -1;
  121. break;
  122. case LWS_CALLBACK_HTTP_BODY_COMPLETION:
  123. lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
  124. /* call to inform no more payload data coming */
  125. lws_spa_finalize(pss->spa);
  126. p = (unsigned char *)pss->result + LWS_PRE;
  127. end = p + sizeof(pss->result) - LWS_PRE - 1;
  128. p += sprintf((char *)p,
  129. "<html><body><h1>Form results (after urldecoding)</h1>"
  130. "<table><tr><td>Name</td><td>Length</td><td>Value</td></tr>");
  131. for (n = 0; n < ARRAY_SIZE(param_names); n++)
  132. p += lws_snprintf((char *)p, end - p,
  133. "<tr><td><b>%s</b></td><td>%d</td><td>%s</td></tr>",
  134. param_names[n],
  135. lws_spa_get_length(pss->spa, n),
  136. lws_spa_get_string(pss->spa, n));
  137. p += lws_snprintf((char *)p, end - p, "</table><br><b>filename:</b> %s, <b>length</b> %ld",
  138. pss->filename, pss->file_length);
  139. p += lws_snprintf((char *)p, end - p, "</body></html>");
  140. pss->result_len = p - (unsigned char *)(pss->result + LWS_PRE);
  141. n = LWS_PRE + 1024;
  142. buffer = malloc(n);
  143. p = buffer + LWS_PRE;
  144. start = p;
  145. end = p + n - LWS_PRE - 1;
  146. if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
  147. goto bail;
  148. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
  149. (unsigned char *)"text/html", 9, &p, end))
  150. goto bail;
  151. if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
  152. goto bail;
  153. if (lws_finalize_http_header(wsi, &p, end))
  154. goto bail;
  155. n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
  156. if (n < 0)
  157. goto bail;
  158. free(buffer);
  159. lws_callback_on_writable(wsi);
  160. break;
  161. case LWS_CALLBACK_HTTP_WRITEABLE:
  162. lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
  163. pss->result_len);
  164. n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
  165. pss->result_len, LWS_WRITE_HTTP);
  166. if (n < 0)
  167. return 1;
  168. goto try_to_reuse;
  169. case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
  170. /* called when our wsi user_space is going to be destroyed */
  171. if (pss->spa) {
  172. lws_spa_destroy(pss->spa);
  173. pss->spa = NULL;
  174. }
  175. break;
  176. default:
  177. break;
  178. }
  179. return 0;
  180. bail:
  181. free(buffer);
  182. return 1;
  183. try_to_reuse:
  184. if (lws_http_transaction_completed(wsi))
  185. return -1;
  186. return 0;
  187. }
  188. #define LWS_PLUGIN_PROTOCOL_POST_DEMO \
  189. { \
  190. "protocol-post-demo", \
  191. callback_post_demo, \
  192. sizeof(struct per_session_data__post_demo), \
  193. 1024, \
  194. }
  195. #if !defined (LWS_PLUGIN_STATIC)
  196. static const struct lws_protocols protocols[] = {
  197. LWS_PLUGIN_PROTOCOL_POST_DEMO
  198. };
  199. LWS_EXTERN LWS_VISIBLE int
  200. init_protocol_post_demo(struct lws_context *context,
  201. struct lws_plugin_capability *c)
  202. {
  203. if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
  204. lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
  205. c->api_magic);
  206. return 1;
  207. }
  208. c->protocols = protocols;
  209. c->count_protocols = ARRAY_SIZE(protocols);
  210. c->extensions = NULL;
  211. c->count_extensions = 0;
  212. return 0;
  213. }
  214. LWS_EXTERN LWS_VISIBLE int
  215. destroy_protocol_post_demo(struct lws_context *context)
  216. {
  217. return 0;
  218. }
  219. #endif