Code cleanup
This commit is contained in:
parent
a0e97c7de4
commit
d9ca9b128c
59
servefile
59
servefile
|
@ -108,6 +108,10 @@ class FileHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
return myfile.read(readsize)
|
return myfile.read(readsize)
|
||||||
|
|
||||||
class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
""" Simple HTTP Server which allows uploading to a specified directory
|
||||||
|
either via multipart/form-data or POST/PUT requests containing the file.
|
||||||
|
"""
|
||||||
|
|
||||||
targetDir = "unknown"
|
targetDir = "unknown"
|
||||||
uploadPage = """
|
uploadPage = """
|
||||||
<!docype html>
|
<!docype html>
|
||||||
|
@ -122,33 +126,54 @@ class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
|
""" Answer every GET request with the upload form """
|
||||||
self.sendResponse(200, self.uploadPage)
|
self.sendResponse(200, self.uploadPage)
|
||||||
|
|
||||||
def do_POST(self):
|
def do_POST(self):
|
||||||
env = os.environ
|
""" Upload a file via POST
|
||||||
env['REQUEST_METHOD'] = "POST"
|
|
||||||
|
If the content-type is multipart/form-data it checks for the file
|
||||||
|
field and saves the data to disk. For other content-types it just
|
||||||
|
calls do_PUT and is handled as such except for the http response code.
|
||||||
|
|
||||||
|
Files can be uploaded with wget --post-file=path/to/file <url> or
|
||||||
|
curl -X POST -d @file <url> .
|
||||||
|
"""
|
||||||
ctype = self.headers.getheader('content-type')
|
ctype = self.headers.getheader('content-type')
|
||||||
|
|
||||||
|
# check for multipart/form-data.
|
||||||
if not (ctype and ctype.lower().startswith("multipart/form-data")):
|
if not (ctype and ctype.lower().startswith("multipart/form-data")):
|
||||||
# not a normal multipart request ==> handle as PUT request
|
# not a normal multipart request ==> handle as PUT request
|
||||||
self.do_PUT()
|
return self.do_PUT(fromPost=True)
|
||||||
return
|
|
||||||
self.sendResponse(400, "Request was not a multipart request. If you want to upload data with curl, do a PUT request, e.g. curl -X PUT -d @file http://ip:port/your-filename")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
# create FieldStorage object for multipart parsing
|
||||||
|
env = os.environ
|
||||||
|
env['REQUEST_METHOD'] = "POST"
|
||||||
|
fstorage = cgi.FieldStorage(fp=self.rfile, headers=self.headers, environ=env)
|
||||||
if not "file" in fstorage:
|
if not "file" in fstorage:
|
||||||
self.sendResponse(400, "No file found in request.")
|
self.sendResponse(400, "No file found in request.")
|
||||||
return
|
return
|
||||||
fstorage = cgi.FieldStorage(fp=self.rfile, headers=self.headers, environ=env)
|
|
||||||
destFileName = self.getTargetName(fstorage["file"].filename)
|
destFileName = self.getTargetName(fstorage["file"].filename)
|
||||||
if destFileName == "":
|
if destFileName == "":
|
||||||
self.sendResponse(400, "Filename was empty")
|
self.sendResponse(400, "Filename was empty or invalid")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# write file down to disk, send an
|
||||||
target = open(destFileName, "w")
|
target = open(destFileName, "w")
|
||||||
target.write(fstorage["file"].file.read())
|
target.write(fstorage["file"].file.read())
|
||||||
target.close()
|
target.close()
|
||||||
self.sendResponse(200, "OK!")
|
self.sendResponse(200, "OK!")
|
||||||
|
|
||||||
def do_PUT(self):
|
def do_PUT(self, fromPost=False):
|
||||||
|
""" Upload a file via PUT
|
||||||
|
|
||||||
|
The request path is used as filename, so uploading a file to the url
|
||||||
|
http://host:8080/testfile will cause the file to be named testfile. If
|
||||||
|
no filename is given, a random name will be generated.
|
||||||
|
|
||||||
|
Files can be uploaded with e.g. curl -X POST -d @file <url> .
|
||||||
|
"""
|
||||||
length = 0
|
length = 0
|
||||||
try:
|
try:
|
||||||
length = int(self.headers['Content-Length'])
|
length = int(self.headers['Content-Length'])
|
||||||
|
@ -160,21 +185,29 @@ class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
|
||||||
fileName = urllib.unquote(self.path)
|
fileName = urllib.unquote(self.path)
|
||||||
if fileName == "/":
|
if fileName == "/":
|
||||||
|
# if no filename was given we have to generate one
|
||||||
fileName = str(time.time())
|
fileName = str(time.time())
|
||||||
|
|
||||||
cleanFileName = self.getTargetName(fileName)
|
cleanFileName = self.getTargetName(fileName)
|
||||||
if cleanFileName == "":
|
if cleanFileName == "":
|
||||||
self.sendResponse(400, "Filename was invalid")
|
self.sendResponse(400, "Filename was invalid")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Sometimes clients want to be told to continue with their transfer
|
||||||
if self.headers.getheader("Expect") == "100-continue":
|
if self.headers.getheader("Expect") == "100-continue":
|
||||||
self.send_response(100)
|
self.send_response(100)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
print "Saving uploaded file to %s" % cleanFileName
|
print "Saving uploaded file to %s" % cleanFileName
|
||||||
target = open(cleanFileName, "w")
|
target = open(cleanFileName, "w")
|
||||||
target.write(self.rfile.read(int(self.headers['Content-Length'])))
|
target.write(self.rfile.read(int(self.headers['Content-Length'])))
|
||||||
target.close()
|
target.close()
|
||||||
self.sendResponse(201, "OK!")
|
self.sendResponse(fromPost and 200 or 201, "OK!")
|
||||||
|
|
||||||
def sendResponse(self, code, msg):
|
def sendResponse(self, code, msg):
|
||||||
|
""" Send a HTTP response with code and msg, providing the correct
|
||||||
|
content-length.
|
||||||
|
"""
|
||||||
self.send_response(code)
|
self.send_response(code)
|
||||||
self.send_header('Content-Type', 'text/html')
|
self.send_header('Content-Type', 'text/html')
|
||||||
self.send_header('content-Length', str(len(msg)))
|
self.send_header('content-Length', str(len(msg)))
|
||||||
|
@ -182,6 +215,12 @@ class FilePutter(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
self.wfile.write(msg)
|
self.wfile.write(msg)
|
||||||
|
|
||||||
def getTargetName(self, fname):
|
def getTargetName(self, fname):
|
||||||
|
""" Generate a clean and secure filename.
|
||||||
|
|
||||||
|
This function takes a filename and strips all the slashes out of it.
|
||||||
|
If the file already exists in the target directory, a (NUM) will be
|
||||||
|
appended, so no file will be overwritten.
|
||||||
|
"""
|
||||||
cleanFileName = fname.replace("/", "")
|
cleanFileName = fname.replace("/", "")
|
||||||
if cleanFileName == "":
|
if cleanFileName == "":
|
||||||
return ""
|
return ""
|
||||||
|
|
Loading…
Reference in New Issue