[Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - HTTPRequest.py:1.1.2.10 HTTPResponse.py:1.1.2.7
Shane Hathaway
shane@digicool.com
Wed, 21 Nov 2001 19:23:10 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP
In directory cvs.zope.org:/tmp/cvs-serv31156/Publisher/HTTP
Modified Files:
Tag: Zope-3x-branch
HTTPRequest.py HTTPResponse.py
Log Message:
- Created new HTTP server based on Medusa and ZServer.
- Made some corresponding changes to Zope.Publication.
- Got minitest working again.
=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.9 => 1.1.2.10 ===
self.environ=environ
get_env=environ.get
- other=self.other={'RESPONSE': response}
+ other = self.other
self.form={}
################################################################
=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.6 => 1.1.2.7 ===
The Response type encapsulates all possible responses to HTTP
requests. Responses are normally created by the object publisher.
- A published object may recieve the response abject as an argument
+ A published object may recieve the response object as an argument
named 'RESPONSE'. A published object may also create it's own
response object. Normally, published objects use response objects
to:
@@ -111,24 +111,27 @@
passed into the object must be used.
"""
- accumulated_headers = ''
- body = ''
+ accumulated_headers = None
base = None
realm = 'Zope'
_error_format = 'text/html'
payload = None
+ _wrote_headers = 0
+ _streaming = 0
- def __init__(self, payload, outstream, body='', headers=None,
- status=None, cookies=None):
+
+ def __init__(self, payload, outstream, header_output=None):
self.payload = payload
self._orig_payload = payload
- BaseResponse.__init__(self, outstream, body, headers, status, cookies)
+ self.header_output = header_output
+ BaseResponse.__init__(self, outstream)
def retry(self):
"""
Returns a response object to be used in a retry attempt
"""
- return self.__class__(self._orig_payload, self.outstream)
+ return self.__class__(self._orig_payload, self.outstream,
+ self.header_output)
def setStatus(self, status, reason=None):
'''
@@ -182,8 +185,10 @@
'''
Sets a new HTTP return header with the given value, while retaining
any previously set headers with the same name.'''
- self.accumulated_headers=(
- "%s%s: %s\n" % (self.accumulated_headers, name, value))
+ accum = self.accumulated_headers
+ if not accum:
+ self.accumulated_headers = accum = []
+ accum.append('%s: %s' % (name, value))
def setBody(self, body):
return self.payload.setBody(self, body)
@@ -262,7 +267,7 @@
headers=self.headers
if headers.has_key(name):
h=self.header[name]
- h="%s%s\n\t%s" % (h,delimiter,value)
+ h="%s%s\r\n\t%s" % (h,delimiter,value)
else: h=value
self.setHeader(name,h)
@@ -277,7 +282,6 @@
"""
self.payload.handleException(self, exc_info)
- _wrote=None
def _cookie_list(self):
cookie_list=[]
@@ -302,27 +306,21 @@
return cookie_list
- def __str__(self):
+
+ def getStatusAndHeaders(self):
"""
- Outputs the headers of the response.
+ Returns a tuple of the status and a mapping of correctly-cased
+ header names to values.
"""
- if self._wrote: return '' # Streaming output was used.
+ res = {}
+ headers = self.headers
- headers=self.headers
- body=self.body
-
- if (not headers.has_key('content-length') and
- not headers.has_key('transfer-encoding')):
+ if (not self._streaming and not headers.has_key('content-length')
+ and not headers.has_key('transfer-encoding')):
self.updateContentLength()
- headersl=[]
- append=headersl.append
+ res["X-Powered-By"] = "Zope (www.zope.org), Python (www.python.org)"
- # status header must come first.
- append("Status: %s" % headers.get('status', '200 OK'))
- append("X-Powered-By: Zope (www.zope.org), Python (www.python.org)")
- if headers.has_key('status'):
- del headers['status']
for key, val in headers.items():
if key.lower() == key:
# only change non-literal header names
@@ -333,13 +331,59 @@
key="%s-%s%s" % (key[:l],key[l+1:l+2].upper(),key[l+2:])
start=l+1
l=key.find('-',start)
- append("%s: %s" % (key, val))
- if self.cookies:
- headersl=headersl+self._cookie_list()
- headersl[len(headersl):]=[self.accumulated_headers, body]
- return '\n'.join(headersl)
+ res[key] = val
- def write(self,data):
+ if res.has_key('Status'):
+ status = res['Status']
+ del res['Status']
+ else:
+ if not self._streaming and not self.body:
+ status = '204 No Content'
+ else:
+ status = '200 OK'
+
+ return status, res
+
+
+ def getHeaderText(self, status, m):
+ lst = ['Status: %s' % status]
+ lst.extend(map(lambda x: '%s: %s' % x, m.items()))
+ lst.extend(self._cookie_list())
+ accum = self.accumulated_headers
+ if accum:
+ lst.extend(accum)
+ return ('%s\r\n\r\n' % '\r\n'.join(lst))
+
+
+ def outputHeaders(self):
+ status, m = self.getStatusAndHeaders()
+ header_output = self.header_output
+ if header_output is not None:
+ # Use the IHeaderOutput interface.
+ header_output.setResponseStatus(status)
+ header_output.setResponseHeaders(m)
+ cookies = self._cookie_list()
+ if cookies:
+ header_output.appendResponseHeaders(cookies)
+ accum = self.accumulated_headers
+ if accum:
+ header_output.appendResponseHeaders(accum)
+ else:
+ # Write directly to outstream.
+ s = self.getHeaderText(status, m)
+ self.outstream.write(s)
+
+
+ def __str__(self):
+ """
+ Debugging output. Does not include headers added for connection
+ control.
+ """
+ status, m = self.getStatusAndHeaders()
+ return self.getHeaderText(status, m) + self.body
+
+
+ def write(self, data):
"""
Return data as a stream
@@ -354,11 +398,19 @@
after beginning stream-oriented output.
"""
- if not self._wrote:
- self.outputBody()
- self._wrote=1
- self.outstream.flush()
-
+ if streaming:
+ self._streaming = 1
+ self.output(data)
+
+ def output(self, data):
+ if not self._wrote_headers:
+ self.outputHeaders()
+ self._wrote_headers = 1
self.outstream.write(data)
+ def outputBody(self):
+ """
+ Outputs the response body.
+ """
+ self.output(self.body)