Mercurial > hg
comparison tests/tinyproxy.py @ 2337:3f24bc5dee81
http: fix many problems with url parsing and auth. added proxy test.
problems fixed:
- https scheme handled properly for real and proxy urls.
- url of form "http://user:password@host:port/path" now ok.
- no-proxy check uses proper host names.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Mon, 22 May 2006 15:42:49 -0700 |
parents | |
children | 08a0f04b56bd |
comparison
equal
deleted
inserted
replaced
2336:f77edcffb837 | 2337:3f24bc5dee81 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 __doc__ = """Tiny HTTP Proxy. | |
4 | |
5 This module implements GET, HEAD, POST, PUT and DELETE methods | |
6 on BaseHTTPServer, and behaves as an HTTP proxy. The CONNECT | |
7 method is also implemented experimentally, but has not been | |
8 tested yet. | |
9 | |
10 Any help will be greatly appreciated. SUZUKI Hisao | |
11 """ | |
12 | |
13 __version__ = "0.2.1" | |
14 | |
15 import BaseHTTPServer, select, socket, SocketServer, urlparse | |
16 | |
17 class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler): | |
18 __base = BaseHTTPServer.BaseHTTPRequestHandler | |
19 __base_handle = __base.handle | |
20 | |
21 server_version = "TinyHTTPProxy/" + __version__ | |
22 rbufsize = 0 # self.rfile Be unbuffered | |
23 | |
24 def handle(self): | |
25 (ip, port) = self.client_address | |
26 if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients: | |
27 self.raw_requestline = self.rfile.readline() | |
28 if self.parse_request(): self.send_error(403) | |
29 else: | |
30 self.__base_handle() | |
31 | |
32 def _connect_to(self, netloc, soc): | |
33 i = netloc.find(':') | |
34 if i >= 0: | |
35 host_port = netloc[:i], int(netloc[i+1:]) | |
36 else: | |
37 host_port = netloc, 80 | |
38 print "\t" "connect to %s:%d" % host_port | |
39 try: soc.connect(host_port) | |
40 except socket.error, arg: | |
41 try: msg = arg[1] | |
42 except: msg = arg | |
43 self.send_error(404, msg) | |
44 return 0 | |
45 return 1 | |
46 | |
47 def do_CONNECT(self): | |
48 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
49 try: | |
50 if self._connect_to(self.path, soc): | |
51 self.log_request(200) | |
52 self.wfile.write(self.protocol_version + | |
53 " 200 Connection established\r\n") | |
54 self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) | |
55 self.wfile.write("\r\n") | |
56 self._read_write(soc, 300) | |
57 finally: | |
58 print "\t" "bye" | |
59 soc.close() | |
60 self.connection.close() | |
61 | |
62 def do_GET(self): | |
63 (scm, netloc, path, params, query, fragment) = urlparse.urlparse( | |
64 self.path, 'http') | |
65 if scm != 'http' or fragment or not netloc: | |
66 self.send_error(400, "bad url %s" % self.path) | |
67 return | |
68 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
69 try: | |
70 if self._connect_to(netloc, soc): | |
71 self.log_request() | |
72 soc.send("%s %s %s\r\n" % ( | |
73 self.command, | |
74 urlparse.urlunparse(('', '', path, params, query, '')), | |
75 self.request_version)) | |
76 self.headers['Connection'] = 'close' | |
77 del self.headers['Proxy-Connection'] | |
78 for key_val in self.headers.items(): | |
79 soc.send("%s: %s\r\n" % key_val) | |
80 soc.send("\r\n") | |
81 self._read_write(soc) | |
82 finally: | |
83 print "\t" "bye" | |
84 soc.close() | |
85 self.connection.close() | |
86 | |
87 def _read_write(self, soc, max_idling=20): | |
88 iw = [self.connection, soc] | |
89 ow = [] | |
90 count = 0 | |
91 while 1: | |
92 count += 1 | |
93 (ins, _, exs) = select.select(iw, ow, iw, 3) | |
94 if exs: break | |
95 if ins: | |
96 for i in ins: | |
97 if i is soc: | |
98 out = self.connection | |
99 else: | |
100 out = soc | |
101 data = i.recv(8192) | |
102 if data: | |
103 out.send(data) | |
104 count = 0 | |
105 else: | |
106 print "\t" "idle", count | |
107 if count == max_idling: break | |
108 | |
109 do_HEAD = do_GET | |
110 do_POST = do_GET | |
111 do_PUT = do_GET | |
112 do_DELETE=do_GET | |
113 | |
114 class ThreadingHTTPServer (SocketServer.ThreadingMixIn, | |
115 BaseHTTPServer.HTTPServer): pass | |
116 | |
117 if __name__ == '__main__': | |
118 from sys import argv | |
119 if argv[1:] and argv[1] in ('-h', '--help'): | |
120 print argv[0], "[port [allowed_client_name ...]]" | |
121 else: | |
122 if argv[2:]: | |
123 allowed = [] | |
124 for name in argv[2:]: | |
125 client = socket.gethostbyname(name) | |
126 allowed.append(client) | |
127 print "Accept: %s (%s)" % (client, name) | |
128 ProxyHandler.allowed_clients = allowed | |
129 del argv[2:] | |
130 else: | |
131 print "Any clients will be served..." | |
132 BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer) |