diff --git a/pyutils.c b/pyutils.c index 3201389d..656aaf70 100644 --- a/pyutils.c +++ b/pyutils.c @@ -4,6 +4,9 @@ int manage_python_response(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi PyObject *pychunk ; ssize_t wsize ; +#ifdef UWSGI_SENDFILE + ssize_t sf_len = 0 ; +#endif // return or yield ? if (PyString_Check(wsgi_req->async_result)) { @@ -16,6 +19,20 @@ int manage_python_response(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi goto clear; } + if (wsgi_req->sendfile_fd != -1) { + sf_len = uwsgi_sendfile(uwsgi, wsgi_req); + if (sf_len < 1) goto clear; + wsgi_req->response_size += sf_len ; +#ifdef UWSGI_ASYNC + if (uwsgi->async > 1) { + if (wsgi_req->response_size < wsgi_req->sendfile_fd_size) { + return UWSGI_AGAIN; + } + } +#endif + goto clear; + } + // ok its a yield if (!wsgi_req->async_placeholder) { wsgi_req->async_placeholder = PyObject_GetIter(wsgi_req->async_result); diff --git a/sendfile.c b/sendfile.c new file mode 100644 index 00000000..5562d481 --- /dev/null +++ b/sendfile.c @@ -0,0 +1,94 @@ +#ifdef UWSGI_SENDFILE + +#include "uwsgi.h" + +extern struct uwsgi_server uwsgi; + +PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) { + + if (!PyArg_ParseTuple(args, "Oi:uwsgi_sendfile", &uwsgi.wsgi_req->async_sendfile, &uwsgi.wsgi_req->sendfile_fd_chunk)) { + return NULL; + } + +#ifdef PYTHREE + uwsgi.wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(uwsgi.wsgi_req->async_sendfile); +#else + if (PyFile_Check(uwsgi.wsgi_req->async_sendfile)) { + uwsgi.wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(uwsgi.wsgi_req->async_sendfile); + } +#endif + + + return PyTuple_New(0); +} + +ssize_t uwsgi_sendfile(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { + + off_t rlen; + int fd = wsgi_req->sendfile_fd ; + int sockfd = wsgi_req->poll.fd ; + struct stat stat_buf; + + if (!wsgi_req->sendfile_fd_size) { + + if (fstat(fd, &stat_buf)) { + perror("fstat()"); + return 0; + } + else { + wsgi_req->sendfile_fd_size = stat_buf.st_size; + } + } + + if (wsgi_req->sendfile_fd_size) { + +#if defined(__FreeBSD__) || defined(__DragonFly__) + + if (sendfile(fd, sockfd, 0, 0, NULL, &wsgi_req->sendfile_fd_size, 0)) { + perror("sendfile()"); + } +#elif __APPLE__ + if (sendfile(fd, sockfd, 0, &rlen, NULL, 0)) { + perror("sendfile()"); + } +#elif defined(__linux__) || defined(__sun__) + if (uwsgi->async > 1) { + return sendfile(sockfd, fd, &wsgi_req->sendfile_fd_pos, wsgi_req->sendfile_fd_chunk); + } + else { + return sendfile(sockfd, fd, &wsgi_req->sendfile_fd_pos, wsgi_req->sendfile_fd_size); + } +#else + ssize_t i = 0; + char *no_sendfile_buf[4096]; + ssize_t jlen = 0; + rlen = 0; + i = 0; + while (i < rlen) { + jlen = read(fd, no_sendfile_buf, 4096); + if (jlen <= 0) { + perror("read()"); + break; + } + i += jlen; + jlen = write(sockfd, no_sendfile_buf, jlen); + if (jlen <= 0) { + perror("write()"); + break; + } + rlen += jlen; + } + + return rlen; +#endif + + } + + return 0; +} + + + + + +#endif diff --git a/tests/fileserve_async.py b/tests/fileserve_async.py new file mode 100644 index 00000000..e1939917 --- /dev/null +++ b/tests/fileserve_async.py @@ -0,0 +1,18 @@ +import sys +import mimetypes + +basedir = sys.argv[1] +mimetypes.init() + + +def application(environ, start_response): + + print environ['PATH_INFO'] + filename = basedir + environ['PATH_INFO'] + (content_type, encoding) = mimetypes.guess_type(filename) + if not content_type: + content_type = 'text/plain' + + start_response('200 OK', [('Content-Type', content_type)]) + fd = open(filename,'r') + yield environ['wsgi.file_wrapper'](fd, 32*1024) diff --git a/tests/staticfile.py b/tests/staticfile.py index ab1230c6..52834d95 100644 --- a/tests/staticfile.py +++ b/tests/staticfile.py @@ -1,5 +1,20 @@ +import sys + +content_type = 'image/png' +filename = 'logo_uWSGI.png' + +try: + filename = sys.argv[1] +except: + pass + +try: + content_type = sys.argv[2] +except: + pass + def application(environ, start_response): - start_response('200 OK', [('Content-Type', 'image/png')]) - fd = open('logo_uWSGI.png','r') - yield environ['wsgi.file_wrapper'](fd, 4096) + start_response('200 OK', [('Content-Type', content_type)]) + fd = open(filename,'r') + yield environ['wsgi.file_wrapper'](fd, 32*1024) diff --git a/uwsgi.c b/uwsgi.c index bceb0ba5..ae14ed05 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -44,6 +44,10 @@ static const char *app_slash = "/"; extern char **environ; +#ifdef UWSGI_SENDFILE +PyMethodDef uwsgi_sendfile_method[] = {{"uwsgi_sendfile", py_uwsgi_sendfile, METH_VARARGS, ""}}; +#endif + int find_worker_id(pid_t pid) { int i; for (i = 1; i <= uwsgi.numproc; i++) { @@ -438,38 +442,9 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) { return Py_None; } -#ifdef UWSGI_SENDFILE -PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) { - - //PyObject *zero ; - - uwsgi.py_sendfile = PyTuple_GetItem(args, 0); - -#ifdef PYTHREE - if ((uwsgi.wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(uwsgi.py_sendfile)) >= 0) { - Py_INCREF(uwsgi.py_sendfile); - } -#else - if (PyFile_Check(uwsgi.py_sendfile)) { - //zero = PyFile_Name(uwsgi.py_sendfile) ; - //fprintf(stderr,"->serving %s as static file...", PyString_AsString(zero)); - uwsgi.wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(uwsgi.py_sendfile); - Py_INCREF(uwsgi.py_sendfile); - } -#endif - - - return PyTuple_New(0); -} -#endif - PyMethodDef uwsgi_spit_method[] = { {"uwsgi_spit", py_uwsgi_spit, METH_VARARGS, ""} }; PyMethodDef uwsgi_write_method[] = { {"uwsgi_write", py_uwsgi_write, METH_VARARGS, ""} }; -#ifdef UWSGI_SENDFILE -PyMethodDef uwsgi_sendfile_method[] = { {"uwsgi_sendfile", py_uwsgi_sendfile, METH_VARARGS, ""}}; -#endif - #ifdef UWSGI_ASYNC PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_read, METH_VARARGS, ""}}; PyMethodDef uwsgi_eventfd_write_method[] = { {"uwsgi_eventfd_write", py_eventfd_write, METH_VARARGS, ""}}; @@ -1670,7 +1645,6 @@ int main(int argc, char *argv[], char *envp[]) { if (uwsgi.async > 1) { current_async_timeout = async_get_timeout(&uwsgi) ; - fprintf(stderr,"sleeping for %d secs\n", current_async_timeout); uwsgi.async_nevents = async_wait(uwsgi.async_queue, uwsgi.async_events, uwsgi.async, uwsgi.async_running, current_async_timeout); async_expire_timeouts(&uwsgi); diff --git a/uwsgi.h b/uwsgi.h index c903f41e..5687eb88 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -274,12 +274,15 @@ struct __attribute__ ((packed)) wsgi_request { #endif int sendfile_fd; + size_t sendfile_fd_chunk; + size_t sendfile_fd_size; + off_t sendfile_fd_pos; uint16_t var_cnt; uint16_t header_cnt; int status; - int response_size; + size_t response_size; int headers_size; int async_id; @@ -297,6 +300,7 @@ struct __attribute__ ((packed)) wsgi_request { void *async_placeholder; void *async_environ; void *async_post; + void *async_sendfile; // buffer MUST BE THE LAST VAR !!! char buffer; @@ -417,7 +421,6 @@ struct uwsgi_server { int single_interpreter; int py_optimize; - PyObject *py_sendfile; PyObject *embedded_dict; PyObject *embedded_args; PyObject *fastfuncslist; @@ -669,3 +672,8 @@ void async_expire_timeouts(struct uwsgi_server *); int manage_python_response(struct uwsgi_server *, struct wsgi_request *); int uwsgi_python_call(struct uwsgi_server *, struct wsgi_request *, PyObject *, PyObject *); PyObject *python_call(PyObject *, PyObject *); + +#ifdef UWSGI_SENDFILE +PyObject *py_uwsgi_sendfile(PyObject *, PyObject *) ; +ssize_t uwsgi_sendfile(struct uwsgi_server *, struct wsgi_request *); +#endif diff --git a/uwsgiconfig.py b/uwsgiconfig.py index 7c7e68c6..c3aa8533 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -142,6 +142,7 @@ def parse_vars(): if SENDFILE: cflags.append("-DUWSGI_SENDFILE") + gcc_list.append('sendfile') if XML: xmlconf = spcall('xml2-config --libs') diff --git a/wsgi_handlers.c b/wsgi_handlers.c index 4b9ecd4e..80e25301 100644 --- a/wsgi_handlers.c +++ b/wsgi_handlers.c @@ -1,7 +1,5 @@ #include "uwsgi.h" -static int uwsgi_sendfile(struct uwsgi_server *, int, int); - int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { int i; @@ -219,34 +217,14 @@ int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req if (wsgi_req->async_result) { - -#ifdef UWSGI_SENDFILE - if (wsgi_req->sendfile_fd > -1) { - wsgi_req->response_size = uwsgi_sendfile(uwsgi, wsgi_req->sendfile_fd, wsgi_req->poll.fd); - if (wsgi_req->async_environ) { - PyDict_Clear(wsgi_req->async_environ); - } - if (wsgi_req->async_post) { - fclose(wsgi_req->async_post); - } - Py_DECREF(wsgi_req->async_result); - } - else { - -#endif - - while ( manage_python_response(uwsgi, wsgi_req) != UWSGI_OK) { - //fprintf(stderr,"WSGI CYCLE\n"); + while ( manage_python_response(uwsgi, wsgi_req) != UWSGI_OK) { #ifdef UWSGI_ASYNC - if (uwsgi->async > 1) { - return UWSGI_AGAIN; - } -#endif + if (uwsgi->async > 1) { + return UWSGI_AGAIN; } - -#ifdef UWSGI_SENDFILE - } #endif + } + } @@ -268,66 +246,3 @@ void uwsgi_after_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *w if (uwsgi->shared->options[UWSGI_OPTION_LOGGING]) log_request(wsgi_req); } - -#ifdef UWSGI_SENDFILE -static int uwsgi_sendfile(struct uwsgi_server *uwsgi, int fd, int sockfd) { - - off_t rlen; - -#ifdef __sun__ - struct stat stat_buf; - if (fstat(fd, &stat_buf)) { - perror("fstat()"); - return 0; - } - else { - rlen = stat_buf.st_size; - } -#else - rlen = lseek(fd, 0, SEEK_END); -#endif - - if (rlen > 0) { - lseek(fd, 0, SEEK_SET); -#if !defined(__linux__) && !defined(__sun__) -#if defined(__FreeBSD__) || defined(__DragonFly__) - - if (sendfile(fd, sockfd, 0, 0, NULL, &rlen, 0)) { - perror("sendfile()"); - } -#elif __APPLE__ - if (sendfile(fd, sockfd, 0, &rlen, NULL, 0)) { - perror("sendfile()"); - } -#else - ssize_t i = 0; - char *no_sendfile_buf[4096]; - ssize_t jlen = 0; - rlen = 0; - i = 0; - while (i < rlen) { - jlen = read(fd, no_sendfile_buf, 4096); - if (jlen <= 0) { - perror("read()"); - break; - } - i += jlen; - jlen = write(sockfd, no_sendfile_buf, jlen); - if (jlen <= 0) { - perror("write()"); - break; - } - rlen += jlen; - } -#endif -#else - off_t sf_ot = 0; - rlen = sendfile(sockfd, fd, &sf_ot, rlen); -#endif - - } - Py_DECREF(uwsgi->py_sendfile); - - return rlen; -} -#endif