Простой веб-сервер с 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)