Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-bjoern for openSUSE:Factory checked in at 2022-10-12 18:26:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-bjoern (Old) and /work/SRC/openSUSE:Factory/.python-bjoern.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-bjoern" Wed Oct 12 18:26:44 2022 rev:10 rq:1010198 version:3.2.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-bjoern/python-bjoern.changes 2020-06-24 15:49:23.708533019 +0200 +++ /work/SRC/openSUSE:Factory/.python-bjoern.new.2275/python-bjoern.changes 2022-10-12 18:28:25.826183715 +0200 @@ -1,0 +2,13 @@ +Wed Oct 12 02:47:21 UTC 2022 - Yogalakshmi Arunachalam <[email protected]> + +- Update to version 3.2.2: + * #228, 235 Fix libev paths (Ian Swanson, Nicolas Damgaard Larsen) + * #234 Set ``wsgi.input_terminated`` (Nathan Hoad) + * Update PyPI description + * #173 Fix segfault with old interpreters (Goldstein) + * #171 Implement FileWrapper.close() + * Fix FileWrapper/sendfile with offset + * #184 Fix compile flags + * #218 Fix SERVER_PORT (Souheil Chelfouh) + +------------------------------------------------------------------- Old: ---- bjoern-3.1.0.tar.gz New: ---- bjoern-3.2.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-bjoern.spec ++++++ --- /var/tmp/diff_new_pack.FJ0wZ8/_old 2022-10-12 18:28:26.190184516 +0200 +++ /var/tmp/diff_new_pack.FJ0wZ8/_new 2022-10-12 18:28:26.194184525 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-bjoern # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-bjoern -Version: 3.1.0 +Version: 3.2.2 Release: 0 Summary: A screamingly fast Python 2 + 3 WSGI server written in C License: BSD-2-Clause ++++++ bjoern-3.1.0.tar.gz -> bjoern-3.2.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/.gitmodules new/bjoern-3.2.2/.gitmodules --- old/bjoern-3.1.0/.gitmodules 2019-10-19 14:58:30.000000000 +0200 +++ new/bjoern-3.2.2/.gitmodules 2021-04-21 14:03:05.000000000 +0200 @@ -1,6 +1,6 @@ [submodule "http-parser"] path = http-parser - url = git://github.com/joyent/http-parser + url = https://github.com/joyent/http-parser [submodule "statsd-c-client"] path = statsd-c-client url = https://github.com/romanbsd/statsd-c-client diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/CHANGELOG new/bjoern-3.2.2/CHANGELOG --- old/bjoern-3.1.0/CHANGELOG 2019-11-03 10:44:04.000000000 +0100 +++ new/bjoern-3.2.2/CHANGELOG 2022-09-11 20:40:07.000000000 +0200 @@ -1,3 +1,18 @@ +3.2.2 (Sep 11, 2022) + - #228, 235 Fix libev paths (Ian Swanson, Nicolas Damgaard Larsen) + - #234 Set ``wsgi.input_terminated`` (Nathan Hoad) + - Update PyPI description + +3.2.1 (Feb 14, 2022) + - Fix release + +3.2.0 (Feb 13, 2022) + - #173 Fix segfault with old interpreters (Goldstein) + - #171 Implement FileWrapper.close() + - Fix FileWrapper/sendfile with offset + - #184 Fix compile flags + - #218 Fix SERVER_PORT (Souheil Chelfouh) + 3.1.0 (Nov 3, 2019) - #169 Fix blocking accept() (Ionut Negru) - #164 Add support for statsd metrics/events (Mohammad Gufran) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/Makefile new/bjoern-3.2.2/Makefile --- old/bjoern-3.1.0/Makefile 2019-11-03 10:43:15.000000000 +0100 +++ new/bjoern-3.2.2/Makefile 2022-09-11 20:37:14.000000000 +0200 @@ -59,8 +59,8 @@ CFLAGS='-Os' make _bjoernmodule: - @echo ' -> ' $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(objects) -o $(BUILD_DIR)/_bjoern.so - @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(objects) -o $(BUILD_DIR)/_bjoern.so + @echo ' -> ' $(CC) $(CPPFLAGS) $(CFLAGS) $(objects) $(LDFLAGS) -o $(BUILD_DIR)/_bjoern.so + @$(CC) $(CPPFLAGS) $(CFLAGS) $(objects) $(LDFLAGS) -o $(BUILD_DIR)/_bjoern.so @PYTHONPATH=$$PYTHONPATH:$(BUILD_DIR) ${PYTHON} -c "import bjoern" again: clean all @@ -82,6 +82,9 @@ clean: @rm -rf $(BUILD_DIR)/* +distclean: + @rm -rf dist/ + AB = ab -c 100 -n 10000 TEST_URL = "http://127.0.0.1:8080/a/b/c?k=v&k2=v2" @@ -113,11 +116,15 @@ echo; echo; \ tail -n +25 /proc/$$(pgrep -n ${PYTHON})/smaps' -upload: - ${PYTHON} setup.py sdist upload +packages: + ${PYTHON} setup.py sdist + $(MAKE) -C packaging all + +upload: packages + twine upload dist/*.tar.gz dist/*.whl $(HTTP_PARSER_OBJ): $(MAKE) -C $(HTTP_PARSER_DIR) http_parser.o CFLAGS_DEBUG_EXTRA=-fPIC CFLAGS_FAST_EXTRA=-fPIC $(STATSD_CLIENT_OBJ): - $(MAKE) -C $(STATSD_CLIENT_DIR) statsd-client.o CFLAGS_DEBUG_EXTRA=-fPIC CFLAGS_FAST_EXTRA=-fPIC + $(MAKE) -C $(STATSD_CLIENT_DIR) statsd-client.o CFLAGS=-fPIC diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/PKG-INFO new/bjoern-3.2.2/PKG-INFO --- old/bjoern-3.1.0/PKG-INFO 2019-11-03 10:45:13.000000000 +0100 +++ new/bjoern-3.2.2/PKG-INFO 2022-09-11 20:48:02.896385400 +0200 @@ -1,16 +1,111 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: bjoern -Version: 3.1.0 +Version: 3.2.2 Summary: A screamingly fast Python 2 + 3 WSGI server written in C. Home-page: https://github.com/jonashaag/bjoern Author: Jonas Haag Author-email: [email protected] License: 2-clause BSD -Description: UNKNOWN -Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: C Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server +License-File: LICENSE + +bjoern: Fast And Ultra-Lightweight HTTP/1.1 WSGI Server +======================================================= + +.. image:: https://badges.gitter.im/Join%20Chat.svg + :alt: Join the chat at https://gitter.im/jonashaag/bjoern + :target: https://gitter.im/jonashaag/bjoern?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + +A screamingly fast, ultra-lightweight WSGI_ server for CPython 2 and CPython 3, +written in C using Marc Lehmann's high performance libev_ event loop and +Ryan Dahl's http-parser_. + +Why It's Cool +~~~~~~~~~~~~~ +bjoern is the *fastest*, *smallest* and *most lightweight* WSGI server out there, +featuring + +* ~ 1000 lines of C code +* Memory footprint ~ 600KB +* Python 2 and Python 3 support (thanks @yanghao!) +* Single-threaded and without coroutines or other crap +* Can bind to TCP `host:port` addresses and Unix sockets (thanks @k3d3!) +* Full persistent connection ("*keep-alive*") support in both HTTP/1.0 and 1.1, + including support for HTTP/1.1 chunked responses + +Installation +~~~~~~~~~~~~ +``pip install bjoern``. See `wiki <https://github.com/jonashaag/bjoern/wiki/Installation>`_ for details. + +Usage +~~~~~ + +Flask example +------------- + +.. code-block:: python + + from flask import Flask + + app = Flask(__name__) + + @app.route("/") + def hello_world(): + return "Hello, World!" + + if __name__ == "__main__": + import bjoern + + bjoern.run(app, "127.0.0.1", 8000) + + +Advanced usage +-------------- + +.. code-block:: python + + # Bind to TCP host/port pair: + bjoern.run(wsgi_application, host, port) + + # TCP host/port pair, enabling SO_REUSEPORT if available. + bjoern.run(wsgi_application, host, port, reuse_port=True) + + # Bind to Unix socket: + bjoern.run(wsgi_application, 'unix:/path/to/socket') + + # Bind to abstract Unix socket: (Linux only) + bjoern.run(wsgi_application, 'unix:@socket_name') + + # Enable statsd metrics. See instrumentation.md for details. + bjoern.run(wsgi_application, host, port, statsd=...) + +Alternatively, the mainloop can be run separately: + +.. code-block:: python + + bjoern.listen(wsgi_application, host, port) + bjoern.run() + + # With metrics. See instrumentation.md for details. + bjoern.listen(wsgi_application, host, port) + bjoern.run(statsd=...) + +You can also simply pass a Python socket(-like) object. Note that you are responsible +for initializing and cleaning up the socket in that case. + +.. code-block:: python + + bjoern.server_run(socket_object, wsgi_application) + bjoern.server_run(filedescriptor_as_integer, wsgi_application) + + # This needs manual compilation with `WANT_STATSD=yes` + bjoern.server_run(socket_object, wsgi_application, enable_statsd=True) + +.. _WSGI: http://www.python.org/dev/peps/pep-0333/ +.. _libev: http://software.schmorp.de/pkg/libev.html +.. _http-parser: https://github.com/joyent/http-parser diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/README.rst new/bjoern-3.2.2/README.rst --- old/bjoern-3.1.0/README.rst 2019-10-19 14:58:30.000000000 +0200 +++ new/bjoern-3.2.2/README.rst 2021-04-21 14:03:05.000000000 +0200 @@ -28,7 +28,30 @@ Usage ~~~~~ -:: + +Flask example +------------- + +.. code-block:: python + + from flask import Flask + + app = Flask(__name__) + + @app.route("/") + def hello_world(): + return "Hello, World!" + + if __name__ == "__main__": + import bjoern + + bjoern.run(app, "127.0.0.1", 8000) + + +Advanced usage +-------------- + +.. code-block:: python # Bind to TCP host/port pair: bjoern.run(wsgi_application, host, port) @@ -45,7 +68,9 @@ # Enable statsd metrics. See instrumentation.md for details. bjoern.run(wsgi_application, host, port, statsd=...) -Alternatively, the mainloop can be run separately:: +Alternatively, the mainloop can be run separately: + +.. code-block:: python bjoern.listen(wsgi_application, host, port) bjoern.run() @@ -55,7 +80,9 @@ bjoern.run(statsd=...) You can also simply pass a Python socket(-like) object. Note that you are responsible -for initializing and cleaning up the socket in that case. :: +for initializing and cleaning up the socket in that case. + +.. code-block:: python bjoern.server_run(socket_object, wsgi_application) bjoern.server_run(filedescriptor_as_integer, wsgi_application) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/_bjoernmodule.c new/bjoern-3.2.2/bjoern/_bjoernmodule.c --- old/bjoern-3.1.0/bjoern/_bjoernmodule.c 2019-11-03 10:44:28.000000000 +0100 +++ new/bjoern-3.2.2/bjoern/_bjoernmodule.c 2022-09-11 20:38:11.000000000 +0200 @@ -164,7 +164,7 @@ #endif PyModule_AddObject(bjoern_module, "features", features); - PyModule_AddObject(bjoern_module, "version", Py_BuildValue("(iii)", 3, 1, 0)); + PyModule_AddObject(bjoern_module, "version", Py_BuildValue("(iii)", 3, 2, 2)); #if PY_MAJOR_VERSION >= 3 return bjoern_module; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/filewrapper.c new/bjoern-3.2.2/bjoern/filewrapper.c --- old/bjoern-3.1.0/bjoern/filewrapper.c 2019-07-15 11:19:46.000000000 +0200 +++ new/bjoern-3.2.2/bjoern/filewrapper.c 2019-12-14 17:37:17.000000000 +0100 @@ -8,13 +8,6 @@ return FW_self->fd; } -void FileWrapper_Done(PyObject *self) -{ - if (FW_self->fd != -1) { - PyFile_DecUseCount((PyFileObject*)FW_self->file); - } -} - static PyObject* FileWrapper_New(PyTypeObject* cls, PyObject* args, PyObject* kwargs) { @@ -67,6 +60,23 @@ PyObject_FREE(self); } +PyObject* FileWrapper_close(PyObject* self) +{ + if (PyObject_HasAttr(FW_self->file, _close)) { + return PyObject_CallMethodObjArgs(FW_self->file, _close, NULL); + } else { + Py_RETURN_NONE; + } + if (FW_self->fd != -1) { + PyFile_DecUseCount((PyFileObject*)FW_self->file); + } +} + +static PyMethodDef FileWrapper_methods[] = { + {"close", (PyCFunction) FileWrapper_close, METH_NOARGS, NULL}, + {NULL} /* Sentinel */ +}; + PyTypeObject FileWrapper_Type = { PyVarObject_HEAD_INIT(NULL, 0) "FileWrapper", /* tp_name (__name__) */ @@ -81,4 +91,5 @@ FileWrapper_Type.tp_iter = FileWrapper_Iter; FileWrapper_Type.tp_iternext = FileWrapper_IterNext; FileWrapper_Type.tp_flags |= Py_TPFLAGS_DEFAULT; + FileWrapper_Type.tp_methods = FileWrapper_methods; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/filewrapper.h new/bjoern-3.2.2/bjoern/filewrapper.h --- old/bjoern-3.1.0/bjoern/filewrapper.h 2019-07-15 11:19:46.000000000 +0200 +++ new/bjoern-3.2.2/bjoern/filewrapper.h 2019-12-14 17:37:17.000000000 +0100 @@ -13,4 +13,3 @@ void _init_filewrapper(void); int FileWrapper_GetFd(PyObject *self); -void FileWrapper_Done(PyObject *self); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/py2py3.h new/bjoern-3.2.2/bjoern/py2py3.h --- old/bjoern-3.1.0/bjoern/py2py3.h 2019-09-12 09:31:24.000000000 +0200 +++ new/bjoern-3.2.2/bjoern/py2py3.h 2019-12-14 17:37:17.000000000 +0100 @@ -15,6 +15,11 @@ #define _PEP3333_BytesLatin1_FromUnicode(u) PyUnicode_AsLatin1String(u) #define _PEP3333_String_FromUTF8String(data) PyUnicode_FromString(data) #define _PEP3333_String_FromLatin1StringAndSize(data, len) PyUnicode_DecodeLatin1(data, len, "replace") +// Shouldn't use FromFormat here because of Python bug: +// https://bugs.python.org/issue33817 +// While problem with PyUnicode_FromString("") was not reported, it's still better +// to create empty string without formatting +#define _PEP3333_String_Empty() PyUnicode_FromString("") #define _PEP3333_String_FromFormat(...) PyUnicode_FromFormat(__VA_ARGS__) #define _PEP3333_String_GET_SIZE(u) PyUnicode_GET_LENGTH(u) #define _PEP3333_String_Concat(u1, u2) PyUnicode_Concat(u1, u2) @@ -31,6 +36,10 @@ #define _PEP3333_Bytes_Resize(bytes, len) _PyString_Resize(bytes, len) #define _PEP3333_BytesLatin1_FromUnicode(u) (Py_INCREF(u),u) #define _PEP3333_String_FromUTF8String(data) PyString_FromString(data) // Assume UTF8 +// Can't use FromFormat here because of Python bug: +// https://bugs.python.org/issue33817 +// Arguments (NULL, 0) will create empty string, it's explicitly allowed +#define _PEP3333_String_Empty() PyString_FromStringAndSize(NULL, 0) #define _PEP3333_String_FromFormat(...) PyString_FromFormat(__VA_ARGS__) #define _PEP3333_String_GET_SIZE(u) PyString_GET_SIZE(u) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/request.c new/bjoern-3.2.2/bjoern/request.c --- old/bjoern-3.1.0/bjoern/request.c 2019-09-12 09:31:24.000000000 +0200 +++ new/bjoern-3.2.2/bjoern/request.c 2022-09-11 20:37:14.000000000 +0200 @@ -50,7 +50,8 @@ void Request_clean(Request* request) { if(request->iterable) { - /* Call 'iterable.close()' if available */ + /* Call 'iterable.close()' if available. This will also call into FileWrapper_close() + * if 'iterable' is a FileWrapper object. */ PyObject* close_method = PyObject_GetAttr(request->iterable, _close); if(close_method == NULL) { if(PyErr_ExceptionMatches(PyExc_AttributeError)) @@ -349,6 +350,16 @@ PyTuple_Pack(2, _FromLong(1), _FromLong(0)) ); + /* dct['wsgi.input_terminated'] = True + * (Tell Flask/other WSGI apps that the input has been terminated, so that chunked + * transfer-encoding can be used in requests. This can be hard coded as bjoern + * provides the body as a BytesIO object.) */ + PyDict_SetItemString( + wsgi_base_dict, + "wsgi.input_terminated", + Py_True + ); + /* dct['wsgi.url_scheme'] = 'http' * (This can be hard-coded as there is no TLS support in bjoern.) */ Py_INCREF(_http); @@ -398,14 +409,14 @@ PyDict_SetItemString(wsgi_base_dict, "SERVER_NAME", server_info->host); if (server_info->port == Py_None) { - PyDict_SetItemString(wsgi_base_dict, "SERVER_PORT", _PEP3333_String_FromFormat("")); + PyDict_SetItemString(wsgi_base_dict, "SERVER_PORT", _PEP3333_String_Empty()); } else { - PyDict_SetItemString(wsgi_base_dict, "SERVER_PORT", _PEP3333_String_FromFormat("%i", server_info->port)); + PyDict_SetItemString(wsgi_base_dict, "SERVER_PORT", _PEP3333_String_FromFormat("%S", server_info->port)); } } else { /* SERVER_NAME is required, but not usefull with UNIX type sockets */ - PyDict_SetItemString(wsgi_base_dict, "SERVER_NAME", _PEP3333_String_FromFormat("")); - PyDict_SetItemString(wsgi_base_dict, "SERVER_PORT", _PEP3333_String_FromFormat("")); + PyDict_SetItemString(wsgi_base_dict, "SERVER_NAME", _PEP3333_String_Empty()); + PyDict_SetItemString(wsgi_base_dict, "SERVER_PORT", _PEP3333_String_Empty()); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/server.c new/bjoern-3.2.2/bjoern/server.c --- old/bjoern-3.1.0/bjoern/server.c 2019-11-03 10:42:57.000000000 +0100 +++ new/bjoern-3.2.2/bjoern/server.c 2022-09-11 20:37:14.000000000 +0200 @@ -24,7 +24,6 @@ #endif #define READ_BUFFER_SIZE 64*1024 -#define Py_XCLEAR(obj) do { if(obj) { Py_DECREF(obj); obj = NULL; } } while(0) #define GIL_LOCK(n) PyGILState_STATE _gilstate_##n = PyGILState_Ensure() #define GIL_UNLOCK(n) PyGILState_Release(_gilstate_##n) @@ -255,7 +254,7 @@ assert(PyErr_Occurred()); PyErr_Print(); assert(!request->state.chunked_response); - Py_XCLEAR(request->iterator); + Py_CLEAR(request->iterator); request->current_chunk = _PEP3333_Bytes_FromString( http_error_messages[HTTP_SERVER_ERROR]); STATSD_INCREMENT("req.error.internal"); @@ -380,9 +379,16 @@ */ if(request->current_chunk) { /* Phase A) -- current_chunk contains the HTTP headers */ - do_send_chunk(request); - // Either we have headers left to send, or current_chunk has been set to - // NULL and we'll fall into Phase B) on the next invocation. + if (do_send_chunk(request)) { + /* Headers left to send */ + } else { + /* Done with headers, current_chunk has been set to NULL + * and we'll fall into Phase B) on the next invocation. */ + request->current_chunk_p = lseek(FileWrapper_GetFd(request->iterable), 0, SEEK_CUR); + if (request->current_chunk_p == -1) { + return aborted; + } + } return not_yet_done; } else { /* Phase B) */ @@ -500,11 +506,9 @@ if (handle_nonzero_errno(request)) { return true; } else { - FileWrapper_Done(request->iterable); return false; } case 0: - FileWrapper_Done(request->iterable); return false; default: request->current_chunk_p += bytes_sent; @@ -522,7 +526,7 @@ /* Serious transmission failure. Hang up. */ fprintf(stderr, "Client %d hit errno %d\n", request->client_fd, errno); Py_XDECREF(request->current_chunk); - Py_XCLEAR(request->iterator); + Py_CLEAR(request->iterator); request->state.keep_alive = false; return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern/wsgi.c new/bjoern-3.2.2/bjoern/wsgi.c --- old/bjoern-3.1.0/bjoern/wsgi.c 2019-09-12 10:14:48.000000000 +0200 +++ new/bjoern-3.2.2/bjoern/wsgi.c 2022-09-11 20:37:14.000000000 +0200 @@ -182,22 +182,32 @@ return true; } -static inline bool -inspect_headers(Request* request) +static inline PyObject* +clean_headers(PyObject* headers, bool* found_content_length) { - Py_ssize_t i; - PyObject* tuple; - if(!PyList_Check(request->headers)) { - TYPE_ERROR("start response argument 2", "a list of 2-tuples", request->headers); + if(!PyList_Check(headers)) { + TYPE_ERROR("start response argument 2", "a list of 2-tuples", headers); return NULL; } - for(i=0; i<PyList_GET_SIZE(request->headers); ++i) { - tuple = PyList_GET_ITEM(request->headers, i); + for(Py_ssize_t i=0; i<PyList_GET_SIZE(headers); ++i) { + PyObject* tuple = PyList_GET_ITEM(headers, i); + if(!PyTuple_Check(tuple) || PyTuple_GET_SIZE(tuple) != 2) { + TYPE_ERROR_INNER("start_response argument 2", "a list of 2-tuples (field: str, value: str)", + "(found invalid '%.200s' object at position %zd)", Py_TYPE(tuple)->tp_name, i); + return NULL; + } + } + + /* Create copy of headers list that we may modify */ + PyObject* new_headers = PyList_New(PyList_GET_SIZE(headers)); + if (new_headers == NULL) { + return NULL; + } - if(!PyTuple_Check(tuple) || PyTuple_GET_SIZE(tuple) != 2) - goto err; + for(Py_ssize_t i=0; i<PyList_GET_SIZE(headers); ++i) { + PyObject* tuple = PyList_GET_ITEM(headers, i); PyObject* unicode_field = PyTuple_GET_ITEM(tuple, 0); PyObject* unicode_value = PyTuple_GET_ITEM(tuple, 1); @@ -206,26 +216,23 @@ PyObject* bytes_value = _PEP3333_BytesLatin1_FromUnicode(unicode_value); if (bytes_field == NULL || bytes_value == NULL) { + TYPE_ERROR_INNER("start_response argument 2", "a list of 2-tuples (field: str, value: str)", + "(found invalid ('%.200s', '%.200s') tuple at position %zd)", Py_TYPE(unicode_field)->tp_name, Py_TYPE(unicode_value)->tp_name, i); + Py_DECREF(new_headers); Py_XDECREF(bytes_field); Py_XDECREF(bytes_value); - goto err; + return NULL; } - PyList_SET_ITEM(request->headers, i, PyTuple_Pack(2, bytes_field, bytes_value)); - Py_DECREF(tuple); + PyList_SET_ITEM(new_headers, i, PyTuple_Pack(2, bytes_field, bytes_value)); if(!strncasecmp(_PEP3333_Bytes_AS_DATA(bytes_field), "Content-Length", _PEP3333_Bytes_GET_SIZE(bytes_field))) - request->state.response_length_unknown = false; + *found_content_length = true; Py_DECREF(bytes_field); Py_DECREF(bytes_value); } - return true; - -err: - TYPE_ERROR_INNER("start_response argument 2", "a list of 2-tuples (field: str, value: str)", - "(found invalid '%.200s' object at position %zd)", Py_TYPE(tuple)->tp_name, i); - return false; + return new_headers; } @@ -336,7 +343,8 @@ PyObject* exc_info = NULL; PyObject* status_unicode = NULL; - if(!PyArg_UnpackTuple(args, "start_response", 2, 3, &status_unicode, &request->headers, &exc_info)) + PyObject* headers = NULL; + if(!PyArg_UnpackTuple(args, "start_response", 2, 3, &status_unicode, &headers, &exc_info)) return NULL; if(exc_info && exc_info != Py_None) { @@ -372,13 +380,14 @@ return NULL; } - if(!inspect_headers(request)) { - request->headers = NULL; + + bool found_content_length = false; + request->headers = clean_headers(headers, &found_content_length); + if (request->headers == NULL) { return NULL; } - Py_INCREF(request->headers); - + request->state.response_length_unknown = !found_content_length; request->state.start_response_called = true; Py_RETURN_NONE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/bjoern.egg-info/PKG-INFO new/bjoern-3.2.2/bjoern.egg-info/PKG-INFO --- old/bjoern-3.1.0/bjoern.egg-info/PKG-INFO 2019-11-03 10:45:13.000000000 +0100 +++ new/bjoern-3.2.2/bjoern.egg-info/PKG-INFO 2022-09-11 20:48:02.000000000 +0200 @@ -1,16 +1,111 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: bjoern -Version: 3.1.0 +Version: 3.2.2 Summary: A screamingly fast Python 2 + 3 WSGI server written in C. Home-page: https://github.com/jonashaag/bjoern Author: Jonas Haag Author-email: [email protected] License: 2-clause BSD -Description: UNKNOWN -Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: C Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server +License-File: LICENSE + +bjoern: Fast And Ultra-Lightweight HTTP/1.1 WSGI Server +======================================================= + +.. image:: https://badges.gitter.im/Join%20Chat.svg + :alt: Join the chat at https://gitter.im/jonashaag/bjoern + :target: https://gitter.im/jonashaag/bjoern?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + +A screamingly fast, ultra-lightweight WSGI_ server for CPython 2 and CPython 3, +written in C using Marc Lehmann's high performance libev_ event loop and +Ryan Dahl's http-parser_. + +Why It's Cool +~~~~~~~~~~~~~ +bjoern is the *fastest*, *smallest* and *most lightweight* WSGI server out there, +featuring + +* ~ 1000 lines of C code +* Memory footprint ~ 600KB +* Python 2 and Python 3 support (thanks @yanghao!) +* Single-threaded and without coroutines or other crap +* Can bind to TCP `host:port` addresses and Unix sockets (thanks @k3d3!) +* Full persistent connection ("*keep-alive*") support in both HTTP/1.0 and 1.1, + including support for HTTP/1.1 chunked responses + +Installation +~~~~~~~~~~~~ +``pip install bjoern``. See `wiki <https://github.com/jonashaag/bjoern/wiki/Installation>`_ for details. + +Usage +~~~~~ + +Flask example +------------- + +.. code-block:: python + + from flask import Flask + + app = Flask(__name__) + + @app.route("/") + def hello_world(): + return "Hello, World!" + + if __name__ == "__main__": + import bjoern + + bjoern.run(app, "127.0.0.1", 8000) + + +Advanced usage +-------------- + +.. code-block:: python + + # Bind to TCP host/port pair: + bjoern.run(wsgi_application, host, port) + + # TCP host/port pair, enabling SO_REUSEPORT if available. + bjoern.run(wsgi_application, host, port, reuse_port=True) + + # Bind to Unix socket: + bjoern.run(wsgi_application, 'unix:/path/to/socket') + + # Bind to abstract Unix socket: (Linux only) + bjoern.run(wsgi_application, 'unix:@socket_name') + + # Enable statsd metrics. See instrumentation.md for details. + bjoern.run(wsgi_application, host, port, statsd=...) + +Alternatively, the mainloop can be run separately: + +.. code-block:: python + + bjoern.listen(wsgi_application, host, port) + bjoern.run() + + # With metrics. See instrumentation.md for details. + bjoern.listen(wsgi_application, host, port) + bjoern.run(statsd=...) + +You can also simply pass a Python socket(-like) object. Note that you are responsible +for initializing and cleaning up the socket in that case. + +.. code-block:: python + + bjoern.server_run(socket_object, wsgi_application) + bjoern.server_run(filedescriptor_as_integer, wsgi_application) + + # This needs manual compilation with `WANT_STATSD=yes` + bjoern.server_run(socket_object, wsgi_application, enable_statsd=True) + +.. _WSGI: http://www.python.org/dev/peps/pep-0333/ +.. _libev: http://software.schmorp.de/pkg/libev.html +.. _http-parser: https://github.com/joyent/http-parser diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/setup.py new/bjoern-3.2.2/setup.py --- old/bjoern-3.1.0/setup.py 2019-11-03 10:44:14.000000000 +0100 +++ new/bjoern-3.2.2/setup.py 2022-09-11 20:38:01.000000000 +0200 @@ -2,6 +2,8 @@ import glob from setuptools import setup, Extension +long_description = open(os.path.join(os.path.dirname(__file__), "README.rst")).read() + WANT_SIGINT_HANDLING = os.environ.get('BJOERN_WANT_SIGINT_HANDLING', True) WANT_SIGNAL_HANDLING = os.environ.get('BJOERN_WANT_SIGNAL_HANDLING', True) SIGNAL_CHECK_INTERVAL = os.environ.get('BJOERN_SIGNAL_CHECK_INTERVAL', '0.1') @@ -30,11 +32,13 @@ '_bjoern', sources = SOURCE_FILES, libraries = ['ev'], - include_dirs = ['http-parser', 'statsd-c-client', '/usr/include/libev', '/opt/local/include'], + include_dirs = ['http-parser', 'statsd-c-client', '/usr/include/libev', + '/opt/local/include', '/opt/homebrew/include', '/usr/local/include'], + library_dirs = ['/opt/homebrew/lib/', '/usr/local/lib'], define_macros = compile_flags, extra_compile_args = ['-std=c99', '-fno-strict-aliasing', '-fcommon', '-fPIC', '-Wall', '-Wextra', '-Wno-unused-parameter', - '-Wno-missing-field-initializers', '-g'] + '-Wno-missing-field-initializers', '-g'], ) setup( @@ -44,7 +48,8 @@ license = '2-clause BSD', url = 'https://github.com/jonashaag/bjoern', description = 'A screamingly fast Python 2 + 3 WSGI server written in C.', - version = '3.1.0', + version = '3.2.2', + long_description = long_description, classifiers = ['Development Status :: 4 - Beta', 'License :: OSI Approved :: BSD License', 'Programming Language :: C', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/tests/interrupt-during-request.py new/bjoern-3.2.2/tests/interrupt-during-request.py --- old/bjoern-3.1.0/tests/interrupt-during-request.py 2019-07-15 11:19:46.000000000 +0200 +++ new/bjoern-3.2.2/tests/interrupt-during-request.py 2022-09-11 20:37:14.000000000 +0200 @@ -3,7 +3,11 @@ import bjoern import os import signal -import httplib + +try: + from http import client as httplib +except ImportError: # Py 2 + import httplib HOST = ('127.0.0.1', 9000) @@ -22,7 +26,7 @@ def requester(): conn = httplib.HTTPConnection(*HOST) conn.request("GET", "/") - conn.getresponse() + print(conn.getresponse().read()) threading.Thread(target=requester).start() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/tests/keep-alive-behaviour.py new/bjoern-3.2.2/tests/keep-alive-behaviour.py --- old/bjoern-3.1.0/tests/keep-alive-behaviour.py 2019-07-15 11:19:46.000000000 +0200 +++ new/bjoern-3.2.2/tests/keep-alive-behaviour.py 2021-04-21 14:03:05.000000000 +0200 @@ -1,10 +1,11 @@ import os import random +import socket + try: + from http import client as httplib +except ImportError: # Py 2 import httplib -except ImportError: - import http.client as httplib -import socket HOST = ('127.0.0.1', 9000) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bjoern-3.1.0/tests/reuse_port.py new/bjoern-3.2.2/tests/reuse_port.py --- old/bjoern-3.1.0/tests/reuse_port.py 2019-07-15 11:19:46.000000000 +0200 +++ new/bjoern-3.2.2/tests/reuse_port.py 2021-04-21 14:03:05.000000000 +0200 @@ -1,10 +1,14 @@ import os import time import sys -import httplib import subprocess from collections import defaultdict +try: + from http import client as httplib +except ImportError: # Py 2 + import httplib + N_PROCESSES = 3 N_REQUESTS_PER_PROCESS = 100
