Commit c85b579a authored by Hanno Schlichting's avatar Hanno Schlichting

Move WSGI request/response classes into http request/response modules.

parent d5d72e9a
......@@ -62,11 +62,9 @@ class Functional(sandbox.Sandboxed):
'''Publishes the object at 'path' returning a response object.'''
from StringIO import StringIO
from ZPublisher.HTTPRequest import HTTPRequest as Request
from ZPublisher.WSGIPublisher import (
publish_module,
WSGIResponse,
)
from ZPublisher.HTTPRequest import WSGIRequest as Request
from ZPublisher.HTTPResponse import WSGIResponse
from ZPublisher.WSGIPublisher import publish_module
# Commit the sandbox for good measure
transaction.commit()
......
......@@ -129,11 +129,9 @@ def http(request_string, handle_errors=True):
import urllib
import rfc822
from cStringIO import StringIO
from ZPublisher.HTTPRequest import HTTPRequest as Request
from ZPublisher.WSGIPublisher import (
publish_module,
WSGIResponse,
)
from ZPublisher.HTTPRequest import WSGIRequest as Request
from ZPublisher.HTTPResponse import WSGIResponse
from ZPublisher.WSGIPublisher import publish_module
# Commit work done by previous python code.
transaction.commit()
......
......@@ -1555,6 +1555,11 @@ class HTTPRequest(BaseRequest):
return self.URL
class WSGIRequest(HTTPRequest):
# A request object for WSGI, no docstring to avoid being publishable.
pass
class TaintRequestWrapper:
def __init__(self, req):
self._req = req
......
......@@ -19,6 +19,7 @@ from string import maketrans
from string import translate
import struct
import sys
import time
import types
from urllib import quote
import zlib
......@@ -35,10 +36,14 @@ from zExceptions import (
)
from zExceptions.ExceptionFormatter import format_exception
from ZPublisher.BaseResponse import BaseResponse
from ZPublisher.pubevents import PubBeforeStreaming
from ZPublisher.Iterators import IUnboundStreamIterator, IStreamIterator
from ZPublisher import pubevents
if sys.version_info >= (3, ):
from io import IOBase
unicode = str
else:
IOBase = file # NOQA
nl2sp = maketrans('\n', ' ')
......@@ -92,6 +97,24 @@ def _scrubHeader(name, value):
return ''.join(_CRLF.split(str(name))), ''.join(_CRLF.split(str(value)))
_NOW = None # overwrite for testing
MONTHNAME = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
WEEKDAYNAME = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
def _now():
if _NOW is not None:
return _NOW
return time.time()
def build_http_date(when):
year, month, day, hh, mm, ss, wd, y, z = time.gmtime(when)
return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss)
class HTTPResponse(BaseResponse):
""" An object representation of an HTTP response.
......@@ -908,10 +931,86 @@ class HTTPResponse(BaseResponse):
after beginning stream-oriented output.
"""
if not self._wrote:
notify(PubBeforeStreaming(self))
notify(pubevents.PubBeforeStreaming(self))
self.outputBody()
self._wrote = 1
self.stdout.flush()
self.stdout.write(data)
class WSGIResponse(HTTPResponse):
"""A response object for WSGI
"""
_streaming = 0
_http_version = None
_server_version = None
# Append any "cleanup" functions to this list.
after_list = ()
def finalize(self):
# Set 204 (no content) status if 200 and response is empty
# and not streaming.
if ('content-type' not in self.headers and
'content-length' not in self.headers and
not self._streaming and self.status == 200):
self.setStatus('nocontent')
# Add content length if not streaming.
content_length = self.headers.get('content-length')
if content_length is None and not self._streaming:
self.setHeader('content-length', len(self.body))
return ('%s %s' % (self.status, self.errmsg), self.listHeaders())
def listHeaders(self):
result = []
if self._server_version:
result.append(('Server', self._server_version))
result.append(('Date', build_http_date(_now())))
result.extend(HTTPResponse.listHeaders(self))
return result
def _unauthorized(self, exc=None):
status = exc.getStatus() if exc is not None else 401
self.setStatus(status)
if self.realm:
self.setHeader('WWW-Authenticate',
'basic realm="%s"' % self.realm, 1)
def write(self, data):
"""Add data to our output stream.
HTML data may be returned using a stream-oriented interface.
This allows the browser to display partial results while
computation of a response proceeds.
"""
if not self._streaming:
notify(pubevents.PubBeforeStreaming(self))
self._streaming = 1
self.stdout.flush()
self.stdout.write(data)
def setBody(self, body, title='', is_error=0):
if isinstance(body, IOBase):
body.seek(0, 2)
length = body.tell()
body.seek(0)
self.setHeader('Content-Length', '%d' % length)
self.body = body
elif IStreamIterator.providedBy(body):
self.body = body
HTTPResponse.setBody(self, '', title, is_error)
elif IUnboundStreamIterator.providedBy(body):
self.body = body
self._streaming = 1
HTTPResponse.setBody(self, '', title, is_error)
else:
HTTPResponse.setBody(self, body, title, is_error)
def __str__(self):
raise NotImplementedError
......@@ -16,7 +16,6 @@ from contextlib import contextmanager, closing
from cStringIO import StringIO
import sys
from thread import allocate_lock
import time
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager
......@@ -33,18 +32,13 @@ from zope.event import notify
from zope.security.management import newInteraction, endInteraction
from zope.publisher.skinnable import setDefaultSkin
from ZPublisher.HTTPRequest import HTTPRequest
from ZPublisher.HTTPResponse import HTTPResponse
from ZPublisher.Iterators import IUnboundStreamIterator, IStreamIterator
from ZPublisher.HTTPRequest import WSGIRequest
from ZPublisher.HTTPResponse import WSGIResponse
from ZPublisher.Iterators import IUnboundStreamIterator
from ZPublisher.mapply import mapply
from ZPublisher import pubevents
from ZPublisher.utils import recordMetaData
_NOW = None # overwrite for testing
MONTHNAME = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
WEEKDAYNAME = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
if sys.version_info >= (3, ):
from io import IOBase
else:
......@@ -56,18 +50,6 @@ _MODULE_LOCK = allocate_lock()
_MODULES = {}
def _now():
if _NOW is not None:
return _NOW
return time.time()
def build_http_date(when):
year, month, day, hh, mm, ss, wd, y, z = time.gmtime(when)
return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss)
def call_object(obj, args, request):
return obj(*args)
......@@ -110,88 +92,6 @@ def get_module_info(module_name='Zope2'):
return info
class WSGIRequest(HTTPRequest):
"""A request object for WSGI
"""
pass
class WSGIResponse(HTTPResponse):
"""A response object for WSGI
"""
_streaming = 0
_http_version = None
_server_version = None
# Append any "cleanup" functions to this list.
after_list = ()
def finalize(self):
# Set 204 (no content) status if 200 and response is empty
# and not streaming.
if ('content-type' not in self.headers and
'content-length' not in self.headers and
not self._streaming and self.status == 200):
self.setStatus('nocontent')
# Add content length if not streaming.
content_length = self.headers.get('content-length')
if content_length is None and not self._streaming:
self.setHeader('content-length', len(self.body))
return ('%s %s' % (self.status, self.errmsg), self.listHeaders())
def listHeaders(self):
result = []
if self._server_version:
result.append(('Server', self._server_version))
result.append(('Date', build_http_date(_now())))
result.extend(HTTPResponse.listHeaders(self))
return result
def _unauthorized(self, exc=None):
status = exc.getStatus() if exc is not None else 401
self.setStatus(status)
if self.realm:
self.setHeader('WWW-Authenticate',
'basic realm="%s"' % self.realm, 1)
def write(self, data):
"""Add data to our output stream.
HTML data may be returned using a stream-oriented interface.
This allows the browser to display partial results while
computation of a response proceeds.
"""
if not self._streaming:
notify(pubevents.PubBeforeStreaming(self))
self._streaming = 1
self.stdout.flush()
self.stdout.write(data)
def setBody(self, body, title='', is_error=0):
if isinstance(body, IOBase):
body.seek(0, 2)
length = body.tell()
body.seek(0)
self.setHeader('Content-Length', '%d' % length)
self.body = body
elif IStreamIterator.providedBy(body):
self.body = body
HTTPResponse.setBody(self, '', title, is_error)
elif IUnboundStreamIterator.providedBy(body):
self.body = body
self._streaming = 1
HTTPResponse.setBody(self, '', title, is_error)
else:
HTTPResponse.setBody(self, body, title, is_error)
def __str__(self):
raise NotImplementedError
@contextmanager
def transaction_pubevents(request, tm=transaction.manager):
ok_exception = None
......
......@@ -30,15 +30,15 @@ class WSGIResponseTests(unittest.TestCase):
self._setNOW(self._old_NOW)
def _getTargetClass(self):
from ZPublisher.WSGIPublisher import WSGIResponse
from ZPublisher.HTTPResponse import WSGIResponse
return WSGIResponse
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
def _setNOW(self, value):
from ZPublisher import WSGIPublisher
WSGIPublisher._NOW, self._old_NOW = value, WSGIPublisher._NOW
from ZPublisher import HTTPResponse
HTTPResponse._NOW, self._old_NOW = value, HTTPResponse._NOW
def test_finalize_sets_204_on_empty_not_streaming(self):
response = self._makeOne()
......
......@@ -7,18 +7,18 @@ from zope.interface.verify import verifyObject
from zope.event import subscribers
from ZPublisher.BaseRequest import BaseRequest
from ZPublisher.pubevents import (
PubStart, PubSuccess, PubFailure,
PubAfterTraversal, PubBeforeCommit, PubBeforeAbort,
PubBeforeStreaming,
)
from ZPublisher.HTTPResponse import WSGIResponse
from ZPublisher.interfaces import (
IPubStart, IPubEnd, IPubSuccess, IPubFailure,
IPubAfterTraversal, IPubBeforeCommit,
IPubBeforeStreaming,
)
from ZPublisher.pubevents import (
PubStart, PubSuccess, PubFailure,
PubAfterTraversal, PubBeforeCommit, PubBeforeAbort,
PubBeforeStreaming,
)
from ZPublisher.WSGIPublisher import publish_module
from ZPublisher.WSGIPublisher import WSGIResponse
PUBMODULE = 'TEST_testpubevents'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment