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