Skip to content

Instantly share code, notes, and snippets.

@arthurafarias
Created June 7, 2017 04:37
Show Gist options
  • Save arthurafarias/c331eac1b2fec0aa34f8b478cfa5c5bd to your computer and use it in GitHub Desktop.
Save arthurafarias/c331eac1b2fec0aa34f8b478cfa5c5bd to your computer and use it in GitHub Desktop.
Atividade de Redes de Computadores - Questão 01
#!/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