zoukankan      html  css  js  c++  java
  • Tiny HTTP Proxy in Python

    Tiny HTTP Proxy in Python

    Tiny HTTP Proxy in Python

    28 November 2006
    SUZUKI Hisao

    I wrote a tiny HTTP proxy in Python in September, 2001.
    It was for Python 2.1 on
    BeOS R5 originally,
    and has been working well ever since in every version of Python on
    almost every platform, including Mac OS X and Windows 2000/XP.
    I posted it to python-list on 17 June, 2003.
    It had been available publicly as
    http://mail.python.org/pipermail/python-list/2003-June/168957.html.


    Now the page is gone and not found;
    you cannot get the code conveniently.
    So I write this page as its home.


    TinyHTTPProxy-0.2.1.zip


    MD5: f0bcffd54ce8e8fb286c23966d5b1ba6

    To make the code open explicitly,
    I put LICENSE.txt in the zip file.
    It is based on
    http://www.opensource.org/licenses/mit-license.html.
    The text is as follows:


    Copyright (c) 2001 SUZUKI Hisao



    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or
    sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:



    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.



    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

    The code of the proxy is as follows.
    I hope it is short enough to be self-explanatory.
    If your LAN is narrow or unstable, it would be better to increase
    the default value of max_idling in _read_write()
    from 20 to, say, 100.

    The doc-string says that the CONNECT method has not been tested yet;
    however, I can say now it has been tested and works well.

    The first line of the code begins with #!/bin/sh.
    The primary reason is that one of the targets is
    BeOS R5
    where there is no /usr/bin/env.

    #!/bin/sh -
    "exec" "python" "-O" "$0" "$@"
    
    __doc__ = """Tiny HTTP Proxy.
    
    This module implements GET, HEAD, POST, PUT and DELETE methods
    on BaseHTTPServer, and behaves as an HTTP proxy.  The CONNECT
    method is also implemented experimentally, but has not been
    tested yet.
    
    Any help will be greatly appreciated.		SUZUKI Hisao
    """
    
    __version__ = "0.2.1"
    
    import BaseHTTPServer, select, socket, SocketServer, urlparse
    
    class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
        __base = BaseHTTPServer.BaseHTTPRequestHandler
        __base_handle = __base.handle
    
        server_version = "TinyHTTPProxy/" + __version__
        rbufsize = 0                        # self.rfile Be unbuffered
    
        def handle(self):
            (ip, port) =  self.client_address
            if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients:
                self.raw_requestline = self.rfile.readline()
                if self.parse_request(): self.send_error(403)
            else:
                self.__base_handle()
    
        def _connect_to(self, netloc, soc):
            i = netloc.find(':')
            if i >= 0:
                host_port = netloc[:i], int(netloc[i+1:])
            else:
                host_port = netloc, 80
            print "\t" "connect to %s:%d" % host_port
            try: soc.connect(host_port)
            except socket.error, arg:
                try: msg = arg[1]
                except: msg = arg
                self.send_error(404, msg)
                return 0
            return 1
    
        def do_CONNECT(self):
            soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                if self._connect_to(self.path, soc):
                    self.log_request(200)
                    self.wfile.write(self.protocol_version +
                                     " 200 Connection established\r\n")
                    self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
                    self.wfile.write("\r\n")
                    self._read_write(soc, 300)
            finally:
                print "\t" "bye"
                soc.close()
                self.connection.close()
    
        def do_GET(self):
            (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
                self.path, 'http')
            if scm != 'http' or fragment or not netloc:
                self.send_error(400, "bad url %s" % self.path)
                return
            soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                if self._connect_to(netloc, soc):
                    self.log_request()
                    soc.send("%s %s %s\r\n" % (
                        self.command,
                        urlparse.urlunparse(('', '', path, params, query, '')),
                        self.request_version))
                    self.headers['Connection'] = 'close'
                    del self.headers['Proxy-Connection']
                    for key_val in self.headers.items():
                        soc.send("%s: %s\r\n" % key_val)
                    soc.send("\r\n")
                    self._read_write(soc)
            finally:
                print "\t" "bye"
                soc.close()
                self.connection.close()
    
        def _read_write(self, soc, max_idling=20):
            iw = [self.connection, soc]
            ow = []
            count = 0
            while 1:
                count += 1
                (ins, _, exs) = select.select(iw, ow, iw, 3)
                if exs: break
                if ins:
                    for i in ins:
                        if i is soc:
                            out = self.connection
                        else:
                            out = soc
                        data = i.recv(8192)
                        if data:
                            out.send(data)
                            count = 0
                else:
                    print "\t" "idle", count
                if count == max_idling: break
    
        do_HEAD = do_GET
        do_POST = do_GET
        do_PUT  = do_GET
        do_DELETE=do_GET
    
    class ThreadingHTTPServer (SocketServer.ThreadingMixIn,
                               BaseHTTPServer.HTTPServer): pass
    
    if __name__ == '__main__':
        from sys import argv
        if argv[1:] and argv[1] in ('-h', '--help'):
            print argv[0], "[port [allowed_client_name ...]]"
        else:
            if argv[2:]:
                allowed = []
                for name in argv[2:]:
                    client = socket.gethostbyname(name)
                    allowed.append(client)
                    print "Accept: %s (%s)" % (client, name)
                ProxyHandler.allowed_clients = allowed
                del argv[2:]
            else:
                print "Any clients will be served..."
            BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)
  • 相关阅读:
    Android"寻龙点穴"指南针
    如何获取注册地图API的SHA1值与PackageName?
    如何获取注册地图API的SHA1值与PackageName?
    Error:Execution failed for task ':app:transformClassesWithDexForDebug'解决记录
    Error:Execution failed for task ':app:transformClassesWithDexForDebug'解决记录
    LocationManager的使用
    LocationManager的使用
    Android方向传感器
    Android方向传感器
    Android光线传感器
  • 原文地址:https://www.cnblogs.com/lexus/p/2476688.html
Copyright © 2011-2022 走看看