Coverage for jutil/request.py : 51%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import logging
2from typing import Tuple, Union
3from django.conf import settings
4import requests
5import socket
6from django.http.request import HttpRequest
7from ipware import get_client_ip # type: ignore
8from rest_framework.request import Request
11logger = logging.getLogger(__name__)
14def get_ip(request: Union[HttpRequest, Request]) -> str:
15 """
16 Returns best-guess IP for given request.
17 Uses ipware library get_client_ip.
18 If you need to know is IP routable or not, use ipware get_client_ip directly.
19 See ipware documentation for more info.
21 Note: Why such a simple function wrapper? I'm generally against wrappers like this,
22 but in this case made an exceptions: I used to use ipware get_real_ip() everywhere before
23 it was deprecated and had quite big update process to change all code to use ipware get_client_ip.
24 I want to avoid such process again so added this wrapper.
26 :param request: Djangos HttpRequest or DRF Request
27 :return: IP-address or None
28 """
29 return get_client_ip(request)[0]
32def get_geo_ip(ip: str, exceptions: bool = False, timeout: int = 10) -> dict:
33 """
34 Returns geo IP info or empty dict if geoip query fails at http://ipstack.com.
35 requires settings.IPSTACK_TOKEN set as valid access token to the API.
37 Example replies:
39 {'country_name': 'United States', 'country_code': 'US', 'region_code': 'TX', 'region_name': 'Texas',
40 'ip': '76.184.236.184', 'latitude': 33.1507, 'time_zone': 'America/Chicago', 'metro_code': 623, 'city':
41 'Frisco', 'longitude': -96.8236, 'zip_code': '75033'}
43 {'latitude': 60.1641, 'country_name': 'Finland', 'zip_code': '02920', 'region_name': 'Uusimaa', 'city':
44 'Espoo', 'metro_code': 0, 'ip': '194.100.27.41', 'time_zone': 'Europe/Helsinki', 'country_code': 'FI',
45 'longitude': 24.7136, 'region_code': '18'}
47 :param ip: str
48 :param exceptions: if True raises Exception on failure
49 :param timeout: timeout in seconds
50 :return: dict
51 """
52 try:
53 res = requests.get(
54 "http://api.ipstack.com/{}?access_key={}&format=1".format(ip, settings.IPSTACK_TOKEN), timeout=timeout
55 )
56 if res.status_code != 200: 56 ↛ 57line 56 didn't jump to line 57, because the condition on line 56 was never true
57 if exceptions:
58 raise Exception("api.ipstack.com HTTP {}".format(res.status_code))
59 return {}
60 return res.json()
61 except Exception as e:
62 msg = "geoip({}) failed: {}".format(ip, e)
63 logger.error(msg)
64 if exceptions:
65 raise
66 return {}
69def get_ip_info(ip: str, exceptions: bool = False, timeout: int = 10) -> Tuple[str, str, str]:
70 """
71 Returns (ip, country_code, host) tuple of the IP address.
72 :param ip: IP address
73 :param exceptions: Raise Exception or not
74 :param timeout: Timeout in seconds. Note that timeout only affects geo IP part, not getting host name.
75 :return: (ip, country_code, host)
76 """
77 if not ip: # localhost 77 ↛ 78line 77 didn't jump to line 78, because the condition on line 77 was never true
78 return "", "", ""
79 host = ""
80 country_code = get_geo_ip(ip, exceptions=exceptions, timeout=timeout).get("country_code", "")
81 try:
82 res = socket.gethostbyaddr(ip)
83 host = res[0][:255] if ip else ""
84 except Exception as e:
85 msg = "socket.gethostbyaddr({}) failed: {}".format(ip, e)
86 logger.error(msg)
87 if exceptions:
88 raise e
89 return ip, country_code, host