Простой веб-сервер с directories walk - Python

Узнай цену своей работы

Формулировка задачи:

В общем, на просторах инета уже многовато поискал информации, но сложновато все структуризировать и создать свой план действия. Смотрим скриншот, что мне нужно. Дальше я бы хотел услышать как мне лучше всего это сделать. Возможно у вас даже есть ссылки на готовое, чтоб можно было засесть и разбирать по строчке сам код.

Решение задачи: «Простой веб-сервер с directories walk»

textual
Листинг программы
import time,os,sys
import socket
import mimetypes
from urllib.parse import quote,unquote
from subprocess import Popen
#для автоопределения кодировки файлов
from chardet.universaldetector import UniversalDetector
 
ENCODING = "utf-8"
 
 
def read_file(filepath,encoding):
    result = None
    detector = UniversalDetector()
    detector.reset()
    
    for line in open(filepath, 'rb'):
        detector.feed(line)
        if detector.done: break
    detector.close()
    encoding = detector.result.get('encoding') or encoding
    
    print("DETECT:",encoding)
    
    try:
        with open(filepath,encoding=encoding) as f:
            result = f.read()
    except:
        pass
    return result,encoding
 
def generate_html(root):
    
    answer = """<!DOCTYPE html>"""
    answer += """<html><head><title>%s</title>""" % root
    answer += """</head><body><h1>[%s]</h1><ul>"""  % root
    format = """
    <li><a  href='javascript: document.location.href=
"{proto}://{server}:{port}/{relpath}";'>{name}</a></li>
"""
    
    # сортировка файлов и директорий - первыми идут каталоги
    dirs  = []
    files = []
    for name in os.listdir(root):
        if os.path.isdir(os.path.join(root,name)):
            dirs.append(name.upper() + "/")
        else:
            files.append(name)
    
    dirs.sort()
    files.sort()
    dirs.extend(files)
    
    for name in dirs: 
        relpath = name                                              
        if root != ROOT:                                            
            relpath =  os.path.join(root.replace(ROOT,""),name)
        
        answer += format.format(proto="http",
                                server=SERVER, 
                                port=PORT,
                                root=root,
                                name=name,
                                relpath=quote(relpath.replace('\\','/').lstrip('/')))
    
    answer += """</ul></body></html>"""
    return answer
 
def send_answer(conn, 
                method="GET", 
                protocol = "HTTP/1.1", 
                status="200 OK", 
                charset="utf-8",
                typ="text/plain", 
                data=""):
    
    data = data.encode(charset)
    headers = [
        "{} {} {}".format(method, protocol, status),
        "Server: %s" % "simplehttp",
        "Connection: %s" % "close",
        "Content-Type: %s; charset=%s" % (typ,charset),
        "Content-Length: %s" % len(data),
       ]
    print('-' * 10) 
    print("RESPONSE:")
    for header in headers:
        conn.send(header.encode(ENCODING) + b"\r\n")     
        print(header)
    
    conn.send(b"\r\n") # после пустой строки в HTTP начинаются данные
    conn.send(data)
    
    
def route(conn, addr):# обработка соединения в отдельной функции
    data = b""
    
    while not b"\r\n" in data: # ждём первую строку
        tmp = conn.recv(1024)
        if not tmp:   # сокет закрыли, пустой объект
            break
        else:
            data += tmp
    
    if not data:      # данные не пришли
        return        # не обрабатываем
        
    udata = data.decode(ENCODING)
    print('-' * 10) 
    print('REQUEST:')
    print(udata.split("\r\n\r\n")[0]) 
    
    # берём первую строку из клиентского запроса
    udata = udata.split("\r\n", 1)[0]
   
    # разбиваем по пробелам 
    method, address, protocol = udata.split(" ", 2)
    #print(method, address, protocol)
   
    filepath = os.path.join(ROOT,address.strip('/').replace('/','\\'))
    typ,enc = mimetypes.guess_type(filepath)
    filepath = unquote(filepath)
    print('-'* 10)
    print(filepath,typ)
    
    if address == "/":
        answer = generate_html(ROOT)
        return send_answer(conn, 
                            typ="text/html",
                            charset=ENCODING,
                            data=answer)
    else:                        
    
        if os.path.exists(filepath):
            if os.path.isdir(filepath):
                answer = generate_html(filepath) 
                send_answer(conn, 
                            typ="text/html", 
                            charset=ENCODING,
                            data=answer)
                
            # если файл имеет читабельное текстовое содержимое - выводим его
            elif typ == "text/plain":
                text = None
                error = 'None'
                try:
                    text,charset =  read_file(filepath,encoding=ENCODING)
                except Exception as err:        
                    error = str(err)
                
                if text is not None:
                    send_answer(conn, typ=typ ,charset=charset, data=text)
                else:
                    send_answer(conn, 
                            status="500 Internal Server Error",
                            data= "|".join([error,filepath]))
            # если файл не типа text/plain        
            else:
                # пробуем открыть его в программе по умолчанию
                Popen(filepath,shell=True)
                # генерируем заново список файлов в этом каталоге
                answer = generate_html(os.path.dirname(filepath)) 
                send_answer(conn, 
                            typ="text/html",
                            charset=ENCODING, 
                            data=answer)
        # если файла не существует           
        else:
            send_answer(conn, 
                        status="404 Not Found", 
                        data="File not Found:{}".format(filepath)
                        )
            
    
def main(server,port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((server, port))
    sock.listen(5)
 
    try:
        while 1: 
            conn, addr = sock.accept()
            print('-' * 10)
            print("Новое подключение: " + addr[0])
            
            try:
                route(conn, addr)
            
            except Exception as err:
                print(err)
                send_answer(conn, "500 Internal Server Error", data=str(err))
            
            finally:
                # закрываем сокет клиентского подключения
                conn.close()
    finally: 
        sock.close()
 
    
#--------------------------------------------------
if __name__ == "__main__":
    SERVER,PORT = "localhost",8080
    # корневая директория, которая будет доступна по адресу http://localhost:8080
    ROOT = os.path.dirname(__file__)
    
    main(SERVER,PORT)

Оцени полезность:

13   голосов , оценка 4.077 из 5
Похожие ответы