diff --git a/plugins/php/php_plugin.c b/plugins/php/php_plugin.c index f6748810..e9be772a 100644 --- a/plugins/php/php_plugin.c +++ b/plugins/php/php_plugin.c @@ -94,12 +94,11 @@ static int sapi_uwsgi_ub_write(const char *str, uint str_length TSRMLS_DC) { struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); - ssize_t len = wsgi_req->socket->proto_write(wsgi_req, (char *) str, str_length); - if (len != (ssize_t) str_length) { + wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, (char *) str, str_length); + if (wsgi_req->write_errors > 0) { php_handle_aborted_connection(); return -1; } - wsgi_req->response_size += len; return str_length; } diff --git a/plugins/psgi/psgi_response.c b/plugins/psgi/psgi_response.c index 9b9b4ab4..f1c67914 100644 --- a/plugins/psgi/psgi_response.c +++ b/plugins/psgi/psgi_response.c @@ -126,9 +126,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) { vi = (i*2)+base; wsgi_req->hvec[vi].iov_base = "\r\n"; wsgi_req->hvec[vi].iov_len = 2; - if ( !(wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, vi+1)) ) { - uwsgi_error("writev()"); - } + wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, vi+1); hitem = av_fetch(response, 2, 0); diff --git a/plugins/python/python_plugin.c b/plugins/python/python_plugin.c index b4e3e2c6..a0aa3b55 100644 --- a/plugins/python/python_plugin.c +++ b/plugins/python/python_plugin.c @@ -552,6 +552,7 @@ void init_uwsgi_embedded_module() { // just for safety Py_INCREF(up.embedded_dict); + if (PyDict_SetItemString(up.embedded_dict, "version", PyString_FromString(UWSGI_VERSION))) { PyErr_Print(); exit(1); diff --git a/plugins/python/uwsgi_python.h b/plugins/python/uwsgi_python.h index 65e796f5..30f4a50f 100644 --- a/plugins/python/uwsgi_python.h +++ b/plugins/python/uwsgi_python.h @@ -38,6 +38,8 @@ #define PyVarObject_HEAD_INIT(x, y) PyObject_HEAD_INIT(x) y, #endif +#define uwsgi_py_write_set_exception(x) PyErr_SetString(PyExc_IOError, "write error"); +#define uwsgi_py_write_exception(x) uwsgi_py_write_set_exception(x); PyErr_Print(); PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t); diff --git a/plugins/python/web3_subhandler.c b/plugins/python/web3_subhandler.c index 5f24735b..68e2c026 100644 --- a/plugins/python/web3_subhandler.c +++ b/plugins/python/web3_subhandler.c @@ -134,7 +134,6 @@ void *uwsgi_request_subhandler_web3(struct wsgi_request *wsgi_req, struct uwsgi_ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) { PyObject *pychunk; - ssize_t wsize; // ok its a yield if (!wsgi_req->async_placeholder) { @@ -168,11 +167,14 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) { Py_DECREF(spit_args); if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) { - if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(wsgi_req->async_placeholder), PyString_Size(wsgi_req->async_placeholder))) < 0) { - uwsgi_error("write()"); - goto clear; + char *content = PyString_AsString(wsgi_req->async_placeholder); + size_t content_len = PyString_Size(wsgi_req->async_placeholder); + UWSGI_RELEASE_GIL + wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len); + UWSGI_GET_GIL + if (wsgi_req->write_errors > 0) { + uwsgi_py_write_exception(wsgi_req); } - wsgi_req->response_size += wsize; goto clear; } @@ -208,12 +210,16 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) { if (PyString_Check(pychunk)) { - if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) { - uwsgi_error("write()"); + char *content = PyString_AsString(pychunk); + size_t content_len = PyString_Size(pychunk); + UWSGI_RELEASE_GIL + wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len); + UWSGI_GET_GIL + if (wsgi_req->write_errors > 0) { + uwsgi_py_write_exception(wsgi_req); Py_DECREF(pychunk); goto clear; } - wsgi_req->response_size += wsize; } diff --git a/plugins/python/wsgi_handlers.c b/plugins/python/wsgi_handlers.c index fa4a6a46..6ce21ecc 100644 --- a/plugins/python/wsgi_handlers.c +++ b/plugins/python/wsgi_handlers.c @@ -278,6 +278,10 @@ PyObject *py_uwsgi_write(PyObject * self, PyObject * args) { UWSGI_RELEASE_GIL wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, content, len); UWSGI_GET_GIL + if (wsgi_req->write_errors > 0) { + uwsgi_py_write_set_exception(wsgi_req); + return NULL; + } } Py_INCREF(Py_None); diff --git a/plugins/python/wsgi_subhandler.c b/plugins/python/wsgi_subhandler.c index 3707ddf0..82f21258 100644 --- a/plugins/python/wsgi_subhandler.c +++ b/plugins/python/wsgi_subhandler.c @@ -158,18 +158,20 @@ void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) { PyObject *pychunk; - ssize_t wsize; #ifdef UWSGI_SENDFILE ssize_t sf_len = 0; #endif // return or yield ? if (PyString_Check((PyObject *)wsgi_req->async_result)) { - if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) { - uwsgi_error("write()"); - goto clear; + char *content = PyString_AsString(wsgi_req->async_result); + size_t content_len = PyString_Size(wsgi_req->async_result); + UWSGI_RELEASE_GIL + wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len); + UWSGI_GET_GIL + if (wsgi_req->write_errors > 0) { + uwsgi_py_write_exception(wsgi_req); } - wsgi_req->response_size += wsize; goto clear; } @@ -248,12 +250,16 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) { if (PyString_Check(pychunk)) { - if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) { - uwsgi_error("write()"); + char *content = PyString_AsString(pychunk); + size_t content_len = PyString_Size(pychunk); + UWSGI_RELEASE_GIL + wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len); + UWSGI_GET_GIL + if (wsgi_req->write_errors > 0) { + uwsgi_py_write_exception(wsgi_req); Py_DECREF(pychunk); goto clear; } - wsgi_req->response_size += wsize; } #ifdef UWSGI_SENDFILE diff --git a/plugins/rack/rack_plugin.c b/plugins/rack/rack_plugin.c index fa6c1eb1..f8cbcfac 100644 --- a/plugins/rack/rack_plugin.c +++ b/plugins/rack/rack_plugin.c @@ -520,18 +520,15 @@ VALUE call_dispatch(VALUE env) { static VALUE send_body(VALUE obj) { struct wsgi_request *wsgi_req = current_wsgi_req(); - ssize_t len = 0; //uwsgi_log("sending body\n"); if (TYPE(obj) == T_STRING) { - len = wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(obj), RSTRING_LEN(obj)); + wsgi_req->response_size += wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(obj), RSTRING_LEN(obj)); } else { uwsgi_log("UNMANAGED BODY TYPE %d\n", TYPE(obj)); } - wsgi_req->response_size += len; - return Qnil; } @@ -765,9 +762,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) { wsgi_req->hvec[5].iov_base = (char *) "\r\n"; wsgi_req->hvec[5].iov_len = 2 ; - if ( !(wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, 6)) ) { - uwsgi_error("writev()"); - } + wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, 6); headers = RARRAY_PTR(ret)[1] ; if (rb_respond_to( headers, rb_intern("each") )) { @@ -778,9 +773,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) { } } - if (wsgi_req->socket->proto_write(wsgi_req, (char *)"\r\n", 2) != 2) { - uwsgi_error("write()"); - } + wsgi_req->socket->proto_write(wsgi_req, (char *)"\r\n", 2); body = RARRAY_PTR(ret)[2] ; diff --git a/proto/http.c b/proto/http.c index 89e10eb8..d4902692 100644 --- a/proto/http.c +++ b/proto/http.c @@ -369,19 +369,3 @@ int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) { return UWSGI_AGAIN; } - -ssize_t uwsgi_proto_http_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) { - return writev(wsgi_req->poll.fd, iovec, iov_len); -} - -ssize_t uwsgi_proto_http_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) { - return writev(wsgi_req->poll.fd, iovec, iov_len); -} - -ssize_t uwsgi_proto_http_write(struct wsgi_request * wsgi_req, char *buf, size_t len) { - return write(wsgi_req->poll.fd, buf, len); -} - -ssize_t uwsgi_proto_http_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) { - return write(wsgi_req->poll.fd, buf, len); -} diff --git a/proto/uwsgi.c b/proto/uwsgi.c index 87461f69..6c1444f8 100644 --- a/proto/uwsgi.c +++ b/proto/uwsgi.c @@ -114,38 +114,44 @@ int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) { return -1; } -ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) { +ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request *wsgi_req, struct iovec * iovec, size_t iov_len) { + if (iov_len == 0) return 0; ssize_t wlen = writev(wsgi_req->poll.fd, iovec, iov_len); if (wlen < 0) { - uwsgi_req_error("writev()"); + if (!uwsgi.ignore_write_errors) { + uwsgi_req_error("writev()"); + } + wsgi_req->write_errors++; return 0; } return wlen; } -ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) { - ssize_t wlen = writev(wsgi_req->poll.fd, iovec, iov_len); - if (wlen < 0) { - uwsgi_req_error("writev()"); - return 0; - } - return wlen; +ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request *wsgi_req, struct iovec * iovec, size_t iov_len) { + return uwsgi_proto_uwsgi_writev_header(wsgi_req, iovec, iov_len); } ssize_t uwsgi_proto_uwsgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) { - ssize_t wlen = write(wsgi_req->poll.fd, buf, len); - if (wlen < 0) { - uwsgi_req_error("write()"); - return 0; + ssize_t wlen; + char *ptr = buf; + if (len == 0) return 0; + + while(len > 0) { + wlen = write(wsgi_req->poll.fd, ptr, len); + if (wlen <= 0) { + if (!uwsgi.ignore_write_errors) { + uwsgi_req_error("write()"); + } + wsgi_req->write_errors++; + return ptr-buf; + } + ptr+=wlen; + len -= wlen; } - return wlen; + + return ptr-buf; } -ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) { - ssize_t wlen = write(wsgi_req->poll.fd, buf, len); - if (wlen < 0) { - uwsgi_req_error("write()"); - return 0; - } - return wlen; +ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request *wsgi_req, char *buf, size_t len) { + return uwsgi_proto_uwsgi_write(wsgi_req, buf, len); } diff --git a/uwsgi.c b/uwsgi.c index fd7bcadb..e0de65ea 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -83,6 +83,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"endif", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE}, {"ignore-sigpipe", no_argument, 0, "do not report (annoying) SIGPIPE", uwsgi_opt_true, &uwsgi.ignore_sigpipe,0}, + {"ignore-write-errors", no_argument, 0, "do not report (annoying) write()/writev() errors", uwsgi_opt_true, &uwsgi.ignore_write_errors,0}, {"inherit", required_argument, 0, "use the specified file as config template", uwsgi_opt_load, NULL,0}, {"daemonize", required_argument, 'd', "daemonize uWSGI", uwsgi_opt_set_str, &uwsgi.daemonize, 0}, @@ -2293,10 +2294,10 @@ skipzero: if (requested_protocol && !strcmp("http", requested_protocol)) { uwsgi_sock->proto = uwsgi_proto_http_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; - uwsgi_sock->proto_write = uwsgi_proto_http_write; - uwsgi_sock->proto_writev = uwsgi_proto_http_writev; - uwsgi_sock->proto_write_header = uwsgi_proto_http_write_header; - uwsgi_sock->proto_writev_header = uwsgi_proto_http_writev_header; + uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write; + uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev; + uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header; + uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header; uwsgi_sock->proto_sendfile = NULL; uwsgi_sock->proto_close = uwsgi_proto_base_close; } diff --git a/uwsgi.h b/uwsgi.h index e3634e98..cfe9291f 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -672,7 +672,6 @@ struct uwsgi_app { void *interpreter; void *callable; - #ifdef UWSGI_ASYNC void **args; void **environ; @@ -918,6 +917,7 @@ struct wsgi_request { int async_plagued; int suspended; + int write_errors; int *ovector; size_t post_cl; @@ -1189,6 +1189,7 @@ struct uwsgi_server { #endif int ignore_sigpipe; + int ignore_write_errors; // still working on it char *profiler; @@ -2377,10 +2378,6 @@ ssize_t uwsgi_proto_sctp_read_body(struct wsgi_request *, char *, size_t); #endif int uwsgi_proto_http_parser(struct wsgi_request *); -ssize_t uwsgi_proto_http_writev_header(struct wsgi_request *, struct iovec *, size_t); -ssize_t uwsgi_proto_http_writev(struct wsgi_request *, struct iovec *, size_t); -ssize_t uwsgi_proto_http_write(struct wsgi_request *, char *, size_t); -ssize_t uwsgi_proto_http_write_header(struct wsgi_request *, char *, size_t); int uwsgi_proto_fastcgi_parser(struct wsgi_request *); ssize_t uwsgi_proto_fastcgi_writev_header(struct wsgi_request *, struct iovec *, size_t);