Added tar and tar-compression support
This commit is contained in:
parent
a1b08ba10a
commit
fba7b2e117
106
servefile
106
servefile
|
@ -39,6 +39,8 @@ def getDateStrNow():
|
||||||
|
|
||||||
class FileBaseHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
class FileBaseHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
fileName = "Undefined"
|
fileName = "Undefined"
|
||||||
|
blockSize = 1024 * 1024
|
||||||
|
|
||||||
def checkAndDoRedirect(self):
|
def checkAndDoRedirect(self):
|
||||||
""" If request didn't request self.fileName redirect to self.fileName.
|
""" If request didn't request self.fileName redirect to self.fileName.
|
||||||
|
|
||||||
|
@ -54,7 +56,6 @@ class FileHandler(FileBaseHandler):
|
||||||
filePath = "/dev/null"
|
filePath = "/dev/null"
|
||||||
fileLength = 0
|
fileLength = 0
|
||||||
startTime = getDateStrNow()
|
startTime = getDateStrNow()
|
||||||
blockSize = 1024 * 1024
|
|
||||||
|
|
||||||
def do_HEAD(self):
|
def do_HEAD(self):
|
||||||
if self.checkAndDoRedirect():
|
if self.checkAndDoRedirect():
|
||||||
|
@ -121,6 +122,65 @@ class FileHandler(FileBaseHandler):
|
||||||
readsize = self.blockSize
|
readsize = self.blockSize
|
||||||
return myfile.read(readsize)
|
return myfile.read(readsize)
|
||||||
|
|
||||||
|
class TarFileHandler(FileBaseHandler):
|
||||||
|
target = None
|
||||||
|
compression = "none"
|
||||||
|
compressionMethods = ("none", "gzip", "bzip2")
|
||||||
|
|
||||||
|
def do_HEAD(self):
|
||||||
|
if self.checkAndDoRedirect():
|
||||||
|
return
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Last-Modified', getDateStrNow())
|
||||||
|
self.send_header('Content-Type', 'application/octet-stream')
|
||||||
|
self.send_header('Content-Disposition', 'attachment; filename="%s"' % self.fileName)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.checkAndDoRedirect():
|
||||||
|
return
|
||||||
|
|
||||||
|
tarCmd = Popen(self.getCompressionCmd(), stdout=PIPE)
|
||||||
|
# give the process a short time to find out if it can
|
||||||
|
# pack/compress the file
|
||||||
|
time.sleep(0.05)
|
||||||
|
if tarCmd.poll() != None and tarCmd.poll() != 0:
|
||||||
|
# something went wrong
|
||||||
|
print "Error while compressing '%s'. Aborting request." % self.target
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Last-Modified', getDateStrNow())
|
||||||
|
self.send_header('Content-Type', 'application/octet-stream')
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
block = True
|
||||||
|
while block and block != '':
|
||||||
|
block = tarCmd.stdout.read(self.blockSize)
|
||||||
|
if block and block != '':
|
||||||
|
self.wfile.write(block)
|
||||||
|
|
||||||
|
def getCompressionCmd(self):
|
||||||
|
if self.compression == "none":
|
||||||
|
self.fileName += ".tar"
|
||||||
|
cmd = ["tar", "-c"]
|
||||||
|
elif self.compression == "gzip":
|
||||||
|
self.fileName += ".tar.gz"
|
||||||
|
cmd = ["tar", "-cz"]
|
||||||
|
elif self.compression == "bzip2":
|
||||||
|
self.fileName += ".tar.bz2"
|
||||||
|
cmd = ["tar", "-cj"]
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown compression mode '%s'" % self.compression)
|
||||||
|
dirname = os.path.basename(self.target.rstrip("/"))
|
||||||
|
chdirTo = os.path.dirname(self.target.rstrip("/"))
|
||||||
|
if chdirTo != '':
|
||||||
|
cmd.extend(["-C", chdirTo])
|
||||||
|
cmd.append(dirname)
|
||||||
|
return cmd
|
||||||
|
|
||||||
class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
""" Simple HTTP Server which allows uploading to a specified directory
|
""" Simple HTTP Server which allows uploading to a specified directory
|
||||||
either via multipart/form-data or POST/PUT requests containing the file.
|
either via multipart/form-data or POST/PUT requests containing the file.
|
||||||
|
@ -310,7 +370,7 @@ class ServeFileException(Exception):
|
||||||
class ServeFile():
|
class ServeFile():
|
||||||
""" Main class to manage everything. """
|
""" Main class to manage everything. """
|
||||||
|
|
||||||
(MODE_SINGLE, MODE_UPLOAD, MODE_LISTDIR) = range(3)
|
(MODE_SINGLE, MODE_SINGLETAR, MODE_UPLOAD, MODE_LISTDIR) = range(4)
|
||||||
|
|
||||||
def __init__(self, target, port=8080, serveMode=0, useSSL=False):
|
def __init__(self, target, port=8080, serveMode=0, useSSL=False):
|
||||||
self.target = target
|
self.target = target
|
||||||
|
@ -366,6 +426,14 @@ class ServeFile():
|
||||||
""" Set the maximum upload size in byte """
|
""" Set the maximum upload size in byte """
|
||||||
self.maxUploadSize = limit
|
self.maxUploadSize = limit
|
||||||
|
|
||||||
|
def setCompression(self, compression):
|
||||||
|
""" Set the compression of TarFileHandler """
|
||||||
|
if self.serveMode != self.MODE_SINGLETAR:
|
||||||
|
raise ServeFileException("Compression mode can only be set in tar-mode")
|
||||||
|
if compression not in TarFileHandler.compressionMethods:
|
||||||
|
raise ServeFileException("Compression mode not available")
|
||||||
|
TarFileHandler.compression = compression
|
||||||
|
|
||||||
def genKeyPair(self):
|
def genKeyPair(self):
|
||||||
print "Generating SSL certificate...",
|
print "Generating SSL certificate...",
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
@ -471,6 +539,11 @@ class ServeFile():
|
||||||
except IOError:
|
except IOError:
|
||||||
raise ServeFileException("Error: Could not open file!")
|
raise ServeFileException("Error: Could not open file!")
|
||||||
handler = FileHandler
|
handler = FileHandler
|
||||||
|
elif self.serveMode == self.MODE_SINGLETAR:
|
||||||
|
TarFileHandler.target = self.target
|
||||||
|
TarFileHandler.fileName = os.path.basename(self.target.rstrip("/"))
|
||||||
|
|
||||||
|
handler = TarFileHandler
|
||||||
elif self.serveMode == self.MODE_UPLOAD:
|
elif self.serveMode == self.MODE_UPLOAD:
|
||||||
if os.path.isdir(self.target):
|
if os.path.isdir(self.target):
|
||||||
print "Warning: Uploading to an already existing directory"
|
print "Warning: Uploading to an already existing directory"
|
||||||
|
@ -560,6 +633,11 @@ def main():
|
||||||
help="Certfile to use for SSL")
|
help="Certfile to use for SSL")
|
||||||
parser.add_argument('-a', '--auth', type=str, metavar='user:password', \
|
parser.add_argument('-a', '--auth', type=str, metavar='user:password', \
|
||||||
help="Set user and password for HTTP basic authentication")
|
help="Set user and password for HTTP basic authentication")
|
||||||
|
parser.add_argument('-t', '--tar', action="store_true", default=False, \
|
||||||
|
help="Enable on the fly tar creation for given file or directory. Note: Download continuation will not be available.")
|
||||||
|
parser.add_argument('-c', '--compression', type=str, metavar='method', \
|
||||||
|
default="none", \
|
||||||
|
help="Set compression method, only in combination with --tar. Can be one of %s." % ", ".join(TarFileHandler.compressionMethods))
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
maxUploadSize = 0
|
maxUploadSize = 0
|
||||||
|
@ -600,11 +678,33 @@ def main():
|
||||||
print "Error: User and password for HTTP basic auth need to be both at least one character long and have to be seperated by a \":\""
|
print "Error: User and password for HTTP basic auth need to be both at least one character long and have to be seperated by a \":\""
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.compression != "none" and not args.tar:
|
||||||
|
print "Error: Please specify --tar if you want to tar everything"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.tar and args.upload:
|
||||||
|
print "Error: --tar mode will not work with uploads"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.tar and args.list_dir:
|
||||||
|
print "Error: --tar mode will not work with directory listings"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
compression = None
|
||||||
|
if args.compression:
|
||||||
|
if args.compression in TarFileHandler.compressionMethods:
|
||||||
|
compression = args.compression
|
||||||
|
else:
|
||||||
|
print "Error: Compression mode '%s' is unknown" % self.compression
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
mode = None
|
mode = None
|
||||||
if args.upload:
|
if args.upload:
|
||||||
mode = ServeFile.MODE_UPLOAD
|
mode = ServeFile.MODE_UPLOAD
|
||||||
elif args.list_dir:
|
elif args.list_dir:
|
||||||
mode = ServeFile.MODE_LISTDIR
|
mode = ServeFile.MODE_LISTDIR
|
||||||
|
elif args.tar:
|
||||||
|
mode = ServeFile.MODE_SINGLETAR
|
||||||
else:
|
else:
|
||||||
mode = ServeFile.MODE_SINGLE
|
mode = ServeFile.MODE_SINGLE
|
||||||
|
|
||||||
|
@ -619,6 +719,8 @@ def main():
|
||||||
if args.auth:
|
if args.auth:
|
||||||
user, password = args.auth.split(":", 1)
|
user, password = args.auth.split(":", 1)
|
||||||
server.setAuth(user, password)
|
server.setAuth(user, password)
|
||||||
|
if compression and compression != "none":
|
||||||
|
server.setCompression(compression)
|
||||||
server.serve()
|
server.serve()
|
||||||
except ServeFileException, e:
|
except ServeFileException, e:
|
||||||
print e
|
print e
|
||||||
|
|
Loading…
Reference in New Issue