Created
June 7, 2017 04:37
-
-
Save arthurafarias/c331eac1b2fec0aa34f8b478cfa5c5bd to your computer and use it in GitHub Desktop.
Atividade de Redes de Computadores - Questão 01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
"""HTTP Daemon. | |
Usage: | |
httpd [-p=<port> | --port=<port>] [-r=<path> | --root=<path> ] | |
httpd (-h | --help) | |
Options: | |
-h --help Show this screen. | |
-p --port=<port> Specify port number [default: 8888 ]. | |
-r --root=<path> Specify document root location [default: ./public ]. | |
""" | |
import os | |
import socket | |
import threading | |
import SocketServer | |
import time | |
import pprint | |
import re | |
import traceback | |
from docopt import docopt | |
from StringIO import StringIO | |
global document_root | |
# Classe de exceção específica para eventos do servidor | |
class HTTPException(Exception): | |
def __init__(self, code, message): | |
self.code = code | |
self.message = message | |
self.response_message = "HTTP/1.0 %s %s\r\n" % (str(self.code), self.message) | |
# Classe que implementa uma interface Stream que lida com requisições TCP | |
class TCPRequestHandler(SocketServer.StreamRequestHandler): | |
# Método chamado toda vez que há uma nova requisição TCP | |
def handle(self): | |
try: | |
# As requisições TCP recebidas pelo servidor são colocadas em um | |
# apontador para um arquivo. Aqui, faz-se a leitura linha por linha | |
# e remove-se os excessos de espações antes e depois. | |
self.data = self.rfile.readline().strip() | |
# Faz-se uma filtragem por expressão regular, seleciona-se apenas | |
# requisições do tipo GET. | |
self.data_parsed = re.search("^GET (.*) HTTP\/(.*)$", self.data) | |
# rd_str -> Requested Document String | |
# Constrói o caminho em forma de string do documento solicitado. | |
rd_str = os.path.realpath(document_root.rstrip() + self.data_parsed.group(1)) | |
# Testa para ver se o documento solicitado está dentro do diretório | |
# raiz do servidor. | |
if not rd_str.startswith(document_root) : | |
raise HTTPException(403, "Access Denied") | |
# Se foi requisitado um diretório, tenta-se abrir o arquivo | |
# index.html | |
if (os.path.isdir(rd_str)): | |
f = open(rd_str + "/index.html" ) | |
# Caso não seja um diretório, tenta-se abrir o caminho diretamente | |
else: | |
f = open(rd_str) | |
# Constrói-se a mensagem de resposta HTTP | |
self.wfile.write("HTTP/1.0 200 OK\r\n") | |
self.wfile.write("Connection: close\r\n") | |
self.wfile.write("Content-Type: text/html\r\n\r\n") | |
# Envia-se o arquivo aberto | |
for l in f: | |
self.wfile.write(l) | |
self.wfile.write("\r\n") | |
# Caso ocorra alguma exceção, de entrada e saída ou de atributo. | |
except (AttributeError, IOError) as e: | |
# retornar ao cliente o erro 404 | |
self.wfile.write("HTTP/1.0 404 Not Found\r\n") | |
# Se foi disparada uma HTTPException, envia-se a mensagem de erro | |
# correspondente. | |
except (HTTPException) as e: | |
self.wfile.write(e.response_message) | |
# Qualquer outro erro produzido durante a execução do método que lida | |
# com requisições, dentro do bloco "try", envia-se um sinal de erro 500 | |
# "Internal Server Error". | |
except Exception as e: | |
self.wfile.write("HTTP/1.0 500 Internal Server Error\r\n") | |
traceback.print_exc() | |
class TCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): | |
pass | |
if __name__ == "__main__": | |
# Interpretação dos parâmetros em linha de comand | |
docopt_args = docopt | |
( | |
__doc__, | |
version="Simple Proof of concept HTTP Server v0.2" | |
) | |
# Obtendo o Host e a porta em que o servidor HTTP escutará conexões | |
HOST, PORT = '0.0.0.0', int(docopt_args.get("--port")) | |
# Obtendo o diretório raiz onde o servidor servirá páginas estáticas | |
document_root = os.path.realpath(docopt_args.get("--root")).strip() | |
# Habilitando reutilização de portas | |
TCPServer.allow_reuse_address = True | |
# Criando objeto a partir da classe TCPServer que implementa um servidor TCP | |
# e os métodos necessários à colocação do processo em uma "Thread". | |
server = TCPServer((HOST, PORT), TCPRequestHandler) | |
# Criando a "Thread" do servidor | |
server_thread = threading.Thread(target=server.serve_forever) | |
# Configurando a "Thread" para funcionar em segundo plano | |
server_thread.daemon = True | |
try: | |
# Inicializa a "Thread" | |
server_thread.start() | |
# Imprime informações na saída padrão do sistema | |
print "Server loop running in thread:", server_thread.name | |
# Começa a iterar infinitamente esperando uma noa requisição | |
while True: time.sleep(100) | |
# Espera por exceções do tipo Interrupção do teclado e sinais do sistema | |
# operacional | |
except (KeyboardInterrupt, SystemExit): | |
# Para a "Thread" | |
server_thread.stop() | |
# Desliga o servidor | |
server.shutdown() | |
# Fecha as conexões | |
server.server_close() | |
# Sai do programa | |
exit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment