Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F24682708
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/fileserv.py b/woof.py
similarity index 50%
rename from fileserv.py
rename to woof.py
index 1958b22..a599ccb 100755
--- a/fileserv.py
+++ b/woof.py
@@ -1,238 +1,325 @@
#!/usr/bin/env python
#
-# fileserv.py -- an ad-hoc single file webserver
+# woof -- 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.
#
# A copy of the GNU General Public License is available at
# http://www.fsf.org/licenses/gpl.txt, you can also write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
-import os, sys, select, getopt, commands
+import sys, os, popen2, signal, select, socket, getopt, commands
import urllib, BaseHTTPServer, SimpleHTTPServer
+import ConfigParser
maxdownloads = 1
cpid = -1
+compressed = True
# 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:" + os.environ["PATH"]
+ platform = os.uname()[0];
+
+ if platform == "Linux":
+ 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"]
+ elif platform == "Darwin":
+ netstat = commands.getoutput ("LC_MESSAGES=C netstat -rn")
+ defiface = [i.split ()[-1] for i in netstat.split ('\n')
+ if len(i) > 2 and i.split ()[0] == "default"]
+ else:
+ print >>sys.stderr, "Unsupported platform; please add support for your platform in find_ip().";
+ return None
- 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 platform == "Linux":
+ ifcfg = commands.getoutput ("LC_MESSAGES=C ifconfig "
+ + defiface[0]).split ("inet addr:")
+ elif platform == "Darwin":
+ ifcfg = commands.getoutput ("LC_MESSAGES=C ifconfig "
+ + defiface[0]).split ("inet ")
+
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 = "."
def log_request (self, code='-', size='-'):
if code == 200:
BaseHTTPServer.BaseHTTPRequestHandler.log_request (self, code, size)
def do_GET (self):
- global maxdownloads, cpid
+ global maxdownloads, cpid, compressed
# 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))
location = "/" + urllib.quote (os.path.basename (self.filename))
if os.path.isdir (self.filename):
- location += ".tar.gz"
+ if compressed:
+ location += ".tar.gz"
+ else:
+ location += ".tar"
if self.path != location:
txt = """\
<html>
<head><title>302 Found</title></head>
<body>302 Found <a href="%s">here</a>.</body>
</html>\n""" % location
self.send_response (302)
self.send_header ("Location", 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 ()
+ os.setpgrp ()
+
if cpid == 0:
# Child process
size = -1
datafile = None
+ child = None
if os.path.isfile (self.filename):
size = os.path.getsize (self.filename)
datafile = open (self.filename)
elif os.path.isdir (self.filename):
- os.environ['fileserv_dir'], os.environ['fileserv_file'] = os.path.split (self.filename)
- datafile = os.popen ('cd "$fileserv_dir";tar cfz - "$fileserv_file"')
+ os.environ['woof_dir'], os.environ['woof_file'] = os.path.split (self.filename)
+ if compressed:
+ arg = 'z'
+ else:
+ arg = ''
+ child = popen2.Popen3 ('cd "$woof_dir";tar c%sf - "$woof_file"' % arg)
+ datafile = child.fromchild
self.send_response (200)
self.send_header ("Content-type", "application/octet-stream")
if size >= 0:
self.send_header ("Content-Length", size)
self.end_headers ()
- while 1:
- if select.select ([datafile], [], [], 2)[0]:
- c = datafile.read (1024)
- if c:
- self.wfile.write (c)
- else:
- datafile.close ()
- return
+ try:
+ try:
+ while 1:
+ if select.select ([datafile], [], [], 2)[0]:
+ c = datafile.read (1024)
+ if c:
+ self.wfile.write (c)
+ else:
+ datafile.close ()
+ break
+ except:
+ print >>sys.stderr, "Connection broke. Aborting"
+
+ finally:
+ # for some reason tar doesnt stop working when the pipe breaks
+ if child:
+ if child.poll ():
+ os.killpg (os.getpgid (child.pid), signal.SIGTERM)
-def serve_files (filename, maxdown = 1, port = 8080):
+def serve_files (filename, maxdown = 1, ip_addr = '', port = 8080):
global maxdownloads
maxdownloads = maxdown
# 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
- httpd = BaseHTTPServer.HTTPServer (('', port),
- FileServHTTPRequestHandler)
+ try:
+ httpd = BaseHTTPServer.HTTPServer ((ip_addr, port),
+ FileServHTTPRequestHandler)
+ except socket.error:
+ print >>sys.stderr, "cannot bind to IP address '%s' port %d" % (ip_addr, port)
+ sys.exit (1)
- ip = find_ip ()
- if ip:
- print "Now serving on http://%s:%s/" % (ip, httpd.server_port)
+ if not ip_addr:
+ ip_addr = find_ip ()
+ if ip_addr:
+ print "Now serving on http://%s:%s/" % (ip_addr, httpd.server_port)
while cpid != 0 and maxdownloads > 0:
httpd.handle_request ()
-def usage (errmsg = None):
+def usage (defport, defmaxdown, errmsg = None):
name = os.path.basename (sys.argv[0])
print >>sys.stderr, """
- Usage: %s [-p <port>] [-c <count>] <file/dir>
- %s [-p <port>] [-c <count>] -s
+ Usage: %s [-i <ip_addr>] [-p <port>] [-c <count>] [-u] <file/dir>
+ %s [-i <ip_addr>] [-p <port>] [-c <count>] [-u] -s
- Serves a single file <count> times via http on port <port>."
- When a directory is specified, a .tar.gz archive gets served,"
- when -s is specified instead of a filename, %s distributes itself.
+ Serves a single file <count> times via http on port <port> on IP
+ address <ip_addr>.
+ When a directory is specified, a .tar.gz archive gets served (or an
+ uncompressed tar archive when -u is specified), when -s is specified
+ instead of a filename, %s distributes itself.
- defaults: count = 1, port = 8080
- """ % (name, name, name)
+ defaults: count = %d, port = %d
+
+ You can specify different defaults in two locations: /etc/woofrc
+ and ~/.woofrc can be INI-style config files containing the default
+ port and the default count. The file in the home directory takes
+ precedence.
+
+ Sample file:
+
+ [main]
+ port = 8008
+ count = 2
+ """ % (name, name, name, defmaxdown, defport)
if errmsg:
print >>sys.stderr, errmsg
print >>sys.stderr
sys.exit (1)
def main ():
- global cpid
+ global cpid, compressed
maxdown = 1
port = 8080
+ ip_addr = ''
+
+ config = ConfigParser.ConfigParser()
+ config.read (['/etc/woofrc', os.path.expanduser('~/.woofrc')])
+
+ if config.has_option ('main', 'port'):
+ port = config.getint ('main', 'port')
+
+ if config.has_option ('main', 'count'):
+ maxdown = config.getint ('main', 'count')
+
+ if config.has_option ('main', 'ip'):
+ maxdown = config.get ('main', 'ip')
+
+ if config.has_option ('main', 'compressed'):
+ compressed = config.getboolean ('main', 'compressed')
+
+ defaultport = port
+ defaultmaxdown = maxdown
try:
- options, filenames = getopt.getopt (sys.argv[1:], "hsc:p:")
+ options, filenames = getopt.getopt (sys.argv[1:], "hsui:c:p:")
except getopt.GetoptError, desc:
- usage (desc)
+ usage (defaultport, defaultmaxdown, desc)
for option, val in options:
if option == '-c':
try:
maxdown = int (val)
if maxdown <= 0:
raise ValueError
except ValueError:
- usage ("invalid download count: %r. "
+ usage (defaultport, defaultmaxdown,
+ "invalid download count: %r. "
"Please specify an integer >= 0." % val)
+ elif option == '-i':
+ ip_addr = val
+
elif option == '-p':
try:
port = int (val)
except ValueError:
- usage ("invalid port number: %r. Please specify an integer" % value)
+ usage (defaultport, defaultmaxdown,
+ "invalid port number: %r. Please specify an integer" % val)
elif option == '-s':
filenames.append (__file__)
elif option == '-h':
- usage ()
+ usage (defaultport, defaultmaxdown)
+
+ elif option == '-u':
+ compressed = False
else:
- usage ("Unknown option: %r" % option)
+ usage (defaultport, defaultmaxdown, "Unknown option: %r" % option)
if len (filenames) == 1:
filename = os.path.abspath (filenames[0])
else:
- usage ("Can only serve single files/directories.")
+ usage (defaultport, defaultmaxdown,
+ "Can only serve single files/directories.")
if not os.path.exists (filename):
- usage ("%s: No such file or directory" % filenames[0])
+ usage (defaultport, defaultmaxdown,
+ "%s: No such file or directory" % filenames[0])
if not (os.path.isfile (filename) or os.path.isdir (filename)):
- usage ("%s: Neither file nor directory" % filenames[0])
+ usage (defaultport, defaultmaxdown,
+ "%s: Neither file nor directory" % filenames[0])
- serve_files (filename, maxdown, port)
+ serve_files (filename, maxdown, ip_addr, port)
# wait for child processes to terminate
if cpid != 0:
try:
while 1:
os.wait ()
except OSError:
pass
if __name__=='__main__':
try:
main ()
except KeyboardInterrupt:
pass
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Mar 7, 01:48 (19 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3500303
Default Alt Text
(12 KB)
Attached To
Mode
rWURF wurf
Attached
Detach File
Event Timeline
Log In to Comment