diff --git a/core/errors.c b/core/errors.c
index 499403eb..afd4c96c 100644
--- a/core/errors.c
+++ b/core/errors.c
@@ -3,18 +3,21 @@
// generate internal server error message
void uwsgi_500(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) return;
+ if (uwsgi_response_add_connection_close(wsgi_req)) return;
uwsgi_response_write_body_do(wsgi_req, "Internal Server Error", 21);
}
void uwsgi_404(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "404 Not Found", 13)) return;
+ if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/plain", 10)) return;
uwsgi_response_write_body_do(wsgi_req, "Not Found", 9);
}
void uwsgi_403(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "403 Forbidden", 13)) return;
+ if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return;
uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9);
}
@@ -25,6 +28,7 @@ void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
size_t redirect_len = 0;
if (uwsgi_response_prepare_headers(wsgi_req, "301 Moved Permanently", 21)) return;
+ if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (wsgi_req->query_string_len == 0) {
redirect = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1);
diff --git a/plugins/cache/cache.c b/plugins/cache/cache.c
index af3ab5e0..8105caea 100644
--- a/plugins/cache/cache.c
+++ b/plugins/cache/cache.c
@@ -14,17 +14,17 @@ static void cache_command(char *key, uint16_t keylen, char *val, uint16_t vallen
#ifdef UWSGI_DEBUG
uwsgi_log("cache value size: %llu\n", tmp_vallen);
#endif
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
+ uwsgi_response_write_body_do(wsgi_req, val, tmp_vallen);
}
}
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
if (val && vallen > 0) {
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
+ uwsgi_response_write_body_do(wsgi_req, val, tmp_vallen);
}
else {
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 404 Not Found\r\n\r\n
Not Found
", 44);
+ uwsgi_404(wsgi_req);
}
}
}
@@ -46,8 +46,8 @@ int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
if (value && vallen > 0) {
wsgi_req->uh.pktsize = vallen;
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
- wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen);
+ if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) return -1;
+ uwsgi_response_write_body_do(wsgi_req, value, vallen);
}
}
break;
@@ -82,13 +82,13 @@ int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
if (value && vallen > 0) {
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 1;
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
- wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen);
+ if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) return -1;
+ uwsgi_response_write_body_do(wsgi_req, value, vallen);
}
else {
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = 0;
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
+ if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) return -1;
}
}
break;
@@ -106,11 +106,10 @@ int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
}
wsgi_req->uh.pktsize = cache_dump->pos;
- wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
- wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, cache_dump->buf, cache_dump->pos);
+ if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) return -1;
+ uwsgi_response_write_body_do(wsgi_req, cache_dump->buf, cache_dump->pos);
uwsgi_buffer_destroy(cache_dump);
uwsgi_wlock(uwsgi.cache_lock);
- uwsgi_socket_nb(wsgi_req->poll.fd);
int ret = uwsgi_write_nb(wsgi_req->poll.fd, (char *)uwsgi.cache_items, uwsgi.cache_filesize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (!ret) {
wsgi_req->response_size += uwsgi.cache_filesize;
diff --git a/plugins/gevent/gevent.c b/plugins/gevent/gevent.c
index a7dc4a0c..70d82d00 100644
--- a/plugins/gevent/gevent.c
+++ b/plugins/gevent/gevent.c
@@ -1,59 +1,10 @@
-#include "../python/uwsgi_python.h"
+#include "gevent.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
+struct uwsgi_gevent ugevent;
-#define GEVENT_SWITCH PyObject *gswitch = python_call(ugevent.greenlet_switch, ugevent.greenlet_switch_args, 0, NULL); Py_DECREF(gswitch)
-#define GET_CURRENT_GREENLET python_call(ugevent.get_current, ugevent.get_current_args, 0, NULL)
-#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
-#define stop_the_watchers if (timer) { ret = PyObject_CallMethod(timer, "stop", NULL);\
- if (ret) { Py_DECREF(ret); } }\
- ret = PyObject_CallMethod(watcher, "stop", NULL);\
- if (ret) { Py_DECREF(ret); }
-
-#define stop_the_watchers_and_clear stop_the_watchers\
- Py_DECREF(current); Py_DECREF(current_greenlet);\
- Py_DECREF(watcher);\
- if (timer) Py_DECREF(timer);
-
-#define stop_the_io ret = PyObject_CallMethod(watcher, "stop", NULL);\
- if (ret) { Py_DECREF(ret); }
-
-#define stop_the_io_and_clear stop_the_io;\
- Py_DECREF(current); Py_DECREF(current_greenlet);\
- Py_DECREF(watcher);\
-
-#define stop_the_c_watchers if (c_watchers) { int j;\
- for(j=0;joptions[UWSGI_OPTION_HARAKIRI]);
}
- // accept the connection
+ // accept the connection (since uWSGI 1.5 all of teh sockets are non-blocking)
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
free_req_queue;
if (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) {
@@ -203,11 +154,6 @@ edge:
goto clear;
}
-// on linux we need to set the socket in non-blocking as it is not inherited
-#ifdef __linux__
- uwsgi_socket_nb(wsgi_req->poll.fd);
-#endif
-
// hack to easily pass wsgi_req pointer to the greenlet
PyTuple_SetItem(ugevent.greenlet_args, 1, PyLong_FromLong((long)wsgi_req));
@@ -710,98 +656,6 @@ error:
return -1;
}
-
-
-void uwsgi_gevent_nb_write(struct wsgi_request *wsgi_req, PyObject *str) {
- PyObject *ret;
- char *content = PyString_AsString(str);
- size_t content_len = PyString_Size(str);
-
- // do not try to write empty chunks
- if (content_len == 0) return;
-
- /// create a watcher for writes
- PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 2);
- if (!watcher) goto error;
-
- PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
- if (!timer) {
- Py_DECREF(watcher);
- goto error;
- }
-
- PyObject *current_greenlet = GET_CURRENT_GREENLET;
- PyObject *current = PyObject_GetAttrString(current_greenlet, "switch");
-
- char *ptr = content;
- size_t remains = content_len;
-
- // this is the main writing cycle, wait for writability and send...
- for(;;) {
- ret = PyObject_CallMethod(watcher, "start", "OO", current, watcher);
- if (!ret) {
- stop_the_watchers_and_clear
- goto error;
- }
- Py_DECREF(ret);
-
- ret = PyObject_CallMethod(timer, "start", "OO", current, timer);
- if (!ret) {
- stop_the_watchers_and_clear
- goto error;
- }
- Py_DECREF(ret);
-
- ret = PyObject_CallMethod(ugevent.hub, "switch", NULL);
- wsgi_req->switches++;
- if (!ret) {
- stop_the_watchers_and_clear
- goto error;
- }
- Py_DECREF(ret);
-
- if (ret == timer) {
- goto fail;
- }
-
- // ok we can write a chunk to the socket
- UWSGI_RELEASE_GIL
- ssize_t len = write(wsgi_req->poll.fd, ptr, remains);
- UWSGI_GET_GIL
- if (len > 0) {
- ptr += len;
- remains -= len;
- wsgi_req->response_size += len;
- if (remains == 0) {
- break;
- }
- stop_the_watchers
- continue;
- }
- else if (len < 0) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
- stop_the_watchers
- continue;
- }
- }
-
-fail:
- stop_the_watchers_and_clear
- goto error;
- }
-
- stop_the_watchers
- Py_DECREF(current); Py_DECREF(current_greenlet);
- Py_DECREF(watcher);
- Py_DECREF(timer);
- return ;
-
-error:
- if (PyErr_Occurred())
- PyErr_Print();
- wsgi_req->write_errors++;
-}
-
PyObject *uwsgi_gevent_wait(PyObject *watcher, PyObject *timer, PyObject *current) {
PyObject *ret;
@@ -924,15 +778,15 @@ PyMethodDef uwsgi_gevent_my_signal_def[] = { {"uwsgi_gevent_my_signal", py_uwsgi
PyMethodDef uwsgi_gevent_signal_handler_def[] = { {"uwsgi_gevent_signal_handler", py_uwsgi_gevent_signal_handler, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_handler_def[] = { {"uwsgi_gevent_unix_signal_handler", py_uwsgi_gevent_graceful, METH_VARARGS, ""} };
-void gil_gevent_get() {
+static void gil_gevent_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
-void gil_gevent_release() {
+static void gil_gevent_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
-void gevent_loop() {
+static void gevent_loop() {
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n");
@@ -955,6 +809,7 @@ void gevent_loop() {
uwsgi.channel_recv_hook = uwsgi_channel_gevent_recv;
// buffer write generic hook
uwsgi.buffer_write_hook = uwsgi_buffer_gevent_write;
+ uwsgi.wait_write_hook = uwsgi_gevent_wait_write_hook;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
@@ -1084,7 +939,7 @@ void gevent_loop() {
}
-void gevent_init() {
+static void gevent_init() {
uwsgi_register_loop( (char *) "gevent", gevent_loop);
}
diff --git a/plugins/gevent/hooks.c b/plugins/gevent/hooks.c
new file mode 100644
index 00000000..a6ed7e4b
--- /dev/null
+++ b/plugins/gevent/hooks.c
@@ -0,0 +1,54 @@
+#include "gevent.h"
+
+extern struct uwsgi_server uwsgi;
+extern struct uwsgi_gevent ugevent;
+
+
+int uwsgi_gevent_wait_write_hook(struct wsgi_request *wsgi_req) {
+
+ PyObject *ret = NULL;
+
+ /// create a watcher for writes
+ PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 2);
+ if (!watcher) return -1;
+
+ PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
+ if (!timer) {
+ Py_DECREF(watcher);
+ return -1;
+ }
+
+ PyObject *current_greenlet = GET_CURRENT_GREENLET;
+ PyObject *current = PyObject_GetAttrString(current_greenlet, "switch");
+
+ ret = PyObject_CallMethod(watcher, "start", "OO", current, watcher);
+ if (!ret) {
+ stop_the_watchers_and_clear
+ return -1;
+ }
+ Py_DECREF(ret);
+
+ ret = PyObject_CallMethod(timer, "start", "OO", current, timer);
+ if (!ret) {
+ stop_the_watchers_and_clear
+ return -1;
+ }
+ Py_DECREF(ret);
+
+ ret = PyObject_CallMethod(ugevent.hub, "switch", NULL);
+ wsgi_req->switches++;
+ if (!ret) {
+ stop_the_watchers_and_clear
+ return -1;
+ }
+ Py_DECREF(ret);
+
+ if (ret == timer) {
+ stop_the_watchers_and_clear;
+ return -1;
+ }
+
+ stop_the_watchers_and_clear;
+ return 0;
+}
+
diff --git a/plugins/gevent/uwsgiplugin.py b/plugins/gevent/uwsgiplugin.py
index 91e46849..155e2f23 100644
--- a/plugins/gevent/uwsgiplugin.py
+++ b/plugins/gevent/uwsgiplugin.py
@@ -5,4 +5,4 @@ CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(pla
LDFLAGS = []
LIBS = []
-GCC_LIST = ['gevent']
+GCC_LIST = ['gevent', 'hooks']