1
2
3 """
4 fproxyproxy
5
6 An http proxy atop fproxy which uses pyFreenet's 'name services'
7 """
8
9
10
11 import sys, os, getopt, traceback, mimetypes, time
12 from BaseHTTPServer import HTTPServer
13 from SimpleHTTPServer import SimpleHTTPRequestHandler
14 from SocketServer import ThreadingMixIn
15 from httplib import HTTPConnection
16 import socket
17
18 import node
19 from node import ERROR, INFO, DETAIL, DEBUG
20
21
22
23 progname = sys.argv[0]
24
25
26
27 -class Handler(SimpleHTTPRequestHandler):
28 """
29 Handles each FProxyProxy client request
30 """
31
32
33 - def __init__(self, request, client_address, server):
34
35 self.server = server
36 SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
37
38
39
41
42 print "GET: client=%s path=%s" % (self.client_address, self.path)
43
44
45
46 try:
47
48
49
50
51
52
53
54
55 self.fproxyGet(self.path)
56
57 except:
58 traceback.print_exc()
59 self.send_error(404, "File not found")
60 return None
61
62
63
65 """
66 Fetches from fproxy, returns (status, mimetype, data)
67 """
68 server = self.server
69 headers = self.headers
70
71 print "--------------------------------------------"
72 print "** path=%s" % path
73
74
75
76 if not path.startswith("http://"):
77 self.send_response(400)
78 self.send_header("Content-type", "text/html")
79 data = "\n".join([
80 "<html><head>",
81 "<title>Access Denied</title>",
82 "</head><body>",
83 "<h1>Access Denied</h1>",
84 "Sorry, but FProxyProxy is an http proxy server.<br>",
85 "Please don't try to access it like a web server.",
86 "</body></html>",
87 "",
88 ])
89 self.send_header("Content-Length", str(len(data)))
90 self.send_header("Location", location)
91 self.end_headers()
92 self.wfile.write(data)
93 self.wfile.flush()
94 return
95
96
97 path = "/" + path[7:].split("/", 1)[-1]
98
99
100
101 try:
102
103 hostname = headers.get("Host", 'fproxy')
104 pathbits = path.split("/")
105
106 print "** hostname = %s" % hostname
107
108
109 if len(pathbits) == 1:
110
111 location = path + "/"
112 print "** redirecting to: %s" % location
113
114 self.send_response(301)
115 self.send_header("Content-type", "text/html")
116 data = "\n".join([
117 "<html><head>",
118 "<title>Permanent redirect: new URI</title>",
119 "</head><body>",
120 "<h1>Permanent redirect: new URI</h1>",
121 "<a href=\"%s\">Click here</a>",
122 "</body></html>",
123 "",
124 ]) % location
125 self.send_header("Content-Length", str(len(data)))
126 self.send_header("Location", location)
127 self.end_headers()
128 self.wfile.write(data)
129 self.wfile.flush()
130 return
131
132 tail = "/".join(pathbits[1:])
133
134
135 if hostname == 'fproxy':
136
137
138 conn = HTTPConnection(server.fproxyHost, server.fproxyPort)
139 conn.request("GET", path)
140 resp = conn.getresponse()
141 self.send_response(resp.status)
142 self.send_header("Content-type",
143 resp.getheader("Content-Type", "text/plain"))
144 data = resp.read()
145 self.send_header("Content-Length", str(len(data)))
146 self.end_headers()
147 self.wfile.write(data)
148 self.wfile.flush()
149 conn.close()
150 return
151
152 else:
153
154 uri = server.node.namesiteLookup(hostname)
155
156 if not uri:
157
158 print "** lookup of domain %s failed" % hostname
159 self.send_response(404)
160 self.send_header("Content-type", "text/html")
161 data = "\n".join([
162 "<html><head>",
163 "<title>404 - Freenet name not found</title>",
164 "</head><body",
165 "<h1>404 - Freenet name not found</title>",
166 "The pyFreenet name service was unable to resolve ",
167 "the name %s" % hostname,
168 "<br><br>",
169 "You might like to find its freenet uri and try that ",
170 "within <a href=\"/fproxy/\">FProxy</a>",
171 "</body></html>",
172 "",
173 ])
174 self.send_header("Content-Length", str(len(data)))
175 self.end_headers()
176 self.wfile.write(data)
177 self.wfile.flush()
178
179
180 conn = HTTPConnection(server.fproxyHost, server.fproxyPort)
181 newpath = "/" + uri
182 if tail:
183 if not newpath.endswith("/"):
184 newpath += "/"
185 newpath += tail
186 print "** newpath=%s" % newpath
187 conn.request("GET", newpath)
188 resp = conn.getresponse()
189 print "** status=%s" % resp.status
190 self.send_response(resp.status)
191 self.send_header("Content-type",
192 resp.getheader("Content-Type", "text/plain"))
193
194
195 if resp.status == 301:
196
197
198
199 location = resp.getheader("location")
200 newLocation = "http://fproxy" + location
201 print "*** redirected!!!"
202 print "*** old location = %s" % location
203 print "*** --> %s" % newLocation
204 self.send_header("Location", newLocation)
205
206
207 data = resp.read()
208 self.send_header("Content-Length", str(len(data)))
209 self.end_headers()
210 self.wfile.write(data)
211 self.wfile.flush()
212 conn.close()
213 return
214
215 return
216
217 except socket.error:
218 raise
219
220
221
222
223
224
226 """
227 an http proxy that runs atop fproxy, and uses the pyFreenet name service
228 """
229
230
232 """
233 runs the FProxyProxy service
234
235 Keywords:
236 - node - a live FCPNode object
237 - fproxyHost - hostname of fproxy
238 - fproxyPort - port of fproxy
239 - listenHost - hostname to listen on for client HTTP connections
240 - listenPort - port to listen on for client HTTP connections
241 """
242 for k in ['node', 'fproxyHost', 'fproxyPort', 'listenHost', 'listenPort']:
243 setattr(self, k, kw[k])
244
245 self.log = self.node._log
246
247 HTTPServer.__init__(self, (self.listenHost, self.listenPort), Handler)
248
249
250
252 """
253 Starts the proxy, runs forever till interrupted
254 """
255 log = self.log
256 log(ERROR, "FproxyProxy listening on %s:%s" % (self.listenHost, self.listenPort))
257 log(ERROR, " -> forwarding requests to fproxy at %s:%s" % (
258 self.fproxyHost, self.fproxyPort))
259
260 self.serve_forever()
261
262
263
264
265
266
267 -def usage(msg=None, ret=1):
268 """
269 Prints usage message then exits
270 """
271 if msg:
272 sys.stderr.write(msg+"\n")
273 sys.stderr.write("Usage: %s [options] src-uri target-uri\n" % progname)
274 sys.stderr.write("Type '%s -h' for help\n" % progname)
275 sys.exit(ret)
276
277
278
280 """
281 print help options, then exit
282 """
283 print "%s: runs an http proxy atop fproxy," % progname
284 print "which uses pyFreenet 'name services'"
285 print
286 print "Note - you should configure fproxyproxy as an http proxy"
287 print "in your browser (best done via Firefox's 'switchproxy' extension"
288 print
289 print "Usage: %s [options] src-uri target-uri" % progname
290 print
291 print "Options:"
292 print " -h, -?, --help"
293 print " Print this help message"
294 print " -v, --verbose"
295 print " Print verbose progress messages to stderr"
296 print " -H, --fcpHost=<hostname>"
297 print " Connect to FCP service at host <hostname>"
298 print " -P, --fcpPort=<portnum>"
299 print " Connect to FCP service at port <portnum>"
300 print " -p, --fproxyAddress=[<hostname>][:<portnum>]"
301 print " Use fproxy service at <hostname>:<portnum>,"
302 print " default 127.0.0.1:8888"
303 print " -L, --listenAddress=[<hostname>][:<portnum>]"
304 print " Listen for http connections on <hostname>:<portnum>,"
305 print " default is 127.0.0.1:8889"
306 print " -V, --version"
307 print " Print version number and exit"
308 print
309 print "Environment:"
310 print " Instead of specifying -H and/or -P, you can define the environment"
311 print " variables FCP_HOST and/or FCP_PORT respectively"
312
313 sys.exit(0)
314
315
316
318 """
319 Front end for fproxyproxy utility
320 """
321
322 verbosity = node.ERROR
323 verbose = False
324 fcpHost = node.defaultFCPHost
325 fcpPort = node.defaultFCPPort
326 fproxyHost = os.environ.get("FPROXY_HOST", "127.0.0.1")
327 fproxyPort = int(os.environ.get("FPROXY_PORT", 8888))
328 listenHost = os.environ.get("FPROXYPROXY_HOST", "127.0.0.1")
329 listenPort = int(os.environ.get("FPROXYPROXY_PORT", 8889))
330
331 opts = {
332 "Verbosity" : 0,
333 }
334
335
336 try:
337 cmdopts, args = getopt.getopt(
338 sys.argv[1:],
339 "?hvH:P:Vp:L:",
340 ["help", "verbose", "fcpHost=", "fcpPort=", "version",
341 "listenAddress=", "fproxyAddress=",
342 ]
343 )
344 except getopt.GetoptError:
345
346 usage()
347 sys.exit(2)
348 output = None
349 verbose = False
350
351 for o, a in cmdopts:
352
353 if o in ("-?", "-h", "--help"):
354 help()
355
356 if o in ("-V", "--version"):
357 print "This is %s, version %s" % (progname, node.fcpVersion)
358 sys.exit(0)
359
360 if o in ("-v", "--verbosity"):
361 verbosity = node.DETAIL
362 opts['Verbosity'] = 1023
363 verbose = True
364
365 if o in ("-H", "--fcpHost"):
366 fcpHost = a
367
368 if o in ("-P", "--fcpPort"):
369 try:
370 fcpPort = int(a)
371 except:
372 usage("Invalid fcpPort argument %s" % repr(a))
373
374 if o in ("-L", "--listenAddress"):
375 parts = a.split(":")
376 if len(parts) == 1:
377 listenHost = parts[0]
378 elif len(parts) == 2:
379 if parts[0]:
380 listenHost = parts[0]
381 if parts[1]:
382 listenPort = int(parts[1])
383 else:
384 usage("Invalid listen address '%s'" % a)
385
386 if o in ("-p", "--fproxyAddress"):
387 parts = a.split(":")
388 if len(parts) == 1:
389 fproxyHost = parts[0]
390 elif len(parts) == 2:
391 if parts[0]:
392 fproxyHost = parts[0]
393 if parts[1]:
394 fproxyPort = int(parts[1])
395
396
397 try:
398 n = node.FCPNode(host=fcpHost, port=fcpPort, verbosity=verbosity,
399 logfile=sys.stderr)
400 log = n._log
401 except:
402 if verbose:
403 traceback.print_exc(file=sys.stderr)
404 usage("Failed to connect to FCP service at %s:%s" % (fcpHost, fcpPort))
405
406 try:
407 proxy = FProxyProxy(
408 node=n,
409 fproxyHost=fproxyHost, fproxyPort=fproxyPort,
410 listenHost=listenHost, listenPort=listenPort)
411 proxy.run()
412 sys.exit(0)
413 except KeyboardInterrupt:
414 print "fproxyproxy terminated by user"
415 n.shutdown()
416 sys.exit(0)
417 except:
418 traceback.print_exc()
419 print "fproxyproxy terminated"
420 n.shutdown()
421 sys.exit(1)
422
423
424
425
426
427
428