Hello community,

here is the log from the commit of package python-Werkzeug for openSUSE:Factory 
checked in at 2016-09-27 13:44:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Werkzeug (Old)
 and      /work/SRC/openSUSE:Factory/.python-Werkzeug.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Werkzeug"

Changes:
--------
New Changes file:

--- /dev/null   2016-09-15 12:42:18.240042505 +0200
+++ /work/SRC/openSUSE:Factory/.python-Werkzeug.new/python-Werkzeug-doc.changes 
2016-09-27 13:44:41.000000000 +0200
@@ -0,0 +1,53 @@
+-------------------------------------------------------------------
+Thu Sep 15 23:08:05 UTC 2016 - [email protected]
+
+- update to version 0.11.11:
+  * Fix JSONRequestMixin for Python3. See #731
+  * Fix broken string handling in test client when passing
+    integers. See #852
+  * Fix a bug in "parse_options_header" where an invalid content type
+    starting with comma or semi-colon would result in an invalid
+    return value, see issue "#995".
+  * Fix a bug in multidicts when passing empty lists as values, see
+    issue "#979".
+  * Fix a security issue that allows XSS on the Werkzeug debugger. See
+    "#1001".
+- update to version 0.11.10:
+  * Fixed a bug that occurs when running on Python 2.6 and using a
+    broken locale.  See pull request #912.
+  * Fixed a crash when running the debugger on Google App Engine. See
+    issue #925.
+  * Fixed an issue with multipart parsing that could cause memory
+    exhaustion.
+- Update to 0.11.9
+  - Corrected an issue that caused the debugger not to use the
+    machine GUID on POSIX systems.
+  - Corrected an Unicode error on Python 3 for the debugger's
+    PIN usage.
+  - Corrected the timestamp verification in the pin debug code.
+    Without this fix the pin was remebered until too long.
+- update to version 0.11.8:
+  * fixed a problem with the machine GUID detection code on OS X on
+    Python 3.
+- changes from version 0.11.7:
+  * fixed a regression on Python 3 for the debugger.
+- changes from version 0.11.6:
+  * werkzeug.serving: Still show the client address on bad requests.
+  * improved the PIN based protection for the debugger to make it
+    harder to brute force via trying cookies.  Please keep in mind
+    that the debugger *is not intended for running on production
+    environments*
+  * increased the pin timeout to a week to make it less annoying for
+    people which should decrease the change that users disable the pin
+    check entirely.
+  * werkzeug.serving: Fix broken HTTP_HOST when path starts with
+    double slash.
+- update to version 0.11.5:
+  * werkzeug.serving: Fix crash when attempting SSL connection to HTTP
+    server.
+- update to version 0.11.4:
+  * Fixed werkzeug.serving not working from -m flag.
+  * Fixed incorrect weak etag handling.
+- Rebase 0001_create_a_thread_to_reap_death_process.patch
+- Split documentation into own subpackage to speed up build.
+
--- /work/SRC/openSUSE:Factory/python-Werkzeug/python-Werkzeug.changes  
2016-02-11 12:37:49.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python-Werkzeug.new/python-Werkzeug.changes     
2016-09-27 13:44:42.000000000 +0200
@@ -1,0 +2,58 @@
+Fri Sep 16 14:25:04 UTC 2016 - [email protected]
+
+- Fix download url.
+
+-------------------------------------------------------------------
+Thu Sep 15 23:08:05 UTC 2016 - [email protected]
+
+- update to version 0.11.11:
+  * Fix JSONRequestMixin for Python3. See #731
+  * Fix broken string handling in test client when passing
+    integers. See #852
+  * Fix a bug in "parse_options_header" where an invalid content type
+    starting with comma or semi-colon would result in an invalid
+    return value, see issue "#995".
+  * Fix a bug in multidicts when passing empty lists as values, see
+    issue "#979".
+  * Fix a security issue that allows XSS on the Werkzeug debugger. See
+    "#1001".
+- update to version 0.11.10:
+  * Fixed a bug that occurs when running on Python 2.6 and using a
+    broken locale.  See pull request #912.
+  * Fixed a crash when running the debugger on Google App Engine. See
+    issue #925.
+  * Fixed an issue with multipart parsing that could cause memory
+    exhaustion.
+- Update to 0.11.9
+  - Corrected an issue that caused the debugger not to use the
+    machine GUID on POSIX systems.
+  - Corrected an Unicode error on Python 3 for the debugger's
+    PIN usage.
+  - Corrected the timestamp verification in the pin debug code.
+    Without this fix the pin was remebered until too long.
+- update to version 0.11.8:
+  * fixed a problem with the machine GUID detection code on OS X on
+    Python 3.
+- changes from version 0.11.7:
+  * fixed a regression on Python 3 for the debugger.
+- changes from version 0.11.6:
+  * werkzeug.serving: Still show the client address on bad requests.
+  * improved the PIN based protection for the debugger to make it
+    harder to brute force via trying cookies.  Please keep in mind
+    that the debugger *is not intended for running on production
+    environments*
+  * increased the pin timeout to a week to make it less annoying for
+    people which should decrease the change that users disable the pin
+    check entirely.
+  * werkzeug.serving: Fix broken HTTP_HOST when path starts with
+    double slash.
+- update to version 0.11.5:
+  * werkzeug.serving: Fix crash when attempting SSL connection to HTTP
+    server.
+- update to version 0.11.4:
+  * Fixed werkzeug.serving not working from -m flag.
+  * Fixed incorrect weak etag handling.
+- Rebase 0001_create_a_thread_to_reap_death_process.patch
+- Split documentation into own subpackage to speed up build.
+
+-------------------------------------------------------------------

Old:
----
  Werkzeug-0.11.3.tar.gz

New:
----
  Werkzeug-0.11.11.tar.gz
  python-Werkzeug-doc.changes
  python-Werkzeug-doc.spec

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Werkzeug-doc.spec ++++++
#
# spec file for package python3-Werkzeug-doc
#
# Copyright (c) 2016 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
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via http://bugs.opensuse.org/
#


Name:           python-Werkzeug-doc
Version:        0.11.11
Release:        0
Url:            http://werkzeug.pocoo.org/
Summary:        Documentation for python3-Werkzeug
License:        BSD-3-Clause
Group:          Documentation/Other
Source:         
https://files.pythonhosted.org/packages/source/W/Werkzeug/Werkzeug-%{version}.tar.gz
BuildRoot:      %{_tmppath}/%{name}-%{version}-build
BuildRequires:  python-Sphinx
BuildRequires:  python-Werkzeug = %{version}
BuildRequires:  python-setuptools
BuildArch:      noarch
Requires:       python-Werkzeug = %{version}

%description
Documentation and examples for python3-Werkzeug

%prep
%setup -q -n Werkzeug-%{version}
sed -i "s/\r//" LICENSE # Fix wrong EOL-encoding
sed -i "1d" 
examples/manage-{i18nurls,simplewiki,shorty,couchy,cupoftee,webpylike,plnt,coolmagic}.py
 # Fix non-executable scripts

%build
# Not needed

%install
cd docs && make html && rm -rf _build/html/.buildinfo # Build HTML Documentation

%files
%defattr(-,root,root,-)
%doc AUTHORS LICENSE
%doc docs/_build/html
%doc examples

%changelog
++++++ python-Werkzeug.spec ++++++
--- /var/tmp/diff_new_pack.aB0Gzq/_old  2016-09-27 13:44:43.000000000 +0200
+++ /var/tmp/diff_new_pack.aB0Gzq/_new  2016-09-27 13:44:43.000000000 +0200
@@ -17,19 +17,18 @@
 
 
 Name:           python-Werkzeug
-Version:        0.11.3
+Version:        0.11.11
 Release:        0
 Url:            http://werkzeug.pocoo.org/
 Summary:        The Swiss Army knife of Python web development
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
-Source:         
http://pypi.python.org/packages/source/W/Werkzeug/Werkzeug-%{version}.tar.gz
+Source:         
https://files.pythonhosted.org/packages/source/W/Werkzeug/Werkzeug-%{version}.tar.gz
 # PATCH-FIX-UPSTREAM 0001_create_a_thread_to_reap_death_process.patch 
bsc#954591
 Patch0:         0001_create_a_thread_to_reap_death_process.patch
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-BuildRequires:  python-Sphinx
 BuildRequires:  python-devel
-BuildRequires:  python-nose
+BuildRequires:  python-pytest
 BuildRequires:  python-setuptools
 Provides:       python-werkzeug = %{version}
 Obsoletes:      python-werkzeug < %{version}
@@ -54,14 +53,6 @@
 on as many server environments as possible (such as blogs, wikis,
 bulletin boards, etc.).
 
-%package doc
-Summary:        Documentation for %{name}
-Group:          Documentation/Other
-Requires:       %{name} = %{version}
-
-%description doc
-Documentation and examples for %{name}.
-
 %prep
 %setup -q -n Werkzeug-%{version}
 sed -i "s/\r//" LICENSE # Fix wrong EOL-encoding
@@ -70,18 +61,16 @@
 
 %build
 python setup.py build
-cd docs && make html && rm -rf _build/html/.buildinfo # Build HTML 
Documentation
 
 %install
 python setup.py install --prefix=%{_prefix} --root=%{buildroot}
 
+%check
+python setup.py test
+
 %files
 %defattr(-,root,root,-)
 %doc AUTHORS LICENSE CHANGES
 %{python_sitelib}/*
 
-%files doc
-%defattr(-,root,root,-)
-%doc docs/_build/html examples
-
 %changelog

++++++ 0001_create_a_thread_to_reap_death_process.patch ++++++
--- /var/tmp/diff_new_pack.aB0Gzq/_old  2016-09-27 13:44:43.000000000 +0200
+++ /var/tmp/diff_new_pack.aB0Gzq/_new  2016-09-27 13:44:43.000000000 +0200
@@ -29,9 +29,10 @@
  import signal
 +import threading
  
- from ._compat import PY2
+ try:
+     import ssl
 
-@@ -522,11 +523,29 @@ class ForkingWSGIServer(ForkingMixIn, BaseWSGIServer):
+@@ -524,11 +525,29 @@
      multiprocess = True
  
      def __init__(self, host, port, app, processes=40, handler=None,
@@ -39,7 +40,7 @@
 +                 passthrough_errors=False, ssl_context=None, fd=None,
 +                 frequency=5):
          BaseWSGIServer.__init__(self, host, port, app, handler,
-                                 passthrough_errors, ssl_context, fd)
+                                passthrough_errors, ssl_context, fd)
          self.max_children = processes
  
 +        if frequency:

++++++ Werkzeug-0.11.3.tar.gz -> Werkzeug-0.11.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/AUTHORS new/Werkzeug-0.11.11/AUTHORS
--- old/Werkzeug-0.11.3/AUTHORS 2015-01-03 16:03:47.000000000 +0100
+++ new/Werkzeug-0.11.11/AUTHORS        2016-08-31 15:12:07.000000000 +0200
@@ -28,6 +28,8 @@
 - Daniel Neuhäuser
 - Markus Unterwaditzer
 - Joe Esposito <[email protected]>
+- Cédric Krier
+- Lars Holm Nielsen
 
 Contributors of code for werkzeug/examples are:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/CHANGES new/Werkzeug-0.11.11/CHANGES
--- old/Werkzeug-0.11.3/CHANGES 2015-12-20 00:13:11.000000000 +0100
+++ new/Werkzeug-0.11.11/CHANGES        2016-08-31 15:12:53.000000000 +0200
@@ -1,6 +1,86 @@
 Werkzeug Changelog
 ==================
 
+Version 0.11.11
+---------------
+
+Released on August 31st 2016.
+
+- Fix JSONRequestMixin for Python3. See #731
+- Fix broken string handling in test client when passing integers. See #852
+- Fix a bug in ``parse_options_header`` where an invalid content type
+  starting with comma or semi-colon would result in an invalid return value,
+  see issue ``#995``.
+- Fix a bug in multidicts when passing empty lists as values, see issue
+  ``#979``.
+- Fix a security issue that allows XSS on the Werkzeug debugger. See ``#1001``.
+
+Version 0.11.10
+---------------
+
+Released on May 24th 2016.
+
+- Fixed a bug that occurs when running on Python 2.6 and using a broken locale.
+  See pull request #912.
+- Fixed a crash when running the debugger on Google App Engine. See issue #925.
+- Fixed an issue with multipart parsing that could cause memory exhaustion.
+
+Version 0.11.9
+--------------
+
+Released on April 24th 2016.
+
+- Corrected an issue that caused the debugger not to use the
+  machine GUID on POSIX systems.
+- Corrected an Unicode error on Python 3 for the debugger's
+  PIN usage.
+- Corrected the timestamp verification in the pin debug code.
+  Without this fix the pin was remebered until too long.
+
+Version 0.11.8
+--------------
+
+Released on April 15th 2016.
+
+- fixed a problem with the machine GUID detection code on OS X
+  on Python 3.
+
+Version 0.11.7
+--------------
+
+Released on April 14th 2016.
+
+- fixed a regression on Python 3 for the debugger.
+
+Version 0.11.6
+--------------
+
+Released on April 14th 2016.
+
+- werkzeug.serving: Still show the client address on bad requests.
+- improved the PIN based protection for the debugger to make it harder to
+  brute force via trying cookies.  Please keep in mind that the debugger
+  *is not intended for running on production environments*
+- increased the pin timeout to a week to make it less annoying for people
+  which should decrease the change that users disable the pin check
+  entirely.
+- werkzeug.serving: Fix broken HTTP_HOST when path starts with double slash.
+
+Version 0.11.5
+--------------
+
+Released on March 22nd 2016.
+
+- werkzeug.serving: Fix crash when attempting SSL connection to HTTP server.
+
+Version 0.11.4
+--------------
+
+Released on February 14th 2016.
+
+- Fixed werkzeug.serving not working from -m flag.
+- Fixed incorrect weak etag handling.
+
 Version 0.11.3
 --------------
 
@@ -211,7 +291,7 @@
   object (pull request ``#583``).
 - The ``qop`` parameter for ``WWW-Authenticate`` headers is now always quoted,
   as required by RFC 2617 (issue ``#633``).
-- Fix bug in ``werkzeug.contrib.cache.SimpleCache`` with Python 3 where 
add/set 
+- Fix bug in ``werkzeug.contrib.cache.SimpleCache`` with Python 3 where add/set
   may throw an exception when pruning old entries from the cache (pull request
   ``#651``).
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/PKG-INFO 
new/Werkzeug-0.11.11/PKG-INFO
--- old/Werkzeug-0.11.3/PKG-INFO        2015-12-20 00:13:39.000000000 +0100
+++ new/Werkzeug-0.11.11/PKG-INFO       2016-08-31 15:13:05.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Werkzeug
-Version: 0.11.3
+Version: 0.11.11
 Summary: The Swiss Army knife of Python web development
 Home-page: http://werkzeug.pocoo.org/
 Author: Armin Ronacher
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/Werkzeug.egg-info/PKG-INFO 
new/Werkzeug-0.11.11/Werkzeug.egg-info/PKG-INFO
--- old/Werkzeug-0.11.3/Werkzeug.egg-info/PKG-INFO      2015-12-20 
00:13:38.000000000 +0100
+++ new/Werkzeug-0.11.11/Werkzeug.egg-info/PKG-INFO     2016-08-31 
15:13:04.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Werkzeug
-Version: 0.11.3
+Version: 0.11.11
 Summary: The Swiss Army knife of Python web development
 Home-page: http://werkzeug.pocoo.org/
 Author: Armin Ronacher
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/Werkzeug.egg-info/SOURCES.txt 
new/Werkzeug-0.11.11/Werkzeug.egg-info/SOURCES.txt
--- old/Werkzeug-0.11.3/Werkzeug.egg-info/SOURCES.txt   2015-12-20 
00:13:39.000000000 +0100
+++ new/Werkzeug-0.11.11/Werkzeug.egg-info/SOURCES.txt  2016-08-31 
15:13:04.000000000 +0200
@@ -11,10 +11,8 @@
 Werkzeug.egg-info/dependency_links.txt
 Werkzeug.egg-info/not-zip-safe
 Werkzeug.egg-info/top_level.txt
-artwork/.DS_Store
 artwork/logo.png
 artwork/logo.svg
-docs/.DS_Store
 docs/Makefile
 docs/changes.rst
 docs/conf.py
Files old/Werkzeug-0.11.3/artwork/.DS_Store and 
new/Werkzeug-0.11.11/artwork/.DS_Store differ
Files old/Werkzeug-0.11.3/docs/.DS_Store and 
new/Werkzeug-0.11.11/docs/.DS_Store differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/setup.cfg 
new/Werkzeug-0.11.11/setup.cfg
--- old/Werkzeug-0.11.3/setup.cfg       2015-12-20 00:13:39.000000000 +0100
+++ new/Werkzeug-0.11.11/setup.cfg      2016-08-31 15:13:05.000000000 +0200
@@ -8,7 +8,7 @@
 universal = 1
 
 [flake8]
-ignore = E126,E241,E272
+ignore = E126,E241,E272,E402,E731,W503
 exclude = .tox,examples,docs
 max-line-length = 100
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/contrib/test_wrappers.py 
new/Werkzeug-0.11.11/tests/contrib/test_wrappers.py
--- old/Werkzeug-0.11.3/tests/contrib/test_wrappers.py  2015-09-20 
20:59:05.000000000 +0200
+++ new/Werkzeug-0.11.11/tests/contrib/test_wrappers.py 2016-08-28 
23:58:14.000000000 +0200
@@ -16,6 +16,16 @@
 from werkzeug.wrappers import Request, Response
 
 
+def test_json_request_mixin():
+    class MyRequest(wrappers.JSONRequestMixin, Request):
+        pass
+    req = MyRequest.from_values(
+        data=u'{"foä": "bar"}'.encode('utf-8'),
+        content_type='text/json'
+    )
+    assert req.json == {u'foä': 'bar'}
+
+
 def test_reverse_slash_behavior():
     class MyRequest(wrappers.ReverseSlashBehaviorRequestMixin, Request):
         pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_datastructures.py 
new/Werkzeug-0.11.11/tests/test_datastructures.py
--- old/Werkzeug-0.11.3/tests/test_datastructures.py    2015-09-20 
20:59:05.000000000 +0200
+++ new/Werkzeug-0.11.11/tests/test_datastructures.py   2016-08-31 
15:12:07.000000000 +0200
@@ -377,6 +377,15 @@
         assert list(zip(iterkeys(md), iterlistvalues(md))) == \
             list(iterlists(md))
 
+    def test_getitem_raise_badrequestkeyerror_for_empty_list_value(self):
+        mapping = [('a', 'b'), ('a', 'c')]
+        md = self.storage_class(mapping)
+
+        md.setlistdefault('empty', [])
+
+        with pytest.raises(KeyError):
+            md['empty']
+
 
 class TestOrderedMultiDict(_MutableMultiDictTests):
     storage_class = datastructures.OrderedMultiDict
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_formparser.py 
new/Werkzeug-0.11.11/tests/test_formparser.py
--- old/Werkzeug-0.11.3/tests/test_formparser.py        2015-09-20 
20:59:05.000000000 +0200
+++ new/Werkzeug-0.11.11/tests/test_formparser.py       2016-08-31 
15:12:07.000000000 +0200
@@ -154,7 +154,8 @@
         class StreamMPP(formparser.MultiPartParser):
 
             def parse(self, file, boundary, content_length):
-                i = iter(self.parse_lines(file, boundary, content_length))
+                i = iter(self.parse_lines(file, boundary, content_length,
+                                          cap_at_buffer=False))
                 one = next(i)
                 two = next(i)
                 return self.cls(()), {'one': one, 'two': two}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_http.py 
new/Werkzeug-0.11.11/tests/test_http.py
--- old/Werkzeug-0.11.3/tests/test_http.py      2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/tests/test_http.py     2016-08-31 15:12:07.000000000 
+0200
@@ -179,23 +179,23 @@
 
     def test_etags(self):
         assert http.quote_etag('foo') == '"foo"'
-        assert http.quote_etag('foo', True) == 'w/"foo"'
+        assert http.quote_etag('foo', True) == 'W/"foo"'
         assert http.unquote_etag('"foo"') == ('foo', False)
-        assert http.unquote_etag('w/"foo"') == ('foo', True)
-        es = http.parse_etags('"foo", "bar", w/"baz", blar')
+        assert http.unquote_etag('W/"foo"') == ('foo', True)
+        es = http.parse_etags('"foo", "bar", W/"baz", blar')
         assert sorted(es) == ['bar', 'blar', 'foo']
         assert 'foo' in es
         assert 'baz' not in es
         assert es.contains_weak('baz')
         assert 'blar' in es
-        assert es.contains_raw('w/"baz"')
+        assert es.contains_raw('W/"baz"')
         assert es.contains_raw('"foo"')
-        assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', 
'"foo"', 'w/"baz"']
+        assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', 
'"foo"', 'W/"baz"']
 
     def test_etags_nonzero(self):
-        etags = http.parse_etags('w/"foo"')
+        etags = http.parse_etags('W/"foo"')
         assert bool(etags)
-        assert etags.contains_raw('w/"foo"')
+        assert etags.contains_raw('W/"foo"')
 
     def test_parse_date(self):
         assert http.parse_date('Sun, 06 Nov 1994 08:49:37 GMT    ') == 
datetime(
@@ -247,7 +247,8 @@
         assert http.parse_options_header('something; foo="otherthing"; meh=; 
bleh') == \
             ('something', {'foo': 'otherthing', 'meh': None, 'bleh': None})
         # Issue #404
-        assert http.parse_options_header('multipart/form-data; name="foo bar"; 
filename="bar foo"') == \
+        assert http.parse_options_header('multipart/form-data; name="foo bar"; 
'
+                                         'filename="bar foo"') == \
             ('multipart/form-data', {'name': 'foo bar', 'filename': 'bar foo'})
         # Examples from RFC
         assert http.parse_options_header('audio/*; q=0.2, audio/basic') == \
@@ -260,9 +261,20 @@
             multiple=True) == \
             ('text/plain', {'q': '0.5'}, "text/html", {},
              "text/x-dvi", {'q': '0.8'}, "text/x-c", {})
-        assert http.parse_options_header('text/plain; q=0.5, text/html\n       
 text/x-dvi; q=0.8, text/x-c') == \
+        assert http.parse_options_header('text/plain; q=0.5, text/html\n'
+                                         '        '
+                                         'text/x-dvi; q=0.8, text/x-c') == \
             ('text/plain', {'q': '0.5'})
 
+    def test_parse_options_header_broken_values(self):
+        # Issue #995
+        assert http.parse_options_header(' ') == ('', {})
+        assert http.parse_options_header(' , ') == ('', {})
+        assert http.parse_options_header(' ; ') == ('', {})
+        assert http.parse_options_header(' ,; ') == ('', {})
+        assert http.parse_options_header(' , a ') == ('', {})
+        assert http.parse_options_header(' ; a ') == ('', {})
+
     def test_dump_options_header(self):
         assert http.dump_options_header('foo', {'bar': 42}) == \
             'foo; bar=42'
@@ -377,7 +389,7 @@
         assert rv.to_header() == '"Test"'
 
         # weak information is dropped
-        rv = http.parse_if_range_header('w/"Test"')
+        rv = http.parse_if_range_header('W/"Test"')
         assert rv.etag == 'Test'
         assert rv.date is None
         assert rv.to_header() == '"Test"'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_local.py 
new/Werkzeug-0.11.11/tests/test_local.py
--- old/Werkzeug-0.11.3/tests/test_local.py     2015-11-25 09:46:21.000000000 
+0100
+++ new/Werkzeug-0.11.11/tests/test_local.py    2016-08-31 15:12:07.000000000 
+0200
@@ -162,8 +162,10 @@
 def test_deepcopy_on_proxy():
     class Foo(object):
         attr = 42
+
         def __copy__(self):
             return self
+
         def __deepcopy__(self, memo):
             return self
     f = Foo()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_serving.py 
new/Werkzeug-0.11.11/tests/test_serving.py
--- old/Werkzeug-0.11.3/tests/test_serving.py   2015-10-02 16:54:47.000000000 
+0200
+++ new/Werkzeug-0.11.11/tests/test_serving.py  2016-08-31 15:12:07.000000000 
+0200
@@ -24,6 +24,11 @@
 except ImportError:
     watchdog = None
 
+try:
+    import httplib
+except ImportError:
+    from http import client as httplib
+
 import requests
 import requests.exceptions
 import pytest
@@ -39,6 +44,36 @@
     assert b'Werkzeug/' + version.encode('ascii') in rv
 
 
+def test_absolute_requests(dev_server):
+    server = dev_server('''
+    def app(environ, start_response):
+        assert environ['HTTP_HOST'] == 'surelynotexisting.example.com:1337'
+        assert environ['PATH_INFO'] == '/index.htm'
+        addr = environ['HTTP_X_WERKZEUG_ADDR']
+        assert environ['SERVER_PORT'] == addr.split(':')[1]
+        start_response('200 OK', [('Content-Type', 'text/html')])
+        return [b'YES']
+    ''')
+
+    conn = httplib.HTTPConnection(server.addr)
+    conn.request('GET', 
'http://surelynotexisting.example.com:1337/index.htm#ignorethis',
+                 headers={'X-Werkzeug-Addr': server.addr})
+    res = conn.getresponse()
+    assert res.read() == b'YES'
+
+
+def test_double_slash_path(dev_server):
+    server = dev_server('''
+    def app(environ, start_response):
+        assert 'fail' not in environ['HTTP_HOST']
+        start_response('200 OK', [('Content-Type', 'text/plain')])
+        return [b'YES']
+    ''')
+
+    r = requests.get(server.url + '//fail')
+    assert r.content == b'YES'
+
+
 def test_broken_app(dev_server):
     server = dev_server('''
     def app(environ, start_response):
@@ -196,3 +231,21 @@
     ReloaderLoop()._sleep(0)
     '''))
     subprocess.check_call(['python', str(script)])
+
+
+def test_wrong_protocol(dev_server):
+    # Assert that sending HTTPS requests to a HTTP server doesn't show a
+    # traceback
+    # See https://github.com/mitsuhiko/werkzeug/pull/838
+
+    server = dev_server('''
+    def app(environ, start_response):
+        start_response('200 OK', [('Content-Type', 'text/html')])
+        return [b'hello']
+    ''')
+    with pytest.raises(requests.exceptions.ConnectionError):
+        requests.get('https://%s/' % server.addr)
+
+    log = server.logfile.read()
+    assert 'Traceback' not in log
+    assert '\n127.0.0.1' in log
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_test.py 
new/Werkzeug-0.11.11/tests/test_test.py
--- old/Werkzeug-0.11.3/tests/test_test.py      2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/tests/test_test.py     2016-08-31 15:12:07.000000000 
+0200
@@ -143,6 +143,7 @@
     assert b.content_type == 'application/x-www-form-urlencoded'
     b.files.add_file('test', BytesIO(b'test contents'), 'test.txt')
     assert b.files['test'].content_type == 'text/plain'
+    b.form['test_int'] = 1
     assert b.content_type == 'multipart/form-data'
 
     req = b.get_request()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_wrappers.py 
new/Werkzeug-0.11.11/tests/test_wrappers.py
--- old/Werkzeug-0.11.3/tests/test_wrappers.py  2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/tests/test_wrappers.py 2016-08-31 15:12:07.000000000 
+0200
@@ -345,8 +345,8 @@
 def test_etag_request_mixin():
     request = wrappers.Request({
         'HTTP_CACHE_CONTROL':       'no-store, no-cache',
-        'HTTP_IF_MATCH':            'w/"foo", bar, "baz"',
-        'HTTP_IF_NONE_MATCH':       'w/"foo", bar, "baz"',
+        'HTTP_IF_MATCH':            'W/"foo", bar, "baz"',
+        'HTTP_IF_NONE_MATCH':       'W/"foo", bar, "baz"',
         'HTTP_IF_MODIFIED_SINCE':   'Tue, 22 Jan 2008 11:18:44 GMT',
         'HTTP_IF_UNMODIFIED_SINCE': 'Tue, 22 Jan 2008 11:18:44 GMT'
     })
@@ -355,7 +355,7 @@
 
     for etags in request.if_match, request.if_none_match:
         assert etags('bar')
-        assert etags.contains_raw('w/"foo"')
+        assert etags.contains_raw('W/"foo"')
         assert etags.contains_weak('foo')
         assert not etags.contains('foo')
 
@@ -639,17 +639,25 @@
 
 
 def test_form_parsing_failed():
-    data = (
-        b'--blah\r\n'
-    )
-    data = wrappers.Request.from_values(
+    data = b'--blah\r\n'
+    request = wrappers.Request.from_values(
         input_stream=BytesIO(data),
         content_length=len(data),
         content_type='multipart/form-data; boundary=foo',
         method='POST'
     )
-    assert not data.files
-    assert not data.form
+    assert not request.files
+    assert not request.form
+
+    # Bad Content-Type
+    data = b'test'
+    request = wrappers.Request.from_values(
+        input_stream=BytesIO(data),
+        content_length=len(data),
+        content_type=', ',
+        method='POST'
+    )
+    assert not request.form
 
 
 def test_file_closing():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/tests/test_wsgi.py 
new/Werkzeug-0.11.11/tests/test_wsgi.py
--- old/Werkzeug-0.11.3/tests/test_wsgi.py      2015-10-24 22:22:59.000000000 
+0200
+++ new/Werkzeug-0.11.11/tests/test_wsgi.py     2016-08-28 23:58:14.000000000 
+0200
@@ -381,6 +381,13 @@
                                    buffer_size=4))
     assert rv == [b'abcdef', b'ghijkl', b'mnopqrstuvwxyz', b'ABCDEFGHIJK']
 
+    data = b'abcdefXghijklXmnopqrstuvwxyzXABCDEFGHIJK'
+    test_stream = BytesIO(data)
+    rv = list(wsgi.make_chunk_iter(test_stream, 'X', limit=len(data),
+                                   buffer_size=4, cap_at_buffer=True))
+    assert rv == [b'abcd', b'ef', b'ghij', b'kl', b'mnop', b'qrst', b'uvwx',
+                  b'yz', b'ABCD', b'EFGH', b'IJK']
+
 
 def test_lines_longer_buffer_size():
     data = '1234567890\n1234567890\n'
@@ -388,3 +395,11 @@
         lines = list(wsgi.make_line_iter(NativeStringIO(data), limit=len(data),
                                          buffer_size=4))
         assert lines == ['1234567890\n', '1234567890\n']
+
+
+def test_lines_longer_buffer_size_cap():
+    data = '1234567890\n1234567890\n'
+    for bufsize in range(1, 15):
+        lines = list(wsgi.make_line_iter(NativeStringIO(data), limit=len(data),
+                                         buffer_size=4, cap_at_buffer=True))
+        assert lines == ['1234', '5678', '90\n', '1234', '5678', '90\n']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/__init__.py 
new/Werkzeug-0.11.11/werkzeug/__init__.py
--- old/Werkzeug-0.11.3/werkzeug/__init__.py    2015-12-20 00:13:27.000000000 
+0100
+++ new/Werkzeug-0.11.11/werkzeug/__init__.py   2016-08-31 15:13:02.000000000 
+0200
@@ -20,7 +20,7 @@
 from werkzeug._compat import iteritems
 
 # the version.  Usually set automatically by a script.
-__version__ = '0.11.3'
+__version__ = '0.11.11'
 
 
 # This import magic raises concerns quite often which is why the implementation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/contrib/lint.py 
new/Werkzeug-0.11.11/werkzeug/contrib/lint.py
--- old/Werkzeug-0.11.3/werkzeug/contrib/lint.py        2015-09-20 
20:59:05.000000000 +0200
+++ new/Werkzeug-0.11.11/werkzeug/contrib/lint.py       2016-08-19 
21:37:38.000000000 +0200
@@ -276,7 +276,10 @@
     def check_headers(self, headers):
         etag = headers.get('etag')
         if etag is not None:
-            if etag.startswith('w/'):
+            if etag.startswith(('W/', 'w/')):
+                if etag.startswith('w/'):
+                    warn(HTTPWarning('weak etag indicator should be upcase.'),
+                         stacklevel=4)
                 etag = etag[2:]
             if not (etag[:1] == etag[-1:] == '"'):
                 warn(HTTPWarning('unquoted etag emitted.'), stacklevel=4)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/contrib/wrappers.py 
new/Werkzeug-0.11.11/werkzeug/contrib/wrappers.py
--- old/Werkzeug-0.11.3/werkzeug/contrib/wrappers.py    2015-09-20 
20:59:05.000000000 +0200
+++ new/Werkzeug-0.11.11/werkzeug/contrib/wrappers.py   2016-08-31 
15:12:07.000000000 +0200
@@ -56,7 +56,7 @@
         if 'json' not in self.environ.get('CONTENT_TYPE', ''):
             raise BadRequest('Not a JSON request')
         try:
-            return loads(self.data)
+            return loads(self.data.decode(self.charset, self.encoding_errors))
         except Exception:
             raise BadRequest('Unable to read JSON request')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/datastructures.py 
new/Werkzeug-0.11.11/werkzeug/datastructures.py
--- old/Werkzeug-0.11.3/werkzeug/datastructures.py      2015-09-20 
20:59:05.000000000 +0200
+++ new/Werkzeug-0.11.11/werkzeug/datastructures.py     2016-08-31 
15:12:07.000000000 +0200
@@ -372,6 +372,8 @@
             tmp = {}
             for key, value in iteritems(mapping):
                 if isinstance(value, (tuple, list)):
+                    if len(value) == 0:
+                        continue
                     value = list(value)
                 else:
                     value = [value]
@@ -398,7 +400,9 @@
         :raise KeyError: if the key does not exist.
         """
         if key in self:
-            return dict.__getitem__(self, key)[0]
+            lst = dict.__getitem__(self, key)
+            if len(lst) > 0:
+                return lst[0]
         raise exceptions.BadRequestKeyError(key)
 
     def __setitem__(self, key, value):
@@ -2160,7 +2164,7 @@
             return '*'
         return ', '.join(
             ['"%s"' % x for x in self._strong] +
-            ['w/"%s"' % x for x in self._weak]
+            ['W/"%s"' % x for x in self._weak]
         )
 
     def __call__(self, etag=None, data=None, include_weak=False):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/debug/__init__.py 
new/Werkzeug-0.11.11/werkzeug/debug/__init__.py
--- old/Werkzeug-0.11.3/werkzeug/debug/__init__.py      2015-11-10 
12:49:52.000000000 +0100
+++ new/Werkzeug-0.11.11/werkzeug/debug/__init__.py     2016-08-31 
15:12:07.000000000 +0200
@@ -9,6 +9,7 @@
     :license: BSD, see LICENSE for more details.
 """
 import os
+import re
 import sys
 import uuid
 import json
@@ -16,6 +17,7 @@
 import getpass
 import hashlib
 import mimetypes
+from itertools import chain
 from os.path import join, dirname, basename, isfile
 from werkzeug.wrappers import BaseRequest as Request, BaseResponse as Response
 from werkzeug.http import parse_cookie
@@ -32,7 +34,70 @@
 from werkzeug.debug.repr import debug_repr  # noqa
 
 
-PIN_TIME = 60 * 60 * 8
+# A week
+PIN_TIME = 60 * 60 * 24 * 7
+
+
+def hash_pin(pin):
+    if isinstance(pin, text_type):
+        pin = pin.encode('utf-8', 'replace')
+    return hashlib.md5(pin + b'shittysalt').hexdigest()[:12]
+
+
+_machine_id = None
+
+
+def get_machine_id():
+    global _machine_id
+    rv = _machine_id
+    if rv is not None:
+        return rv
+
+    def _generate():
+        # Potential sources of secret information on linux.  The machine-id
+        # is stable across boots, the boot id is not
+        for filename in '/etc/machine-id', '/proc/sys/kernel/random/boot_id':
+            try:
+                with open(filename, 'rb') as f:
+                    return f.readline().strip()
+            except IOError:
+                continue
+
+        # On OS X we can use the computer's serial number assuming that
+        # ioreg exists and can spit out that information.
+        try:
+            # Also catch import errors: subprocess may not be available, e.g.
+            # Google App Engine
+            # See https://github.com/pallets/werkzeug/issues/925
+            from subprocess import Popen, PIPE
+            dump = Popen(['ioreg', '-c', 'IOPlatformExpertDevice', '-d', '2'],
+                         stdout=PIPE).communicate()[0]
+            match = re.search(b'"serial-number" = <([^>]+)', dump)
+            if match is not None:
+                return match.group(1)
+        except (OSError, ImportError):
+            pass
+
+        # On Windows we can use winreg to get the machine guid
+        wr = None
+        try:
+            import winreg as wr
+        except ImportError:
+            try:
+                import _winreg as wr
+            except ImportError:
+                pass
+        if wr is not None:
+            try:
+                with wr.OpenKey(wr.HKEY_LOCAL_MACHINE,
+                                'SOFTWARE\\Microsoft\\Cryptography', 0,
+                                wr.KEY_READ | wr.KEY_WOW64_64KEY) as rk:
+                    return wr.QueryValueEx(rk, 'MachineGuid')[0]
+            except WindowsError:
+                pass
+
+    _machine_id = rv = _generate()
+    return rv
 
 
 class _ConsoleFrame(object):
@@ -72,30 +137,50 @@
 
     modname = getattr(app, '__module__',
                       getattr(app.__class__, '__module__'))
-    bits = [
-        getpass.getuser(),
-        str(uuid.getnode()),
+
+    try:
+        # `getpass.getuser()` imports the `pwd` module,
+        # which does not exist in the Google App Engine sandbox.
+        username = getpass.getuser()
+    except ImportError:
+        username = None
+
+    mod = sys.modules.get(modname)
+
+    # This information only exists to make the cookie unique on the
+    # computer, not as a security feature.
+    probably_public_bits = [
+        username,
         modname,
         getattr(app, '__name__', getattr(app.__class__, '__name__')),
+        getattr(mod, '__file__', None),
     ]
 
-    mod = sys.modules.get(modname)
-    bits.append(getattr(mod, '__file__', None))
-    bits.append('cookiesalt')
+    # This information is here to make it harder for an attacker to
+    # guess the cookie name.  They are unlikely to be contained anywhere
+    # within the unauthenticated debug page.
+    private_bits = [
+        str(uuid.getnode()),
+        get_machine_id(),
+    ]
 
     h = hashlib.md5()
-    for bit in bits:
+    for bit in chain(probably_public_bits, private_bits):
         if not bit:
             continue
         if isinstance(bit, text_type):
             bit = bit.encode('utf-8')
         h.update(bit)
+    h.update(b'cookiesalt')
 
+    cookie_name = '__wzd' + h.hexdigest()[:20]
+
+    # If we need to generate a pin we salt it a bit more so that we don't
+    # end up with the same value and generate out 9 digits
     if num is None:
+        h.update(b'pinsalt')
         num = ('%09d' % int(h.hexdigest(), 16))[:9]
 
-    cookie_name = '__wzd' + h.hexdigest()[:12]
-
     # Format the pincode in groups of digits for easier remembering if
     # we don't have a result yet.
     if rv is None:
@@ -228,7 +313,7 @@
                     'response at a point where response headers were already '
                     'sent.\n')
             else:
-                is_trusted = self.is_trusted(environ)
+                is_trusted = bool(self.check_pin_trust(environ))
                 yield traceback.render_full(evalex=self.evalex,
                                             evalex_trusted=is_trusted,
                                             secret=self.secret) \
@@ -249,7 +334,7 @@
                 ns = dict(self.console_init_func())
             ns.setdefault('app', self.app)
             self.frames[0] = _ConsoleFrame(ns)
-        is_trusted = self.is_trusted(request.environ)
+        is_trusted = bool(self.check_pin_trust(request.environ))
         return Response(render_console_html(secret=self.secret,
                                             evalex_trusted=is_trusted),
                         mimetype='text/html')
@@ -272,23 +357,53 @@
                 f.close()
         return Response('Not Found', status=404)
 
-    def is_trusted(self, environ):
-        """Checks if the request passed the pin test."""
+    def check_pin_trust(self, environ):
+        """Checks if the request passed the pin test.  This returns `True` if 
the
+        request is trusted on a pin/cookie basis and returns `False` if not.
+        Additionally if the cookie's stored pin hash is wrong it will return
+        `None` so that appropriate action can be taken.
+        """
         if self.pin is None:
             return True
-        ts = parse_cookie(environ).get(self.pin_cookie_name, type=int)
-        if ts is None:
+        val = parse_cookie(environ).get(self.pin_cookie_name)
+        if not val or '|' not in val:
             return False
-        return (time.time() - PIN_TIME) < ts
+        ts, pin_hash = val.split('|', 1)
+        if not ts.isdigit():
+            return False
+        if pin_hash != hash_pin(self.pin):
+            return None
+        return (time.time() - PIN_TIME) < int(ts)
+
+    def _fail_pin_auth(self):
+        time.sleep(self._failed_pin_auth > 5 and 5.0 or 0.5)
+        self._failed_pin_auth += 1
 
     def pin_auth(self, request):
         """Authenticates with the pin."""
         exhausted = False
         auth = False
-        if self.is_trusted(request.environ):
+        trust = self.check_pin_trust(request.environ)
+
+        # If the trust return value is `None` it means that the cookie is
+        # set but the stored pin hash value is bad.  This means that the
+        # pin was changed.  In this case we count a bad auth and unset the
+        # cookie.  This way it becomes harder to guess the cookie name
+        # instead of the pin as we still count up failures.
+        bad_cookie = False
+        if trust is None:
+            self._fail_pin_auth()
+            bad_cookie = True
+
+        # If we're trusted, we're authenticated.
+        elif trust:
             auth = True
+
+        # If we failed too many times, then we're locked out.
         elif self._failed_pin_auth > 10:
             exhausted = True
+
+        # Otherwise go through pin based authentication
         else:
             entered_pin = request.args.get('pin')
             if entered_pin.strip().replace('-', '') == \
@@ -296,17 +411,19 @@
                 self._failed_pin_auth = 0
                 auth = True
             else:
-                time.sleep(self._failed_pin_auth > 5 and 5.0 or 0.5)
-                self._failed_pin_auth += 1
-                auth = False
+                self._fail_pin_auth()
 
         rv = Response(json.dumps({
             'auth': auth,
             'exhausted': exhausted,
         }), mimetype='application/json')
         if auth:
-            rv.set_cookie(self.pin_cookie_name, str(int(time.time())),
-                          httponly=True)
+            rv.set_cookie(self.pin_cookie_name, '%s|%s' % (
+                int(time.time()),
+                hash_pin(self.pin)
+            ), httponly=True)
+        elif bad_cookie:
+            rv.delete_cookie(self.pin_cookie_name)
         return rv
 
     def log_pin_request(self):
@@ -341,7 +458,7 @@
                 response = self.log_pin_request()
             elif self.evalex and cmd is not None and frame is not None \
                     and self.secret == secret and \
-                    self.is_trusted(environ):
+                    self.check_pin_trust(environ):
                 response = self.execute_command(request, cmd, frame)
         elif self.evalex and self.console_path is not None and \
                 request.path == self.console_path:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/debug/tbtools.py 
new/Werkzeug-0.11.11/werkzeug/debug/tbtools.py
--- old/Werkzeug-0.11.3/werkzeug/debug/tbtools.py       2015-10-24 
22:22:59.000000000 +0200
+++ new/Werkzeug-0.11.11/werkzeug/debug/tbtools.py      2016-08-31 
15:12:01.000000000 +0200
@@ -358,7 +358,7 @@
             'exception':        exc,
             'exception_type':   escape(self.exception_type),
             'summary':          self.render_summary(include_title=False),
-            'plaintext':        self.plaintext,
+            'plaintext':        escape(self.plaintext),
             'plaintext_cs':     re.sub('-{2,}', '-', self.plaintext),
             'traceback_id':     self.id,
             'secret':           secret
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/filesystem.py 
new/Werkzeug-0.11.11/werkzeug/filesystem.py
--- old/Werkzeug-0.11.3/werkzeug/filesystem.py  2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/werkzeug/filesystem.py 2016-08-28 23:58:14.000000000 
+0200
@@ -59,7 +59,7 @@
         if not _warned_about_filesystem_encoding:
             warnings.warn(
                 'Detected a misconfigured UNIX filesystem: Will use UTF-8 as '
-                'filesystem encoding instead of {!r}'.format(rv),
+                'filesystem encoding instead of {0!r}'.format(rv),
                 BrokenFilesystemWarning)
             _warned_about_filesystem_encoding = True
         return 'utf-8'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/formparser.py 
new/Werkzeug-0.11.11/werkzeug/formparser.py
--- old/Werkzeug-0.11.3/werkzeug/formparser.py  2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/werkzeug/formparser.py 2016-08-31 15:12:07.000000000 
+0200
@@ -372,7 +372,7 @@
             # the assert is skipped.
             self.fail('Boundary longer than buffer size')
 
-    def parse_lines(self, file, boundary, content_length):
+    def parse_lines(self, file, boundary, content_length, cap_at_buffer=True):
         """Generate parts of
         ``('begin_form', (headers, name))``
         ``('begin_file', (headers, name, filename))``
@@ -387,7 +387,8 @@
         last_part = next_part + b'--'
 
         iterator = chain(make_line_iter(file, limit=content_length,
-                                        buffer_size=self.buffer_size),
+                                        buffer_size=self.buffer_size,
+                                        cap_at_buffer=cap_at_buffer),
                          _empty_string_iter)
 
         terminator = self._find_terminator(iterator)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/http.py 
new/Werkzeug-0.11.11/werkzeug/http.py
--- old/Werkzeug-0.11.3/werkzeug/http.py        2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/werkzeug/http.py       2016-08-31 15:12:07.000000000 
+0200
@@ -336,7 +336,6 @@
     :return: (mimetype, options) or (mimetype, options, mimetype, options, …)
              if multiple=True
     """
-
     if not value:
         return '', {}
 
@@ -368,7 +367,7 @@
             return tuple(result)
         value = rest
 
-    return tuple(result)
+    return tuple(result) if result else ('', {})
 
 
 def parse_accept_header(value, cls=None):
@@ -627,14 +626,14 @@
         raise ValueError('invalid etag')
     etag = '"%s"' % etag
     if weak:
-        etag = 'w/' + etag
+        etag = 'W/' + etag
     return etag
 
 
 def unquote_etag(etag):
     """Unquote a single etag:
 
-    >>> unquote_etag('w/"bar"')
+    >>> unquote_etag('W/"bar"')
     ('bar', True)
     >>> unquote_etag('"bar"')
     ('bar', False)
@@ -646,7 +645,7 @@
         return None, None
     etag = etag.strip()
     weak = False
-    if etag[:2] in ('w/', 'W/'):
+    if etag.startswith(('W/', 'w/')):
         weak = True
         etag = etag[2:]
     if etag[:1] == etag[-1:] == '"':
@@ -800,7 +799,11 @@
     if etag:
         if_none_match = parse_etags(environ.get('HTTP_IF_NONE_MATCH'))
         if if_none_match:
-            unmodified = if_none_match.contains_raw(etag)
+            # http://tools.ietf.org/html/rfc7232#section-3.2
+            # "A recipient MUST use the weak comparison function when comparing
+            # entity-tags for If-None-Match"
+            etag, _ = unquote_etag(etag)
+            unmodified = if_none_match.contains_weak(etag)
 
     return not unmodified
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/serving.py 
new/Werkzeug-0.11.11/werkzeug/serving.py
--- old/Werkzeug-0.11.3/werkzeug/serving.py     2015-12-20 00:12:55.000000000 
+0100
+++ new/Werkzeug-0.11.11/werkzeug/serving.py    2016-08-31 15:12:07.000000000 
+0200
@@ -42,8 +42,6 @@
 import sys
 import signal
 
-from ._compat import PY2
-
 try:
     import ssl
 except ImportError:
@@ -70,9 +68,10 @@
     from socketserver import ThreadingMixIn, ForkingMixIn
     from http.server import HTTPServer, BaseHTTPRequestHandler
 
+# important: do not use relative imports here or python -m will break
 import werkzeug
 from werkzeug._internal import _log
-from werkzeug._compat import reraise, wsgi_encoding_dance
+from werkzeug._compat import PY2, reraise, wsgi_encoding_dance
 from werkzeug.urls import url_parse, url_unquote
 from werkzeug.exceptions import InternalServerError
 
@@ -114,8 +113,8 @@
             'QUERY_STRING':         wsgi_encoding_dance(request_url.query),
             'CONTENT_TYPE':         self.headers.get('Content-Type', ''),
             'CONTENT_LENGTH':       self.headers.get('Content-Length', ''),
-            'REMOTE_ADDR':          self.client_address[0],
-            'REMOTE_PORT':          self.client_address[1],
+            'REMOTE_ADDR':          self.address_string(),
+            'REMOTE_PORT':          self.port_integer(),
             'SERVER_NAME':          self.server.server_address[0],
             'SERVER_PORT':          str(self.server.server_address[1]),
             'SERVER_PROTOCOL':      self.request_version
@@ -126,7 +125,7 @@
             if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
                 environ[key] = value
 
-        if request_url.netloc:
+        if request_url.scheme and request_url.netloc:
             environ['HTTP_HOST'] = request_url.netloc
 
         return environ
@@ -264,7 +263,10 @@
         return BaseHTTPRequestHandler.version_string(self).strip()
 
     def address_string(self):
-        return self.environ['REMOTE_ADDR']
+        return self.client_address[0]
+
+    def port_integer(self):
+        return self.client_address[1]
 
     def log_request(self, code='-', size='-'):
         self.log('info', '"%s" %s %s', self.requestline, code, size)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/test.py 
new/Werkzeug-0.11.11/werkzeug/test.py
--- old/Werkzeug-0.11.3/werkzeug/test.py        2015-09-20 20:59:05.000000000 
+0200
+++ new/Werkzeug-0.11.11/werkzeug/test.py       2016-08-31 15:12:07.000000000 
+0200
@@ -99,8 +99,8 @@
             else:
                 if not isinstance(value, string_types):
                     value = str(value)
-                else:
-                    value = to_bytes(value, charset)
+
+                value = to_bytes(value, charset)
                 write('\r\n\r\n')
                 write_binary(value)
             write('\r\n')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/urls.py 
new/Werkzeug-0.11.11/werkzeug/urls.py
--- old/Werkzeug-0.11.3/werkzeug/urls.py        2015-11-12 12:21:06.000000000 
+0100
+++ new/Werkzeug-0.11.11/werkzeug/urls.py       2016-08-19 21:37:38.000000000 
+0200
@@ -40,8 +40,10 @@
 )
 
 
-_URLTuple = fix_tuple_repr(namedtuple('_URLTuple',
-    ['scheme', 'netloc', 'path', 'query', 'fragment']))
+_URLTuple = fix_tuple_repr(namedtuple(
+    '_URLTuple',
+    ['scheme', 'netloc', 'path', 'query', 'fragment']
+))
 
 
 class BaseURL(_URLTuple):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Werkzeug-0.11.3/werkzeug/wsgi.py 
new/Werkzeug-0.11.11/werkzeug/wsgi.py
--- old/Werkzeug-0.11.3/werkzeug/wsgi.py        2015-11-12 12:21:06.000000000 
+0100
+++ new/Werkzeug-0.11.11/werkzeug/wsgi.py       2016-08-31 15:12:07.000000000 
+0200
@@ -784,7 +784,8 @@
         yield item
 
 
-def make_line_iter(stream, limit=None, buffer_size=10 * 1024):
+def make_line_iter(stream, limit=None, buffer_size=10 * 1024,
+                   cap_at_buffer=False):
     """Safely iterates line-based over an input stream.  If the input stream
     is not a :class:`LimitedStream` the `limit` parameter is mandatory.
 
@@ -808,6 +809,12 @@
                   content length.  Not necessary if the `stream`
                   is a :class:`LimitedStream`.
     :param buffer_size: The optional buffer size.
+    :param cap_at_buffer: if this is set chunks are split if they are longer
+                          than the buffer size.  Internally this is implemented
+                          that the buffer size might be exhausted by a factor
+                          of two however.
+    .. versionadded:: 0.11.10
+       added support for the `cap_at_buffer` parameter.
     """
     _iter = _make_chunk_iter(stream, limit, buffer_size)
 
@@ -831,11 +838,19 @@
             if not new_data:
                 break
             new_buf = []
+            buf_size = 0
             for item in chain(buffer, new_data.splitlines(True)):
                 new_buf.append(item)
+                buf_size += len(item)
                 if item and item[-1:] in crlf:
                     yield _join(new_buf)
                     new_buf = []
+                elif cap_at_buffer and buf_size >= buffer_size:
+                    rv = _join(new_buf)
+                    while len(rv) >= buffer_size:
+                        yield rv[:buffer_size]
+                        rv = rv[buffer_size:]
+                    new_buf = [rv]
             buffer = new_buf
         if buffer:
             yield _join(buffer)
@@ -854,7 +869,8 @@
         yield previous
 
 
-def make_chunk_iter(stream, separator, limit=None, buffer_size=10 * 1024):
+def make_chunk_iter(stream, separator, limit=None, buffer_size=10 * 1024,
+                    cap_at_buffer=False):
     """Works like :func:`make_line_iter` but accepts a separator
     which divides chunks.  If you want newline based processing
     you should use :func:`make_line_iter` instead as it
@@ -865,12 +881,19 @@
     .. versionadded:: 0.9
        added support for iterators as input stream.
 
+    .. versionadded:: 0.11.10
+       added support for the `cap_at_buffer` parameter.
+
     :param stream: the stream or iterate to iterate over.
     :param separator: the separator that divides chunks.
     :param limit: the limit in bytes for the stream.  (Usually
                   content length.  Not necessary if the `stream`
                   is otherwise already limited).
     :param buffer_size: The optional buffer size.
+    :param cap_at_buffer: if this is set chunks are split if they are longer
+                          than the buffer size.  Internally this is implemented
+                          that the buffer size might be exhausted by a factor
+                          of two however.
     """
     _iter = _make_chunk_iter(stream, limit, buffer_size)
 
@@ -895,12 +918,24 @@
             break
         chunks = _split(new_data)
         new_buf = []
+        buf_size = 0
         for item in chain(buffer, chunks):
             if item == separator:
                 yield _join(new_buf)
                 new_buf = []
+                buf_size = 0
             else:
+                buf_size += len(item)
                 new_buf.append(item)
+
+                if cap_at_buffer and buf_size >= buffer_size:
+                    rv = _join(new_buf)
+                    while len(rv) >= buffer_size:
+                        yield rv[:buffer_size]
+                        rv = rv[buffer_size:]
+                    new_buf = [rv]
+                    buf_size = len(rv)
+
         buffer = new_buf
     if buffer:
         yield _join(buffer)


Reply via email to