http proxy

作者: 金刚_30bf | 来源:发表于2018-06-11 09:53 被阅读0次

    有时在内网无法访问外网资源 , 但有些应用如conda pip yum 需要在线更新,本例使用一台有两网卡的机器(同时上内外网)作为代理,为内网提供在线更新服务。 (在内网机器隔离比较严格的场景不推荐使用!)

    使用python做简单的http代理, 支持CONNECT 和GET方法, 支持http 和 https 。

    
    import urllib.parse
    import socket 
    import select 
    from http.server import BaseHTTPRequestHandler, HTTPServer
    from socketserver import ThreadingMixIn
    import sys
    
    class MyHandler(BaseHTTPRequestHandler):
        def do_CONNECT(self):
            
            print('CONNECT:',self.client_address,self.requestline, self.headers)
    
            uri = self.path
            print("url:", uri)
            host,port = urllib.parse.splittype(uri)
    
            address = (host, port or 443)
            
            try:
                targetconn = socket.create_connection(address=address)
            except socket.error:
                self.send_error(504)
                return 
            
            self.send_response(200, 'Connection Established')
            self.send_header('Connection', 'close')
            self.end_headers()
            
            conns = [self.connection, targetconn]
            
            keep_connection = True 
            while(keep_connection):
                keep_connection = False
                rlist, wlist, xlist = select.select(conns, [], conns, self.timeout)
                if (xlist):
                    break
                for r in rlist:
                    other = conns[1] if r is conns[0] else conns[0]
                    data = r.recv(8192)
                    if (data):
                        other.sendall(data)
                        keep_connection = True
            
            targetconn.close()
            print("Connect end!========================",self.client_address)
            
        def do_GET(self):
            print('GET:',self.client_address,self.requestline, self.headers)
            uri = self.path
            print("url:", uri)
            protocol,rest = urllib.parse.splittype(uri)
            print("protocol:", protocol)
            host,rest = urllib.parse.splithost(rest)
            
            print("host:", host) 
            
            path = rest
            
            print("Path:", path)
            
            if (path is None or len(path) == 0):
                path = '/'
            
            host,port = urllib.parse.splitnport(host)
            
            print("host:", host)
            port = 80 if port < 0 else port
            
            host_ip = socket.gethostbyname(host)
            
            print(host_ip, port)
            
            # print("headers:", self.headers)
            
            send_data = 'GET ' + path + ' ' + self.protocol_version + '\r\n' 
            
            head = ''
            for key, val in self.headers.items():
                head = head + "%s: %s\r\n" % (key,val)
            send_data = send_data + head + '\r\n' 
            
            print("send_data:" , send_data) 
            
            client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            client.connect((host_ip,port))
            client.send(send_data.encode('utf-8'))
            
            data = bytes()
            
            while True:
                tmp = client.recv(8192)
                if not tmp:
                    break
                data = data + tmp
                
            client.close()
            # print("resData:", data)
            print("resData len:", len(data))
            self.wfile.write(data)
            
            print('GET end ! =====================',self.client_address)
    
    class MyHttpServer(ThreadingMixIn, HTTPServer):
        pass
    
    
    def main(ip, port):
        try:
            server = MyHttpServer((ip, port), MyHandler)
            print('Welcome to the machine...')
            server.serve_forever()
        except KeyboardInterrupt:
            print('^C received, shutting down server')
            server.socket.close()
    
    if __name__ == '__main__':
        # main()
        
        if (len(sys.argv) == 3):
            for arg in sys.argv:
                print(arg)
        else:
            print("Error, arguments less!")
            print("Usage: python httpProxy.py ip  port ")
            sys.exit()
        
        ip = sys.argv[1]
        port = int(sys.argv[2])
        
        print("Starting proxy at ", ip, port )
        main(ip,port)
    

    https CONNECT

    CONNECT 用于建立通道,后续将使用建立的通道进行通信 。
    在收到CONNECT请求时 , 回复客户端 200 , ‘Connection Established’ 。
    然后与目标服务器建立连接,CONNECT头中有host和端口(即目标服务器的主机和端口)。
    监控与客户端和目标服务器的连接socket ,当有读事件时, 读取之然后发送出去;
    客户端--》 proxy --》 目标服务器;
    目标服务器 --》 proxy --》 客户端 ;

    select 的使用

    select.select(读列表, 写列表, 执行列表, timeout)

    循环处理准备好的读写执行列表, 执行相应操作。

    相关文章

      网友评论

        本文标题:http proxy

        本文链接:https://www.haomeiwen.com/subject/sneceftx.html