由浅入深写代理(6)-http-代理

日期: 2020-03-18 14:02

本文讲 http 代理,顾名思义,http 代理代理的是 http 请求,其实这里面分两类

普通代理 这种代理扮演的是「中间人」角色,对于连接到它的客户端来说,它是服务端;对于要连接的服务端来说,它是客户端。它就负责在两端之间来回传送 HTTP 报文。隧道代理。它通过 HTTP 协议正文部分(Body)完成通讯,以 HTTP 的方式实现任意基于 TCP 的应用层协议代理。这种代理使用 HTTP 的 CONNECT 方法建立连接。

通俗一点讲,普通代理解析 http 包,然后将请求转发到目标地址,但是没法解析 https 的包,所以也就没法代理 https 的请求,但是隧道代理可以代理 https 的请求或者其他的一些协议请求。

0x01 普通代理

代码很简单

import socket
from urllib.parse import urlparse
from http.server import BaseHTTPRequestHandler, HTTPServer
class ProxyHandler(BaseHTTPRequestHandler):
def _recv_data_from_remote(self, sock):
data = b''
while True:
recv_data = sock.recv(4096)
if not recv_data:
break
data += recv_data
sock.close()
return data
def do_GET(self):
# 解析 GET 请求信息
uri = urlparse(self.path)
scheme, host, path = uri.scheme, uri.hostname, uri.path
host_ip = socket.gethostbyname(host)
port = 443 if scheme == "https" else 80
# 为了简单起见,Connection 都为 close, 也就不需要 Proxy-Connection 判断了
del self.headers['Proxy-Connection']
self.headers['Connection'] = 'close'
# 构造新的 http 请求
send_data = "GET {path} {protocol_version}\r\n".format(path=path, protocol_version=self.protocol_version)
headers = ''
for key, value in self.headers.items():
headers += "{key}: {value}\r\n".format(key=key, value=value)
headers += '\r\n'
send_data += headers
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host_ip, port))
# 发送请求到目标地址
sock.sendall(send_data.encode())
data = self._recv_data_from_remote(sock)
self.wfile.write(data)
def main():
try:
server = HTTPServer(('', 8888), ProxyHandler)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()
if __name__ == '__main__':
main()

这里面就实现了 get 请求的转发,只用单线程的方式来处理,其他的有兴趣的同学可以自己扩展下。

看下效果

python3 http_server.py

由浅入深写代理(6)-http-代理

配置完代理后可以发现 http 的请求都能正常转发,但是 https 的都没法识别。

下篇教程看如何通过隧道代理解决这个问题。

相关新闻