handle_form.inl 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. /* Copyright (c) 2016-2017 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. static int
  22. url_encoded_field_found(const struct mg_connection *conn,
  23. const char *key,
  24. size_t key_len,
  25. const char *filename,
  26. size_t filename_len,
  27. char *path,
  28. size_t path_len,
  29. struct mg_form_data_handler *fdh)
  30. {
  31. char key_dec[1024];
  32. char filename_dec[1024];
  33. int key_dec_len;
  34. int filename_dec_len;
  35. int ret;
  36. key_dec_len =
  37. mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
  38. if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
  39. return MG_FORM_FIELD_STORAGE_SKIP;
  40. }
  41. if (filename) {
  42. filename_dec_len = mg_url_decode(filename,
  43. (int)filename_len,
  44. filename_dec,
  45. (int)sizeof(filename_dec),
  46. 1);
  47. if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
  48. || (filename_dec_len < 0)) {
  49. /* Log error message and skip this field. */
  50. mg_cry(conn, "%s: Cannot decode filename", __func__);
  51. return MG_FORM_FIELD_STORAGE_SKIP;
  52. }
  53. } else {
  54. filename_dec[0] = 0;
  55. }
  56. ret =
  57. fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
  58. if ((ret & 0xF) == MG_FORM_FIELD_STORAGE_GET) {
  59. if (fdh->field_get == NULL) {
  60. mg_cry(conn, "%s: Function \"Get\" not available", __func__);
  61. return MG_FORM_FIELD_STORAGE_SKIP;
  62. }
  63. }
  64. if ((ret & 0xF) == MG_FORM_FIELD_STORAGE_STORE) {
  65. if (fdh->field_store == NULL) {
  66. mg_cry(conn, "%s: Function \"Store\" not available", __func__);
  67. return MG_FORM_FIELD_STORAGE_SKIP;
  68. }
  69. }
  70. return ret;
  71. }
  72. static int
  73. url_encoded_field_get(const struct mg_connection *conn,
  74. const char *key,
  75. size_t key_len,
  76. const char *value,
  77. size_t value_len,
  78. struct mg_form_data_handler *fdh)
  79. {
  80. char key_dec[1024];
  81. char *value_dec = (char *)mg_malloc_ctx(value_len + 1, conn->ctx);
  82. int value_dec_len, ret;
  83. if (!value_dec) {
  84. /* Log error message and stop parsing the form data. */
  85. mg_cry(conn,
  86. "%s: Not enough memory (required: %lu)",
  87. __func__,
  88. (unsigned long)(value_len + 1));
  89. return MG_FORM_FIELD_STORAGE_ABORT;
  90. }
  91. mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
  92. value_dec_len =
  93. mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
  94. ret = fdh->field_get(key_dec,
  95. value_dec,
  96. (size_t)value_dec_len,
  97. fdh->user_data);
  98. mg_free(value_dec);
  99. return ret;
  100. }
  101. static int
  102. unencoded_field_get(const struct mg_connection *conn,
  103. const char *key,
  104. size_t key_len,
  105. const char *value,
  106. size_t value_len,
  107. struct mg_form_data_handler *fdh)
  108. {
  109. char key_dec[1024];
  110. (void)conn;
  111. mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
  112. return fdh->field_get(key_dec, value, value_len, fdh->user_data);
  113. }
  114. static int
  115. field_stored(const struct mg_connection *conn,
  116. const char *path,
  117. long long file_size,
  118. struct mg_form_data_handler *fdh)
  119. {
  120. /* Equivalent to "upload" callback of "mg_upload". */
  121. (void)conn; /* we do not need mg_cry here, so conn is currently unused */
  122. return fdh->field_store(path, file_size, fdh->user_data);
  123. }
  124. static const char *
  125. search_boundary(const char *buf,
  126. size_t buf_len,
  127. const char *boundary,
  128. size_t boundary_len)
  129. {
  130. /* We must do a binary search here, not a string search, since the buffer
  131. * may contain '\x00' bytes, if binary data is transferred. */
  132. int clen = (int)buf_len - (int)boundary_len - 4;
  133. int i;
  134. for (i = 0; i <= clen; i++) {
  135. if (!memcmp(buf + i, "\r\n--", 4)) {
  136. if (!memcmp(buf + i + 4, boundary, boundary_len)) {
  137. return buf + i;
  138. }
  139. }
  140. }
  141. return NULL;
  142. }
  143. int
  144. mg_handle_form_request(struct mg_connection *conn,
  145. struct mg_form_data_handler *fdh)
  146. {
  147. const char *content_type;
  148. char path[512];
  149. char buf[1024]; /* Must not be smaller than ~900 - see sanity check */
  150. int field_storage;
  151. int buf_fill = 0;
  152. int r;
  153. int field_count = 0;
  154. struct mg_file fstore = STRUCT_FILE_INITIALIZER;
  155. int64_t file_size = 0; /* init here, to a avoid a false positive
  156. "uninitialized variable used" warning */
  157. int has_body_data =
  158. (conn->request_info.content_length > 0) || (conn->is_chunked);
  159. /* There are three ways to encode data from a HTML form:
  160. * 1) method: GET (default)
  161. * The form data is in the HTTP query string.
  162. * 2) method: POST, enctype: "application/x-www-form-urlencoded"
  163. * The form data is in the request body.
  164. * The body is url encoded (the default encoding for POST).
  165. * 3) method: POST, enctype: "multipart/form-data".
  166. * The form data is in the request body of a multipart message.
  167. * This is the typical way to handle file upload from a form.
  168. */
  169. if (!has_body_data) {
  170. const char *data;
  171. if (strcmp(conn->request_info.request_method, "GET")) {
  172. /* No body data, but not a GET request.
  173. * This is not a valid form request. */
  174. return -1;
  175. }
  176. /* GET request: form data is in the query string. */
  177. /* The entire data has already been loaded, so there is no nead to
  178. * call mg_read. We just need to split the query string into key-value
  179. * pairs. */
  180. data = conn->request_info.query_string;
  181. if (!data) {
  182. /* No query string. */
  183. return -1;
  184. }
  185. /* Split data in a=1&b=xy&c=3&c=4 ... */
  186. while (*data) {
  187. const char *val = strchr(data, '=');
  188. const char *next;
  189. ptrdiff_t keylen, vallen;
  190. if (!val) {
  191. break;
  192. }
  193. keylen = val - data;
  194. /* In every "field_found" callback we ask what to do with the
  195. * data ("field_storage"). This could be:
  196. * MG_FORM_FIELD_STORAGE_SKIP (0):
  197. * ignore the value of this field
  198. * MG_FORM_FIELD_STORAGE_GET (1):
  199. * read the data and call the get callback function
  200. * MG_FORM_FIELD_STORAGE_STORE (2):
  201. * store the data in a file
  202. * MG_FORM_FIELD_STORAGE_READ (3):
  203. * let the user read the data (for parsing long data on the fly)
  204. * MG_FORM_FIELD_STORAGE_ABORT (flag):
  205. * stop parsing
  206. */
  207. memset(path, 0, sizeof(path));
  208. field_count++;
  209. field_storage = url_encoded_field_found(conn,
  210. data,
  211. (size_t)keylen,
  212. NULL,
  213. 0,
  214. path,
  215. sizeof(path) - 1,
  216. fdh);
  217. val++;
  218. next = strchr(val, '&');
  219. if (next) {
  220. vallen = next - val;
  221. next++;
  222. } else {
  223. vallen = (ptrdiff_t)strlen(val);
  224. next = val + vallen;
  225. }
  226. if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
  227. /* Call callback */
  228. url_encoded_field_get(
  229. conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
  230. }
  231. if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
  232. /* Store the content to a file */
  233. if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
  234. fstore.access.fp = NULL;
  235. }
  236. file_size = 0;
  237. if (fstore.access.fp != NULL) {
  238. size_t n = (size_t)
  239. fwrite(val, 1, (size_t)vallen, fstore.access.fp);
  240. if ((n != (size_t)vallen) || (ferror(fstore.access.fp))) {
  241. mg_cry(conn,
  242. "%s: Cannot write file %s",
  243. __func__,
  244. path);
  245. (void)mg_fclose(&fstore.access);
  246. remove_bad_file(conn, path);
  247. }
  248. file_size += (int64_t)n;
  249. if (fstore.access.fp) {
  250. r = mg_fclose(&fstore.access);
  251. if (r == 0) {
  252. /* stored successfully */
  253. field_stored(conn, path, file_size, fdh);
  254. } else {
  255. mg_cry(conn,
  256. "%s: Error saving file %s",
  257. __func__,
  258. path);
  259. remove_bad_file(conn, path);
  260. }
  261. fstore.access.fp = NULL;
  262. }
  263. } else {
  264. mg_cry(conn, "%s: Cannot create file %s", __func__, path);
  265. }
  266. }
  267. /* if (field_storage == MG_FORM_FIELD_STORAGE_READ) { */
  268. /* The idea of "field_storage=read" is to let the API user read
  269. * data chunk by chunk and to some data processing on the fly.
  270. * This should avoid the need to store data in the server:
  271. * It should neither be stored in memory, like
  272. * "field_storage=get" does, nor in a file like
  273. * "field_storage=store".
  274. * However, for a "GET" request this does not make any much
  275. * sense, since the data is already stored in memory, as it is
  276. * part of the query string.
  277. */
  278. /* } */
  279. if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
  280. == MG_FORM_FIELD_STORAGE_ABORT) {
  281. /* Stop parsing the request */
  282. break;
  283. }
  284. /* Proceed to next entry */
  285. data = next;
  286. }
  287. return field_count;
  288. }
  289. content_type = mg_get_header(conn, "Content-Type");
  290. if (!content_type
  291. || !mg_strcasecmp(content_type, "APPLICATION/X-WWW-FORM-URLENCODED")
  292. || !mg_strcasecmp(content_type, "APPLICATION/WWW-FORM-URLENCODED")) {
  293. /* The form data is in the request body data, encoded in key/value
  294. * pairs. */
  295. int all_data_read = 0;
  296. /* Read body data and split it in keys and values.
  297. * The encoding is like in the "GET" case above: a=1&b&c=3&c=4.
  298. * Here we use "POST", and read the data from the request body.
  299. * The data read on the fly, so it is not required to buffer the
  300. * entire request in memory before processing it. */
  301. for (;;) {
  302. const char *val;
  303. const char *next;
  304. ptrdiff_t keylen, vallen;
  305. ptrdiff_t used;
  306. int end_of_key_value_pair_found = 0;
  307. int get_block;
  308. if ((size_t)buf_fill < (sizeof(buf) - 1)) {
  309. size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
  310. r = mg_read(conn, buf + (size_t)buf_fill, to_read);
  311. if (r < 0) {
  312. /* read error */
  313. return -1;
  314. }
  315. if (r != (int)to_read) {
  316. /* TODO: Create a function to get "all_data_read" from
  317. * the conn object. All data is read if the Content-Length
  318. * has been reached, or if chunked encoding is used and
  319. * the end marker has been read, or if the connection has
  320. * been closed. */
  321. all_data_read = 1;
  322. }
  323. buf_fill += r;
  324. buf[buf_fill] = 0;
  325. if (buf_fill < 1) {
  326. break;
  327. }
  328. }
  329. val = strchr(buf, '=');
  330. if (!val) {
  331. break;
  332. }
  333. keylen = val - buf;
  334. val++;
  335. /* Call callback */
  336. memset(path, 0, sizeof(path));
  337. field_count++;
  338. field_storage = url_encoded_field_found(conn,
  339. buf,
  340. (size_t)keylen,
  341. NULL,
  342. 0,
  343. path,
  344. sizeof(path) - 1,
  345. fdh);
  346. if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
  347. == MG_FORM_FIELD_STORAGE_ABORT) {
  348. /* Stop parsing the request */
  349. break;
  350. }
  351. if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
  352. if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
  353. fstore.access.fp = NULL;
  354. }
  355. file_size = 0;
  356. if (!fstore.access.fp) {
  357. mg_cry(conn, "%s: Cannot create file %s", __func__, path);
  358. }
  359. }
  360. get_block = 0;
  361. /* Loop to read values larger than sizeof(buf)-keylen-2 */
  362. do {
  363. next = strchr(val, '&');
  364. if (next) {
  365. vallen = next - val;
  366. next++;
  367. end_of_key_value_pair_found = 1;
  368. } else {
  369. vallen = (ptrdiff_t)strlen(val);
  370. next = val + vallen;
  371. }
  372. if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
  373. #if 0
  374. if (!end_of_key_value_pair_found && !all_data_read) {
  375. /* This callback will deliver partial contents */
  376. }
  377. #else
  378. (void)all_data_read; /* avoid warning */
  379. #endif
  380. /* Call callback */
  381. url_encoded_field_get(conn,
  382. ((get_block > 0) ? NULL : buf),
  383. ((get_block > 0) ? 0
  384. : (size_t)keylen),
  385. val,
  386. (size_t)vallen,
  387. fdh);
  388. get_block++;
  389. }
  390. if (fstore.access.fp) {
  391. size_t n = (size_t)
  392. fwrite(val, 1, (size_t)vallen, fstore.access.fp);
  393. if ((n != (size_t)vallen) || (ferror(fstore.access.fp))) {
  394. mg_cry(conn,
  395. "%s: Cannot write file %s",
  396. __func__,
  397. path);
  398. mg_fclose(&fstore.access);
  399. remove_bad_file(conn, path);
  400. }
  401. file_size += (int64_t)n;
  402. }
  403. if (!end_of_key_value_pair_found) {
  404. used = next - buf;
  405. memmove(buf,
  406. buf + (size_t)used,
  407. sizeof(buf) - (size_t)used);
  408. buf_fill -= (int)used;
  409. if ((size_t)buf_fill < (sizeof(buf) - 1)) {
  410. size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
  411. r = mg_read(conn, buf + (size_t)buf_fill, to_read);
  412. if (r < 0) {
  413. /* read error */
  414. return -1;
  415. }
  416. if (r != (int)to_read) {
  417. /* TODO: Create a function to get "all_data_read"
  418. * from the conn object. All data is read if the
  419. * Content-Length has been reached, or if chunked
  420. * encoding is used and the end marker has been
  421. * read, or if the connection has been closed. */
  422. all_data_read = 1;
  423. }
  424. buf_fill += r;
  425. buf[buf_fill] = 0;
  426. if (buf_fill < 1) {
  427. break;
  428. }
  429. val = buf;
  430. }
  431. }
  432. } while (!end_of_key_value_pair_found);
  433. if (fstore.access.fp) {
  434. r = mg_fclose(&fstore.access);
  435. if (r == 0) {
  436. /* stored successfully */
  437. field_stored(conn, path, file_size, fdh);
  438. } else {
  439. mg_cry(conn, "%s: Error saving file %s", __func__, path);
  440. remove_bad_file(conn, path);
  441. }
  442. fstore.access.fp = NULL;
  443. }
  444. /* Proceed to next entry */
  445. used = next - buf;
  446. memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
  447. buf_fill -= (int)used;
  448. }
  449. return field_count;
  450. }
  451. if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
  452. /* The form data is in the request body data, encoded as multipart
  453. * content (see https://www.ietf.org/rfc/rfc1867.txt,
  454. * https://www.ietf.org/rfc/rfc2388.txt). */
  455. char *boundary;
  456. size_t bl;
  457. ptrdiff_t used;
  458. struct mg_request_info part_header;
  459. char *hbuf;
  460. const char *content_disp, *hend, *fbeg, *fend, *nbeg, *nend;
  461. const char *next;
  462. unsigned part_no;
  463. memset(&part_header, 0, sizeof(part_header));
  464. /* Skip all spaces between MULTIPART/FORM-DATA; and BOUNDARY= */
  465. bl = 20;
  466. while (content_type[bl] == ' ') {
  467. bl++;
  468. }
  469. /* There has to be a BOUNDARY definition in the Content-Type header */
  470. if (mg_strncasecmp(content_type + bl, "BOUNDARY=", 9)) {
  471. /* Malformed request */
  472. return -1;
  473. }
  474. /* Copy boundary string to variable "boundary" */
  475. fbeg = content_type + bl + 9;
  476. bl = strlen(fbeg);
  477. boundary = (char *)mg_malloc(bl + 1);
  478. if (!boundary) {
  479. /* Out of memory */
  480. mg_cry(conn,
  481. "%s: Cannot allocate memory for boundary [%lu]",
  482. __func__,
  483. (unsigned long)bl);
  484. return -1;
  485. }
  486. memcpy(boundary, fbeg, bl);
  487. boundary[bl] = 0;
  488. /* RFC 2046 permits the boundary string to be quoted. */
  489. /* If the boundary is quoted, trim the quotes */
  490. if (boundary[0] == '"') {
  491. hbuf = strchr(boundary + 1, '"');
  492. if ((!hbuf) || (*hbuf != '"')) {
  493. /* Malformed request */
  494. mg_free(boundary);
  495. return -1;
  496. }
  497. *hbuf = 0;
  498. memmove(boundary, boundary + 1, bl);
  499. bl = strlen(boundary);
  500. }
  501. /* Do some sanity checks for boundary lengths */
  502. if (bl > 70) {
  503. /* From RFC 2046:
  504. * Boundary delimiters must not appear within the
  505. * encapsulated material, and must be no longer
  506. * than 70 characters, not counting the two
  507. * leading hyphens.
  508. */
  509. /* The initial sanity check
  510. * (bl + 800 > sizeof(buf))
  511. * is no longer required, since sizeof(buf) == 1024
  512. *
  513. * Original comment:
  514. */
  515. /* Sanity check: The algorithm can not work if bl >= sizeof(buf),
  516. * and it will not work effectively, if the buf is only a few byte
  517. * larger than bl, or if buf can not hold the multipart header
  518. * plus the boundary.
  519. * Check some reasonable number here, that should be fulfilled by
  520. * any reasonable request from every browser. If it is not
  521. * fulfilled, it might be a hand-made request, intended to
  522. * interfere with the algorithm. */
  523. mg_free(boundary);
  524. return -1;
  525. }
  526. if (bl < 4) {
  527. /* Sanity check: A boundary string of less than 4 bytes makes
  528. * no sense either. */
  529. mg_free(boundary);
  530. return -1;
  531. }
  532. for (part_no = 0;; part_no++) {
  533. size_t towrite, n;
  534. int get_block;
  535. r = mg_read(conn,
  536. buf + (size_t)buf_fill,
  537. sizeof(buf) - 1 - (size_t)buf_fill);
  538. if (r < 0) {
  539. /* read error */
  540. mg_free(boundary);
  541. return -1;
  542. }
  543. buf_fill += r;
  544. buf[buf_fill] = 0;
  545. if (buf_fill < 1) {
  546. /* No data */
  547. mg_free(boundary);
  548. return -1;
  549. }
  550. if (part_no == 0) {
  551. int d = 0;
  552. while ((buf[d] != '-') && (d < buf_fill)) {
  553. d++;
  554. }
  555. if ((d > 0) && (buf[d] == '-')) {
  556. memmove(buf, buf + d, (unsigned)buf_fill - (unsigned)d);
  557. buf_fill -= d;
  558. buf[buf_fill] = 0;
  559. }
  560. }
  561. if (buf[0] != '-' || buf[1] != '-') {
  562. /* Malformed request */
  563. mg_free(boundary);
  564. return -1;
  565. }
  566. if (strncmp(buf + 2, boundary, bl)) {
  567. /* Malformed request */
  568. mg_free(boundary);
  569. return -1;
  570. }
  571. if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
  572. /* Every part must end with \r\n, if there is another part.
  573. * The end of the request has an extra -- */
  574. if (((size_t)buf_fill != (size_t)(bl + 6))
  575. || (strncmp(buf + bl + 2, "--\r\n", 4))) {
  576. /* Malformed request */
  577. mg_free(boundary);
  578. return -1;
  579. }
  580. /* End of the request */
  581. break;
  582. }
  583. /* Next, we need to get the part header: Read until \r\n\r\n */
  584. hbuf = buf + bl + 4;
  585. hend = strstr(hbuf, "\r\n\r\n");
  586. if (!hend) {
  587. /* Malformed request */
  588. mg_free(boundary);
  589. return -1;
  590. }
  591. part_header.num_headers =
  592. parse_http_headers(&hbuf, part_header.http_headers);
  593. if ((hend + 2) != hbuf) {
  594. /* Malformed request */
  595. mg_free(boundary);
  596. return -1;
  597. }
  598. /* Skip \r\n\r\n */
  599. hend += 4;
  600. /* According to the RFC, every part has to have a header field like:
  601. * Content-Disposition: form-data; name="..." */
  602. content_disp = get_header(part_header.http_headers,
  603. part_header.num_headers,
  604. "Content-Disposition");
  605. if (!content_disp) {
  606. /* Malformed request */
  607. mg_free(boundary);
  608. return -1;
  609. }
  610. /* Get the mandatory name="..." part of the Content-Disposition
  611. * header. */
  612. nbeg = strstr(content_disp, "name=\"");
  613. while ((nbeg != NULL) && (strcspn(nbeg - 1, ":,; \t") != 0)) {
  614. /* It could be somethingname= instead of name= */
  615. nbeg = strstr(nbeg + 1, "name=\"");
  616. }
  617. /* This line is not required, but otherwise some compilers
  618. * generate spurious warnings. */
  619. nend = nbeg;
  620. /* And others complain, the result is unused. */
  621. (void)nend;
  622. /* If name=" is found, search for the closing " */
  623. if (nbeg) {
  624. nbeg += 6;
  625. nend = strchr(nbeg, '\"');
  626. if (!nend) {
  627. /* Malformed request */
  628. mg_free(boundary);
  629. return -1;
  630. }
  631. } else {
  632. /* name= without quotes is also allowed */
  633. nbeg = strstr(content_disp, "name=");
  634. while ((nbeg != NULL) && (strcspn(nbeg - 1, ":,; \t") != 0)) {
  635. /* It could be somethingname= instead of name= */
  636. nbeg = strstr(nbeg + 1, "name=");
  637. }
  638. if (!nbeg) {
  639. /* Malformed request */
  640. mg_free(boundary);
  641. return -1;
  642. }
  643. nbeg += 5;
  644. /* RFC 2616 Sec. 2.2 defines a list of allowed
  645. * separators, but many of them make no sense
  646. * here, e.g. various brackets or slashes.
  647. * If they are used, probably someone is
  648. * trying to attack with curious hand made
  649. * requests. Only ; , space and tab seem to be
  650. * reasonable here. Ignore everything else. */
  651. nend = nbeg + strcspn(nbeg, ",; \t");
  652. }
  653. /* Get the optional filename="..." part of the Content-Disposition
  654. * header. */
  655. fbeg = strstr(content_disp, "filename=\"");
  656. while ((fbeg != NULL) && (strcspn(fbeg - 1, ":,; \t") != 0)) {
  657. /* It could be somethingfilename= instead of filename= */
  658. fbeg = strstr(fbeg + 1, "filename=\"");
  659. }
  660. /* This line is not required, but otherwise some compilers
  661. * generate spurious warnings. */
  662. fend = fbeg;
  663. /* If filename=" is found, search for the closing " */
  664. if (fbeg) {
  665. fbeg += 10;
  666. fend = strchr(fbeg, '\"');
  667. if (!fend) {
  668. /* Malformed request (the filename field is optional, but if
  669. * it exists, it needs to be terminated correctly). */
  670. mg_free(boundary);
  671. return -1;
  672. }
  673. /* TODO: check Content-Type */
  674. /* Content-Type: application/octet-stream */
  675. }
  676. if (!fbeg) {
  677. /* Try the same without quotes */
  678. fbeg = strstr(content_disp, "filename=");
  679. while ((fbeg != NULL) && (strcspn(fbeg - 1, ":,; \t") != 0)) {
  680. /* It could be somethingfilename= instead of filename= */
  681. fbeg = strstr(fbeg + 1, "filename=");
  682. }
  683. if (fbeg) {
  684. fbeg += 9;
  685. fend = fbeg + strcspn(fbeg, ",; \t");
  686. }
  687. }
  688. if (!fbeg) {
  689. fend = NULL;
  690. }
  691. /* In theory, it could be possible that someone crafts
  692. * a request like name=filename=xyz. Check if name and
  693. * filename do not overlap. */
  694. if (!(((ptrdiff_t)fbeg > (ptrdiff_t)nend)
  695. || ((ptrdiff_t)nbeg > (ptrdiff_t)fend))) {
  696. mg_free(boundary);
  697. return -1;
  698. }
  699. /* Call callback for new field */
  700. memset(path, 0, sizeof(path));
  701. field_count++;
  702. field_storage = url_encoded_field_found(conn,
  703. nbeg,
  704. (size_t)(nend - nbeg),
  705. fbeg,
  706. (size_t)(fend - fbeg),
  707. path,
  708. sizeof(path) - 1,
  709. fdh);
  710. /* If the boundary is already in the buffer, get the address,
  711. * otherwise next will be NULL. */
  712. next = search_boundary(hbuf,
  713. (size_t)((buf - hbuf) + buf_fill),
  714. boundary,
  715. bl);
  716. if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
  717. /* Store the content to a file */
  718. if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
  719. fstore.access.fp = NULL;
  720. }
  721. file_size = 0;
  722. if (!fstore.access.fp) {
  723. mg_cry(conn, "%s: Cannot create file %s", __func__, path);
  724. }
  725. }
  726. get_block = 0;
  727. while (!next) {
  728. /* Set "towrite" to the number of bytes available
  729. * in the buffer */
  730. towrite = (size_t)(buf - hend + buf_fill);
  731. /* Subtract the boundary length, to deal with
  732. * cases the boundary is only partially stored
  733. * in the buffer. */
  734. towrite -= bl + 4;
  735. if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
  736. unencoded_field_get(conn,
  737. ((get_block > 0) ? NULL : nbeg),
  738. ((get_block > 0)
  739. ? 0
  740. : (size_t)(nend - nbeg)),
  741. hend,
  742. towrite,
  743. fdh);
  744. get_block++;
  745. }
  746. if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
  747. if (fstore.access.fp) {
  748. /* Store the content of the buffer. */
  749. n = (size_t)fwrite(hend, 1, towrite, fstore.access.fp);
  750. if ((n != towrite) || (ferror(fstore.access.fp))) {
  751. mg_cry(conn,
  752. "%s: Cannot write file %s",
  753. __func__,
  754. path);
  755. mg_fclose(&fstore.access);
  756. remove_bad_file(conn, path);
  757. }
  758. file_size += (int64_t)n;
  759. }
  760. }
  761. memmove(buf, hend + towrite, bl + 4);
  762. buf_fill = (int)(bl + 4);
  763. hend = buf;
  764. /* Read new data */
  765. r = mg_read(conn,
  766. buf + (size_t)buf_fill,
  767. sizeof(buf) - 1 - (size_t)buf_fill);
  768. if (r < 0) {
  769. /* read error */
  770. mg_free(boundary);
  771. return -1;
  772. }
  773. buf_fill += r;
  774. buf[buf_fill] = 0;
  775. if (buf_fill < 1) {
  776. /* No data */
  777. mg_free(boundary);
  778. return -1;
  779. }
  780. /* Find boundary */
  781. next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
  782. }
  783. towrite = (size_t)(next - hend);
  784. if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
  785. /* Call callback */
  786. unencoded_field_get(conn,
  787. ((get_block > 0) ? NULL : nbeg),
  788. ((get_block > 0) ? 0
  789. : (size_t)(nend - nbeg)),
  790. hend,
  791. towrite,
  792. fdh);
  793. }
  794. if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
  795. if (fstore.access.fp) {
  796. n = (size_t)fwrite(hend, 1, towrite, fstore.access.fp);
  797. if ((n != towrite) || (ferror(fstore.access.fp))) {
  798. mg_cry(conn,
  799. "%s: Cannot write file %s",
  800. __func__,
  801. path);
  802. mg_fclose(&fstore.access);
  803. remove_bad_file(conn, path);
  804. } else {
  805. file_size += (int64_t)n;
  806. r = mg_fclose(&fstore.access);
  807. if (r == 0) {
  808. /* stored successfully */
  809. field_stored(conn, path, file_size, fdh);
  810. } else {
  811. mg_cry(conn,
  812. "%s: Error saving file %s",
  813. __func__,
  814. path);
  815. remove_bad_file(conn, path);
  816. }
  817. }
  818. fstore.access.fp = NULL;
  819. }
  820. }
  821. if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
  822. == MG_FORM_FIELD_STORAGE_ABORT) {
  823. /* Stop parsing the request */
  824. break;
  825. }
  826. /* Remove from the buffer */
  827. used = next - buf + 2;
  828. memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
  829. buf_fill -= (int)used;
  830. }
  831. /* All parts handled */
  832. mg_free(boundary);
  833. return field_count;
  834. }
  835. /* Unknown Content-Type */
  836. return -1;
  837. }
  838. /* End of handle_form.inl */