diff options
| author | Armin Ronacher <armin.ronacher@active-4.com> | 2014-09-06 14:47:19 +0200 |
|---|---|---|
| committer | Markus Unterwaditzer <markus@unterwaditzer.net> | 2014-09-06 16:26:40 +0200 |
| commit | 45c8ea57e3cac6c204642cb7434244c23cf62a58 (patch) | |
| tree | 51dfa5f44e1f0d9e6fe00937932071c51ca0cdd2 | |
| parent | e729594dcadb2d20af6f55e2cbce7efb3aaff6b8 (diff) | |
| download | werkzeug-header_merging.tar.gz | |
Added proper header merging to the simple server.header_merging
| -rw-r--r-- | CHANGES | 1 | ||||
| -rw-r--r-- | werkzeug/serving.py | 26 | ||||
| -rw-r--r-- | werkzeug/testsuite/serving.py | 21 |
3 files changed, 46 insertions, 2 deletions
@@ -26,6 +26,7 @@ Version 0.9.7 - ``werkzeug.urls.url_fix`` now doesn't crash on malformed URLs anymore, but returns them unmodified. This is a cheap workaround for ``#582``, the proper fix is included in version 0.10. +- Fixed header concatenation on the Werkzeug server. Version 0.9.6 ------------- diff --git a/werkzeug/serving.py b/werkzeug/serving.py index 98e9d1f6..76501033 100644 --- a/werkzeug/serving.py +++ b/werkzeug/serving.py @@ -61,7 +61,23 @@ from werkzeug._internal import _log from werkzeug._compat import iteritems, PY2, reraise, text_type, \ wsgi_encoding_dance from werkzeug.urls import url_parse, url_unquote -from werkzeug.exceptions import InternalServerError, BadRequest +from werkzeug.exceptions import InternalServerError + + +def _iter_headers(lineiter): + """Super crappy way to iterate over lines that might look like HTTP + headers. This must only be used with preparsed HTTP messages. This + would be nice if it was not necessary but unfortunately the rfc822 + Message in the stdlib is not very good. + """ + rv = [] + for line in lineiter: + if not line[:1].isspace(): + key, value = line.split(':', 1) + rv.append((key.strip(), value.strip())) + elif rv: + rv[-1] = (rv[-1][0], rv[-1][1] + '\n ' + line[1:].strip()) + return rv class WSGIRequestHandler(BaseHTTPRequestHandler, object): @@ -104,9 +120,15 @@ class WSGIRequestHandler(BaseHTTPRequestHandler, object): 'SERVER_PROTOCOL': self.request_version } - for key, value in self.headers.items(): + for key, value in _iter_headers(self.headers.headers): key = 'HTTP_' + key.upper().replace('-', '_') if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): + if key in environ: + value = '%s%s%s' % ( + environ[key], + key == 'HTTP_COOKIE' and '; ' or ', ', + value, + ) environ[key] = value if request_url.netloc: diff --git a/werkzeug/testsuite/serving.py b/werkzeug/testsuite/serving.py index e478de26..0bc1b0b5 100644 --- a/werkzeug/testsuite/serving.py +++ b/werkzeug/testsuite/serving.py @@ -110,6 +110,27 @@ class ServingTestCase(WerkzeugTestCase): res = conn.getresponse() assert res.read() == b'YES' + @silencestderr + def test_header_merging(self): + def asserting_app(environ, start_response): + assert environ['HTTP_X_FOO'] == 'foo, bar' + assert environ['HTTP_COOKIE'] == 'foo; bar' + assert environ['HTTP_CONT'] == '1 2\n 3' + start_response('200 OK', [('Content-Type', 'text/plain')]) + return [b'OK'] + + server, addr = run_dev_server(asserting_app) + conn = httplib.HTTPConnection(addr) + conn.putrequest('GET', '/') + conn.putheader('X-Foo', 'foo') + conn.putheader('X_Foo', 'bar') + conn.putheader('Cookie', 'foo') + conn.putheader('Cookie', 'bar') + conn.putheader('Cont', '1 2\n 3') + conn.endheaders() + res = conn.getresponse() + assert res.read() == b'OK' + def suite(): suite = unittest.TestSuite() |
