handle_form.inl 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* Copyright (c) 2016 the Civetweb developers
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. /********************/
  22. /* EXPERIMENTAL !!! */
  23. /********************/
  24. void
  25. mirror_body___dev_helper(struct mg_connection *conn)
  26. {
  27. /* TODO: remove this function when handle_form_data is completed. */
  28. char buf[256];
  29. int r;
  30. mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n");
  31. do {
  32. r = mg_read(conn, buf, sizeof(buf));
  33. mg_write(conn, buf, r);
  34. } while (r > 0);
  35. }
  36. enum {
  37. FORM_DISPOSITION_SKIP = 0x0,
  38. FORM_DISPOSITION_GET = 0x1,
  39. FORM_DISPOSITION_STORE = 0x2,
  40. FORM_DISPOSITION_READ = 0x4,
  41. FORM_DISPOSITION_ABORT = 0x10
  42. };
  43. struct mg_form_data_handler {
  44. int (*field_found)(const char *key,
  45. size_t keylen,
  46. const char *filename,
  47. void *user_data);
  48. int (*field_get)(const char *key,
  49. size_t keylen,
  50. const char *filename,
  51. const char *value,
  52. size_t valuelen,
  53. void *user_data);
  54. void *user_data;
  55. };
  56. static int
  57. url_encoded_field_found(const char *key,
  58. size_t keylen,
  59. const char *filename,
  60. struct mg_form_data_handler *fdh)
  61. {
  62. /* Call callback */
  63. char key_dec[1024];
  64. int ret =
  65. mg_url_decode(key, (size_t)keylen, key_dec, (int)sizeof(key_dec), 1);
  66. if ((ret < sizeof(key_dec)) && (ret >= 0)) {
  67. return fdh->field_found(key, keylen, filename, fdh->user_data);
  68. }
  69. return FORM_DISPOSITION_SKIP;
  70. }
  71. int
  72. url_encoded_field_get(const char *key,
  73. size_t keylen,
  74. const char *filename,
  75. const char *value,
  76. size_t valuelen,
  77. struct mg_form_data_handler *fdh)
  78. {
  79. char key_dec[1024];
  80. char *value_dec = mg_malloc(valuelen + 1);
  81. if (!value_dec) {
  82. /* TODO: oom */
  83. return FORM_DISPOSITION_ABORT;
  84. }
  85. mg_url_decode(key, (size_t)keylen, key_dec, (int)sizeof(key_dec), 1);
  86. mg_url_decode(value, (size_t)valuelen, value_dec, (int)valuelen + 1, 1);
  87. return fdh->field_get(
  88. key, keylen, filename, value_dec, strlen(value_dec), fdh->user_data);
  89. }
  90. int
  91. mg_handle_form_data(struct mg_connection *conn,
  92. struct mg_form_data_handler *fdh)
  93. {
  94. const char *content_type;
  95. char buf[1024];
  96. int disposition;
  97. int buf_fill = 0;
  98. int has_body_data =
  99. (conn->request_info.content_length > 0) || (conn->is_chunked);
  100. /* There are three ways to encode data from a HTML form:
  101. * 1) method: GET (default)
  102. * The form data is in the HTTP query string.
  103. * 2) method: POST, enctype: "application/x-www-form-urlencoded"
  104. * The form data is in the request body.
  105. * The body is url encoded (the default encoding for POST).
  106. * 3) method: POST, enctype: "multipart/form-data".
  107. * The form data is in the request body of a multipart message.
  108. * This is the typical way to handle file upload from a form.
  109. */
  110. if (!has_body_data) {
  111. const char *data;
  112. if (strcmp(conn->request_info.request_method, "GET")) {
  113. /* No body data, but not a GET request.
  114. * This is not a valid form request. */
  115. return 0;
  116. }
  117. /* GET request: form data is in the query string. */
  118. data = conn->request_info.query_string;
  119. if (!data) {
  120. /* No query string. */
  121. return 0;
  122. }
  123. /* Split data in a=1&b&c=3&c=4 ... */
  124. while (*data) {
  125. const char *val = strchr(data, '=');
  126. const char *next;
  127. ptrdiff_t keylen, vallen;
  128. if (!val) {
  129. break;
  130. }
  131. keylen = val - data;
  132. disposition =
  133. url_encoded_field_found(data, (size_t)keylen, NULL, fdh);
  134. val++;
  135. next = strchr(val, '&');
  136. if (next) {
  137. vallen = next - val;
  138. next++;
  139. } else {
  140. vallen = strlen(val);
  141. next = val + vallen;
  142. }
  143. if (disposition == FORM_DISPOSITION_GET) {
  144. /* Call callback */
  145. url_encoded_field_get(
  146. data, (size_t)keylen, NULL, val, (size_t)vallen, fdh);
  147. }
  148. /* Proceed to next entry */
  149. data = next;
  150. }
  151. return 0;
  152. }
  153. content_type = mg_get_header(conn, "Content-Type");
  154. if (!content_type
  155. || !mg_strcasecmp(content_type, "APPLICATION/X-WWW-FORM-URLENCODED")) {
  156. /* The form data is in the request body data, encoded in key/value
  157. * pairs. */
  158. /* Read body data and split it in a=1&b&c=3&c=4 ... */
  159. /* The encoding is like in the "GET" case above, but here we read data
  160. * on the fly */
  161. for (;;) {
  162. /* TODO(high): Handle (text) fields with data > sizeof(buf). */
  163. const char *val;
  164. const char *next;
  165. ptrdiff_t keylen, vallen;
  166. int used;
  167. if (buf_fill < (sizeof(buf) - 1)) {
  168. int r =
  169. mg_read(conn, buf + buf_fill, sizeof(buf) - 1 - buf_fill);
  170. if (r < 0) {
  171. /* read error */
  172. return 0;
  173. }
  174. buf_fill += r;
  175. buf[buf_fill] = 0;
  176. if (buf_fill < 1) {
  177. break;
  178. }
  179. }
  180. val = strchr(buf, '=');
  181. if (!val) {
  182. break;
  183. }
  184. keylen = val - buf;
  185. val++;
  186. next = strchr(val, '&');
  187. if (next) {
  188. vallen = next - val;
  189. next++;
  190. } else {
  191. vallen = strlen(val);
  192. next = val + vallen;
  193. }
  194. /* Call callback */
  195. disposition =
  196. fdh->field_found(buf, (size_t)keylen, NULL, fdh->user_data);
  197. /* Proceed to next entry */
  198. used = next - buf;
  199. memmove(buf, buf + used, sizeof(buf) - used);
  200. buf_fill -= used;
  201. }
  202. return 0;
  203. }
  204. // mirror_body___dev_helper(conn);
  205. if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
  206. /* The form data is in the request body data, encoded as multipart
  207. * content. */
  208. const char *boundary;
  209. size_t bl;
  210. int r;
  211. /* There has to be a BOUNDARY definition in the Content-Type header */
  212. if (mg_strncasecmp(content_type + 21, "BOUNDARY=", 9)) {
  213. /* Malformed request */
  214. return 0;
  215. }
  216. boundary = content_type + 30;
  217. bl = strlen(boundary);
  218. r = mg_read(conn, buf + buf_fill, sizeof(buf) - 1 - buf_fill);
  219. if (r < 0) {
  220. /* read error */
  221. return 0;
  222. }
  223. buf_fill += r;
  224. buf[buf_fill] = 0;
  225. if (buf_fill < 1) {
  226. /* No data */
  227. return 0;
  228. }
  229. if (buf[0] != '-' || buf[1] != '-') {
  230. /* Malformed request */
  231. return 0;
  232. }
  233. if (strncmp(buf + 2, boundary, bl)) {
  234. /* Malformed request */
  235. return 0;
  236. }
  237. if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
  238. /* Malformed request */
  239. return 0;
  240. }
  241. /* TODO: handle multipart request */
  242. return 0;
  243. }
  244. /* Unknown Content-Type */
  245. return 0;
  246. }