Skip to content

Commit

Permalink
Merge branch 'master' into restore_response_unauthorized
Browse files Browse the repository at this point in the history
  • Loading branch information
hannosch committed May 5, 2017
2 parents 14312c0 + 23f094f commit 17b01b7
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 24 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Expand Up @@ -13,6 +13,8 @@ Bugs Fixed

- Restore a `_unauthorized` hook on the response object.

- Restore `HTTPResponse.redirect` behaviour of not raising an exception.

Features Added
++++++++++++++

Expand Down
36 changes: 36 additions & 0 deletions src/Testing/tests/test_testbrowser.py
Expand Up @@ -42,6 +42,13 @@ def __call__(self, REQUEST):
raise ValueError('dummy')


class RedirectStub(Item):
"""This is a stub, causing a redirect."""

def __call__(self, REQUEST):
return REQUEST.RESPONSE.redirect('/redirected')


class TestTestbrowser(FunctionalTestCase):

def test_auth(self):
Expand Down Expand Up @@ -86,6 +93,7 @@ def test_cookies(self):
def test_handle_errors_true(self):
self.folder._setObject('stub', ExceptionStub())
browser = Browser()

with self.assertRaises(HTTPError):
browser.open('http://localhost/test_folder_1_/stub')
self.assertTrue(browser.headers['status'].startswith('500'))
Expand All @@ -94,10 +102,20 @@ def test_handle_errors_true(self):
browser.open('http://localhost/nothing-is-here')
self.assertTrue(browser.headers['status'].startswith('404'))

def test_handle_errors_true_redirect(self):
self.folder._setObject('redirect', RedirectStub())
browser = Browser()

with self.assertRaises(HTTPError):
browser.open('http://localhost/test_folder_1_/redirect')
self.assertTrue(browser.headers['status'].startswith('404'))
self.assertEqual(browser.url, 'http://localhost/redirected')

def test_handle_errors_false(self):
self.folder._setObject('stub', ExceptionStub())
browser = Browser()
browser.handleErrors = False

with self.assertRaises(ValueError):
browser.open('http://localhost/test_folder_1_/stub')
self.assertTrue(browser.contents is None)
Expand All @@ -106,6 +124,15 @@ def test_handle_errors_false(self):
browser.open('http://localhost/nothing-is-here')
self.assertTrue(browser.contents is None)

def test_handle_errors_false_redirect(self):
self.folder._setObject('redirect', RedirectStub())
browser = Browser()
browser.handleErrors = False

with self.assertRaises(NotFound):
browser.open('http://localhost/test_folder_1_/redirect')
self.assertTrue(browser.contents is None)

def test_raise_http_errors_false(self):
self.folder._setObject('stub', ExceptionStub())
browser = Browser()
Expand All @@ -117,6 +144,15 @@ def test_raise_http_errors_false(self):
browser.open('http://localhost/nothing-is-here')
self.assertTrue(browser.headers['status'].startswith('404'))

def test_raise_http_errors_false_redirect(self):
self.folder._setObject('redirect', RedirectStub())
browser = Browser()
browser.raiseHttpErrors = False

browser.open('http://localhost/test_folder_1_/redirect')
self.assertTrue(browser.headers['status'].startswith('404'))
self.assertEqual(browser.url, 'http://localhost/redirected')

def test_headers_camel_case(self):
# The Zope2 response mungs headers so they come out
# in camel case. We should do the same.
Expand Down
27 changes: 9 additions & 18 deletions src/ZPublisher/HTTPResponse.py
Expand Up @@ -174,6 +174,15 @@ def __init__(self,
self.stdout = stdout
self.stderr = stderr

def redirect(self, location, status=302, lock=0):
"""Cause a redirection without raising an error"""
if isinstance(location, HTTPRedirection):
status = location.getStatus()
location = str(location)
self.setStatus(status, lock=lock)
self.setHeader('Location', location)
return location

def retry(self):
""" Return a cloned response object to be used in a retry attempt.
"""
Expand Down Expand Up @@ -798,15 +807,6 @@ def unauthorized(self):
m = m + '\nNo Authorization header found.'
raise Unauthorized(m)

def redirect(self, location, status=302, lock=0):
"""Cause a redirection without raising an error"""
if isinstance(location, HTTPRedirection):
status = location.getStatus()
location = str(location)
self.setStatus(status, lock=lock)
self.setHeader('Location', location)
return location

def _setBCIHeaders(self, t, tb):
try:
# Try to capture exception info for bci calls
Expand Down Expand Up @@ -1009,15 +1009,6 @@ def unauthorized(self):
exc.detail = 'No Authorization header found.'
raise exc

def redirect(self, location, status=302, lock=0):
"""Cause a redirection."""
if isinstance(location, HTTPRedirection):
raise location

exc = Redirect(str(location))
exc.setStatus(status)
raise exc

def exception(self, fatal=0, info=None, abort=1):
if isinstance(info, tuple) and len(info) == 3:
t, v, tb = info
Expand Down
21 changes: 21 additions & 0 deletions src/ZTUtils/Zope.py
Expand Up @@ -166,6 +166,22 @@ def __init__(self, sequence, size, start=0, end=0,
# "make_query(bstart=batch.end)" to the other.


#Do not do this at import time.
#Call '_default_encoding()' at run time to retrieve it from config, if present
#If not configured, will be 'utf8' by default.
_DEFAULT_ENCODING = None
def _default_encoding():
''' Retreive default encoding from config '''
global _DEFAULT_ENCODING
if _DEFAULT_ENCODING is None:
from App.config import getConfiguration
config = getConfiguration()
try:
_DEFAULT_ENCODING = config.zpublisher_default_encoding
except AttributeError:
_DEFAULT_ENCODING = 'utf8'
return _DEFAULT_ENCODING

def make_query(*args, **kwargs):
'''Construct a URL query string, with marshalling markup.
Expand All @@ -188,6 +204,8 @@ def make_query(*args, **kwargs):
qlist = complex_marshal(list(d.items()))
for i in range(len(qlist)):
k, m, v = qlist[i]
if isinstance(v, unicode):
v = v.encode(_default_encoding())
qlist[i] = '%s%s=%s' % (quote(k), m, quote(str(v)))

return '&'.join(qlist)
Expand Down Expand Up @@ -275,6 +293,9 @@ def complex_marshal(pairs):
def simple_marshal(v):
if isinstance(v, str):
return ''
if isinstance(v, unicode):
encoding = _default_encoding()
return ':%s:ustring' % (encoding,)
if isinstance(v, bool):
return ':boolean'
if isinstance(v, int):
Expand Down
41 changes: 35 additions & 6 deletions src/ZTUtils/tests/testZope.py
Expand Up @@ -5,39 +5,61 @@

from ZTUtils.Zope import (
complex_marshal,
simple_marshal,
make_hidden_input,
make_query,
)


class QueryTests(unittest.TestCase):


def testMarshalString(self):
self.assertEqual(simple_marshal('string'), '')

def testMarshalBool(self):
self.assertEqual(simple_marshal(True), ':boolean')

def testMarshalInt(self):
self.assertEqual(simple_marshal(42), ":int")

def testMarshalFloat(self):
self.assertEqual(simple_marshal(3.1415), ":float")

def testMarshalDate(self):
self.assertEqual(simple_marshal(DateTime()), ":date")

def testMarshalUnicode(self):
self.assertEqual(simple_marshal(u'unic\xF3de'), ":utf8:ustring")

def testMarshallLists(self):
'''Test marshalling lists'''
test_date = DateTime()
list_ = [1, test_date, 'str']
list_ = [1, test_date, 'str', u'unic\xF3de']
result = complex_marshal([('list', list_), ])
assert result == [('list', ':int:list', 1),
('list', ':date:list', test_date),
('list', ':list', 'str')]
('list', ':list', 'str'),
('list', ':utf8:ustring:list', u'unic\xF3de')]

def testMarshallRecords(self):
'''Test marshalling records'''
test_date = DateTime()
record = {'arg1': 1, 'arg2': test_date, 'arg3': 'str'}
record = {'arg1': 1, 'arg2': test_date, 'arg3': 'str', 'arg4': u'unic\xF3de'}
result = complex_marshal([('record', record), ])
assert result == [('record.arg1', ':int:record', 1),
('record.arg2', ':date:record', test_date),
('record.arg3', ':record', 'str')]
('record.arg3', ':record', 'str'),
('record.arg4', ':utf8:ustring:record', u'unic\xF3de' )]

def testMarshallListsInRecords(self):
'''Test marshalling lists inside of records'''
test_date = DateTime()
record = {'arg1': [1, test_date, 'str'], 'arg2': 1}
record = {'arg1': [1, test_date, 'str', u'unic\xF3de'], 'arg2': 1}
result = complex_marshal([('record', record), ])
assert result == [('record.arg1', ':int:list:record', 1),
('record.arg1', ':date:list:record', test_date),
('record.arg1', ':list:record', 'str'),
('record.arg1', ':utf8:ustring:list:record', u'unic\xF3de'),
('record.arg2', ':int:record', 1)]

def testMakeComplexQuery(self):
Expand All @@ -56,6 +78,13 @@ def testMakeComplexQuery(self):
'record.arg1:int:list:record=1&record.arg1:date:list:record=%s&'
'record.arg1:list:record=str&record.arg2:int:record=1' % (
quote_date, quote_date, quote_date))

def testMakeQueryUnicode(self):
''' Test makequery against Github issue 15
https://github.com/zopefoundation/Zope/issues/15
'''
query = make_query(search_text=u'unic\xF3de')
self.assertEqual('search_text:utf8:ustring=unic%C3%B3de', query)

def testMakeHiddenInput(self):
tag = make_hidden_input(foo='bar')
Expand Down

0 comments on commit 17b01b7

Please sign in to comment.