4 Copyright (c) 2001 SUZUKI Hisao
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 __doc__ = """Tiny HTTP Proxy.
15 This module implements GET, HEAD, POST, PUT and DELETE methods
16 on BaseHTTPServer, and behaves as an HTTP proxy. The CONNECT
17 method is also implemented experimentally, but has not been
20 Any help will be greatly appreciated. SUZUKI Hisao
25 import BaseHTTPServer, select, socket, SocketServer, urlparse, re, string, os, sys
27 class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
28 __base = BaseHTTPServer.BaseHTTPRequestHandler
29 __base_handle = __base.handle
31 server_version = "TinyHTTPProxy/" + __version__
32 rbufsize = 0 # self.rfile Be unbuffered
36 (ip, port) = self.client_address
37 if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients:
38 self.raw_requestline = self.rfile.readline()
39 if self.parse_request(): self.send_error(403)
43 def _connect_to(self, netloc, soc):
47 self.host_port = netloc[:i], int(netloc[i+1:])
48 if (re.match("(\w+\.)*gnunet$", self.host_port[0])):
49 print 'calling gnunet-gns -a '+netloc[:i]
50 auth = os.popen("gnunet-gns -a "+netloc[:i])
51 lines = auth.readlines()
53 print 'result: '+lines[0].split(" ")[-1].rstrip()
54 to_replace = lines[0].split(" ")[-1].rstrip()
58 self.host_port = netloc, 80
59 if (re.match("(\w+\.)*gnunet$", self.host_port[0])):
60 print 'calling gnunet-gns -a '+netloc
61 auth = os.popen("gnunet-gns -a "+netloc)
62 lines = auth.readlines()
64 print 'result: '+lines[0].split(" ")[-1].rstrip()
65 to_replace = lines[0].split(" ")[-1].rstrip()
69 print "\t" "connect to %s:%d" % self.host_port
70 try: soc.connect(self.host_port)
71 except socket.error, arg:
74 self.send_error(404, msg)
76 return (1, to_replace)
79 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
81 res, to_repl = self._connect_to(self.path, soc)
84 self.wfile.write(self.protocol_version +
85 " 200 Connection established\r\n")
86 self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
87 self.wfile.write("\r\n")
88 self._read_write(soc, to_repl, 300)
92 self.connection.close()
94 def test_re2(self, mo):
95 short = os.popen("gnunet-gns -s"+string.replace(mo.group(1), 'a href="http://', ""))
96 lines = short.readlines()
99 elif (len(lines[0].split(" ")) > 0):
100 return 'a href="http://'+lines[0].split(" ")[-1].rstrip()
104 def shorten_zkey(self):
105 return lambda mo: self.test_re2(mo)
106 #return lambda mo: 'a href="http://'+os.popen("gnunet-gns -s"+string.replace(mo.group(1), 'a href="http://', "")).readlines()[0].split(" ")[-1].rstrip()
108 def test_re(self, to_repl, mo):
109 short = os.popen("gnunet-gns -s "+string.replace(mo.group(1)+to_repl, 'a href="http://', ""))
110 lines = short.readlines()
113 elif (len(lines[0].split(" ")) > 0):
114 return 'a href="http://'+lines[0].split(" ")[-1].rstrip()
118 def replace_and_shorten(self, to_repl):
119 return lambda mo: self.test_re(to_repl, mo)
120 # return lambda mo: 'a href="http://'+os.popen("gnunet-gns -s "+string.replace(mo.group(1)+to_repl, 'a href="http://', "")).readlines()[0].split(" ")[-1].rstrip()
121 #full = string.replace(mo.group(1)+to_repl, 'a href="http://', "")
122 #print 'calling gnunet-gns -s '+full
123 #s = os.popen("gnunet-gns -s "+full)
124 #lines = s.readlines()
125 #print 'short: '+lines[0].split(" ")[-1].rstrip()
126 #return 'a href="'+lines[0].split(" ")[-1].rstrip()
129 (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
131 if scm != 'http' or fragment or not netloc:
132 self.send_error(400, "bad url %s" % self.path)
134 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
136 res, to_repl = self._connect_to(netloc, soc)
139 soc.send("%s %s %s\r\n" % (
141 urlparse.urlunparse(('', '', path, params, query, '')),
142 self.request_version))
143 if (re.match("(\w+\.)*gnunet$", self.headers['Host'])):
144 leho = os.popen("gnunet-gns -t LEHO -u "+self.headers['Host']).readlines()
146 print "Legacy hostname lookup failed!"
147 elif (len(leho) == 1):
148 print "Legacy hostname not present!"
150 newhost = leho[1].split(" ")[-1].rstrip()
151 print "Changing Host: "+self.headers['Host']+" to "+newhost
152 self.headers['Host'] = newhost
153 self.headers['Connection'] = 'close'
154 del self.headers['Proxy-Connection']
155 del self.headers['Accept-Encoding']
156 for key_val in self.headers.items():
157 soc.send("%s: %s\r\n" % key_val)
159 self._read_write(soc, to_repl)
163 self.connection.close()
165 def _read_write(self, soc, to_repl="", max_idling=20):
166 iw = [self.connection, soc]
172 (ins, _, exs) = select.select(iw, ow, iw, 3)
178 out = self.connection
184 data = re.sub(r'\nAccept-Ranges: \w+', r'', data)
185 data = re.sub('(a href="http://(\w+\.)*zkey)',
186 self.shorten_zkey(), data)
187 if (re.match("(\w+\.)*gnunet$", self.host_port[0])):
188 arr = self.host_port[0].split('.')
190 data = re.sub('(a href="http://(\w+\.)*)(\+)',
191 self.replace_and_shorten(to_repl), data)
195 # print "GNS exception:", sys.exc_info()[0]
198 print "\t" "idle", count
200 if count == max_idling: break
207 class ThreadingHTTPServer (SocketServer.ThreadingMixIn,
208 BaseHTTPServer.HTTPServer): pass
210 if __name__ == '__main__':
212 if argv[1:] and argv[1] in ('-h', '--help'):
213 print argv[0], "[port [allowed_client_name ...]]"
217 for name in argv[2:]:
218 client = socket.gethostbyname(name)
219 allowed.append(client)
220 print "Accept: %s (%s)" % (client, name)
221 ProxyHandler.allowed_clients = allowed
224 print "Any clients will be served..."
225 BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)