Robert Brewer avatar 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.

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(),
     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
         
 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.
     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
     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", "")

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):

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

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):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.