##// END OF EJS Templates
py3: re-implement the BaseHTTPServer.test() function...
Pulkit Goyal -
r29565:143d21a7 default
parent child Browse files
Show More
@@ -1,161 +1,184 b''
1 1 #!/usr/bin/env python
2 2
3 3 from __future__ import absolute_import, print_function
4 4
5 5 __doc__ = """Tiny HTTP Proxy.
6 6
7 7 This module implements GET, HEAD, POST, PUT and DELETE methods
8 8 on BaseHTTPServer, and behaves as an HTTP proxy. The CONNECT
9 9 method is also implemented experimentally, but has not been
10 10 tested yet.
11 11
12 12 Any help will be greatly appreciated. SUZUKI Hisao
13 13 """
14 14
15 15 __version__ = "0.2.1"
16 16
17 17 import BaseHTTPServer
18 import optparse
18 19 import os
19 20 import select
20 21 import socket
21 22 import sys
22 23
23 24 from mercurial import util
24 25
25 26 urlparse = util.urlparse
26 27 socketserver = util.socketserver
27 28
28 29 class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
29 30 __base = BaseHTTPServer.BaseHTTPRequestHandler
30 31 __base_handle = __base.handle
31 32
32 33 server_version = "TinyHTTPProxy/" + __version__
33 34 rbufsize = 0 # self.rfile Be unbuffered
34 35
35 36 def handle(self):
36 37 (ip, port) = self.client_address
37 38 allowed = getattr(self, 'allowed_clients', None)
38 39 if allowed is not None and ip not in allowed:
39 40 self.raw_requestline = self.rfile.readline()
40 41 if self.parse_request():
41 42 self.send_error(403)
42 43 else:
43 44 self.__base_handle()
44 45
45 46 def log_request(self, code='-', size='-'):
46 47 xheaders = [h for h in self.headers.items() if h[0].startswith('x-')]
47 48 self.log_message('"%s" %s %s%s',
48 49 self.requestline, str(code), str(size),
49 50 ''.join([' %s:%s' % h for h in sorted(xheaders)]))
50 51
51 52 def _connect_to(self, netloc, soc):
52 53 i = netloc.find(':')
53 54 if i >= 0:
54 55 host_port = netloc[:i], int(netloc[i + 1:])
55 56 else:
56 57 host_port = netloc, 80
57 58 print("\t" "connect to %s:%d" % host_port)
58 59 try: soc.connect(host_port)
59 60 except socket.error as arg:
60 61 try: msg = arg[1]
61 62 except (IndexError, TypeError): msg = arg
62 63 self.send_error(404, msg)
63 64 return 0
64 65 return 1
65 66
66 67 def do_CONNECT(self):
67 68 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
68 69 try:
69 70 if self._connect_to(self.path, soc):
70 71 self.log_request(200)
71 72 self.wfile.write(self.protocol_version +
72 73 " 200 Connection established\r\n")
73 74 self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
74 75 self.wfile.write("\r\n")
75 76 self._read_write(soc, 300)
76 77 finally:
77 78 print("\t" "bye")
78 79 soc.close()
79 80 self.connection.close()
80 81
81 82 def do_GET(self):
82 83 (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
83 84 self.path, 'http')
84 85 if scm != 'http' or fragment or not netloc:
85 86 self.send_error(400, "bad url %s" % self.path)
86 87 return
87 88 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
88 89 try:
89 90 if self._connect_to(netloc, soc):
90 91 self.log_request()
91 92 soc.send("%s %s %s\r\n" % (
92 93 self.command,
93 94 urlparse.urlunparse(('', '', path, params, query, '')),
94 95 self.request_version))
95 96 self.headers['Connection'] = 'close'
96 97 del self.headers['Proxy-Connection']
97 98 for key_val in self.headers.items():
98 99 soc.send("%s: %s\r\n" % key_val)
99 100 soc.send("\r\n")
100 101 self._read_write(soc)
101 102 finally:
102 103 print("\t" "bye")
103 104 soc.close()
104 105 self.connection.close()
105 106
106 107 def _read_write(self, soc, max_idling=20):
107 108 iw = [self.connection, soc]
108 109 ow = []
109 110 count = 0
110 111 while True:
111 112 count += 1
112 113 (ins, _, exs) = select.select(iw, ow, iw, 3)
113 114 if exs:
114 115 break
115 116 if ins:
116 117 for i in ins:
117 118 if i is soc:
118 119 out = self.connection
119 120 else:
120 121 out = soc
121 122 try:
122 123 data = i.recv(8192)
123 124 except socket.error:
124 125 break
125 126 if data:
126 127 out.send(data)
127 128 count = 0
128 129 else:
129 130 print("\t" "idle", count)
130 131 if count == max_idling:
131 132 break
132 133
133 134 do_HEAD = do_GET
134 135 do_POST = do_GET
135 136 do_PUT = do_GET
136 137 do_DELETE = do_GET
137 138
138 139 class ThreadingHTTPServer (socketserver.ThreadingMixIn,
139 140 BaseHTTPServer.HTTPServer):
140 141 def __init__(self, *args, **kwargs):
141 142 BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
142 143 a = open("proxy.pid", "w")
143 144 a.write(str(os.getpid()) + "\n")
144 145 a.close()
145 146
147 def runserver(port=8000, bind=""):
148 server_address = (bind, port)
149 ProxyHandler.protocol_version = "HTTP/1.0"
150 httpd = ThreadingHTTPServer(server_address, ProxyHandler)
151 sa = httpd.socket.getsockname()
152 print("Serving HTTP on", sa[0], "port", sa[1], "...")
153 try:
154 httpd.serve_forever()
155 except KeyboardInterrupt:
156 print("\nKeyboard interrupt received, exiting.")
157 httpd.server_close()
158 sys.exit(0)
159
146 160 if __name__ == '__main__':
147 161 argv = sys.argv
148 162 if argv[1:] and argv[1] in ('-h', '--help'):
149 163 print(argv[0], "[port [allowed_client_name ...]]")
150 164 else:
151 165 if argv[2:]:
152 166 allowed = []
153 167 for name in argv[2:]:
154 168 client = socket.gethostbyname(name)
155 169 allowed.append(client)
156 170 print("Accept: %s (%s)" % (client, name))
157 171 ProxyHandler.allowed_clients = allowed
158 172 del argv[2:]
159 173 else:
160 174 print("Any clients will be served...")
161 BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)
175
176 parser = optparse.OptionParser()
177 parser.add_option('-b', '--bind', metavar='ADDRESS',
178 help='Specify alternate bind address '
179 '[default: all interfaces]', default='')
180 (options, args) = parser.parse_args()
181 port = 8000
182 if len(args) == 1:
183 port = int(args[0])
184 runserver(port, options.bind)
General Comments 0
You need to be logged in to leave comments. Login now