[Zope-Checkins] SVN: Zope/branches/tseaver-fix_wsgi/src/ZPublisher/ More PEP8; coverage for retry, status, cookie, header, and base APIs.
Tres Seaver
tseaver at palladion.com
Mon Dec 21 16:35:21 EST 2009
Log message for revision 106837:
More PEP8; coverage for retry, status, cookie, header, and base APIs.
Changed:
U Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py
U Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py
-=-
Modified: Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py
===================================================================
--- Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py 2009-12-21 20:56:35 UTC (rev 106836)
+++ Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py 2009-12-21 21:35:21 UTC (rev 106837)
@@ -200,20 +200,6 @@
# think that that's all that is ever passed.
return self.__class__(stdout=self.stdout, stderr=self.stderr)
- _shutdown_flag = None
- def _requestShutdown(self, exitCode=0):
- """ Request that the server shut down with exitCode after fulfilling
- the current request.
- """
- import ZServer
- ZServer.exit_code = exitCode
- self._shutdown_flag = 1
-
- def _shutdownRequested(self):
- """ Returns true if this request requested a server shutdown.
- """
- return self._shutdown_flag is not None
-
def setStatus(self, status, reason=None, lock=None):
""" Set the HTTP status code of the response
@@ -252,42 +238,184 @@
if lock:
self._locked_status = 1
+ def setCookie(self, name, value, **kw):
+ """ Set an HTTP cookie.
+
+ The response will include an HTTP header that sets a cookie on
+ cookie-enabled browsers with a key "name" and value
+ "value".
+
+ This value overwrites any previously set value for the
+ cookie in the Response object.
+ """
+ name = str(name)
+ value = str(value)
+
+ cookies = self.cookies
+ if cookies.has_key(name):
+ cookie = cookies[name]
+ else:
+ cookie = cookies[name] = {}
+ for k, v in kw.items():
+ cookie[k] = v
+ cookie['value'] = value
+
+ def appendCookie(self, name, value):
+ """ Set an HTTP cookie.
+
+ Returns an HTTP header that sets a cookie on cookie-enabled
+ browsers with a key "name" and value "value". If a value for the
+ cookie has previously been set in the response object, the new
+ value is appended to the old one separated by a colon.
+ """
+ name = str(name)
+ value = str(value)
+
+ cookies = self.cookies
+ if cookies.has_key(name):
+ cookie = cookies[name]
+ else:
+ cookie = cookies[name] = {}
+ if cookie.has_key('value'):
+ cookie['value'] = '%s:%s' % (cookie['value'], value)
+ else:
+ cookie['value'] = value
+
+ def expireCookie(self, name, **kw):
+ """ Clear an HTTP cookie.
+
+ The response will include an HTTP header that will remove the cookie
+ corresponding to "name" on the client, if one exists. This is
+ accomplished by sending a new cookie with an expiration date
+ that has already passed. Note that some clients require a path
+ to be specified - this path must exactly match the path given
+ when creating the cookie. The path can be specified as a keyword
+ argument.
+ """
+ name = str(name)
+
+ d = kw.copy()
+ if 'value' in d:
+ d.pop('value')
+ d['max_age'] = 0
+ d['expires'] = 'Wed, 31-Dec-97 23:59:59 GMT'
+
+ self.setCookie(name, value='deleted', **d)
+
+ def getHeader(self, name, literal=0):
+ """ Get a previously set header value.
+
+ Return the value associated with a HTTP return header, or
+ None if no such header has been set in the response
+ yet.
+
+ If the 'literal' flag is true, preserve the case of the header name;
+ otherwise lower-case the header name before looking up the value.
+ """
+ key = literal and name or name.lower()
+ return self.headers.get(key, None)
+
def setHeader(self, name, value, literal=0, scrubbed=False):
- '''\
- Sets an HTTP return header "name" with value "value", clearing
- the previous value set for the header, if one exists. If the
- literal flag is true, the case of the header name is preserved,
- otherwise the header name will be lowercased.'''
+ """ Set an HTTP return header on the response.
+
+ Replay any existing value set for the header.
+
+ If the 'literal' flag is true, preserve the case of the header name;
+ otherwise the header name will be lowercased.
+
+ 'scrubbed' is for internal use, to indicate that another API has
+ already removed any CRLF from the name and value.
+ """
if not scrubbed:
name, value = _scrubHeader(name, value)
key = name.lower()
- if key == 'set-cookie':
+ # The following is crazy, given that we have APIs for cookies.
+ # Special behavior will go away in Zope 2.13
+ if key == 'set-cookie':
self.accumulated_headers.append((name, value))
else:
name = literal and name or key
self.headers[name] = value
- def getHeader(self, name, literal=0):
- '''\
- Get a header value
+ def appendHeader(self, name, value, delimiter=","):
+ """ Append a value to an HTTP return header.
- Returns the value associated with a HTTP return header, or
- "None" if no such header has been set in the response
- yet. If the literal flag is true, the case of the header name is
- preserved, otherwise the header name will be lowercased.'''
- key = name.lower()
- name = literal and name or key
- return self.headers.get(name, None)
+ Set an HTTP return header "name" with value "value",
+ appending it following a comma if there was a previous value
+ set for the header.
+ 'name' is always lowercased before use.
+ """
+ name, value = _scrubHeader(name, value)
+ name = name.lower()
+
+ headers = self.headers
+ if headers.has_key(name):
+ h = headers[name]
+ h = "%s%s\r\n\t%s" % (h, delimiter, value)
+ else:
+ h = value
+ self.setHeader(name,h, scrubbed=True)
+
def addHeader(self, name, value):
- '''\
- Set a new HTTP return header with the given value, while retaining
- any previously set headers with the same name.'''
+ """ Set a new HTTP return header with the given value,
+
+ Retain any previously set headers with the same name.
+
+ Note that this API appneds to the 'accumulated_headers' attribute;
+ it does not update the 'headers' mapping.
+ """
name, value = _scrubHeader(name, value)
self.accumulated_headers.append((name, value))
__setitem__ = setHeader
+ def setBase(self, base):
+ """Set the base URL for the returned document.
+
+ If base is None, set to the empty string.
+
+ If base is not None, ensure that it has a trailing slach.
+ """
+ if base is None:
+ base = ''
+ elif not base.endswith('/'):
+ base = base + '/'
+
+ self.base = str(base)
+
+ def insertBase(self,
+ base_re_search=re.compile('(<base.*?>)',re.I).search
+ ):
+
+ # Only insert a base tag if content appears to be html.
+ content_type = self.headers.get('content-type', '').split(';')[0]
+ if content_type and (content_type != 'text/html'):
+ return
+
+ if self.base:
+ body = self.body
+ if body:
+ match = start_of_header_search(body)
+ if match is not None:
+ index = match.start(0) + len(match.group(0))
+ ibase = base_re_search(body)
+ if ibase is None:
+ self.body = ('%s\n<base href="%s" />\n%s' %
+ (body[:index], escape(self.base, 1),
+ body[index:]))
+ self.setHeader('content-length', len(self.body))
+
+ def isHTML(self, s):
+ s = s.lstrip()
+ # Note that the string can be big, so s.lower().startswith() is more
+ # expensive than s[:n].lower().
+ if (s[:6].lower() == '<html>' or s[:14].lower() == '<!doctype html'):
+ return 1
+ if s.find('</') > 0:
+ return 1
+ return 0
+
def setBody(self, body, title='', is_error=0,
bogus_str_search=re.compile(" [a-fA-F0-9]+>$").search,
latin1_alias_match=re.compile(
@@ -460,6 +588,23 @@
return self.use_HTTP_content_compression
+ # The following two methods are part of a private protocol with the
+ # publisher for handling fatal import errors and TTW shutdown requests.
+ _shutdown_flag = None
+ def _requestShutdown(self, exitCode=0):
+ """ Request that the server shut down with exitCode after fulfilling
+ the current request.
+ """
+ import ZServer
+ ZServer.exit_code = exitCode
+ self._shutdown_flag = 1
+
+ def _shutdownRequested(self):
+ """ Returns true if this request requested a server shutdown.
+ """
+ return self._shutdown_flag is not None
+
+
def _encode_unicode(self,body,
charset_re=re.compile(r'(?:application|text)/[-+0-9a-z]+\s*;\s*' +
r'charset=([-_0-9a-z]+' +
@@ -496,127 +641,6 @@
body = fix_xml_preamble(body, default_encoding)
return body
- def setBase(self, base):
- """Set the base URL for the returned document.
-
- If base is None, or the document already has a base, do nothing.
- """
- if base is None:
- base = ''
- elif not base.endswith('/'):
- base = base + '/'
- self.base = str(base)
-
- def insertBase(self,
- base_re_search=re.compile('(<base.*?>)',re.I).search
- ):
-
- # Only insert a base tag if content appears to be html.
- content_type = self.headers.get('content-type', '').split(';')[0]
- if content_type and (content_type != 'text/html'):
- return
-
- if self.base:
- body = self.body
- if body:
- match = start_of_header_search(body)
- if match is not None:
- index = match.start(0) + len(match.group(0))
- ibase = base_re_search(body)
- if ibase is None:
- self.body = ('%s\n<base href="%s" />\n%s' %
- (body[:index], escape(self.base, 1),
- body[index:]))
- self.setHeader('content-length', len(self.body))
-
- def appendCookie(self, name, value):
- '''\
- Returns an HTTP header that sets a cookie on cookie-enabled
- browsers with a key "name" and value "value". If a value for the
- cookie has previously been set in the response object, the new
- value is appended to the old one separated by a colon. '''
-
- name = str(name)
- value = str(value)
-
- cookies = self.cookies
- if cookies.has_key(name):
- cookie = cookies[name]
- else:
- cookie = cookies[name] = {}
- if cookie.has_key('value'):
- cookie['value'] = '%s:%s' % (cookie['value'], value)
- else:
- cookie['value'] = value
-
- def expireCookie(self, name, **kw):
- '''\
- Cause an HTTP cookie to be removed from the browser
-
- The response will include an HTTP header that will remove the cookie
- corresponding to "name" on the client, if one exists. This is
- accomplished by sending a new cookie with an expiration date
- that has already passed. Note that some clients require a path
- to be specified - this path must exactly match the path given
- when creating the cookie. The path can be specified as a keyword
- argument.
- '''
- name = str(name)
-
- d = kw.copy()
- d['max_age'] = 0
- d['expires'] = 'Wed, 31-Dec-97 23:59:59 GMT'
- apply(HTTPResponse.setCookie, (self, name, 'deleted'), d)
-
- def setCookie(self,name,value,**kw):
- '''\
- Set an HTTP cookie on the browser
-
- The response will include an HTTP header that sets a cookie on
- cookie-enabled browsers with a key "name" and value
- "value". This overwrites any previously set value for the
- cookie in the Response object.
- '''
- name = str(name)
- value = str(value)
-
- cookies = self.cookies
- if cookies.has_key(name):
- cookie = cookies[name]
- else:
- cookie = cookies[name] = {}
- for k, v in kw.items():
- cookie[k] = v
- cookie['value'] = value
-
- def appendHeader(self, name, value, delimiter=","):
- '''\
- Append a value to a header.
-
- Sets an HTTP return header "name" with value "value",
- appending it following a comma if there was a previous value
- set for the header. '''
- name, value = _scrubHeader(name, value)
- name = name.lower()
-
- headers = self.headers
- if headers.has_key(name):
- h = headers[name]
- h = "%s%s\r\n\t%s" % (h,delimiter,value)
- else:
- h = value
- self.setHeader(name,h, scrubbed=True)
-
- def isHTML(self, s):
- s = s.lstrip()
- # Note that the string can be big, so s.lower().startswith() is more
- # expensive than s[:n].lower().
- if (s[:6].lower() == '<html>' or s[:14].lower() == '<!doctype html'):
- return 1
- if s.find('</') > 0:
- return 1
- return 0
-
# deprecated
def quoteHTML(self, text):
return escape(text, 1)
Modified: Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py
===================================================================
--- Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py 2009-12-21 20:56:35 UTC (rev 106836)
+++ Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py 2009-12-21 21:35:21 UTC (rev 106837)
@@ -58,14 +58,6 @@
self.assertEqual(response.headers,
{'status': '401 Unauthorized'}) # XXX WTF?
- def test_retry(self):
- STDOUT, STDERR = object(), object()
- response = self._makeOne(stdout=STDOUT, stderr=STDERR)
- cloned = response.retry()
- self.failUnless(isinstance(cloned, self._getTargetClass()))
- self.failUnless(cloned.stdout is STDOUT)
- self.failUnless(cloned.stderr is STDERR)
-
def test_ctor_charset_no_content_type_header(self):
response = self._makeOne(body='foo')
self.assertEqual(response.headers.get('content-type'),
@@ -122,49 +114,86 @@
'text/xml; charset=iso-8859-15'})
self.assertEqual(response.body, xml)
+ def test_retry(self):
+ STDOUT, STDERR = object(), object()
+ response = self._makeOne(stdout=STDOUT, stderr=STDERR)
+ cloned = response.retry()
+ self.failUnless(isinstance(cloned, self._getTargetClass()))
+ self.failUnless(cloned.stdout is STDOUT)
+ self.failUnless(cloned.stderr is STDERR)
+
+ def test_setStatus_code(self):
+ response = self._makeOne()
+ response.setStatus(400)
+ self.assertEqual(response.status, 400)
+ self.assertEqual(response.errmsg, 'Bad Request')
+
+ def test_setStatus_errmsg(self):
+ response = self._makeOne()
+ response.setStatus('Bad Request')
+ self.assertEqual(response.status, 400)
+ self.assertEqual(response.errmsg, 'Bad Request')
+
def test_setStatus_BadRequest(self):
from zExceptions import BadRequest
response = self._makeOne()
response.setStatus(BadRequest)
self.assertEqual(response.status, 400)
+ self.assertEqual(response.errmsg, 'Bad Request')
- def test_setStatus_Unauthorized(self):
+ def test_setStatus_Unauthorized_exception(self):
from zExceptions import Unauthorized
response = self._makeOne()
response.setStatus(Unauthorized)
self.assertEqual(response.status, 401)
+ self.assertEqual(response.errmsg, 'Unauthorized')
- def test_setStatus_Forbidden(self):
+ def test_setStatus_Forbidden_exception(self):
from zExceptions import Forbidden
response = self._makeOne()
response.setStatus(Forbidden)
self.assertEqual(response.status, 403)
+ self.assertEqual(response.errmsg, 'Forbidden')
- def test_setStatus_NotFound(self):
+ def test_setStatus_NotFound_exception(self):
from zExceptions import NotFound
response = self._makeOne()
response.setStatus(NotFound)
self.assertEqual(response.status, 404)
+ self.assertEqual(response.errmsg, 'Not Found')
- def test_setStatus_ResourceLockedError(self):
+ def test_setStatus_ResourceLockedError_exception(self):
response = self._makeOne()
from webdav.Lockable import ResourceLockedError
response.setStatus(ResourceLockedError)
self.assertEqual(response.status, 423)
+ self.assertEqual(response.errmsg, 'Locked')
- def test_setStatus_InternalError(self):
+ def test_setStatus_InternalError_exception(self):
from zExceptions import InternalError
response = self._makeOne()
response.setStatus(InternalError)
self.assertEqual(response.status, 500)
+ self.assertEqual(response.errmsg, 'Internal Server Error')
- def test_setCookie_no_attrs(self):
+ def test_setCookie_no_existing(self):
response = self._makeOne()
response.setCookie('foo', 'bar')
cookie = response.cookies.get('foo', None)
self.assertEqual(len(cookie), 1)
self.assertEqual(cookie.get('value'), 'bar')
+ def test_setCookie_w_existing(self):
+ response = self._makeOne()
+ response.setCookie('foo', 'bar')
+ response.setCookie('foo', 'baz')
+ cookie = response.cookies.get('foo', None)
+ self.assertEqual(len(cookie), 1)
+ self.assertEqual(cookie.get('value'), 'baz')
+
+ def test_setCookie_no_attrs(self):
+ response = self._makeOne()
+ response.setCookie('foo', 'bar')
cookies = response._cookie_list()
self.assertEqual(len(cookies), 1)
self.assertEqual(cookies[0], 'Set-Cookie: foo="bar"')
@@ -268,6 +297,22 @@
self.assertEqual(len(cookie_list), 1)
self.assertEqual(cookie_list[0], 'Set-Cookie: foo="bar"')
+ def test_appendCookie_w_existing(self):
+ response = self._makeOne()
+ response.setCookie('foo', 'bar', path='/')
+ response.appendCookie('foo', 'baz')
+ cookie = response.cookies.get('foo', None)
+ self.failUnless(cookie)
+ self.assertEqual(cookie.get('value'), 'bar:baz')
+ self.assertEqual(cookie.get('path'), '/')
+
+ def test_appendCookie_no_existing(self):
+ response = self._makeOne()
+ response.appendCookie('foo', 'baz')
+ cookie = response.cookies.get('foo', None)
+ self.failUnless(cookie)
+ self.assertEqual(cookie.get('value'), 'baz')
+
def test_expireCookie(self):
response = self._makeOne()
response.expireCookie('foo', path='/')
@@ -289,24 +334,22 @@
self.assertEqual(cookie.get('max_age'), 0)
self.assertEqual(cookie.get('path'), '/')
- def test_appendCookie(self):
+ def test_getHeader_nonesuch(self):
response = self._makeOne()
- response.setCookie('foo', 'bar', path='/')
- response.appendCookie('foo', 'baz')
- cookie = response.cookies.get('foo', None)
- self.failUnless(cookie)
- self.assertEqual(cookie.get('value'), 'bar:baz')
- self.assertEqual(cookie.get('path'), '/')
+ self.assertEqual(response.getHeader('nonesuch'), None)
- def test_appendHeader(self):
- response = self._makeOne()
- response.setHeader('foo', 'bar')
- response.appendHeader('foo', 'foo')
- self.assertEqual(response.headers.get('foo'), 'bar,\r\n\tfoo')
- response.setHeader('xxx', 'bar')
- response.appendHeader('XXX', 'foo')
- self.assertEqual(response.headers.get('xxx'), 'bar,\r\n\tfoo')
+ def test_getHeader_existing(self):
+ response = self._makeOne(headers={'foo': 'bar'})
+ self.assertEqual(response.getHeader('foo'), 'bar')
+ def test_getHeader_existing_not_literal(self):
+ response = self._makeOne(headers={'foo': 'bar'})
+ self.assertEqual(response.getHeader('Foo'), 'bar')
+
+ def test_getHeader_existing_w_literal(self):
+ response = self._makeOne(headers={'Foo': 'Bar'})
+ self.assertEqual(response.getHeader('Foo', literal=True), 'Bar')
+
def test_setHeader(self):
response = self._makeOne()
response.setHeader('foo', 'bar')
@@ -324,22 +367,6 @@
self.assertEqual(response.getHeader('SPAM', literal=True), 'eggs')
self.assertEqual(response.getHeader('spam'), None)
- def test_addHeader_drops_CRLF(self):
- # RFC2616 disallows CRLF in a header value.
- response = self._makeOne()
- response.addHeader('Location',
- 'http://www.ietf.org/rfc/\r\nrfc2616.txt')
- self.assertEqual(response.accumulated_headers,
- [('Location', 'http://www.ietf.org/rfc/rfc2616.txt')])
-
- def test_appendHeader_drops_CRLF(self):
- # RFC2616 disallows CRLF in a header value.
- response = self._makeOne()
- response.appendHeader('Location',
- 'http://www.ietf.org/rfc/\r\nrfc2616.txt')
- self.assertEqual(response.headers['location'],
- 'http://www.ietf.org/rfc/rfc2616.txt')
-
def test_setHeader_drops_CRLF(self):
# RFC2616 disallows CRLF in a header value.
response = self._makeOne()
@@ -348,8 +375,19 @@
self.assertEqual(response.headers['location'],
'http://www.ietf.org/rfc/rfc2616.txt')
+ def test_setHeader_Set_Cookie_special_case(self):
+ # This is crazy, given that we have APIs for cookies. Special
+ # behavior will go away in Zope 2.13
+ response = self._makeOne()
+ response.setHeader('Set-Cookie', 'foo="bar"')
+ self.assertEqual(response.getHeader('Set-Cookie'), None)
+ self.assertEqual(response.accumulated_headers,
+ [('Set-Cookie', 'foo="bar"')])
+
def test_setHeader_drops_CRLF_when_accumulating(self):
# RFC2616 disallows CRLF in a header value.
+ # This is crazy, given that we have APIs for cookies. Special
+ # behavior will go away in Zope 2.13
response = self._makeOne()
response.setHeader('Set-Cookie', 'allowed="OK"')
response.setHeader('Set-Cookie',
@@ -359,6 +397,110 @@
('Set-Cookie',
'violation="http://www.ietf.org/rfc/rfc2616.txt"')])
+ def test_appendHeader_no_existing(self):
+ response = self._makeOne()
+ response.appendHeader('foo', 'foo')
+ self.assertEqual(response.headers.get('foo'), 'foo')
+
+ def test_appendHeader_no_existing_case_insensative(self):
+ response = self._makeOne()
+ response.appendHeader('Foo', 'foo')
+ self.assertEqual(response.headers.get('foo'), 'foo')
+
+ def test_appendHeader_w_existing(self):
+ response = self._makeOne()
+ response.setHeader('foo', 'bar')
+ response.appendHeader('foo', 'foo')
+ self.assertEqual(response.headers.get('foo'), 'bar,\r\n\tfoo')
+
+ def test_appendHeader_w_existing_case_insenstative(self):
+ response = self._makeOne()
+ response.setHeader('xxx', 'bar')
+ response.appendHeader('XXX', 'foo')
+ self.assertEqual(response.headers.get('xxx'), 'bar,\r\n\tfoo')
+
+ def test_appendHeader_drops_CRLF(self):
+ # RFC2616 disallows CRLF in a header value.
+ response = self._makeOne()
+ response.appendHeader('Location',
+ 'http://www.ietf.org/rfc/\r\nrfc2616.txt')
+ self.assertEqual(response.headers['location'],
+ 'http://www.ietf.org/rfc/rfc2616.txt')
+
+ def test_addHeader_is_case_sensitive(self):
+ response = self._makeOne()
+ response.addHeader('Location', 'http://www.ietf.org/rfc/rfc2616.txt')
+ self.assertEqual(response.accumulated_headers,
+ [('Location', 'http://www.ietf.org/rfc/rfc2616.txt')])
+
+ def test_addHeader_drops_CRLF(self):
+ # RFC2616 disallows CRLF in a header value.
+ response = self._makeOne()
+ response.addHeader('Location',
+ 'http://www.ietf.org/rfc/\r\nrfc2616.txt')
+ self.assertEqual(response.accumulated_headers,
+ [('Location', 'http://www.ietf.org/rfc/rfc2616.txt')])
+
+ def test_setBase_None(self):
+ response = self._makeOne()
+ response.base = 'BEFORE'
+ response.setBase(None)
+ self.assertEqual(response.base, '')
+
+ def test_setBase_no_trailing_path(self):
+ response = self._makeOne()
+ response.setBase('foo')
+ self.assertEqual(response.base, 'foo/')
+
+ def test_setBase_w_trailing_path(self):
+ response = self._makeOne()
+ response.setBase('foo/')
+ self.assertEqual(response.base, 'foo/')
+
+ def test_insertBase_not_HTML_no_change(self):
+ response = self._makeOne()
+ response.setHeader('Content-Type', 'application/pdf')
+ response.setHeader('Content-Length', 8)
+ response.body = 'BLAHBLAH'
+ response.insertBase()
+ self.assertEqual(response.body, 'BLAHBLAH')
+ self.assertEqual(response.getHeader('Content-Length'), '8')
+
+ def test_insertBase_HTML_no_base_w_head_not_munged(self):
+ HTML = '<html><head></head><body></body></html>'
+ response = self._makeOne()
+ response.setHeader('Content-Type', 'text/html')
+ response.setHeader('Content-Length', len(HTML))
+ response.body = HTML
+ response.insertBase()
+ self.assertEqual(response.body, HTML)
+ self.assertEqual(response.getHeader('Content-Length'), str(len(HTML)))
+
+ def test_insertBase_HTML_w_base_no_head_not_munged(self):
+ HTML = '<html><body></body></html>'
+ response = self._makeOne()
+ response.setHeader('Content-Type', 'text/html')
+ response.setHeader('Content-Length', len(HTML))
+ response.body = HTML
+ response.insertBase()
+ self.assertEqual(response.body, HTML)
+ self.assertEqual(response.getHeader('Content-Length'), str(len(HTML)))
+
+ def test_insertBase_HTML_w_base_w_head_munged(self):
+ HTML = '<html><head></head><body></body></html>'
+ MUNGED = ('<html><head>\n'
+ '<base href="http://example.com/base/" />\n'
+ '</head><body></body></html>')
+ response = self._makeOne()
+ response.setHeader('Content-Type', 'text/html')
+ response.setHeader('Content-Length', 8)
+ response.body = HTML
+ response.setBase('http://example.com/base/')
+ response.insertBase()
+ self.assertEqual(response.body, MUNGED)
+ self.assertEqual(response.getHeader('Content-Length'),
+ str(len(MUNGED)))
+
def test_setBody_compression_vary(self):
# Vary header should be added here
response = self._makeOne()
More information about the Zope-Checkins
mailing list