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; }
int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct stat st; int ret = UWSGI_ROUTE_BREAK; struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; int fd = open(ub->buf, O_RDONLY); if (fd < 0) { if (ur->custom) ret = UWSGI_ROUTE_NEXT; goto end; } if (fstat(fd, &st)) { goto end2; } struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len); if (!ub_s) goto end2; // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; if (urfc->no_headers) { uwsgi_buffer_destroy(ub_s); goto send; } if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) { uwsgi_buffer_destroy(ub_s); goto end2; } uwsgi_buffer_destroy(ub_s); if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2; if (urfc->mime) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2; } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } send: if (!wsgi_req->headers_sent) { if (uwsgi_response_write_headers_do(wsgi_req)) goto end2; } if (wsgi_req->socket->can_offload) { if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, st.st_size)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += st.st_size; // the fd will be closed by the offload engine goto end; } } if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) { wsgi_req->via = UWSGI_VIA_SENDFILE; wsgi_req->response_size += st.st_size; } end2: close(fd); end: uwsgi_buffer_destroy(ub); return ret; }