[Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - IHTTPResponse.py:1.1.2.1 HTTPRequest.py:1.1.2.21.2.2 HTTPResponse.py:1.1.2.13.4.2 IHTTPRequest.py:1.1.2.2.4.1

Jim Fulton jim@zope.com
Wed, 20 Mar 2002 18:42:32 -0500


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

Modified Files:
      Tag: Zope3-publisher-refactor-branch
	HTTPRequest.py HTTPResponse.py IHTTPRequest.py 
Added Files:
      Tag: Zope3-publisher-refactor-branch
	IHTTPResponse.py 
Log Message:
Began significant refactoring of publication framework.

- Added accessor functions, getResponse and getPublication.

- Moved some methods between existing interfaces as seem best, and
  added new new interfaces.

- Getting rid of payloads.




=== Added File Zope3/lib/python/Zope/Publisher/HTTP/IHTTPResponse.py ===
##############################################################################
#
# Copyright (c) 2001 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: IHTTPResponse.py,v 1.1.2.1 2002/03/20 23:42:32 jim Exp $
"""

from Interface import Interface


class IHTTPResponse(Interface):

    def getStatus():
        'Returns the current HTTP status code as an integer. '

    def setStatus(status, reason=None):
        '''Sets the HTTP status code of the response

        The argument may either be an integer or a string from { OK,
        Created, Accepted, NoContent, MovedPermanently,
        MovedTemporarily, NotModified, BadRequest, Unauthorized,
        Forbidden, NotFound, InternalError, NotImplemented,
        BadGateway, ServiceUnavailable } that will be converted to the
        correct integer value.
        '''

    def setHeader(name, value, literal=0):
        '''Sets an HTTP return header "name" with value "value"

        The previous value is cleared. If the literal flag is true,
        the case of the header name is preserved, otherwise
        word-capitalization will be performed on the header name on
        output.        
        '''

    def addHeader(name, value):
        '''Add an HTTP Header
        
        Sets a new HTTP return header with the given value, while retaining
        any previously set headers with the same name.

        '''

    def appendToCookie(name, value):
        '''Append text to a cookie value
        
        If a value for the cookie has previously been set, the new
        value is appended to the old one separated by a colon.
        '''


    def expireCookie(name, **kw):
        '''Causes 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.
        '''


    def setCookie(name, value, **kw):
        '''Sets 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.
        '''

    def appendToHeader(name, value, delimiter=","):
        '''Appends 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.

        '''


=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.21.2.1 => 1.1.2.21.2.2 ===
         self._environ=environ
 
-        self.__getPath()
+        self.__setupPath()
+        self.__setupCookies()
+
+
+    def __setupCookies(self)
 
         ################################################################
         # Cookie values should *not* be appended to existing form
         # vars with the same name - they are more like default values
         # for names not otherwise specified in the form.
+        other = self._other
         cookies={}
-        k=environ.get('HTTP_COOKIE','')
-        if k:
-            parse_cookie(k, cookies)
-            for k,item in cookies.items():
-                if not other.has_key(k):
-                    other[k]=item
+        cookie_header = self._environ.get('HTTP_COOKIE','')
+        if cookie_header:
+            parse_cookie(cookie_header, cookies)
+            for cookie, item in cookies.items():
+                other.setdefault(cookie, item)
+
         self.__cookies = cookies
 
-    def __getPath(self):
+    def __setupPath(self):
         path = self.get('PATH_INFO', '').strip()
         if path.startswith('/'):  path = path[1:] # XXX Why? Not sure
         clean = []
@@ -133,16 +138,18 @@
         clean.reverse()
         self.setTraversalStack(clean)
 
-    def getCookies(self):
-        return self.__cookies
+    ######################################
+    # from: Zope.Publisher.IPublisherRequest.IPublisherRequest
 
-    def supports_retry(self):
+    def supportsRetry(self):
+        'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
         if self.retry_count < self.retry_max_count:
             if STAGGER_RETRIES:
                 time.sleep(whrandom.uniform(0, 2**(self.retry_count)))
             return 1
 
     def retry(self):
+        'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
         self.retry_count=self.retry_count+1
         self.body_instream.seek(0)
         r=self.__class__(
@@ -153,30 +160,10 @@
         r.retry_count=self.retry_count
         return r
 
-    def getHeader(self, name, default=None):
-        """Return the named HTTP header, or an optional default
-        argument or None if the header is not found. Note that
-        both original and CGI-ified header names are recognized,
-        e.g. 'Content-Type', 'CONTENT_TYPE' and 'HTTP_CONTENT_TYPE'
-        should all return the Content-Type header, if available.
-        """
-        environ = self._environ
-        name = name.replace('-', '_').upper()
-        val = environ.get(name, None)
-        if val is not None:
-            return val
-        if not name.startswith('HTTP_'):
-            name='HTTP_%s' % name
-        return environ.get(name, default)
-
-    def __str__(self):
-        return self.payload.debugInfo(self)
+    def traverse(self, object):
+        'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
 
-    def traverse(self, publication, object):
-        """
-        Traverses to an object and returns it.
-        Private.
-        """
+        publication = self.getPublication()
         
         traversal_altered = 0 # flag for adding traversal steps
         add_steps = None
@@ -251,37 +238,41 @@
 
         return object
 
-    def text(self):
-        result = "URL: %s\n" % self.URL
-        result = result + "SERVER_URL: %s\n\n" % self.SERVER_URL
-        result = result + "FORM\n\n"
-        row='%-20s %s\n'
-        for k,v in self.form.items():
-            result=result + row % (k, repr(v))
-        result=result+"\nCOOKIES\n\n"
-        for k,v in self.cookies.items():
-            result=result + row % (k, repr(v))
-        result=result+"\nOTHER\n\n"
-        for k,v in self.other.items():
-            if k in ('PARENTS','RESPONSE'): continue
-            result=result + row % (k, repr(v))
-    
-        for n in "0123456789":
-            key = "URL%s"%n
-            try: result=result + row % (key, self[key]) 
-            except KeyError: pass
-        for n in "0123456789":
-            key = "BASE%s"%n
-            try: result=result + row % (key, self[key]) 
-            except KeyError: pass
-
-        result=result+"\nENVIRON\n\n"
-        for k,v in self.environ.items():
-            if not hide_key(k):
-                result=result + row % (k, v)
-        return result
+    #
+    ######################################
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Publisher.HTTP.IHTTPRequest.
+
+    def getHeader(self, name, default=None):
+        'See Zope.Publisher.HTTP.IHTTPRequest.IHTTPRequest'
+        environ = self._environ
+        name = name.replace('-', '_').upper()
+        val = environ.get(name, None)
+        if val is not None:
+            return val
+        if not name.startswith('HTTP_'):
+            name='HTTP_%s' % name
+        return environ.get(name, default)
+
+    def getCookies(self):
+        'See Zope.Publisher.HTTP.IHTTPRequest.IHTTPRequest'
+        return self.__cookies
+
+    def setPathSuffix(self, steps):
+        'See Zope.Publisher.HTTP.IHTTPRequest.IHTTPRequest'
+        self.__path_suffix = steps
+
+    #
+    ############################################################
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Publisher.HTTP.IHTTPCredentials.
 
     def _authUserPW(self):
+        'See Zope.Publisher.HTTP.IHTTPCredentials.IHTTPCredentials'
         global base64
         auth=self._auth
         if auth:
@@ -292,17 +283,12 @@
                 return name, password
 
     def unauthorized(self, challenge):
+        'See Zope.Publisher.HTTP.IHTTPCredentials.IHTTPCredentials'
         self.response.setHeader("WWW-Authenticate", challenge, 1)
         self.response.setStatus(401)
 
-
-    # _viewtype is overridden from the BaseRequest 
-    #  to implement IBrowserPublisher
-    _viewtype = IBrowserPublisher
-
-    # XXX this doesn't belong here
-    def getEffectiveURL(self):
-        return self.effective_url or self.URL
+    #
+    ############################################################
 
 base64 = None
 


=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.13.4.1 => 1.1.2.13.4.2 ===
                               self.header_output)
 
+    def getStatus(self):
+        return self.status
+
     def setStatus(self, status, reason=None):
-        '''
-        Sets the HTTP status code of the response; the argument may
-        either be an integer or a string from { OK, Created, Accepted,
-        NoContent, MovedPermanently, MovedTemporarily,
-        NotModified, BadRequest, Unauthorized, Forbidden,
-        NotFound, InternalError, NotImplemented, BadGateway,
-        ServiceUnavailable } that will be converted to the correct
-        integer value.
-        '''
         if status is None:
             status = 200
         else:
@@ -162,13 +156,6 @@
         self.reason = reason
 
     def setHeader(self, name, value, literal=0):
-        '''
-        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 word-capitalization will be performed on the header
-        name on output.
-        '''
         key = name.lower()
         if accumulate_header(key):
             self.addHeader(name, value)
@@ -176,12 +163,7 @@
             name = literal and name or key
             self.headers[name]=value
 
-    __setitem__ = setHeader
-
     def addHeader(self, name, value):
-        '''
-        Sets a new HTTP return header with the given value, while retaining
-        any previously set headers with the same name.'''
         accum = self.accumulated_headers
         if not accum:
             self.accumulated_headers = accum = []
@@ -190,18 +172,13 @@
     def setBody(self, body):
         return self.payload.setBody(self, body)
 
-    def updateContentLength(self):
+    def __updateContentLength(self):
         blen = str(len(self.body))
         if blen.endswith('L'):
             blen = blen[:-1]
         self.setHeader('content-length', blen)
 
     def appendToCookie(self, name, value):
-        '''
-        Creates 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. '''
 
         cookies=self.cookies
         if cookies.has_key(name): cookie=cookies[name]
@@ -211,17 +188,6 @@
         else: cookie['value']=value
 
     def expireCookie(self, name, **kw):
-        '''
-        Causes 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.
-        '''
         dict={'max_age':0, 'expires':'Wed, 31-Dec-97 23:59:59 GMT'}
         for k, v in kw.items():
             dict[k]=v
@@ -232,14 +198,6 @@
         self.setCookie(name, 'deleted', **dict)
 
     def setCookie(self, name, value, **kw):
-        '''
-        Sets 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.
-        '''
         cookies=self.cookies
         if cookies.has_key(name):
             cookie=cookies[name]
@@ -249,12 +207,6 @@
         cookie['value']=value
 
     def appendToHeader(self, name, value, delimiter=","):
-        '''
-        Appends 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. '''
         headers=self.headers
         if headers.has_key(name):
             h=self.header[name]
@@ -296,6 +248,16 @@
         
         return cookie_list
 
+    def getHeader(self, name):
+         '''
+         Gets a header value
+         
+         Returns the value associated with a HTTP return header, or
+         "None" if no such header has been set in the response
+         yet.
+         '''
+         return self.headers.get(name, None)
+
 
     def getHeaders(self):
         """
@@ -306,7 +268,7 @@
 
         if (not self._streaming and not headers.has_key('content-length')
             and not headers.has_key('transfer-encoding')):
-            self.updateContentLength()
+            self.__updateContentLength()
 
         res["X-Powered-By"] = "Zope (www.zope.org), Python (www.python.org)"
 


=== Zope3/lib/python/Zope/Publisher/HTTP/IHTTPRequest.py 1.1.2.2 => 1.1.2.2.4.1 ===
 """
 
-
 from Interface import Interface
 
+
+# XXX Should we extend IRequest?
+
 class IHTTPRequest(Interface):
 
     def __getitem__(key):
@@ -54,3 +56,32 @@
           Data that may be set by an application object.
 
         """
+
+    def getCookies():
+        """Return the cookie data
+
+        Data are returned as a mapping object, mapping cookie name to value.
+        """
+
+        return IMapping(str, str)
+
+    def getHeader(name, default=None):
+        """Get a header value
+
+        Return the named HTTP header, or an optional default
+        argument or None if the header is not found. Note that
+        both original and CGI-ified header names are recognized,
+        e.g. 'Content-Type', 'CONTENT_TYPE' and 'HTTP_CONTENT_TYPE'
+        should all return the Content-Type header, if available.
+        """
+
+    def setPathSuffix(steps):
+        """Add additional trversal steps to be taken after all other traversal
+
+        This is used to handle HTTP request methods (except for GET
+        and POST in the case of browser requests) and XML-RPC methods.
+        """
+
+    
+
+