#coding:utf-8
import BaseHTTPServer
import select
import socket
import SocketServer
import urlparse
import httplib
import StringIO
import sys
import os
# 多线程HTTPServer
class ThreadingHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): 
    pass

class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    __base = BaseHTTPServer.BaseHTTPRequestHandler
    __base_handle = __base.handle
    server_version = "HTTPProxy"
    # handle() is be calling in a new thread when a client is connected.
    def handle(self): 
        print 'handle()'
        self.__base_handle()
        return 

    def do_CONNECT(self):
        print 'do_CONNECT()'
        # HTTP Protocol CONNECT command
        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")
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        host, port = self.path.split(':')
        port = int(port)
        s.connect((host, port))
        self.turn_to(s, 900)
        s.close()
        self.connection.close()
        print 'a client is disconnected'

    # the most process in do_GET function
    def do_GET(self):
        print 'do_GET()'
        #netloc is a url like 'www.codepongo.com:80'
        (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http')
        print urlparse.urlparse(self.path, 'http')
        print self.headers.get('Host', "")
        if not netloc:
            netloc = self.headers.get('Host', "")
        if scheme != 'http' or not netloc or fragment:
            self.send_error(400, "bad url %s" % self.path)
            return
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        if -1 != netloc.find(':'):
            host, port = netloc.split(':')
            port = int(port)
        else:
            host = netloc
            port = 80
        print host, port
        s.connect((host, port))
        self.log_request()
        # send HTTP Request HEADER
        s.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():
            s.send("%s: %s\r\n" % key_val)
        s.send("\r\n")
        self.turn_to(s)
        s.close()
        self.connection.close()    
        print 'a client is disconnected'

    do_HEAD = do_GET
    do_POST = do_GET
    do_PUT  = do_GET
    do_DELETE=do_GET

    def turn_to(self, s, timeout = 60):
        #  client <-self.connection-> proxy <-s-> server
        # s 客户端与代理服务器的连接
        # self.connection 代理服务器与外部服务器之间的连接
        iw = [self.connection, s]
        ow = []
        time = 0
        while time < timeout:
            time += 1
            (ins, _, exs) = select.select(iw, ow, iw, 1)
            if exs: #exception
                for e in exs:
                    print "%s is exception" % (s.getpeername())
                break
            elif ins: #input readable
                for i in ins:
                    if i is s:
                        o = self.connection
                    elif i is self.connection:
                        o = s
                    else:
                        pass
                    data = i.recv(8192)
                    if data:                        
                        print 'recv length is', len(data)
                        o.send(data)
                        time = 0
                    else:
                        pass
            else: # output readable
                pass

def serving(port = 8000, protocol="HTTP/1.0", debug = False):
    host_port = ('', port)
    ThreadingHTTPServer.protocol_version = protocol
    httpd = ThreadingHTTPServer(host_port, ProxyHandler)
    print httpd.socket.getsockname()
    if not debug:
        buff = StringIO.StringIO()
        sys.stdout = buff
        sys.stderr = buff
    httpd.serve_forever()

if __name__ == '__main__':
    serving(port=8001, debug=True)