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