Главная > web, Программирование > Python: Реализация простого web-сервера.

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]) > 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('Download results.')
except Exception:
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" />XO
</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>
Пожалуйста, оцените полезность и качество данной статьи. Одна звезда - плохо, 5 - хорошо.
1/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.2/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.3/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.4/5.5/5. (9 голосов, средний: 3,78 из 5)
Загрузка...
  1. Пока что нет комментариев.
  1. Пока что нет уведомлений.