[Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - BrowserPayload.py:1.1.2.1 IPayload.py:1.1.2.1 cgi_names.py:1.1.2.1 HTTPRequest.py:1.1.2.4 HTTPResponse.py:1.1.2.3
Shane Hathaway
shane@digicool.com
Thu, 15 Nov 2001 18:10:02 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP
In directory cvs.zope.org:/tmp/cvs-serv16729/HTTP
Modified Files:
Tag: Zope-3x-branch
HTTPRequest.py HTTPResponse.py
Added Files:
Tag: Zope-3x-branch
BrowserPayload.py IPayload.py cgi_names.py
Log Message:
- Divided the HTTP protocol from its payload
- Expanded minitest
- Renamed some interface methods
=== Added File Zope3/lib/python/Zope/Publisher/HTTP/BrowserPayload.py === (516/616 lines abridged)
import re
from types import ClassType, ListType, StringType
from cgi import FieldStorage, escape
from cgi_names import isCGI_NAME
from IPayload import IRequestPayload, IResponsePayload
from Zope.Publisher.Converters import get_converter
from Zope.Publisher.Exceptions import Redirect
#from Zope.Publisher.Browser import IBrowserPublish
latin1_alias_match = re.compile(
r'text/html(\s*;\s*charset=((latin)|(latin[-_]?1)|'
r'(cp1252)|(cp819)|(csISOLatin1)|(IBM819)|(iso-ir-100)|'
r'(iso[-_]8859[-_]1(:1987)?)))?$',re.I).match
def is_text_html(content_type):
return (content_type == 'text/html' or
latin1_alias_match(content_type) is not None)
class BrowserRequestPayload:
"""
Works with the body of a browser request.
"""
__implements__ = IRequestPayload
def getPreferredPublishingType(self):
return IBrowserPublish
def processInputs(
self, request, fs=None,
# "static" variables that we want to be local for speed
SEQUENCE=1,
DEFAULT=2,
RECORD=4,
RECORDS=8,
REC=12, # RECORD|RECORDS
EMPTY=16,
CONVERTED=32,
hasattr=hasattr,
getattr=getattr,
setattr=setattr,
search_type=re.compile('(:[a-zA-Z][a-zA-Z0-9_]+|\\.[xy])$').search,
):
"""
[-=- -=- -=- 516 lines omitted -=- -=- -=-]
L1.sort()
return ", ".join(
map(lambda item: "%s: %s" % (item[0], repr(item[1])), L1))
# Flags
SEQUENCE=1
DEFAULT=2
RECORD=4
RECORDS=8
REC=RECORD|RECORDS
EMPTY=16
CONVERTED=32
def format_exception(etype,value,tb,limit=None):
import traceback
result=['Traceback (innermost last):']
if limit is None:
if hasattr(sys, 'tracebacklimit'):
limit = sys.tracebacklimit
n = 0
while tb is not None and (limit is None or n < limit):
f = tb.tb_frame
lineno = tb.tb_lineno
co = f.f_code
filename = co.co_filename
name = co.co_name
locals = f.f_locals
globals = f.f_globals
modname = globals.get('__name__', filename)
result.append(' Module %s, line %d, in %s'
% (modname,lineno,name))
try: result.append(' (Object: %s)' %
locals[co.co_varnames[0]].__name__)
except: pass
try: result.append(' (Info: %s)' %
str(locals['__traceback_info__']))
except: pass
tb = tb.tb_next
n = n+1
result.append(' '.join(traceback.format_exception_only(etype, value)))
return result
def traceback_string(t,v,tb):
tb=format_exception(t,v,tb,200)
return '\n'.join(tb)
=== Added File Zope3/lib/python/Zope/Publisher/HTTP/IPayload.py ===
from Interface import Interface
class IRequestPayload (Interface):
def processInputs(request):
"""
Processes request inputs.
"""
def getPreferredPublishingType():
"""
Returns an interface object.
"""
class IResponsePayload (Interface):
def setBody(response, body):
"""
Sets the body of the response.
"""
def handleException(response, exc_info):
"""
Calls setBody() with an error response.
"""
=== Added File Zope3/lib/python/Zope/Publisher/HTTP/cgi_names.py ===
#cgi hotfix:
import cgi
if not hasattr(cgi, 'valid_boundary'):
try: import cgi_hotfix
except ImportError: pass
isCGI_NAME = {
# These fields are placed in request.environ instead of request.form.
'SERVER_SOFTWARE' : 1,
'SERVER_NAME' : 1,
'GATEWAY_INTERFACE' : 1,
'SERVER_PROTOCOL' : 1,
'SERVER_PORT' : 1,
'REQUEST_METHOD' : 1,
'PATH_INFO' : 1,
'PATH_TRANSLATED' : 1,
'SCRIPT_NAME' : 1,
'QUERY_STRING' : 1,
'REMOTE_HOST' : 1,
'REMOTE_ADDR' : 1,
'AUTH_TYPE' : 1,
'REMOTE_USER' : 1,
'REMOTE_IDENT' : 1,
'CONTENT_TYPE' : 1,
'CONTENT_LENGTH' : 1,
'SERVER_URL': 1,
}.has_key
hide_key={
'HTTP_AUTHORIZATION':1,
'HTTP_CGI_AUTHORIZATION': 1,
}.has_key
=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.3 => 1.1.2.4 === (471/571 lines abridged)
import re, sys, os, string, time, whrandom, cgi
from Zope.Publisher.BaseRequest import BaseRequest
-from Zope.Publisher.Converters import get_converter
from HTTPResponse import HTTPResponse
-from cgi import FieldStorage, escape
+from BrowserPayload import BrowserRequestPayload
+from cgi_names import isCGI_NAME, hide_key
from urllib import quote, unquote, splittype, splitport
-#cgi hotfix:
-if not hasattr(cgi, 'valid_boundary'):
- try: import cgi_hotfix
- except ImportError: pass
-
-isCGI_NAME = {
- # These fields are placed in request.environ instead of request.form.
- 'SERVER_SOFTWARE' : 1,
- 'SERVER_NAME' : 1,
- 'GATEWAY_INTERFACE' : 1,
- 'SERVER_PROTOCOL' : 1,
- 'SERVER_PORT' : 1,
- 'REQUEST_METHOD' : 1,
- 'PATH_INFO' : 1,
- 'PATH_TRANSLATED' : 1,
- 'SCRIPT_NAME' : 1,
- 'QUERY_STRING' : 1,
- 'REMOTE_HOST' : 1,
- 'REMOTE_ADDR' : 1,
- 'AUTH_TYPE' : 1,
- 'REMOTE_USER' : 1,
- 'REMOTE_IDENT' : 1,
- 'CONTENT_TYPE' : 1,
- 'CONTENT_LENGTH' : 1,
- 'SERVER_URL': 1,
- }.has_key
-
-hide_key={
- 'HTTP_AUTHORIZATION':1,
- 'HTTP_CGI_AUTHORIZATION': 1,
- }.has_key
DEFAULT_PORTS = {'http': '80', 'https': '443'}
@@ -99,6 +68,8 @@
_auth = None # The value of the HTTP_AUTHORIZATION header.
_computed_urls = () # Names of computed URLx variables
_script = () # SERVER_URL + _script + quoted_steps == full URL
+ script = '' # script + quoted_steps = full URL
+ payload = BrowserRequestPayload()
[-=- -=- -=- 471 lines omitted -=- -=- -=-]
+def parse_cookie(
+ text,
+ result=None,
+ qparmre=re.compile(
+ '([\x00- ]*([^\x00- ;,="]+)="([^"]*)"([\x00- ]*[;,])?[\x00- ]*)'),
+ parmre=re.compile(
+ '([\x00- ]*([^\x00- ;,="]+)=([^\x00- ;,"]*)([\x00- ]*[;,])?[\x00- ]*)'),
+ acquire=parse_cookie_lock.acquire,
+ release=parse_cookie_lock.release,
+ ):
if result is None: result={}
already_have=result.has_key
@@ -973,36 +515,4 @@
return apply(parse_cookie,(text[l:],result))
-# add class
-class record:
-
- # TODO: declare public.
-
- def __getattr__(self, key, default=None):
- if key in ('get', 'keys', 'items', 'values', 'copy', 'has_key'):
- return getattr(self.__dict__, key)
- raise AttributeError, key
-
- def __getitem__(self, key):
- return self.__dict__[key]
-
- def __str__(self):
- L1 = self.__dict__.items()
- L1.sort()
- return ", ".join(map(lambda item: "%s: %s" % item, L1))
-
- def __repr__(self):
- L1 = self.__dict__.items()
- L1.sort()
- return ", ".join(
- map(lambda item: "%s: %s" % (item[0], repr(item[1])), L1))
-
-# Flags
-SEQUENCE=1
-DEFAULT=2
-RECORD=4
-RECORDS=8
-REC=RECORD|RECORDS
-EMPTY=16
-CONVERTED=32
=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.2 => 1.1.2.3 ===
from Zope.Publisher.BaseResponse import BaseResponse
from Zope.Publisher.Exceptions import Redirect
+from BrowserPayload import BrowserResponsePayload
nl2sp = string.maketrans('\n',' ')
@@ -78,20 +79,9 @@
status_codes['redirect']=300
-start_of_header_search=re.compile('(<head[^>]*>)', re.IGNORECASE).search
-
accumulate_header={'set-cookie': 1}.has_key
-latin1_alias_match=re.compile(
- r'text/html(\s*;\s*charset=((latin)|(latin[-_]?1)|'
- r'(cp1252)|(cp819)|(csISOLatin1)|(IBM819)|(iso-ir-100)|'
- r'(iso[-_]8859[-_]1(:1987)?)))?$',re.I).match
-
-def is_text_html(content_type):
- return (content_type == 'text/html' or
- latin1_alias_match(content_type) is not None)
-
class HTTPResponse (BaseResponse):
"""
@@ -119,6 +109,7 @@
base = None
realm = 'Zope'
_error_format = 'text/html'
+ payload = BrowserResponsePayload()
def __init__(self, outstream, body='', headers=None,
status=None, cookies=None):
@@ -185,36 +176,7 @@
"%s%s: %s\n" % (self.accumulated_headers, name, value))
def setBody(self, body):
- '''
- Sets the body of the response
-
- Sets the return body equal to the (string) argument "body". Also
- updates the "content-length" return header.
-
- If the body is a 2-element tuple, then it will be treated
- as (title,body)
-
- If is_error is true then the HTML will be formatted as a Zope error
- message instead of a generic HTML page.
- '''
- body = str(body)
-
- if not self.headers.has_key('content-type'):
- c = (self.isHTML(body) and 'text/html' or 'text/plain')
- self.setHeader('content-type', c)
-
- content_type = self.headers['content-type']
- if is_text_html(content_type):
- # Some browsers interpret certain characters in Latin 1 as html
- # special characters. These cannot be removed by html_quote,
- # because this is not the case for all encodings.
- body = body.replace('\213', '<')
- body = body.replace('\233', '>')
-
- self.body = body
- self.insertBase()
- self.updateContentLength()
- return self
+ return self.payload.setBody(self, body)
def updateContentLength(self):
blen = str(len(self.body))
@@ -228,26 +190,6 @@
base=base+'/'
self.base=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], self.base, body[index:]))
-
def appendToCookie(self, name, value):
'''
Creates an HTTP header that sets a cookie on cookie-enabled
@@ -314,11 +256,6 @@
else: h=value
self.setHeader(name,h)
- def isHTML(self, str):
- s = str.strip()
- return (s[:6].lower() == '<html>' or
- s[:14].lower() == '<!doctype html')
-
def redirect(self, location, status=302):
"""Causes a redirection without raising an error"""
self.setStatus(status)
@@ -328,22 +265,7 @@
def handleException(self, exc_info):
"""
"""
- t, v = exc_info[:2]
- if isinstance(t, ClassType):
- if issubclass(t, Redirect):
- self.redirect(v.getLocation())
- return
- self.setStatus(t)
- body = ("<html><head><title>Site error</title></head>\n"
- "<body><p>A site error occurred.</p>\n"
- "<pre>\n"
- "%s\n"
- "</pre>\n"
- "</body></html>\n" %
- escape(traceback_string(t, v, exc_info[2]))
- )
- self.setBody(body)
-
+ self.payload.handleException(self, exc_info)
_wrote=None
@@ -370,9 +292,7 @@
return cookie_list
- def __str__(self,
- html_search=re.compile('<html>',re.I).search,
- ):
+ def __str__(self):
"""
Outputs the headers of the response.
"""
@@ -431,39 +351,4 @@
self.outstream.write(data)
-
-
-def format_exception(etype,value,tb,limit=None):
- import traceback
- result=['Traceback (innermost last):']
- if limit is None:
- if hasattr(sys, 'tracebacklimit'):
- limit = sys.tracebacklimit
- n = 0
- while tb is not None and (limit is None or n < limit):
- f = tb.tb_frame
- lineno = tb.tb_lineno
- co = f.f_code
- filename = co.co_filename
- name = co.co_name
- locals = f.f_locals
- globals = f.f_globals
- modname = globals.get('__name__', filename)
- result.append(' Module %s, line %d, in %s'
- % (modname,lineno,name))
- try: result.append(' (Object: %s)' %
- locals[co.co_varnames[0]].__name__)
- except: pass
- try: result.append(' (Info: %s)' %
- str(locals['__traceback_info__']))
- except: pass
- tb = tb.tb_next
- n = n+1
- result.append(' '.join(traceback.format_exception_only(etype, value)))
- return result
-
-
-def traceback_string(t,v,tb):
- tb=format_exception(t,v,tb,200)
- return '\n'.join(tb)