py3: Be able to parse non-RFC-compliant request lines · openstack/swift@93b49c5 (original) (raw)
`@@ -35,7 +35,8 @@
`
35
35
``
36
36
`from swift.common import utils, constraints
`
37
37
`from swift.common.storage_policy import BindPortsCache
`
38
``
`-
from swift.common.swob import Request, wsgi_unquote
`
``
38
`+
from swift.common.swob import Request, wsgi_quote, wsgi_unquote, \
`
``
39
`+
wsgi_quote_plus, wsgi_unquote_plus, wsgi_to_bytes, bytes_to_wsgi
`
39
40
`from swift.common.utils import capture_stdio, disable_fallocate, \
`
40
41
`drop_privileges, get_logger, NullLogger, config_true_value, \
`
41
42
`validate_configuration, get_hub, config_auto_int_value, \
`
`@@ -433,6 +434,36 @@ def get_default_type(self):
`
433
434
`'''If the client didn't provide a content type, leave it blank.'''
`
434
435
`return ''
`
435
436
``
``
437
`+
def parse_request(self):
`
``
438
`+
if not six.PY2:
`
``
439
`+
request lines should be ascii per the RFC, but historically
`
``
440
`+
we've allowed (and even have func tests that use) arbitrary
`
``
441
`+
bytes. This breaks on py3 (see https://bugs.python.org/issue33973
`
``
442
`+
) but the work-around is simple: munge the request line to be
`
``
443
`+
properly quoted. py2 will do the right thing without this, but it
`
``
444
`+
doesn't hurt to re-write the request line like this and it
`
``
445
`+
simplifies testing.
`
``
446
`+
if self.raw_requestline.count(b' ') >= 2:
`
``
447
`+
parts = self.raw_requestline.split(b' ', 2)
`
``
448
`+
path, q, query = parts[1].partition(b'?')
`
``
449
`+
unquote first, so we don't over-quote something
`
``
450
`+
that was correctly quoted
`
``
451
`+
path = wsgi_to_bytes(wsgi_quote(wsgi_unquote(
`
``
452
`+
bytes_to_wsgi(path))))
`
``
453
`+
query = b'&'.join(
`
``
454
`+
sep.join([
`
``
455
`+
wsgi_to_bytes(wsgi_quote_plus(wsgi_unquote_plus(
`
``
456
`+
bytes_to_wsgi(key)))),
`
``
457
`+
wsgi_to_bytes(wsgi_quote_plus(wsgi_unquote_plus(
`
``
458
`+
bytes_to_wsgi(val))))
`
``
459
`+
])
`
``
460
`+
for part in query.split(b'&')
`
``
461
`+
for key, sep, val in (part.partition(b'='), ))
`
``
462
`+
parts[1] = path + q + query
`
``
463
`+
self.raw_requestline = b' '.join(parts)
`
``
464
`+
else, mangled protocol, most likely; let base class deal with it
`
``
465
`+
return wsgi.HttpProtocol.parse_request(self)
`
``
466
+
436
467
``
437
468
`class SwiftHttpProxiedProtocol(SwiftHttpProtocol):
`
438
469
`"""
`