Commits

Robert Brewer committed 25739c0

Replaced request.remote_addr, remote_port, and remote_host with a single "remote" attribute, an instance of lib.http.Host, which has "ip", "port" and "name" attributes. Added a similar request.local attribute. Changed request() signature to (local, remote, scheme). This allows requests run behind multiple HTTP servers to know the address info for their particular connection.

  • Participants
  • Parent commits eceb4cb
  • Branches cherrypy

Comments (0)

Files changed (11)

 def log_access():
     """Default method for logging access"""
     tmpl = '%(h)s %(l)s %(u)s [%(t)s] "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
-    s = tmpl % {'h': request.remote_host,
+    s = tmpl % {'h': request.remote.name or request.remote.ip,
                 'l': '-',
                 'u': getattr(request, "login", None) or "-",
                 't': logtime(),

File _cpengine.py

     if _signal_exc.args[0] != "signal only works in main thread":
         raise
 
+
 class Engine(object):
     """The application engine, which exposes a request interface to (HTTP) servers."""
     
     ready = property(_is_ready, doc="Return True if the engine is ready to"
                                     " receive requests, False otherwise.")
     
-    def request(self, client_address, remote_host, scheme="http"):
+    def request(self, local_host, remote_host, scheme="http"):
         """Obtain an HTTP Request object.
         
-        client_address: the (IP address, port) of the client
-        remote_host should be the client's host name. If not available
-            (because no reverse DNS lookup is performed), the client
-            IP should be provided.
+        local_host should be an http.Host object with the server info.
+        remote_host should be an http.Host object with the client info.
         scheme: either "http" or "https"; defaults to "http"
         """
         if self.state == STOPPED:
                 
                 for func in self.on_start_thread_list:
                     func(i)
-            r = self.request_class(client_address[0], client_address[1],
-                                   remote_host, scheme)
+            r = self.request_class(local_host, remote_host, scheme)
         cherrypy.serving.request = r
         cherrypy.serving.response = self.response_class()
         return r
 from mod_python import apache
 import cherrypy
 from cherrypy._cperror import format_exc, bare_error
+from cherrypy.lib import http
 
 
 def setup(req):
             _isSetUp = True
         
         # Obtain a Request object from CherryPy
-        clientAddress = req.connection.remote_addr
-        remoteHost = clientAddress[0]
+        local = req.connection.local_addr
+        local = http.Host(local[0], local[1], req.connection.local_host or "")
+        remote = req.connection.remote_addr
+        remote = http.Host(remote[0], remote[1], req.connection.remote_host or "")
+        
         scheme = req.parsed_uri[0] or 'http'
-        request = cherrypy.engine.request(clientAddress, remoteHost, scheme)
+        request = cherrypy.engine.request(local, remote, scheme)
         req.get_basic_auth_pw()
         request.login = req.user
         

File _cprequest.py

 class Request(object):
     """An HTTP request."""
     
-    # Conversation attributes
-    remote_addr = "localhost"
-    remote_port = 1111
-    remote_host = "localhost"
+    # Conversation/connection attributes
+    local = http.Host("localhost", 80)
+    remote = http.Host("localhost", 1111)
     scheme = "http"
     base = ""
     
                   'before_error_response', 'after_error_response']
     hooks = HookMap(hookpoints)
     
-    def __init__(self, remote_addr, remote_port, remote_host, scheme="http"):
+    def __init__(self, local_host, remote_host, scheme="http"):
         """Populate a new Request object.
         
-        remote_addr should be the client IP address.
-        remote_port should be the client Port.
-        remote_host should be the client's host name. If not available
-            (because no reverse DNS lookup is performed), the client
-            IP should be provided.
+        local_host should be an http.Host object with the server info.
+        remote_host should be an http.Host object with the client info.
         scheme should be a string, either "http" or "https".
         """
-        self.remote_addr = remote_addr
-        self.remote_port = remote_port
-        self.remote_host = remote_host
+        self.local = local_host
+        self.remote = remote_host
         self.scheme = scheme
         
         self.closed = False
                 raise cherrypy.HTTPError(400, msg)
         host = dict.__getitem__(headers, 'Host')
         if not host:
-            host = cherrypy.config.get('server.socket_host', '')
+            host = self.local.name or self.local.ip
         self.base = "%s://%s" % (self.scheme, host)
     
     def get_resource(self, path):
     request = None
     try:
         env = environ.get
-        clientAddr = (env('REMOTE_ADDR', ''), int(env('REMOTE_PORT', -1)))
-        request = cherrypy.engine.request(clientAddr, env('REMOTE_ADDR', ''),
-                                          environ['wsgi.url_scheme'])
+        local = http.Host('', int(env('SERVER_PORT', 80)),
+                          env('SERVER_NAME', ''))
+        remote = http.Host(env('REMOTE_ADDR', ''),
+                           int(env('REMOTE_PORT', -1)),
+                           env('REMOTE_HOST', ''))
+        request = cherrypy.engine.request(local, remote, env('wsgi.url_scheme'))
         
         # LOGON_USER is served by IIS, and is the name of the
         # user after having been mapped to a local account.

File lib/cptools.py

     request = cherrypy.request
     
     if base is None:
-        port = str(cherrypy.config.get('server.socket_port', '80'))
-        if port == "80":
+        port = cherrypy.local.port
+        if port == 80:
             base = 'http://localhost'
         else:
             base = 'http://localhost:%s' % port
             if remote == 'X-Forwarded-For':
                 # See http://bob.pythonmac.org/archives/2005/09/23/apache-x-forwarded-for-caveat/
                 xff = xff.split(',')[-1].strip()
-            request.remote_host = xff
+            request.remote.name = xff
 
 
 def response_headers(headers=None):
 ##            raise StopIteration()
         return data
 
+
+class Host(object):
+    """An internet address.
+    
+    name should be the client's host name. If not available (because no DNS
+        lookup is performed), the IP address should be used instead.
+    """
+    
+    ip = "0.0.0.0"
+    port = 80
+    name = "unknown.tld"
+    
+    def __init__(self, ip, port, name=None):
+        self.ip = ip
+        self.port = port
+        if name is None:
+            name = ip
+        self.name = name

File lib/wsgiapp.py

     environ["PATH_INFO"] = cherrypy.request.path_info
     environ["QUERY_STRING"] = cherrypy.request.query_string
     environ["SERVER_PROTOCOL"] = cherrypy.request.protocol
-    server_name = getattr(cherrypy.server.httpserver, 'server_name', "None")
-    environ["SERVER_NAME"] = server_name 
-    environ["SERVER_PORT"] = cherrypy.config.get('server.socket_port')
-    environ["REMOTE_HOST"] = cherrypy.request.remote_host
-    environ["REMOTE_ADDR"] = cherrypy.request.remote_addr
-    environ["REMOTE_PORT"] = cherrypy.request.remote_port
+    environ["SERVER_NAME"] = cherrypy.request.local.name
+    environ["SERVER_PORT"] = cherrypy.request.local.port
+    environ["REMOTE_HOST"] = cherrypy.request.remote.name
+    environ["REMOTE_ADDR"] = cherrypy.request.remote.ip
+    environ["REMOTE_PORT"] = cherrypy.request.remote.port
     # then all the http headers
     headers = cherrypy.request.headers
     environ["CONTENT_TYPE"] = headers.get("Content-type", "")

File test/benchmark.py

 class NullRequest:
     """A null HTTP request class, returning 204 and an empty body."""
     
-    def __init__(self, remote_addr, remote_port, remote_host, scheme="http"):
+    def __init__(self, local, remote, scheme="http"):
         pass
     
     def close(self):

File test/test_core.py

             hMap['content-length'] = 18
             hMap['server'] = 'CherryPy headertest'
             hMap['location'] = ('%s://127.0.0.1:%s/headers/'
-                                % (cherrypy.request.remote_port,
+                                % (cherrypy.request.remote.port,
                                    cherrypy.request.scheme))
             
             # Set a rare header for fun

File test/test_proxy.py

         index.exposed = True
         
         def remotehost(self):
-            return cherrypy.request.remote_host
+            return cherrypy.request.remote.name
         remotehost.exposed = True
         
         def xhost(self):