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