/* simplified write to client (generally used as fallback) */ int uwsgi_simple_write(struct wsgi_request *wsgi_req, char *buf, size_t len) { wsgi_req->write_pos = 0; for(;;) { int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_simple_write()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_simple_write() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } return 0; }
// this is the function called by all request plugins to send chunks to the client int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { if (wsgi_req->write_errors) return -1; if (!wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendbody; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; return -1; } sendbody: if (len == 0) return UWSGI_OK; for(;;) { int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_response_write_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; // now we need to check if the chunk must be stored if (wsgi_req->cache_it) { if (!wsgi_req->cached_response) { wsgi_req->cached_response = uwsgi_buffer_new(len); } // if we are unable to append the buffer, we just stop caching it if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) { uwsgi_buffer_destroy(wsgi_req->cache_it); wsgi_req->cache_it = NULL; } } return UWSGI_OK; }
// this is the function called by all request plugins to send chunks to the client int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { if (wsgi_req->write_errors) return -1; // do not commit headers until a response_buffer is available if (!wsgi_req->response_buffer && !wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendbody; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; return -1; } sendbody: if (len == 0) return UWSGI_OK; if (wsgi_req->response_buffer) { if (uwsgi_buffer_append(wsgi_req->response_buffer, buf, len)) { wsgi_req->write_errors++; return -1; } return UWSGI_OK; } for(;;) { int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_response_write_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; return UWSGI_OK; }
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) { if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) { return UWSGI_OK; } struct uwsgi_string_list *ah = uwsgi.additional_headers; while(ah) { if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1; ah = ah->next; } ah = wsgi_req->additional_headers; while(ah) { if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1; ah = ah->next; } if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;} for(;;) { int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_response_write_headers_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->headers_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; wsgi_req->headers_sent = 1; return UWSGI_OK; }
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { int can_close = 1; if (fd == wsgi_req->sendfile_fd) can_close = 0; if (wsgi_req->write_errors) return -1; if (!wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendfile; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; if (can_close) close(fd); return -1; } sendfile: if (len == 0) { struct stat st; if (fstat(fd, &st)) { uwsgi_error("fstat()"); wsgi_req->write_errors++; if (can_close) close(fd); return -1; } if (pos >= (size_t)st.st_size) return UWSGI_OK; len = st.st_size; } if (wsgi_req->socket->can_offload) { // of we cannot close the socket (before the app will close it later) // let's dup it if (!can_close) { int tmp_fd = dup(fd); if (tmp_fd < 0) { uwsgi_error("uwsgi_response_sendfile_do()/dup()"); wsgi_req->write_errors++; return -1; } fd = tmp_fd; can_close = 1; } if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, len)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += len; return 0; } wsgi_req->write_errors++; if (can_close) close(fd); return -1; } wsgi_req->via = UWSGI_VIA_SENDFILE; for(;;) { int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_response_sendfile_do()"); } wsgi_req->write_errors++; if (can_close) close(fd); return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; if (can_close) close(fd); return -1; } if (ret == 0) { uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; // close the file descriptor if (can_close) close(fd); return UWSGI_OK; }
// this is the function called by all request plugins to send chunks to the client int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { if (wsgi_req->write_errors) return -1; if (wsgi_req->ignore_body) return UWSGI_OK; // if the transformation chain returns 1, we are in buffering mode if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) { int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len); if (t_ret == 0) { buf = wsgi_req->transformed_chunk; len = wsgi_req->transformed_chunk_len; // reset transformation wsgi_req->transformed_chunk = NULL; wsgi_req->transformed_chunk_len = 0; goto write; } if (t_ret == 1) { return UWSGI_OK; } wsgi_req->write_errors++; return -1; } write: // send headers if not already sent if (!wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendbody; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; return -1; } sendbody: if (len == 0) return UWSGI_OK; for(;;) { int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_response_write_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; return UWSGI_OK; }