From 7d049d98d181d62980a0f9516948c9b4dd9a5feb Mon Sep 17 00:00:00 2001 From: mopemoepe Date: Thu, 10 May 2012 11:22:53 +0900 Subject: [PATCH] Hello Python3 --- .gitignore | 1 + MANIFEST.in | 3 +- example/hello_world.py | 4 +- meinheld/server/client.c | 14 +- meinheld/server/client.h | 4 +- meinheld/server/http_request_parser.c | 186 +++++++++++------- meinheld/server/log.c | 46 +++-- meinheld/server/log.h | 2 +- meinheld/server/meinheld.h | 49 +++-- meinheld/server/response.c | 58 ++++-- meinheld/server/server.c | 52 +++-- meinheld/server/server.h | 2 +- .../server/{stringio.c => stringio.c.old} | 0 setup.py | 72 ++++--- tox.ini | 5 + 15 files changed, 318 insertions(+), 180 deletions(-) rename meinheld/server/{stringio.c => stringio.c.old} (100%) create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 260cc5f..e56f566 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ build *.egg-info _mailinglist TODO +.tox diff --git a/MANIFEST.in b/MANIFEST.in index 6aa9e11..d65b16c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,4 +4,5 @@ include CHANGES.rst include meinheld/server/picoev_epoll.c include meinheld/server/picoev_kqueue.c include meinheld/server/picoev_select.c -recursive-include meinheld/server/ *.h +include meinheld/server/*.h + diff --git a/example/hello_world.py b/example/hello_world.py index 947b0e2..4d899d1 100644 --- a/example/hello_world.py +++ b/example/hello_world.py @@ -2,10 +2,10 @@ def hello_world(environ, start_response): status = '200 OK' - res = "Hello world!" + res = b"Hello world!" response_headers = [('Content-type','text/plain')] start_response(status, response_headers) - #print environ + print(environ) return [res] server.listen(("0.0.0.0", 8000)) diff --git a/meinheld/server/client.c b/meinheld/server/client.c index 63b8d58..b461021 100644 --- a/meinheld/server/client.c +++ b/meinheld/server/client.c @@ -37,10 +37,10 @@ alloc_ClientObject(void) if (client_numfree) { client = client_free_list[--client_numfree]; _Py_NewReference((PyObject *)client); - DEBUG("use pooled ClientObject %p", client); + /* DEBUG("use pooled ClientObject %p", client); */ }else{ client = PyObject_NEW(ClientObject, &ClientObjectType); - DEBUG("alloc ClientObject %p", client); + /* DEBUG("alloc ClientObject %p", client); */ } return client; } @@ -50,7 +50,7 @@ dealloc_ClientObject(ClientObject *client) { Py_CLEAR(client->greenlet); if (client_numfree < CLIENT_MAXFREELIST){ - DEBUG("back to ClientObject pool %p", client); + /* DEBUG("back to ClientObject pool %p", client); */ client_free_list[client_numfree++] = client; }else{ PyObject_DEL(client); @@ -174,8 +174,12 @@ static PyMemberDef ClientObject_members[] = { PyTypeObject ClientObjectType = { - PyObject_HEAD_INIT(&PyType_Type) - 0, +#ifdef PY3 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif "meinheld.client", /*tp_name*/ sizeof(ClientObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/meinheld/server/client.h b/meinheld/server/client.h index 0fe65b9..1a6c47b 100644 --- a/meinheld/server/client.h +++ b/meinheld/server/client.h @@ -20,11 +20,11 @@ typedef struct _client { char upgrade; // new protocol uint8_t complete; - http_parser *http; // http req parser + http_parser *http_parser; // http req parser PyObject *environ; // wsgi environ int status_code; // response status code - PyObject *http_status; // response status line(PyString) + PyObject *http_status; // response status line(PyBytes) PyObject *headers; // http response headers uint8_t header_done; // header write status PyObject *response; // wsgi response object diff --git a/meinheld/server/http_request_parser.c b/meinheld/server/http_request_parser.c index 87cdf9c..ffda7de 100644 --- a/meinheld/server/http_request_parser.c +++ b/meinheld/server/http_request_parser.c @@ -129,11 +129,11 @@ new_environ(client_t *client) PyDict_SetItem(environ, server_port_key, server_port_val); PyDict_SetItem(environ, file_wrapper_key, file_wrapper_val); - object = PyBytes_FromString(client->remote_addr); + object = NATIVE_FROMSTRING(client->remote_addr); PyDict_SetItem(environ, remote_addr_key, object); Py_DECREF(object); - object = PyBytes_FromFormat("%d", client->remote_port); + object = NATIVE_FROMFORMAT("%d", client->remote_port); PyDict_SetItem(environ, remote_port_key, object); Py_DECREF(object); return environ; @@ -214,7 +214,15 @@ set_query(PyObject *env, char *buf, int len) return -1; } +#ifdef PY3 + //TODO CHECK ERROR + char *c2 = PyBytes_AS_STRING(obj); + PyObject *v = PyUnicode_DecodeLatin1(c2, strlen(c2), NULL); + ret = PyDict_SetItem(env, query_string_key, v); + Py_DECREF(v); +#else ret = PyDict_SetItem(env, query_string_key, obj); +#endif Py_DECREF(obj); if(unlikely(ret == -1)){ @@ -263,7 +271,15 @@ set_path(PyObject *env, char *buf, int len) DEBUG("path:%.*s", (int)len, PyBytes_AS_STRING(obj)); if(likely(obj != NULL)){ +#ifdef PY3 + //TODO CHECK ERROR + char *c2 = PyBytes_AS_STRING(obj); + PyObject *v = PyUnicode_DecodeLatin1(c2, strlen(c2), NULL); + PyDict_SetItem(env, path_info_key, v); + Py_DECREF(v); +#else PyDict_SetItem(env, path_info_key, obj); +#endif Py_DECREF(obj); return slen; }else{ @@ -394,7 +410,18 @@ header_field_cb(http_parser *p, const char *buf, size_t len) client->bad_request_code = 400; return -1; } +#ifdef PY3 + //TODO CHECK ERROR + char *c1 = PyBytes_AS_STRING(req->field); + PyObject *f = PyUnicode_DecodeLatin1(c1, strlen(c1), NULL); + char *c2 = PyBytes_AS_STRING(req->value); + PyObject *v = PyUnicode_DecodeLatin1(c2, strlen(c2), NULL); + PyDict_SetItem(env, f, v); + Py_DECREF(f); + Py_DECREF(v); +#else PyDict_SetItem(env, req->field, req->value); +#endif Py_DECREF(req->field); Py_DECREF(req->value); req->field = NULL; @@ -487,10 +514,9 @@ body_cb(http_parser *p, const char *buf, size_t len) DEBUG("body_cb"); client_t *client = get_client(p); - DEBUG("content_length:%lu", (unsigned long)p->content_length); - if(max_content_length < client->body_readed + len){ + DEBUG("set request code %d", 413); client->bad_request_code = 413; return -1; } @@ -527,13 +553,17 @@ headers_complete_cb(http_parser *p) { PyObject *obj; int ret; + uint64_t content_length = 0; client_t *client = get_client(p); request *req = client->req; PyObject *env = client->environ; - - if(max_content_length < p->content_length){ - + + if(p->content_length != ULLONG_MAX){ + content_length = p->content_length; + } + if(max_content_length < content_length){ + DEBUG("set request code %d", 413); client->bad_request_code = 413; return -1; } @@ -566,7 +596,19 @@ headers_complete_cb(http_parser *p) //Last header if(likely(req->field && req->value)){ - ret = PyDict_SetItem(env, req->field, req->value); + +#ifdef PY3 + //TODO CHECK ERROR + char *c1 = PyBytes_AS_STRING(req->field); + PyObject *f = PyUnicode_DecodeLatin1(c1, strlen(c1), NULL); + char *c2 = PyBytes_AS_STRING(req->value); + PyObject *v = PyUnicode_DecodeLatin1(c2, strlen(c2), NULL); + PyDict_SetItem(env, f, v); + Py_DECREF(f); + Py_DECREF(v); +#else + PyDict_SetItem(env, req->field, req->value); +#endif Py_DECREF(req->field); Py_DECREF(req->value); req->field = NULL; @@ -653,7 +695,7 @@ headers_complete_cb(http_parser *p) } //free_request(req); client->req = NULL; - client->body_length = p->content_length; + client->body_length = content_length; obj = InputObject_New(client); if(unlikely(obj == NULL)){ @@ -711,20 +753,22 @@ int init_parser(client_t *cli, const char *name, const short port) { - cli->http = (http_parser*)PyMem_Malloc(sizeof(http_parser)); - memset(cli->http, 0, sizeof(http_parser)); - - http_parser_init(cli->http, HTTP_REQUEST); - cli->http->data = cli; + cli->http_parser = (http_parser*)PyMem_Malloc(sizeof(http_parser)); + if(cli->http_parser == NULL){ + return -1; + } + memset(cli->http_parser, 0, sizeof(http_parser)); + http_parser_init(cli->http_parser, HTTP_REQUEST); + cli->http_parser->data = cli; return 0; } size_t execute_parse(client_t *cli, const char *data, size_t len) { - size_t ret = http_parser_execute(cli->http, &settings, data, len); + size_t ret = http_parser_execute(cli->http_parser, &settings, data, len); //check new protocol - cli->upgrade = cli->http->upgrade; + cli->upgrade = cli->http_parser->upgrade; return ret; } @@ -741,76 +785,76 @@ setup_static_env(char *name, int port) { prefix_len = strlen("HTTP_"); - empty_string = PyBytes_FromString(""); + empty_string = NATIVE_FROMSTRING(""); version_val = Py_BuildValue("(ii)", 1, 0); - version_key = PyBytes_FromString("wsgi.version"); + version_key = NATIVE_FROMSTRING("wsgi.version"); - scheme_val = PyBytes_FromString("http"); - scheme_key = PyBytes_FromString("wsgi.url_scheme"); + scheme_val = NATIVE_FROMSTRING("http"); + scheme_key = NATIVE_FROMSTRING("wsgi.url_scheme"); errors_val = PySys_GetObject("stderr"); - errors_key = PyBytes_FromString("wsgi.errors"); + errors_key = NATIVE_FROMSTRING("wsgi.errors"); multithread_val = PyBool_FromLong(0); - multithread_key = PyBytes_FromString("wsgi.multithread"); + multithread_key = NATIVE_FROMSTRING("wsgi.multithread"); multiprocess_val = PyBool_FromLong(1); - multiprocess_key = PyBytes_FromString("wsgi.multiprocess"); + multiprocess_key = NATIVE_FROMSTRING("wsgi.multiprocess"); run_once_val = PyBool_FromLong(0); - run_once_key = PyBytes_FromString("wsgi.run_once"); + run_once_key = NATIVE_FROMSTRING("wsgi.run_once"); file_wrapper_val = PyCFunction_New(&method, NULL); - file_wrapper_key = PyBytes_FromString("wsgi.file_wrapper"); + file_wrapper_key = NATIVE_FROMSTRING("wsgi.file_wrapper"); - wsgi_input_key = PyBytes_FromString("wsgi.input"); + wsgi_input_key = NATIVE_FROMSTRING("wsgi.input"); - script_key = PyBytes_FromString("SCRIPT_NAME"); - - server_name_val = PyBytes_FromString(name); - server_name_key = PyBytes_FromString("SERVER_NAME"); - - server_port_val = PyBytes_FromFormat("%d", port); - server_port_key = PyBytes_FromString("SERVER_PORT"); - - remote_addr_key = PyBytes_FromString("REMOTE_ADDR"); - remote_port_key = PyBytes_FromString("REMOTE_PORT"); - - server_protocol_key = PyBytes_FromString("SERVER_PROTOCOL"); - path_info_key = PyBytes_FromString("PATH_INFO"); - query_string_key = PyBytes_FromString("QUERY_STRING"); - request_method_key = PyBytes_FromString("REQUEST_METHOD"); - client_key = PyBytes_FromString("meinheld.client"); - - content_type_key = PyBytes_FromString("CONTENT_TYPE"); - content_length_key = PyBytes_FromString("CONTENT_LENGTH"); - - h_content_type_key = PyBytes_FromString("HTTP_CONTENT_TYPE"); - h_content_length_key = PyBytes_FromString("HTTP_CONTENT_LENGTH"); - - server_protocol_val10 = PyBytes_FromString("HTTP/1.0"); - server_protocol_val11 = PyBytes_FromString("HTTP/1.1"); - - http_method_delete = PyBytes_FromStringAndSize("DELETE", 6); - http_method_get = PyBytes_FromStringAndSize("GET", 3); - http_method_head = PyBytes_FromStringAndSize("HEAD", 4); - http_method_post = PyBytes_FromStringAndSize("POST", 4); - http_method_put = PyBytes_FromStringAndSize("PUT", 3); - http_method_connect = PyBytes_FromStringAndSize("CONNECT", 7); - http_method_options = PyBytes_FromStringAndSize("OPTIONS", 7); - http_method_trace = PyBytes_FromStringAndSize("TRACE", 5); - http_method_copy = PyBytes_FromStringAndSize("COPY", 4); - http_method_lock = PyBytes_FromStringAndSize("LOCK", 4); - http_method_mkcol = PyBytes_FromStringAndSize("MKCOL", 5); - http_method_move = PyBytes_FromStringAndSize("MOVE", 4); - http_method_propfind= PyBytes_FromStringAndSize("PROPFIND", 8); - http_method_proppatch = PyBytes_FromStringAndSize("PROPPATCH", 9); - http_method_unlock = PyBytes_FromStringAndSize("UNLOCK", 6); - http_method_report = PyBytes_FromStringAndSize("REPORT", 6); - http_method_mkactivity = PyBytes_FromStringAndSize("MKACTIVITY", 10); - http_method_checkout = PyBytes_FromStringAndSize("CHECKOUT", 8); - http_method_merge = PyBytes_FromStringAndSize("MERGE", 5); + script_key = NATIVE_FROMSTRING("SCRIPT_NAME"); + + server_name_val = NATIVE_FROMSTRING(name); + server_name_key = NATIVE_FROMSTRING("SERVER_NAME"); + + server_port_val = NATIVE_FROMFORMAT("%d", port); + server_port_key = NATIVE_FROMSTRING("SERVER_PORT"); + + remote_addr_key = NATIVE_FROMSTRING("REMOTE_ADDR"); + remote_port_key = NATIVE_FROMSTRING("REMOTE_PORT"); + + server_protocol_key = NATIVE_FROMSTRING("SERVER_PROTOCOL"); + path_info_key = NATIVE_FROMSTRING("PATH_INFO"); + query_string_key = NATIVE_FROMSTRING("QUERY_STRING"); + request_method_key = NATIVE_FROMSTRING("REQUEST_METHOD"); + client_key = NATIVE_FROMSTRING("meinheld.client"); + + content_type_key = NATIVE_FROMSTRING("CONTENT_TYPE"); + content_length_key = NATIVE_FROMSTRING("CONTENT_LENGTH"); + + h_content_type_key = NATIVE_FROMSTRING("HTTP_CONTENT_TYPE"); + h_content_length_key = NATIVE_FROMSTRING("HTTP_CONTENT_LENGTH"); + + server_protocol_val10 = NATIVE_FROMSTRING("HTTP/1.0"); + server_protocol_val11 = NATIVE_FROMSTRING("HTTP/1.1"); + + http_method_delete = NATIVE_FROMSTRING("DELETE"); + http_method_get = NATIVE_FROMSTRING("GET"); + http_method_head = NATIVE_FROMSTRING("HEAD"); + http_method_post = NATIVE_FROMSTRING("POST"); + http_method_put = NATIVE_FROMSTRING("PUT"); + http_method_connect = NATIVE_FROMSTRING("CONNECT"); + http_method_options = NATIVE_FROMSTRING("OPTIONS"); + http_method_trace = NATIVE_FROMSTRING("TRACE"); + http_method_copy = NATIVE_FROMSTRING("COPY"); + http_method_lock = NATIVE_FROMSTRING("LOCK"); + http_method_mkcol = NATIVE_FROMSTRING("MKCOL"); + http_method_move = NATIVE_FROMSTRING("MOVE"); + http_method_propfind= NATIVE_FROMSTRING("PROPFIND"); + http_method_proppatch = NATIVE_FROMSTRING("PROPPATCH"); + http_method_unlock = NATIVE_FROMSTRING("UNLOCK"); + http_method_report = NATIVE_FROMSTRING("REPORT"); + http_method_mkactivity = NATIVE_FROMSTRING("MKACTIVITY"); + http_method_checkout = NATIVE_FROMSTRING("CHECKOUT"); + http_method_merge = NATIVE_FROMSTRING("MERGE"); //PycString_IMPORT; } diff --git a/meinheld/server/log.c b/meinheld/server/log.c index 9343a92..044921e 100644 --- a/meinheld/server/log.c +++ b/meinheld/server/log.c @@ -7,30 +7,52 @@ open_log_file(const char *path) return open(path, O_CREAT|O_APPEND|O_WRONLY, 0744); } -void +int write_error_log(char *file_name, int line) { - char buf[64]; + char buf[256]; + int fd, ret; PyObject *f = PySys_GetObject("stderr"); - FILE *fp = PyFile_AsFile(f); - int fd = fileno(fp); - flock(fd, LOCK_EX); + fd = PyObject_AsFileDescriptor(f); + if(fd < 0){ + return -1; + } + ret = flock(fd, LOCK_EX); + if(ret < 0){ + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } cache_time_update(); - fputs((char *)err_log_time, fp); - fputs(" [error] ", fp); + ret = write(fd, (char *)err_log_time, strlen((char*)err_log_time)); + if(ret < 0){ + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + ret = write(fd, " [error] ", 9); + if(ret < 0){ + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } - sprintf(buf, "pid %d, File \"%s\", line %d \n", getpid(), file_name, line); - fputs(buf, fp); + snprintf(buf, 256, "pid %d, File \"%s\", line %d \n", getpid(), file_name, line); + ret = write(fd, buf, strlen(buf)); + if(ret < 0){ + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } PyErr_Print(); PyErr_Clear(); - fflush(fp); - - flock(fd, LOCK_UN); + ret = flock(fd, LOCK_UN); + if(ret < 0){ + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + return 1; } static int diff --git a/meinheld/server/log.h b/meinheld/server/log.h index b7a68b6..c1d7e69 100644 --- a/meinheld/server/log.h +++ b/meinheld/server/log.h @@ -6,7 +6,7 @@ int open_log_file(const char *path); -void write_error_log(char *file_name, int line); +int write_error_log(char *file_name, int line); int write_access_log(client_t *cli, int log_fd, const char *log_path); diff --git a/meinheld/server/meinheld.h b/meinheld/server/meinheld.h index a2c694b..a5bad6a 100644 --- a/meinheld/server/meinheld.h +++ b/meinheld/server/meinheld.h @@ -63,26 +63,11 @@ PyErr_SetString(PyExc_NotImplementedError, "greenlet not support"); \ return NULL;\ -#endif - #if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2) || PY_MAJOR_VERSION > 3 -#define PY3 -#endif - -#if PY_MAJOR_VERSION < 3 -#ifndef Py_REFCNT -# define Py_REFCNT(ob) (((PyObject *) (ob))->ob_refcnt) -#endif -#ifndef Py_TYPE -# define Py_TYPE(ob) (((PyObject *) (ob))->ob_type) -#endif -#endif - -#ifdef PY3 -static char* -from_unicode(PyObject* obj) +static __inline__ char* +as_str(PyObject* obj) { - char *c; + char *c = NULL; PyObject *latin1; latin1 = PyUnicode_AsLatin1String(obj); @@ -93,14 +78,28 @@ from_unicode(PyObject* obj) Py_DECREF(latin1); return c; } - -#define AS_STRING(x) from_unicode(x); -//latin1 -#define FROM_STRING(x) PyUnicode_FromString(x); - +# define PY3 +# define NATIVE_GET_STRING_SIZE PyUnicode_GET_SIZE +# define NATIVE_ASSTRING as_str +# define NATIVE_FROMSTRING PyUnicode_FromString +# define NATIVE_FROMSTRINGANDSIZE PyUnicode_FromStringAndSize +# define NATIVE_FROMFORMAT PyUnicode_FromFormat #else +# define NATIVE_GET_STRING_SIZE PyBytes_GET_SIZE +# define NATIVE_ASSTRING PyBytes_AsString +# define NATIVE_FROMSTRING PyBytes_FromString +# define NATIVE_FROMSTRINGANDSIZE PyBytes_FromStringAndSize +# define NATIVE_FROMFORMAT PyBytes_FromFormat +#endif -#define AS_STRING(x) PyBytes_AsString(x); -#define FROM_STRING(x) PyBytes_FromString(x); +#if PY_MAJOR_VERSION < 3 +#ifndef Py_REFCNT +# define Py_REFCNT(ob) (((PyObject *) (ob))->ob_refcnt) +#endif +#ifndef Py_TYPE +# define Py_TYPE(ob) (((PyObject *) (ob))->ob_type) +#endif +#endif #endif + diff --git a/meinheld/server/response.c b/meinheld/server/response.c index a09bc51..61abbcd 100644 --- a/meinheld/server/response.c +++ b/meinheld/server/response.c @@ -1,6 +1,7 @@ #include "response.h" #include "log.h" #include "util.h" +#include "meinheld.h" #define CRLF "\r\n" #define DELIM ": " @@ -315,7 +316,19 @@ write_headers(client_t *client, char *data, size_t datalen) object1 = PyTuple_GET_ITEM(tuple, 0); object2 = PyTuple_GET_ITEM(tuple, 1); - + +#ifdef PY3 + if (PyUnicode_Check(object1)) { + PyObject *latin1; + + latin1 = PyUnicode_AsLatin1String(object1); + if(latin1 == NULL){ + goto error; + } + Py_DECREF(object1); + object1 = latin1; + } +#endif if (PyBytes_Check(object1)) { PyBytes_AsStringAndSize(object1, &name, &namelen); }else { @@ -325,6 +338,18 @@ write_headers(client_t *client, char *data, size_t datalen) goto error; } +#ifdef PY3 + if (PyUnicode_Check(object2)) { + PyObject *latin1; + + latin1 = PyUnicode_AsLatin1String(object2); + if(latin1 == NULL){ + goto error; + } + Py_DECREF(object2); + object2 = latin1; + } +#endif if (PyBytes_Check(object2)) { PyBytes_AsStringAndSize(object2, &value, &valuelen); }else { @@ -373,7 +398,7 @@ write_headers(client_t *client, char *data, size_t datalen) } //header done // check content_length_set - if(data && !client->content_length_set && client->http->http_minor == 1){ + if(data && !client->content_length_set && client->http_parser->http_minor == 1){ //Transfer-Encoding chunked add_header(bucket, "Transfer-Encoding", 17, "chunked", 7); client->chunked_response = 1; @@ -594,7 +619,7 @@ processs_write(client_t *client) } } }else{ - PyErr_SetString(PyExc_TypeError, "response item must be a string"); + PyErr_SetString(PyExc_TypeError, "response item must be a byte string"); Py_DECREF(item); if (PyErr_Occurred()){ write_error_log(__FILE__, __LINE__); @@ -788,16 +813,15 @@ ResponseObject_call(PyObject *obj, PyObject *args, PyObject *kw) ResponseObject *self = NULL; self = (ResponseObject *)obj; - if (!PyArg_ParseTuple(args, "SO|O:start_response", &status, &headers, &exc_info)){ +#ifdef PY3 + if (!PyArg_ParseTuple(args, "UO|O:start_response", &status, &headers, &exc_info)){ return NULL; } - - if (!PyBytes_Check(status)) { - PyErr_Format(PyExc_TypeError, "expected byte string object for " - "status, value of type %.200s found", - status->ob_type->tp_name); +#else + if (!PyArg_ParseTuple(args, "SO|O:start_response", &status, &headers, &exc_info)){ return NULL; } +#endif if (!PyList_Check(headers)) { PyErr_SetString(PyExc_TypeError, "response headers must be a list"); @@ -822,9 +846,15 @@ ResponseObject_call(PyObject *obj, PyObject *args, PyObject *kw) return NULL; } - char buf[PyBytes_GET_SIZE(status)]; + char buf[NATIVE_GET_STRING_SIZE(status)]; status_line = buf; - strcpy(status_line, PyBytes_AS_STRING(status)); + /* strncpy(status_line, (char*)NATIVE_ASSTRING(status), NATIVE_GET_STRING_SIZE(status)); */ + strcpy(status_line, (char*)NATIVE_ASSTRING(status)); + + if (!*status_line) { + PyErr_SetString(PyExc_ValueError, "status message was not supplied"); + return NULL; + } status_code = strsep((char **)&status_line, " "); @@ -836,10 +866,6 @@ ResponseObject_call(PyObject *obj, PyObject *args, PyObject *kw) return NULL; } - if (!*status_line) { - PyErr_SetString(PyExc_ValueError, "status message was not supplied"); - return NULL; - } if (int_code < 100 || int_code > 999) { PyErr_SetString(PyExc_ValueError, "status code is invalid"); @@ -854,7 +880,7 @@ ResponseObject_call(PyObject *obj, PyObject *args, PyObject *kw) Py_XDECREF(self->cli->http_status); - if(self->cli->http->http_minor == 1){ + if(self->cli->http_parser->http_minor == 1){ self->cli->http_status = PyBytes_FromFormat("HTTP/1.1 %s\r\n", PyBytes_AS_STRING(status)); }else{ self->cli->http_status = PyBytes_FromFormat("HTTP/1.0 %s\r\n", PyBytes_AS_STRING(status)); diff --git a/meinheld/server/server.c b/meinheld/server/server.c index 06f9003..35912cc 100644 --- a/meinheld/server/server.c +++ b/meinheld/server/server.c @@ -51,7 +51,7 @@ static int err_log_fd = -1; //error log static int is_keep_alive = 0; //keep alive support static int keep_alive_timeout = 5; -int max_content_length = 1024 * 1024 * 16; //max_content_length +uint64_t max_content_length = 1024 * 1024 * 16; //max_content_length int client_body_buffer_size = 1024 * 500; //client_body_buffer_size static char *unix_sock_name = NULL; @@ -217,8 +217,8 @@ close_conn(client_t *cli, picoev_loop* loop) return ; } - if(cli->http != NULL){ - PyMem_Free(cli->http); + if(cli->http_parser != NULL){ + PyMem_Free(cli->http_parser); } free_request_queue(cli->request_queue); @@ -310,16 +310,20 @@ process_resume_wsgi_app(ClientObject *pyclient) return -1; } #ifdef PY3 - if(!PyLong_Check(res)){ + if(PyLong_Check(res)){ if(PyLong_AS_LONG(res) == -1){ + // suspend process + return 0; + } + } #else - if(!PyInt_Check(res)){ + if(PyInt_Check(res)){ if(PyInt_AS_LONG(res) == -1){ -#endif // suspend process return 0; } } +#endif client->response = res; //next send response @@ -373,16 +377,20 @@ process_wsgi_app(client_t *cli) } #ifdef PY3 - if(!PyLong_Check(res)){ + if(PyLong_Check(res)){ if(PyLong_AS_LONG(res) == -1){ + // suspend process + return 0; + } + } #else - if(!PyInt_Check(res)){ + if(PyInt_Check(res)){ if(PyInt_AS_LONG(res) == -1){ -#endif // suspend process return 0; } } +#endif //next send response cli->response = res; @@ -587,7 +595,7 @@ check_http_expect(client_t *client) char *val = NULL; int ret; - if(client->http->http_minor == 1){ + if(client->http_parser->http_minor == 1){ c = PyDict_GetItemString(client->environ, "HTTP_EXPECT"); if(c){ val = PyBytes_AS_STRING(c); @@ -657,7 +665,7 @@ prepare_call_wsgi(client_t *client) if(is_keep_alive){ //support keep-alive c = PyDict_GetItemString(client->environ, "HTTP_CONNECTION"); - if(client->http->http_minor == 1){ + if(client->http_parser->http_minor == 1){ //HTTP 1.1 if(c){ val = PyBytes_AS_STRING(c); @@ -877,9 +885,9 @@ setup_server_env(void) InputObject_list_fill(); hub_switch_value = Py_BuildValue("(i)", -1); - client_key = PyBytes_FromString("meinheld.client"); - wsgi_input_key = PyBytes_FromString("wsgi.input"); - empty_string = PyBytes_FromString(""); + client_key = NATIVE_FROMSTRING("meinheld.client"); + wsgi_input_key = NATIVE_FROMSTRING("wsgi.input"); + empty_string = NATIVE_FROMSTRING(""); } static void @@ -1143,12 +1151,24 @@ meinheld_access_log(PyObject *self, PyObject *args) static PyObject * meinheld_error_log(PyObject *self, PyObject *args) { - if (!PyArg_ParseTuple(args, "s:error_log", &error_log_path)) + PyObject *f = NULL; + + if (!PyArg_ParseTuple(args, "s:error_log", &error_log_path)){ return NULL; + } if(err_log_fd > 0){ close(err_log_fd); } - PyObject *f = PyFile_FromString(error_log_path, "a"); +#ifdef PY3 + int fd = open(error_log_path, O_CREAT|O_APPEND|O_WRONLY, 0744); + if(fd < 0){ + PyErr_Format(PyExc_TypeError, "not open file. %s", error_log_path); + return NULL; + } + f = PyFile_FromFd(fd, NULL, NULL, -1, NULL, NULL, NULL, 1); +#else + f = PyFile_FromString(error_log_path, "a"); +#endif if(!f){ PyErr_Format(PyExc_TypeError, "not open file. %s", error_log_path); return NULL; diff --git a/meinheld/server/server.h b/meinheld/server/server.h index 64be5cb..8ec39a9 100644 --- a/meinheld/server/server.h +++ b/meinheld/server/server.h @@ -7,7 +7,7 @@ #include "http_parser.h" -extern int max_content_length; //max_content_length +extern uint64_t max_content_length; //max_content_length extern int client_body_buffer_size; //client_body_buffer_size extern picoev_loop* main_loop; //main loop extern PyObject* hub_switch_value; diff --git a/meinheld/server/stringio.c b/meinheld/server/stringio.c.old similarity index 100% rename from meinheld/server/stringio.c rename to meinheld/server/stringio.c.old diff --git a/setup.py b/setup.py index 4c06c8f..60c6279 100644 --- a/setup.py +++ b/setup.py @@ -8,25 +8,45 @@ import sys import os.path import platform +import fnmatch def read(name): return open(os.path.join(os.path.dirname(__file__), name)).read() -if "posix" not in os.name: - print("Are you really running a posix compliant OS ?") - print("Be posix compliant is mandatory") - sys.exit(1) +def check_platform(): + if "posix" not in os.name: + print("Are you really running a posix compliant OS ?") + print("Be posix compliant is mandatory") + sys.exit(1) +def get_picoev_file(): + poller_file = None -if "Linux" == platform.system(): - poller_file = 'meinheld/server/picoev_epoll.c' -elif "Darwin" == platform.system(): - poller_file = 'meinheld/server/picoev_kqueue.c' -elif "FreeBSD" == platform.system(): - poller_file = 'meinheld/server/picoev_kqueue.c' -else: - print("Sorry, not support .") - sys.exit(1) + if "Linux" == platform.system(): + poller_file = 'meinheld/server/picoev_epoll.c' + elif "Darwin" == platform.system(): + poller_file = 'meinheld/server/picoev_kqueue.c' + elif "FreeBSD" == platform.system(): + poller_file = 'meinheld/server/picoev_kqueue.c' + else: + print("Sorry, not support .") + sys.exit(1) + return poller_file + +def get_sources(path, ignore_files): + src = [] + for root, dirs , files in os.walk(path): + for file in files: + src_path = os.path.join(root, file) + #ignore = reduce(lambda x, y: x or y, [fnmatch.fnmatch(src_path, i) for i in ignore_files]) + ignore = [i for i in ignore_files if fnmatch.fnmatch(src_path, i)] + if not ignore and src_path.endswith(".c"): + src.append(src_path) + return src + +check_platform() +sources = get_sources("meinheld", ["*picoev_*"]) +sources.append(get_picoev_file()) library_dirs=['/usr/local/lib'] include_dirs=[] @@ -52,21 +72,17 @@ def read(name): """, ext_modules = [ Extension('meinheld.server', - sources=['meinheld/server/server.c', poller_file, - 'meinheld/server/http_parser.c','meinheld/server/http_request_parser.c', - 'meinheld/server/response.c', 'meinheld/server/time_cache.c', 'meinheld/server/log.c', - 'meinheld/server/buffer.c', 'meinheld/server/request.c', - 'meinheld/server/client.c', 'meinheld/server/util.c', - 'meinheld/server/input.c', 'meinheld/server/greensupport.c'], - include_dirs=include_dirs, - library_dirs=library_dirs, - #libraries=["profiler"], - define_macros=[ - ("DEVELOP",None), - ("WITH_GREENLET",None), - ("HTTP_PARSER_DEBUG", "0") - ], - )], + sources=sources, + include_dirs=include_dirs, + library_dirs=library_dirs, + #libraries=["profiler"], + #extra_compile_args=["-save-temps"], + define_macros=[ + ("DEVELOP",None), + ("WITH_GREENLET",None), + ("HTTP_PARSER_DEBUG", "0") + ], + )], classifiers=[ 'Development Status :: 4 - Beta', diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..0f39838 --- /dev/null +++ b/tox.ini @@ -0,0 +1,5 @@ +[tox] +envlist = py27,py32 +[testenv] +deps=pytest +commands=py.test