diff --git a/logging.c b/logging.c index bccea63a..628ccd13 100644 --- a/logging.c +++ b/logging.c @@ -40,7 +40,7 @@ void log_request(struct wsgi_request *wsgi_req) { struct uwsgi_app *wi; if (wsgi_req->app_id >= 0) { - wi = &uwsgi.wsgi_apps[wsgi_req->app_id]; + wi = &uwsgi.apps[wsgi_req->app_id]; if (wi->requests > 0) { app_req = wi->requests; } diff --git a/pyutils.c b/pyutils.c index b9b94464..5421e35a 100644 --- a/pyutils.c +++ b/pyutils.c @@ -1,174 +1,11 @@ #include "uwsgi.h" + int manage_python_response(struct uwsgi_server *uwsgi, 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 = write(wsgi_req->poll.fd, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) { - uwsgi_error("write()"); - goto clear; - } - wsgi_req->response_size += wsize; - goto clear; - } - -#ifdef PYTHREE - if (PyBytes_Check((PyObject *)wsgi_req->async_result)) { - if ((wsize = write(wsgi_req->poll.fd, PyBytes_AsString(wsgi_req->async_result), PyBytes_Size(wsgi_req->async_result))) < 0) { - uwsgi_error("write()"); - goto clear; - } - wsgi_req->response_size += wsize; - goto clear; - } -#endif - -#ifdef UWSGI_SENDFILE - if (wsgi_req->sendfile_obj == wsgi_req->async_result && 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; - } -#endif - -#ifdef UWSGI_WSGI2 - // is it a tuple (WSGI2.0) ? - // move it to another hook !!! - if (PyTuple_Check((PyObject *)wsgi_req->async_result)) { - if (PyTuple_Size((PyObject *)wsgi_req->async_result) != 3) { - uwsgi_log("invalid WSGI2.0 response size: %d.\n", PyTuple_Size((PyObject *)wsgi_req->async_result)); - goto clear; - } -#ifdef UWSGI_DEBUG - uwsgi_debug("wsgi_req->async_result = %d\n", ((PyObject *)wsgi_req->async_result)->ob_refcnt); -#endif - if (py_uwsgi_spit(NULL, (PyObject *)wsgi_req->async_result) == Py_None) { - goto clear; - } -#ifdef UWSGI_DEBUG - uwsgi_debug("wsgi_req->async_result = %d\n", ((PyObject *)wsgi_req->async_result)->ob_refcnt); -#endif - wsgi_req->async_orig_result = wsgi_req->async_result ; - wsgi_req->async_result = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 2); -#ifdef UWSGI_DEBUG - uwsgi_debug("wsgi_req->async_orig_result = %d\n", ((PyObject *)wsgi_req->async_orig_result)->ob_refcnt); - uwsgi_debug("wsgi_req->async_result = %d\n", ((PyObject *)wsgi_req->async_result)->ob_refcnt); -#endif - return UWSGI_AGAIN; - } -#endif - - // ok its a yield - if (!wsgi_req->async_placeholder) { - wsgi_req->async_placeholder = PyObject_GetIter(wsgi_req->async_result); - if (!wsgi_req->async_placeholder) { - goto clear2; - } -#ifdef UWSGI_ASYNC - if (uwsgi->async > 1) { - return UWSGI_AGAIN; - } -#endif - } - - - - pychunk = PyIter_Next(wsgi_req->async_placeholder) ; - - if (!pychunk) { - if (PyErr_Occurred()) PyErr_Print(); - goto clear; - } - - - - if (PyString_Check(pychunk)) { - if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) { - uwsgi_error("write()"); - Py_DECREF(pychunk); - goto clear; - } - wsgi_req->response_size += wsize; - } - -#ifdef PYTHREE - else if (PyBytes_Check(pychunk)) { - if ((wsize = write(wsgi_req->poll.fd, PyBytes_AsString(pychunk), PyBytes_Size(pychunk))) < 0) { - uwsgi_error("write()"); - Py_DECREF(pychunk); - goto clear; - } - wsgi_req->response_size += wsize; - } -#endif - -#ifdef UWSGI_SENDFILE - else if (wsgi_req->sendfile_obj == pychunk && wsgi_req->sendfile_fd != -1) { - sf_len = uwsgi_sendfile(uwsgi, wsgi_req); - if (sf_len < 1) goto clear; - wsgi_req->response_size += sf_len ; - } -#endif - - Py_DECREF(pychunk); - return UWSGI_AGAIN ; - -clear: - if (wsgi_req->sendfile_fd != -1) { - Py_DECREF((PyObject *)wsgi_req->async_sendfile); - } - if (wsgi_req->async_environ) { - PyDict_Clear(wsgi_req->async_environ); - } - if (wsgi_req->async_post && !wsgi_req->fd_closed) { - fclose(wsgi_req->async_post); - if (!uwsgi->post_buffering || wsgi_req->post_cl <= (size_t) uwsgi->post_buffering) { - wsgi_req->fd_closed = 1 ; - - } - } - Py_XDECREF((PyObject *)wsgi_req->async_placeholder); -#ifdef UWSGI_WSGI2 - Py_XDECREF((PyObject *)wsgi_req->async_orig_result); -#endif -clear2: - Py_DECREF((PyObject *)wsgi_req->async_result); - PyErr_Clear(); - -#ifdef UWSGI_DEBUG - if (wsgi_req->async_placeholder) { - uwsgi_debug("wsgi_req->async_placeholder: %d\n", ((PyObject *)wsgi_req->async_placeholder)->ob_refcnt); - } -#ifdef UWSGI_WSGI2 - if (wsgi_req->async_orig_result) { - uwsgi_debug("wsgi_req->async_orig_result: %d\n", ((PyObject *)wsgi_req->async_orig_result)->ob_refcnt); - } -#endif - if (wsgi_req->async_result) { - uwsgi_debug("wsgi_req->async_result: %d\n", ((PyObject *)wsgi_req->async_result)->ob_refcnt); - } - if (wsgi_req->async_app) { - uwsgi_debug("wsgi_req->async_app: %d\n", ((PyObject *)wsgi_req->async_app)->ob_refcnt); - } -#endif - return UWSGI_OK; + // use standard WSGI response parse + return uwsgi_response_subhandler_wsgi(uwsgi, wsgi_req); } - PyObject *python_call(PyObject *callable, PyObject *args, int catch) { PyObject *pyret; diff --git a/setup.py b/setup.py index 7d0fca98..316c79fb 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ class uWSGIDistribution(Distribution): setup(name='uWSGI', - version='0.9.6.1', + version='0.9.7-dev', description='The uWSGI server', author='Unbit', author_email='info@unbit.it', diff --git a/simple_app.py b/simple_app.py index 2dad9bd1..c56c2030 100644 --- a/simple_app.py +++ b/simple_app.py @@ -1,12 +1,12 @@ import uwsgi -print "!!! uWSGI version:", uwsgi.version +print("!!! uWSGI version:", uwsgi.version) def ciao(): - print "modifica su /tmp" + print("modifica su /tmp") def ciao2(): - print "nuovo uwsgi_server" + print("nuovo uwsgi_server") counter = 0 @@ -22,13 +22,14 @@ counter = 0 def application(env, start_response): global counter + - print env + print(env) start_response('200 Ok', [('Content-type', 'text/plain')]) yield "hello world" yield "hello world2" - for i in xrange(1,1000): + for i in range(1,1000): yield str(i) yield "\n" diff --git a/utils.c b/utils.c index 6f9164c1..72eb2235 100644 --- a/utils.c +++ b/utils.c @@ -535,3 +535,178 @@ inline int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) { return memcmp(src, dst, dlen); } + +char *uwsgi_concatn(int c, ...) { + + va_list s; + char *item; + int j = c; + char *buf; + size_t len = 1; + size_t tlen = 1; + + va_start( s, c); + while(j>0) { + item = va_arg( s, char *); + if (item == NULL) { + break; + } + len += va_arg( s, int); + j--; + } + va_end( s ); + + + buf = malloc(len); + if (buf == NULL) { + uwsgi_error("malloc()"); + exit(1); + } + memset( buf, 0, len); + + j = c ; + + len = 0; + + va_start( s, c); + while(j>0) { + item = va_arg( s, char *); + if (item == NULL) { + break; + } + tlen = va_arg( s, int); + memcpy(buf + len, item, tlen); + len += tlen; + j--; + } + va_end( s ); + + + return buf; + +} + +char *uwsgi_concat3(char *one, char *two, char *three) { + + char *buf; + size_t len = strlen(one) + strlen(two) + strlen(three) + 1; + + + buf = malloc(len); + if (buf == NULL) { + uwsgi_error("malloc()"); + exit(1); + } + buf[len-1] = 0; + + memcpy( buf, one, strlen(one)); + memcpy( buf + strlen(one) , two, strlen(two)); + memcpy( buf + strlen(one) + strlen(two) , three, strlen(three)); + + return buf; + +} + +char *uwsgi_concat3n(char *one, int s1, char *two, int s2, char *three, int s3) { + + char *buf; + size_t len = s1 + s2 + s3 + 1; + + + buf = malloc(len); + if (buf == NULL) { + uwsgi_error("malloc()"); + exit(1); + } + buf[len-1] = 0; + + memcpy( buf, one, s1); + memcpy( buf + s1, two, s2); + memcpy( buf + s1 + s2, three, s3); + + return buf; + +} + + +char *uwsgi_concat(int c, ... ) { + + va_list s; + char *item; + size_t len = 1; + int j = c; + char *buf ; + + va_start( s, c); + while(j>0) { + item = va_arg( s, char *); + if (item == NULL) { + break; + } + len += (int) strlen(item); + j--; + } + va_end( s ); + + + buf = malloc(len); + if (buf == NULL) { + uwsgi_error("malloc()"); + exit(1); + } + memset( buf, 0, len); + + j = c ; + + len = 0; + + va_start( s, c); + while(j>0) { + item = va_arg( s, char *); + if (item == NULL) { + break; + } + memcpy(buf + len, item, strlen(item)); + len += strlen(item); + j--; + } + va_end( s ); + + + return buf; + +} + +char *uwsgi_strncopy(char *s, int len) { + + char *buf ; + + buf = malloc(len + 1); + if (buf == NULL) { + uwsgi_error("malloc()"); + exit(1); + } + buf[len] = 0; + + memcpy(buf, s, len); + + return buf; + +} + + +int uwsgi_get_app_id(struct uwsgi_server *uwsgi, char *script_name, int script_name_len) { + + int i; + + for(i=0;iapps_cnt;i++) { + if (!uwsgi->apps[i].mountpoint_len) { + continue; + } + if (!uwsgi_strncmp(uwsgi->apps[i].mountpoint, uwsgi->apps[i].mountpoint_len, script_name, script_name_len)) { + return i; + } + } + + return -1; +} diff --git a/uwsgi.c b/uwsgi.c index c73fc5f4..cf98c292 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -170,6 +170,10 @@ static struct option long_options[] = { {"vacuum", no_argument, &uwsgi.vacuum, 1}, {"ping", required_argument, 0, LONG_ARGS_PING}, {"ping-timeout", required_argument, 0, LONG_ARGS_PING_TIMEOUT}, +#ifdef __linux__ + {"cgroup", required_argument, 0, LONG_ARGS_CGROUP}, + {"cgroup-opt", required_argument, 0, LONG_ARGS_CGROUP_OPT}, +#endif {"version", no_argument, 0, LONG_ARGS_VERSION}, {0, 0, 0, 0} }; @@ -324,8 +328,8 @@ void stats() { uwsgi_log("*** pid %d stats ***\n", getpid()); uwsgi_log("\ttotal requests: %llu\n", uwsgi.workers[0].requests); - for (i = 0; i < uwsgi.wsgi_cnt; i++) { - ua = &uwsgi.wsgi_apps[i]; + for (i = 0; i < uwsgi.apps_cnt; i++) { + ua = &uwsgi.apps[i]; if (ua) { uwsgi_log("\tapp %d requests: %d\n", i, ua->requests); } @@ -525,7 +529,7 @@ int main(int argc, char *argv[], char *envp[]) { uwsgi.shared->after_hooks[i] = unconfigured_after_hook; } - uwsgi.wsgi_cnt = 1; + uwsgi.apps_cnt = 1; uwsgi.default_app = -1; uwsgi.buffer_size = 4096; @@ -906,16 +910,9 @@ int main(int argc, char *argv[], char *envp[]) { if (uwsgi.vhost) { uwsgi_log("VirtualHosting mode enabled.\n"); - uwsgi.wsgi_cnt = 0 ; + uwsgi.apps_cnt = 0 ; } - uwsgi.py_apps = PyDict_New(); - if (!uwsgi.py_apps) { - PyErr_Print(); - exit(1); - } - - wsgi_spitout = PyCFunction_New(uwsgi_spit_method, NULL); uwsgi.wsgi_writeout = PyCFunction_New(uwsgi_write_method, NULL); @@ -1085,7 +1082,7 @@ int main(int argc, char *argv[], char *envp[]) { init_uwsgi_vars(); } - memset(uwsgi.wsgi_apps, 0, sizeof(uwsgi.wsgi_apps)); + memset(uwsgi.apps, 0, sizeof(uwsgi.apps)); @@ -1500,6 +1497,19 @@ int main(int argc, char *argv[], char *envp[]) { check_interval.tv_sec = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; if (!check_interval.tv_sec) check_interval.tv_sec = 1; + + +#ifdef __linux__ + struct tcp_info ti; + socklen_t tis = sizeof(struct tcp_info) ; + if (getsockopt(uwsgi.serverfd, IPPROTO_TCP, TCP_INFO, &ti, &tis)) { + uwsgi_error("getsockopt()"); + } + else { + uwsgi_log("socket status: %d %d\n", ti.tcpi_unacked, ti.tcpi_sacked); + } +#endif + for (i = 1; i <= uwsgi.numproc; i++) { /* first check for harakiri */ if (uwsgi.workers[i].harakiri > 0) { @@ -1924,11 +1934,8 @@ void init_uwsgi_vars() { if (snprintf(venv_version, 15, "/lib/python%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION) == -1) { return ; } -#ifdef PYTHREE - venv_path = PyString_Concat( venv_path, PyString_FromString(venv_version) ); -#else + PyString_Concat( &venv_path, PyString_FromString(venv_version) ); -#endif if ( PyList_Insert(pypath, 0, venv_path) ) { PyErr_Print(); @@ -1942,12 +1949,12 @@ void init_uwsgi_vars() { } #endif - if (PyList_Insert(pypath, 0, PyString_FromString(".")) != 0) { + if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(".") ) != 0) { PyErr_Print(); } for (i = 0; i < uwsgi.python_path_cnt; i++) { - if (PyList_Insert(pypath, 0, PyString_FromString(uwsgi.python_path[i])) != 0) { + if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(uwsgi.python_path[i]) ) != 0) { PyErr_Print(); } else { @@ -1969,6 +1976,8 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { int i; #endif + char *mountpoint; + struct uwsgi_app *wi; memset(tmpstring, 0, 256); @@ -1989,7 +1998,7 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { return -1; } - id = uwsgi.wsgi_cnt; + id = uwsgi.apps_cnt; if (uwsgi.wsgi_req->script_name_len == 0) { @@ -2006,38 +2015,30 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { } } - + if (uwsgi.vhost) { - zero = PyString_FromStringAndSize(uwsgi.wsgi_req->host, uwsgi.wsgi_req->host_len); -#ifdef PYTHREE - zero = PyString_Concat(zero, PyString_FromString("|")); - zero = PyString_Concat(zero, PyString_FromStringAndSize(uwsgi.wsgi_req->script_name, uwsgi.wsgi_req->script_name_len)); -#else - PyString_Concat(&zero, PyString_FromString("|")); - PyString_Concat(&zero, PyString_FromStringAndSize(uwsgi.wsgi_req->script_name, uwsgi.wsgi_req->script_name_len)); -#endif + mountpoint = uwsgi_concat3n(uwsgi.wsgi_req->host, uwsgi.wsgi_req->host_len, "|", 1, uwsgi.wsgi_req->script_name, uwsgi.wsgi_req->script_name_len); } else { - zero = PyString_FromStringAndSize(uwsgi.wsgi_req->script_name, uwsgi.wsgi_req->script_name_len); + mountpoint = uwsgi_strncopy(uwsgi.wsgi_req->script_name, uwsgi.wsgi_req->script_name_len); } - if (!zero) { - Py_FatalError("cannot get mountpoint python object !\n"); - } - - if (PyDict_GetItem(uwsgi.py_apps, zero) != NULL) { - Py_DECREF(zero); - uwsgi_log( "mountpoint %.*s already configured. skip.\n", uwsgi.wsgi_req->script_name_len, uwsgi.wsgi_req->script_name); + if (uwsgi_get_app_id(&uwsgi, mountpoint, strlen(mountpoint)) != -1) { + uwsgi_log( "mountpoint %.*s already configured. skip.\n", strlen(mountpoint), mountpoint); return -1; } - wi = &uwsgi.wsgi_apps[id]; + wi = &uwsgi.apps[id]; memset(wi, 0, sizeof(struct uwsgi_app)); + wi->mountpoint = mountpoint; + wi->mountpoint_len = strlen(mountpoint); + // dynamic chdir ? + if (uwsgi.wsgi_req->chdir_len > 0) { wi->chdir = malloc(uwsgi.wsgi_req->chdir_len + 1); if (wi->chdir == NULL) { @@ -2054,6 +2055,7 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { } if (uwsgi.single_interpreter == 0) { + wi->interpreter = Py_NewInterpreter(); if (!wi->interpreter) { uwsgi_log( "unable to initialize the new interpreter\n"); @@ -2281,6 +2283,32 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { else { #endif +#ifdef UWSGI_WEB3 + // heck function args + zero = PyObject_GetAttrString(wi->wsgi_callable, "__code__"); + zero = PyObject_GetAttrString(zero, "co_argcount"); + wi->argc = (int) PyInt_AsLong(zero); + + if (wi->argc == 1) { + uwsgi_log("-- Web3 callable detected --\n"); + wi->request_subhandler = uwsgi_request_subhandler_web3; + wi->response_subhandler = uwsgi_response_subhandler_web3; + } + else if (wi->argc == 2) { + uwsgi_log("-- WSGI callable detected --\n"); + wi->request_subhandler = uwsgi_request_subhandler_wsgi; + wi->response_subhandler = uwsgi_response_subhandler_wsgi; + } + else { + uwsgi_log("-- INVALID callable detected --\n"); + if (uwsgi.single_interpreter == 0) { + Py_EndInterpreter(wi->interpreter); + PyThreadState_Swap(uwsgi.main_thread) ; + } + return -1; + } +#endif + #ifdef UWSGI_ASYNC wi->wsgi_args = malloc(sizeof(PyObject*)*uwsgi.async); if (!wi->wsgi_args) { @@ -2293,7 +2321,7 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { } for(i=0;iwsgi_args[i] = PyTuple_New(2); + wi->wsgi_args[i] = PyTuple_New(wi->argc); // this will leak all the already allocated dictionary !!! if (!wi->wsgi_args[i]) { if (uwsgi.single_interpreter == 0) { @@ -2302,25 +2330,30 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { } return -1 ; } - if (PyTuple_SetItem(wi->wsgi_args[i], 1, wsgi_spitout)) { - PyErr_Print(); - if (uwsgi.single_interpreter == 0) { - Py_EndInterpreter(wi->interpreter); - PyThreadState_Swap(uwsgi.main_thread); + + if (wi->argc > 1) { + if (PyTuple_SetItem(wi->wsgi_args[i], 1, wsgi_spitout)) { + PyErr_Print(); + if (uwsgi.single_interpreter == 0) { + Py_EndInterpreter(wi->interpreter); + PyThreadState_Swap(uwsgi.main_thread); + } + return -1; } - return -1; } } #else - wi->wsgi_args = PyTuple_New(2); - if (PyTuple_SetItem(wi->wsgi_args, 1, wsgi_spitout)) { - PyErr_Print(); - if (uwsgi.single_interpreter == 0) { - Py_EndInterpreter(wi->interpreter); - PyThreadState_Swap(uwsgi.main_thread); + wi->wsgi_args = PyTuple_New(wi->argc); + if (wi->argc > 1) { + if (PyTuple_SetItem(wi->wsgi_args, 1, wsgi_spitout)) { + PyErr_Print(); + if (uwsgi.single_interpreter == 0) { + Py_EndInterpreter(wi->interpreter); + PyThreadState_Swap(uwsgi.main_thread); + } + return -1; } - return -1; } #endif @@ -2342,10 +2375,8 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { PyThreadState_Swap(uwsgi.main_thread); } - PyDict_SetItem(uwsgi.py_apps, zero, PyInt_FromLong(id)); - PyErr_Print(); - uwsgi_log( "application %d (%s) ready\n", id, PyString_AsString(zero)); + uwsgi_log( "application %d (%.*s) ready\n", id, wi->mountpoint_len, wi->mountpoint); Py_DECREF(zero); @@ -2353,11 +2384,11 @@ int init_uwsgi_app(PyObject * force_wsgi_dict, PyObject * my_callable) { uwsgi_log( "setting default application to 0\n"); uwsgi.default_app = 0; if (uwsgi.vhost) { - uwsgi.wsgi_cnt++; + uwsgi.apps_cnt++; } } else { - uwsgi.wsgi_cnt++; + uwsgi.apps_cnt++; } return id; @@ -2616,6 +2647,7 @@ void uwsgi_wsgi_config(char *filename) { } } + wsgi_module = PyImport_ImportModule(uwsgi.wsgi_config); if (!wsgi_module) { PyErr_Print(); @@ -2630,6 +2662,7 @@ void uwsgi_wsgi_config(char *filename) { exit(1); } + if (!quick_callable) { uwsgi_log( "...getting the applications list from the '%s' module...\n", uwsgi.wsgi_config); @@ -2728,16 +2761,27 @@ void uwsgi_wsgi_config(char *filename) { for (i = 0; i < PyList_Size(app_list); i++) { app_mnt = PyList_GetItem(app_list, i); +#ifdef PYTHREE + if (!PyUnicode_Check(app_mnt)) { +#else if (!PyString_Check(app_mnt)) { +#endif uwsgi_log( "the app mountpoint must be a string.\n"); exit(1); } + +#ifdef PYTHREE + uwsgi.wsgi_req->script_name = (char *) PyUnicode_AS_DATA(app_mnt); +#else uwsgi.wsgi_req->script_name = PyString_AsString(app_mnt); +#endif uwsgi.wsgi_req->script_name_len = strlen(uwsgi.wsgi_req->script_name); + app_app = PyDict_GetItem(applications, app_mnt); + if (!PyString_Check(app_app) && !PyFunction_Check(app_app) && !PyCallable_Check(app_app)) { uwsgi_log( "the app callable must be a string, a function or a callable. (found %s)\n", app_app->ob_type->tp_name); exit(1); @@ -2868,11 +2912,6 @@ void init_uwsgi_embedded_module() { } - if (PyDict_SetItemString(uwsgi.embedded_dict, "applist", uwsgi.py_apps)) { - PyErr_Print(); - exit(1); - } - if (PyDict_SetItemString(uwsgi.embedded_dict, "applications", Py_None)) { PyErr_Print(); exit(1); @@ -3139,6 +3178,20 @@ void manage_opt(int i, char *optarg) { uwsgi_log( "you can specify at most 64 --http-var options\n"); } break; +#endif +#ifdef __linux__ + case LONG_ARGS_CGROUP: + uwsgi.cgroup = optarg; + break; + case LONG_ARGS_CGROUP_OPT: + if (uwsgi.cgroup_opt_cnt < 63) { + uwsgi.cgroup_opt[uwsgi.cgroup_opt_cnt] = optarg; + uwsgi.cgroup_opt_cnt++; + } + else { + uwsgi_log( "you can specify at most 64 --cgroup_opt options\n"); + } + break; #endif case LONG_ARGS_PYTHONPATH: if (uwsgi.python_path_cnt < 63) { @@ -3421,6 +3474,8 @@ void manage_opt(int i, char *optarg) { \t--vacuum\t\t\tclear the environment on exit (remove UNIX sockets and pidfiles)\n\ \t--ping \t\t\tping a uWSGI server (returns 1 on failure 0 on success)\n\ \t--ping-timeout \t\tset ping timeout to \n\ +\t--cgroup \t\trun the server in cgroup (Linux only)\n\ +\t--cgroup-opt KEY=VAL\t\tset cgroup option (Linux only)\n\ \t--version\t\t\tprint server version\n\ \t-d|--daemonize \tdaemonize and log into or udp \n", uwsgi.binary_path); exit(1); diff --git a/uwsgi.h b/uwsgi.h index 91f8e4e6..f101c0ba 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2,7 +2,7 @@ /* indent -i8 -br -brs -brf -l0 -npsl -nip -npcs -npsl -di1 */ -#define UWSGI_VERSION "0.9.6.1" +#define UWSGI_VERSION "0.9.7-dev" #define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); #define uwsgi_debug(x, ...) uwsgi_log("[uWSGI DEBUG] " x, __VA_ARGS__); @@ -188,6 +188,8 @@ PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t); #define LONG_ARGS_HTTP_VAR 17043 #define LONG_ARGS_NO_DEFAULT_APP 17044 #define LONG_ARGS_EVAL_CONFIG 17045 +#define LONG_ARGS_CGROUP 17046 +#define LONG_ARGS_CGROUP_OPT 17047 @@ -257,17 +259,21 @@ PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t); #define UWSGI_MODIFIER_RESPONSE 255 #ifdef PYTHREE +#define UWSGI_PYFROMSTRING(x) PyUnicode_FromString(x) #define PyInt_FromLong PyLong_FromLong #define PyInt_AsLong PyLong_AsLong #define PyInt_Check PyLong_Check -#define PyString_Check PyUnicode_Check -#define PyString_FromStringAndSize PyUnicode_FromStringAndSize -#define PyString_FromFormat PyUnicode_FromFormat -#define PyString_FromString PyUnicode_FromString -#define PyString_Size PyUnicode_GET_DATA_SIZE -#define PyString_Concat PyUnicode_Concat -#define PyString_AsString (char *) PyUnicode_AS_UNICODE +#define PyString_Check PyBytes_Check +#define PyString_FromStringAndSize PyBytes_FromStringAndSize +#define PyString_FromFormat PyBytes_FromFormat +#define PyString_FromString PyBytes_FromString +#define PyString_Size PyBytes_Size +#define PyString_Concat PyBytes_Concat +#define PyString_AsString (char *) PyBytes_AsString #define PyFile_FromFile(A,B,C,D) PyFile_FromFd(fileno((A)), (B), (C), -1, NULL, NULL, NULL, 0) + +#else +#define UWSGI_PYFROMSTRING(x) PyString_FromString(x) #endif #define NL_SIZE 2 @@ -283,6 +289,9 @@ struct uwsgi_server; struct uwsgi_app { + char *mountpoint; + int mountpoint_len; + PyThreadState *interpreter; PyObject *pymain_dict; PyObject *wsgi_dict; @@ -306,6 +315,10 @@ struct uwsgi_app { PyObject *wsgi_eventfd_write; #endif + void* (*request_subhandler)(struct uwsgi_server *, struct wsgi_request *, struct uwsgi_app *); + int (*response_subhandler)(struct uwsgi_server *, struct wsgi_request *); + + int argc; int requests; char *chdir; @@ -425,9 +438,6 @@ struct wsgi_request { void *async_app; void *async_result; -#ifdef UWSGI_WSGI2 - void *async_orig_result; -#endif void *async_placeholder; void *async_args; void *async_environ; @@ -453,7 +463,7 @@ struct uwsgi_server { char *pyhome; int has_threads; - int wsgi_cnt; + int apps_cnt; int default_app; int enable_profiler; @@ -659,8 +669,7 @@ struct uwsgi_server { struct uwsgi_shared *shared; - struct uwsgi_app wsgi_apps[64]; - PyObject *py_apps; + struct uwsgi_app apps[64]; #ifdef UWSGI_ERLANG int erlang_nodes; @@ -711,6 +720,12 @@ struct uwsgi_server { int log_zero_headers; int log_empty_body; int log_high_memory; + +#ifdef __linux__ + char *cgroup; + char *cgroup_opt[64]; + int cgroup_opt_cnt; +#endif }; struct uwsgi_cluster_node { @@ -1132,3 +1147,21 @@ int uwsgi_strncmp(char *, int , char *, int ); #else inline int uwsgi_strncmp(char *, int , char *, int ); #endif + + +char *uwsgi_concat(int, ...); +char *uwsgi_concatn(int, ...); +char *uwsgi_concat3(char *, char *, char *); +char *uwsgi_concat3n(char *, int, char *, int, char *, int); + + +void *uwsgi_request_subhandler_wsgi(struct uwsgi_server *, struct wsgi_request *, struct uwsgi_app *); +int uwsgi_response_subhandler_wsgi(struct uwsgi_server *, struct wsgi_request *); + +#ifdef UWSGI_WEB3 +void *uwsgi_request_subhandler_web3(struct uwsgi_server *, struct wsgi_request *, struct uwsgi_app *); +int uwsgi_response_subhandler_web3(struct uwsgi_server *, struct wsgi_request *); +#endif + +int uwsgi_get_app_id(struct uwsgi_server *, char *, int); +char *uwsgi_strncopy(char *, int ); diff --git a/uwsgiconfig.py b/uwsgiconfig.py index c06882c1..9c86cda9 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -21,7 +21,7 @@ UGREEN=False HTTP=True EVDIS=False LDAP=False -WSGI2=False +WEB3=True ROUTING=False STACKLESS=False #PLUGINS = ['psgi'] @@ -90,7 +90,7 @@ gcc_major = int(gcc_version.split('.')[0]) gcc_minor = int(gcc_version.split('.')[1]) -gcc_list = ['utils', 'pyutils', 'protocol', 'socket', 'logging', 'wsgi_handlers', 'wsgi_headers', 'uwsgi_handlers', 'plugins', 'uwsgi'] +gcc_list = ['utils', 'pyutils', 'protocol', 'socket', 'logging', 'wsgi_handlers', 'wsgi_subhandler', 'wsgi_headers', 'uwsgi_handlers', 'plugins', 'uwsgi'] cflags = ['-O2', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split() @@ -220,8 +220,8 @@ def unbit_setup(): global EVDIS EVDIS=False - global WSGI2 - WSGI2=False + global WEB3 + WEB3=False global LDAP LDAP=False @@ -336,7 +336,7 @@ def parse_vars(): libs.append('-lldap') if ROUTING: - depends_on("ROUTING", ['WSGI2', 'XML']) + depends_on("ROUTING", ['WEB3', 'XML']) cflags.append("-DUWSGI_ROUTING") gcc_list.append('routing') pcreconf = spcall("pcre-config --cflags") @@ -434,8 +434,9 @@ def parse_vars(): cflags.append("-DUWSGI_SPOOLER") gcc_list.append('spooler') - if WSGI2: - cflags.append("-DUWSGI_WSGI2") + if WEB3: + cflags.append("-DUWSGI_WEB3") + gcc_list.append('web3_subhandler') if DEBUG: cflags.append("-DUWSGI_DEBUG") diff --git a/wsgi_handlers.c b/wsgi_handlers.c index ad542b09..37c1e12d 100644 --- a/wsgi_handlers.c +++ b/wsgi_handlers.c @@ -77,7 +77,7 @@ int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req size_t post_remains = wsgi_req->post_cl; ssize_t post_chunk; - PyObject *zero, *wsgi_socket; + PyObject *zero; PyObject *pydictkey, *pydictvalue; @@ -139,15 +139,10 @@ int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req if (uwsgi->vhost) { zero = PyString_FromStringAndSize(wsgi_req->host, wsgi_req->host_len); -#ifdef PYTHREE - zero = PyString_Concat(zero, PyString_FromString("|")); - zero = PyString_Concat(zero, PyString_FromStringAndSize(wsgi_req->script_name, wsgi_req->script_name_len)); -#else PyString_Concat(&zero, PyString_FromString("|")); PyString_Concat(&zero, PyString_FromStringAndSize(wsgi_req->script_name, wsgi_req->script_name_len)); #ifdef UWSGI_DEBUG uwsgi_debug("VirtualHost SCRIPT_NAME=%s\n", PyString_AsString(zero)); -#endif #endif } else { @@ -155,14 +150,13 @@ int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req } - if (PyDict_Contains(uwsgi->py_apps, zero)) { - wsgi_req->app_id = PyInt_AsLong(PyDict_GetItem(uwsgi->py_apps, zero)); - } - else if (wsgi_req->script_name_len > 1 || uwsgi->default_app < 0 || uwsgi->vhost) { - /* unavailable app for this SCRIPT_NAME */ - wsgi_req->app_id = -1; - if (wsgi_req->wsgi_script_len > 0 || (wsgi_req->wsgi_callable_len > 0 && wsgi_req->wsgi_module_len > 0)) { - wsgi_req->app_id = init_uwsgi_app(NULL, NULL); + if ( (wsgi_req->app_id = uwsgi_get_app_id(uwsgi, wsgi_req->script_name, wsgi_req->script_name_len)) == -1) { + if (wsgi_req->script_name_len > 1 || uwsgi->default_app < 0 || uwsgi->vhost) { + /* unavailable app for this SCRIPT_NAME */ + wsgi_req->app_id = -1; + if (wsgi_req->wsgi_script_len > 0 || (wsgi_req->wsgi_callable_len > 0 && wsgi_req->wsgi_module_len > 0)) { + wsgi_req->app_id = init_uwsgi_app(NULL, NULL); + } } } @@ -185,7 +179,7 @@ int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req } - wi = &uwsgi->wsgi_apps[wsgi_req->app_id]; + wi = &uwsgi->apps[wsgi_req->app_id]; if (uwsgi->single_interpreter == 0) { if (!wi->interpreter) { @@ -302,103 +296,13 @@ int uwsgi_request_wsgi(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req wsgi_req->async_post = fdopen(wsgi_req->poll.fd, "r"); } - wsgi_socket = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL); - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_socket); - Py_DECREF(wsgi_socket); - -#ifdef UWSGI_SENDFILE - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.file_wrapper", wi->wsgi_sendfile); -#endif - -#ifdef UWSGI_ASYNC - if (uwsgi->async > 1) { - PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.readable", wi->wsgi_eventfd_read); - PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.writable", wi->wsgi_eventfd_write); - PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_None); - } -#endif - - zero = PyTuple_New(2); - PyTuple_SetItem(zero, 0, PyInt_FromLong(1)); - PyTuple_SetItem(zero, 1, PyInt_FromLong(0)); - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.version", zero); - Py_DECREF(zero); - - zero = PyFile_FromFile(stderr, "wsgi_input", "w", NULL); - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.errors", zero); - Py_DECREF(zero); - - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.run_once", Py_False); - - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multithread", Py_False); - if (uwsgi->numproc == 1) { - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multiprocess", Py_False); - } - else { - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multiprocess", Py_True); - } - - if (wsgi_req->scheme_len > 0) { - zero = PyString_FromStringAndSize(wsgi_req->scheme, wsgi_req->scheme_len); - } - else if (wsgi_req->https_len > 0) { - if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') { - zero = PyString_FromString("https"); - } - else { - zero = PyString_FromString("http"); - } - } - else { - zero = PyString_FromString("http"); - } - PyDict_SetItemString(wsgi_req->async_environ, "wsgi.url_scheme", zero); - Py_DECREF(zero); - - - wsgi_req->async_app = wi->wsgi_callable ; - - PyDict_SetItemString(uwsgi->embedded_dict, "env", wsgi_req->async_environ); - - PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.uwsgi.version", uwsgi_version); - - -#ifdef UWSGI_ROUTING - uwsgi_log("routing %d routes %d\n", uwsgi->routing, uwsgi->nroutes); - if (uwsgi->routing && uwsgi->nroutes > 0) { - check_route(uwsgi, wsgi_req); - } -#endif - - - // call - -#ifdef UWSGI_PROFILER - if (uwsgi->enable_profiler == 1) { - PyDict_SetItem(wi->pymain_dict, PyString_FromFormat("uwsgi_environ__%d", wsgi_req->app_id), wsgi_req->async_environ); - wsgi_req->async_result = python_call(wi->wsgi_cprofile_run, wsgi_req->async_args, 0); - if (wsgi_req->async_result) { - wsgi_req->async_result = PyDict_GetItemString(wi->pymain_dict, "uwsgi_out"); - Py_INCREF((PyObject*)wsgi_req->async_result); - Py_INCREF((PyObject*)wsgi_req->async_result); - } - } - else { -#endif - - - PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ); - wsgi_req->async_result = python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi->catch_exceptions); - -#ifdef UWSGI_PROFILER - } -#endif + wsgi_req->async_result = (*wi->request_subhandler)(uwsgi, wsgi_req, wi); if (wsgi_req->async_result) { - while ( manage_python_response(uwsgi, wsgi_req) != UWSGI_OK) { + while ( (*wi->response_subhandler)(uwsgi, wsgi_req) != UWSGI_OK) { #ifdef UWSGI_ASYNC if (uwsgi->async > 1) { return UWSGI_AGAIN;