py3: Be able to parse non-RFC-compliant request lines · openstack/swift@93b49c5

@@ -35,7 +35,8 @@

35353636

from swift.common import utils, constraints

3737

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

3940

from swift.common.utils import capture_stdio, disable_fallocate, \

4041

drop_privileges, get_logger, NullLogger, config_true_value, \

4142

validate_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.'''

434435

return ''

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+436467437468

class SwiftHttpProxiedProtocol(SwiftHttpProtocol):

438469

"""