Criando um servidor HTTP (Web) com Python

Hoje contamos com alguns servidores HTTP (web) tais como ApachelighttpdNginxTUXCherokee e outros. O desenvolvimento deste artigo é para explicar melhor como trabalhar com Python e desenvolver coisas novas para as necessidades do dia a dia.
Vou explicar qual foi a necessidade do meu cliente para que eu escrevesse este software:
O Cliente tinha um sistema rodando com Ruby On Rails e o desenvolvedor como não sabia configura o Ruby para processar juntamente com o servidor web (Apache); ele rodou o servidor web do próprio Ruby On Rails com a porta 4000.
Como teria que mexer no sistema e não sou programador Ruby, fiz uma contra-proposta para desenvolver o sistema novamente (porque tinha muitos erros) em Python (pois é a linguagem que eu sei programar). O cliente aceitou e dei start no desenvolvimento.
Ao terminar o software, queria que ficasse transparente para o usuário final (para ele acessar da mesma forma que acessava); testei alguns servidores web como Nginx e lighttpd, só que ele estava comendo recursos desnecessário no servidor, lembrando que eu só queria colocar um HTML com uma meta tag para redirecionar para o sistema novo. Bom, resolvi desenvolver uma solução própria em Python, e achei a biblioteca BaseHTTPServer.
A estrutura que montei é a seguinte:
avelino@program-8:~/python/httpd$ ls
htdocs  httpd.py
daemon que vamos usar é o httpd.py, vamos para a parte de código.
Vamos usar as seguintes bibliotecas:
import sys,osimport string,cgi,timefrom BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
Vamos escrever uma classe para tratar o POST e GET (Não usei o POST na minha necessidade, mas para quem quer fazer um servidor HTTP simples pode precisar):
class http(BaseHTTPRequestHandler): 

    def do_GET(self):
        try:
            if self.path.endswith(".html"):
                f = open(DocumentRoot + self.path)
                self.send_response(200)
                self.send_header('Content-type','text/html')
                self.end_headers()
                self.wfile.write(f.read())
                f.close()
                return

            if self.path.endswith(".esp"):
                self.send_response(200)
                self.send_header('Content-type','text/html')
                self.end_headers()
                self.wfile.write("hey, today is the" + str(time.localtime()[7]))
                self.wfile.write(" day in the year " + str(time.localtime()[0]))
                return

            return

        except IOError:
            self.send_error(404,'File Not Found: %s' % self.path)

    def do_POST(self):
        global rootnode
        try:
            ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
            if ctype == 'multipart/form-data':
                query=cgi.parse_multipart(self.rfile, pdict)
            self.send_response(301)

            self.end_headers()
            upfilecontent = query.get('upfile')
            print "filecontent", upfilecontent[0]
            self.wfile.write("<html>Post OK. <br /><br />");
            self.wfile.write(upfilecontent[0]);
            self.wfile.write("</html>")

        except:

            pass
Os nomes das def do_GET e do_POST são padrões do BaseHTTPRequestHandler. O do_GET usamos para renderização de qualquer arquivo. Por exemplo, temos uma index.html em nossa pasta htdocs, ele vai trabalhar pegando o arquivo index.html (/home/avelino/python/httpd/htdocs/index.html) e renderizando o html dele.
Vou criar uma função para chamar as declarações da classe:
def main(NameVirtualHost):

    try:
        virtualhost = string.split(NameVirtualHost,":")
        if virtualhost[0] == "*":
            virtualhost[0] = ""
         
        server = HTTPServer((virtualhost[0], int(virtualhost[1])), http)
        print 'Start server HTTP IN %s' % NameVirtualHost
        server.serve_forever()

    except KeyboardInterrupt:
        print 'Shutting down server HTTP'
        server.socket.close()
A var NameVirtualHost é onde vamos passar IP e PORTA para o servidor HTTP, exemplo.
Liberar só para acesso local: localhost:8000
Liberar para qualquer IP que estiver configurado na maquina: *:8000
Na biblioteca BaseHTTPServer temos uma função onde o mesmo server, para rodar o servidor, recebe dois parâmetros: o primeiro é IP/PORTA, e o segundo é a classe onde estão os métodos (GET, POST etc) que, no nosso caso, é a classe html.
Agora vamos chamar a def que fizemos:
if __name__ == '__main__':
    DocumentRoot = "%s/htdocs/" % os.path.realpath(os.path.dirname(__file__))
    PORT = "8000"
    HOST = "localhost"

    try :
        main(sys.argv[1])
    except :
        main("%s:%s" % (HOST,PORT))
  • DocumentRoot = Pega a pasta local que estamos e concatena com "/htdocs/"
  • PORT = Porta padrão do servidor
  • HOST = Host padrão do servidor
Temos uma TRY que vamos tratar o que vem por parâmetro (argv), caso ele tenha valores errados chamará o HOST/PORT declarado do software.
Rodando o servidor:
avelino@program-8:~/python/httpd$ python httpd.py *:8000
Start server HTTP IN *:8000
imagem 
Agora, para matar o processo, é como qualquer outro:
avelino@program-8:~/python/httpd$ python httpd.py localhost:8000
Start server HTTP IN localhost:8000
localhost - - [14/Sep/2010 09:42:05] "GET /index.html HTTP/1.1" 200 -
localhost - - [14/Sep/2010 09:42:54] "GET /index.html HTTP/1.1" 200 -
^CShutting down server HTTP
avelino@program-8:~/python/httpd$ 
Se olharmos o LOG acima, ele mostra tudo que foi processado com LOG de Apache ou qualquer outro servidor HTTP.
Obrigado pelo seu comentário

Postagens Relacionadas

Related Posts Plugin for WordPress, Blogger...

Programador GB