Hello community, here is the log from the commit of package python3-bottle for openSUSE:Factory checked in at 2017-01-19 10:41:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-bottle (Old) and /work/SRC/openSUSE:Factory/.python3-bottle.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python3-bottle" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-bottle/python3-bottle.changes 2016-12-08 00:27:35.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python3-bottle.new/python3-bottle.changes 2017-01-19 10:41:11.235619085 +0100 @@ -1,0 +2,20 @@ +Tue Jan 10 17:08:15 UTC 2017 - arun@gmx.de + +- specfile: + * update copyright year + +- update to version 0.12.13: + * Fix #923: TypeError WSGI response header value u'...' is not of + type str + +- changes from version 0.12.12: + * fix #918: AttributeError: 'FileUpload' object has no attribute + 'get_header' + +- changes from version 0.12.11: + * fix #913: redirect() doesn't filter "\r\n" leads to CRLF attack + * Fix tests for Python 2.5 (itertools.product missing) + * fix #913: Harden bottle against malformed headers. + * Use setuptools again. + +------------------------------------------------------------------- Old: ---- bottle-0.12.10.tar.gz New: ---- bottle-0.12.13.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-bottle.spec ++++++ --- /var/tmp/diff_new_pack.dTBnuy/_old 2017-01-19 10:41:11.623564362 +0100 +++ /var/tmp/diff_new_pack.dTBnuy/_new 2017-01-19 10:41:11.623564362 +0100 @@ -1,7 +1,7 @@ # # spec file for package python3-bottle # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: python3-bottle -Version: 0.12.10 +Version: 0.12.13 Release: 0 Url: http://bottlepy.org/ Summary: Fast and simple WSGI-framework for small web-applications @@ -28,6 +28,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: python3 BuildRequires: python3-base +BuildRequires: python3-setuptools BuildArch: noarch %description ++++++ bottle-0.12.10.tar.gz -> bottle-0.12.13.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/MANIFEST.in new/bottle-0.12.13/MANIFEST.in --- old/bottle-0.12.10/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 +++ new/bottle-0.12.13/MANIFEST.in 2016-07-05 12:08:44.000000000 +0200 @@ -0,0 +1,6 @@ +include bottle.py +include setup.py +include README.rst +include LICENSE.txt +include test/views/*.tpl +include test/*.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/PKG-INFO new/bottle-0.12.13/PKG-INFO --- old/bottle-0.12.10/PKG-INFO 2016-10-09 15:44:51.000000000 +0200 +++ new/bottle-0.12.13/PKG-INFO 2017-01-09 13:33:49.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: bottle -Version: 0.12.10 +Version: 0.12.13 Summary: Fast and simple WSGI-framework for small web-applications. Home-page: http://bottlepy.org/ Author: Marcel Hellkamp @@ -15,7 +15,7 @@ Homepage and documentation: http://bottlepy.org/ - Copyright (c) 2013, Marcel Hellkamp. + Copyright (c) 2016, Marcel Hellkamp. License: MIT (see LICENSE for details) Platform: any diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/bottle.egg-info/PKG-INFO new/bottle-0.12.13/bottle.egg-info/PKG-INFO --- old/bottle-0.12.10/bottle.egg-info/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/bottle-0.12.13/bottle.egg-info/PKG-INFO 2017-01-09 13:33:48.000000000 +0100 @@ -0,0 +1,37 @@ +Metadata-Version: 1.1 +Name: bottle +Version: 0.12.13 +Summary: Fast and simple WSGI-framework for small web-applications. +Home-page: http://bottlepy.org/ +Author: Marcel Hellkamp +Author-email: marc@gsites.de +License: MIT +Description: + Bottle is a fast and simple micro-framework for small web applications. It + offers request dispatching (Routes) with url parameter support, templates, + a built-in HTTP Server and adapters for many third party WSGI/HTTP-server and + template engines - all in a single file and with no dependencies other than the + Python Standard Library. + + Homepage and documentation: http://bottlepy.org/ + + Copyright (c) 2016, Marcel Hellkamp. + License: MIT (see LICENSE for details) + +Platform: any +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries +Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Programming Language :: Python :: 2.5 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/bottle.egg-info/SOURCES.txt new/bottle-0.12.13/bottle.egg-info/SOURCES.txt --- old/bottle-0.12.10/bottle.egg-info/SOURCES.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/bottle-0.12.13/bottle.egg-info/SOURCES.txt 2017-01-09 13:33:48.000000000 +0100 @@ -0,0 +1,46 @@ +MANIFEST.in +README.rst +bottle.py +setup.py +bottle.egg-info/PKG-INFO +bottle.egg-info/SOURCES.txt +bottle.egg-info/dependency_links.txt +bottle.egg-info/top_level.txt +test/servertest.py +test/test_auth.py +test/test_config.py +test/test_configdict.py +test/test_contextlocals.py +test/test_environ.py +test/test_fileupload.py +test/test_formsdict.py +test/test_importhook.py +test/test_jinja2.py +test/test_mako.py +test/test_mdict.py +test/test_mount.py +test/test_outputfilter.py +test/test_plugins.py +test/test_resources.py +test/test_route.py +test/test_router.py +test/test_securecookies.py +test/test_sendfile.py +test/test_server.py +test/test_stpl.py +test/test_wsgi.py +test/testall.py +test/tools.py +test/views/jinja2_base.tpl +test/views/jinja2_inherit.tpl +test/views/jinja2_simple.tpl +test/views/mako_base.tpl +test/views/mako_inherit.tpl +test/views/mako_simple.tpl +test/views/stpl_include.tpl +test/views/stpl_no_vars.tpl +test/views/stpl_simple.tpl +test/views/stpl_t2base.tpl +test/views/stpl_t2inc.tpl +test/views/stpl_t2main.tpl +test/views/stpl_unicode.tpl \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/bottle.egg-info/dependency_links.txt new/bottle-0.12.13/bottle.egg-info/dependency_links.txt --- old/bottle-0.12.10/bottle.egg-info/dependency_links.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/bottle-0.12.13/bottle.egg-info/dependency_links.txt 2017-01-09 13:33:48.000000000 +0100 @@ -0,0 +1 @@ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/bottle.egg-info/top_level.txt new/bottle-0.12.13/bottle.egg-info/top_level.txt --- old/bottle-0.12.10/bottle.egg-info/top_level.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/bottle-0.12.13/bottle.egg-info/top_level.txt 2017-01-09 13:33:48.000000000 +0100 @@ -0,0 +1 @@ +bottle diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/bottle.py new/bottle-0.12.13/bottle.py --- old/bottle-0.12.10/bottle.py 2016-10-09 15:35:44.000000000 +0200 +++ new/bottle-0.12.13/bottle.py 2017-01-09 13:31:53.000000000 +0100 @@ -9,14 +9,14 @@ Homepage and documentation: http://bottlepy.org/ -Copyright (c) 2013, Marcel Hellkamp. +Copyright (c) 2016, Marcel Hellkamp. License: MIT (see LICENSE for details) """ from __future__ import with_statement __author__ = 'Marcel Hellkamp' -__version__ = '0.12.10' +__version__ = '0.12.13' __license__ = 'MIT' # The gevent server adapter needs to patch some modules before they are imported @@ -1398,28 +1398,36 @@ self.environ['bottle.request.ext.%s'%name] = value +def _hkey(key): + if '\n' in key or '\r' in key or '\0' in key: + raise ValueError("Header names must not contain control characters: %r" % key) + return key.title().replace('_', '-') -def _hkey(s): - return s.title().replace('_','-') +def _hval(value): + value = tonat(value) + if '\n' in value or '\r' in value or '\0' in value: + raise ValueError("Header value must not contain control characters: %r" % value) + return value + class HeaderProperty(object): - def __init__(self, name, reader=None, writer=str, default=''): + def __init__(self, name, reader=None, writer=None, default=''): self.name, self.default = name, default self.reader, self.writer = reader, writer self.__doc__ = 'Current value of the %r header.' % name.title() def __get__(self, obj, cls): if obj is None: return self - value = obj.headers.get(self.name, self.default) + value = obj.get_header(self.name, self.default) return self.reader(value) if self.reader else value def __set__(self, obj, value): - obj.headers[self.name] = self.writer(value) + obj[self.name] = self.writer(value) if self.writer else value def __delete__(self, obj): - del obj.headers[self.name] + del obj[self.name] class BaseResponse(object): @@ -1526,7 +1534,7 @@ def __contains__(self, name): return _hkey(name) in self._headers def __delitem__(self, name): del self._headers[_hkey(name)] def __getitem__(self, name): return self._headers[_hkey(name)][-1] - def __setitem__(self, name, value): self._headers[_hkey(name)] = [str(value)] + def __setitem__(self, name, value): self._headers[_hkey(name)] = [_hval(value)] def get_header(self, name, default=None): ''' Return the value of a previously defined header. If there is no @@ -1536,11 +1544,11 @@ def set_header(self, name, value): ''' Create a new response header, replacing any previously defined headers with the same name. ''' - self._headers[_hkey(name)] = [str(value)] + self._headers[_hkey(name)] = [_hval(value)] def add_header(self, name, value): ''' Add an additional response header, not removing duplicates. ''' - self._headers.setdefault(_hkey(name), []).append(str(value)) + self._headers.setdefault(_hkey(name), []).append(_hval(value)) def iter_headers(self): ''' Yield (header, value) tuples, skipping headers that are not @@ -1921,7 +1929,6 @@ return super(FormsDict, self).__getattr__(name) return self.getunicode(name, default=default) - class HeaderDict(MultiDict): """ A case-insensitive version of :class:`MultiDict` that defaults to replace the old value instead of appending it. """ @@ -1933,15 +1940,14 @@ def __contains__(self, key): return _hkey(key) in self.dict def __delitem__(self, key): del self.dict[_hkey(key)] def __getitem__(self, key): return self.dict[_hkey(key)][-1] - def __setitem__(self, key, value): self.dict[_hkey(key)] = [str(value)] - def append(self, key, value): - self.dict.setdefault(_hkey(key), []).append(str(value)) - def replace(self, key, value): self.dict[_hkey(key)] = [str(value)] + def __setitem__(self, key, value): self.dict[_hkey(key)] = [_hval(value)] + def append(self, key, value): self.dict.setdefault(_hkey(key), []).append(_hval(value)) + def replace(self, key, value): self.dict[_hkey(key)] = [_hval(value)] def getall(self, key): return self.dict.get(_hkey(key)) or [] def get(self, key, default=None, index=-1): return MultiDict.get(self, _hkey(key), default, index) def filter(self, names): - for name in [_hkey(n) for n in names]: + for name in (_hkey(n) for n in names): if name in self.dict: del self.dict[name] @@ -2349,6 +2355,10 @@ content_type = HeaderProperty('Content-Type') content_length = HeaderProperty('Content-Length', reader=int, default=-1) + def get_header(self, name, default=None): + """ Return the value of a header within the mulripart part. """ + return self.headers.get(name, default) + @cached_property def filename(self): ''' Name of the file on the client file system, but normalized to ensure diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/setup.cfg new/bottle-0.12.13/setup.cfg --- old/bottle-0.12.10/setup.cfg 1970-01-01 01:00:00.000000000 +0100 +++ new/bottle-0.12.13/setup.cfg 2017-01-09 13:33:49.000000000 +0100 @@ -0,0 +1,5 @@ +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/setup.py new/bottle-0.12.13/setup.py --- old/bottle-0.12.10/setup.py 2016-10-09 15:12:19.000000000 +0200 +++ new/bottle-0.12.13/setup.py 2017-01-09 13:19:52.000000000 +0100 @@ -2,7 +2,7 @@ import sys import os -from distutils.core import setup +from setuptools import setup if sys.version_info < (2,5): raise NotImplementedError("Sorry, you need at least Python 2.5 or Python 3.x to use bottle.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/test/test_environ.py new/bottle-0.12.13/test/test_environ.py --- old/bottle-0.12.10/test/test_environ.py 2016-10-09 15:12:19.000000000 +0200 +++ new/bottle-0.12.13/test/test_environ.py 2017-01-09 13:30:30.000000000 +0100 @@ -3,6 +3,7 @@ import unittest import sys + import bottle from bottle import request, tob, touni, tonat, json_dumps, _e, HTTPError, parse_date import tools @@ -11,6 +12,18 @@ from bottle import BaseRequest, BaseResponse, LocalRequest + +try: + from itertools import product +except ImportError: + def product(*args): + pools = map(tuple, args) + result = [[]] + for pool in pools: + result = [x + [y] for x in result for y in pool] + for prod in result: + yield tuple(prod) + class TestRequest(unittest.TestCase): def test_app_property(self): @@ -654,6 +667,30 @@ self.assertEqual('5', response['x-test']) response['x-test'] = None self.assertEqual('None', response['x-test']) + response['x-test'] = touni('瓶') + self.assertEqual(tonat(touni('瓶')), response['x-test']) + + def test_prevent_control_characters_in_headers(self): + masks = '{}test', 'test{}', 'te{}st' + tests = '\n', '\r', '\n\r', '\0' + + # Test HeaderDict + apis = 'append', 'replace', '__setitem__', 'setdefault' + for api, mask, test in product(apis, masks, tests): + hd = bottle.HeaderDict() + func = getattr(hd, api) + value = mask.replace("{}", test) + self.assertRaises(ValueError, func, value, "test-value") + self.assertRaises(ValueError, func, "test-name", value) + + # Test functions on BaseResponse + apis = 'add_header', 'set_header', '__setitem__' + for api, mask, test in product(apis, masks, tests): + rs = bottle.BaseResponse() + func = getattr(rs, api) + value = mask.replace("{}", test) + self.assertRaises(ValueError, func, value, "test-value") + self.assertRaises(ValueError, func, "test-name", value) def test_expires_header(self): import datetime diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bottle-0.12.10/test/test_fileupload.py new/bottle-0.12.13/test/test_fileupload.py --- old/bottle-0.12.10/test/test_fileupload.py 2016-10-09 15:12:19.000000000 +0200 +++ new/bottle-0.12.13/test/test_fileupload.py 2017-01-09 13:19:52.000000000 +0100 @@ -4,7 +4,7 @@ import unittest import sys, os.path import bottle -from bottle import FileUpload, BytesIO +from bottle import FileUpload, BytesIO, tob import tempfile class TestFileUpload(unittest.TestCase): @@ -14,6 +14,10 @@ def test_raw_filename(self): self.assertEqual(FileUpload(None, None, 'x/x').raw_filename, 'x/x') + def test_content_type(self): + fu = FileUpload(None, None, None, {"Content-type": "text/plain"}) + self.assertEqual(fu.content_type, 'text/plain') + def assertFilename(self, bad, good): fu = FileUpload(None, None, bad) self.assertEqual(fu.filename, good)