py3: Be able to parse non-RFC-compliant request lines · openstack/swift@93b49c5
@@ -35,7 +35,8 @@
35353636from swift.common import utils, constraints
3737from 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
3940from swift.common.utils import capture_stdio, disable_fallocate, \
4041drop_privileges, get_logger, NullLogger, config_true_value, \
4142validate_configuration, get_hub, config_auto_int_value, \
@@ -433,6 +434,36 @@ def get_default_type(self):
433434'''If the client didn't provide a content type, leave it blank.'''
434435return ''
435436437+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+436467437468class SwiftHttpProxiedProtocol(SwiftHttpProtocol):
438469"""