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