1 #include "uwsgi.h"
2 
3 extern struct uwsgi_server uwsgi;
4 
uwsgi_simple_wait_read_hook(int fd,int timeout)5 int uwsgi_simple_wait_read_hook(int fd, int timeout) {
6 	struct pollfd upoll;
7 	timeout = timeout * 1000;
8 	int ret;
9 
10         upoll.fd = fd;
11         upoll.events = POLLIN;
12         upoll.revents = 0;
13 	for (;;) {
14 		ret = poll(&upoll, 1, timeout);
15 		if ((ret < 0) && (errno == EINTR))
16 			continue;
17 		break;
18         }
19 
20         if (ret > 0) {
21                 if (upoll.revents & POLLIN) {
22                         return 1;
23                 }
24 		return -1;
25         }
26         if (ret < 0) {
27                 uwsgi_error("uwsgi_simple_wait_read_hook()/poll()");
28         }
29 
30         return ret;
31 }
32 
uwsgi_simple_wait_read2_hook(int fd0,int fd1,int timeout,int * fd)33 int uwsgi_simple_wait_read2_hook(int fd0, int fd1, int timeout, int *fd) {
34         struct pollfd upoll[2];
35         timeout = timeout * 1000;
36 
37         upoll[0].fd = fd0;
38         upoll[0].events = POLLIN;
39         upoll[0].revents = 0;
40 
41         upoll[1].fd = fd1;
42         upoll[1].events = POLLIN;
43         upoll[1].revents = 0;
44 
45         int ret = poll(upoll, 2, timeout);
46 
47         if (ret > 0) {
48                 if (upoll[0].revents & POLLIN) {
49 			*fd = fd0;
50                         return 1;
51                 }
52                 if (upoll[1].revents & POLLIN) {
53 			*fd = fd1;
54                         return 1;
55                 }
56                 return -1;
57         }
58         if (ret < 0) {
59                 uwsgi_error("uwsgi_simple_wait_read_hook2()/poll()");
60         }
61 
62         return ret;
63 }
64 
65 
66 /*
67 	seek()/rewind() language-independent implementations.
68 */
69 
uwsgi_request_body_seek(struct wsgi_request * wsgi_req,off_t pos)70 void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) {
71 	if (wsgi_req->post_file) {
72 		if (pos < 0) {
73 			if (fseek(wsgi_req->post_file, pos, SEEK_CUR)) {
74                         	uwsgi_req_error("uwsgi_request_body_seek()/fseek()");
75 				wsgi_req->read_errors++;
76                 	}
77 			wsgi_req->post_pos = ftell(wsgi_req->post_file);
78 			return;
79 		}
80 
81 		if (fseek(wsgi_req->post_file, pos, SEEK_SET)) {
82 			uwsgi_req_error("uwsgi_request_body_seek()/fseek()");
83 			wsgi_req->read_errors++;
84 		}
85 		wsgi_req->post_pos = ftell(wsgi_req->post_file);
86 		return;
87 	}
88 
89 	if (uwsgi.post_buffering) {
90 		if (pos < 0) {
91 			if ((off_t) wsgi_req->post_pos - pos < 0) {
92 				wsgi_req->post_pos = 0;
93 				return;
94 			}
95 			wsgi_req->post_pos -= pos;
96 			return;
97 		}
98 		if (pos >= (off_t) uwsgi.post_buffering) {
99 			pos = uwsgi.post_buffering - 1;
100 		}
101 		wsgi_req->post_pos = pos;
102 	}
103 }
104 
105 /*
106 
107 	read() and readline() language-independent implementations.
108 
109 */
110 
111 #define uwsgi_read_error0(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: Client closed connection\n",\
112                         (unsigned long long) x,\
113                         (unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
114 
115 #define uwsgi_read_error(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: %s\n",\
116 			(unsigned long long) x,\
117 			(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos,\
118 			strerror(errno));
119 
120 #define uwsgi_read_timeout(x) uwsgi_log("[uwsgi-body-read] Timeout reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu\n",\
121                         (unsigned long long) x,\
122                         (unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
123 
consume_body_for_readline(struct wsgi_request * wsgi_req)124 static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
125 
126 	size_t remains = UMIN(uwsgi.buffer_size, wsgi_req->post_cl - wsgi_req->post_pos);
127 
128 	int ret;
129 
130 	// allocate more memory if needed
131 	if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) {
132 		memmove(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
133 		wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos;
134 		wsgi_req->post_readline_pos = 0;
135 		// still something to use ?
136 		if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark < remains) {
137         		char *tmp_buf = realloc(wsgi_req->post_readline_buf, wsgi_req->post_readline_size + remains);
138                 	if (!tmp_buf) {
139                 		uwsgi_req_error("consume_body_for_readline()/realloc()");
140                         	return -1;
141                 	}
142                 	wsgi_req->post_readline_buf = tmp_buf;
143                 	wsgi_req->post_readline_size += remains;
144 			// INFORM THE USER HIS readline() USAGE IS FOOLISH
145 			if (!wsgi_req->post_warning && wsgi_req->post_readline_size > (uwsgi.body_read_warning * 1024*1024)) {
146 				uwsgi_log("[uwsgi-warning] you are using readline() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_readline_size/(1024*1024)));
147 				wsgi_req->post_warning = 1;
148 			}
149 		}
150         }
151 
152 	remains = UMIN(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, wsgi_req->post_cl - wsgi_req->post_pos);
153 
154 	// read from a file
155 	if (wsgi_req->post_file) {
156 		size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, remains, 1, wsgi_req->post_file);
157 		if (ret == 0) {
158 			uwsgi_req_error("consume_body_for_readline()/fread()");
159 			return -1;
160 		}
161 		wsgi_req->post_pos += remains;
162 		wsgi_req->post_readline_watermark += remains;
163 		return 0;
164 	}
165 
166 
167 	// read from post_buffering memory
168 	if (uwsgi.post_buffering) {
169 		memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, remains);
170 		wsgi_req->post_pos += remains;
171 		wsgi_req->post_readline_watermark += remains;
172 		return 0;
173 	}
174 
175 	// read from socket
176 	ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
177 	if (len > 0) {
178 		wsgi_req->post_pos += len;
179 		wsgi_req->post_readline_watermark += len;
180 		return 0;
181 	}
182 	if (len == 0) {
183 		uwsgi_read_error(remains);
184 		wsgi_req->read_errors++;
185 		return -1;
186 	}
187 	if (len < 0) {
188 		if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
189 			goto wait;
190 		}
191 		uwsgi_read_error(remains);
192 		wsgi_req->read_errors++;
193 		return -1;
194 	}
195 wait:
196 	ret = uwsgi_wait_read_req(wsgi_req);
197         if (ret > 0) {
198         	len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
199                 if (len > 0) {
200 			wsgi_req->post_pos += len;
201 			wsgi_req->post_readline_watermark += len;
202 			return 0;
203 		}
204 		uwsgi_read_error(remains);
205 		wsgi_req->read_errors++;
206                 return -1;
207 	}
208         // 0 means timeout
209         else if (ret == 0) {
210 		uwsgi_read_timeout(remains);
211 		return -1;
212         }
213 	uwsgi_read_error(remains);
214 	wsgi_req->read_errors++;
215         return -1;
216 }
217 
218 // TODO take hint into account
219 // readline_buf is allocated when needed and freed at the end of the request
uwsgi_request_body_readline(struct wsgi_request * wsgi_req,ssize_t hint,ssize_t * rlen)220 char *uwsgi_request_body_readline(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
221 
222 	// return 0 if no post_cl or pos >= post_cl and no residual data
223         if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
224 		return uwsgi.empty;
225         }
226 
227 	// some residual data ?
228 	if (wsgi_req->post_readline_pos > 0) {
229 		size_t i;
230 		for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
231 			// found a newline
232 			if (wsgi_req->post_readline_buf[i] == '\n') {
233 				*rlen = (i+1)-wsgi_req->post_readline_pos;
234 				char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
235 				wsgi_req->post_readline_pos += *rlen;
236 				// all the readline buffer has been consumed
237 				if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
238 					wsgi_req->post_readline_pos = 0;
239 					wsgi_req->post_readline_watermark = 0;
240 				}
241 				return buf;
242 			}
243 		}
244 		// ok, no newline found, continue below
245 	}
246 
247 	// allocate memory on the first round
248 	if (!wsgi_req->post_readline_buf) {
249 		size_t amount = UMIN(uwsgi.buffer_size, wsgi_req->post_cl);
250 		wsgi_req->post_readline_buf = malloc(amount);
251 		if (!wsgi_req->post_readline_buf) {
252 			uwsgi_req_error("uwsgi_request_body_readline()/malloc()");
253 			wsgi_req->read_errors++;
254 			*rlen = -1;
255 			return NULL;
256 		}
257 		wsgi_req->post_readline_size = amount;
258 	}
259 
260 	// ok, no newline found, consume a bit more of memory and retry
261         for(;;) {
262 		// no more data to consume
263 		if (wsgi_req->post_pos >= wsgi_req->post_cl) break;
264 
265                         if (consume_body_for_readline(wsgi_req)) {
266 				wsgi_req->read_errors++;
267                                 *rlen = -1;
268                                 return NULL;
269                         }
270 			size_t i;
271                         for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
272                                 if (wsgi_req->post_readline_buf[i] == '\n') {
273                                         *rlen = (i+1)-wsgi_req->post_readline_pos;
274                                         char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
275                                         wsgi_req->post_readline_pos += *rlen;
276                                         if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
277                                                 wsgi_req->post_readline_pos = 0;
278 						wsgi_req->post_readline_watermark = 0;
279                                         }
280                                         return buf;
281                                 }
282                         }
283                 }
284 
285 	// no line found, let's return all
286         *rlen = wsgi_req->post_readline_size - wsgi_req->post_readline_pos;
287         char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
288 	wsgi_req->post_readline_pos = 0;
289 	return buf;
290 
291 }
292 
uwsgi_request_body_read(struct wsgi_request * wsgi_req,ssize_t hint,ssize_t * rlen)293 char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
294 
295 	int ret = -1;
296 	size_t remains = hint;
297 
298 	// return empty if no post_cl or pos >= post_cl and no residual data
299         if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
300 		return uwsgi.empty;
301         }
302 
303         // return the whole input
304         if (remains <= 0) {
305                 remains = wsgi_req->post_cl;
306         }
307 
308         // some residual data ?
309         if (wsgi_req->post_readline_pos > 0) {
310                        if (remains <= (wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos)) {
311 				*rlen = remains;
312 				char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
313 				wsgi_req->post_readline_pos += remains;
314 				return buf;
315                         }
316 			// the hint is higher than residual data, let's copy it to read() memory and go on
317 			size_t avail = wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos;
318 			// check if we have enough memory...
319 			if (avail > wsgi_req->post_read_buf_size) {
320 				char *tmp_buf = realloc(wsgi_req->post_read_buf, avail);
321 				if (!tmp_buf) {
322                                 	uwsgi_req_error("uwsgi_request_body_read()/realloc()");
323                                 	*rlen = -1;
324 					wsgi_req->read_errors++;
325                                 	return NULL;
326                         	}
327                         	wsgi_req->post_read_buf = tmp_buf;
328                         	wsgi_req->post_read_buf_size = avail;
329                         	if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
330                                 	uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
331                                 	wsgi_req->post_warning = 1;
332                         	}
333 			}
334 			// fix remains...
335 			if (remains > 0) {
336 				remains -= avail;
337 			}
338 			*rlen += avail;
339 			memcpy(wsgi_req->post_read_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, avail);
340                 	wsgi_req->post_readline_pos = 0;
341 			wsgi_req->post_readline_watermark = 0;
342         }
343 
344         if (remains + wsgi_req->post_pos > wsgi_req->post_cl) {
345                 remains = wsgi_req->post_cl - wsgi_req->post_pos;
346         }
347 
348 
349 
350         if (remains == 0) {
351 		if (*rlen > 0) {
352 			return wsgi_req->post_read_buf;
353 		}
354 		else {
355                 	return uwsgi.empty;
356 		}
357         }
358 
359 	// read from post buffering memory
360         if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) {
361 		*rlen += remains;
362                 char *buf = wsgi_req->post_buffering_buf+wsgi_req->post_pos;
363 		wsgi_req->post_pos += remains;
364 		return buf;
365         }
366 
367 	// ok we need to check if we need to allocate memory
368 	if (!wsgi_req->post_read_buf) {
369 		wsgi_req->post_read_buf = malloc(remains);
370 		if (!wsgi_req->post_read_buf) {
371 			uwsgi_req_error("uwsgi_request_body_read()/malloc()");
372 			wsgi_req->read_errors++;
373 			*rlen = -1;
374 			return NULL;
375 		}
376 		wsgi_req->post_read_buf_size = remains;
377 	}
378 	// need to realloc ?
379 	else {
380 		if ((remains+*rlen) > wsgi_req->post_read_buf_size) {
381 			char *tmp_buf = realloc(wsgi_req->post_read_buf, (remains+*rlen));
382 			if (!tmp_buf) {
383 				uwsgi_req_error("uwsgi_request_body_read()/realloc()");
384 				wsgi_req->read_errors++;
385 				*rlen = -1;
386 				return NULL;
387 			}
388 			wsgi_req->post_read_buf = tmp_buf;
389 			wsgi_req->post_read_buf_size = (remains+*rlen);
390 			if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
391                                 uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
392                                 wsgi_req->post_warning = 1;
393                         }
394 		}
395 	}
396 
397 	// check for disk buffered body first (they are all read in one shot)
398 	if (wsgi_req->post_file) {
399 		if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) {
400 			*rlen = -1;
401 			uwsgi_req_error("uwsgi_request_body_read()/fread()");
402 			wsgi_req->read_errors++;
403 			return NULL;
404 		}
405 		*rlen += remains;
406 		wsgi_req->post_pos+= remains;
407 		return wsgi_req->post_read_buf;
408 	}
409 
410 	// ok read all the required bytes...
411 	while(remains > 0) {
412 		// here we first try to read (as data could be already available)
413 		ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen , remains);
414 		if (len > 0) {
415 			wsgi_req->post_pos+=len;
416 			remains -= len;
417 			*rlen += len;
418 			continue;
419 		}
420 		// client closed connection...
421 		if (len == 0) {
422 			*rlen = -1;
423 			uwsgi_read_error0(remains);
424 			return NULL;
425 		}
426 		if (len < 0) {
427 			if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
428 				goto wait;
429 			}
430 			*rlen = -1;
431 			uwsgi_read_error(remains);
432 			wsgi_req->read_errors++;
433 			return NULL;
434 		}
435 wait:
436 		ret = uwsgi_wait_read_req(wsgi_req);
437         	if (ret > 0) {
438 			len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen, remains);
439 			if (len > 0) {
440 				wsgi_req->post_pos+=len;
441 				remains -= len;
442                         	*rlen += len;
443                         	continue;
444 			}else if (len < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS)) {
445 				goto wait;
446 			}
447 			*rlen = -1;
448 			if (len == 0) {
449 				uwsgi_read_error0(remains);
450 			}
451 			else {
452 				uwsgi_read_error(remains);
453 				wsgi_req->read_errors++;
454 			}
455 			return NULL;
456 		}
457 		// 0 means timeout
458 		else if (ret == 0) {
459 			*rlen = 0;
460 			uwsgi_read_timeout(remains);
461 			return NULL;
462 		}
463 		*rlen = -1;
464 		uwsgi_read_error(remains);
465 		wsgi_req->read_errors++;
466 		return NULL;
467 	}
468 
469 	return wsgi_req->post_read_buf;
470 }
471 
472 /*
473 
474 	post buffering
475 
476 */
477 
uwsgi_postbuffer_do_in_mem(struct wsgi_request * wsgi_req)478 int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
479 
480         size_t remains = wsgi_req->post_cl;
481         int ret;
482         char *ptr = wsgi_req->post_buffering_buf;
483 
484         while (remains > 0) {
485                 if (uwsgi.harakiri_options.workers > 0) {
486                         inc_harakiri(uwsgi.harakiri_options.workers);
487                 }
488 
489                 ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
490                 if (rlen > 0) {
491 			remains -= rlen;
492 			ptr += rlen;
493 			continue;
494 		}
495                 if (rlen == 0) {
496 			uwsgi_read_error0(remains);
497 			return -1;
498 		}
499                 if (rlen < 0) {
500                         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
501                                 goto wait;
502                         }
503 			uwsgi_read_error(remains);
504 			wsgi_req->read_errors++;
505                         return -1;
506                 }
507 
508 wait:
509                 ret = uwsgi_wait_read_req(wsgi_req);
510                 if (ret > 0) {
511 			rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
512 			if (rlen > 0) {
513 				remains -= rlen;
514 				ptr += rlen;
515 				continue;
516 			}
517 		}
518                 if (ret < 0) {
519 			uwsgi_read_error(remains);
520 			wsgi_req->read_errors++;
521                         return -1;
522                 }
523 		uwsgi_read_timeout(remains);
524                 return -1;
525 	}
526 
527         return 0;
528 
529 }
530 
531 
uwsgi_postbuffer_do_in_disk(struct wsgi_request * wsgi_req)532 int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
533 
534         size_t post_remains = wsgi_req->post_cl;
535         int ret;
536         int upload_progress_fd = -1;
537         char *upload_progress_filename = NULL;
538 
539         wsgi_req->post_file = uwsgi_tmpfile();
540         if (!wsgi_req->post_file) {
541                 uwsgi_req_error("uwsgi_postbuffer_do_in_disk()/uwsgi_tmpfile()");
542 		wsgi_req->read_errors++;
543                 return -1;
544         }
545 
546         if (uwsgi.upload_progress) {
547                 // first check for X-Progress-ID size
548                 // separator + 'X-Progress-ID' + '=' + uuid
549                 upload_progress_filename = uwsgi_upload_progress_create(wsgi_req, &upload_progress_fd);
550                 if (!upload_progress_filename) {
551                         uwsgi_log("invalid X-Progress-ID value: must be a UUID\n");
552                 }
553         }
554 
555         // manage buffered data and upload progress
556         while (post_remains > 0) {
557 
558                 // during post buffering we need to constantly reset the harakiri
559                 if (uwsgi.harakiri_options.workers > 0) {
560                         inc_harakiri(uwsgi.harakiri_options.workers);
561                 }
562 
563                 // we use the already available post buffering buffer to read chunks....
564                 size_t remains = UMIN(post_remains, uwsgi.post_buffering);
565 
566                 // first try to read data (there could be something already available
567                 ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
568                 if (rlen > 0) goto write;
569                 if (rlen == 0) {
570 			uwsgi_read_error0(remains);
571 			goto end;
572 		}
573                 if (rlen < 0) {
574                         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
575                                 goto wait;
576                         }
577 			uwsgi_read_error(remains);
578 			wsgi_req->read_errors++;
579                         goto end;
580                 }
581 
582 wait:
583                 ret = uwsgi_wait_read_req(wsgi_req);
584                 if (ret > 0) {
585 			rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
586 			if (rlen > 0) goto write;
587 			if (rlen == 0) {
588 				uwsgi_read_error0(remains);
589 			}
590 			else {
591 				uwsgi_read_error(remains);
592 				wsgi_req->read_errors++;
593 			}
594                         goto end;
595 		}
596                 if (ret < 0) {
597 			uwsgi_read_error(remains);
598 			wsgi_req->read_errors++;
599                         goto end;
600                 }
601 		uwsgi_read_timeout(remains);
602                 goto end;
603 
604 write:
605                 if (fwrite(wsgi_req->post_buffering_buf, rlen, 1, wsgi_req->post_file) != 1) {
606                         uwsgi_req_error("uwsgi_postbuffer_do_in_disk()/fwrite()");
607 			wsgi_req->read_errors++;
608                         goto end;
609                 }
610 
611                 post_remains -= rlen;
612 
613 		if (upload_progress_filename) {
614                         // stop updating it on errors
615                         if (uwsgi_upload_progress_update(wsgi_req, upload_progress_fd, post_remains)) {
616                                 uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
617                                 upload_progress_filename = NULL;
618                         }
619                 }
620         }
621         rewind(wsgi_req->post_file);
622 
623         if (upload_progress_filename) {
624                 uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
625         }
626 
627         return 0;
628 
629 end:
630         if (upload_progress_filename) {
631                 uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
632         }
633         return -1;
634 }
635 
636