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