Obtaining Client IP address from a WSGI app using Eventlet
Question: I'm currently writing a basic dispatch model server based on the Python
Eventlet library (http://eventlet.net/doc/). Having looked at the WSGI docs on
Eventlet (http://eventlet.net/doc/modules/wsgi.html), I can see that the
eventlet.wsgi.server function logs the x-forwarded-for header in addition to
the client IP address.

However, the way to obtain this is to attach a file-like object (the default
which is sys.stderr) and then have the server pipe that to that object.

I would like to be able to obtain the client IP from within the application
itself (i.e. the function that has start_response and environ as parameters).
Indeed, an environ key would be perfect for this. Is there a way to obtain the
IP address simply (i.e. through the environ dictionary or similar), without
having to resort to redirecting the log object somehow?


Answer: What you want is in the wsgi
[environ](http://www.python.org/dev/peps/pep-0333/#environ-variables),
specifically `environ['REMOTE_ADDR']`.

However, if there is a proxy involved, then `REMOTE_ADDR` will be the address
of the proxy, and the client address will be included (most likely) in
`HTTP_X_FORWARDED_FOR`.

Here's a function that should do what you want, for most cases (all credit to
[Sævar](http://stackoverflow.com/questions/4581789/how-do-i-get-user-ip-
address-in-django/5976065#5976065)):

    
    
    def get_client_address(environ):
        try:
            return environ['HTTP_X_FORWARDED_FOR'].split(',')[-1].strip()
        except KeyError:
            return environ['REMOTE_ADDR']
    

* * *

You can easily see what is included in the wsgi environ by writing a simple
wsgi app and pointing a browser at it, for example:

    
    
    from eventlet import wsgi
    import eventlet
    
    from pprint import pformat
    
    def show_env(env, start_response):
        start_response('200 OK', [('Content-Type', 'text/plain')])
        return ['%s\r\n' % pformat(env)]
    
    wsgi.server(eventlet.listen(('', 8090)), show_env)
    

* * *

And combining the two ...

    
    
    from eventlet import wsgi
    import eventlet
    
    from pprint import pformat
    
    def get_client_address(environ):
        try:
            return environ['HTTP_X_FORWARDED_FOR'].split(',')[-1].strip()
        except KeyError:
            return environ['REMOTE_ADDR']
    
    def show_env(env, start_response):
        start_response('200 OK', [('Content-Type', 'text/plain')])
        return ['%s\r\n\r\nClient Address: %s\r\n' % (pformat(env), get_client_address(env))]
    
    wsgi.server(eventlet.listen(('', 8090)), show_env)
    

