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