forked from seba/servefile
Merge branch 'dirlisting'
This commit is contained in:
commit
0f54983a63
379
servefile
379
servefile
|
@ -11,12 +11,12 @@ import argparse
|
||||||
import base64
|
import base64
|
||||||
import cgi
|
import cgi
|
||||||
import BaseHTTPServer
|
import BaseHTTPServer
|
||||||
import commands
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import mimetypes
|
||||||
import urllib
|
import urllib
|
||||||
import os
|
import os
|
||||||
|
import posixpath
|
||||||
import re
|
import re
|
||||||
import SimpleHTTPServer
|
|
||||||
import SocketServer
|
import SocketServer
|
||||||
import socket
|
import socket
|
||||||
from stat import ST_SIZE
|
from stat import ST_SIZE
|
||||||
|
@ -38,21 +38,169 @@ def getDateStrNow():
|
||||||
return now.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
return now.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
||||||
|
|
||||||
class FileBaseHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
class FileBaseHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
fileName = "Undefined"
|
fileName = None
|
||||||
blockSize = 1024 * 1024
|
blockSize = 1024 * 1024
|
||||||
server_version = "servefile/" + __version__
|
server_version = "servefile/" + __version__
|
||||||
|
|
||||||
def checkAndDoRedirect(self):
|
def checkAndDoRedirect(self, fileName=None):
|
||||||
""" If request didn't request self.fileName redirect to self.fileName.
|
""" If request didn't request self.fileName redirect to self.fileName.
|
||||||
|
|
||||||
Returns True if a redirect was issued. """
|
Returns True if a redirect was issued. """
|
||||||
if urllib.unquote(self.path) != "/" + self.fileName:
|
if not fileName:
|
||||||
|
fileName = self.fileName
|
||||||
|
if urllib.unquote(self.path) != "/" + fileName:
|
||||||
self.send_response(302)
|
self.send_response(302)
|
||||||
self.send_header('Location', '/' + self.fileName)
|
self.send_header('Location', '/' + fileName)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def sendContentHeaders(self, fileName, fileLength, lastModified=None):
|
||||||
|
""" Send default Content headers for given fileName and fileLength.
|
||||||
|
|
||||||
|
If no lastModified is given the current date is taken. If
|
||||||
|
fileLength is lesser than 0 no Content-Length will be sent."""
|
||||||
|
if not lastModified:
|
||||||
|
lastModified = getDateStrNow()
|
||||||
|
|
||||||
|
if fileLength >= 0:
|
||||||
|
self.send_header('Content-Length', str(fileLength))
|
||||||
|
self.send_header('Last-Modified', lastModified)
|
||||||
|
self.send_header('Content-Type', 'application/octet-stream')
|
||||||
|
self.send_header('Content-Disposition', 'attachment; filename="%s"' % fileName)
|
||||||
|
self.send_header('Content-Transfer-Encoding', 'binary')
|
||||||
|
|
||||||
|
def isRangeRequest(self):
|
||||||
|
""" Return True if partial content is requestet """
|
||||||
|
return "Range" in self.headers
|
||||||
|
|
||||||
|
def handleRangeRequest(self, fileLength):
|
||||||
|
""" Find out and handle continuing downloads.
|
||||||
|
|
||||||
|
Returns a tuple of a boolean, if this is a valid range request,
|
||||||
|
and a range. When the requested range is out of range, range is
|
||||||
|
set to None.
|
||||||
|
"""
|
||||||
|
fromto = None
|
||||||
|
if self.isRangeRequest():
|
||||||
|
cont = self.headers.get("Range").split("=")
|
||||||
|
if len(cont) > 1 and cont[0] == 'bytes':
|
||||||
|
fromto = cont[1].split('-')
|
||||||
|
if len(fromto) > 1:
|
||||||
|
if fromto[1] == '':
|
||||||
|
fromto[1] = fileLength - 1
|
||||||
|
try:
|
||||||
|
fromto[0] = int(fromto[0])
|
||||||
|
fromto[1] = int(fromto[1])
|
||||||
|
except:
|
||||||
|
return (False, None)
|
||||||
|
|
||||||
|
if fromto[0] >= fileLength or fromto[0] < 0 or fromto[1] >= fileLength or fromto[1]-fromto[0] < 0:
|
||||||
|
# oops, already done! (requested range out of range)
|
||||||
|
self.send_response(416)
|
||||||
|
self.send_header('Content-Range', 'bytes */%s' % fileLength)
|
||||||
|
self.end_headers()
|
||||||
|
return (True, None)
|
||||||
|
return (True, fromto)
|
||||||
|
# broken request or no range header
|
||||||
|
return (False, None)
|
||||||
|
|
||||||
|
def sendFile(self, filePath, fileLength=None, lastModified=None):
|
||||||
|
""" Send file with continuation support.
|
||||||
|
|
||||||
|
filePath: path to file to be sent
|
||||||
|
fileLength: length of file (if None is given this will be found out)
|
||||||
|
lastModified: time the file was last modified, None for "now"
|
||||||
|
"""
|
||||||
|
if not fileLength:
|
||||||
|
fileLength = os.stat(filePath)[ST_SIZE]
|
||||||
|
|
||||||
|
(responseCode, myfile) = self.getFileHandle(filePath)
|
||||||
|
if not myfile:
|
||||||
|
self.send_response(responseCode)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
(continueDownload, fromto) = self.handleRangeRequest(fileLength)
|
||||||
|
if continueDownload:
|
||||||
|
if not fromto:
|
||||||
|
# we are done
|
||||||
|
return True
|
||||||
|
|
||||||
|
# now we can wind the file *brrrrrr*
|
||||||
|
myfile.seek(fromto[0])
|
||||||
|
|
||||||
|
if fromto != None:
|
||||||
|
self.send_response(216)
|
||||||
|
self.send_header('Content-Range', 'bytes %s-%s/%s' % (fromto[0], fromto[1], fileLength))
|
||||||
|
fileLength = fromto[1] - fromto[0] + 1
|
||||||
|
else:
|
||||||
|
self.send_response(200)
|
||||||
|
|
||||||
|
fileName = self.fileName
|
||||||
|
if not fileName:
|
||||||
|
fileName = os.path.basename(filePath)
|
||||||
|
self.sendContentHeaders(fileName, fileLength, lastModified)
|
||||||
|
self.end_headers()
|
||||||
|
block = self.getChunk(myfile, fromto)
|
||||||
|
while block:
|
||||||
|
try:
|
||||||
|
self.wfile.write(block)
|
||||||
|
except socket.error, e:
|
||||||
|
print "%s ABORTED transmission (Reason %s: %s)" % (self.client_address[0], e[0], e[1])
|
||||||
|
return False
|
||||||
|
block = self.getChunk(myfile, fromto)
|
||||||
|
myfile.close()
|
||||||
|
print "%s finished downloading %s" % (self.client_address[0], filePath)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getChunk(self, myfile, fromto):
|
||||||
|
if fromto and myfile.tell()+self.blockSize >= fromto[1]:
|
||||||
|
readsize = fromto[1]-myfile.tell()+1
|
||||||
|
else:
|
||||||
|
readsize = self.blockSize
|
||||||
|
return myfile.read(readsize)
|
||||||
|
|
||||||
|
def getFileHandle(self, path):
|
||||||
|
""" Get handle to a file.
|
||||||
|
|
||||||
|
Return a tuple of HTTP response code and file handle.
|
||||||
|
If the handle couldn't be acquired it is set to None
|
||||||
|
and an appropriate HTTP error code is returned.
|
||||||
|
"""
|
||||||
|
myfile = None
|
||||||
|
responseCode = 200
|
||||||
|
try:
|
||||||
|
myfile = open(path, 'rb')
|
||||||
|
except IOError, e:
|
||||||
|
responseCode = self.getResponseForErrno(e.errno)
|
||||||
|
return (responseCode, myfile)
|
||||||
|
|
||||||
|
def getFileLength(self, path):
|
||||||
|
""" Get length of a file.
|
||||||
|
|
||||||
|
Return a tuple of HTTP response code and file length.
|
||||||
|
If filelength couldn't be determined, it is set to -1
|
||||||
|
and an appropriate HTTP error code is returned.
|
||||||
|
"""
|
||||||
|
fileSize = -1
|
||||||
|
responseCode = 200
|
||||||
|
try:
|
||||||
|
fileSize = os.stat(path)[ST_SIZE]
|
||||||
|
except IOError, e:
|
||||||
|
responseCode = self.getResponseForErrno(e.errno)
|
||||||
|
return (responseCode, fileSize)
|
||||||
|
|
||||||
|
def getResponseForErrno(self, errno):
|
||||||
|
""" Return HTTP response code for an IOError errno """
|
||||||
|
if errno == 2:
|
||||||
|
return 404
|
||||||
|
elif errno == 13:
|
||||||
|
return 403
|
||||||
|
else:
|
||||||
|
return 500
|
||||||
|
|
||||||
|
|
||||||
class FileHandler(FileBaseHandler):
|
class FileHandler(FileBaseHandler):
|
||||||
filePath = "/dev/null"
|
filePath = "/dev/null"
|
||||||
fileLength = 0
|
fileLength = 0
|
||||||
|
@ -62,66 +210,14 @@ class FileHandler(FileBaseHandler):
|
||||||
if self.checkAndDoRedirect():
|
if self.checkAndDoRedirect():
|
||||||
return
|
return
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header('Content-Length', self.fileLength)
|
self.sendContentHeaders(self.fileName, self.fileLength, self.startTime)
|
||||||
self.send_header('Last-Modified', self.startTime)
|
|
||||||
self.send_header('Content-Type', 'application/octet-stream')
|
|
||||||
self.send_header('Content-Disposition', 'attachment; filename="%s"' % self.fileName)
|
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
if self.checkAndDoRedirect():
|
if self.checkAndDoRedirect():
|
||||||
return
|
return
|
||||||
myfile = open(self.filePath, 'rb')
|
self.sendFile(self.filePath, self.fileLength, self.startTime)
|
||||||
|
|
||||||
# find out if this is a continuing download
|
|
||||||
fromto = None
|
|
||||||
if "Range" in self.headers:
|
|
||||||
cont = self.headers.get("Range").split("=")
|
|
||||||
if len(cont) > 1 and cont[0] == 'bytes':
|
|
||||||
fromto = cont[1].split('-')
|
|
||||||
if len(fromto) > 1:
|
|
||||||
if fromto[1] == '':
|
|
||||||
fromto[1] = self.fileLength-1
|
|
||||||
fromto[0] = int(fromto[0])
|
|
||||||
fromto[1] = int(fromto[1])
|
|
||||||
if fromto[0] >= self.fileLength or fromto[0] < 0 or fromto[1] >= self.fileLength or fromto[1]-fromto[0] < 0:
|
|
||||||
# oops, already done!
|
|
||||||
self.send_response(416)
|
|
||||||
self.send_header('Content-Range', 'bytes */%s' % self.fileLength)
|
|
||||||
self.end_headers()
|
|
||||||
return
|
|
||||||
# now we can wind the file *brrrrrr*
|
|
||||||
myfile.seek(fromto[0])
|
|
||||||
|
|
||||||
if fromto != None:
|
|
||||||
self.send_response(216)
|
|
||||||
self.send_header('Content-Range', 'bytes %s-%s/%s' % (fromto[0], fromto[1], self.fileLength))
|
|
||||||
self.send_header('Content-Length', fromto[1]-fromto[0]+1)
|
|
||||||
else:
|
|
||||||
self.send_response(200)
|
|
||||||
self.send_header('Content-Length', self.fileLength)
|
|
||||||
self.send_header('Content-Disposition', 'attachment; filename="%s"' % self.fileName)
|
|
||||||
self.send_header('Content-Type', 'application/octet-stream')
|
|
||||||
self.send_header('Content-Transfer-Encoding', 'binary')
|
|
||||||
self.end_headers()
|
|
||||||
block = self.getChunk(myfile, fromto)
|
|
||||||
while block:
|
|
||||||
try:
|
|
||||||
self.wfile.write(block)
|
|
||||||
except socket.error, e:
|
|
||||||
print "%s ABORTED transmission (Reason %s: %s)" % (self.client_address[0], e[0], e[1])
|
|
||||||
return
|
|
||||||
block = self.getChunk(myfile, fromto)
|
|
||||||
myfile.close()
|
|
||||||
print "%s finished downloading" % (self.client_address[0])
|
|
||||||
return
|
|
||||||
|
|
||||||
def getChunk(self, myfile, fromto):
|
|
||||||
if fromto and myfile.tell()+self.blockSize >= fromto[1]:
|
|
||||||
readsize = fromto[1]-myfile.tell()+1
|
|
||||||
else:
|
|
||||||
readsize = self.blockSize
|
|
||||||
return myfile.read(readsize)
|
|
||||||
|
|
||||||
class TarFileHandler(FileBaseHandler):
|
class TarFileHandler(FileBaseHandler):
|
||||||
target = None
|
target = None
|
||||||
|
@ -133,9 +229,7 @@ class TarFileHandler(FileBaseHandler):
|
||||||
if self.checkAndDoRedirect():
|
if self.checkAndDoRedirect():
|
||||||
return
|
return
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header('Last-Modified', getDateStrNow())
|
self.sendContentHeaders(self.fileName, -1)
|
||||||
self.send_header('Content-Type', 'application/octet-stream')
|
|
||||||
self.send_header('Content-Disposition', 'attachment; filename="%s"' % self.fileName)
|
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
|
@ -154,8 +248,7 @@ class TarFileHandler(FileBaseHandler):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header('Last-Modified', getDateStrNow())
|
self.sendContentHeaders(self.fileName, -1)
|
||||||
self.send_header('Content-Type', 'application/octet-stream')
|
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
block = True
|
block = True
|
||||||
|
@ -193,7 +286,143 @@ class TarFileHandler(FileBaseHandler):
|
||||||
return ".tar.gz"
|
return ".tar.gz"
|
||||||
elif TarFileHandler.compression == "bzip2":
|
elif TarFileHandler.compression == "bzip2":
|
||||||
return ".tar.bz2"
|
return ".tar.bz2"
|
||||||
raise ValueError("Unknown compression mode '%s'." % self.compression)
|
raise ValueError("Unknown compression mode '%s'." % TarFileHandler.compression)
|
||||||
|
|
||||||
|
|
||||||
|
class DirListingHandler(FileBaseHandler):
|
||||||
|
""" DOCUMENTATION MISSING """
|
||||||
|
|
||||||
|
targetDir = None
|
||||||
|
|
||||||
|
def do_HEAD(self):
|
||||||
|
self.getFileOrDirectory(head=True)
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
self.getFileOrDirectory(head=False)
|
||||||
|
|
||||||
|
def getFileOrDirectory(self, head=False):
|
||||||
|
""" Send file or directory index, depending on requested path """
|
||||||
|
path = self.getCleanPath()
|
||||||
|
|
||||||
|
if os.path.isdir(path):
|
||||||
|
if not self.path.endswith('/'):
|
||||||
|
self.send_response(301)
|
||||||
|
self.send_header("Location", self.path + '/')
|
||||||
|
self.end_headers()
|
||||||
|
else:
|
||||||
|
self.sendDirectoryListing(path, head)
|
||||||
|
elif os.path.isfile(path):
|
||||||
|
if head:
|
||||||
|
(response, length) = self.getFileLength(path)
|
||||||
|
if length < 0:
|
||||||
|
self.send_response(response)
|
||||||
|
self.end_headers()
|
||||||
|
else:
|
||||||
|
self.send_response(200)
|
||||||
|
self.sendContentHeaders(self, path, length)
|
||||||
|
self.end_headers()
|
||||||
|
else:
|
||||||
|
self.sendFile(path, head)
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def sendDirectoryListing(self, path, head):
|
||||||
|
""" Generate a directorylisting for path and send it """
|
||||||
|
header = """<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title>Index of %(path)s</title>
|
||||||
|
<style type="text/css">
|
||||||
|
a { text-decoration: none; color: #0000BB;}
|
||||||
|
a:visited { color: #000066;}
|
||||||
|
a:hover, a:focus, a:active { text-decoration: underline; color: #cc0000; text-indent: 5px; }
|
||||||
|
body { background-color: #eaeaea; padding: 20px 0; margin: 0; font: 400 13px/1.2em Arial, sans-serif; }
|
||||||
|
h1 { margin: 0 10px 12px 10px; font-family: Arial, sans-serif; }
|
||||||
|
div.content { background-color: white; border-color: #ccc; border-width: 1px 0; border-style: solid; padding: 10px 10px 15px 10px; }
|
||||||
|
td { padding-right: 15px; text-align: left; font-family: monospace; }
|
||||||
|
th { font-weight: bold; font-size: 115%%; padding: 0 15px 5px 0; text-align: left; }
|
||||||
|
.size { text-align: right; }
|
||||||
|
.footer { font: 12px monospace; color: #333; margin: 5px 10px 0; }
|
||||||
|
.footer, h1 { text-shadow: 0 1px 0 white; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of %(path)s</h1>
|
||||||
|
<div class="content">
|
||||||
|
<table summary="Directory Listing">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="name">Name</th>
|
||||||
|
<th class="lastModified">Last Modified</th>
|
||||||
|
<th class="size">Size</th>
|
||||||
|
<th class="type">Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
""" % {'path': posixpath.normpath(urllib.unquote(self.path))}
|
||||||
|
footer = """</tbody></table></div>
|
||||||
|
<div class="footer">servefile %(version)s</div>
|
||||||
|
</body>
|
||||||
|
</html>""" % {'version': __version__}
|
||||||
|
content = []
|
||||||
|
for item in [".."] + sorted(os.listdir(path)):
|
||||||
|
# create path to item
|
||||||
|
itemPath = os.path.join(path, item)
|
||||||
|
|
||||||
|
# try to stat file for size, last modified... continue on error
|
||||||
|
stat = None
|
||||||
|
try:
|
||||||
|
stat = os.stat(itemPath)
|
||||||
|
except IOError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Strings to display on directory listing
|
||||||
|
lastModifiedDate = datetime.datetime.fromtimestamp(stat.st_mtime)
|
||||||
|
lastModified = lastModifiedDate.strftime("%Y-%m-%d %H:%M")
|
||||||
|
fileSize = "%.1f%s" % self.convertSize(stat.st_size)
|
||||||
|
(fileType, _) = mimetypes.guess_type(itemPath)
|
||||||
|
if not fileType:
|
||||||
|
fileType = "-"
|
||||||
|
|
||||||
|
if os.path.isdir(itemPath):
|
||||||
|
item += "/"
|
||||||
|
fileType = "Directory"
|
||||||
|
content.append("""
|
||||||
|
<tr>
|
||||||
|
<td class="name"><a href="%s">%s</a></td>
|
||||||
|
<td class="last-modified">%s</td>
|
||||||
|
<td class="size">%s</td>
|
||||||
|
<td class="type">%s</td>
|
||||||
|
</tr>
|
||||||
|
""" % (urllib.quote(item), item, lastModified, fileSize, fileType))
|
||||||
|
|
||||||
|
listing = header + "\n".join(content) + footer
|
||||||
|
|
||||||
|
# write listing
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "text/html")
|
||||||
|
if head:
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
self.send_header("Content-Length", str(len(listing)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(listing)
|
||||||
|
|
||||||
|
def convertSize(self, size):
|
||||||
|
ext = None
|
||||||
|
for ext in "BKMGT":
|
||||||
|
if size < 1024.0:
|
||||||
|
break
|
||||||
|
size /= 1024.0
|
||||||
|
return (size, ext)
|
||||||
|
|
||||||
|
def getCleanPath(self):
|
||||||
|
urlPath = posixpath.normpath(urllib.unquote(self.path)).strip("/")
|
||||||
|
path = os.path.join(self.targetDir, urlPath)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -353,6 +582,7 @@ def catchSSLErrors(BaseSSLClass):
|
||||||
print "%s SSL Error: %s" % (self.client_address[0], e)
|
print "%s SSL Error: %s" % (self.client_address[0], e)
|
||||||
return X
|
return X
|
||||||
|
|
||||||
|
|
||||||
class SecureThreadedHTTPServer(ThreadedHTTPServer):
|
class SecureThreadedHTTPServer(ThreadedHTTPServer):
|
||||||
def __init__(self, pubKey, privKey, *args, **kwargs):
|
def __init__(self, pubKey, privKey, *args, **kwargs):
|
||||||
ThreadedHTTPServer.__init__(self, *args, **kwargs)
|
ThreadedHTTPServer.__init__(self, *args, **kwargs)
|
||||||
|
@ -373,6 +603,7 @@ class SecureThreadedHTTPServer(ThreadedHTTPServer):
|
||||||
def shutdown_request(self, request):
|
def shutdown_request(self, request):
|
||||||
request.shutdown()
|
request.shutdown()
|
||||||
|
|
||||||
|
|
||||||
class SecureHandler():
|
class SecureHandler():
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.connection = self.request
|
self.connection = self.request
|
||||||
|
@ -382,6 +613,7 @@ class SecureHandler():
|
||||||
class ServeFileException(Exception):
|
class ServeFileException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ServeFile():
|
class ServeFile():
|
||||||
""" Main class to manage everything. """
|
""" Main class to manage everything. """
|
||||||
|
|
||||||
|
@ -571,7 +803,7 @@ class ServeFile():
|
||||||
self.dirCreated = True
|
self.dirCreated = True
|
||||||
try:
|
try:
|
||||||
os.mkdir(self.target)
|
os.mkdir(self.target)
|
||||||
except IOError, OSError:
|
except (IOError, OSError):
|
||||||
raise ServeFileException("Error: Could not create directory '%s' for uploads." % (self.target,) )
|
raise ServeFileException("Error: Could not create directory '%s' for uploads." % (self.target,) )
|
||||||
else:
|
else:
|
||||||
raise ServeFileException("Error: Upload directory already exists and is a file.")
|
raise ServeFileException("Error: Upload directory already exists and is a file.")
|
||||||
|
@ -579,12 +811,8 @@ class ServeFile():
|
||||||
FilePutter.maxUploadSize = self.maxUploadSize
|
FilePutter.maxUploadSize = self.maxUploadSize
|
||||||
handler = FilePutter
|
handler = FilePutter
|
||||||
elif self.serveMode == self.MODE_LISTDIR:
|
elif self.serveMode == self.MODE_LISTDIR:
|
||||||
try:
|
handler = DirListingHandler
|
||||||
os.chdir(self.target)
|
handler.targetDir = self.target
|
||||||
except OSError:
|
|
||||||
raise ServeFileException("Error: Could not change directory to '%s'." % self.target)
|
|
||||||
handler = SimpleHTTPServer.SimpleHTTPRequestHandler
|
|
||||||
|
|
||||||
|
|
||||||
if self.auth:
|
if self.auth:
|
||||||
# do authentication
|
# do authentication
|
||||||
|
@ -601,6 +829,7 @@ class ServeFile():
|
||||||
handler = AlreadySecuredHandler
|
handler = AlreadySecuredHandler
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationHandler():
|
class AuthenticationHandler():
|
||||||
# base64 encoded user:password string for authentication
|
# base64 encoded user:password string for authentication
|
||||||
authString = None
|
authString = None
|
||||||
|
@ -633,6 +862,7 @@ class AuthenticationHandler():
|
||||||
self.send_response(401)
|
self.send_response(401)
|
||||||
self.send_header("WWW-Authenticate", "Basic realm=\"%s\"" % self.realm)
|
self.send_header("WWW-Authenticate", "Basic realm=\"%s\"" % self.realm)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Serve a single file via HTTP.')
|
parser = argparse.ArgumentParser(description='Serve a single file via HTTP.')
|
||||||
parser.add_argument('--version', action='version', version='%(prog)s ' + __version__)
|
parser.add_argument('--version', action='version', version='%(prog)s ' + __version__)
|
||||||
|
@ -715,7 +945,7 @@ def main():
|
||||||
if args.compression in TarFileHandler.compressionMethods:
|
if args.compression in TarFileHandler.compressionMethods:
|
||||||
compression = args.compression
|
compression = args.compression
|
||||||
else:
|
else:
|
||||||
print "Error: Compression mode '%s' is unknown." % self.compression
|
print "Error: Compression mode '%s' is unknown." % TarFileHandler.compression
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
mode = None
|
mode = None
|
||||||
|
@ -747,6 +977,7 @@ def main():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print "Good bye."
|
print "Good bye."
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue