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