diff --git a/lfsa/lfsa-201905.py b/lfsa/lfsa-201905.py new file mode 100755 index 0000000..6381891 --- /dev/null +++ b/lfsa/lfsa-201905.py @@ -0,0 +1,183 @@ +#!/usr/bin/python + +import sys +# Python 3. +try: + from http.server import HTTPServer + from http.server import SimpleHTTPRequestHandler +# Python 2. +except ImportError: + from BaseHTTPServer import HTTPServer + from SimpleHTTPServer import SimpleHTTPRequestHandler +import glob +import os +import base64 + +class HTTPRequestHandler(SimpleHTTPRequestHandler): + # Implementation. + def do_GET(self): + tool.process(self) + def do_POST(self): + tool.process(self) + +def listFiles(path): + items = [] + + fileNames = glob.glob(path + "/*") + fileNames.sort() + for fileName in fileNames: + file = { } + # Path. + file["path"] = os.path.basename(fileName) + # Type. + file["type"] = None + if (os.path.isdir(fileName)): + file["type"] = "dir" + elif (os.path.isfile(fileName)): + file["type"] = "file"; + + items.append(file) + + return items +def fileListToJSON(fileList): + out = "" + for file in fileList: + if (len(out)): + out += "," + out += "{\"path\":\"%s\",\"type\":\"%s\"}" % (file["path"], file["type"]) + return "[" + out + "]" +def jsonToPathContents(json): + # This function takes `abc` and `def` from string of the following format: + # `{"path": "abc", "contents": "def"}`. + parts = json.split('"') + if (len(parts) == 9): + return (parts[3], parts[7]) + return (None, None) + +class Tool(object): + # Configuration. + def __init__(self, arguments): + self.arguments = arguments + self.PORT = 8000 + self.serverHost = "" + # Main execution sequence. + def run(self): + self.validateArguments() + self.parseArguments() + self.printArguments() + self.runServer() + # Implementation. + def validateArguments(self): + if (len(self.arguments) < 2): + print( + ( + "Usage: %s DIR [PORT]" + "\n\n" + "\tPORT defaults to 8000" + ) % self.arguments[0] + ) + sys.exit(1) + + def printArguments(self): + print("DIR: '%s'" % self.DIR) + print("PORT: '%s'" % self.PORT) + def parseArguments(self): + self.DIR = self.arguments[1] + # Override default port if specified. + if (len(self.arguments) >= 3): + self.PORT = self.arguments[2] + def runServer(self): + addr = (self.serverHost, int(self.PORT)) + self.httpd = HTTPServer(addr, HTTPRequestHandler) + self.httpd.serve_forever() + def process(self, requestHandler): + if (requestHandler.path == "/path"): + self.processPath(requestHandler) + if (requestHandler.path == "/list"): + self.processFileList(requestHandler) + if (requestHandler.path == "/read"): + self.processReadFile(requestHandler) + if (requestHandler.path == "/write"): + self.processWriteFile(requestHandler) + def processPath(self, request): + request.send_response(200) + request.send_header("Access-Control-Allow-Origin", "*") + request.end_headers() + + data = self.DIR.encode() + request.wfile.write(data) + def processFileList(self, request): + request.send_response(200) + request.send_header("Access-Control-Allow-Origin", "*") + request.end_headers() + + size = int(request.headers["Content-Length"]) + path = request.rfile.read(size) + path = path.decode() + absPath = "%s/%s" % (self.DIR, path) + + fileList = listFiles(absPath) + fileListJSON = fileListToJSON(fileList) + data = fileListJSON.encode() + request.wfile.write(data) + def processReadFile(self, request): + request.send_response(200) + request.send_header("Access-Control-Allow-Origin", "*") + request.end_headers() + + size = int(request.headers["Content-Length"]) + path = request.rfile.read(size) + path = path.decode() + absPath = "%s/%s" % (self.DIR, path) + print("Reading '%s'" % absPath) + + f = open(absPath, "r") + contents = f.read() + f.close() + + # Perform Python3 compatible encoding. + # If this crashes for Python2 (when there are non-ASCII symbols), + # it's probably fine for `contents` to stay intact. + try: + contents = contents.encode() + except: + pass + + request.wfile.write(contents) + def processWriteFile(self, request): + request.send_response(200) + request.send_header("Access-Control-Allow-Origin", "*") + request.end_headers() + + size = int(request.headers["Content-Length"]) + data = request.rfile.read(size) + + # Extract path and contents. + (path, contents) = jsonToPathContents(data) + if ((path is None) or (contents is None)): + print("ERROR Writing failed due to corrupt incoming data") + + # Try to convert using pre-Python2.4 API. + try: + contents = base64.decodestring(contents) + # Resort to Python2.4+ API. + except: + contents = base64.b64decode(contents) + + # Perform Python3 compatible DEcoding. + # If this crashes for Python2 (when there are non-ASCII symbols), + # it's probably fine for `contents` to stay intact. + try: + contents = contents.decode() + except: + pass + + # Write. + absPath = "%s/%s" % (self.DIR, path) + print("Writing '%s'" % absPath) + f = open(absPath, "w") + f.write(contents) + f.close() + +tool = Tool(sys.argv) +tool.run()