-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttpsocket.py
More file actions
76 lines (67 loc) · 2.73 KB
/
Copy pathhttpsocket.py
File metadata and controls
76 lines (67 loc) · 2.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import socket
import ssl
from http.client import HTTPResponse, RemoteDisconnected
from io import BytesIO
class HTTPSocket:
def __init__(self):
self.parser = HTTPResponseParser()
def connect(self, domain, ip, tls=False, timeout=2):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.settimeout(timeout)
self.domain = domain
self.ip = ip
self.tls = tls
if(tls):
context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_NONE # disable cert. validation
context.check_hostname = False # disable host name checking
self.socket = context.wrap_socket(self.socket, server_hostname=domain, do_handshake_on_connect=False)
self.socket.connect((ip, 443))
else:
self.socket.connect((ip, 80))
def send(self, data, max_response_size=4096):
self.socket.send(data)
response_bytes = self.recv(max_response_size)
# If a redirect message is received, convert the socket to TLS and retry
if(self.parser.parsed_response and
(self.parser.parsed_response.status >= 300 and self.parser.parsed_response.status <= 308) and
self.parser.parsed_response.getheader("Location") and
self.parser.parsed_response.getheader("Location").startswith("https")):
self.connect(self.domain, self.ip, tls=True)
self.socket.send(data)
response_bytes = self.recv(max_response_size)
if(response_bytes):
try:
result = response_bytes.decode("utf-8")
except UnicodeDecodeError:
result = str(response_bytes)
else:
result = None
return result
def recv(self, max_response_size):
response_bytes = None
try:
response_bytes = self.socket.recv(max_response_size)
except socket.timeout:
response_bytes = None
self.parser.parse(response_bytes)
return response_bytes
def close(self):
try:
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
except socket.error:
pass
# Fake socket used to parse raw HTTP response packets
# Taken from answer here: https://stackoverflow.com/questions/24728088/python-parse-http-response-string
class HTTPResponseParser:
def parse(self, response_bytes):
self.response_bytes = response_bytes
self._file = BytesIO(response_bytes)
self.parsed_response = HTTPResponse(self)
try:
self.parsed_response.begin()
except RemoteDisconnected:
self.parsed_response = None
def makefile(self, *args, **kwargs):
return self._file