[Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - HTTPRequest.py:1.1.2.21.2.5 HTTPResponse.py:1.1.2.13.4.5 IHTTPApplicationRequest.py:1.1.2.1.2.1 IHTTPApplicationResponse.py:1.1.2.3 IHTTPRequest.py:1.1.2.2.4.2 BrowserPayload.py:NONE IPayload.py:NONE

Jim Fulton jim@zope.com
Mon, 25 Mar 2002 18:31:13 -0500


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

Modified Files:
      Tag: Zope3-publisher-refactor-branch
	HTTPRequest.py HTTPResponse.py IHTTPApplicationRequest.py 
	IHTTPApplicationResponse.py IHTTPRequest.py 
Removed Files:
      Tag: Zope3-publisher-refactor-branch
	BrowserPayload.py IPayload.py 
Log Message:
Refactord BaseRequest/BaseResponse and HTTPRequest/Response some more:

- Use slots so I can keep track of what's going on. ;)
- Use properties for environment, cookies, headers, URLs.
- Put URL responsibilities in HTTPRequest.
- Have HTTP traverse delegate to and augment Base traverse.



=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.21.2.4 => 1.1.2.21.2.5 ===
 from IHTTPCredentials import IHTTPCredentials
 from IHTTPRequest import IHTTPRequest
+from IHTTPApplicationRequest import IHTTPApplicationRequest
+
+from Zope.Publisher.RequestDataProperty \
+     import RequestDataProperty, RequestDataMapper, RequestDataGetter
+
+class CookieMapper(RequestDataMapper):
+    _mapname = '_cookies'
+
+class HeaderGetter(RequestDataGetter):
+    _gettrname = 'getHeader'
+
+_marker = object()
+
+class URLGetter:
+
+    def __init__(self, request):
+        self.__request = request
+
+    def __str__(self):
+        return self.__request.getURL()
+
+    def __getitem__(self, name):
+        i = int(name)
+        try:
+            if i < 0:
+                i = -i
+                return self.__request.getURL(i)
+            else:
+                return self.__request.getApplicationURL(i)
+        except IndexError, v:
+            if v[0] == i:
+                raise KeyError, name
+            raise
+
+    def get(self, name, default=None):
+        i = int(name)
+        try:
+            if i < 0:
+                return self.__request.getURL(-i)
+            else:
+                return self.__request.getApplicationURL(i)
+        except IndexError, v:
+            if v == i:
+                return default
+            raise
 
 DEFAULT_PORTS = {'http': '80', 'https': '443'}
 STAGGER_RETRIES = 1
@@ -34,9 +79,6 @@
 URLmatch=re.compile('URL(PATH)?([0-9]+)$').match
 BASEmatch=re.compile('BASE(PATH)?([0-9]+)$').match
 
-_marker = []
-
-
 class HTTPRequest(BaseRequest):
     """
     Model HTTP request data.
@@ -84,20 +126,30 @@
     other variables, form data, and then cookies.
     """
 
-    __implements__ = BaseRequest.__implements__, IHTTPCredentials, IHTTPRequest
+    __implements__ = (BaseRequest.__implements__,
+                      IHTTPCredentials, IHTTPRequest, IHTTPApplicationRequest,
+                      )
+
+    __slots__ = (
+        '_auth',          # The value of the HTTP_AUTHORIZATION header.    
+        '_cookies',       # The request cookies                            
+        '_path_suffix',   # Extra traversal steps after normal traversal   
+        '_retry_count',   # How many times the request has been retried    
+        '_app_url',       # The application URL                            
+        '_app_path',      # The path part of the application URL           
+        '_app_names',     # The application path as a sequence             
+        '_app_base',      # The application URL without the last name      
+        '_app_server',    # The server path of the application url
+        '_orig_env',      # The original environment
+        )
 
-
-    __auth = None          # The value of the HTTP_AUTHORIZATION header.
-    __cookies = None
-
-    retry_count = 0
-    retry_max_count = 3
+    retry_max_count = 3    # How many times we're willing to retry
 
     def __init__(self, body_instream, outstream, environ):
 
         super(HTTPRequest, self).__init__(body_instream, outstream, environ)
 
-        self.__orig_env = environ
+        self._orig_env = environ
         environ = sane_environment(environ)
 
         if environ.has_key('HTTP_AUTHORIZATION'):
@@ -106,48 +158,143 @@
 
         self._environ = environ
 
-        self.__setupPath()
         self.__setupCookies()
+        self.__setupPath()
+        self.__setupURLBase()
 
+    def __setupURLBase(self):
 
-    def __setupCookies(self)
+        get_env = self._environ.get
+
+        ################################################################
+        # Get base info first. This isn't likely to cause
+        # errors and might be useful to error handlers.
+        base = script = get_env('SCRIPT_NAME','').strip()
+
+        # _script and the other _names are meant for URL construction
+        self._app_names = app_names = filter(None, script.split('/'))
+        self._app_path = map(quote, app_names)
+
+        # Remove trailing /'s
+        while base and base.endswith('/'):
+            base = base[:-1]
+
+        # strip off last element of the URL
+        p = base.rfind('/')
+        if p >= 0:
+            base = base[:p+1]
+        else:
+            base = ''
+
+        # strip off leading /'s
+        while base and base.startswith('/'):
+            base = base[1:]
+
+        # get server URL and store it too, since we are already looking it up
+        server_url = get_env('SERVER_URL', None)
+        if server_url is not None:
+            self._app_server = server_url = server_url.strip()
+        else:
+            server_url = self.__deduceServerURL()
+
+        if server_url.endswith('/'):
+            server_url = server_url[:-1]
+
+        # put the complete base URL together
+        if base:
+            self._app_base = "%s/%s" % (server_url, base)
+        else:
+            self._app_base = server_url
+
+        # strip off leading /'s of script
+        while script.startswith('/'):
+            script = script[1:]
+
+        self._app_server = server_url
+
+        # put the script URL together
+        if script:
+            script = "%s/%s" % (server_url,script)
+        else:
+            script = server_url
+
+        self._app_url = script
+
+    def __deduceServerURL(self):
+        environ = self._environ
+        have_env = environ.has_key
+
+        if have_env('HTTPS') and (
+            environ['HTTPS'] == "on" or environ['HTTPS'] == "ON"):
+            protocol = 'https'
+
+        elif (have_env('SERVER_PORT_SECURE') and 
+              environ['SERVER_PORT_SECURE'] == "1"):
+            protocol = 'https'
+        else: protocol = 'http'
+
+        if have_env('HTTP_HOST'):
+            host = environ['HTTP_HOST'].strip()
+            hostname, port = splitport(host)
+
+        else:
+            hostname = environ.get('SERVER_NAME', '').strip()
+            port = environ.get('SERVER_PORT', '')
+
+
+        if (not port or DEFAULT_PORTS.get(protocol, 80) == port):
+            host = hostname
+        else:
+            host = hostname + ':' + port
+
+        server_url = '%s://%s' % (protocol, host)
+        return server_url
+
+    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={}
         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
 
+        self._cookies = cookies
 
     def __setupPath(self):
-        path = self.get('PATH_INFO', '').strip()
-        if path.startswith('/'):  path = path[1:] # XXX Why? Not sure
+        path = self.get('PATH_INFO', '/').strip()
+
+        if path.endswith('/'):
+            path = path[:-1] # XXX Why? Not sure
+            self._endswithslash = 1
+        
+        if path.startswith('/'):
+            path = path[1:] # XXX Why? Not sure
+
         clean = []
         for item in path.split('/'):
-            if not item or item == '.':
+            if item == '.':
                 continue
             elif item == '..':
-                del clean[-1]
+                try: del clean[-1]
+                except IndexError:
+                    raise NotFound('..')
             else: clean.append(item)
 
         clean.reverse()
         self.setTraversalStack(clean)
 
+        self._path_suffix = None
+
 
     ######################################
     # from: Zope.Publisher.IPublisherRequest.IPublisherRequest
 
     def supportsRetry(self):
         'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
-        if self.retry_count < self.retry_max_count:
+        if self._retry_count < self.retry_max_count:
             if STAGGER_RETRIES:
                 time.sleep(whrandom.uniform(0, 2**(self.retry_count)))
             return 1
@@ -158,9 +305,9 @@
         self.retry_count = self.retry_count + 1
         self.body_instream.seek(0)
         request = self.__class__(
-            body_instream = self.__body_instream,
+            body_instream = self._body_instream,
             outstream = self.getResponse().getOutputStream(),
-            environ = self.__orig_env
+            environ = self._orig_env
             )
         request.retry_count = self.retry_count
         return request
@@ -169,89 +316,12 @@
     def traverse(self, object):
         'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
 
-        publication = self.getPublication()
-        
-        traversal_altered = 0 # flag for adding traversal steps
-        add_steps = None
-        path_str = self.get('PATH_INFO', '').strip()
-
-        traversal_stack = self._splitPath(path_str)
-        traversal_stack.reverse()
-        self.setTraversalStack(traversal_stack)
-
-        self.traversed = traversed = []
-        traversed.append(object)
-        steps = self.steps
-        self.quoted_steps = quoted_steps = map(pc_quote, steps)
-
-        prev_object = None
-        while 1:
-            if object is not prev_object:
-                # Invoke hooks (but not more than once).
-                publication.callTraversalHooks(self, object)
-                # A hook may have called changeTraversalStack().
-                traversal_stack = self.getTraversalStack()
-
-            prev_object = object
-
-            if traversal_stack:
-                # Traverse to the next step.
-                entry_name = traversal_stack.pop()
-                if entry_name:
-                    qstep = pc_quote(entry_name)
-                    quoted_steps.append(qstep)
-                        
-                    if traversal_altered:
-                        # The effective URL includes the altered traversal.
-                        #import pdb; pdb.set_trace()
-                        e_url = self.effective_url or self.URL
-                        self.effective_url = '%s/%s' % (e_url, qstep)
-                    else:
-                        # Build up the URL to the object, but not
-                        # to the default traversal.                        
-                        self.URL = '%s/%s' % (self.URL, qstep)
-                    subobject = publication.traverseName(
-                        self, object, entry_name)
-                    object = subobject
-                    traversed.append(object)
-                    steps.append(entry_name)
-
-            else:
-                add_steps = self._request_default
-                
-                if add_steps:
-                    self._request_default = None
-                
-                if add_steps is None:
-                    object, add_steps = publication.getDefaultTraversal(
-                        self, object)
-                    
-                if add_steps:
-                    traversal_altered = 1
-                    traversal_stack.extend(add_steps)
-                else:
-                    # Finished traversal.
-                    break
-        
-        if traversal_altered:
-            eurl = self.effective_url
-            loc = eurl.rfind('/')
-            # XXX Quick bug fix, need better impl
-            if loc >= 0:
-                eurl = eurl[:loc+1] 
-            self.response.setBase(eurl)
-
-
-        self.traversed = tuple(traversed)  # No more changes allowed
-        self._afterTraveral() # Sometimes we want to do something here
-        return object
-
-
-    # This method is not part of the interface.
-    def _afterTraversal(self):
-        '''Do whatever needs to be done after an object traveral'''
-        pass
+        ob = super(HTTPRequest, self).traverse(object)
+        if self._path_suffix:
+            self._traversal_stack = self._path_suffix
+            ob = super(HTTPRequest, self).traverse(ob)
 
+        return ob
 
     # This method is not part of the interface.
     def _splitPath(self, path):
@@ -290,13 +360,19 @@
             name='HTTP_%s' % name
         return environ.get(name, default)
 
+    headers = RequestDataProperty(HeaderGetter)
+
     def getCookies(self):
         'See Zope.Publisher.HTTP.IHTTPRequest.IHTTPRequest'
-        return self.__cookies
+        return self._cookies
+
+    cookies = RequestDataProperty(CookieMapper)
 
     def setPathSuffix(self, steps):
         'See Zope.Publisher.HTTP.IHTTPRequest.IHTTPRequest'
-        self.__path_suffix = steps
+        steps = list(steps)
+        steps.reverse()
+        self._path_suffix = steps
 
     #
     ############################################################
@@ -327,6 +403,68 @@
     def _createResponse(self, outstream):
         # Should be overridden by subclasses
         return HTTPResponse(outstream)
+
+
+    def getURL(self, level=0, path_only=0):
+        names = self._app_names + self._traversed_names        
+        if level:
+            if level > len(names):
+                raise IndexError, level 
+            names = names[:-level]
+        names = map(quote, names)
+
+        if path_only:
+            if not names: return '/'
+            return '/' + '/'.join(names)
+        else:
+            if not names: return self._app_server
+            return "%s/%s" % (self._app_server, '/'.join(names))
+
+    def getApplicationURL(self, depth=0, path_only=0):
+        if depth:
+            names = self._traversed_names        
+            if depth > len(names):
+                raise IndexError, depth 
+            names = self._app_names + names[:depth]
+        else:
+            names = self._app_names
+            
+        names = map(quote, names)
+
+        if path_only:
+            return names and ('/' + '/'.join(names)) or '/'
+        else:
+            return (names and ("%s/%s" % (self._app_server, '/'.join(names)))
+                    or self._app_server)
+
+    URL = RequestDataProperty(URLGetter)
+
+    ######################################
+    # from: Interface.Common.Mapping.IReadMapping
+
+    def get(self, key, default=None):
+        'See Interface.Common.Mapping.IReadMapping'
+
+        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
+
+    #
+    ############################################################
+
+    ######################################
+    # from: Interface.Common.Mapping.IEnumerableMapping
+
+    def keys(self):
+        'See Interface.Common.Mapping.IEnumerableMapping'
+        d = {}
+        d.update(self._environ)
+        d.update(self._cookies)
+        return d.keys()
 
 
 


=== Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.13.4.4 => 1.1.2.13.4.5 ===
 from Zope.Publisher.BaseResponse import BaseResponse
 from Zope.Publisher.Exceptions import Redirect
+from IHTTPResponse import IHTTPResponse
+from IHTTPApplicationResponse import IHTTPApplicationResponse
+from Zope.Exceptions.ExceptionFormatter import format_exception
 
 # Possible HTTP status responses
 status_reasons = {
@@ -96,22 +99,29 @@
     __implements__ = IHTTPResponse, IHTTPApplicationResponse, \
                      BaseResponse.__implements__
 
-    base = None
-    realm = 'Zope'
-    _error_format = 'text/html'
-    _wrote_headers = 0
-    _streaming = 0
-    __status = 200      # The response status (usually an integer)
-    reason = 'Ok'
+    __slots__ = (
+        '_header_output', # XXX what is this
+        '_headers',
+        '_cookies',
+        '_accumulated_headers', # Headers that can have multiples
+        '_wrote_headers',
+        '_streaming',
+        '_status',      # The response status (usually an integer)
+        '_reason'       # The reason that goes with the status
+        )
 
 
     def __init__(self, outstream, header_output = None):
-        self.__header_output = header_output
+        self._header_output = header_output
 
         super(HTTPResponse, self).__init__(outstream)
-        self.__headers = {}
-        self.__cookies = {}
-        self.__accumulated_headers = []
+        self._headers = {} 
+        self._cookies = {} 
+        self._accumulated_headers = []
+        self._wrote_headers = 0
+        self._streaming = 0
+        self._status = 200
+        self._reason = 'Ok'
 
 
     ############################################################
@@ -129,7 +139,7 @@
                 status = status_codes[status]
             else:
                 status=500
-        self.__status = status
+        self._status = status
 
         if reason is None:
             if status == 200:
@@ -138,12 +148,12 @@
                 reason = status_reasons[status]
             else:
                 reason = 'Unknown'
-        self.reason = reason
+        self._reason = reason
 
 
     def getStatus(self):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
-        return self.__status
+        return self._status
 
 
     def setHeader(self, name, value, literal=0):
@@ -153,24 +163,24 @@
             self.addHeader(name, value)
         else:
             name = literal and name or key
-            self.__headers[name]=value
+            self._headers[name]=value
 
 
     def addHeader(self, name, value):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
-        accum = self.accumulated_headers
+        accum = self._accumulated_headers
         accum.append('%s: %s' % (name, value))
 
 
     def getHeader(self, name, default=None):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
-        return self.__headers.get(name, default)
+        return self._headers.get(name, default)
 
 
     def getHeaders(self):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
         result = {}
-        headers = self.__headers
+        headers = self._headers
 
         if (not self._streaming and not headers.has_key('content-length')
             and not headers.has_key('transfer-encoding')):
@@ -196,9 +206,9 @@
 
     def appendToHeader(self, name, value, delimiter=','):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
-        headers = self.headers
+        headers = self._headers
         if headers.has_key(name):
-            h = self.header[name]
+            h = self._header[name]
             h = "%s%s\r\n\t%s" % (h, delimiter, value)
         else: h = value
         self.setHeader(name, h)
@@ -206,7 +216,7 @@
 
     def appendToCookie(self, name, value):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
-        cookies = self.cookies
+        cookies = self._cookies
         if cookies.has_key(name): cookie = cookies[name]
         else: cookie = cookies[name] = {}
         if cookie.has_key('value'):
@@ -219,7 +229,7 @@
         dict={'max_age':0, 'expires':'Wed, 31-Dec-97 23:59:59 GMT'}
         for k, v in kw.items():
             dict[k]=v
-        cookies=self.cookies
+        cookies=self._cookies
         if cookies.has_key(name):
             # Cancel previous setCookie().
             del cookies[name]
@@ -228,7 +238,7 @@
 
     def setCookie(self, name, value, **kw):
         'See Zope.Publisher.HTTP.IHTTPResponse.IHTTPResponse'
-        cookies=self.cookies
+        cookies=self._cookies
         if cookies.has_key(name):
             cookie=cookies[name]
         else: cookie=cookies[name]={}
@@ -246,9 +256,9 @@
     ######################################
     # from: Zope.Publisher.IPublisherResponse.IPublisherResponse
 
-
     def handleException(self, exc_info):
         """
+        Calls self.setBody() with an error response.
         """
         t, v = exc_info[:2]
         if isinstance(t, ClassType):
@@ -263,18 +273,34 @@
         # for apps to control the status code.
         self.setStatus(tname)
 
-        tb = escape(traceback_string(t, v, exc_info[2]))
-        self.setBody(tb)
+        tb = ''.join(format_exception(t, v, exc_info[2], 1))
+        body = self._html(title, "%s" % tb)
+        self.setBody(body)
+
+
+    def _html(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 retry(self):
         """
         Returns a response object to be used in a retry attempt
         """
-        return self.__class__(self.outstream,
-                              self.header_output)
+        return self.__class__(self._outstream,
+                              self._header_output)
 
     def _updateContentLength(self):
-        blen = str(len(self.body))
+        blen = str(len(self._body))
         if blen.endswith('L'):
             blen = blen[:-1]
         self.setHeader('content-length', blen)
@@ -287,7 +313,7 @@
 
     def _cookie_list(self):
         cookie_list = []
-        for name, attrs in self.cookies.items():
+        for name, attrs in self._cookies.items():
 
             # Note that as of May 98, IE4 ignores cookies with
             # quoted cookie attr values, so only the value part
@@ -316,26 +342,26 @@
 
 
     def getHeaderText(self, m):
-        lst = ['Status: %s %s' % (self.status, self.reason)]
+        lst = ['Status: %s %s' % (self._status, self._reason)]
         lst.extend(map(lambda x: '%s: %s' % x, m.items()))
         lst.extend(self._cookie_list())
-        lst.extend(self.__accumulated_headers)
+        lst.extend(self._accumulated_headers)
         return ('%s\r\n\r\n' % '\r\n'.join(lst))
 
 
     def outputHeaders(self):
         headers = self.getHeaders()
-        header_output = self.header_output
+        header_output = self._header_output
         if header_output is not None:
             # Use the IHeaderOutput interface.
-            header_output.setResponseStatus(self.status, self.reason)
+            header_output.setResponseStatus(self._status, self._reason)
             header_output.setResponseHeaders(headers)
             header_output.appendResponseHeaders(self._cookie_list())
             header_output.appendResponseHeaders(self.__accumulated_headers)
         else:
             # Write directly to outstream.
             headers_text = self.getHeaderText(headers)
-            self.outstream.write(headers_text)
+            self._outstream.write(headers_text)
 
 
     ######################################
@@ -372,13 +398,13 @@
         if not self._wrote_headers:
             self.outputHeaders()
             self._wrote_headers = 1
-        self.outstream.write(data)
+        self._outstream.write(data)
 
     def outputBody(self):
         """
         Outputs the response body.
         """
-        self.output(self.body)
+        self.output(self._body)
 
 
     def _formatException(etype, value, tb, limit=None):


=== Zope3/lib/python/Zope/Publisher/HTTP/IHTTPApplicationRequest.py 1.1.2.1 => 1.1.2.1.2.1 ===
 
 from Zope.Publisher.IApplicationRequest import IApplicationRequest
+from Interface.Attribute import Attribute
 
 class IHTTPApplicationRequest(IApplicationRequest):
     """HTTP request data.
     
     This object provides access to request data.  This includes, the
-    input headers, form data, server data, and cookies.
+    input headers, server data, and cookies.
 
     Request objects are created by the object publisher and will be
     passed to published objects through the argument name, REQUEST.
@@ -51,5 +52,88 @@
 
     The request object may be used as a mapping object, in which case
     values will be looked up in the order: environment variables,
-    other variables, form data, and then cookies.    
+    other variables, cookies, and special.    
     """
+
+    def __getitem__(key):
+        """Return HTTP 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.
+
+        Cookies are searched before environmental data.
+        """
+
+    def getCookies():
+        """Return the cookie data
+
+        Data are returned as a mapping object, mapping cookie name to value.
+        """
+
+        return IMapping(str, str)
+
+    cookies = Attribute(
+        """Request cookie data
+
+        This is a read-only mapping from variable name to value.
+        """)
+
+    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.
+        """
+
+    headers = Attribute(
+        """Request header data
+
+        This is a read-only mapping from variable name to value.
+        """)
+
+    URL = Attribute(
+        """Request URL data
+
+        When convered to a string, this gives the effective published URL.
+
+        This is object can also be used as a mapping object. The keys
+        must be integers or strings that can be converted to
+        integers. A non-negative integer returns a URL n steps from
+        the URL of the top-level application objects. A negative
+        integer gives a URL that is -n steps back from the effective
+        URL.
+
+        For example, 'request.URL[-2]' is equivalent to the Zope 2
+        'request["URL2"]'. The notion is that this would be used in
+        path expressions, like 'request/URL/-2'.
+        """)
+        
+
+    def getURL(level=0, path_only=0):
+        """Return the published URL with level names removed from the end.
+
+        If path_only is true, then only a path will be returned.
+        """
+
+    def getApplicationURL(depth=0, path_only=0):
+        """Return the application URL plus depth steps
+
+        If path_only is true, then only a path will be returned.
+        """
+
+    


=== Zope3/lib/python/Zope/Publisher/HTTP/IHTTPApplicationResponse.py 1.1.2.2 => 1.1.2.3 ===
 
 class IHTTPApplicationResponse(IApplicationResponse):
-    """This interface expands IHTTPResponse interface by methods that
-    will be used by the application.
+    """HTTP Response
     """
 
-    def __getitem__(key):
-        """Return HTTP 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.
-
-        Cookies are searched before environmental data.
-        """
-
-    def getCookies():
-        """Return the cookie data
-
-        Data are returned as a mapping object, mapping cookie name to value.
-        """
-
-        return IMapping(str, str)
-
-    cookies = Attribute(
-        """Request cookie data
-
-        This is a read-only mapping from variable name to value.
-        """)
-
-    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.
-        """
-
-    headers = Attribute(
-        """Request header data
-
-        This is a read-only mapping from variable name to value.
-        """)
-
-    URL = Attribute(
-        """Request URL data
-
-        When convered to a string, this gives the effective published URL.
-
-        This is object can also be used as a mapping object. The keys
-        must be integers or strings that can be converted to
-        integers. A non-negative integer returns a URL n steps from
-        the URL of the top-level application objects. A negative
-        integer gives a URL that is -n steps back from the effective
-        URL.
-
-        For example, 'request.URL[-2]' is equivalent to the Zope 2
-        'request["URL2"]'. The notion is that this would be used in
-        path expressions, like 'request/URL/-2'.
-        """
-
-    def redirect(self, location, status=302):
+    def redirect(location, status=302):
         """Causes a redirection without raising an error.
         """
 


=== Zope3/lib/python/Zope/Publisher/HTTP/IHTTPRequest.py 1.1.2.2.4.1 => 1.1.2.2.4.2 ===
 class IHTTPRequest(Interface):
 
-    def __getitem__(key):
-        """Return HTTP request data 
-
-        Request data are divided into five categories:
-
-        - 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>
-
-        - Form data
-
-          These are data extracted from either a URL-encoded query
-          string or body, if present.
-
-        - Cookies
-
-          These are the cookie data, if present.
-
-        - Lazy Data
-
-          These are callables which are deferred until explicitly
-          referenced, at which point they are resolved and stored as
-          application data.
-
-        - Other
-
-          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
 

=== Removed File Zope3/lib/python/Zope/Publisher/HTTP/BrowserPayload.py ===

=== Removed File Zope3/lib/python/Zope/Publisher/HTTP/IPayload.py ===