справочник по Python. мм isbn 9785932861578 9 785932 861578
Скачать 4.21 Mb.
|
Глава 22 . Разработка интернет-приложений В этой главе описываются модули, обеспечивающие поддержку приклад- ных протоколов Интернета, включая HTTP, XML-RPC, FTP and SMTP. Темы, связанные с веб-программированием, такие как разработка CGI- сценариев, рассматриваются в главе 23 «Веб-программирование». Модули, связанные с обработкой форматов данных, широко используемых в Интер- нете, описываются в главе 24 «Обработка и кодирование данных в Интер- нете». Организация сетевых библиотечных модулей является одной из областей, где между Python 2 и 3 имеются существенные различия. В этой главе за основу взята организация модулей, принятая в Python 3, как более логич- Python 3, как более логич- 3, как более логич- ная. При этом функциональные возможности модулей в этих двух верси- ях Python к моменту написания этих строк были практически идентич- Python к моменту написания этих строк были практически идентич- к моменту написания этих строк были практически идентич- ны. В случае необходимости в разделах будут указываться имена модулей Python 2. Модуль ftplib Модуль ftplib реализует клиентскую часть протокола FTP. На практике достаточно редко приходится использовать этот модуль непосредственно, потому что имеется пакет urllib, который реализует более высокоуровне- вый интерфейс. Однако этот модуль может пригодиться, когда в програм- ме потребуется иметь более полный контроль над низкоуровневыми осо- бенностями FTP-соединения. Для работы с этим модулем совсем не лиш- FTP-соединения. Для работы с этим модулем совсем не лиш- -соединения. Для работы с этим модулем совсем не лиш- ним будет поближе познакомиться с протоколом FTP, который описывает- FTP, который описывает- , который описывает- ся в RFC 959. Модуль определяет единственный класс, используемый для создания FTP- соединений: FTP([host [, user [, passwd [, acct [, timeout]]]]]) Создает объект, представляющий FTP-соединение. В аргументе host пере- дается строка с именем хоста. Аргументы user, passwd и acct являются не- 620 Глава 22. Разработка интернет-приложений обязательными и определяют имя пользователя, пароль и учетную запись. При вызове без аргументов, чтобы установить фактическое соединение, по- требуется явно вызвать методы connect() и login(). Если указать аргумент host , автоматически будет вызван метод connect(). Если указать аргумен- ты user, passwd и acct, автоматически будет вызван метод login(). Аргумент timeout определяет предельное время ожидания в секундах. Экземпляр f класса FTP обладает следующими методами: f.abort() Выполняет попытку прервать продолжающуюся передачу файла. Вызов этого метода может не давать желаемого результата, в зависимости от осо- бенностей удаленного сервера. f.close() Закрывает FTP-соединение. После вызова этого метода никакие другие операции не должны выполняться над объектом f. f.connect(host [, port [, timeout]]) Открывает FTP-соединение с указанным именем хоста и номером порта. В аргументе host передается строка с именем хоста, а в аргументе port – целочисленный номер порта сервера FTP (по умолчанию используется порт 21). Аргумент timeout определяет предельное время ожидания в се- кундах. Нет необходимости вызывать этот метод, если имя хоста уже пере- давалось конструктору FTP(). f.cwd(pathname) Изменяет текущий рабочий каталог на сервере, выполняя переход по ука- занному пути pathname. f.delete(filename) Удаляет файл filename на сервере. f.dir([dirname [, ... [, callback]]]) Создает список содержимого каталога, который создается командой ‘LIST’. В необязательном аргументе dirname можно указать имя каталога, для ко- торого должен быть составлен список содержимого. 1 Кроме того, все допол- нительные аргументы метода будут просто передаваться команде ‘LIST’. Если в последнем аргументе callback передать функцию, она будет исполь- зована как функция обратного вызова для обработки возвращаемого спи- ска с содержимым каталога. Эта функция используется точно так же, как и в методе retrlines(). По умолчанию метод выводит содержимое списка в поток sys.stdout f.login([user, [passwd [, acct]]]) Выполняет регистрацию на сервере, используя указанные имя пользовате- ля, пароль и учетную запись. В аргументе user передается строка с именем пользователя; аргумент по умолчанию имеет значение ‘anonymous’. В аргу- 1 По умолчанию используется текущий рабочий каталог на сервере. – Прим. пе- рев. Модуль ftplib 621 менте passwd передается строка с паролем; аргумент по умолчанию имеет значение ‘’ (пустая строка). В аргументе acct передается строка, по умол- чанию – пустая строка. Нет необходимости вызывать этот метод, если эта информация уже передавалась конструктору FTP(). f.mkd(pathname) Создает новый каталог на сервере. f.ntransfercmd(command [, rest]) То же, что и transfercmd(), за исключением того, что этот метод возвращает кортеж (sock, size), где в поле sock возвращается объект сокета, соответ- ствующий соединению, через которое идет обмен данными, а в поле size возвращается ожидаемый объем данных в байтах или None, если объем за- ранее неизвестен. f.pwd() Возвращает строку с именем текущего рабочего каталога на сервере. f.quit() Закрывает FTP-соединение, отправляя серверу команду ‘QUIT’. f.rename(oldname, newname) Переименовывает файл на сервере. f.retrbinary(command, callback [, blocksize [, rest]]) Возвращает результат выполнения команды на сервере, используя двоич- ный режим передачи. В аргументе command передается строка, определяю- щая соответствующую команду извлечения файла, которая практически всегда имеет вид ‘RETR filename’. В аргументе callback передается функция обратного вызова, которая будет вызываться всякий раз при получении очередного блока данных. Эта функция будет вызываться с единствен- ным аргументом, содержащим принятые данные в виде строки. Аргумент blocksize определяет максимальный размер блока. По умолчанию передача ведется блоками по 8192 байта. Необязательный аргумент rest определяет смещение относительно начала файла. Если указан, определяет позицию в файле, откуда должна начаться передача данных. Однако не все серверы FTP поддерживают такую возможность, поэтому использование этого ар- поддерживают такую возможность, поэтому использование этого ар- гумента может вызывать исключение error_reply. f.retrlines(command [, callback]) Возвращает результат выполнения команды на сервере, используя тексто- результат выполнения команды на сервере, используя тексто- результат выполнения команды на сервере, используя тексто- выполнения команды на сервере, используя тексто- выполнения команды на сервере, используя тексто- команды на сервере, используя тексто- команды на сервере, используя тексто- на сервере, используя тексто- на сервере, используя тексто- сервере, используя тексто- сервере, используя тексто- , используя тексто- используя тексто- тексто- тексто- вый режим передачи. В аргументе command передается строка, определяю- щая соответствующую команду, которая обычно имеет вид ‘RETR filename’. В аргументе callback передается функция обратного вызова, которая бу- дет вызываться всякий раз при получении очередной строки данных. Эта функция будет вызываться с единственным аргументом, содержащим при- нятые данные в виде строки. При вызове без аргумента callback возвращае- мые данные будут выводиться в поток sys.stdout. f.rmd(pathname) Удаляет каталог pathname на сервере. 622 Глава 22. Разработка интернет-приложений f.sendcmd(command) Отправляет серверу простую команду и возвращает ответ. В аргументе command передается строка с командой. Этот метод должен использоваться только для выполнения команд, которые не связаны с передачей данных. f.set_pasv(pasv) Устанавливает пассивный режим. В аргументе pasv передается логический флаг, значение True в котором включает пассивный режим, а значение False – отключает. По умолчанию пассивный режим включен. f.size(filename) Возвращает размер файла filename в байтах. Возвращает None, если по каким-либо причинам размер файла определить невозможно. f.storbinary(command, file [, blocksize]) Выполняет команду на сервере и возвращает результаты, используя двоич- ный режим передачи. В аргументе command передается строка с низкоуров- невой командой, которая практически всегда имеет вид ‘STOR filename’, где подстрока filename определяет имя файла, который требуется сохранить на сервере. В аргументе file передается открытый объект файла, откуда вы- зовом метода file.read(blocksize) будут читаться данные и отправляться на сервер. Аргумент blocksize определяет размер блока при передаче. По умол- чанию передача ведется блоками по 8192 байтов. f.storlines(command, file) Выполняет команду на сервере и возвращает результаты, используя тек- стовый режим передачи. В аргументе command передается строка с низко- уровневой командой, которая обычно имеет вид ‘STOR filename’. В аргумен- те file передается открытый объект файла, откуда вызовом метода file. readline() будут читаться данные и отправляться на сервер. f.transfercmd(command [, rest]) Инициирует передачу через FTP-соединение обмена данными. Если ис- FTP-соединение обмена данными. Если ис- -соединение обмена данными. Если ис- пользуется активный режим, отправляет команду ‘PORT’ или ‘EPRT’ и при- нимает соединение со стороны сервера. Если используется пассивный ре- жим, отправляет команду ‘EPSV’ или ‘PASV’ с последующим запросом на соединение с сервером. В любом случае, как только соединение будет уста- новлено, выполняется FTP-команда command. Этот метод возвращает объект сокета, соответствующего открытому соединению, предназначенному для передачи данных. Необязательный аргумент rest определяет смещение в байтах от начала запрашиваемого файла. Однако не все серверы FTP под- FTP под- под- держивают такую возможность, поэтому использование этого аргумента может вызывать исключение error_reply. Пример Следующий пример демонстрирует, как с помощью этого модуля выгру- зить файл на сервер FTP: host = “ftp.foo.com” username = “dave” Пакет http 623 password = “1235” filename = “somefile.dat” ёёё import ftplib ftp_serv = ftplib.FTP(host,username,password) # Открыть файл, предназначенный для передачи f = open(filename,”rb”) # Передать файл на сервер FTP resp = ftp_serv.storbinary(“STOR “+filename, f) # Закрыть соединение ftp_serv.close Для загрузки документов с сервера FTP можно использовать пакет urllib. Например: try: from urllib.request import urlopen # Python 3 except ImportError: from urllib2 import urlopen # Python 2 ёёё u = urlopen(“ftp://username:password@somehostname/somefile”) contents = u.read() Пакет http Пакет http состоит из модулей, предназначенных для разработки клиентов и серверов HTTP, а также для управления механизмом сохранения состоя- ния (cookies). Протокол передачи гипертекста (Hypertext Transfer Protocol, HTTP) – это простой текстовый протокол, который действует следующим образом: 1. Клиент устанавливает соединение с сервером HTTP и отправляет за- HTTP и отправляет за- и отправляет за- прос с заголовком следующего вида: GET /document.html HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.61 [en] (X11; U; SunOS 5.6 sun4u) Host: rustler.cs.uchicago.edu:8000 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* Accept-Encoding: gzip Accept-Language: en Accept-Charset: iso-8859-1,*,utf-8 ёёё Дополнительные данные ... Первая строка определяет тип запроса, путь к документу (селектор) и версию протокола. Далее следует последовательность строк-заголовков с различной информацией о клиенте, например пароли, cookies, пред- cookies, пред- , пред- почтительные настройки механизма кэширования и версия клиентско- го программного обеспечения. Вслед за строками-заголовками следует одна пустая строка, которая указывает на окончание последовательно- сти заголовков. Далее могут следовать дополнительные данные, когда вместе с запросом отправляются данные формы или производится вы- 624 Глава 22. Разработка интернет-приложений грузка файла. Каждая строка заголовка должна завершаться символом возврата каретки и символом перевода строки (‘\r\n’). 2. Сервер возвращает ответ следующего вида: HTTP/1.0 200 OK Content-type: text/html Content-length: 72883 bytes ... Заголовок: данные ёёё Данные ... Первая строка ответа сервера определяет версию протокола HTTP, код успеха и возвращаемое сообщение. Далее следует последовательность строк-заголовков с информацией о типе возвращаемого документа, о размере документа, о версии программного обеспечения веб-сервера, cookies и так далее. Последовательность заголовков заканчивается пу- и так далее. Последовательность заголовков заканчивается пу- стой строкой, за которой следуют данные, составляющие тело запро- шенного документа. Наиболее часто используются следующие методы запросов: Метод Описание GET Получить документ. POST Послать данные формы. HEAD Вернуть только заголовки. PUT Выгрузить данные на сервер. Коды ответов, которые наиболее часто возвращаются серверами, приво- дятся в табл. 22.1. В столбце «Символическая константа» приводится имя предопределенной переменной в модуле http.client, хранящей целочислен- ный код ответа, которая может использоваться для повышения удобочи- таемости программного кода. Таблица 22.1. Коды ответов, наиболее часто возвращаемые серверами Код Описание Символическая константа Коды успешного выполнения запроса 200 Выполнено OK 201 Создано CREATED 202 Принято ACCEPTED 204 Нет содержимого NO_CONTENT Пакет http 625 Код Описание Символическая константа Переадресация (3xx) 300 Не сколько документов MULTIPLE_CHOICES 301 Документ был перемещен по другому адресу MOVED_PERMANENTLY 302 Документ временно перемещен по другому адресу MOVED_TEMPORARILY 303 Документ не изменялся NOT_MODIFIED Ошибка клиента (4xx) 400 Недопустимый запрос BAD_REQUEST 401 Требуется авторизация UNAUTHORIZED 403 Доступ к документу запрещен FORBIDDEN 404 Документ не найден NOT_FOUND Ошибка сервера (5xx) 500 Внутренняя ошибка сервера INTERNAL_SERVER_ERROR 501 Не реализовано NOT_IMPLEMENTED 502 Ошибка шлюза BAD_GATEWAY 503 Служба недоступна SERVICE_UNAVAILABLE Заголовки, которые могут присутствовать как в запросах, так и в ответах, следуют формату, широко известному как RFC-822. В общем случае каж- RFC-822. В общем случае каж- -822. В общем случае каж- дый заголовок имеет вид Имязаголовка: данные; дополнительные подробности вы найдете в документе RFC. На практике практически никогда не прихо- RFC. На практике практически никогда не прихо- . На практике практически никогда не прихо- дится анализировать заголовки, так как в случае необходимости это дела- ется автоматически. Модуль http.client (httplib) Модуль http.client реализует низкоуровневую поддержку протокола HTTP со стороны клиента. В Python 2 этот модуль называется httplib. Вместо этого модуля предпочтительнее пользоваться функциями из пакета urllib. Модуль поддерживает обе версии протокола, HTTP/1.0 и HTTP/1.1, и до- HTTP/1.0 и HTTP/1.1, и до- /1.0 и HTTP/1.1, и до- HTTP/1.1, и до- /1.1, и до- полнительно позволяет использовать защищенные SSL-соединения, если интерпретатор Python был скомпилирован с поддержкой OpenSSL. На практике достаточно редко приходится использовать этот пакет непосред- ственно; вместо него лучше использовать пакет urllib. Однако, учитывая большую важность протокола HTTP, можно столкнуться с ситуациями, когда потребуется решать задачи на более низком уровне, которые трудно или невозможно решить с помощью пакета urllib, например реализовать отправку запросов с командами, отличными от GET и POST. За дополнитель- ной информацией о протоколе HTTP обращайтесь к RFC 2616 (HTTP/1.1) и RFC 1945 (HTTP/1.0). 626 Глава 22. Разработка интернет-приложений Н иже перечислены классы, которые могут использоваться для создания HTTP-соединений с сервером: HTTPConnection(host [,port]) Создает HTTP-соединение. В аргументе host передается имя хоста, а в аргу- менте port – номер порта. По умолчанию используется порт с номером 80. Возвращает экземпляр класса HTTPConnection. HTTPSConnection(host [, port [, key_file=kfile [, cert_file=cfile]]]) Создает HTTP-соединение, используя защищенный сокет. По умолчанию используется порт с номером 443. Необязательные именованные аргумен- ты key_file и cert_file определяют файлы частного ключа и сертификата клиента в формате PEM, если они необходимы для аутентификации кли- PEM, если они необходимы для аутентификации кли- , если они необходимы для аутентификации кли- ента. Однако никакой проверки достоверности сертификата сервера не вы- полняется. Возвращает экземпляр класса HTTPSConnection. Экземпляр h класса HTTPConnection или HTTPSConnection поддерживает сле- дующие методы: h.connect() Инициирует соединение с хостом и портом, указанными в вызове кон- структора HTTPConnection() или HTTPSConnection(). Другие методы вызывают его автоматически, если соединение еще не было установлено. h.close() Закрывает соединение. h.send(bytes) Отправляет строку байтов bytes серверу. Не рекомендуется пользоваться этим методом непосредственно, потому что это может привести к наруше- ниям в работе протокола запрос/ответ. Обычно он используется для пере- дачи данных на сервер после вызова метода h.endheaders(). h.putrequest(method, selector [, skip_host [, skip_accept_encoding]]) Отправляет запрос серверу. В аргументе method указывается метод HTTP, такой как ‘GET’ или ‘POST’. Аргумент selector определяет возвращаемый объект, например: ‘/index.html’. В аргументах skip_host и skip_accept_en- _accept_en- accept_en- _en- en- coding передаются флаги, запрещающие отправку заголовков HTTP Host: и Accept-Encoding:. По умолчанию оба аргумента получают значение False. Протокол HTTP/1.1 позволяет отправлять несколько запросов через одно и то же соединение, поэтому если соединение находится в состоянии, пре- пятствующем отправке нового запроса, этот метод возбуждает исключение CannotSendRequest h.putheader(header, value, ...) Отправляет серверу заголовок, соответствующий формату RFC-822. Серве- RFC-822. Серве- -822. Серве- ру отправляется строка, состоящая из имени заголовка, двоеточия, про- бела и значения. Дополнительные аргументы интерпретируются как до- полнительные строки текста в заголовке. Если соединение находится в со- стоянии, препятствующем отправке заголовка, возбуждается исключение CannotSendRequest Пакет http 627 h.endheaders() Отправляет серверу пустую строку, обозначающую конец последователь- ности заголовков. h.request(method, url [, body [, headers]]) Отправляет серверу полный запрос HTTP. Аргументы method и url имеют тот же смысл, что и в методе h.putrequest(). В необязательном аргумен- В необязательном аргумен- те body передается строка с данными, которые должны быть выгружены после отправки запроса. Если аргумент body указан, в заголовке Context- length: автоматически будет указано соответствующее значение. В аргу- менте headers передается словарь, содержащий пары header:value для пере- дачи методу h.putheader(). h.getresponse() Получает ответ сервера и возвращает экземпляр класса HTTPResponse, с по- мощью которого можно читать данные. Если экземпляр h находится в со- стоянии, не позволяющем выполнить прием ответа, метод возбуждает ис- ключение ResponseNotReady. Экземпляр r класса HTTPResponse, возвращаемый методом getresponse(), поддерживает следующие методы: r.read([size]) Читает до size байтов из ответа сервера. При вызове без аргумента size воз- вращает все данные, полученные в ответ на запрос. r.getheader(name [,default]) Получает заголовки ответа. В аргументе name передается имя заголовка, а в аргументе default – значение по умолчанию, возвращаемое в случае отсут- ствия заголовка. r.getheaders() Возвращает список кортежей (header, value). Кроме того, экземпляр r класса HTTPResponse обладает следующими атри- бутами: r.version Версия протокола HTTP, используемая сервером. r.status Код состояния HTTP, полученный от сервера. r.reason Текст сообщения HTTP, полученный от сервера. r.length Количество байтов, оставшихся в ответе. Исключения При работе с HTTP-соединениями могут возбуждаться следующие исклю- HTTP-соединениями могут возбуждаться следующие исклю- -соединениями могут возбуждаться следующие исклю- чения: 628 Глава 22. Разработка интернет-приложений Исключение Описание HTTPException Б азовый класс всех исключений, имеющих отношение к HTTP. NotConnected Ошибка соединения при попытке выполнить запрос. InvalidURL Ошибка в адресе URL или в номере порта. UnknownProtocol Неизвестный номер протокола HTTP. UnknownTransferEncoding Неизвестный формат передачи. UnimplementedFileMode Нереализованный режим работы с файлами. IncompleteRead Данные приняты не полностью. BadStatusLine Принят неизвестный код состояния. Ниже перечислены исключения, имеющие отношение к состоянию соеди- нений HTTP/1.1. Протокол HTTP/1.1 позволяет передавать несколько за- HTTP/1.1. Протокол HTTP/1.1 позволяет передавать несколько за- /1.1. Протокол HTTP/1.1 позволяет передавать несколько за- HTTP/1.1 позволяет передавать несколько за- /1.1 позволяет передавать несколько за- просов/ответов через одно и то же соединение, поэтому существуют допол- нительные правила, которые диктуют, когда запросы могут отправляться, а ответы – приниматься. Попытка выполнить операции в недопустимом порядке будет приводить к исключению. Исключение Описание ImproperConnectionState Базовый класс всех исключений, имеющих отношение к состоянию HTTP-соединений. CannotSendRequest Невозможно отправить запрос. CannotSendHeader Невозможно отправить заголовки. ResponseNotReady Невозможно прочитать ответ. Пример Следующий пример демонстрирует применение класса HTTPConnection для выгрузки файла на сервер в виде запроса POST способом, не требующим больших объемов памяти, чего непросто добиться при использовании па- кета urllib. import os try: from httplib import HTTPConnection # Python 2 except ImportError: from http.client import HTTPConnection # Python 3 ёёё BOUNDARY = “$Python-Essential-Reference$” CRLF = ‘\r\n’ ёёё def upload(addr, url, formfields, filefields): # Создать разделы для полей формы formsections = [] for name in formfields: Пакет http 629 section = [ ‘--’+BOUNDARY, ‘Content-disposition: form-data; name=”%s”’ % name, ‘’, formfields[name] ] formsections.append(CRLF.join(section)+CRLF) ёёё # Собрать информацию обо всех выгружаемых файлах fileinfo = [(os.path.getsize(filename), formname, filename) for formname, filename in filefields.items()] ёёё # Создать HTTP-заголовки для каждого файла filebytes = 0 fileheaders = [] for filesize, formname,filename in fileinfo: headers = [ ‘--’+BOUNDARY, ‘Content-Disposition: form-data; name=”%s”; filename=”%s”’ % \ (formname, filename), ‘Content-length: %d’ % filesize, ‘’ ] fileheaders.append(CRLF.join(headers)+CRLF) filebytes += filesize ёёё # Закрывающая метка closing = “--”+BOUNDARY+”--\r\n” ёёё # Определить общую длину запроса content_size = (sum(len(f) for f in formsections) + sum(len(f) for f in fileheaders) + filebytes+len(closing)) ёёё # Выгрузить его conn = HTTPConnection(*addr) conn.putrequest(“POST”,url) conn.putheader(“Content-type”, ‘multipart/form-data; boundary=%s’ % BOUNDARY) conn.putheader(“Content-length”, str(content_size)) conn.endheaders() ёёё # Отправить все разделы формы for s in formsections: conn.send(s.encode(‘latin-1’)) ёёё # Отправить все файлы for head,filename in zip(fileheaders,filefields.values()): conn.send(head.encode(‘latin-1’)) f = open(filename,”rb”) while True: chunk = f.read(16384) if not chunk: break conn.send(chunk) f.close() conn.send(closing.encode(‘latin-1’)) 630 Глава 22. Разработка интернет-приложений r = conn.getresponse() responsedata = r.read() conn.close() return responsedata ёёё # Пример: Выгрузить несколько файлов. Удаленный сервер ожидает получить # поля формы ‘name’, ‘email’, ‘file_1’,’file_2’ и так далее # (очевидно, что это будет зависеть от конкретного сервера). server = (‘localhost’, 8080) url = ‘/cgi-bin/upload.py’ formfields = { ‘name’ : ‘Dave’, ‘email’ : ‘dave@dabeaz.com’ } filefields = { ‘file_1’ : ‘IMG_1008.JPG’, ‘file_2’ : ‘IMG_1757.JPG’ } resp = upload(server, url,formfields,filefields) print(resp) Модуль http.server (BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer) М одуль http.server предоставляет различные классы, реализующие функ- циональность серверов HTTP. В Python 2 содержимое этого модуля разбито на три модуля: BaseHTTPServer, CGIHTTPServer и SimpleHTTPServer. Класс HTTPServer Следующий класс реализует простейший сервер HTTP. В Python 2 он объ- HTTP. В Python 2 он объ- . В Python 2 он объ- Python 2 он объ- 2 он объ- явлен в модуле BaseHTTPServer. HTTPServer(server_address, request_handler) Создает новый объект класса HTTPServer. В аргументе server_address переда- переда- ется кортеж вида (host, port), определяющий адрес, на котором сервер будет ожидать поступления запросов на соединение. В аргументе request_handler передается класс-обработчик, производный от класса BaseHTTPRequestHan- dler , который описывается ниже. Класс HTTPServer является непосредственным наследником класса TCPServ- er , объявленного в модуле socketserver. Поэтому, если потребуется реализо- вать нестандартные операции для работы с сервером HTTP, можно создать свой класс, производный от класса HTTPServer, и расширить его. Ниже при- водится пример создания многопоточного сервера HTTP, принимающего соединения только из определенной подсети: try: from http.server import HTTPServer # Python 3 from socketserver import ThreadingMixIn except ImportError: from BaseHTTPServer import HTTPServer # Python 2 from SocketServer import ThreadingMixIn ёёё Пакет http 631 class MyHTTPServer(ThreadingMixIn,HTTPServer): def __init__(self,addr,handler,subnet): HTTPServer.__init__(self,addr,handler) self.subnet = subnet def verify_request(self, request, client_address): host, port = client_address if not host.startswith(subnet): return False return HTTPServer.verify_request(self,request,client_address) ёёё # Пример запуска сервера serv = MyHTTPServer((‘’,8080), SomeHandler, ‘192.168.69.’) serv.serve_forever() Класс HTTPServer оперирует только низкоуровневым протоколом HTTP. Чтобы сервер действительно мог делать что-то полезное, необходимо ука- зать класс обработчика. Существует два встроенных класса обработчиков и базовый класс, на основе которого можно реализовать собственную об- работку. Все они описываются ниже. Классы SimpleHTTPRequestHandler и CGIHTTPRequestHandler Имеется возможность использовать два предопределенных класса обработ- чиков, если необходимо быстро создать простой веб-сервер. Эти классы дей- ствуют независимо от любых сторонних веб-серверов, таких как Apache. CGIHTTPRequestHandler(request, client_address, server) Обслуживает файлы в текущем каталоге и во всех вложенных подкатало- гах. Кроме того, обработчик будет выполнять файлы, как сценарии CGI, если они находятся в специальном каталоге CGI (имена каталогов опреде- CGI (имена каталогов опреде- (имена каталогов опреде- ляются атрибутом cgi_directories класса, который по умолчанию содержит список [‘/cgi-bin’, ‘/htbin’]). Обработчик поддерживает методы GET, HEAD и POST. Но он не поддерживает переадресацию HTTP (код 302), вследствие чего он может использоваться только для выполнения наиболее простых CGI-приложений. Из соображений безопасности сценарии CGI выполня- -приложений. Из соображений безопасности сценарии CGI выполня- CGI выполня- выполня- ются с привилегиями пользователя nobody. В Python 2 определение этого класса находится в модуле CGIHTTPServer. SimpleHTTPRequestHandler(request, client_address, server) Обслуживает файлы в текущем каталоге и во всех вложенных подката- логах. Этот класс реализует поддержку методов HEAD и GET запросов. Все исключения IOError приводят к выводу сообщения об ошибке “404 File not found” («404 Файл не найден»). Попытки обратиться к каталогам оканчи- ваются выводом сообщения об ошибке “403 Directory listing not supported” («403 Вывод содержимого каталогов не поддерживается»). В Python 2 опре- Python 2 опре- опре- деление этого класса находится в модуле SimpleHTTPServer. Оба эти обработчика определяют следующие атрибуты класса, значения которых при желании можно изменять за счет наследования: handler.server_version Строка с номером версии, возвращаемая клиенту. По умолчанию имеет строковое значение, такое как ‘SimpleHTTP/0.6’. 632 Глава 22. Разработка интернет-приложений handler.extensions_map Словарь, отображающий расширения файлов в типы MIME. Файлы не- опознанного типа относятся к типу ‘application/octet-stream’. Ниже приво- дится пример использования этих классов обработчиков для запуска са- мостоятельного веб-сервера, поддерживающего возможность выполнения CGI-сценариев: try: from http.server import HTTPServer, CGIHTTPRequestHandler # Python 3 except ImportError: from BaseHTTPServer import HTTPServer # Python 2 from CGIHTTPServer import CGIHTTPRequestHandler import os ёёё # Перейти в корневой каталог с документами os.chdir(“/home/httpd/html”) ёёё # Запустить сервер CGIHTTP на порту с номером 8080 serv = HTTPServer((“”,8080),CGIHTTPRequestHandler) serv.serve_forever() Класс BaseHTTPRequestHandler Класс BaseHTTPRequestHandler может использоваться как базовый класс для разработки собственного обработчика, действующего в составе сервера HTTP. Встроенные классы обработчиков, такие как SimpleHTTPRequestHan- dler и CGIHTTPRequestHandler, также являются производными этого класса. В Python 2 определение этого класса находится в модуле BaseHTTPServer. BaseHTTPRequestHandler(request, client_address, server) Базовый класс обработчика, используемый для обработки запросов HTTP. После того как клиент установит соединение и HTTP-заголовки его запро- HTTP-заголовки его запро- -заголовки его запро- са будут проанализированы, выполняется попытка вызвать метод вида do_ REQUEST , имя которого конструируется исходя из типа запроса. Напри- мер, для обработки запроса типа ‘GET’ будет вызван метод do_GET(), а для обработки запроса типа ‘POST’ – метод do_POST(). По умолчанию этот класс ничего не делает, и предполагается, что эти методы должны быть переопре- делены в подклассах. Ниже перечислены атрибуты класса BaseHTTPRequestHandler, которые могут быть переопределены в подклассах. BaseHTTPRequestHandler.server_version Строка с описанием версии программного обеспечения, которая отправля- ется клиенту, например ‘ServerName/1.2’. BaseHTTPRequestHandler.sys_version Версия Python, например ‘Python/2.6’. BaseHTTPRequestHandler.error_message_format Строка формата, которая используется для сборки сообщений об ошибках, отправляемых клиенту. Строка формата применяется к словарю с атрибу- тами code, message и explain. Например: |