Page MenuHomeDevCentral

No OneTemporary

diff --git a/fileserv.py b/fileserv.py
index 8dfd4c3..d8d96ad 100755
--- a/fileserv.py
+++ b/fileserv.py
@@ -1,162 +1,230 @@
#!/usr/bin/env python
-import os, sys, shutil, getopt, urllib, BaseHTTPServer, SimpleHTTPServer
+# fileserv.py -- an ad-hoc single file webserver
+# Copyright (C) 2004 Simon Budig <simon@budig.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+import os, sys, tempfile, shutil, getopt, commands
+import urllib, BaseHTTPServer, SimpleHTTPServer
maxdownloads = 1
+port = 8080
+
+tarfile = None
+tarfilename = None
+location = "/"
+
cpid = -1
+# Utility function to guess the IP (as a string) where the server can be
+# reached from the outside. Quite nasty problem actually.
+
+def find_ip ():
+ os.environ["PATH"] += ":/sbin:/usr/sbin:/usr/local/sbin"
+
+ netstat = commands.getoutput ("LC_MESSAGES=C netstat -rn")
+ defiface = [i.split ()[-1] for i in netstat.split ('\n')
+ if i.split ()[0] == "0.0.0.0"]
+ if not defiface: return None
+ ifcfg = commands.getoutput ("LC_MESSAGES=C ifconfig "
+ + defiface[0]).split ("inet addr:")
+ if len (ifcfg) != 2: return None
+ ip_addr = ifcfg[1].split ()[0]
+
+ # sanity check
+ try:
+ ints = [ i for i in ip_addr.split (".") if 0 <= int(i) <= 255]
+ if len (ints) != 4: return None
+ except ValueError: return None
+
+ return ip_addr
+
+
+# Main class implementing an HTTP-Requesthandler, that serves just a single
+# file and redirects all other requests to this file (this passes the actual
+# filename to the client).
+# Currently it is impossible to serve different files with different
+# instances of this class.
+
class FileServHTTPRequestHandler (BaseHTTPServer.BaseHTTPRequestHandler):
server_version = "Simons FileServer"
protocol_version = "HTTP/1.0"
filename = "."
location = "/"
def log_request (self, code='-', size='-'):
if code == 200:
BaseHTTPServer.BaseHTTPRequestHandler.log_request (self, code, size)
def do_GET (self):
global maxdownloads, cpid
# Redirect any request to the filename of the file to serve.
# This hands over the filename to the client.
+ self.path = urllib.quote (urllib.unquote (self.path))
+
if self.path != self.location:
txt = """\
<html>
<head><title>302 Found</title></head>
<body>302 Found <a href="%s">here</a>.</body>
</html>\n""" % self.location
self.send_response (302)
self.send_header ("Location", self.location)
self.send_header ("Content-type", "text/html")
self.send_header ("Content-Length", str (len (txt)))
self.end_headers ()
self.wfile.write (txt)
return
maxdownloads -= 1
# let a separate process handle the actual download, so that
# multiple downloads can happen simultaneously.
cpid = os.fork ()
if cpid == 0:
# Child process
f = open (self.filename)
size = os.path.getsize (self.filename)
self.send_response (200)
self.send_header ("Content-type", "application/octet-stream")
self.send_header ("Content-Length", size)
self.end_headers ()
shutil.copyfileobj (f, self.wfile)
f.close ()
+def serve_files (filename, location, port):
+ # We have to somehow push the filename of the file to serve to the
+ # class handling the requests. This is an evil way to do this...
-class ForkingDownloadHTTPRequestHandler (SimpleHTTPServer.SimpleHTTPRequestHandler):
- def guess_type (self, path):
- return self.extensions_map['']
+ FileServHTTPRequestHandler.filename = filename
+ FileServHTTPRequestHandler.location = location
- def do_GET (self):
- global cpid
+ httpd = BaseHTTPServer.HTTPServer (('', port),
+ FileServHTTPRequestHandler)
- cpid = os.fork ()
- if cpid == 0:
- # Child process
- SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET (self)
+ ip = find_ip ()
+ if ip:
+ print "Now serving on http://%s:%s/" % (ip, httpd.server_port)
+
+ while cpid != 0 and maxdownloads > 0:
+ httpd.handle_request ()
def usage (errmsg = None):
if errmsg:
print >>sys.stderr, errmsg
- print >>sys.stderr, "Usage:", sys.argv[0], "[-p <port>] [-c <count>] [file]"
+ print >>sys.stderr
+ print >>sys.stderr, "Usage: %s [-p <port>] [-c <count>] [file]" % sys.argv[0]
+ print >>sys.stderr, " serves a single file <count> times via http on port <port>"
+ print >>sys.stderr, " defaults: count = 1, port = 8080"
sys.exit (1)
-if __name__=='__main__':
- port = 8080
- serve_file = True
- location = "/"
+
+def main ():
+ global cpid, port, tarfile, tarfilename, maxdownloads, location
try:
options, filenames = getopt.getopt (sys.argv[1:], "c:p:")
except getopt.GetoptError, desc:
usage (desc)
if len (filenames) == 1:
filename = os.path.abspath (filenames[0])
- location = "/" + urllib.quote (os.path.basename (filename))
else:
usage ("Can only serve single files/directories.")
if not os.path.exists (filename):
usage ("%s: No such file or directory" % filenames[0])
if os.path.isfile (filename):
- serve_file = True
+ tarfilename = None
+ location = "/" + urllib.quote (os.path.basename (filename))
+
elif os.path.isdir (filename):
- serve_file = False
+ tarfile, tarfilename = tempfile.mkstemp (".tar.gz")
+
+ location = "/" + urllib.quote (os.path.basename (filename + ".tar.gz"))
+
+ r = os.spawnlp (os.P_WAIT, 'tar', 'tar', 'czf', tarfilename, filenames[0])
+ if r != 0:
+ usage ("error while creating archive '%s' - see above" % tarfilename)
+
+ filename = tarfilename
+
else:
usage ("%s: Neither file nor directory" % filenames[0])
- if serve_file:
- try:
- # Check for readability
- os.path.getsize (filename)
- open (filename).close ()
- except (OSError, IOError):
- usage ("%s: Not readable" % filenames[0])
+ try:
+ # Check for readability
+ os.path.getsize (filename)
+ open (filename).close ()
+ except (OSError, IOError):
+ usage ("%s: Not readable" % filenames[0])
for option, val in options:
if option == '-c':
- if not serve_file:
- print >>sys.stderr, "WARNING: Download count ignored for directories."
try:
maxdownloads = int (val)
+ if maxdownloads <= 0:
+ raise ValueError
except ValueError:
- usage ("invalid download count: %r. Please specify an integer." % val)
+ usage ("invalid download count: %r. "
+ "Please specify an integer >= 0." % val)
if option == '-p':
try:
port = int (val)
except ValueError:
usage ("invalid port number: %r. Please specify an integer" % value)
else:
usage ("Unknown option: %r" % option)
- # Directories sollten eigentlich als .tar.gz geliefert werden.
- # tempfile.mkstemp()
-
- if serve_file:
- # We have to somehow push the filename of the file to serve to the
- # class handling the requests. This is an evil way to do this...
-
- FileServHTTPRequestHandler.filename = filename
- FileServHTTPRequestHandler.location = location
-
- httpd = BaseHTTPServer.HTTPServer (('', port),
- FileServHTTPRequestHandler)
- while cpid != 0 and maxdownloads > 0:
- httpd.handle_request ()
-
- else:
- httpd = BaseHTTPServer.HTTPServer (('', port),
- ForkingDownloadHTTPRequestHandler)
- while cpid != 0:
- httpd.handle_request ()
-
-
+ serve_files (filename, location, port)
# wait for child processes to terminate
if cpid != 0:
try:
while 1:
os.wait ()
except OSError:
pass
+
+
+if __name__=='__main__':
+ try:
+ try:
+ main ()
+ except KeyboardInterrupt:
+ pass
+ finally:
+ # delete temporary archive
+
+ if cpid != 0 and tarfilename:
+ os.close (tarfile)
+ os.remove (tarfilename)
+
+

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 09:34 (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2259028
Default Alt Text
(8 KB)

Event Timeline