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