diff -Nru uwsgi-2.0.14+20170111/core/hooks.c uwsgi-2.0.15/core/hooks.c --- uwsgi-2.0.14+20170111/core/hooks.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/core/hooks.c 2017-03-30 22:11:36.000000000 +0000 @@ -591,6 +591,43 @@ return uwsgi_wait_for_socket(arg); } +static int spinningfifo_hook(char *arg) { + int fd; + char *space = strchr(arg, ' '); + if (!space) { + uwsgi_log("invalid hook spinningfifo syntax, must be: \n"); + return -1; + } + *space = 0; +retry: + uwsgi_log("waiting for %s ...\n", arg); + fd = open(arg, O_WRONLY|O_NONBLOCK); + if (fd < 0) { + if (errno == ENODEV || errno == ENOENT) { + sleep(1); + goto retry; + } +#ifdef ENXIO + if (errno == ENXIO) { + sleep(1); + goto retry; + } +#endif + uwsgi_error_open(arg); + *space = ' '; + return -1; + } + *space = ' '; + size_t l = strlen(space+1); + if (write(fd, space+1, l) != (ssize_t) l) { + uwsgi_error("spinningfifo_hook()/write()"); + close(fd); + return -1; + } + close(fd); + return 0; +} + void uwsgi_register_base_hooks() { uwsgi_register_hook("cd", uwsgi_hook_chdir); uwsgi_register_hook("chdir", uwsgi_hook_chdir); @@ -640,6 +677,8 @@ uwsgi_register_hook("unix_signal", uwsgi_hook_unix_signal); + uwsgi_register_hook("spinningfifo", spinningfifo_hook); + // for testing uwsgi_register_hook("exit", uwsgi_hook_exit); uwsgi_register_hook("print", uwsgi_hook_print); diff -Nru uwsgi-2.0.14+20170111/core/logging.c uwsgi-2.0.15/core/logging.c --- uwsgi-2.0.14+20170111/core/logging.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/core/logging.c 2017-03-30 22:11:36.000000000 +0000 @@ -684,7 +684,10 @@ ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, time_request); #endif - uint64_t rt = wsgi_req->end_of_request - wsgi_req->start_of_request; + uint64_t rt = 0; + // avoid overflow on clock instability (#1489) + if (wsgi_req->end_of_request > wsgi_req->start_of_request) + rt = wsgi_req->end_of_request - wsgi_req->start_of_request; if (uwsgi.log_micros) { tsize = (char *) micros; diff -Nru uwsgi-2.0.14+20170111/debian/ARCHS_mongodb uwsgi-2.0.15/debian/ARCHS_mongodb --- uwsgi-2.0.14+20170111/debian/ARCHS_mongodb 2017-02-27 06:16:06.000000000 +0000 +++ uwsgi-2.0.15/debian/ARCHS_mongodb 2017-05-01 13:46:59.000000000 +0000 @@ -1 +1 @@ -amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x +amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x diff -Nru uwsgi-2.0.14+20170111/debian/changelog uwsgi-2.0.15/debian/changelog --- uwsgi-2.0.14+20170111/debian/changelog 2017-02-27 06:16:06.000000000 +0000 +++ uwsgi-2.0.15/debian/changelog 2017-05-01 22:17:49.000000000 +0000 @@ -1,11 +1,42 @@ -uwsgi (2.0.14+20170111-4ubuntu1) zesty; urgency=medium +uwsgi (2.0.15-1ubuntu2) artful; urgency=medium + + * No-change rebuild for PHP7.1. + + -- Nishanth Aravamudan Mon, 01 May 2017 15:17:49 -0700 + +uwsgi (2.0.15-1ubuntu1) artful; urgency=medium * Sync with Debian. Remaining change: - - Don't build mongo plugins on arm* and powerpc since - mongo-cxx-legacy-plugin is not available for those architectures - in Ubuntu + - Don't build mongo plugins on arm* since mongo-cxx-legacy-plugin + is not available for those architectures in Ubuntu + + -- Jeremy Bicha Mon, 01 May 2017 09:46:59 -0400 + +uwsgi (2.0.15-1) unstable; urgency=medium + + [ upstream ] + * New upstream release. + + Fix writefifo race condition. + https://github.com/unbit/uwsgi/issues/1434 + + Support passing authentication info in redislog plugin. + https://github.com/unbit/uwsgi/issues/1498 + + Fix avoid closing $env->{'psgix.io'} on "PSGI cancel". + + Fix segfault in python plugin decoding null string. + https://github.com/unbit/uwsgi/issues/1476 + + Fix logger in python plugin. + https://github.com/unbit/uwsgi/issues/1494 + + Fix integer overflow in logger module. + https://github.com/unbit/uwsgi/issues/1489 + + Fix (hopefully) memory corruptions in python plugin. + https://github.com/unbit/uwsgi/issues/1478 + + Fix sendfile-over-SSL API. + https://github.com/unbit/uwsgi/issues/1490 + + [ Jonas Smedegaard ] + * Extend copyright coverage for packaging. + * Update watch file: Adjust for recent upstream indirect download URL. - -- Jeremy Bicha Mon, 27 Feb 2017 01:16:06 -0500 + -- Jonas Smedegaard Sat, 08 Apr 2017 11:33:44 +0200 uwsgi (2.0.14+20170111-4) unstable; urgency=medium diff -Nru uwsgi-2.0.14+20170111/debian/control uwsgi-2.0.15/debian/control --- uwsgi-2.0.14+20170111/debian/control 2017-02-27 06:16:06.000000000 +0000 +++ uwsgi-2.0.15/debian/control 2017-05-01 22:17:49.000000000 +0000 @@ -54,7 +54,7 @@ libjail-dev [kfreebsd-any], libkvm-dev [kfreebsd-any], glusterfs-common [amd64 arm64 armel armhf i386 mips mips64el mipsel powerpc ppc64el s390x], - libmongoclient-dev [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x] | mongodb-dev [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x], + libmongoclient-dev [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x] | mongodb-dev [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x], libboost-thread-dev [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x], libboost-filesystem-dev [amd64 arm64 armel armhf hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x], librados-dev [amd64 arm64 armel armhf i386 mips mips64el mipsel powerpc ppc64el s390x], @@ -254,7 +254,7 @@ Package: uwsgi-infrastructure-plugins Architecture: any Depends: ${misc:Depends}, - uwsgi-mongodb-plugins (= ${binary:Version}) [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x], + uwsgi-mongodb-plugins (= ${binary:Version}) [amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x], uwsgi-plugin-alarm-curl (= ${binary:Version}), uwsgi-plugin-alarm-xmpp (= ${binary:Version}), uwsgi-plugin-curl-cron (= ${binary:Version}), @@ -334,7 +334,7 @@ Java, Mono and V8 plugins are provided only on supported architectures. Package: uwsgi-mongodb-plugins -Architecture: amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x +Architecture: amd64 armel hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64el s390x Depends: ${shlibs:Depends}, ${misc:Depends}, uwsgi-core (= ${binary:Version}) Recommends: mongodb-server Description: MongoDB/GridFS plugins for uWSGI diff -Nru uwsgi-2.0.14+20170111/debian/pkgarchs.sh uwsgi-2.0.15/debian/pkgarchs.sh --- uwsgi-2.0.14+20170111/debian/pkgarchs.sh 2017-02-27 06:16:06.000000000 +0000 +++ uwsgi-2.0.15/debian/pkgarchs.sh 2017-05-01 13:46:59.000000000 +0000 @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright © 2008 Jonas Smedegaard +# Copyright © 2008, 2013-2014 Jonas Smedegaard # Description: Resolves supported archs of a Debian package # # This program is free software; you can redistribute it and/or modify diff -Nru uwsgi-2.0.14+20170111/debian/watch uwsgi-2.0.15/debian/watch --- uwsgi-2.0.14+20170111/debian/watch 2017-02-27 06:16:06.000000000 +0000 +++ uwsgi-2.0.15/debian/watch 2017-05-01 13:46:59.000000000 +0000 @@ -1,4 +1,4 @@ # run "uscan --report" to check or "gpb import-orig --uscan" to update version=4 -opts="dversionmangle=s/~dfsg.*//,repacksuffix=~dfsg" \ -http://projects.unbit.it/downloads/uwsgi-(\d[\d\.]+)\.tar\.gz +opts="dversionmangle=s/~dfsg.*//,repacksuffix=~dfsg,downloadurlmangle=s&.*/Changelog-(\d[\d.]+)\.html&https://projects.unbit.it/downloads/@PACKAGE@-$1.tar.gz&" \ +https://uwsgi-docs.readthedocs.io/en/latest/ Changelog-(\d[\d.]+)\.html diff -Nru uwsgi-2.0.14+20170111/PKG-INFO uwsgi-2.0.15/PKG-INFO --- uwsgi-2.0.14+20170111/PKG-INFO 1970-01-01 00:00:00.000000000 +0000 +++ uwsgi-2.0.15/PKG-INFO 2017-03-30 22:11:36.000000000 +0000 @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: uWSGI +Version: 2.0.15 +Summary: The uWSGI server +Home-page: https://uwsgi-docs.readthedocs.io/en/latest/ +Author: Unbit +Author-email: info@unbit.it +License: GPL2 +Description: UNKNOWN +Platform: UNKNOWN diff -Nru uwsgi-2.0.14+20170111/plugins/psgi/psgi_response.c uwsgi-2.0.15/plugins/psgi/psgi_response.c --- uwsgi-2.0.14+20170111/plugins/psgi/psgi_response.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/plugins/psgi/psgi_response.c 2017-03-30 22:11:36.000000000 +0000 @@ -63,6 +63,8 @@ if (av_len(response) == -1) { // deliberately empty response wsgi_req->status = 101; + // don't actually close socket, it must be closed by application itself + wsgi_req->fd_closed = 1; return UWSGI_OK; } diff -Nru uwsgi-2.0.14+20170111/plugins/python/python_plugin.c uwsgi-2.0.15/plugins/python/python_plugin.c --- uwsgi-2.0.14+20170111/plugins/python/python_plugin.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/plugins/python/python_plugin.c 2017-03-30 22:11:36.000000000 +0000 @@ -1057,17 +1057,16 @@ Py_INCREF(up.wsgi_spitout); PyTuple_SetItem((PyObject *)wsgi_req->async_args, 1, up.wsgi_spitout); PyObject *env = PyDict_New(); - Py_INCREF(env); return env; } void uwsgi_python_destroy_env_holy(struct wsgi_request *wsgi_req) { - Py_DECREF((PyObject *)wsgi_req->async_environ); - Py_DECREF((PyObject *) wsgi_req->async_args); // in non-multithread modes, we set uwsgi.env incrementing the refcount of the environ if (uwsgi.threads < 2) { Py_DECREF((PyObject *)wsgi_req->async_environ); } + Py_DECREF((PyObject *) wsgi_req->async_args); + Py_DECREF((PyObject *)wsgi_req->async_environ); } @@ -1922,7 +1921,7 @@ PyObject *py_getLogger_args = NULL; if (ul->arg) { py_getLogger_args = PyTuple_New(1); - PyTuple_SetItem(py_getLogger_args, 0, PyString_FromString(ul->arg)); + PyTuple_SetItem(py_getLogger_args, 0, UWSGI_PYFROMSTRING(ul->arg)); } ul->data = (void *) PyEval_CallObject(py_getLogger, py_getLogger_args); if (PyErr_Occurred()) { diff -Nru uwsgi-2.0.14+20170111/plugins/python/pyutils.c uwsgi-2.0.15/plugins/python/pyutils.c --- uwsgi-2.0.14+20170111/plugins/python/pyutils.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/plugins/python/pyutils.c 2017-03-30 22:11:36.000000000 +0000 @@ -91,37 +91,52 @@ PyObject *tb_text = PyTuple_GetItem(t, 3); int64_t line_no = PyInt_AsLong(tb_lineno); - #ifdef PYTHREE - PyObject *zero = PyUnicode_AsUTF8String(tb_filename); - if (!zero) goto end0; - - // filename - if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } - if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } - - Py_DECREF(zero); + PyObject *zero = NULL; + if (tb_filename) { + zero = PyUnicode_AsUTF8String(tb_filename); + if (!zero) goto end0; + + // filename + if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } + if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } + + Py_DECREF(zero); + } + else { + if (uwsgi_buffer_u16le(ub, 0)) { goto end0; } + } // lineno if (uwsgi_buffer_append_valnum(ub, line_no)) goto end0; - zero = PyUnicode_AsUTF8String(tb_function); - if (!zero) goto end0; - - // function - if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } - if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } - - Py_DECREF(zero); - - zero = PyUnicode_AsUTF8String(tb_text); - if (!zero) goto end0; - - // text - if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } - if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } - - Py_DECREF(zero); + if (tb_function) { + zero = PyUnicode_AsUTF8String(tb_function); + if (!zero) goto end0; + + // function + if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } + if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } + Py_DECREF(zero); + } + else { + if (uwsgi_buffer_u16le(ub, 0)) { goto end0; } + } + + + if (tb_text) { + zero = PyUnicode_AsUTF8String(tb_text); + if (!zero) goto end0; + + // text + if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } + if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } + + Py_DECREF(zero); + } + else { + if (uwsgi_buffer_u16le(ub, 0)) { goto end0; } + } #else // filename diff -Nru uwsgi-2.0.14+20170111/plugins/redislog/redislog_plugin.c uwsgi-2.0.15/plugins/redislog/redislog_plugin.c --- uwsgi-2.0.14+20170111/plugins/redislog/redislog_plugin.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/plugins/redislog/redislog_plugin.c 2017-03-30 22:11:36.000000000 +0000 @@ -4,7 +4,9 @@ struct uwsgi_redislog_state { int fd; + char *password; char *address; + char *id; char *command; char *prefix; char msgsize[11]; @@ -50,9 +52,26 @@ return orig_dst; } +static ssize_t uwsgi_redis_logger_discard_response(struct uwsgi_redislog_state *uredislog) { + ssize_t ret = 0, ret2; +again: + // read til a \n is found (ugly but fast) + ret2 = read(uredislog->fd, uredislog->response, 8); + if (ret2 <= 0) { + close(uredislog->fd); + uredislog->fd = -1; + return -1; + } + ret += ret2; + if (!memchr(uredislog->response, '\n', ret2)) { + goto again; + } + return ret; +} + ssize_t uwsgi_redis_logger(struct uwsgi_logger *ul, char *message, size_t len) { - ssize_t ret,ret2; + ssize_t ret; struct uwsgi_redislog_state *uredislog = NULL; if (!ul->configured) { @@ -64,12 +83,28 @@ if (ul->arg != NULL) { char *logarg = uwsgi_str(ul->arg); + char *at = strchr(logarg, '@'); + if (at) { + *at = 0; + uredislog->password = logarg; + logarg = at + 1; + } char *comma1 = strchr(logarg, ','); if (!comma1) { + char *slash = strchr(logarg, '/'); + if (slash) { + *slash = 0; + uredislog->id = slash + 1; + } uredislog->address = logarg; goto done; } *comma1 = 0; + char *slash = strchr(logarg, '/'); + if (slash) { + *slash = 0; + uredislog->id = slash + 1; + } uredislog->address = logarg; comma1++; if (*comma1 == 0) goto done; @@ -90,6 +125,8 @@ done: + if (!uredislog->password) uredislog->password = NULL; + if (!uredislog->id) uredislog->id = "0"; if (!uredislog->address) uredislog->address = uwsgi_str("127.0.0.1:6379"); if (!uredislog->command) uredislog->command = "*3\r\n$7\r\npublish\r\n$5\r\nuwsgi\r\n"; if (!uredislog->prefix) uredislog->prefix = ""; @@ -117,7 +154,35 @@ uredislog = (struct uwsgi_redislog_state *) ul->data; if (uredislog->fd == -1) { + struct iovec setup_iov; + char setup_buf[4096]; uredislog->fd = uwsgi_connect(uredislog->address, uwsgi.socket_timeout, 0); + if (uredislog->password) { + setup_iov.iov_len = snprintf( + setup_buf, sizeof (setup_buf), "*2\r\n$4\r\nauth\r\n$%lu\r\n%*s\r\n", + strlen(uredislog->password), (int)strlen(uredislog->password), uredislog->password); + setup_iov.iov_base = setup_buf; + ret = writev(uredislog->fd, &setup_iov, 1); + if (ret <= 0) { + close(uredislog->fd); + uredislog->fd = -1; + return -1; + } + uwsgi_redis_logger_discard_response(uredislog); + } + if (uredislog->id) { + setup_iov.iov_len = snprintf( + setup_buf, sizeof (setup_buf), "*2\r\n$6\r\nselect\r\n$%lu\r\n%*s\r\n", + strlen(uredislog->id), (int)strlen(uredislog->id), uredislog->id); + setup_iov.iov_base = setup_buf; + ret = writev(uredislog->fd, &setup_iov, 1); + if (ret <= 0) { + close(uredislog->fd); + uredislog->fd = -1; + return -1; + } + uwsgi_redis_logger_discard_response(uredislog); + } } if (uredislog->fd == -1) return -1; @@ -138,18 +203,7 @@ return -1; } -again: - // read til a \n is found (ugly but fast) - ret2 = read(uredislog->fd, uredislog->response, 8); - if (ret2 <= 0) { - close(uredislog->fd); - uredislog->fd = -1; - return -1; - } - - if (!memchr(uredislog->response, '\n', ret2)) { - goto again; - } + uwsgi_redis_logger_discard_response(uredislog); return ret; diff -Nru uwsgi-2.0.14+20170111/proto/base.c uwsgi-2.0.15/proto/base.c --- uwsgi-2.0.14+20170111/proto/base.c 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/proto/base.c 2017-03-30 22:11:36.000000000 +0000 @@ -266,7 +266,7 @@ int ret = -1; retry: ret = SSL_write(wsgi_req->ssl, buf, len); - if (ret >= 0) { + if (ret > 0) { wsgi_req->write_pos += ret; if (wsgi_req->write_pos == len) { return UWSGI_OK; @@ -277,7 +277,9 @@ int err = SSL_get_error(wsgi_req->ssl, ret); if (err == SSL_ERROR_WANT_WRITE) { - return UWSGI_AGAIN; + ret = uwsgi_wait_write_req(wsgi_req); + if (ret <= 0) return -1; + goto retry; } else if (err == SSL_ERROR_WANT_READ) { @@ -316,26 +318,33 @@ int uwsgi_proto_ssl_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { char buf[32768]; - ssize_t rlen = read(fd, buf, UMIN(len, 32768)); + if (lseek(fd, pos+wsgi_req->write_pos, SEEK_SET) < 0) { + uwsgi_error("lseek()"); + return -1; + } + ssize_t rlen = read(fd, buf, UMIN(len-wsgi_req->write_pos, 32768)); if (rlen <= 0) return -1; - for(;;) { - int ret = uwsgi_proto_ssl_write(wsgi_req, buf, rlen); + char *rbuf = buf; + + while(rlen > 0) { + size_t current_write_pos = wsgi_req->write_pos; + int ret = uwsgi_proto_ssl_write(wsgi_req, rbuf, rlen); if (ret == UWSGI_OK) { - if (wsgi_req->write_pos >= len) { - return UWSGI_OK; - } - return UWSGI_AGAIN; + break; } if (ret == UWSGI_AGAIN) { - ret = uwsgi_wait_write_req(wsgi_req); - if (ret <= 0 ) return -1; + rbuf += (wsgi_req->write_pos - current_write_pos); + rlen -= (wsgi_req->write_pos - current_write_pos); continue; } return -1; } - return -1; + if (wsgi_req->write_pos == len) { + return UWSGI_OK; + } + return UWSGI_AGAIN; } #endif @@ -368,7 +377,7 @@ retry: ret = SSL_read(wsgi_req->ssl, buf, len); - if (ret >= 0) return ret; + if (ret > 0) return ret; int err = SSL_get_error(wsgi_req->ssl, ret); diff -Nru uwsgi-2.0.14+20170111/setup.py uwsgi-2.0.15/setup.py --- uwsgi-2.0.14+20170111/setup.py 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/setup.py 2017-03-30 22:11:36.000000000 +0000 @@ -120,6 +120,8 @@ author='Unbit', author_email='info@unbit.it', license='GPL2', + descriptions='The uWSGI Platform', + url='https://uwsgi-docs.readthedocs.io/en/latest/', py_modules=['uwsgidecorators'], distclass=uWSGIDistribution, ) diff -Nru uwsgi-2.0.14+20170111/uwsgiconfig.py uwsgi-2.0.15/uwsgiconfig.py --- uwsgi-2.0.14+20170111/uwsgiconfig.py 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/uwsgiconfig.py 2017-03-30 22:11:36.000000000 +0000 @@ -1,6 +1,6 @@ # uWSGI build system -uwsgi_version = '2.0.14' +uwsgi_version = '2.0.15' import os import re diff -Nru uwsgi-2.0.14+20170111/uwsgi.gemspec uwsgi-2.0.15/uwsgi.gemspec --- uwsgi-2.0.14+20170111/uwsgi.gemspec 2017-01-11 21:11:10.000000000 +0000 +++ uwsgi-2.0.15/uwsgi.gemspec 2017-03-30 22:11:36.000000000 +0000 @@ -2,7 +2,7 @@ s.name = 'uwsgi' s.license = 'GPL-2' s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'') - s.date = '2016-10-03' + s.date = '2017-03-30' s.summary = "uWSGI" s.description = "The uWSGI server for Ruby/Rack" s.authors = ["Unbit"]