欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一个python写的简易的http代理服务器

程序员文章站 2022-04-08 21:39:34
...

一个python写的简易的http代理服务器

该代码以学习为主,运行后会在本地1080端口监听数据。
只实现了http的数据转发,还未实现https的数据处理。

import socket
import re

PROXY_PORT = 1080
bufsize = 65536


class Server:
    def __init__(self, sock=None):
        self.socket = sock

    def recv_all_data(self, from_client=False):
        """
        :param from_client:
            当接收客户端请求的时候,如果是post,就会有Content-Length,防止过长
            如果是get的话,结尾就是\r\n\r\n
        :return:
        """
        sock = self.socket
        data = sock.recv(bufsize)
        if b'Content-Length' in data:  # 数据没压缩的时候,以Content-Length判断数据是否传输结束
            length = re.search(r'Content-Length: (\d+)', data.decode(encoding='utf8')).group(1)
            head_length = len(data.split(b'\r\n\r\n')[0]) + 4
            total = int(length) + head_length  # 响应头+内容长度 = 总长度
            while len(data) != total:
                data += sock.recv(bufsize)
        else:  # 数据压缩传输的时候,以b'\r\n0\r\n\r\n'判断是否传输结束 或者 from_client=Ture 方法是get的时候
            condition = b'\r\n\r\n' if from_client else b'\r\n0\r\n\r\n'
            while data[-len(condition):] != condition:
                data += sock.recv(bufsize)
        return data

    @staticmethod
    def get_host_port(data: bytes):
        data = data.decode(encoding='utf8')
        if 'http://' in data:
            host = data.split('\r\n')[1].split()[1]
            port = 80
        else:
            host = re.search(r'\s([^\s]+):443', data).group(1)
            port = 443

        return host, port

    @classmethod
    def get_web_data(cls, addr, _send_data):
        sender = socket.socket()
        sender.connect(addr)
        sender.sendall(_send_data)
        result = cls(sender).recv_all_data()
        sender.close()
        return result


if __name__ == '__main__':
    server = socket.socket()
    server.bind(('0.0.0.0', PROXY_PORT))
    server.listen(1024)
    while True:
        origin_conn, origin_addr = server.accept()
        send_data = Server(origin_conn).recv_all_data(from_client=True)
        target_addr = Server.get_host_port(send_data)
        result_data = Server.get_web_data(target_addr, send_data)
        origin_conn.sendall(result_data)
        origin_conn.close()
    server.close()
    print('end')