You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
5.6KB

  1. #!/usr/bin/python
  2. import sys
  3. # Python 3.
  4. try:
  5. from http.server import HTTPServer
  6. from http.server import SimpleHTTPRequestHandler
  7. # Python 2.
  8. except ImportError:
  9. from BaseHTTPServer import HTTPServer
  10. from SimpleHTTPServer import SimpleHTTPRequestHandler
  11. import glob
  12. import os
  13. import base64
  14. class HTTPRequestHandler(SimpleHTTPRequestHandler):
  15. # Implementation.
  16. def do_GET(self):
  17. tool.process(self)
  18. def do_POST(self):
  19. tool.process(self)
  20. def listFiles(path):
  21. items = []
  22. fileNames = glob.glob(path + "/*")
  23. fileNames.sort()
  24. for fileName in fileNames:
  25. file = { }
  26. # Path.
  27. file["path"] = os.path.basename(fileName)
  28. # Type.
  29. file["type"] = None
  30. if (os.path.isdir(fileName)):
  31. file["type"] = "dir"
  32. elif (os.path.isfile(fileName)):
  33. file["type"] = "file";
  34. items.append(file)
  35. return items
  36. def fileListToJSON(fileList):
  37. out = ""
  38. for file in fileList:
  39. if (len(out)):
  40. out += ","
  41. out += "{\"path\":\"%s\",\"type\":\"%s\"}" % (file["path"], file["type"])
  42. return "[" + out + "]"
  43. def jsonToPathContents(json):
  44. # This function takes `abc` and `def` from string of the following format:
  45. # `{"path": "abc", "contents": "def"}`.
  46. parts = json.split('"')
  47. if (len(parts) == 9):
  48. return (parts[3], parts[7])
  49. return (None, None)
  50. class Tool(object):
  51. # Configuration.
  52. def __init__(self, arguments):
  53. self.arguments = arguments
  54. self.PORT = 8000
  55. self.serverHost = ""
  56. # Main execution sequence.
  57. def run(self):
  58. self.validateArguments()
  59. self.parseArguments()
  60. self.printArguments()
  61. self.runServer()
  62. # Implementation.
  63. def validateArguments(self):
  64. if (len(self.arguments) < 2):
  65. print(
  66. (
  67. "Usage: %s DIR [PORT]"
  68. "\n\n"
  69. "\tPORT defaults to 8000"
  70. ) % self.arguments[0]
  71. )
  72. sys.exit(1)
  73. def printArguments(self):
  74. print("DIR: '%s'" % self.DIR)
  75. print("PORT: '%s'" % self.PORT)
  76. def parseArguments(self):
  77. self.DIR = self.arguments[1]
  78. # Override default port if specified.
  79. if (len(self.arguments) >= 3):
  80. self.PORT = self.arguments[2]
  81. def runServer(self):
  82. addr = (self.serverHost, int(self.PORT))
  83. self.httpd = HTTPServer(addr, HTTPRequestHandler)
  84. self.httpd.serve_forever()
  85. def process(self, requestHandler):
  86. if (requestHandler.path == "/path"):
  87. self.processPath(requestHandler)
  88. if (requestHandler.path == "/list"):
  89. self.processFileList(requestHandler)
  90. if (requestHandler.path == "/read"):
  91. self.processReadFile(requestHandler)
  92. if (requestHandler.path == "/write"):
  93. self.processWriteFile(requestHandler)
  94. def processPath(self, request):
  95. request.send_response(200)
  96. request.send_header("Access-Control-Allow-Origin", "*")
  97. request.end_headers()
  98. data = self.DIR.encode()
  99. request.wfile.write(data)
  100. def processFileList(self, request):
  101. request.send_response(200)
  102. request.send_header("Access-Control-Allow-Origin", "*")
  103. request.end_headers()
  104. size = int(request.headers["Content-Length"])
  105. path = request.rfile.read(size)
  106. path = path.decode()
  107. absPath = "%s/%s" % (self.DIR, path)
  108. fileList = listFiles(absPath)
  109. fileListJSON = fileListToJSON(fileList)
  110. data = fileListJSON.encode()
  111. request.wfile.write(data)
  112. def processReadFile(self, request):
  113. request.send_response(200)
  114. request.send_header("Access-Control-Allow-Origin", "*")
  115. request.end_headers()
  116. size = int(request.headers["Content-Length"])
  117. path = request.rfile.read(size)
  118. path = path.decode()
  119. absPath = "%s/%s" % (self.DIR, path)
  120. print("Reading '%s'" % absPath)
  121. f = open(absPath, "r")
  122. contents = f.read()
  123. f.close()
  124. # Perform Python3 compatible encoding.
  125. # If this crashes for Python2 (when there are non-ASCII symbols),
  126. # it's probably fine for `contents` to stay intact.
  127. try:
  128. contents = contents.encode()
  129. except:
  130. pass
  131. request.wfile.write(contents)
  132. def processWriteFile(self, request):
  133. request.send_response(200)
  134. request.send_header("Access-Control-Allow-Origin", "*")
  135. request.end_headers()
  136. size = int(request.headers["Content-Length"])
  137. data = request.rfile.read(size)
  138. # Extract path and contents.
  139. (path, contents) = jsonToPathContents(data)
  140. if ((path is None) or (contents is None)):
  141. print("ERROR Writing failed due to corrupt incoming data")
  142. # Try to convert using pre-Python2.4 API.
  143. try:
  144. contents = base64.decodestring(contents)
  145. # Resort to Python2.4+ API.
  146. except:
  147. contents = base64.b64decode(contents)
  148. # Perform Python3 compatible DEcoding.
  149. # If this crashes for Python2 (when there are non-ASCII symbols),
  150. # it's probably fine for `contents` to stay intact.
  151. try:
  152. contents = contents.decode()
  153. except:
  154. pass
  155. # Write.
  156. absPath = "%s/%s" % (self.DIR, path)
  157. print("Writing '%s'" % absPath)
  158. f = open(absPath, "w")
  159. f.write(contents)
  160. f.close()
  161. tool = Tool(sys.argv)
  162. tool.run()