Приложение 24.
Интерфейс CGI

Введение в CGI

Большая часть нашего общения с WWW сводится к тому, что обозреватель, работающий на компьютере-клиенте, передает Веб-серверу URI Веб-страницы, сервер находит ее в Сети и передает обозревателю, а тот эту страницу отображает. Этот способ общения вполне достаточен для обычного серфинга, но существует обширный круг задач, требующих более развитой технологии взаимодействия сервера с клиентом, например:

  • обращение к поисковой системе с целью поиска узлов, содержащих определенную информацию;
  • запрос к базе данных с целью выборки данных, отвечающих заданному критерию;
  • передача серверу результатов заполнения пользователем формы с целью оплаты отобранного товара или проведения банковской транзакции.

Все эти примеры, по сути дела, сводятся к одной задаче. Нам нужна технология, позволяющая:

  1. запустить с компьютера клиента на сервере определенную программу (обычно называемую сценарием сервера);
  2. передать ей (опять же от клиента) определенные параметры;
  3. передать результаты работы программы от сервера обратно клиенту.

Для решения этой задачи нужен единый интерфейс клиент-сервер, который не зависел бы ни от платформы, ни от операционной системы, ни от языка программирования, на котором реализован сценарий сервера. Такой несложный интерфейс был создан в 1993 г. в NCSA (The National Centre for Supercomputing Applications) под названием CGI (Common Gateway Interface) и продолжает использоваться без существенных изменений по сей день. Мы опираемся в последующем изложении на спецификацию CGI/1.1, ревизию 03 от 25 июня 1999 г. Общая схема взаимодействия клиента с сервером иллюстрируется следующим рисунком:

Интерфейс CGI

Передача запроса от клиента к серверу

Вспомним, что всякий запрос передается от обозревателя к серверу в форме URI, общий вид которого таков (подробности см. в Приложении 2):

протокол://пользователь@сервер:порт/путь?запрос

Суть CGI состоит в том, что он фиксирует стандартные имена метапеременных, которые сервер должен заполнить, анализируя URI запроса. Эти метапеременные представляют собой текстовые строки, которые должны быть доступны запускаемому сценарию; конкретная реализация механизма доступа к переменным зависит от операционной системы. Согласно спецификации CGI запрос на запуск сценария будет выглядеть так:

протокол "://" SERVER_NAME ":" SERVER_PORT SCRIPT_NAME PATH_INFO "?" QUERY_STRING

где SERVER_NAME, SERVER_PORT, SCRIPT_NAME, PATH_INFO и QUERY_STRING — метапеременные, соответствующие составным элементам URI и описанные ниже.

Примечания.

  1. Протокол URI и протокол CGI не всегда совпадают. Например, если доступ к ресурсу осуществляется через защитный механизм SSL (Secure Sockets Layer), то именем протокола URI будет https, а именем протокола CGI по-прежнему http. Впрочем, CGI не содержит механизмов, позволяющих сценарию извлечь имя протокола, поэтому можно считать, что оно всегда http. Кроме того, URI запроса к CGI не может содержать закладок.
  2. В действительности, URI сценария содержит не SCRIPT_NAME и PATH_INFO, а их кодированную форму. Дело в том, что URL может состоять только из символов базовой латиницы, а в запросе могут присутствовать и иные символы. В этом случае они преобразуются в кодировку UTF-8, как описано в Приложении 2, а затем передаются серверу.

Запуск сценария и передача ему параметров

Как отмечалось выше, сценарием может быть исполняемый модуль, написанный на любом языке (например, на C++). Но чаще всего в качестве сценария выступает интерпретируемый модуль (например, на языке PERL). При этом операционная система сервера распознает тип сценария и вызывает соответствующий интерпретатор (например, perl.exe).

Далее, сервер обязан извлечь информацию из URI запроса и разместить ее в метапеременных. Имена метапеременных не должны зависеть от регистра, но это также определяется системой. Поэтому лучше всегда писать их прописными буквами, как делаем мы в этом справочнике. Значения метапеременных должны считаться зависящими от регистра.

Стандартные метапеременные

Следующие имена метапеременных являются стандартными и должны формироваться всеми серверами, поддерживающими интерфейс CGI.

Таблица П24.1. Стандартные метапеременные CGI
AUTH_TYPE Тип авторизации. Если сервер признал полномочия пользователя, значение этой переменной "Basic", в противном случае оно не определено.
CONTENT_LENGTH Десятичное число байтов в теле сообщения, если оно присоединено к запросу.
CONTENT_TYPE Тип MIME тела сообщения, если оно присоединено к запросу.
GATEWAY_INTERFACE Текущая версия CGI. В настоящее время это "CGI/1.1"
PATH_INFO Указывает на ресурс или подресурс, который должен быть возвращен сценарием. Это часть URI между именем сценария и строкой запроса.
PATH_TRANSLATED Значение PATH_INFO, в котором все виртуальные имена отображены в реальные каталоги сервера.
QUERY_STRING Строка запроса к сценарию. Это все, что следует в URI запроса после "?".
REMOTE_ADDR IP-адрес клиента.
REMOTE_HOST Полное имя домена клиента.
REMOTE_IDENT Если Веб-сервер поддерживает идентификацию по RFC 1413 Внешняя ссылка, сюда заносится имя удаленного пользователя. Используется только для регистрации.
REMOTE_USER Если AUTH_TYPE = "Basic", то здесь содержится имя пользователя, переданное клиентом и проверенное сервером на наличие прав доступа.
REQUEST_METHOD Метод запроса HTTP ("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "TRACE").
SCRIPT_NAME Имя запускаемого сценария.
SERVER_NAME Имя или IP-адрес сервера.
SERVER_PORT Порт TCP/IP, на который пришел запрос.
SERVER_PROTOCOL Имя и версия протокола, связанного с запросом. Обычно это "HTTP/1.1".
SERVER_SOFTWARE Имя и версия Веб-сервера в формате "имя/версия".

Обработка тела сообщения

Если запрос помимо URI содержит присоединенные данные, то сервер должен занести размер этих данных в байтах в переменную CONTENT_LENGTH и обеспечить сценарию доступ к этим данным. Если не оговорено иное, доступ осуществляется через дескриптор файла "стандартный ввод" (stdin).

Сценарий считывает переданные ему данные, при необходимости анализирует метапеременные и формирует документ, который сервер должен передать клиенту.

Передача данных от сценария к серверу

Сценарий всегда должен вернуть какой-либо результат серверу, а сервер должен обеспечить механизм передачи результатов от сценария к серверу. Если не оговорено иное, эта передача осуществляется через дескриптор файла "стандартный вывод" (stdout). Сервер, в свою очередь, формирует из полученных от сценария данных стандатный HTTP-отклик и передает его клиенту.

Результатом работы сценария может быть либо сгенерированный HTML-документ, либо указание серверу вернуть пользователю определенный ресурс. Данные, передаваемые сценарием серверу, начинаются со служебного заголовка, состоящего из текстовых строк и заканчивающегося пустой строкой (т. е. строкой, состоящей из LF или CR/LF). Служебный заголовок может содержать три директивы, аналогичные полям заголовка HTTP:

Поле Описание
Content-Type Содержит тип MIME возвращаемого документа.
Location Возвращает URI ресурса. Используется в том случае, когда сценарий передает серверу не сформированный документ, а ссылку на ресурс.
Status Возвращает код состояния в формате число строка, где число — номер кода состояния, а строка — соответствующее сообщение. Этот код состояния заносится в строку состояния HTTP-отклика.

Пример документа, сформированного сценарием:

Content-type: text/html; charset=windows-1251
Status: 200 OK

<HTML><HEAD>
<TITLE>Вывод HTML из CHI-сценария</TITLE>
</HEAD><BODY>
<H1>Пример</H1>
<P>Как вам <STRONG>это</STRONG> нравиться?</P>
</BODY></HTML>

Реальные примеры CGI-сценариев приведены в гл. 6.13.