Requests: Capture server IP address as part of a Requests object

Created on 1 Aug 2014  路  13Comments  路  Source: psf/requests

Please provide a way to query the request object for the IP address of the server connected to to fulfill the request.

Example:

r = requests.get("http://www.google.com")
r.ip
'74.125.225.242'

Feature Request

Most helpful comment

@shaky You seem to be using Python 3. That changes the layout of the socket object. You should change your ip = line to ip = r.raw._fp.fp.raw._sock.getpeername().

All 13 comments

Hey @zapman449!

Thanks for your suggestion! We really appreciate the fact that you took the time to file this. Unfortunately we're not adding anything new to the requests API at this time.

I'll wait for @Lukasa to chime in before closing this though.

Correct, we're not adding anything at this time. It's information that urllib3 could potentially expose, however, which would make it available through the Response.raw property.

Hey I researched into this issue.

rsp = requests.get(...)
rsp.raw._fp.fileno() 

this should get the underline socket the connect points to, however for some reason, urllib3 made sure its set to null here

https://github.com/shazow/urllib3/blob/master/urllib3/response.py#L303 (related: http://bugs.python.org/issue16298)

def read(...)
    self._fp.close()

which leads us to CPython httplib code here

https://github.com/python/cpython/blob/2.7/Lib/httplib.py#L561

def close(self):
    fp = self.fp
    if fp:
        self.fp = None
        fp.close()

So, it's gone forever. Bummer

On second thought, I cracked it.

rsp = requests.get('http://google.com', stream=True)
# grab the IP while you can, before you consume the body!!!!!!!!
print rsp.raw._fp.fp._sock.getpeername()
# consume the body, which calls the read(), after that fileno is no longer available.
print rsp.content  

This solution right here simply must be added to the docs, brilliant work @est.

I have tried est's fix using 2.9.1 on Ubuntu 14.04 and I am getting
AttributeError: '_io.BufferedReader' object has no attribute '_sock'

My script is trying to grab the IP before the content read as advised too
r = requests.get(start_url, headers=headers, timeout=7.0, verify=False, stream=True)
ip = r.raw._fp.fp._sock.getpeername()

Hmmm, we could add this as Response.origin, but I'm not convinced that it would be very useful.

@shaky You seem to be using Python 3. That changes the layout of the socket object. You should change your ip = line to ip = r.raw._fp.fp.raw._sock.getpeername().

@Lukasa what are your thoughts/feelings on a Response.origin? Seems like it would be a nice addition to me.

Eh. I'm probably -0 on it: I think the value-add is too small to justify adding to the Response API. I'd be more open to adding it on the urllib3 object and then pushing people to grab it from Response.raw.

As a side note, origin is a _bad_ name for it: origin is a term with a specific meaning in HTTP, and that meaning is not the IP address of the server.

I like the idea of urllib3 exposing it, as that's a lower-level connection detail.

with requests.get("https://httpbin.org", stream=True) as response:
    ip21 = response.raw.connection.sock.getsockname()
    print(ip21)
    # ('192.168.100.104', 58254)

    ip22 = response.raw.connection.sock.getpeername()
    print(ip22)
    # ('52.3.177.149', 443)
with requests.get("https://httpbin.org", stream=True) as rsp:
    ip, port = rsp.raw._connection.sock.getpeername()
    print(ip, port)
Was this page helpful?
0 / 5 - 0 ratings