From e1316153be1408d83412a624a7d1e045bd4e0872 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 19 Jan 2013 21:42:05 +0100 Subject: [PATCH] another series of porting --- core/writer.c | 9 + plugins/python/wsgi_headers.c | 240 +++------------------- plugins/python/wsgi_subhandler.c | 46 ++--- plugins/router_redirect/router_redirect.c | 34 +-- 4 files changed, 66 insertions(+), 263 deletions(-) diff --git a/core/writer.c b/core/writer.c index 52b01df3..10ac4007 100644 --- a/core/writer.c +++ b/core/writer.c @@ -117,6 +117,15 @@ int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos sendfile: + if (len == 0) { + struct stat st; + if (fstat(fd, &st)) { + uwsgi_error("fstat()"); + return -1; + } + len = st.st_size; + } + for(;;) { uwsgi_log("XXXX %d %d\n", pos, len); int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len); diff --git a/plugins/python/wsgi_headers.c b/plugins/python/wsgi_headers.c index 3bfd7ba6..bcabdf5a 100644 --- a/plugins/python/wsgi_headers.c +++ b/plugins/python/wsgi_headers.c @@ -3,45 +3,21 @@ extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; -static char *nl = "\r\n"; -static char *h_sep = ": "; -static const char *http_protocol = "HTTP/1.1"; - // check here PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) { PyObject *headers, *head; PyObject *h_key, *h_value; - int i, j; PyObject *exc_info = NULL; + size_t i; struct wsgi_request *wsgi_req = current_wsgi_req(); - int base = 0; - // avoid double sending of headers if (wsgi_req->headers_sent) { return PyErr_Format(PyExc_IOError, "headers already sent"); } - // decref old status line - if (wsgi_req->status_header) { - Py_DECREF((PyObject *)wsgi_req->status_header); - wsgi_req->status_header = NULL; - } - - if (wsgi_req->headers) { - Py_DECREF((PyObject *)wsgi_req->headers); - wsgi_req->headers = NULL; - } - -#ifdef PYTHREE - if (wsgi_req->gc_tracker) { - Py_DECREF((PyObject *)wsgi_req->gc_tracker); - wsgi_req->gc_tracker = NULL; - } -#endif - // this must be done before headers management if (PyTuple_Size(args) > 2) { exc_info = PyTuple_GetItem(args, 2); @@ -79,91 +55,40 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) { return PyErr_Format(PyExc_TypeError, "http status must be a string"); } -#ifdef PYTHREE - // this list maintains reference to encoded strings.. ugly hack, i know, but it works... - wsgi_req->gc_tracker = (void *) PyList_New(0); -#endif - - if (uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] == 0) { - base = 4; - - if (wsgi_req->protocol_len == 0) { - wsgi_req->hvec[0].iov_base = (char *) http_protocol; - wsgi_req->protocol_len = 8; - } - else { - wsgi_req->hvec[0].iov_base = wsgi_req->protocol; - } - - wsgi_req->hvec[0].iov_len = wsgi_req->protocol_len; - wsgi_req->hvec[1].iov_base = " "; - wsgi_req->hvec[1].iov_len = 1; + char *status_line = NULL; + size_t status_line_len = 0; #ifdef PYTHREE if (self != Py_None) { PyObject *zero = PyUnicode_AsASCIIString(head); - wsgi_req->hvec[2].iov_base = PyBytes_AsString(zero); - PyList_Append((PyObject *) wsgi_req->gc_tracker, zero); + status_line = PyBytes_AsString(zero); + status_line_len = PyBytes_Size(zero); Py_DECREF(zero); } else { - wsgi_req->hvec[2].iov_base = PyBytes_AsString(head); + status_line = PyBytes_AsString(head); + status_line_len = PyBytes_Size(head); } - wsgi_req->hvec[2].iov_len = strlen(wsgi_req->hvec[2].iov_base); #else - wsgi_req->hvec[2].iov_base = PyString_AsString(head); - wsgi_req->hvec[2].iov_len = PyString_Size(head); + status_line = PyString_AsString(head); + status_line_len = PyString_Size(head); #endif - wsgi_req->status = uwsgi_str3_num(wsgi_req->hvec[2].iov_base); - wsgi_req->hvec[3].iov_base = nl; - wsgi_req->hvec[3].iov_len = NL_SIZE; - } - else { - // drop http status on cgi mode - base = 3; - wsgi_req->hvec[0].iov_base = "Status: "; - wsgi_req->hvec[0].iov_len = 8; -#ifdef PYTHREE - if (self != Py_None) { - PyObject *zero = PyUnicode_AsASCIIString(head); - wsgi_req->hvec[1].iov_base = PyBytes_AsString(zero); - PyList_Append((PyObject *) wsgi_req->gc_tracker, zero); - Py_DECREF(zero); - } - else { - wsgi_req->hvec[1].iov_base = PyBytes_AsString(head); - } - wsgi_req->hvec[1].iov_len = strlen(wsgi_req->hvec[1].iov_base); -#else - wsgi_req->hvec[1].iov_base = PyString_AsString(head); - wsgi_req->hvec[1].iov_len = PyString_Size(head); -#endif - wsgi_req->status = uwsgi_str3_num(wsgi_req->hvec[1].iov_base); - wsgi_req->hvec[2].iov_base = nl; - wsgi_req->hvec[2].iov_len = NL_SIZE; + if (uwsgi_response_prepare_headers(wsgi_req, status_line, status_line_len)) { + return PyErr_Format(PyExc_TypeError, "unable to set HTTP status line"); } - // incref status line - wsgi_req->status_header = head; - Py_INCREF((PyObject *)wsgi_req->status_header); headers = PyTuple_GetItem(args, 1); if (!headers) { return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments"); } - wsgi_req->headers = headers; - Py_INCREF((PyObject *)wsgi_req->headers); - if (!PyList_Check(headers)) { return PyErr_Format(PyExc_TypeError, "http headers must be in a python list"); } - wsgi_req->header_cnt = PyList_Size(headers); - if (wsgi_req->header_cnt > uwsgi.max_vars) { - wsgi_req->header_cnt = uwsgi.max_vars; - } - for (i = 0; i < wsgi_req->header_cnt; i++) { - j = (i * 4) + base; + size_t h_count = PyList_Size(headers); + + for (i = 0; i < h_count; i++) { head = PyList_GetItem(headers, i); if (!head) { return NULL; @@ -195,151 +120,54 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) { } + char *k = NULL; size_t kl = 0; + char *v = NULL; size_t vl = 0; #ifdef PYTHREE if (self != Py_None) { PyObject *zero = PyUnicode_AsASCIIString(h_key); - wsgi_req->hvec[j].iov_base = PyBytes_AsString(zero); - PyList_Append((PyObject *) wsgi_req->gc_tracker, zero); + k = PyBytes_AsString(zero); + kl = PyBytes_Size(zero); Py_DECREF(zero); } else { - wsgi_req->hvec[j].iov_base = PyBytes_AsString(h_key); + k = PyBytes_AsString(h_key); + kl = PyBytes_Size(h_key); } - wsgi_req->hvec[j].iov_len = strlen(wsgi_req->hvec[j].iov_base); #else - wsgi_req->hvec[j].iov_base = PyString_AsString(h_key); - wsgi_req->hvec[j].iov_len = PyString_Size(h_key); + k = PyString_AsString(h_key); + kl = PyString_Size(h_key); #endif - wsgi_req->hvec[j + 1].iov_base = h_sep; - wsgi_req->hvec[j + 1].iov_len = H_SEP_SIZE; + #ifdef PYTHREE if (self != Py_None) { PyObject *zero = PyUnicode_AsASCIIString(h_value); - wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(zero); - PyList_Append((PyObject *) wsgi_req->gc_tracker, zero); + v = PyBytes_AsString(zero); + vl = PyBytes_Size(zero); Py_DECREF(zero); } else { - wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(h_value); + v = PyBytes_AsString(h_value); + vl = PyBytes_Size(h_value); } - wsgi_req->hvec[j + 2].iov_len = strlen(wsgi_req->hvec[j + 2].iov_base); #else - wsgi_req->hvec[j + 2].iov_base = PyString_AsString(h_value); - wsgi_req->hvec[j + 2].iov_len = PyString_Size(h_value); + v = PyString_AsString(h_value); + vl = PyString_Size(h_value); #endif - - wsgi_req->hvec[j + 3].iov_base = nl; - wsgi_req->hvec[j + 3].iov_len = NL_SIZE; - - //uwsgi_log( "%.*s: %.*s\n", wsgi_req->hvec[j].iov_len, (char *)wsgi_req->hvec[j].iov_base, wsgi_req->hvec[j+2].iov_len, (char *) wsgi_req->hvec[j+2].iov_base); - } - - j = (i * 4) + base; - - struct uwsgi_string_list *ah = uwsgi.additional_headers; - while(ah) { - if (wsgi_req->header_cnt+1 <= uwsgi.max_vars) { - wsgi_req->header_cnt++; - wsgi_req->hvec[j].iov_base = ah->value; - wsgi_req->hvec[j].iov_len = ah->len; - j++; - wsgi_req->hvec[j].iov_base = nl; - wsgi_req->hvec[j].iov_len = NL_SIZE; - j++; - ah = ah->next; - } - else { - uwsgi_log("no more space in iovec. consider increasing max-vars...\n"); - break; + if (uwsgi_response_add_header(wsgi_req, k, kl, v, vl)) { + return PyErr_Format(PyExc_TypeError, "unable to add header to the response"); } + } - ah = wsgi_req->additional_headers; - while(ah) { - if (wsgi_req->header_cnt+1 <= uwsgi.max_vars) { - wsgi_req->header_cnt++; - wsgi_req->hvec[j].iov_base = ah->value; - wsgi_req->hvec[j].iov_len = ah->len; - j++; - wsgi_req->hvec[j].iov_base = nl; - wsgi_req->hvec[j].iov_len = NL_SIZE; - j++; - ah = ah->next; - } - else { - uwsgi_log("no more space in iovec. consider increasing max-vars...\n"); - break; - } - } - - // \r\n - wsgi_req->hvec[j].iov_base = nl; - wsgi_req->hvec[j].iov_len = NL_SIZE; - - wsgi_req->headers_hvec = j; - if (up.start_response_nodelay) { - if (uwsgi_python_do_send_headers(wsgi_req)) { - return NULL; + if (uwsgi_response_write_headers_do(wsgi_req)) { + return PyErr_Format(PyExc_IOError, "unable to directly send headers"); } } - //uwsgi_log("%d %p\n", wsgi_req->poll.fd, up.wsgi_writeout); Py_INCREF(up.wsgi_writeout); return up.wsgi_writeout; } -int uwsgi_python_do_send_headers(struct wsgi_request *wsgi_req) { - - if (!wsgi_req->headers_hvec) return 0; - -#ifdef __sun__ - int remains = wsgi_req->headers_hvec + 1; - int iov_size; - struct iovec* iov_ptr = wsgi_req->hvec; - ssize_t iov_ret; - while(remains) { - iov_size = UMIN(remains, IOV_MAX); - UWSGI_RELEASE_GIL - iov_ret = wsgi_req->socket->proto_writev_header(wsgi_req, iov_ptr, iov_size); - UWSGI_GET_GIL - wsgi_req->headers_size += iov_ret; - iov_ptr += iov_size; - remains -= iov_size; - } -#else - UWSGI_RELEASE_GIL - wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, wsgi_req->headers_hvec + 1); - UWSGI_GET_GIL -#endif - - wsgi_req->headers_sent = 1; - - // decref status line - if (wsgi_req->status_header) { - Py_DECREF((PyObject *)wsgi_req->status_header); - wsgi_req->status_header = NULL; - } - - if (wsgi_req->headers) { - Py_DECREF((PyObject *)wsgi_req->headers); - wsgi_req->headers = NULL; - } - -#ifdef PYTHREE - if (wsgi_req->gc_tracker) { - Py_DECREF((PyObject *)wsgi_req->gc_tracker); - wsgi_req->gc_tracker = NULL; - } -#endif - - if (wsgi_req->write_errors > uwsgi.write_errors_tolerance && !uwsgi.disable_write_exception) { - uwsgi_py_write_set_exception(wsgi_req); - return -1; - } - - return 0; - -} diff --git a/plugins/python/wsgi_subhandler.c b/plugins/python/wsgi_subhandler.c index 40b414ae..c7e8ca29 100644 --- a/plugins/python/wsgi_subhandler.c +++ b/plugins/python/wsgi_subhandler.c @@ -156,13 +156,14 @@ 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 sf_len = 0; // return or yield ? if (PyString_Check((PyObject *)wsgi_req->async_result)) { char *content = PyString_AsString((PyObject *)wsgi_req->async_result); size_t content_len = PyString_Size((PyObject *)wsgi_req->async_result); - uwsgi.nb_write_hook(wsgi_req, content, content_len); + UWSGI_RELEASE_GIL + uwsgi_response_write_body_do(wsgi_req, content, content_len); + UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } @@ -170,25 +171,10 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) { } -#ifdef __FreeBSD__ - if ( ((wsgi_req->sendfile_obj == wsgi_req->async_result) || ( wsgi_req->sendfile_fd_size > 0 && wsgi_req->response_size < wsgi_req->sendfile_fd_size)) && wsgi_req->sendfile_fd != -1) { -#else if (wsgi_req->sendfile_obj == wsgi_req->async_result && wsgi_req->sendfile_fd != -1) { -#endif - // send the headers if not already sent - if (!wsgi_req->headers_sent && wsgi_req->headers_hvec > 0) { - uwsgi_python_do_send_headers(wsgi_req); - } - sf_len = uwsgi_sendfile(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 + UWSGI_RELEASE_GIL + uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0); + UWSGI_GET_GIL goto clear; } @@ -228,13 +214,11 @@ exception: if (PyString_Check(pychunk)) { + char *content = PyString_AsString(pychunk); size_t content_len = PyString_Size(pychunk); - if (content_len > 0 && !wsgi_req->headers_sent) { - if (uwsgi_python_do_send_headers(wsgi_req)) { - goto clear; - } - } - up.hook_write_string(wsgi_req, pychunk); + UWSGI_RELEASE_GIL + uwsgi_response_write_body_do(wsgi_req, content, content_len); + UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); Py_DECREF(pychunk); @@ -243,13 +227,9 @@ exception: } else if (wsgi_req->sendfile_obj == pychunk && wsgi_req->sendfile_fd != -1) { - // send the headers if not already sent - if (!wsgi_req->headers_sent && wsgi_req->headers_hvec > 0) { - uwsgi_python_do_send_headers(wsgi_req); - } - sf_len = uwsgi_sendfile(wsgi_req); - if (sf_len < 1) goto clear; - wsgi_req->response_size += sf_len; + UWSGI_RELEASE_GIL + uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0); + UWSGI_GET_GIL } diff --git a/plugins/router_redirect/router_redirect.c b/plugins/router_redirect/router_redirect.c index 94419bcc..2c5ae2a6 100644 --- a/plugins/router_redirect/router_redirect.c +++ b/plugins/router_redirect/router_redirect.c @@ -6,35 +6,21 @@ extern struct uwsgi_server uwsgi; int uwsgi_routing_func_redirect(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { - struct iovec iov[4]; - - if (wsgi_req->protocol_len > 0) { - iov[0].iov_base = wsgi_req->protocol; - iov[0].iov_len = wsgi_req->protocol_len; - } - else { - iov[0].iov_base = "HTTP/1.0"; - iov[0].iov_len = 8; - } - - iov[1].iov_base = " 302 Found\r\nLocation: "; - iov[1].iov_len = 22; + char *url = NULL; + if (uwsgi_response_headers_prepare(wsgi_req, "302 Found", 9)) goto end + char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); - iov[2].iov_base = uwsgi_regexp_apply_ovec(*subject, *subject_len, ur->data, ur->data_len, ur->ovector, ur->ovn); - iov[2].iov_len = strlen(iov[2].iov_base); + url = uwsgi_regexp_apply_ovec(*subject, *subject_len, ur->data, ur->data_len, ur->ovector, ur->ovn); - iov[3].iov_base = "\r\n\r\n"; - iov[3].iov_len = 4; - - wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4); - - wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, "Moved", 5); - wsgi_req->status = 302; - - free(iov[2].iov_base); + if (uwsgi_response_add_header(wsgi_req, "Location", 8, url, strlen(url))) goto end; + // no need to check the ret value + uwsgi_response_body_write_do(wsgi_req, "Moved", 5); +end: + if (url) + free(url); return UWSGI_ROUTE_BREAK; }