Основы web-технологий

которым закодировано тело сообщения, например,


Заголовки протокола HTTP
Заголовок
Назначение


Заголовки объекта
Allow
Перечисляет поддерживаемые сервером методы
Content-Encoding
Способ, которым закодировано тело сообщения, например, с целью уменьшения размера
Content-Length
Длина сообщения в байтах
Content-Type
Тип содержимого и, возможно, некоторые параметры
ETag
Уникальный тэг ресурса на сервере, позволяющий сравнивать ресурсы
Expires
Дата и время, когда ресурс на сервере будет изменен, и его нужно получать заново
Last-Modified
Дата и время последней модификации содержимого
Заголовки ответа
Age
Число секунд, через которое нужно повторить запрос для получения нового содержимого
Location
URI ресурса, к которому нужно обратиться для получения содержимого
Retry-After
Дата и время или число секунд, через которое нужно повторить запрос, чтобы получить успешный ответ
Server
Название программного обеспечения сервера, приславшего ответ
Заголовки запроса
Accept
Типы содержимого, которое "понимает" клиент и может воспроизвести
Accept-Charset
Кодировки символов, в которых клиент может принимать текстовое содержимое
Accept-Encoding
Способ, которым сервер может закодировать сообщение
Host
Хост и номер порта, с которого запрашивается документ
If-Modified-Since
If-Match
If-None-Match
If-Range
If-Unmodified-Since
Заголовки запроса для условного обращения к ресурсу
Range
Запрос части документа
User-Agent
Название программного обеспечения клиента
Общие заголовки
Connection
Указывает серверу на завершение (close) или продолжение (keep-alive) сеанса
Date
Дата и время формирования сообщения


10.  Читает передаваемые программой CGI данные, формирует из них сообщение HTTP ответа и отправляет его пользовательскому агенту.
Если какие-либо из действий выполнить не удалось, то пользовательскому агенту отправляется строка с ошибочным кодом состояния и созданный процесс уничтожается.
Все современные операционные системы содержат в своем API средства для запуска дочернего процесса с данной средой окружения. В DOS – функция 4B00h прерывания 21h, в UNIX – системный вызов execve, в WIN32 – функция API CreateProcess. В любом случае, прикладная программа может получить доступ к среде окружения. Языки высокого уровня унифицируют интерфейс доступа к среде окружения для различных ОС. Например, в языках C и C++ имеются следующие переменные и функции:
#include <stdlib.h>
extern char **environ;
#include <stdlib.h>
char *getenv(char *varname);
Указатель на массив строк environ может быть использован для доступа ко всей среде окружения процесса. В массиве содержатся переменные окружения в формате "name=value", где name – имя переменной окружения, value – ее значение. Последний элемент массива содержит пустую строку в качестве признака окончания среды процесса.
Функция getenv позволяет получить значение переменной окружения, имя которой передано в качестве параметра varname. Если переменная с данным именем отсутствует, функция возвращает 0.
Если программой CGI обрабатывается запрос, содержащий метод POST, то тело сообщения запроса, в котором находится кодированное содержимое отправленной клиентом формы, можно получить из стандартного потока ввода. С каждым процессом связан стандартный поток ввода. Чтение из этого потока стандартно означает чтение с клавиатуры. При помощи операций с дескрипторами можно поместить блок данных в стандартный поток ввода. Читать из стандартного потока ввода в языке C удобнее всего при помощи функции чтения потока:
#include <stdio.h>
int fread(void *buffer, size_t size, size_t count, FILE *stream);


В параметре buffer передается адрес буфера, куда будут помещены прочитанные данные. В параметрах size и count указывается длина читаемого блока. Поскольку пользовательский агент передает длину тела сообщения в байтах, то в параметре size указывается 1, а в параметре count – длина тела сообщения запроса. В качестве параметра stream следует передать константу stdin для указания, что считывание производится из стандартного потока ввода. Функция fread возвращает количество фактически прочитанных символов.
Чтение из стандартного потока ввода является блокирующим, поэтому следует заранее определить число читаемых символов. Клиент вместе с другими заголовками передает заголовок Content-Length, в котором сообщается длина тела сообщения. Сервер при формировании среды окружения создает переменную CONTENT_LENGTH, значение которой совпадает со значением соответствующего заголовка. Поэтому чтением данной переменной можно определить число символов в стандартном потоке ввода.
Помимо стандартного потока ввода, с каждым процессом связан стандартный поток вывода. Для обычных процессов стандартный поток вывода, как правило, связан с экраном. При помощи операций замены дескриптора можно переключить стандартный поток вывода на любой открытый дескриптор. Сервер Web осуществляет переключение стандартного потока вывода на дескриптор канала или другого коммуникационного объекта. В результате такого перенаправления вся выводимая программой CGI в стандартный поток вывода информация будет передаваться серверу Web.
Формат данных, передаваемых от приложения CGI серверу Web, совместим с форматом сообщений протокола HTTP. Эти данные должны содержать заголовки, пустую строку и тело сообщения. Заголовки делятся на заголовки CGI и заголовки HTTP. Существует 3 заголовка CGI:
1.  Content-Type – тип содержимого передаваемого тела сообщения. Значение соответствует заголовку Content-Type протокола HTTP.
2.  Location – идентификатор, в котором содержится запрашиваемый ресурс. Значение соответствует заголовку Location протокола HTTP. При получении данного заголовка сервер Web передает пользовательскому агенту ответ с кодом перенаправления.


3.  Status – строка состояния. Значением данного заголовка является трехзначный код состояния и поясняющая фраза, которые сервер Web должен передать пользовательскому агенту.
Все остальные заголовки считаются сервером Web заголовками HTTP и передаются пользовательскому агенту без изменения, также как и тело сообщения. Можно считать, что данные передаются от программы CGI непосредственно клиенту Web.
Выводить в стандартный поток вывода можно при помощи функции printf():
#include <stdio.h>
int printf(char *format, ...);
При обмене двоичными данными между приложением CGI и сервером Web, например, при отправке графического изображения, сформированного приложением CGI в процессе своей работы, следует учитывать некоторые особенности. Потоки могут находиться в двух режимах: двоичном и текстовом. В двоичном режиме данные передаются в том виде, в котором они представляются при хранении этих данных в памяти. В текстовом режиме некоторые символы могут приводить к определенным эффектам. Например, при записи символа конца файла происходит закрытие текстового потока, а при записи символа перевода строки в текстовый поток записываются два символа: перевода строки и возврата каретки. Аналогично, при чтении двух символов из потока, содержащего подряд символы перевода строки и возврата каретки, будет считан только один символ перевода строки. Поскольку стандартные потоки, как правило, открываются в текстовом режиме, перед передачей двоичных данных следует перевести эти потоки в двоичный режим. Для перевода потока в двоичный режим следует сначала получить его дескриптор. Это можно сделать, вызвав функцию fileno() стандартной библиотеки:
#include <stdio.h>
int fileno(FILE *stream);
Единственным параметром данной функции является указатель на поток. При получении дескриптора стандартного потока вывода в качестве значения параметра следует указать константу stdout, а при получении дескриптора стандартного потока ввода – stdin. Полученное значение дескриптора теперь можно использовать при вызове функции setmode() для перевода потока в двоичный режим:


#include <io.h>
#include <fcntl.h>
int setmode(int handle, int mode);
Первым параметром данной функции является дескриптор открытого потока. Вторым параметром является режим, в который будет переведен поток, задаваемый одной из констант: O_TEXT при переводе потока в текстовый режим или O_BINARY при переводе потока в двоичный режим. Функция возвращает ранее установленный режим для данного потока или –1 в случае ошибки.
Для записи в поток, находящийся в двоичном режиме, удобно использовать функцию fwrite():
#include <stdio.h>
int fwrite(void *buffer, size_t size, size_t count, FILE *stream);
В параметре buffer передается адрес буфера, откуда будут взяты записываемые в поток данные. В параметрах size и count указывается длина читаемого блока. Поскольку приложение CGI передает длину тела сообщения в байтах, то в параметре size указывается 1, а в параметре count – длина передаваемого блока данных. В качестве параметра stream следует передать константу stdout, для указания того, что запись производится в стандартный поток вывода. Функция fwrite() возвращает количество фактически записанных символов.
Функцию printf() неудобно использовать при передаче двоичных данных, поскольку в передаваемом блоке могут оказаться нули.
Стандартный поток ввода практически всегда нужно переводить в двоичный режим, поскольку, если передаваемые от пользовательского агента данные являются многострочными, то есть содержат символы перевода строки и возврата каретки, то значение переменной окружения CONTENT_LENGTH не будет соответствовать фактическому числу символов, прочитанному из стандартного потока ввода в текстовом режиме.
Программа CGI должна выполнить следующие действия:
1.     Прочитать значение заголовка REQUEST_METHOD для определения запрашиваемого метода.
2.     Если запрашиваемый метод – GET, то прочитать переменную окружения QUERY_STRING и считать полученное значение кодированным содержимым формы. Способ кодирования считать равным application/x-www-url-encoded.
3.     Если запрашиваемый метод – POST, то прочитать длину тела сообщения запроса из переменной окружения CONTENT_LENGTH. Из стандартного потока ввода прочитать тело сообщения запроса и считать его кодированным содержимым формы. Способ кодирования прочитать из переменной окружения CONTENT_TYPE.
4.     Разобрать кодированное содержимое формы в зависимости от способа кодирования.
5.     Прочитать необходимые программе CGI переменные окружения.
6.     Выполнить все необходимые в программе действия и сформировать документ с результатом работы программы.
7.     Отправить в стандартный поток вывода все необходимые заголовки CGI и HTTP и пустую строку.
8.     Отправить в стандартный поток вывода сформированный документ.

Содержание раздела