• 写了一个Web Gateway做Proxy


    写了一个Web Gateway做Proxy « Xiaoxia[PG]

    写了一个Web Gateway做Proxy

    因为EMSVPS的服务器实在有太多的问题,故现在改回比较稳定的burst.net机器。现在Paypal支持Unionpay的卡,5.95USD/mo大概人民币38元。burst.net的机器提供512M内存和2个IP地址,内存充足的时候跑起Wordpress的确轻松很多了。现在一个IP用作博客服务,另外一个IP用作提供一些Web服务。

    因为不同的Web服务都需要监听一个服务端口,为了能让他们共用一个IP上的80端口,需要一个代理分发请求的程序。例如
    访问http://lab.xiaoxia.org/server/*的请求分发到localhost:10000的服务,
    访问http://lab.xiaoxia.org/whois/*的请求分发到localhost:10001的服务,
    而访问http://lab.xiaoxia.org/*的请求,直接获取www目录下的资源文件,例如index.html。

    因为使用的都是同一个域名,不同的只是路径,要根据不同的路径选择不同的服务端口,我使用了正则表达式来解决这个问题。

    效果见 http://lab.xiaoxia.org/

    我现在的分发规则如下:

    # Host            Request Path           Handle Method   Forward Host or Root    Forward Path
    lab.xiaoxia.org   /server/(.*)           proxy           localhost:10000         /$1
    lab.xiaoxia.org   /mail/(.*).action      proxy           localhost:10005         /$1.action
    lab.xiaoxia.org   /mail/(.*)             resource        /var/mail               /mail/$1
    lab.xiaoxia.org   /hashlib/(.*).action   proxy           localhost:10002         /
    lab.xiaoxia.org   /whois/request/(.*)    proxy           localhost:10003         /$1
    lab.xiaoxia.org   /iplookup/request/(.*) proxy           localhost:10004         /$1
    lab.xiaoxia.org   /(.*)                  resource        www                     /$1
    

    今晚写的WebGateway.py的代码如下。可以优化效率的地方很多,但对目前来说,已经足够。本来写了一个epoll版本的,但是代码太复杂太多了,就抛弃了,不利于阅读和维护。对于Python代码来说,应该坚持KISS (Keep It Simple & Stupid) 原则。

    规则文件可以经常修改,而不需要重启WebGateway。

    1. #!/usr/bin/python  
    2.   
    3. from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer  
    4. from httplib import HTTPResponse  
    5. from SocketServer import ThreadingMixIn  
    6. import socket, threading  
    7. import posixpath, shutil, mimetypes, urlparse  
    8. import time, sys, re, traceback, os  
    9.   
    10. threading.stack_size(128*1024)  
    11.   
    12. ConnectionTimeout = 30.0  
    13. ServiceConfigFile = "services.list"  
    14.   
    15. class Handler(BaseHTTPRequestHandler):  
    16.     def proxy(self, proxy_host, proxy_port, url):  
    17.         try:  
    18.             self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
    19.             self.s.settimeout(ConnectionTimeout)  
    20.             self.s.connect((proxy_host, proxy_port))  
    21.             header = " ".join((self.command, url, "HTTP/1.1")) + "\r\n"  
    22.             header += str(self.headers) + "\r\n"  
    23.             self.s.send(header)  
    24.             # Send Post data  
    25.             if(self.command=='POST'):  
    26.                 self.s.send(self.rfile.read(int(self.headers['Content-Length'])))  
    27.             response = HTTPResponse(self.s, method=self.command)  
    28.             response.begin()  
    29.   
    30.             # Reply to the browser  
    31.             status = "HTTP/1.1 " + str(response.status) + " " + response.reason  
    32.             header = status + '\r\n'  
    33.             for hh, vv in response.getheaders():  
    34.                 if hh.upper()!='TRANSFER-ENCODING':  
    35.                     header += hh + ': ' + vv + '\r\n'  
    36.             self.wfile.write(header + '\r\n')  
    37.             while True:  
    38.                 response_data = response.read(8192)  
    39.                 if not response_data: break  
    40.                 self.wfile.write(response_data)  
    41.             self.s.close()  
    42.         except:  
    43.             print('error in ' + self.requestline + '\n' + traceback.format_exc())  
    44.   
    45.     def getResource(self, www_root, path):  
    46.         path = path.split("?")[0].split("#")[0]  
    47.         path = posixpath.normpath(path).strip("/")  
    48.         fullpath = os.path.join(www_root, path)  
    49.         # Default page  
    50.         if os.path.isdir(fullpath):  
    51.             fullpath = os.path.join(fullpath, "index.html")  
    52.         mtype = mimetypes.guess_type(fullpath)[0]  
    53.         if mtype is None: mtype = "text/plain"  
    54.         if os.path.isfile(fullpath):  
    55.             f = open(fullpath, "rb")  
    56.             self.send_response(200)  
    57.             self.send_header("Content-Type", mtype + "; charset=\"utf-8\"")  
    58.             fs = os.fstat(f.fileno())  
    59.             self.send_header("Content-Length", str(fs[6]))  
    60.             self.send_header("Last-Modified"self.date_time_string(fs.st_mtime))  
    61.             self.end_headers()  
    62.             shutil.copyfileobj(f, self.wfile)  
    63.         else:  
    64.             self.send_error(404"File not found %s" % path)  
    65.   
    66.     def getService(self):  
    67.         hostname = self.headers["host"].split(":")[0].lower()  
    68.         self.headers["X-Forwarded-For"] = self.connection.getpeername()[0]  
    69.         for line in file(ServiceConfigFile).readlines():  
    70.             var = line.split()  
    71.             if var[0].lower() == hostname:  
    72.                 r = re.match(var[1], self.path)  
    73.                 if r:  
    74.                     i = 1  
    75.                     for k in r.groups():  
    76.                         var[4] = var[4].replace("$" + str(i), k)  
    77.                         i += 1  
    78.                     if var[2] == "proxy":  
    79.                         ip, port = var[3].split(":")  
    80.                         self.proxy(ip, 80 if port == "" else int(port), var[4])  
    81.                     elif var[2] == "resource":  
    82.                         self.getResource(var[3], var[4])  
    83.                     else:  
    84.                         self.send_error(500"Unknown method")  
    85.                     return  
    86.         self.send_error(400"Bad Request")  
    87.   
    88.     do_POST = getService  
    89.     do_GET = getService  
    90.   
    91. class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): pass  
    92.   
    93. try:  
    94.     server = ThreadingHTTPServer(("", 8000), Handler)  
    95.     server.serve_forever()  
    96. except KeyboardInterrupt:  
    97.     exit()  
  • 相关阅读:
    DataTable常用操作总结[转帖]
    Jquery实现淡入淡出效果
    在自定义Server Control中捆绑JS文件 [转帖]
    ASP.NET利用String.Join以分隔符號來串連集合資料 [转帖]
    fork()的一些测试
    大端小端表示法 && GAS对过程的实现
    GAS中流程控制的实现,for, while, if, switch
    一个看起来奇怪的C++程序 && c++操作符重载
    修改函数的返回地址
    stl algorithm sort ,unique
  • 原文地址:https://www.cnblogs.com/lexus/p/2379102.html
Copyright © 2020-2023  润新知