1 #include "uwsgi.h"
2
3 extern struct uwsgi_server uwsgi;
4
uwsgi_response_add_content_length(struct wsgi_request * wsgi_req,uint64_t cl)5 int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
6 char buf[sizeof(UMAX64_STR)+1];
7 int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
8 if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
9 wsgi_req->write_errors++;
10 return -1;
11 }
12 return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
13 }
14
uwsgi_response_add_expires(struct wsgi_request * wsgi_req,uint64_t t)15 int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) {
16 // 30+1
17 char expires[31];
18 int len = uwsgi_http_date((time_t) t, expires);
19 if (!len) {
20 wsgi_req->write_errors++;
21 return -1;
22 }
23 return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len);
24 }
25
uwsgi_response_add_date(struct wsgi_request * wsgi_req,char * hkey,uint16_t hlen,uint64_t t)26 int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) {
27 // 30+1
28 char d[31];
29 int len = uwsgi_http_date((time_t) t, d);
30 if (!len) {
31 wsgi_req->write_errors++;
32 return -1;
33 }
34 return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len);
35 }
36
uwsgi_response_add_last_modified(struct wsgi_request * wsgi_req,uint64_t t)37 int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) {
38 // 30+1
39 char lm[31];
40 int len = uwsgi_http_date((time_t) t, lm);
41 if (!len) {
42 wsgi_req->write_errors++;
43 return -1;
44 }
45 return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len);
46 }
47
uwsgi_response_add_content_range(struct wsgi_request * wsgi_req,int64_t start,int64_t end,int64_t cl)48 int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, int64_t start, int64_t end, int64_t cl) {
49 char buf[6+(sizeof(UMAX64_STR)*3)+4];
50 int ret = -1;
51 if (start == -1 && end == -1 && cl >= 0) {
52 ret = snprintf(buf, sizeof(buf), "bytes */%lld", (long long) cl);
53 }
54 else if (start < 0 || end < start || end >= cl) {
55 uwsgi_log("uwsgi_response_add_content_range is called with wrong arguments:"
56 "start=%lld end=%lld content-length=%lld\n",
57 start, end, cl);
58 wsgi_req->write_errors++;
59 return -1;
60 }
61 else {
62 ret = snprintf(buf, sizeof(buf), "bytes %lld-%lld/%lld", (long long) start, (long long) end, (long long) cl);
63 }
64 if (ret <= 0 || ret >= (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
65 wsgi_req->write_errors++;
66 return -1;
67 }
68 return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret);
69 }
70
uwsgi_response_prepare_headers_int(struct wsgi_request * wsgi_req,int status)71 int uwsgi_response_prepare_headers_int(struct wsgi_request *wsgi_req, int status) {
72 char status_str[11];
73 uwsgi_num2str2(status, status_str);
74 return uwsgi_response_prepare_headers(wsgi_req, status_str, 3);
75 }
76
77 // status could be NNN or NNN message
uwsgi_response_prepare_headers(struct wsgi_request * wsgi_req,char * status,uint16_t status_len)78 int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
79
80 if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1;
81
82 if (!wsgi_req->headers) {
83 wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
84 wsgi_req->headers->limit = uwsgi.response_header_limit;
85 }
86
87 // reset the buffer (could be useful for rollbacks...)
88 wsgi_req->headers->pos = 0;
89 // reset headers count
90 wsgi_req->header_cnt = 0;
91 struct uwsgi_buffer *hh = NULL;
92 wsgi_req->status = uwsgi_str3_num(status);
93 #ifdef UWSGI_ROUTING
94 // apply error routes
95 if (wsgi_req->is_error_routing == 0) {
96 if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
97 // from now on ignore write body requests...
98 wsgi_req->ignore_body = 1;
99 return -1;
100 }
101 wsgi_req->is_error_routing = 0;
102 }
103 #endif
104 if (status_len <= 4) {
105 char *new_sc = NULL;
106 size_t new_sc_len = 0;
107 uint16_t sc_len = 0;
108 const char *sc = uwsgi_http_status_msg(status, &sc_len);
109 if (sc) {
110 new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len);
111 new_sc_len = 4+sc_len;
112 }
113 else {
114 new_sc = uwsgi_concat2n(status, 3, " Unknown", 8);
115 new_sc_len = 11;
116 }
117 hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len);
118 free(new_sc);
119 }
120 else {
121 hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len);
122 }
123 if (!hh) {wsgi_req->write_errors++; return -1;}
124 if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
125 uwsgi_buffer_destroy(hh);
126 return 0;
127 error:
128 uwsgi_buffer_destroy(hh);
129 wsgi_req->write_errors++;
130 return -1;
131 }
132
133 //each protocol has its header generator
uwsgi_response_add_header_do(struct wsgi_request * wsgi_req,char * key,uint16_t key_len,char * value,uint16_t value_len)134 static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
135
136
137 // pull/collect the header ?
138 struct uwsgi_string_list *usl = NULL;
139
140 uwsgi_foreach(usl, uwsgi.pull_headers) {
141 if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
142 if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
143 wsgi_req->write_errors++ ; return -1;
144 }
145 return 0;
146 }
147 }
148
149 uwsgi_foreach(usl, uwsgi.collect_headers) {
150 if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
151 if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
152 wsgi_req->write_errors++ ; return -1;
153 }
154 }
155 }
156
157 if (!wsgi_req->headers) {
158 wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
159 wsgi_req->headers->limit = uwsgi.response_header_limit;
160 }
161
162 struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
163 if (!hh) { wsgi_req->write_errors++ ; return -1;}
164 if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
165 wsgi_req->header_cnt++;
166 uwsgi_buffer_destroy(hh);
167 return 0;
168 error:
169 uwsgi_buffer_destroy(hh);
170 wsgi_req->write_errors++;
171 return -1;
172 }
173
uwsgi_response_add_header(struct wsgi_request * wsgi_req,char * key,uint16_t key_len,char * value,uint16_t value_len)174 int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
175
176 if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
177
178 struct uwsgi_string_list *rh = uwsgi.remove_headers;
179 while(rh) {
180 if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
181 return 0;
182 }
183 rh = rh->next;
184 }
185 rh = wsgi_req->remove_headers;
186 while(rh) {
187 if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
188 return 0;
189 }
190 rh = rh->next;
191 }
192
193 return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
194 }
195
uwsgi_response_add_header_force(struct wsgi_request * wsgi_req,char * key,uint16_t key_len,char * value,uint16_t value_len)196 int uwsgi_response_add_header_force(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
197
198 if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
199
200 return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
201 }
202
uwsgi_response_write_headers_do0(struct wsgi_request * wsgi_req)203 static int uwsgi_response_write_headers_do0(struct wsgi_request *wsgi_req) {
204 if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) {
205 return UWSGI_OK;
206 }
207
208 #ifdef UWSGI_ROUTING
209 // apply response routes
210 if (wsgi_req->is_response_routing == 0) {
211 if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
212 // from now on ignore write body requests...
213 wsgi_req->ignore_body = 1;
214 return -1;
215 }
216 wsgi_req->is_response_routing = 0;
217 }
218 #endif
219
220 struct uwsgi_string_list *ah = uwsgi.additional_headers;
221 while(ah) {
222 if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
223 ah = ah->next;
224 }
225
226 ah = wsgi_req->additional_headers;
227 while(ah) {
228 if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
229 ah = ah->next;
230 }
231
232
233 if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;}
234
235 return UWSGI_AGAIN;
236 }
237
uwsgi_response_write_headers_do(struct wsgi_request * wsgi_req)238 int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
239
240 int ret = uwsgi_response_write_headers_do0(wsgi_req);
241 if (ret != UWSGI_AGAIN) return ret;
242
243 for(;;) {
244 errno = 0;
245 int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos);
246 if (ret < 0) {
247 if (!uwsgi.ignore_write_errors) {
248 uwsgi_req_error("uwsgi_response_write_headers_do()");
249 }
250 wsgi_req->write_errors++;
251 return -1;
252 }
253 if (ret == UWSGI_OK) {
254 break;
255 }
256 if (!uwsgi_is_again()) continue;
257 ret = uwsgi_wait_write_req(wsgi_req);
258 if (ret < 0) { wsgi_req->write_errors++; return -1;}
259 if (ret == 0) {
260 uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n");
261 wsgi_req->write_errors++;
262 return -1;
263 }
264 }
265
266 wsgi_req->headers_size += wsgi_req->write_pos;
267 // reset for the next write
268 wsgi_req->write_pos = 0;
269 wsgi_req->headers_sent = 1;
270
271 return UWSGI_OK;
272 }
273
274 /*
275 private function for highly optimized writes (1 single syscall for headers and body)
276 */
uwsgi_response_writev_headers_and_body_do(struct wsgi_request * wsgi_req,char * buf,size_t len)277 static int uwsgi_response_writev_headers_and_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
278
279 struct iovec iov[2];
280
281 int ret = uwsgi_response_write_headers_do0(wsgi_req);
282 if (ret != UWSGI_AGAIN) return ret;
283
284 iov[0].iov_base = wsgi_req->headers->buf;
285 iov[0].iov_len = wsgi_req->headers->pos;
286 iov[1].iov_base = buf;
287 iov[1].iov_len = len;
288
289 size_t iov_len = 2;
290 for(;;) {
291 errno = 0;
292 // no need to use writev if a single iovec remains
293 if (iov_len == 1) {
294 buf = iov[0].iov_base;
295 len = iov[0].iov_len;
296 // update counters
297 wsgi_req->headers_size += wsgi_req->headers->pos;
298 wsgi_req->headers_sent = 1;
299 wsgi_req->response_size += wsgi_req->write_pos - wsgi_req->headers_size;
300 wsgi_req->write_pos = 0;
301 goto fallback;
302 }
303 int ret = wsgi_req->socket->proto_writev(wsgi_req, iov, &iov_len);
304 if (ret < 0) {
305 if (!uwsgi.ignore_write_errors) {
306 uwsgi_req_error("uwsgi_response_writev_headers_and_body_do()");
307 }
308 wsgi_req->write_errors++;
309 return -1;
310 }
311 if (ret == UWSGI_OK) {
312 break;
313 }
314 if (!uwsgi_is_again()) continue;
315 ret = uwsgi_wait_write_req(wsgi_req);
316 if (ret < 0) { wsgi_req->write_errors++; return -1;}
317 if (ret == 0) {
318 uwsgi_log("uwsgi_response_writev_headers_and_body_do() TIMEOUT !!!\n");
319 wsgi_req->write_errors++;
320 return -1;
321 }
322 }
323
324 wsgi_req->headers_size += wsgi_req->headers->pos;
325 wsgi_req->response_size += len;
326 wsgi_req->headers_sent = 1;
327
328 // reset for the next write
329 wsgi_req->write_pos = 0;
330
331 return UWSGI_OK;
332
333 fallback:
334
335 for(;;) {
336 errno = 0;
337 int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
338 if (ret < 0) {
339 if (!uwsgi.ignore_write_errors) {
340 // here we use the parent name
341 uwsgi_req_error("uwsgi_response_write_body_do()");
342 }
343 wsgi_req->write_errors++;
344 return -1;
345 }
346 if (ret == UWSGI_OK) {
347 break;
348 }
349 if (!uwsgi_is_again()) continue;
350 ret = uwsgi_wait_write_req(wsgi_req);
351 if (ret < 0) { wsgi_req->write_errors++; return -1;}
352 if (ret == 0) {
353 // here we use the parent name
354 uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
355 wsgi_req->write_errors++;
356 return -1;
357 }
358 }
359
360 wsgi_req->response_size += wsgi_req->write_pos;
361 // reset for the next write
362 wsgi_req->write_pos = 0;
363
364 return UWSGI_OK;
365
366 }
367
368 // this is the function called by all request plugins to send chunks to the client
uwsgi_response_write_body_do(struct wsgi_request * wsgi_req,char * buf,size_t len)369 int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
370
371 if (wsgi_req->write_errors) return -1;
372 if (wsgi_req->ignore_body) return UWSGI_OK;
373
374 #ifdef UWSGI_ROUTING
375 // special case here, we could need to set transformations before
376 if (!wsgi_req->headers_sent) {
377 // apply response routes
378 if (wsgi_req->is_response_routing == 0) {
379 if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
380 // from now on ignore write body requests...
381 wsgi_req->ignore_body = 1;
382 return -1;
383 }
384 wsgi_req->is_response_routing = 0;
385 }
386 }
387 #endif
388
389 // if the transformation chain returns 1, we are in buffering mode
390 if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
391 int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
392 if (t_ret == 0) {
393 buf = wsgi_req->transformed_chunk;
394 len = wsgi_req->transformed_chunk_len;
395 // reset transformation
396 wsgi_req->transformed_chunk = NULL;
397 wsgi_req->transformed_chunk_len = 0;
398 goto write;
399 }
400 if (t_ret == 1) {
401 return UWSGI_OK;
402 }
403 wsgi_req->write_errors++;
404 return -1;
405 }
406
407 write:
408 // send headers if not already sent
409 if (!wsgi_req->headers_sent) {
410 if (wsgi_req->socket->proto_writev && len > 0 && wsgi_req->headers) {
411 return uwsgi_response_writev_headers_and_body_do(wsgi_req, buf, len);
412 }
413 int ret = uwsgi_response_write_headers_do(wsgi_req);
414 if (ret == UWSGI_OK) goto sendbody;
415 if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
416 wsgi_req->write_errors++;
417 return -1;
418 }
419
420 sendbody:
421
422 if (len == 0) return UWSGI_OK;
423
424 for(;;) {
425 errno = 0;
426 int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
427 if (ret < 0) {
428 if (!uwsgi.ignore_write_errors) {
429 uwsgi_req_error("uwsgi_response_write_body_do()");
430 }
431 wsgi_req->write_errors++;
432 return -1;
433 }
434 if (ret == UWSGI_OK) {
435 break;
436 }
437 if (!uwsgi_is_again()) continue;
438 ret = uwsgi_wait_write_req(wsgi_req);
439 if (ret < 0) { wsgi_req->write_errors++; return -1;}
440 if (ret == 0) {
441 uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
442 wsgi_req->write_errors++;
443 return -1;
444 }
445 }
446
447 wsgi_req->response_size += wsgi_req->write_pos;
448 // reset for the next write
449 wsgi_req->write_pos = 0;
450
451 return UWSGI_OK;
452 }
453
uwsgi_response_writev_body_do(struct wsgi_request * wsgi_req,struct iovec * iov,size_t len)454 int uwsgi_response_writev_body_do(struct wsgi_request *wsgi_req, struct iovec *iov, size_t len) {
455
456 if (wsgi_req->write_errors) return -1;
457 if (wsgi_req->ignore_body) return UWSGI_OK;
458
459 #ifdef UWSGI_ROUTING
460 // special case here, we could need to set transformations before
461 if (!wsgi_req->headers_sent) {
462 // apply response routes
463 if (wsgi_req->is_response_routing == 0) {
464 if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
465 // from now on ignore write body requests...
466 wsgi_req->ignore_body = 1;
467 return -1;
468 }
469 wsgi_req->is_response_routing = 0;
470 }
471 }
472 #endif
473
474 size_t i;
475 int buffering = 0;
476 // transformations apply to every vector
477 for(i=0;i<len;i++) {
478 // if the transformation chain returns 1, we are in buffering mode
479 if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
480 int t_ret = uwsgi_apply_transformations(wsgi_req, iov[i].iov_base, iov[i].iov_len);
481 if (t_ret == 0) {
482 iov[i].iov_base = wsgi_req->transformed_chunk;
483 iov[i].iov_len = wsgi_req->transformed_chunk_len;
484 // reset transformation
485 wsgi_req->transformed_chunk = NULL;
486 wsgi_req->transformed_chunk_len = 0;
487 goto write;
488 }
489 if (t_ret == 1) {
490 buffering = 1;
491 continue;
492 }
493 wsgi_req->write_errors++;
494 return -1;
495 }
496 }
497
498 if (buffering) return UWSGI_OK;
499
500 write:
501 // send headers if not already sent
502 if (!wsgi_req->headers_sent) {
503 int ret = uwsgi_response_write_headers_do(wsgi_req);
504 if (ret == UWSGI_OK) goto sendbody;
505 if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
506 wsgi_req->write_errors++;
507 return -1;
508 }
509
510 sendbody:
511
512 if (len == 0) return UWSGI_OK;
513 // unfortunately vector based I/O cannot be accomplished on all protocols
514 if (!wsgi_req->socket->proto_writev) goto fallback;
515
516 // we use a copy to avoid mess
517 size_t iov_len = len;
518 for(;;) {
519 errno = 0;
520 int ret = wsgi_req->socket->proto_writev(wsgi_req, iov, &iov_len);
521 if (ret < 0) {
522 if (!uwsgi.ignore_write_errors) {
523 uwsgi_req_error("uwsgi_response_writev_body_do()");
524 }
525 wsgi_req->write_errors++;
526 return -1;
527 }
528 if (ret == UWSGI_OK) {
529 break;
530 }
531 if (!uwsgi_is_again()) continue;
532 ret = uwsgi_wait_write_req(wsgi_req);
533 if (ret < 0) { wsgi_req->write_errors++; return -1;}
534 if (ret == 0) {
535 uwsgi_log("uwsgi_response_writev_body_do() TIMEOUT !!!\n");
536 wsgi_req->write_errors++;
537 return -1;
538 }
539 }
540
541 goto done;
542
543 fallback:
544
545 for(i=0;i<len;i++) {
546 for(;;) {
547 errno = 0;
548 int ret = wsgi_req->socket->proto_write(wsgi_req, iov[i].iov_base, iov[i].iov_len);
549 if (ret < 0) {
550 if (!uwsgi.ignore_write_errors) {
551 uwsgi_req_error("uwsgi_response_writev_body_do()");
552 }
553 wsgi_req->write_errors++;
554 return -1;
555 }
556 if (ret == UWSGI_OK) {
557 break;
558 }
559 if (!uwsgi_is_again()) continue;
560 ret = uwsgi_wait_write_req(wsgi_req);
561 if (ret < 0) { wsgi_req->write_errors++; return -1;}
562 if (ret == 0) {
563 uwsgi_log("uwsgi_response_writev_body_do() TIMEOUT !!!\n");
564 wsgi_req->write_errors++;
565 return -1;
566 }
567 }
568 }
569
570 done:
571
572 wsgi_req->response_size += wsgi_req->write_pos;
573 // reset for the next write
574 wsgi_req->write_pos = 0;
575
576 return UWSGI_OK;
577 }
578
579
uwsgi_response_sendfile_do(struct wsgi_request * wsgi_req,int fd,size_t pos,size_t len)580 int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
581 return uwsgi_response_sendfile_do_can_close(wsgi_req, fd, pos, len, 1);
582 }
583
uwsgi_response_sendfile_do_can_close(struct wsgi_request * wsgi_req,int fd,size_t pos,size_t len,int can_close)584 int uwsgi_response_sendfile_do_can_close(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len, int can_close) {
585
586 if (fd == wsgi_req->sendfile_fd) can_close = 0;
587
588 if (wsgi_req->write_errors) {
589 if (can_close) close(fd);
590 return -1;
591 }
592
593 if (wsgi_req->ignore_body) {
594 if (can_close) close(fd);
595 return UWSGI_OK;
596 }
597
598 if (!wsgi_req->headers_sent) {
599 int ret = uwsgi_response_write_headers_do(wsgi_req);
600 if (ret == UWSGI_OK) goto sendfile;
601 if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
602 wsgi_req->write_errors++;
603 if (can_close) close(fd);
604 return -1;
605 }
606
607 sendfile:
608
609 if (len == 0) {
610 struct stat st;
611 if (fstat(fd, &st)) {
612 uwsgi_req_error("uwsgi_response_sendfile_do()/fstat()");
613 wsgi_req->write_errors++;
614 if (can_close) close(fd);
615 return -1;
616 }
617 if (pos >= (size_t)st.st_size) {
618 if (can_close) close(fd);
619 return UWSGI_OK;
620 }
621 len = st.st_size;
622 }
623
624 if (wsgi_req->socket->can_offload) {
625 // of we cannot close the socket (before the app will close it later)
626 // let's dup it
627 if (!can_close) {
628 int tmp_fd = dup(fd);
629 if (tmp_fd < 0) {
630 uwsgi_req_error("uwsgi_response_sendfile_do()/dup()");
631 wsgi_req->write_errors++;
632 return -1;
633 }
634 fd = tmp_fd;
635 can_close = 1;
636 }
637 if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, pos, len)) {
638 wsgi_req->via = UWSGI_VIA_OFFLOAD;
639 wsgi_req->response_size += len;
640 return 0;
641 }
642 wsgi_req->write_errors++;
643 if (can_close) close(fd);
644 return -1;
645 }
646
647
648 wsgi_req->via = UWSGI_VIA_SENDFILE;
649
650 for(;;) {
651 errno = 0;
652 int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
653 if (ret < 0) {
654 if (!uwsgi.ignore_write_errors) {
655 uwsgi_req_error("uwsgi_response_sendfile_do()");
656 }
657 wsgi_req->write_errors++;
658 if (can_close) close(fd);
659 return -1;
660 }
661 if (ret == UWSGI_OK) {
662 break;
663 }
664 if (!uwsgi_is_again()) continue;
665 ret = uwsgi_wait_write_req(wsgi_req);
666 if (ret < 0) {
667 wsgi_req->write_errors++;
668 if (can_close) close(fd);
669 return -1;
670 }
671 if (ret == 0) {
672 uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
673 wsgi_req->write_errors++;
674 if (can_close) close(fd);
675 return -1;
676 }
677 }
678
679 wsgi_req->response_size += wsgi_req->write_pos;
680 // reset for the next write
681 wsgi_req->write_pos = 0;
682 // close the file descriptor
683 if (can_close) close(fd);
684 return UWSGI_OK;
685 }
686
687
uwsgi_simple_wait_write_hook(int fd,int timeout)688 int uwsgi_simple_wait_write_hook(int fd, int timeout) {
689 struct pollfd upoll;
690 timeout = timeout * 1000;
691
692 upoll.fd = fd;
693 upoll.events = POLLOUT;
694 upoll.revents = 0;
695 int ret = poll(&upoll, 1, timeout);
696
697 if (ret > 0) {
698 if (upoll.revents & POLLOUT) {
699 return 1;
700 }
701 return -1;
702 }
703 if (ret < 0) {
704 uwsgi_error("uwsgi_simple_wait_write_hook()/poll()");
705 }
706
707 return ret;
708 }
709
710 /*
711 simplified write to client
712 (generally used as fallback)
713 */
uwsgi_simple_write(struct wsgi_request * wsgi_req,char * buf,size_t len)714 int uwsgi_simple_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
715
716 wsgi_req->write_pos = 0;
717
718 for(;;) {
719 errno = 0;
720 int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
721 if (ret < 0) {
722 if (!uwsgi.ignore_write_errors) {
723 uwsgi_req_error("uwsgi_simple_write()");
724 }
725 wsgi_req->write_errors++;
726 return -1;
727 }
728 if (ret == UWSGI_OK) {
729 break;
730 }
731 if (!uwsgi_is_again()) continue;
732 ret = uwsgi_wait_write_req(wsgi_req);
733 if (ret < 0) { wsgi_req->write_errors++; return -1;}
734 if (ret == 0) {
735 uwsgi_log("uwsgi_simple_write() TIMEOUT !!!\n");
736 wsgi_req->write_errors++;
737 return -1;
738 }
739 }
740 return 0;
741 }
742
743