Skip to content

Commit

Permalink
Testing: make publish utility functions handle PATH_INFO (#1060)
Browse files Browse the repository at this point in the history
backport #1059 on 4.x
  • Loading branch information
perrinjerome committed Oct 5, 2022
1 parent 455c42f commit 337bc76
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 20 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ https://zope.readthedocs.io/en/2.13/CHANGES.html
``urllib.parse.quote``
(`#1052 <https://github.com/zopefoundation/Zope/issues/1052>`_).

- Change functional testing utilities to support percent encoded and unicode
paths (`#1058 <https://github.com/zopefoundation/Zope/issues/1058>`_).


4.8.2 (2022-06-01)
------------------
Expand Down
29 changes: 19 additions & 10 deletions src/Testing/ZopeTestCase/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from functools import partial

from six import PY2
from six.moves.urllib.parse import unquote_to_bytes

import transaction
from Testing.ZopeTestCase import interfaces
Expand Down Expand Up @@ -81,13 +82,14 @@ def publish(self, path, basic=None, env=None, extra=None,
env['SERVER_PROTOCOL'] = 'HTTP/1.1'
env['REQUEST_METHOD'] = request_method

p = path.split('?')
if len(p) == 1:
env['PATH_INFO'] = p[0]
elif len(p) == 2:
[env['PATH_INFO'], env['QUERY_STRING']] = p
query = ''
if '?' in path:
path, query = path.split("?", 1)
if PY2:
env['PATH_INFO'] = unquote_to_bytes(path)
else:
raise TypeError('')
env['PATH_INFO'] = unquote_to_bytes(path).decode('latin-1')
env['QUERY_STRING'] = query

if basic:
env['HTTP_AUTHORIZATION'] = basic_auth_encode(basic)
Expand All @@ -98,12 +100,16 @@ def publish(self, path, basic=None, env=None, extra=None,

if stdin is None:
stdin = BytesIO()
env['wsgi.input'] = stdin

outstream = BytesIO()
response = WSGIResponse(stdout=outstream, stderr=sys.stderr)
request = Request(stdin, env, response)
for k, v in extra.items():
request[k] = v

def request_factory(*args):
request = Request(*args)
for k, v in extra.items():
request[k] = v
return request

wsgi_headers = BytesIO()

Expand All @@ -121,7 +127,10 @@ def start_response(status, headers):
wsgi_headers.write(headers)
wsgi_headers.write(b'\r\n\r\n')

publish = partial(publish_module, _request=request, _response=response)
publish = partial(
publish_module,
_request_factory=request_factory,
_response=response)
if handle_errors:
publish = HTTPExceptionHandler(publish)

Expand Down
14 changes: 14 additions & 0 deletions src/Testing/ZopeTestCase/testFunctional.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
##############################################################################
# coding: utf-8
#
# Copyright (c) 2005 Zope Foundation and Contributors.
#
Expand Down Expand Up @@ -61,6 +62,9 @@ def afterSetUp(self):
# A method changing the title property of an object
self.folder.addDTMLMethod('change_title', file=CHANGE_TITLE_DTML)

# A method with a non-ascii path
self.folder.addDTMLMethod('täst', file=b'test')

def testPublishFolder(self):
response = self.publish(self.folder_path)
self.assertEqual(response.getStatus(), 200)
Expand All @@ -71,6 +75,16 @@ def testPublishDocument(self):
self.assertEqual(response.getStatus(), 200)
self.assertEqual(response.getBody(), b'index')

def testPublishDocumentNonAscii(self):
response = self.publish(self.folder_path + '/täst')
self.assertEqual(response.getStatus(), 200)
self.assertEqual(response.getBody(), b'test')

def testPublishDocumentNonAsciiUrlEncoded(self):
response = self.publish(self.folder_path + '/t%C3%A4st')
self.assertEqual(response.getStatus(), 200)
self.assertEqual(response.getBody(), b'test')

def testUnauthorized(self):
response = self.publish(self.folder_path + '/secret_html')
self.assertEqual(response.getStatus(), 401)
Expand Down
24 changes: 14 additions & 10 deletions src/Testing/ZopeTestCase/zopedoctest/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from functools import partial
from io import BytesIO

from six import PY2
from six import text_type

import transaction
Expand Down Expand Up @@ -137,7 +138,8 @@ def http(request_string, handle_errors=True):
This is used for HTTP doc tests.
"""
from six.moves.urllib.parse import unquote
from six.moves.urllib.parse import unquote_to_bytes

from ZPublisher.HTTPRequest import WSGIRequest as Request
from ZPublisher.HTTPResponse import WSGIResponse
from ZPublisher.WSGIPublisher import publish_module
Expand All @@ -153,7 +155,6 @@ def http(request_string, handle_errors=True):
command_line = request_string[:newline].rstrip()
request_string = request_string[newline + 1:]
method, path, protocol = command_line.split()
path = unquote(path)

env = {
'HTTP_HOST': 'localhost',
Expand All @@ -162,13 +163,14 @@ def http(request_string, handle_errors=True):
'SERVER_PROTOCOL': protocol,
}

p = path.split('?', 1)
if len(p) == 1:
env['PATH_INFO'] = p[0]
elif len(p) == 2:
[env['PATH_INFO'], env['QUERY_STRING']] = p
query = ''
if '?' in path:
path, query = path.split("?", 1)
if PY2:
env['PATH_INFO'] = unquote_to_bytes(path)
else:
raise TypeError('')
env['PATH_INFO'] = unquote_to_bytes(path).decode('latin-1')
env['QUERY_STRING'] = query

header_output = HTTPHeaderOutput(
protocol, ('x-content-type-warning', 'x-powered-by'))
Expand Down Expand Up @@ -201,7 +203,6 @@ def http(request_string, handle_errors=True):

outstream = BytesIO()
response = WSGIResponse(stdout=outstream, stderr=sys.stderr)
request = Request(instream, env, response)

env['wsgi.input'] = instream
wsgi_headers = BytesIO()
Expand All @@ -214,7 +215,10 @@ def start_response(status, headers):
wsgi_headers.write(headers)
wsgi_headers.write(b'\r\n\r\n')

publish = partial(publish_module, _request=request, _response=response)
publish = partial(
publish_module,
_request_factory=Request,
_response=response)
if handle_errors:
publish = HTTPExceptionHandler(publish)

Expand Down

0 comments on commit 337bc76

Please sign in to comment.