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