[Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/Browser - BrowserRequest.py:1.1.4.1 BrowserResponse.py:1.1.4.1 IBrowserApplicationRequest.py:1.1.2.3 IBrowserPublication.py:1.1.4.1 IBrowserRequest.py:1.1.4.1 IVirtualHostRequest.py:1.1.4.1 cgi_names.py:1.1.4.1 AttributePublisher.py:1.1.2.10 IBrowserPublisher.py:1.1.2.7

Jim Fulton jim@zope.com
Tue, 26 Mar 2002 16:26:29 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/Browser
In directory cvs.zope.org:/tmp/cvs-serv7731/Zope/Publisher/Browser

Modified Files:
      Tag: Zope-3x-branch
	AttributePublisher.py IBrowserPublisher.py 
Added Files:
      Tag: Zope-3x-branch
	BrowserRequest.py BrowserResponse.py 
	IBrowserApplicationRequest.py IBrowserPublication.py 
	IBrowserRequest.py IVirtualHostRequest.py cgi_names.py 
Log Message:
Merged the publication refactoring branch into the main branch.

Also renamed:

  browser_reaverse -> publishTraverse

  browser_default -> browserDefault



=== Added File Zope3/lib/python/Zope/Publisher/Browser/BrowserRequest.py === (418/518 lines abridged)
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################
"""

$Id: BrowserRequest.py,v 1.1.4.1 2002/03/26 21:25:58 jim Exp $
"""

import re

from cgi import FieldStorage
from urllib import quote, unquote, splittype, splitport
from cgi_names import isCGI_NAME, hide_key
from Zope.Publisher.Converters import get_converter
from Zope.Publisher.HTTP.HTTPRequest import HTTPRequest
from IBrowserPublisher import IBrowserPublisher

from IBrowserRequest import IBrowserRequest
from IBrowserPublication import IBrowserPublication
from IBrowserApplicationRequest import IBrowserApplicationRequest
from BrowserResponse import BrowserResponse

# Flas Constants
SEQUENCE = 1
DEFAULT = 2
RECORD = 4
RECORDS = 8
REC = 12 # RECORD|RECORDS
EMPTY = 16
CONVERTED = 32

search_type = re.compile('(:[a-zA-Z][a-zA-Z0-9_]+|\\.[xy])$').search


class BrowserRequest(HTTPRequest):

    __implements__ = (HTTPRequest.__implements__,
                      IBrowserRequest, IBrowserPublication,
                      IBrowserApplicationRequest,
                      )

[-=- -=- -=- 418 lines omitted -=- -=- -=-]

    ######################################
    # from: Interface.Common.Mapping.IReadMapping

    def get(self, key, default=None):
        'See Interface.Common.Mapping.IReadMapping'

        result = self._form.get(key, self)
        if result is not self: return result

        result = self._cookies.get(key, self)
        if result is not self: return result
        
        result = self._environ.get(key, self)
        if result is not self: return result

        return default

    #
    ############################################################

class RedirectingBrowserRequest(BrowserRequest):
    """Browser requests that redirect when the actual and effective URLs differ
    """
    
    use_redirect = 1

class TestRequest(BrowserRequest):

    def __init__(self, body_instream=None, outstream=None, environ=None, **kw):

        _testEnv =  {
            'SERVER_URL':         'http://127.0.0.1',
            'HTTP_HOST':          '127.0.0.1',
            'CONTENT_LENGTH':     '0',
            'GATEWAY_INTERFACE':  'TestFooInterface/1.0',
            }

        if environ:
            _testEnv.update(environ)
        if kw:
            _testEnv.update(kw)
        if body_instream is None:
            from StringIO import StringIO
            body_instream = StringIO('')

        if outstream is None:
            outstream = StringIO()

        super(TestRequest, self).__init__(body_instream, outstream, _testEnv)
    


=== Added File Zope3/lib/python/Zope/Publisher/Browser/BrowserResponse.py ===
# Copyright (c) 2001 Zope Corporation and Contributors.  All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.

'''HTTP Response Output formatter

$Id: BrowserResponse.py,v 1.1.4.1 2002/03/26 21:25:58 jim Exp $'''
__version__='$Revision: 1.1.4.1 $'[11:-2]

import sys, re
from types import StringType, ClassType
from cgi import escape

from Zope.Publisher.HTTP.HTTPResponse import HTTPResponse
from Zope.Publisher.Exceptions import Redirect


start_of_header_search=re.compile('(<head[^>]*>)', re.IGNORECASE).search
base_re_search=re.compile('(<base.*?>)',re.I).search


class BrowserResponse(HTTPResponse):
    """Browser response
    """

    __slots__ = (
        '_base', # The base href
        )

    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', '&lt;')
            body = body.replace('\233', '&gt;')

        body = self.__insertBase(body)
        self._body = body
        self._updateContentLength()

    def __isHTML(self, str):
        s = str.strip().lower()
        return s.startswith('<html>') or s.startswith('<!doctype html')


    def __wrapInHTML(self, title, content):
        t = escape(title)
        return (
            "<html><head><title>%s</title></head>\n"
            "<body><h2>%s</h2>\n"
            "%s\n"
            "</body></html>\n" %
            (t, t, content)
            )


    def __insertBase(self, body):
        # Only insert a base tag if content appears to be html.
        content_type = self.getHeader('content-type', '')
        if content_type and content_type != 'text/html':
            return body

        if getattr(self, '_base', ''):
            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:
                        body = ('%s\n<base href="%s" />\n%s' %
                                (body[:index], self._base, body[index:]))
        return body

    def getBase(self):
        return getattr(self, '_base', '')

    def setBase(self, base):
        self._base = base



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)


=== Zope3/lib/python/Zope/Publisher/Browser/IBrowserApplicationRequest.py 1.1.2.2 => 1.1.2.3 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Zope.Publisher.HTTP.IHTTPApplicationRequest import IHTTPApplicationRequest
+from Interface.Attribute import Attribute
+
+class IBrowserApplicationRequest(IHTTPApplicationRequest):
+    """Browser-specific requests
+    """
+
+    def __getitem__(key):
+        """Return Browser request data 
+
+        Request data sre retrieved from one of:
+
+        - Environment variables
+
+          These variables include input headers, server data, and other
+          request-related data.  The variable names are as <a
+          href="http://hoohoo.ncsa.uiuc.edu/cgi/env.html">specified</a>
+          in the <a
+          href="http://hoohoo.ncsa.uiuc.edu/cgi/interface.html">CGI
+          specification</a>
+
+        - Cookies
+
+          These are the cookie data, if present.
+
+        - Form data
+
+        Form data are searched before cookies, which are searched
+        before environmental data.
+        """
+
+    form = Attribute(
+        """Form data
+
+        This is a read-only mapping from name to form value for the name.
+        """)


=== Added File Zope3/lib/python/Zope/Publisher/Browser/IBrowserPublication.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################
"""

Revision information:
$Id: IBrowserPublication.py,v 1.1.4.1 2002/03/26 21:25:58 jim Exp $
"""

from Zope.Publisher.IPublication import IPublication

class IBrowserPublication (IPublication):
    """
    Object publication framework.
    """

    def getDefaultTraversal(request, ob):
        """Get the default published object for the request
        
        Allows a default view to be added to traversal.
        Returns (ob, steps_reversed).
        """



=== Added File Zope3/lib/python/Zope/Publisher/Browser/IBrowserRequest.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################
"""

$Id: IBrowserRequest.py,v 1.1.4.1 2002/03/26 21:25:58 jim Exp $
"""

from Zope.Publisher.HTTP.IHTTPRequest import IHTTPRequest
from IVirtualHostRequest import IVirtualHostRequest


class IBrowserRequest(IHTTPRequest, IVirtualHostRequest):
    """Browser-specific Rquest functionality.

    Note that the browser is special in many ways, since it exposes
    the Request object to the end-developer.
    """


=== Added File Zope3/lib/python/Zope/Publisher/Browser/IVirtualHostRequest.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################
"""

$Id: IVirtualHostRequest.py,v 1.1.4.1 2002/03/26 21:25:58 jim Exp $
"""

from Interface import Interface

class IVirtualHostRequest(Interface):
    """The support for virtual hosts in Zope is very important.

    In order to make virtual hosts working, we need to support several
    methods in our Request object. This interface defines the required
    methods.
    """

    def setVirtualRoot(path, hard=0):
        """Treat the current publishing object as a VirtualRoot.
        """


    def convertPhysicalPathToVirtualPath(path):
        """Remove the path to the VirtualRoot from a physical path.
        """


    def convertPhysicalPathToURL(path, relative=0):
        """Convert a physical path into a URL in the current context.
        """


    def getPhysicalPathFromURL(URL):
        """Convert a URL into a physical path in the current context.

        If the URL makes no sense in light of the current virtual
        hosting context, a ValueError is raised.
        """

    def getEffectiveURL(self):
        """Return the effective URL.
        """


=== Added File Zope3/lib/python/Zope/Publisher/Browser/cgi_names.py ===
# Copyright (c) 2001 Zope Corporation and Contributors.  All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.

#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/Browser/AttributePublisher.py 1.1.2.9 => 1.1.2.10 ===
     # Zope.Publisher.Browser.IBrowserPublisher.
 
-    def browser_traverse(self, request, name):
+    def publishTraverse(self, request, name):
         '''See interface IBrowserPublisher'''
 
         if name.endswith('.html'):
@@ -24,6 +24,6 @@
 
         return getattr(self, name)
 
-    def browser_default(self, request):
+    def browserDefault(self, request):
         '''See interface IBrowserPublisher'''
         return self, ("index.html",)


=== Zope3/lib/python/Zope/Publisher/Browser/IBrowserPublisher.py 1.1.2.6 => 1.1.2.7 ===
 class IBrowserPublisher(Interface):
 
-    def browser_traverse(request, name):
+    def publishTraverse(request, name):
         """Lookup a name
 
         The request argument is the publisher request object.
         """
 
-    def browser_default(request):
+    def browserDefault(request):
         """Provide the default object
 
         The default object is expressed as a (possibly different)
@@ -26,13 +26,13 @@
         Returns an object and a sequence of names.  If the sequence of
         names is not empty, then a traversal step is made for each name.
         After the publisher gets to the end of the sequence, it will
-        call browser_default on the last traversed object.
+        call browserDefault on the last traversed object.
 
         Normal usage is to return self for object and a default view name.
 
         The publisher calls this method at the end of each traversal path. If
         a non-empty sequence of names is returned, the publisher will traverse 
-        those names and call browser_default again at the end.
+        those names and call browserDefault again at the end.
 
         Note that if additional traversal steps are indicated (via a
         nonempty sequence of names), then the publisher will try to adjust