Рейтинг@Mail.ru

Python: Реализация простого web-сервера.


Не для собственных нужд, но как-то понадобилось написать простой web-сервер для обработки на нём загруженных данных. В общем-то должен был получиться простой вёб-интерфейс к программе. Он и получился, местами даже слишком простой. В общем суть такова — необходимо получить от пользователя экзешник, на сервере его обработать нужными программами и выдать результат, т.е. обработанный файл для скачивания. Можно было бы написать скрипт на php, что было бы проще, но тогда необходимо с собой таскать какой-нибудь вёб-сервер (apache, denwer и т.п.). На питоне можно его реализовать достаточно просто в самом скрипте используя стандартные заготовки и библиотеки, такие как BaseHTTPServer. Ниже следует листинг с краткими комментариями.

# -*- coding: utf-8 -*- import cgi from os import curdir, sep from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer import subprocess class MyHandler(BaseHTTPRequestHandler):     def do_GET(self):         try:             if self.path != "/output.exe":                 f = open(curdir+sep+"upload.html")                 self.send_response(200)                 self.send_header("Content-type", "text/html")                 self.end_headers()                 self.wfile.write(f.read())                 f.close()             else:                 self.send_response(200)                 self.send_header("Content-type", "application/octet-stream")                 self.end_headers()                 self.wfile.write(open(curdir+sep+"output.exe", "rb").read())         except IOError:             self.send_error(404,"File Not Found: %s" % self.path)     def do_POST(self):         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(200)             self.end_headers()             upfile = query.get("file")             f = open(curdir+sep+"output.exe", "wb")             f.write(upfile[0])             f.close()             params = " np output.exe"             p = query.get("encryption")             if p[0] == "aes":                 params += " sf 1"             elif p[0] == "rc5":                 params += " sf 2"             elif p[0] == "xor":                 params += " sf 3"             else:                 params += " sf 0"             p = query.get("hw_bind")             if p[0] == "yes":                 p = query.get("hw_bind_serial")                 assert len(p[0]) == 8                 params += " sn " + p[0]             else:                 params += " sn 0"             p = query.get("passwd")             assert len(p[0]) &gt; 0             params += " pass " + p[0]             p = query.get("pack")             if p[0] == "yes":                 params += " pack 1"             else:                 params += " pack 0"             pipe = subprocess.Popen("processor.exe "+params, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)             pipe.stdin.close()             pipe.wait()             self.wfile.write('<a href="/output.exe">Download results</a>.');         except :             pass if __name__ == "__main__":     try:         server = HTTPServer(("", 8080), MyHandler)         print "started httpserver..."         server.serve_forever()     except KeyboardInterrupt:         print "^C received, shutting down server"         server.socket.close()

Итак, для начала импортируем из библиотеки BaseHTTPServer два класса: HTTPserver — собственно, сам вёб-сервер и BaseHTTPRequestHandler — класс, который служит для обработки запросов от пользователей.

Объявляем свой класс MyHandler, который наследуется от BaseHTTPRequestHandler. И перегружаем в нём два метода — do_GET и do_POST для обработки данных, переданных методом GET и POST, соответственно.

В первом обработчике проверяем запрос от пользователя (содержится в self.path), если запрашиваемый документ не является /output.exe, то выдаём форму для загрузки файла, иначе — считываем и выдаём output.exe. Так же, перед этим, посылается ответ от сервера с кодом 200, что соответствует успешной обработке запроса от клиента и передаём заголовок, в котором указан тип содержимого (text/html для html-код или application/octet-stream для бинарного файла).

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

Далее, в самой программе создаём вёб-сервер, указав при этом порт, на котором он будет работать (в примере это 8080) и класс, который необходимо использовать для обработки запросов от пользователей.

Недостаток заключается в том, что данная реализация не сможет обработать одновременную загрузку файлов от разных пользователей, т.к. в лучшем случае просто один из запросов затрёт файл output.exe, полученный в другом запросе. Но такая задача не стояла. На мой взгляд хороший пример для демонстрации возможностей python’а.

Так же код html-файла upload.html, который должен располагаться в той же директории, что и сервер:

<form action="/" enctype="multipart/form-data" method="post"> <table border="1"> <tbody> <tr> <td>Encryption:</td> <td> <input checked="checked" name="encryption" type="radio" value="none" />None <input name="encryption" type="radio" value="aes" />AES <input name="encryption" type="radio" value="rc5" />RC5 <input name="encryption" type="radio" value="xor" />XOR</td> </tr> <tr> <td>Hardware binding:</td> <td> <input checked="checked" name="hw_bind" type="radio" value="no" />No <input name="hw_bind" type="radio" value="yes" />Yes <input name="hw_bind_serial" value="media serial number" /></td> </tr> <tr> <td>Password:</td> <td> <input name="passwd" type="password" /></td> </tr> <tr> <td>Pack:</td> <td> <input checked="checked" name="pack" type="radio" value="no" />No <input name="pack" type="radio" value="yes" />Yes</td> </tr> <tr> <td colspan="2"> <input name="file" type="file" /> <input type="submit" value="Отправить" /></td> </tr> </tbody></table> </form>

Ссылки к статье:

http://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP
— Список кодов состояния HTTP.

web, Программирование , ,

Пожалуйста, оцените полезность и качество данной статьи. Одна звезда - плохо, 5 - хорошо.
1 звезда2 звезды3 звезды4 звезды5 звёзд (2 голосов, средний: 3,50 из 5)
Loading ... Loading ...

  1. Пока что нет комментариев.
  1. Пока что нет уведомлений.
*