import http.server import mimetypes import os import urllib.parse import random import sys sys.path.append('C:\\git\\else\\Bytestring') import bytestring sys.path.append('C:\\git\\else\\Ratelimiter') import ratelimiter f = open('favicon.png', 'rb') FAVI = f.read() f.close() CWD = os.getcwd() # The paths which the user may access # Attempting to access anything outside will 403 OKAY_PATHS = set(x.lower() for x in ['/files', '/favicon.ico']) OPENDIR_TEMPLATE = ''' {entries}
''' class Multipart: def __init__(stream, boundary): self.parts = [] class Path: def __init__(self, path): path = path.replace('\\', '/') if len(path) == 0 or path[0] != '/': path = '/' + path self.path = path def __repr__(self): return 'Path(%s)' % self.path def __str__(self): return self.path def anchor(self, display_name=None): if display_name is None: display_name = self.basename if self.is_dir: # Folder emoji icon = '\U0001F4C1' else: # Diamond emoji, because there's not one for files. icon = '\U0001F48E' return '{icon} {display}'.format(full=self.path, icon=icon, display=display_name) @property def basename(self): return os.path.basename(self.path) @property def is_dir(self): return os.path.isdir(self.os_path) @property def os_path(self): abspath = os.path.join(CWD, self.relative_path) #print(abspath) return abspath @property def parent(self): parts = self.path.split('/')[:-1] parts = '/'.join(parts) return Path(parts) @property def relative_path(self): return self.path.lstrip('/') @property def size(self): if self.is_dir: return -1 return os.path.getsize(self.os_path) def table_row(self, display_name=None, shaded=False): form = '{anchor}{size}' bg = 'ddd' if shaded else 'fff'; size = bytestring.bytestring(self.size) if self.size != -1 else '' row = form.format(bg=bg, anchor=self.anchor(display_name=display_name), size=size) return row class RequestHandler(http.server.BaseHTTPRequestHandler): def write(self, string): if isinstance(string, str): string = string.encode('utf-8') self.wfile.write(string) def read_filebytes(self, path): #print(path) if os.path.isfile(path.relative_path): f = open(path.relative_path, 'rb') fr = f.read() f.close() return fr if os.path.isdir(path.relative_path): text = generate_opendir(path) text = text.encode('utf-8') return text self.send_error(404) return bytes() def do_GET(self): #print(dir(self)) path = self.path.lower() path = urllib.parse.unquote(path).rstrip('/') error = path_validation(path) if error: self.send_error(*error) return path = Path(path) self.send_response(200) mime = mimetypes.guess_type(path.path)[0] if mime is not None: #print(mime) self.send_header('Content-type', mime) self.end_headers() d = self.read_filebytes(path) self.write(d) # def do_POST(self): # path = self.path.lower() # path = urllib.parse.unquote(path).rstrip('/') # error = path_validation(path) # if error: # self.send_error(*error) # return # path = Path(path) # content_type = self.headers.get('Content-Type', '') # if not any (req in content_type for req in ['multipart/form-data', 'boundary=']): # self.send_error(400, 'Bad request') # return # boundary = content_type.split('boundary=')[1] # boundary = boundary.split(';')[0] # boundary = boundary.strip() # print('B:', self.headers.get_boundary()) # print('F:', self.headers.get_filename()) # incoming_size = int(self.headers.get('Content-Length', 0)) # received_bytes = 0 # remaining_bytes = incoming_size # while remaining_bytes > 0: # chunk_size = min(remaining_bytes, 16*1024) # chunk = self.rfile.read(chunk_size) # remaining_bytes -= chunk_size # received_bytes += chunk_size # print(chunk) # self.send_response(200) # self.send_header('Content-Type', 'text/html') # self.end_headers() # print(dir(self.request)) # self.write('Thanks') def generate_opendir(path): print('Listdir:', path) items = os.listdir(path.relative_path) items = [os.path.join(path.relative_path, f) for f in items] directories = [] files = [] for item in items: #item = item.lstrip('/') if os.path.isdir(item): directories.append(item) else: files.append(item) directories.sort(key=str.lower) files.sort(key=str.lower) files = directories + files #print(files) files = [Path(f) for f in files] entries = [] if not any(okay == path.path for okay in OKAY_PATHS): # If the path actually equals a okay_path, then we shouldn't # let them step up because that would be outisde the okay area. entries.append(path.parent.table_row(display_name='up')) shaded = True for f in files: entry = f.table_row(shaded=shaded) entries.append(entry) shaded = not shaded entries = '\n'.join(entries) text = OPENDIR_TEMPLATE.format(entries=entries) return text def generate_random_filename(original_filename='', length=8): import random bits = length * 4 bits = random.getrandbits(bits) identifier = '{:x}'.format(bits).rjust(length, '0') return identifier def path_validation(path): if '..' in path: return (403, 'I\'m not going to play games with you.') if not any(path.startswith(okay) for okay in OKAY_PATHS): self.send_error(403, 'Stop that!') return server = http.server.HTTPServer(('', 32768), RequestHandler) print('server starting') server.serve_forever()