Тема 14. Реализация интерфейса информационного взаимодействия программных приложений. Интерфейс взаимодействия сервера с внешней программой.
Рассмотрим реализацию интерфейса взаимодействия сервера с внешней программой (Common Gateway Interface).
Переменные среды Common Gateway Interface (CGI).
Cервер при запуске CGI-скрипта (внешней программы) формирует среду окружения, в которой скрипт может найти всю доступную информацию о HTTP-соединении и о полученных в запросе параметрах.
Большинство переменных CGI стандартизованы. Рассмотрим стандартные переменные CGI-окружения:
REQUEST_METHOD - это одно из самых главных полей, используемое для определения метода запроса HTTP. Как уже было отмечено протокол HTTP использует для запроса к серверу методы GET и POST. Они отличаются тем, что в методе GET запрос является частью URL (например http://www.localhost/myscript.cgi?а=request), а при использовании метода POST данные передаются в теле HTTP-запроса (при GET тело запроса пусто). Соответственно, для CGI: при GET запрос идет в переменную QUERY_STRING, а при POST подается на стандартный ввод скрипта - STDIN.
Пример: REQUEST_METHOD=GET
QUERY_STRING - эта строка запроса при методе GET. Запрос, отправляемый из формы, кодируется броузером, поскольку не все символы разрешены в URL (некоторые из них имеют специальное назначение). В методе urlencode: все пробелы заменяются в URL на знак “+”, а все специальные и непечатаемые символы на последовательность %hh, где hh - шестнадцатеричный код символа. Кроме того, разделителем полей формы является знак &, поэтому при обработке форм надо производить декодирование.
Пример: QUERY_STRING= name=user+chef&age=20&hobby=games
CONTENT_LENGTH - длина тела запроса в байтах. При методе запроса POST необходимо считать со стандартного входа (STDIN) CONTENT_LENGTH - байт, а потом производить их обработку. Обычно методом POST пользуются для передачи форм, содержащих потенциально большие области ввода текста. При этом методе нет никаких ограничений, а при методе GET существуют ограничения на длину URL.
Пример: CONTENT_LENGTH=31
CONTENT_TYPE - тип тела запроса (для форм, кодированных вышеуказанным образом, тип определяется как application/x-www- form- urlencoded).
GATEWAY_INTERFACE - версия протокола CGI.
Пример: GATEWAY_INTERFACE=CGI/1.1
REMOTE_ADDR - IP-адрес удаленного хоста, делающего данный запрос.
Пример: REMOTE_ADDR=139.142.24.157
REMOTE_HOST - это, если запрашивающий хост имеет доменное имя, то эта переменная содержит его, в противном случае, это тот же самый IP-адрес, что и REMOTE_ADDR.
Пример: REMOTE_HOST=idsoftware.com
SCRIPT_NAME - имя скрипта (виртуальное), использованное в запросе. Для получения реального пути на сервере используется переменная SCRIPT_FILENAME.
Пример: SCRIPT_NAME=/cgi/guestbook.cgi
SCRIPT_FILENAME - имя файла скрипта на сервере. Используя эту переменную, вы получаете именно физический путь к файлу.
Пример: SCRIPT_FILENAME=/home/public/cgi/guestbook. cgi
SERVER_NAME - имя сервера, чаще всего доменное (такое как www.microsoft.com), но в редких случаях, за неимением такового оно может быть IP-адресом (типа 157.151.74.254).
Пример: SERVER_NAME=www.tksite.edu
SERVER_PORT - TCP-порт сервера, используемый для соединения. По умолчанию HTTP-порт имеет номер 80, хотя в некоторых случаях он может быть и другим.
Пример: SERVER_PORT=80
SERVER_PROTOCOL - версия протокола сервера.
Пример: SERVER_ROTOCOL=HTTP/1.1
SERVER_SOFTWARE - программное обеспечение сервера.
Пример: Apache/1.0
Основная информация о взаимодействии клиента и сервера может быть получена из стандартных переменных окружения.
При каждом запуске CGI-сценарий работает так, как будто он прежде никогда не запускался. Программа сценария не переходит в состояние ожидания между отдельными вызовами. Каждый раз процедура инициализации запускается с самого начала. До считывания входных данных необходимо прочесть значение переменной окружения REQUEST_METHOD и определить какую информацию она содержит get или post. Дальнейшие действия зависят от этого значения.
Обработка входных данных зависит от целей написания конкретного сценария. В общем случае обработка данных означает их преобразование.
Но в любом случае есть строго регламентированная часть обработки (обработка входных данных), зависящая от метода запроса.
Обработка входных данных для метода get.
Алгоритм обработки входных данных для метода get состоит из следующих шагов:
1. Определение значения переменной QUERY_STRING.
2. Декодирование имен и их значений. При этом учитывают, что все пробелы были заменены символом "+" и что все символы с десятичным кодом больше 128 преобразованы в символ "%" и следующим за ним шестнадцатеричным кодом символа.
3. Формирование структуры “Имя - значение”.
Метод get предполагает передачу данных программе через переменные среды.
В переменную QUERY_STRING попадают значения полей форм в формате:
"Имя1=Значение1&Имя2=Значение2&Имя3=Значение3"….
Здесь ИмяN - значения атрибутов NAME, задающих имена управляющих элементов формы. На месте ЗначеииеN сервер записывает то значение атрибута VALUE, которое ввел пользователь в элементе ИмяN. Строку QUERY_STRING обрабатывают обычными функциями языков программирования. Но ее нельзя модифицировать. Эта строка использует кодировку URL.
После декодирования входных данных в массиве строк хранятся все пары имя=значение из входного набора. Этот массив разработчик использует в зависимости от поставленной задачи.
Обработка входных данных для метода post.
Алгоритм обработки входных данных для метода post состоит из следующих шагов:
1. Определение значения переменной CONTENT_LENGTH.
2. Декодирование имен и их значений. При этом учитывают, что все пробелы были заменены символом "+" и что все символы с десятичным кодом больше 128 преобразованы в символ "%" и следующим за ним шестнадцатеричным кодом символа.
3. Формирование структуры “Имя - значение”.
Необходимо считать данные из потока STDIN. Если переменная окружения CONTENT_TYPE содержит значение application/x-www-form-urlcoded, данные из потока STDIN также следует декодировать.
Метод post предполагает ввод данных через стандартный поток stdin.
Количество байт, которые следует считывать из STDIN, передается в переменной CONTENT_LENGTH.
Рассмотрим интерфейс взаимодействия внешней программы с сервером.
Вывод данных для пользователя
Вне зависимости от метода ввода данных от пользователя, программа CGI направляет свой вывод в стандартный поток STDOUT.
Этот вывод может представлять собой HTML-документ или инструкции серверу, где получить необходимый документ. Преимущество последнего подхода в том, что cgi-модуль не должен формировать полный HTTP заголовок на каждый запрос.
Заголовок вывода сценария.
Как правило, вывод сценария интерпретируется сервером и посылается пользователю. Информация, позволяющая броузеру выяснить, какого типа файл идет к нему по сети, поступает до получения самого файла и называется заголовком. Поскольку сервер не может создать заголовок, сценарий сам должен обеспечивать отправку соответствующего заголовка. Таким образом, помимо собственно результатов обработки, сценарий должен поместить в выходной поток и корректный заголовок. Он состоит из строки состояния и затем полей ответа: общий заголовок (General-Header) и заголовок тела сообщения (Entity-Header), а также заголовок ответа (Response-Header).
Вывод начинается с маленького заголовка. Он содержит текстовые строки, в том же формате, как и в HTTP заголовке, и завершается пустой строкой (содержащей символ перевода строки). Любые строки заголовка, не являющиеся директивами сервера, посылаются непосредственно пользователю. В настоящий время, CG1 спецификация определяет три директивы сервера.
Имя
Пояснение
Content-type
MIME-тип возвращаемого документа.
Location
Это поле используется в случае, когда необходимо указать серверу, что возвращается не сам документ, а ссылка на него. Тогда сервер передает пользователю указание на перенаправление запроса.
Status
Задает серверу НТТР строку-статус, которая будет послана клиенту. Формат: nnn xxxxx, где nnn - 3-х цифровой статус-код, и ххххх строка причины.
Наиболее интересная информация содержится в строке состояния. Строка состояния имеет следующий формат: HTTP/version - версия, Status-Code - трехзначный код статуса идентифицирующий результат и Status-Phrase - текстовая фраза, поясняющая код. Код статуса используется броузером, а текстовая фраза предназначена для пользователя.
Первая цифра кода статуса предназначена для определения класса ответа.
Существует пять катеогрий, определяемых первой цифрой кода:
1) 1хх: пока не используется, зарезервирован для использования в будущем.
2) 2хх: успех - запрос был полностью получен, понят и принят к обработке
3) Зхх: перенаправление - пользователю следует предпринять дальнейшие действия для успешного выполнения запроса.
4) 4хх: ошибка пользователя - запрос не может быть успешно обработан. Если пользователь еще не завершил запрос на момент получения ответа с кодом 4хх, то он должен немедленно прекратить передачу данных серверу.
5) 5хх: ошибка Web-сервера - сервер не смог ответить на корректный запрос. Сервер посылает описание ошибочной ситуации и то, является ли это состояние временным или постоянным, в теле ответа.
Поясняющие текстовые фразы могут быть замещены любыми другими фразами, сохраняющими смысл и допускающимися протоколом.
В следующей таблице перечислены коды ответов HTTP.
Код статуса | Значение |
ок | |
Успешная команда post | |
Запрос принят | |
Запрос get или HEAD выполнен | |
Запрос выполнен но нет содержимого | |
Ресурс обнаружен в нескольких местах | |
Ресурс удален навсегда | |
Ресурс отсутствует временно | |
Ресурс был изменен | |
Плохой запрос от клиента | |
Неавторизованный запрос | |
Необходима оплата за ресурс | |
Доступ запрещен | |
Ресурс не найден | |
Метод не применим для данного ресурса | |
Недопустимый тип ресурса | |
Ресурс недоступен | |
Внутренняя ошибка сервера | |
Метод не выполнен | |
Неисправный сценарий либо сервер перегружен | |
Сервер недоступен/тайм-аут сценария | |
Вторичный сценарий/тайм-аут сервера |
Директива Status позволяет CGI-сценарию вернуть сообщение о состоянии обработки. Если эта директива не задана, то сервер подразумевает 200 Ok.
Пример:
Status: 404 Not found
На базе этой информации сервер и формирует окончательный заголовок, который и передается клиенту. Например, набор директив:
НТТР/1.0 200 ОК
Server: NCSA/1.0a6
Content-type: text/html
сообщает об успешном выполнении запроса.
Здесь: 200 - код означающий успешную обработку запроса, что и поясняет "Ok".
Следующая директива: Content-type: text/html
обязательно присутствует, если есть тело ответа, и сообщает серверу, что далее последует HTML-документ.
А директива:
Location: http://host/file.txt
приведет к тому, что Web-сервер выдаст file.txt, как если бы он был затребован клиентом.
Этапы работы сценария.
Как видно из вышеизложенного, работа сценария в общем случае состоит из трех частей:
1. Инициализация и обработка входных данных.
2. Основная часть работы и вывод пользователю.
3. Завершение своей работы.
При выполнении инициализации все параметры известны заранее (или их несложно узнать), а решаемые задачи более менее одинаковы для любого из сценариев. То, что выполняется на этапе обработки входящих данных, зависит от целей написания сценария. В общем случае обработка входящих данных означает их преобразование.
После инициализации работы, чтения входящих данных и их разделения на отдельные переменные, сценарий будет готов к выполнению основной части работы. В этой части работы сценарий готовит данные для вывода и шаги регламентируются не столь жестко, как на этапе инициализации. Все выполняемые действия определяются поставленными целями. Поскольку обработка данных в CGI довольно проста, а целью создания сценария почти всегда является подготовка некоторой исходящей информации, формализованные шаги обработки входящих и подготовки исходящих данных объединяются в одну фазу программы.
Вывод результатов. В простом CGI-сценарии исходящая информация представляет собой только заголовок и HTML-текст. Более сложные сценарии могут выводить только графику, графику с текстом или же вообще всю информацию, необходимую для повторного вызова сценария с некоторыми дополнительно введенными данными.
Завершение подразумевает всего лишь очистку и освобождение всех использованных ресурсов с последующим выходом из программы. Если выполнялось распределение свободной памяти или других объектов, то они должны быть освобождены. Если этого не сделать может возникнуть утечка или блокировка ресурсов всей системы и остановка работы любых других сценариев или вообще всего сервера. На большинстве платформ файлы и созданные в памяти объекты автоматически закрываются и освобождаются операционной системой после завершения использовавшего их процесса. Но и в данном случае неразумно при освобождении ресурсов целиком полагаться на операционную систему.
Литература: 1осн.[20-26],2осн.[80-98],7доп.[100-117],9доп.[211-234].
Контрольные вопросы
1. Какую информацию содержат переменные среды в интерфейсе CGI?
2. Как производится обработка входных данных для метода get в интерфейсе взаимодействия сервера и внешней программы?
3. Как производится обработка входных данных для метода post в интерфейсе взаимодействия сервера и внешней программы?
4. Каковы этапы работы по обработке входных данных внешней программой?
5. Какую информацию несет заголовок вывода сценария post в интерфейсе взаимодействия сервера и внешней программы?