-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added HTTP Adaptor with random DNS resolution
- Loading branch information
Showing
5 changed files
with
113 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
release_version = "0.0.17" | ||
release_version = "0.0.18" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import copy | ||
import random | ||
import socket | ||
import requests | ||
from requests.adapters import HTTPAdapter | ||
from requests.packages.urllib3.util.connection import allowed_gai_family | ||
try: | ||
from urllib.parse import urlparse | ||
except ImportError: | ||
from urlparse import urlparse | ||
|
||
from .thread_utils import MapWithLockAndTimeout | ||
|
||
|
||
# DNS cache | ||
dnsMap = MapWithLockAndTimeout() | ||
|
||
|
||
# HTTP adaptor with randomized DNS resolution | ||
class HTTPAdapterWithRandomDnsResolver (HTTPAdapter): | ||
|
||
# override to get connection to random host | ||
def get_connection(self, url, proxies=None): | ||
# parse URL | ||
parsed = urlparse(url) | ||
host = parsed.hostname | ||
port = parsed.port | ||
if port is None: | ||
if parsed.scheme == 'http': | ||
port = 80 | ||
else: | ||
port = 443 | ||
# check record | ||
if parsed.hostname in dnsMap: | ||
dnsRecord = dnsMap[parsed.hostname] | ||
else: | ||
family = allowed_gai_family() | ||
dnsRecord = socket.getaddrinfo(host, port, family, socket.SOCK_STREAM) | ||
dnsMap[parsed.hostname] = dnsRecord | ||
dnsRecord = copy.copy(dnsRecord) | ||
random.shuffle(dnsRecord) | ||
# loop over all hosts | ||
err = None | ||
for af, sock_type, proto, canon_name, sa in dnsRecord: | ||
if af == socket.AF_INET6: | ||
addr = '[' + sa[0] + ']' | ||
else: | ||
addr = sa[0] | ||
if parsed.port is not None: | ||
addr += ':{0}'.format(parsed.port) | ||
tmp_url = parsed._replace(netloc=addr).geturl() | ||
try: | ||
con = HTTPAdapter.get_connection(self, tmp_url, proxies=proxies) | ||
# return if valid | ||
if con is not None: | ||
return con | ||
except Exception as e: | ||
err = e | ||
if err is not None: | ||
raise err | ||
return None | ||
|
||
|
||
# utility function to get HTTPAdapterWithRandomDnsResolver | ||
def get_http_adapter_with_random_dns_resolution(): | ||
session = requests.Session() | ||
adapter = HTTPAdapterWithRandomDnsResolver(max_retries=0) | ||
session.mount('http://', adapter) | ||
session.mount('https://', adapter) | ||
return session |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters