WebSphere Application Server

Руководство по программированию для Edge Components

версия 6.1
GC43-0477-00
Первое издание (май 2006 года)

Настоящее издание относится к:

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

Для заказа публикаций обратитесь в местное представительство или филиал IBM.

Copyright International Business Machines Corporation 2005. Все права защищены.

Содержание

Рис.
О книге
Для кого предназначена данная книга
Необходимые знания
Обозначения и терминология
Специальные функции доступа
Связанные документы и Web-сайты
Ждем ваших отзывов
Общие сведения о настройке Edge components
Настройка компонента Caching Proxy
Настройка компонента Load Balancer
Поиск примера программы
API Caching Proxy
Обзор API Caching Proxy
Процедура написания программ API
Этапы обработки сервера
Рекомендации
Функции модулей
Заранее определенные функции и макросы
Директивы конфигурации Caching Proxy для этапов обработки API
Совместимость с другими API
Портирование программ CGI
Справочная информация об API Caching Proxy
Переменные
Идентификация и проверка прав доступа
Кэширование вариантов
Примеры API
Пользовательские советники
Советники предоставляют информацию о распределении нагрузки
Стандартный советник
Создание пользовательского советника
Обычный режим и режим замены
Соглашения об именах советников
Компиляция
Выполнение пользовательского советника
Обязательные процедуры
Порядок поиска
Присваивание имен файлам и использование пути к файлу
Методы пользовательского советника и вызов функций
Примеры
Стандартный советник
Советник с побочным потоком
Посредник с двумя портами
Советник WebSphere Application Server
Использование данных, полученных от советников
Индекс

Рис.

  1. Диаграмма этапов сервера proxy
  2. Приставки переменных HTTP_ и PROXY_
  3. Процессы идентификации и проверки прав доступа сервером Proxy

О книге

В этом разделе описываются цели, структура и условные обозначения, используемые в документе WebSphere Application Server Programming Guide for Edge Components.

Для кого предназначена данная книга

В этой книге описываются прикладные программные интерфейсы (API), доступные для настройки продукта Edge components сервера WebSphere Application Server версии 6.1. Эти сведения предназначены для разработчиков программных модулей. Эта информация также может заинтересовать проектировщиков сетей и системных администраторов, которые могут найти здесь описание возможностей по настройке данного продукта.

Необходимые знания

Для понимания информации, приведенной в данной книге, необходимо иметь представление о приемах программирования на языках Java или C, в зависимости от используемого API. Методы и структуры для каждого из этих интерфейсов описаны в соответствующей документации, но вы должны уметь создавать собственные приложения, а также компилировать и тестировать их. Для некоторых интерфейсов приводятся примеры программ, однако их можно использовать только как руководство для создания собственных приложений.

Обозначения и терминология

В этой документации используются следующие обозначения.

Табл. 1. Обозначения в книге
Обозначение Значение
Полужирное начертание Относится к меню, элементам меню, меткам, кнопкам, значкам и папкам графического интерфейса пользователя (GUI). Также применяется для выделения названий команд в обычном тексте.
Интервал Обозначает текст, который необходимо ввести в командной строке. Также применяется для обозначения текста на экране, примеров программ и частей файлов.
Курсив Применяется для обозначения значений переменных (например, вместо переменной ИмяФайла необходимо указать имя файла). Также используется в заголовках книг, для выделения текста и пр.
Ctrl-x Где x - это название клавиши или комбинация клавиш. Например, Ctrl-c означает нажать клавишу C, удерживая нажатой клавишу Ctrl.
Return Применяется для обозначения клавиш Return, Enter или левой стрелки.
% Обозначает командную строку в операционных системах Linux и UNIX, для использования которой полномочия пользователя root не требуются.
# Обозначает командную строку в операционных системах Linux и UNIX, для использования которой требуются полномочия пользователя root.
C:\ Обозначает командную строку Windows.
Ввод команд Если указано "ввести" или "выполнить" команду, введите команду и нажмите клавишу Return. Например, инструкция "Введите команду ls" означает, что в командной строке необходимо ввести ls и нажать клавишу Return.
[ ] Обозначает необязательные параметры в синтаксисе команды.
{ } Обозначает списки для выбора параметров команды.
| Отделяет допустимые значения параметров, заключенных в { } (скобки) в синтаксисе команды.
... Многоточие в синтаксисе команды означает, что предыдущий элемент можно ввести еще несколько раз. В примерах программ многоточие означает опущенный для краткости исходный код.

Специальные функции доступа

Специальные функции доступа позволяют работать с программой людям с ограниченными физическими возможностями, например, с ограниченной подвижностью или со сниженным зрением. В WebSphere Application Server версии 6.1 предусмотрены следующие специальные функции доступа:

Связанные документы и Web-сайты

Ждем ваших отзывов

Ваши отзывы помогают нам обеспечивать высокое качество и точность публикуемой информации. Если у вас есть комментарии по этой книге или другой документации для Edge components сервера WebSphere Application Server:

Общие сведения о настройке Edge components

В этой книге обсуждаются прикладные программные интерфейсы (API), предоставляемые для продукта Edge components сервера WebSphere Application Server. (Продукт Edge components для сервера WebSphere Application Server включает компоненты Caching Proxy и Load Balancer.) Для настройки взаимодействия между Edge components, а также с другими системами администраторы могут использовать различные интерфейсы.

ВАЖНЫЕ ИСКЛЮЧЕНИЯ:

API, описанные в этом документе, относятся к нескольким категориям.

Настройка компонента Caching Proxy

Компонент Caching Proxy включает несколько интерфейсов, записанных в последовательность обработки, в которую можно добавлять пользовательские функции или использовать вместо стандартной обработки. Настройка включает изменение или расширение следующих задач:

Пользовательские приложения (или модули Caching Proxy) вызываются в определенные моменты последовательности обработки сервера Proxy.

API компонента Caching Proxy применяется для реализации определенных функций системы. Например, поддержка LDAP реализована в виде модуля.

API Caching Proxy подробно описывает интерфейс и содержит инструкции по настройке сервера Proxy для работы с модулями.

Настройка компонента Load Balancer

Для настройки компонента Load Balancer используются пользовательские советники. Советники измеряются фактическое значение нагрузки на серверах. Пользовательские советники позволяют использовать собственные методы измерения нагрузки в конкретной системе. Эта функция особенно для полезна для измененных или специализированных Web-серверов.

Пользовательские советники содержит подробную информацию о разработке и использовании пользовательских советников. Также содержит примеры программ советников.

Поиск примера программы

Примеры программы для этих API можно найти на компакт-диске Edge Components в каталоге samples. Дополнительные примеры программы доступны на Web-сайте WebSphere Application Server, www.ibm.com/software/webservers/appserv/

API Caching Proxy

В этом разделе рассказано об интерфейсах прикладного программирования (API) Caching Proxy, т.е. о том, что это такое, зачем оно нужно и как работает.

ВАЖНАЯ ИНФОРМАЦИЯ: Caching Proxy может присутствовать во всех устанавливаемых конфигурациях Edge Components, за исключением следующих случаев:

Обзор API Caching Proxy

API - это интерфейс Caching Proxy, позволяющий вам расширять базовые возможности сервера Proxy. Вы можете создавать расширения или встраиваемые модули для реализации настраиваемых алгоритмов работы. Вот некоторые примеры применения API:

API Caching Proxy предоставляет следующие преимущества:

Процедура написания программ API

Перед написанием собственных программ модулей Caching Proxy необходимо ознакомиться с принципом работы сервера proxy. Работу сервера proxy при обработке запросов можно набить на несколько отдельных этапов. Для каждого из этих этапов вы можете указать с помощью API собственные функции. Например, хотите ли выполнить какие-либо действия после считывания клиентского запроса, но перед выполнением каких-либо других операций? Или, может быть, вам требуется выполнить какие-либо особые процедуры во время идентификации и повторить их после отправки запрошенного файла?

API предоставляют библиотеку заранее определенных функций. Ваши программы модулей могут вызывать библиотечные функции API для взаимодействия с процессами сервера proxy (например, для манипуляций с запросами, считывания и записи заголовков запросов, либо для занесения записей в протоколы сервера proxy). Эти библиотечные функции не следует путать с вашими собственными функциями модулей, вызываемыми сервером proxy. Заранее определенные функции описаны в разделе Заранее определенные функции и макросы.

Указать серверу proxy, какие из ваших функций модулей должны вызываться на каждом из этапов обработки, можно с помощью директив API Caching Proxy, заданных в файле конфигурации сервера. Эти директивы описаны в разделе Директивы конфигурации Caching Proxy для этапов обработки API.

В настоящий документ включены следующие сведения:

С помощью этих компонентов и процедур вы сможете создавать собственные программы модулей Caching Proxy.

Этапы обработки сервера

Работу сервера proxy можно разделить на несколько этапов в соответствии с типом обработки, выполняемой на каждом из этих этапов. Каждый этап включает промежуточную точку, на которой может быть выполнена указанная часть вашей программы. Добавляя в файл конфигурации Caching Proxy (ibmproxy.conf) директивы API, вы указываете, какие функции модуля должны вызываться на каждом этапе. Указав для одного этапа несколько директив, вы можете вызывать для этого этапа несколько функций модуля.

Некоторые этапы входят в состав процесса обработки запроса сервером. Другими словами, сервер proxy выполняет эти этапы каждый раз, когда он обрабатывает полученный запрос. Другие этапы выполняются независимо от обработки запросов, т.е. сервер выполняет их независимо от того, выполняется какой-либо запрос или нет.

Ваши откомпилированные программы хранятся в общем объекте, например в файле DLL или .so, в зависимости от операционной системы. По мере выполнения этапов обработки запроса сервер вызывает связанные с каждым этапом функции модулей до тех пор, пока одна из функций не укажет, что она обработала запрос. Если вы указали для какого-либо этапа несколько функций модулей, то эти функции вызываются в том порядке, в котором соответствующие директивы указаны в файле конфигурации.

Если запрос не обрабатывается функцией модуля (из-за того, что вы не включили директиву API Caching Proxy для соответствующего этапа или функция модуля для этого этапа вернула значение HTTP_NOACTION), то сервер выполняет действие по умолчанию для этого шага.

Примечание: Это верно для всех этапов, за исключением этапа Service, для которого не предусмотрено действие по умолчанию.

Рис. 1 иллюстрирует этапы обработки сервера proxy и определяет последовательность выполнения этапов, связанных с обработкой запросов.

Рис. 1. Диаграмма этапов сервера proxy

Четыре из показанных на диаграмме этапов выполняются независимо от обработки запросов клиентов. Эти этапы связаны с работой и обслуживанием сервера proxy. К их числу относятся:

В следующем списке разъясняется назначение каждого этапа, изображенного на Рис. 1. Обратите внимание, что не все этапы обязательно выполняются при обработке каждого запроса.

ServerInit
Выполняет инициализацию при запуске сервера proxy и перед получением каких-либо запросов клиентов.
Midnight
Запускает модуль в полночь, вне контекста запроса. Этот этап показан на диаграмме отдельно, поскольку он не является частью обработки запроса; другими словами, его выполнение не связано с каким-либо конкретным запросом.
GCAdvisor
Влияет на решения о сборе мусора при обработке файлов, находящихся в кэше. Этот этап показан на диаграмме отдельно, поскольку он не является частью обработки запроса; другими словами, его выполнение не связано с каким-либо конкретным запросом. Сбор мусора выполняется при достижении кэшем максимального размера. (Информация о конфигурации сбора мусора в кэше приведена в руководстве WebSphere Application Server Caching Proxy Administration Guide.)
PreExit

Выполняется после чтения запроса, но перед любыми другими действиями.

Если по завершении обработки этот этап указывает, что запрос обработан (HTTP_OK), то сервер пропускает остальные этапы обработки запроса и выполняет только этапы Transmogrifier, Log и PostExit.

NameTrans
Преобразует виртуальный путь (из URL) в физический.
Проверка прав доступа

Использует сохраненные маркеры системы безопасности для проверки доступа к физическим каталогам, ACL, других средств управления доступом, а также для формирования заголовков WWW-Authenticate, необходимых для проведения базовой идентификации. Если вы создаете собственную функцию модуля, замещающую этот этап, то вы должны самостоятельно сформировать эти заголовки.

Дополнительная информация приведена в разделе Идентификация и проверка прав доступа.

Идентификация

Декодирует, проверяет и сохраняет маркеры системы безопасности.

Дополнительная информация приведена в разделе Идентификация и проверка прав доступа.

ObjectType
Находит объект файловой системы с заданным путем.
PostAuthorization

Выполняется после проверки прав доступа и обнаружения объекта, но перед собственно выполнением запроса.

Если по завершении обработки этот этап указывает, что запрос обработан (HTTP_OK), то сервер пропускает остальные этапы обработки запроса и выполняет только этапы Transmogrifier, Log и PostExit.

Service
Выполняет запрос (отправляя файл, запуская программу CGI и т.д.)
Proxy Advisor
Определяет принятие решений о кэшировании и работе proxy.
Transmogrifier
Предоставляет доступ на запись к элементу данных отправляемого клиенту ответа.
Log
Обеспечивает ведение настраиваемых протоколов транзакций.
Error
Обеспечивает настраиваемые процедуры обработки ошибок.
PostExit
Выполняет очистку ресурсов, выделенных для обработки запроса.
Server Termination
Выполняет очистку при обычном завершении работы сервера.

Рекомендации

Функции модулей

При написании собственных функций для вызова на различных этапах обработки запросов следуйте синтаксическим диаграммам, показанным в Прототипы функций модулей.

Каждая функция должна указывать в параметре кода возврата значение, указывающее на выполненное действие:

Прототипы функций модулей

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

В каждой из функций модуля допустимы определенные библиотечные функции API. Некоторые функции допустимы не на всех этапах. Следующие библиотечные функции API можно вызывать их всех функций модулей:

Дополнительные допустимые и недопустимые функции API перечислены в описаниях прототипов функций.

Значение переданного вашей функции параметра handle можно передать в виде первого аргумента библиотечной функции. Библиотечные функции API описаны в разделе Заранее определенные функции и макросы.

ServerInit

void HTTPD_LINKAGE ServerInitFunction (
         unsigned char *handle,
     unsigned long *major_version,
     unsigned long *minor_version, 
         long *return_code 
     )

Определенная для этого этапа функция вызывается один раз во время загрузки модуля при инициализации сервера. В этот момент вы можете выполнить собственные действия по инициализации перед началом обработки запросов.

Несмотря на то, что должны вызываться все функции инициализации сервера, возврат кода ошибки функцией на этом этапе приводит к тому, что все остальные функции, настроенные в том же модуле, что и функция, вернувшая код ошибки, игнорируются. (Это значит, что все функции, находящиеся в том же общем объекте, что и функция, вернувшая код ошибки, не вызываются.)

Параметр version содержит номер версии сервера proxy. Он передается сервером Caching Proxy.

PreExit

void  HTTPD_LINKAGE  PreExitFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса после его считывания, но перед выполнением каких-либо других действий по обработке этого запроса. На этом этапе модуль может обращаться к клиентскому запросу до его обработки Caching Proxy.

Допустимые коды возврата для функции preExit:

Другие коды возврата использовать нельзя.

Если функция возвращает результат HTTP_OK, то сервер proxy считает, что запрос обработан. Все последующие этапы обработки запроса в этом случае пропускаются и выполняются только этапы отправки ответа (Transmogrifier, Log и PostExit).

На этом этапе допустимы все библиотечные функции сервера.

Midnight

void  HTTPD_LINKAGE  MidnightFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается один раз в сутки, в полночь. Она не связана с контекстом запросов. Например, она может применяться для вызова дочернего процесса и анализа протоколов. (Обратите внимание, что высокая нагрузка на этом этапе может помешать нормальному ведению протоколов.)

Идентификация

void  HTTPD_LINKAGE  AuthenticationFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса в соответствии со схемой идентификации запроса. Эта функция может применяться для настройки процедур проверки маркеров защиты, отправленных вместе с запросом.

NameTrans

void  HTTPD_LINKAGE  NameTransFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап преобразования имен NameTrans выполняется перед началом обработки запроса и обеспечивает механизм установления соответствия между URL и объектами файловой системы, например, именами файлов.

Проверка прав доступа

void  HTTPD_LINKAGE  AuthorizationFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап проверки прав доступа (Authorization) выполняется перед началом обработки запроса и может применяться для проверки допустимости возврата найденного объекта клиенту. При использовании базовой идентификации необходимо сформировать обязательные заголовки WWW-Authenticate.

ObjectType

void  HTTPD_LINKAGE  ObjTypeFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап определения типа объекта (ObjectType) выполняется перед началом обработки запроса. Он применяется для проверки наличия объекта и определения его типа.

PostAuthorization

void  HTTPD_LINKAGE  PostAuthFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается после проверки прав доступа, но перед выполнением каких-либо других действий. Если функция возвращает результат HTTP_OK, то сервер proxy считает, что запрос обработан. Все последующие этапы обработки запроса в этом случае пропускаются и выполняются только этапы отправки ответа (Transmogrifier, Log и PostExit).

На этом этапе допустимы все библиотечные функции сервера.

Service

void  HTTPD_LINKAGE  ServiceFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап обслуживания (Service) выполняет запрос, если он не был выполнен на этапах PreExit или PostAuthorization.

На этом этапе допустимы все библиотечные функции сервера.

Информация о том, как настроить функцию для этапа Service на основе метода HTTP, а не на основе URL, приведена в описании директивы Enable в руководстве WebSphere Application Server Caching Proxy Administration Guide.

Transmogrifier
Функции, вызываемые на этом этапе обработки, могут применяться для фильтрации потока данных ответа в виде потока. На этом этапе последовательно вызываются четыре функции модуля, каждая из которых представляет собой элемент конвейера, по которому передаются данные. Для каждого этапа вызываются предоставленные вами функции open, write, close и error (именно в таком порядке). Каждая функция обрабатывает тот же поток данных, что и предыдущие функции.

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

Примечания:

GCAdvisor

void  HTTPD_LINKAGE  GCAdvisorFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого находящегося в кэше файла во время сбора мусора. Эта функция позволяет вам оказывать влияние на то, какие файлы должны сохраняться в кэше, а какие - удаляться. Дополнительная информация приведена в описании переменных GC_*.

Proxy Advisor

void  HTTPD_LINKAGE  ProxyAdvisorFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается во время обслуживания каждого запроса proxy. Например, она может применяться для установки переменной USE_PROXY.

Log

void  HTTPD_LINKAGE  LogFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для каждого запроса после его обработки и закрытия соединения с клиентом. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Эта функция вызывается независимо от результата обработки запроса. Если вы не хотите, чтобы ваш модуль переопределял механизм ведения протоколов по умолчанию, то вместо кода возврата HTTP_OK передайте код HTTP_NOACTION.

Error

void  HTTPD_LINKAGE  ErrorFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается для всех запросов, при выполнении которых возникли ошибки. Если вы хотите, чтобы функция модуля вызывалась только для запросов с ошибками, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этот этап предоставляет возможность настройки алгоритма обработки ошибок.

PostExit

void  HTTPD_LINKAGE  PostExitFunction (
         unsigned char *handle,
         long *return_code 
         )

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

Server Termination

void  HTTPD_LINKAGE  ServerTermFunction (
         unsigned char *handle,
         long *return_code 
         )

Определенная для этого этапа функция вызывается во время нормального завершения работы сервера. Она позволяет выполнить очистку ресурсов, выделенных на этапе ServerInit. На этом этапе не следует вызывать функции HTTP_* (результат может оказаться непредсказуемым). Если в файле конфигурации для этапа ServerTerm указано несколько директив с API Caching Proxy, то они все будут последовательно вызваны.

Прим.:
Из-за существующего в настоящее время ограничения в коде Solaris модуль этапа ServerTerm не выполняется при завершении работы Caching Proxy на платформе Solaris с помощью команды ibmproxy -stop. Информация о запуске и завершении работы Caching Proxy приведена в руководстве WebSphere Application Server Caching Proxy Administration Guide.

Значения и коды возврата HTTP

Эти коды возврата соответствуют спецификации HTTP 1.1, RFC 2616, опубликованной консорциумом World Wide Web (www.w3.org/pub/WWW/Protocols/). Функции вашего модуля должны возвращать одно из этих значений.

Табл. 2. Коды возврата HTTP для функций API Caching Proxy
Значение Код возврата
0 HTTP_NOACTION
100 HTTP_CONTINUE
101 HTTP_SWITCHING_PROTOCOLS
200 HTTP_OK
201 HTTP_CREATED
202 HTTP_ACCEPTED
203 HTTP_NON_AUTHORITATIVE
204 HTTP_NO_CONTENT
205 HTTP_RESET_CONTENT
206 HTTP_PARTIAL_CONTENT
300 HTTP_MULTIPLE_CHOICES
301 HTTP_MOVED_PERMANENTLY
302 HTTP_MOVED_TEMPORARILY
302 HTTP_FOUND
303 HTTP_SEE_OTHER
304 HTTP_NOT_MODIFIED
305 HTTP_USE_PROXY
307 HTTP_TEMPORARY_REDIRECT
400 HTTP_BAD_REQUEST
401 HTTP_UNAUTHORIZED
403 HTTP_FORBIDDEN
404 HTTP_NOT_FOUND
405 HTTP_METHOD_NOT_ALLOWED
406 HTTP_NOT_ACCEPTABLE
407 HTTP_PROXY_UNAUTHORIZED
408 HTTP_REQUEST_TIMEOUT
409 HTTP_CONFLICT
410 HTTP_GONE
411 HTTP_LENGTH_REQUIRED
412 HTTP_PRECONDITION_FAILED
413 HTTP_ENTITY_TOO_LARGE
414 HTTP_URI_TOO_LONG
415 HTTP_BAD_MEDIA_TYPE
416 HTTP_BAD_RANGE
417 HTTP_EXPECTATION_FAILED
500 HTTP_SERVER_ERROR
501 HTTP_NOT_IMPLEMENTED
502 HTTP_BAD_GATEWAY
503 HTTP_SERVICE_UNAVAILABLE
504 HTTP_GATEWAY_TIMEOUT
505 HTTP_BAD_VERSION

Заранее определенные функции и макросы

Из своих собственных модулей вы можете вызывать библиотечные макросы и функции сервера. При этом необходимо использовать описанные ниже имена и форматы. В описаниях параметров буква i обозначает входной параметр, буква o - выходной, а буквы i/o указывают, что параметр используется как для ввода, так и для вывода информации.

Каждая из этих функций возвращает один их кодов возврата HTTPD, в зависимости от того, насколько успешно выполнен запрос. Эти коды описаны в разделе Коды возврата заранее определенных функций и макросов.

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

HTTPD_authenticate()
Выполняет идентификацию ИД и/или пароля пользователя. Допускается только на этапах PreExit, Authentication, Authorization и PostAuthorization.

void  HTTPD_LINKAGE  HTTPD_authenticate (
    unsigned char *handle,             /* i; описатель */
         long *return_code         /* o; код возврата */
         )
HTTPD_cacheable_url()
Указывает, допустимо ли кэширование информации с указанным URL в соответствии со стандартами Caching Proxy.

void HTTPD_LINKAGE  HTTPD_cacheable_url ( 
    unsigned char *handle,             /* i; описатель */
        unsigned char *url,         /* i; проверяемый URL */
        unsigned char *req_method,  /* i; метод запроса для URL */
        long *retval                /* o; код возврата */
        )

Возвращенное значение HTTPD_SUCCESS указывает, что информация с данным URL может кэшироваться. Значение HTTPD_FAILURE указывает,что кэширование запрещено. Эта функция может также вернуть значение HTTPD_INTERNAL_ERROR.

HTTPD_close()
(Допускается только на этапе Transmogrifier.) Передает управление следующей процедуре close в стеке. Эту функцию следует вызывать на этапе Transmogrifier из функций open, write и close после выполнения всех требуемых операций. Данная функция уведомляет сервер Proxy, что ответ обработан и что этап Transmogrifier завершен.

void  HTTPD_LINKAGE  HTTPD_close (
    unsigned char *handle,             /* i; описатель */
         long *return_code         /* o; код возврата */
         )
HTTPD_exec()
Выполняет сценарий обработки запроса. Допускается на этапах PreExit, Service, PostAuthorization и Error.

void  HTTPD_LINKAGE  HTTPD_exec (
    unsigned char *handle,             /* i; описатель */
         unsigned char *name,           /* i; имя выполняемого сценария */
         unsigned long *name_length,   /* i; длина имени */
         long *return_code         /* o; код возврата */
         )
HTTPD_extract()
Извлекает значение переменной, связанной с запросом. Переменные, допустимые в параметре name, совпадают с используемыми в CGI. Дополнительная информация приведена в разделе Переменные. Обратите внимание, что данная функция допустима на всех этапах, однако некоторые переменные допустимы не на всех этапах.

void  HTTPD_LINKAGE  HTTPD_extract (
    unsigned char *handle,             /* i; описатель */
      unsigned char *name,         /* i; имя извлекаемой переменной */
         unsigned long *name_length,   /* i; длина имени */
      unsigned char *value,        /* o; буфер для размещения
                                         значения */
      unsigned long *value_length, /* i/o; размер буфера */
         long *return_code         /* o; код возврата */
      )

Если эта функция возвращает код HTTPD_BUFFER_TOO_SMALL, значит размер запрошенного буфера был недостаточен для извлеченного значения. В этом случае функция не использует буфер, но указывает в параметре value_length размер буфера, необходимый для успешного извлечения значения. Повторите операцию с буфером, размер которого равен или больше возвращенному значению value_length.

Прим.:
Если переменная извлекается из заголовка HTTP, то функция HTTPD_extract() извлечет только первое совпадение, даже если запрос содержит несколько заголовков с одинаковыми именами. В этом случае вместо HTTPD_extract() можно использовать функцию httpd_getvar(), которая имеет также и другие преимущества. Дополнительная информация приведена в разделе ***.
HTTPD_file()
Отправляет файл в ответ на запрос. Допускается только на этапах PreExit, Service, Error, PostAuthorization и Transmogrifier.

void  HTTPD_LINKAGE  HTTPD_file (
    unsigned char *handle,             /* i; описатель */
         unsigned char *name,            /* i; имя отправляемого файла */
         unsigned long *name_length,   /* i; длина имени */
         long *return_code         /* o; код возврата */
         )
httpd_getvar()
Аналогична HTTPD_extract(), однако использовать эту функцию проще, поскольку она не требует указывать длину аргументов.

const  unsigned char *          /* o; значение переменной*/
HTTPD_LINKAGE
httpd_getvar(
    unsigned char *handle,             /* i; описатель */
       unsigned char *name,         /* i; имя переменной */
   unsigned long *n             /* i; индекс массива
                                      заголовка */
   )

Индекс массива начинается с 0. Для получения первого элемента массива укажите значение n, равное 0; для получения пятого элемента - значение n, равное 4.

Прим.:
Не изменяйте и не уничтожайте возвращенное значение. Возвращенная строка заканчивается символом null.
HTTPD_log_access()
Записывает строку в протокол доступа сервера.

void  HTTPD_LINKAGE  HTTPD_log_access (
    unsigned char *handle,             /* i; описатель */
         unsigned char *value,           /* i; записываемые данные */
         unsigned long *value_length,    /* i; длина данных */
         long *return_code         /* o; код возврата */
         )  

Обратите внимание, что для записи символа процента (%) в протокол доступа сервера escape-символы не нужны.

HTTPD_log_error()
Записывает строку в протокол ошибок сервера.

void  HTTPD_LINKAGE  HTTPD_log_error (
    unsigned char *handle,             /* i; описатель */
         unsigned char *value,           /* i; записываемые данные */
         unsigned long *value_length,    /* i; длина данных */
         long *return_code         /* o; код возврата */
         )

Обратите внимание, что для записи символа процента (%) в протокол ошибок сервера escape-символы не нужны.

HTTPD_log_event()
Записывает строку в протокол событий сервера.

void  HTTPD_LINKAGE  HTTPD_log_event (
    unsigned char *handle,             /* i; описатель */
         unsigned char *value,           /* i; записываемые данные */
         unsigned long *value_length,    /* i; длина данных */
         long *return_code         /* o; код возврата */
         )

Обратите внимание, что для записи символа процента (%) в протокол событий сервера escape-символы не нужны.

HTTPD_log_trace()
Записывает строку в протокол трассировки сервера.

void  HTTPD_LINKAGE  HTTPD_log_trace (
    unsigned char *handle,             /* i; описатель */
         unsigned char *value,           /* i; записываемые данные */
         unsigned long *value_length,    /* i; длина данных */
         long *return_code         /* o; код возврата */
         )

Обратите внимание, что для записи символа процента (%) в протокол трассировки сервера escape-символы не нужны.

HTTPD_open()
(Допускается только на этапе Transmogrifier.) Передает управление следующей процедуре в стеке. Эту функцию следует вызывать на этапе Transmogrifier из функций open, write и close после установки всех необходимых заголовков и сообщения о готовности к записи.

void  HTTPD_LINKAGE  HTTPD_open (
    unsigned char *handle,             /* i; описатель */
         long *return_code         /* o; код возврата */
         )	
HTTPD_proxy()
Создает запрос proxy. Допускается на этапах PreExit, Service и PostAuthorization.
Прим.:
Это функция завершения. После ее вызова запрос считается выполненным.

void  HTTPD_LINKAGE  HTTPD_proxy (
    unsigned char *handle,             /* i; описатель */
         unsigned char *url_name,      /* i; URL для запроса
                                             proxy */
         unsigned long *name_length,   /* i; длина URL */
         void *request_body,           /* i; текст запроса */
         unsigned long *body_length,   /* i; длина текста */
         long *return_code         /* o; код возврата */
         ) 
HTTPD_read()
Считывает текст запроса клиента. Для заголовков применяется функция HTTPD_extract(). Допускается только на этапах PreExit, Authorization, PostAuthorization и Service и имеет смысл лишь в том случае, если выполнялся запрос PUT или POST. Вызывайте эту функцию в цикле до получения HTTPD_EOF. Если в запросе отсутствует текст, то функция возвращает ошибку.

void  HTTPD_LINKAGE  HTTPD_read (
    unsigned char *handle,             /* i; описатель */
         unsigned char *value,           /* i; буфер данных */
         unsigned long *value_length,    /* i/o; размер буфера
                                                 (длина данных) */
         long *return_code         /* o; код возврата */
         )
HTTPD_restart()
Перезапускает сервер после обработки всех активных запросов. Допускается на всех этапах, кроме Server Initialization, Server Termination и Transmogrifier.

void  HTTPD_LINKAGE  HTTPD_restart ( 
         long *return_code         /* o; код возврата */
         )
HTTPD_set()
Устанавливает значение переменной, связанной с запросом. Переменные, допустимые в параметре name, совпадают с используемыми в CGI. Дополнительная информация приведена в разделе Переменные.

Обратите внимание, что с помощью этой функции можно также создавать переменные. Создаваемые переменные должны отвечать требованиям соглашений для префиксов HTTP_ и PROXY_, описанным в разделе Переменные. При создании переменной с префиксом HTTP_ эта переменная отправляется клиенту вместе с ответом без префикса HTTP_. Например, для задания заголовка Location можно воспользоваться функцией HTTPD_set() с переменной HTTP_LOCATION. Переменные, создаваемые с префиксом PROXY_, отправляются как заголовки запроса серверу информационного наполнения. Переменные, созданные с префиксом CGI_, передаются программам CGI.

Обратите внимание, что данная функция допустима на всех этапах, однако некоторые переменные допустимы не на всех этапах.

void  HTTPD_LINKAGE  HTTPD_set (
    unsigned char *handle,             /* i; описатель */
         unsigned char *name,          /* i; имя устанавливаемой переменной */
         unsigned long *name_length,   /* i; длина имени */
         unsigned char *value,         /* i; буфер со значением */
         unsigned long *value_length,  /* i; длина значения */
         long *return_code         /* o; код возврата */
         ) 
Прим.:
С помощью функции httpd_setvar() можно задавать значения переменных, не указывая буфер и длину. Дополнительная информация приведена в разделе ***.
httpd_setvar()
Аналогична HTTPD_set(), однако использовать эту функцию проще, поскольку она не требует указывать длину аргументов.

long             /* o; код возврата */
HTTPD_LINKAGE   httpd_setvar (
    unsigned char *handle,             /* i; описатель */
       unsigned char *name,         /* i; имя переменной */
       unsigned char *value,        /* i; новое значение */
       unsigned long *addHdr        /* i; добавление или замена заголовка */
       )

параметр addHdr может иметь одно из следующих четырех значений:

Эти переменные определены в файле HTAPI.h.

httpd_variant_insert()
Вставляет вариант в кэш.

void  HTTPD_LINKAGE  httpd_variant_insert (
    unsigned char *handle,             /* i; описатель */
         unsigned char *URI,       /* i; URI объекта */
    unsigned char *dimension,          /* i; размеренность варианта */
    unsigned char *variant,            /* i; значение варианта */
         unsigned char *filename,  /* i; файл объекта */
         long *return_code         /* o; код возврата */
         )

Примечания:

  1. Аргумент dimension относится к заголовку, с помощью которого объект получается из URI. Например, в приведенном выше примере возможным значением dimension может быть User-Agent.
  2. Аргумент variant относится к значению заголовка, заданного в аргументе dimension. Это значение берется из URI. Например, в приведенном примере возможно следующее значение аргумента variant:
    Mozilla 4.0 (compatible; BatBrowser 94.1.2; Bat OS)
  3. Аргумент filename должен указывать на завершающуюся символом null строку с именем файла, в котором пользователь сохранил измененную информацию. Ответственность за удаление файла лежит на пользователе; это можно сделать после выхода из данной функции. Файл содержит только текст, без заголовков.
  4. При кэшировании вариантов сервер обновляет заголовок content-length и добавляет заголовок с предупреждением 214. Теги strong entity удаляются.
httpd_variant_lookup()
Определяет, существуют ли в кэше заданный вариант.

void  HTTPD_LINKAGE  httpd_variant_lookup (
    unsigned char *handle,             /* i; описатель */
    unsigned char *URI,                /* URI объекта */
    unsigned char *dimension,          /* i; размеренность варианта */
    unsigned char *variant,            /* i; значение варианта */
             long *return_code);       /* o; код возврата */      
HTTPD_write()
Записывает текст ответа. Допускается на этапах PreExit, Service, Error и Transmogrifier.

Если вы не задали тип информации перед первым вызовом этой функции, то сервер предполагает, что передается поток данных CGI.

void  HTTPD_LINKAGE  HTTPD_write (
    unsigned char *handle,             /* i; описатель */
    unsigned char *value,              /* i; отправляемые данные */
    unsigned char *value_length,       /* i; длина данных */
             long *return_code);       /* o; код возврата */
Прим.:
Для настройки заголовков ответа применяется функция ***.
Прим.:
После выхода из функции HTTPD_* вы можете освободить всю переданную ей память.

Коды возврата заранее определенных функций и макросов

В зависимости от того, насколько успешно выполнен запрос, сервер присвоит параметру кода возврата одно из следующих значений:

Табл. 3. Коды возврата
Значение Код состояния Описание
-1 HTTPD_UNSUPPORTED Функция не поддерживается.
0 HTTPD_SUCCESS Функция выполнена успешно, все поля вывода допустимы.
1 HTTPD_FAILURE При выполнении функции возникла ошибка.
2 HTTPD_INTERNAL_ERROR Произошла внутренняя ошибка; продолжать обработку запроса невозможно.
3 HTTPD_PARAMETER_ERROR Функции передан один или несколько недопустимых параметров.
4 HTTPD_STATE_CHECK Функция недопустима на данном этапе обработки.
5 HTTPD_READ_ONLY (Возвращается только функциями HTTPD_set и httpd_setvar.) Переменная предназначена только для чтения и ее значение нельзя задавать из модуля.
6 HTTPD_BUFFER_TOO_SMALL (Возвращается функциями HTTPD_set, httpd_setvar и HTTPD_read.) Размер предоставленного буфера слишком мал.
7 HTTPD_AUTHENTICATE_FAILED (Возвращается только функцией HTTPD_authenticate.) Ошибка идентификации. Дополнительная информация приведена в переменных HTTP_RESPONSE и HTTP_REASON.
8 HTTPD_EOF (Возвращается только функцией HTTPD_read.) Указывает на завершение текста запроса.
9 HTTPD_ABORT_REQUEST Запрос отменен, поскольку клиент предоставил тег объекта, не соответствующий указанным в запросе условиям.
10 HTTPD_REQUEST_SERVICED (Возвращается функцией HTTPD_proxy.) Вызванная функция завершила создание ответа на запрос.
11 HTTPD_RESPONSE_ALREADY_COMPLETED Функция не выполнена, поскольку ответ на этот запрос уже создан.
12 HTTPD_WRITE_ONLY Переменная предназначена только для записи и ее значение нельзя считывать из модуля.

Директивы конфигурации Caching Proxy для этапов обработки API

Для каждого этапа обработки запроса существует директива конфигурации, с помощью которой вы можете указать, какая функция модуля должна вызываться и выполняться на этом этапе. Вы можете добавить эти директивы в файл конфигурации сервера (ibmproxy.conf) вручную или с помощью формы API обработки запросов в интерфейсе администрирования и настройки Caching Proxy.

Примечания по использованию API

Синтаксис и директивы API

Следующие директивы файла конфигурации должны быть указаны в файле ibmproxy.conf на одной строке без лишних пробелов. Должны присутствовать лишь те пробелы, которые явно указаны в данной таблице. Несмотря на то, что в некоторых примерах для упрощения чтения директивы перенесены на новую строку, на самом деле в соответствующих позициях директив не должно быть пробелов.

Табл. 4. Директивы API модуля Caching Proxy
ServerInit /путь/файл:функция init_string
PreExit /путь/файл:функция
Authentication type /путь/файл:функция
NameTrans /URL /путь/файл:функция
Authorization /URL /путь/файл:функция
ObjectType /URL /путь/файл:функция
PostAuth /путь/файл:функция
Service /URL /путь/файл:функция
Полночь /путь/файл:функция
Transmogrifier /путь/файл:функция_открытия: функция_записи: функция_закрытия:функция_ошибки
Log /URL /путь/файл:функция
Error /URL /путь/файл:функция
PostExit /путь/файл:функция
ServerTerm /путь/файл:функция
ProxyAdvisor /путь/файл:функция
GCAdvisor /путь/файл:функция

Переменные директив API

Переменные в этих директивах имеют следующее значение:

тип
Применяется только в директиве Authentication, чтобы указать, нужно или нет вызывать вашу функцию модуля. Допустимые значения:
URL
Указывает запросы, для которых вызывается функция модуля. Для запросов, URL которых соответствуют указанному шаблону, будет применяться данная функция. В директивах применяются виртуальные спецификации URL (без указания протокола), однако в них присутствует ведущий символ косой черты (/). Например, значение /www.ics.raleigh.ibm.com допустимо, а значение http://www.ics.raleigh.ibm.com - нет. Можно указывать как отдельные URL, так и шаблоны.
путь/файл
Полное имя файла откомпилированной программы.
функция
Имя, присвоенное функции модуля в программе.

Если необходимо обеспечить доступ к информации о пути, то в директиве Service после имени функции должна быть указана звездочка (*).

строка-инициализации
Это необязательная часть директивы ServerInit, которая может содержать любой текст, передаваемый функции модуля. Для получения текста из переменной INIT_STRING применяется функция httpd_getvar().

Дополнительная информация о директивах, включая описание синтаксиса, приведена в руководстве WebSphere Application Server Caching Proxy Administration Guide.

Совместимость с другими API

API Caching Proxy обеспечивают обратную совместимость с ICAPI и GWAPI вплоть до версии 4.6.1.

Портирование программ CGI

При портировании написанных на C приложений CGI в API Caching Proxy следует руководствоваться следующими правилами:

Справочная информация об API Caching Proxy

Переменные

При написании программ для API можно использовать переменные компонента Caching Proxy, предоставляющие информацию об удаленной системе клиента и сервера.

Примечания:

Определения переменных

Прим.:
Переменные заголовков без приставок HTTP_ или PROXY_ являются неоднозначными. Во избежание неоднозначности рекомендуется всегда использовать приставку HTTP_ или PROXY_ в названиях переменных для заголовков.
ACCEPT_RANGES
Содержит значение заголовка ответа Accept-Ranges, которое указывает, может ли сервер содержимого отвечать на различные запросы. Для извлечения значения заголовка, который сервер содержимого отправляет серверу Proxy, используется переменная PROXY_ACCEPT_RANGES. Для установки значения заголовка, отправляемого сервером Proxy клиенту, используется переменная HTTP_ACCEPT_RANGES.
Прим.:
Переменная ACCEPT_RANGES является неоднозначной. Во избежание неоднозначности следует использовать названия переменных HTTP_ACCEPT_RANGES и PROXY_ACCEPT_RANGES.
ALL_VARIABLES
Только для чтения. Содержит все переменные CGI. Например:
     ACCEPT_RANGES BYTES
     CLIENT_ADDR 9.67.84.3
AUTH_STRING
Только для чтения. Если сервер поддерживает идентификацию клиента, эта строка содержит расшифрованные идентификационные данные, применяемые для идентификации клиента.
AUTH_TYPE
Только для чтения. Если сервер поддерживает идентификацию клиента и сценарий является защищенным, то эта переменная содержит метод, применяемый для идентификации клиента. Например, Basic.
CACHE_HIT
Только для чтения. Определяет, найден ли в кэше запрос сервера Proxy. Возвращаемые значения:
CACHE_MISS
Только для записи. Применяется для принудительной отправки промаха в кэш. Допустимые значения:
CACHE_TASK
Только для чтения. Определяет, используется ли кэш. Возвращаемые значения:

Эта переменная может применяться на шагах PostAuthorization, PostExit, ProxyAdvisor или Log.

CACHE_UPDATE
Только для чтения. Определяет, обновил ли запрос сервера Proxy данные в кэше. Возвращаемые значения:
CLIENT_ADDR или CLIENTADDR
То же, что и REMOTE_ADDR.
CLIENTMETHOD
То же, что и REQUEST_METHOD.
CLIENT_NAME или CLIENTNAME
То же, что и REMOTE_HOST.
CLIENT_PROTOCOL или CLIENTPROTOCOL
Содержит название и версию протокола, применяемого клиентом для отправки запроса. Например, HTTP/1.1.
CLIENT_RESPONSE_HEADERS
Только для чтения. Возвращает буфер, содержащий заголовки, которые сервер отправляет клиенту.
CONNECTIONS
Только для чтения. Содержит число установленных соединений или число активных запросов. Например, 15.
CONTENT_CHARSET
Набор символов ответа для text/*, например, US ASCII. Извлечение этой переменной относится к заголовку content-charset из запроса клиента. Установка этой переменной влияет на значение заголовка content-charset в запросе для сервера содержимого.
CONTENT_ENCODING
Указывает кодировку документа, например, x-gzip. Извлечение этой переменной относится к заголовку content-encoding из запроса клиента. Установка этой переменной влияет на значение заголовка content-charset в запросе для сервера содержимого.
CONTENT_LENGTH
Извлечение этой переменной относится к заголовку из запроса клиента. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого.

Прим.:
Переменная CONTENT_LENGTH является неоднозначной. Во избежание неоднозначности следует использовать названия переменных HTTP_CONTENT_LENGTH и PROXY_CONTENT_LENGTH.
CONTENT_TYPE
Извлечение этой переменной относится к заголовку из запроса клиента. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого.

Прим.:
Переменная CONTENT_TYPE является неоднозначной. Во избежание неоднозначности следует использовать названия переменных HTTP_CONTENT_TYPE и PROXY_CONTENT_TYPE.
CONTENT_TYPE_PARAMETERS
Содержит остальные атрибуты MIME, за исключением набора символов. Извлечение этой переменной относится к заголовку из запроса клиента. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого.
DOCUMENT_URL
Содержит URL-адрес документа. Например:
http://www.anynet.com/~userk/main.htm
DOCUMENT_URI
То же, что и DOCUMENT_URL.
DOCUMENT_ROOT
Только для чтения. Содержит путь к корневому каталогу документа в соответствии с правилами передачи.
ERRORINFO
Указывает код ошибки для определения страницы, содержащей ошибку. Например, blocked.
EXPIRES
Определяет срок действия документов, хранящихся в кэше сервера Proxy. Извлечение этой переменной относится к заголовку из запроса клиента. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого. Например:
Mon, 01 Mar 2002 19:41:17 GMT
GATEWAY_INTERFACE
Read-only. Contains the version of the API that the server is using. For example, ICSAPI/2.0.
GC_BIAS
Write-only. This floating-point value influences the garbage collection decision for the file being considered for garbage collection. The value entered is multiplied by the Caching Proxy's quality setting for that file type to determine ranking. Quality settings range from 0.0 to 0.1 and are defined by the AddType directives in the proxy configuration file (ibmproxy.conf).
GC_EVALUATION
Write-only. This floating-point value determines whether to remove (0.0) or keep (1.0) the file being considered for garbage collection. Значения в диапазоне от 0,0 до 1,0 упорядочиваются по рангу, т.е. файл со значением GC_EVALUATION равным 0,1 имеет большую вероятность, что он будет удален, чем файл со значением GC_EVALUATION равным 0,9.
GC_EXPIRES
Только для чтения. Определяет, сколько секунд осталось до истечения срока действия файла в кэше. Для извлечения этой переменной используется модуль GC Advisor.
GC_FILENAME
Только для чтения. Обозначает файл, предназначенный для сбора мусора. Для извлечения этой переменной используется модуль GC Advisor.
GC_FILESIZE
Только для чтения. Обозначает размер файла, предназначенного для сбора мусора. Для извлечения этой переменной используется модуль GC Advisor.
GC_LAST_ACCESS
Только для чтения. Обозначает время последнего обращения к файлу. Для извлечения этой переменной используется модуль GC Advisor.
GC_LAST_CHECKED
Только для чтения. Обозначает время последней проверки файлов. Для извлечения этой переменной используется модуль GC Advisor.
GC_LOAD_DELAY
Только для чтения. Обозначает продолжительность процедуры извлечения файла. Для извлечения этой переменной используется модуль GC Advisor.
HTTP_COOKIE
Эта переменная содержит значение заголовка Set-Cookie, установленное клиентом. Также применяется для создания новой записи cookie в потоке ответа (между Proxy и клиентом). Установка этой переменной создает новый заголовок Set-Cookie в потоке запроса документа, независимо от наличия дубликата заголовка.
HTTP_HEADERS
Только для чтения. Применяется для извлечения всех заголовков запросов клиентов.
HTTP_REASON
Установка этой переменной влияет на значение строки reason в ответе HTTP. Установка этой переменной также влияет на значение строки reason в ответе, который сервер Proxy отправляет клиенту. Извлечение этой переменной возвращает строку reason в ответе, который сервер содержимого отправляет серверу Proxy.
HTTP_RESPONSE
Установка этой переменной влияет на значение кода в ответе HTTP. Установка этой переменной также влияет на код состояния в ответе, который сервер Proxy отправляет клиенту. Извлечение этой переменной возвращает код состояния в ответе, который сервер содержимого отправляет серверу Proxy.
HTTP_STATUS
Содержит код ответа HTTP и строку reason. Например, 200 OK.
HTTP_USER_AGENT
Содержит значение заголовка запроса User-Agent, который представляет собой имя Web-обозревателя клиента, например, Netscape Navigator / V2.02. Установка этой переменной влияет на значение заголовка в ответе, который сервер Proxy отправляет клиенту. Извлечение этой переменной относится к заголовку из запроса клиента.
INIT_STRING
Только для чтения. Значение этой строки определяется директивой ServerInit. Эта переменная доступна для чтения только во время инициализации сервера.
LAST_MODIFIED
Извлечение этой переменной относится к заголовку из запроса клиента. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого. Например:
Mon, 01 Mar 1998 19:41:17 GMT
LOCAL_VARIABLES
Только для чтения. Все пользовательские переменные.
MAXACTIVETHREADS
Только для чтения. Максимальное число активных нитей.
NOTMODIFIED_TO_OK
Принудительная отправка полного ответа клиенту. Действительно на шагах PreExit и ProxyAdvisor.
ORIGINAL_HOST
Только для чтения. Возвращает имя хоста или IP-адрес, указанный в запросе.
ORIGINAL_URL
Только для чтения. Возвращает исходный URL, отправленный в запросе клиента.
OVERRIDE_HTTP_NOTRANSFORM
Разрешает изменение данных, если указан заголовок Cache-Control: no-transform. Установка этой переменной влияет на значение заголовка ответа клиенту.
OVERRIDE_PROXY_NOTRANSFORM
Разрешает изменение данных, если указан заголовок Cache-Control: no-transform. Установка этой переменной влияет на значение запроса для сервера содержимого.
PASSWORD
Для базовой идентификации содержит расшифрованный пароль. Например, password.
PATH
Содержит полностью преобразованный путь.
PATH_INFO
Содержит дополнительную информацию о пути, отправленную Web-обозревателем. Например, /foo.
PATH_TRANSLATED
Содержит расшифрованную или преобразованную версию пути, который указан в переменной PATH_INFO. Например:
d:\wwwhome\foo
/wwwhome/foo
PPATH
Содержит частично преобразованный путь. Используется на этапе преобразования имен.
PROXIED_CONTENT_LENGTH
Только для чтения. Возвращает длину данных ответа, переданного через сервер Proxy.
PROXY_ACCESS
Определяет, является ли данный запрос proxy-запросом. Например, NO.
PROXY_CONTENT_TYPE
Содержит заголовок Content-Type запроса сервера Proxy, отправленного с помощью функции HTTPD_proxy(). Если информация отправляется с использованием метода POST, эта переменная содержит тип данных. В файле конфигурации сервера Proxy можно создать собственный тип содержимого и отобразить его для программы просмотра. Извлечение этой переменной относится к значению заголовка из ответа сервера содержимого. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого. Например:
application/x-www-form-urlencoded
PROXY_CONTENT_LENGTH
Заголовок Content-Length запроса сервера Proxy, отправленного с помощью функции HTTPD_proxy(). Если информация отправляется с использованием метода POST, эта переменная содержит число символов данных. Обычно серверы не отправляют флаг конца файла при передаче информации, используя стандартный ввод. При необходимо значение CONTENT_LENGTH может применяться для определения конца входной строки. Извлечение этой переменной относится к значению заголовка из ответа сервера содержимого. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого. Например:
7034
PROXY_COOKIE
Эта переменная содержит значение заголовка Set-Cookie, установленное исходным сервером. Также применяется для создания новой записи cookie в потоке запроса. Установка этой переменной создает новый заголовок Set-Cookie в потоке запроса документа, независимо от наличия дубликата заголовка.
PROXY_HEADERS
Только для чтения. Применяется для извлечения заголовков Proxy.
PROXY_METHOD
Метод для запроса, отправленного при помощи функции HTTPD_proxy(). Извлечение этой переменной относится к значению заголовка из ответа сервера содержимого. Установка этой переменной влияет на значение заголовка в запросе для сервера содержимого.
QUERY_STRING
Если информация отправляется с использованием метода GET, эта переменная содержит информацию после вопросительного знака (?) в запросе. Эта информация должна быть декодирована программой CGI. Например:
NAME=Eugene+T%2E+Fox&ADDR=etfox%7Cibm.net&INTEREST=xyz
RCA_OWNER
Только для чтения. Возвращает числовое значение узла, который владеет запрашиваемым объектом. Эта переменная может применяться на шагах PostExit, ProxyAdvisor или Log. Ее значение является значащим, только если сервер является частью кэш-массива, использующего метод удаленного доступа к кэшу (RCA).
RCA_TIMEOUTS
Только для чтения. Возвращает числовое значение, содержащее общее число тайм-аутов в запросах RCA. Эта переменная может применяться на любом шаге.
REDIRECT_*
Только для чтения. Содержит строку redirection для кода ошибки, соответствующего имени переменной (например, REDIRECT_URL). Список допустимых переменных REDIRECT_ приведен в документации по веб-серверу Apache по адресу http://httpd.apache.org/docs-2.0/custom-error.html.
REFERRER_URL
Только для чтения. Содержит последний URL-адрес обозревателя. Позволяет клиенту указать URL-адрес ресурса, из которого было получено значение Request-URL. Например:
http://www.company.com/homepage
REMOTE_ADDR
Содержит IP-адрес Web-обозревателя. Например, 45.23.06.8.
REMOTE_HOST
Содержит имя хоста Web-обозревателя. Например, www.raleigh.ibm.com.
REMOTE_USER
Если сервер поддерживает идентификацию клиента и сценарий является защищенным, то эта переменная содержит имя пользователя, указанное для идентификации. Например, joeuser.
REQHDR
Только для чтения. Содержит список заголовков, отправленных клиентом.
REQUEST_CONTENT_TYPE
Только для чтения. Возвращает тип содержимого тела запроса. Например:
application/x-www-form-urlencoded
REQUEST_CONTENT_LENGTH
Только для чтения. Если информация отправляется с использованием метода POST, эта переменная содержит число символов данных. Обычно серверы не отправляют флаг конца файла при передаче информации, используя стандартный ввод. При необходимо значение CONTENT_LENGTH может применяться для определения конца входной строки. Например, 7034.
REQUEST_METHOD
Только для чтения. Содержит метод (соответствующий значению атрибута METHOD в формате HTML), применяемый для отправки запроса. Например, GET или POST.
REQUEST_PORT
Только для чтения. Возвращает номер порта, указанный в URL-адресе или порт, принятый по умолчанию для данного протокола.
RESPONSE_CONTENT_TYPE
Только для чтения. Если информация отправляется с использованием метода POST, эта переменная содержит тип данных. В файле конфигурации сервера Proxy можно создать собственный тип содержимого и отобразить его для программы просмотра. Например, text/html.
RESPONSE_CONTENT_LENGTH
Только для чтения. Если информация отправляется с использованием метода POST, эта переменная содержит число символов данных. Обычно серверы не отправляют флаг конца файла при передаче информации, используя стандартный ввод. При необходимо значение CONTENT_LENGTH может применяться для определения конца входной строки. Например, 7034.
RULE_FILE_PATH
Только для чтения. Содержит полный путь и имя файла конфигурации.
SSL_SESSIONID
Только для чтения. Возвращает ИД сеанса SSL, если текущий запрос получен по SSL-соединению. В противном случае возвращает значение NULL.
SCRIPT_NAME
Содержит URL-адрес запроса.
SERVER_ADDR
Только для чтения. Содержит локальный IP-адрес сервера Proxy.
SERVER_NAME
Только для чтения. Содержит имя хоста сервера Proxy или IP-адрес сервера содержимого для данного запроса. Например, www.ibm.com.
SERVER_PORT
Только для чтения. Содержит номер порта сервера Proxy, на который отправлен запрос клиента. Например, 80.
SERVER_PROTOCOL
Только для чтения. Содержит название и версию протокола, применяемого для отправки запроса. Например, HTTP/1.1.
SERVER_ROOT
Только для чтения. Содержит каталог, в котором установлен сервер Proxy.
SERVER_SOFTWARE
Только для чтения. Содержит имя и версию сервера Proxy.
STATUS
Содержит код ответа HTTP и строку reason. Например, 200 OK.
TRACE
Определяет объем информации трассировки. Допустимые значения:
URI
Чтение/запись. То же, что и DOCUMENT_URL.
URI_PATH
Только для чтения. Возвращает часть пути только для URL-адреса.
URL
Чтение/запись. То же, что и DOCUMENT_URL.
URL_MD4
Только для чтения. Возвращает имя возможного файла кэша для текущего запроса.
USE_PROXY
Обозначает имя сервера Proxy в цепочке для текущего запроса. Содержит URL-адрес. Например, http://myproxy:8080.
USERID
То же, что и REMOTE_USER.
USERNAME
То же, что и REMOTE_USER.

Идентификация и проверка прав доступа

Вначале определимся с применяемой терминологией:

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

Рис. 3 содержит описание процессов идентификации и проверки прав доступа сервером proxy.

Рис. 3. Процессы идентификации и проверки прав доступа сервером Proxy
Схема процессов идентификации и проверки прав доступа

Как показано на Рис. 3, процессы идентификации и проверки прав доступа начинаются с инициализации процесса проверки прав доступа.

В Caching Proxy идентификация является частью процесса проверки прав доступа и выполняется только в том случае, когда необходимо проверить наличие прав доступа.

Процесс идентификации и проверки прав доступа

При обработке запроса, требующего проверки прав доступа, сервер proxy выполняет следующие действия.

  1. Сначала сервер proxy проверяет наличие директив проверки прав доступа в своем файле конфигурации.
  2. Сервер proxy начинает процесс идентификации путем проверки заголовка HTTP_authenticate в запросе клиента.
  3. Сервер proxy проверяет наличие директивы идентификации в файле конфигурации proxy.

Если в вашем модуле Caching Proxy предусмотрен собственный процесс проверки прав доступа, то он переопределяет применяемые сервером по умолчанию процессы идентификации и проверки прав доступа. Таким образом, если в файле конфигурации присутствуют директивы проверки прав доступа, то связанные с этими директивами функции модуля должны также обрабатывать все необходимые процедуры идентификации. Вы можете использовать заранее определенную функцию HTTPD_authenticate().

Существует три способа обеспечения идентификации в модуле проверки прав доступа:

Если в модуле Caching Proxy не предусмотрен собственный процесс проверки прав доступа, то с помощью следующих методов вы все равно можете включить собственный процесс идентификации:

При выполнении этапа проверки прав доступа (Authorization) вызывается функция проверки прав доступа по умолчанию, которая в свою очередь вызывает вашу функцию модуля идентификации.

Обратите внимание на следующие особенности:

Кэширование вариантов

Кэширование вариантов применяется для кэширования данных, представляющих собой видоизмененный вариант исходного документа (URI). Caching Proxy обрабатывает варианты, сформированные API. Варианты - это различные версии базового документа.

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

Например, можно использовать программу API Transmogrifier для изменения запрошенных пользователями данных на основании отправленного браузером заголовка User-Agent. В функции close сохраните измененную информацию в файле или укажите длину буфера и передайте этот буфер как аргумент данных. После этого можно воспользоваться функциями кэширования вариантов httpd_variant_insert() и httpd_variant_lookup() для размещения варианта в кэше.

Примеры API

Вам будет проще начать разработку собственных функций API Caching Proxy, если вы ознакомитесь с примерами программ, находящимися в каталоге samples установочного компакт-диска Edge Components. Дополнительная информация приведена на Web-сайте WebSphere Application Server www.ibm.com/software/webservers/appserv/.

Пользовательские советники

В этом разделе описывается создание пользовательских советников для компонента Load Balancer.

Советники предоставляют информацию о распределении нагрузки

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

Написание пользовательских советников для Load Balancer позволяет настроить параметры определения нагрузки серверов.

В операционных системах семейства Windows: Если используется протокол IPv6, то при установке Load Balancer для IPv4 и IPv6 необходимо изменить файл protocol, расположенный в каталоге C:\windows\system32\drivers\etc\.

Для использования протокола IPv6 необходимо вставить в файл следующую строку:

ipv6-icmp	 58	  IPv6-ICMP	     # IPv6 interface control message protocol

Стандартный советник

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

  1. Советник периодически устанавливает соединение с каждым сервером и отправляет ему сообщение-запрос. Содержимое сообщения зависит от протокола, запущенного на сервере; например, советник HTTP отправляет серверу запрос HEAD.
  2. Советник ожидает ответ от сервера. После получения ответа советник вычисляет значение нагрузки для данного сервера и сообщает его пользователю. Для разных советников методы вычисления значения нагрузки могут быть различны; большинство советников измеряют время ожидания ответа от сервера (в миллисекундах).
  3. Советник передает это значение диспетчеру Load Balancer. Кроме того, оно отображается в столбце Порт отчета диспетчера. На основе полученного значения, а также других показателей, установленных администратором, диспетчер принимает решение о распределении нагрузки между поступающими на сервер запросами.
  4. Если сервер не отвечает на запрос, советник возвращает отрицательное значение (-1). На основе этой информации диспетчер принимает решение о приостановке службы для определенного сервера.

Стандартные советники, поставляемые вместе с компонентом Load Balancer, выполняют следующие функции. Подробная информация о советниках приведена в документе WebSphere Application Server Load Balancer Administration Guide

Для специальных протоколов, которые не поддерживаются стандартными советниками, необходимо создавать пользовательские советники.

Создание пользовательского советника

Пользовательский советник представляет собой небольшой код на языке Java, сохраненный в виде файле класса, который вызывается основным кодом компонента Load Balancer для определения загрузки сервера. Основной код предоставляет все необходимые административные службы, включая запуск и остановку экземпляра пользовательского советника, информацию о статусе советника, отчеты, ведение журнала событий, а также передачу результатов работы советника компоненту диспетчера.

Процедура вызова пользовательского советника включает следующие этапы.

  1. Основной код Load Balancer устанавливает соединение с сервером.
  2. Если сокет открыт, основной код вызывает функцию GetLoad соответствующего советника.
  3. Функция GetLoad советника выполняет определенные пользователем действия для анализа состояния сервера, в том числе ожидает ответ от сервера. После получения ответа выполнение функции прекращается.
  4. Основной код Load Balancer закрывает сокет и передает информацию о нагрузке диспетчеру. В зависимости от режима работы пользовательского советника (обычный режим или режим замены), основной код может выполнить некоторые дополнительные вычисления после завершения работы функции GetLoad.

Обычный режим и режим замены

Пользовательские советники могут взаимодействовать с Load Balancer либо в обычном режиме работы, либо в режиме замены.

Режим работы задается при помощи специального параметра метода конструктора в файле пользовательского советника. (Каждый советник может работать только в одном режиме, в зависимости от своего назначения).

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

Для выбора обычного режима работы присвойте флагу замены в конструкторе значение false.

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

Для выбора режима замены присвойте флагу замены в конструкторе значение true.

Соглашения об именах советников

Имя файла пользовательского советника должно быть указано в виде ADV_имя.java, где имя - это имя, выбранное для советника. Приставка ADV_ в начале полного имени файла должна содержать символы верхнего регистра, а все остальные символы должны быть указаны в нижнем регистре. Последнее требование позволяет вводить имя файла советника в команде запуска без учета регистра.

В соответствии с соглашениями об именах Java, имя класса, определенного в файле, должно совпадать с именем файла.

Компиляция

Пользовательские советники создаются на языке Java и компилируются при помощи компилятора Java, установленного в системе пользователя. В процедуре компиляции используются следующие файлы:

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

javac -classpath /opt/ibm/edge/lb/servers/lib/ibmnd.jar ADV_имя.java

В этом примере используется путь установки, принятый по умолчанию в операционных системах Linux и UNIX. Файлу советника присвоено имя ADV_имя.java, и он хранится в текущем каталоге.

В результате компиляции создается файл класса, ADV_имя.class. Перед запуском советника необходимо скопировать этот файл в каталог установочный_каталог/servers/lib/CustomAdvisors/.

Прим.:
Пользовательские советники можно компилировать в одной операционной системе, а выполнять в другой. Например, вы можете скомпилировать советник в операционной системе Windows, скопировать файл класса (в двоичном формате) в операционную систему Linux и запустить в ней пользовательский советник.

Выполнение пользовательского советника

Для запуска пользовательского советника необходимо сначала скопировать файл класса советника в каталог lib/CustomAdvisors/ в системе, где установлен Load Balancer. Например, пользовательский советник с именем myping (ADV_myping.class) находится в каталоге установочный_каталог/servers/lib/CustomAdvisors/

Настройте Load Balancer, запустите диспетчер и выполните команду для запуска пользовательского советника. Для запуска пользовательского советника необходимо указать его имя без приставки ADV_ и расширения файла:

dscontrol advisor start myping номер_порта

Указанный в команде номер порта - это порт, к которому подключается советник при установлении соединения с целевым сервером.

Обязательные процедуры

Как и все стандартные советники, пользовательский советник расширяет функциональные возможности базового класса советника, ADV_Base. Базовый класс выполняет большинство функций советника, например, передает значения нагрузки диспетчеру для дальнейшей обработки. Кроме того, он создает сокеты и закрывает операции, а также содержит методы отправки и приема, необходимые для работы советника. Советник применяется исключительно для обмена данными с исследуемым сервером через указанный порт. Методы базового класса советника, основанные на протоколе TCP, используются для вычисления нагрузки. При необходимости для замены текущего значения нагрузки на новое значение, возвращаемое советником, можно использовать специальный флаг в конструкторе базового класса советника.

Прим.:
Базовый класс советника отправляет значения нагрузки через указанные промежутки времени, в зависимости от значения, заданного в конструкторе. Если посредник не успел завершить обработку и не может вернуть текущее значение нагрузки, то базовый класс использует предыдущее значение.

Советники содержат следующие методы базового класса:

Более подробную информацию об этих процедурах можно найти ниже.

Порядок поиска

Пользовательские советники вызываются, если поиск среди стандартных советников не дал результата. Если компоненту Load Balancer не удалось найти требуемый советник в списке стандартных советников, он просматривает список пользовательских советников. Дополнительная информация об использовании советников приведена в документе WebSphere Application Server Load Balancer Administration Guide.

Присваивание имен файлам и использование пути к файлу

При работе с пользовательскими советниками необходимо выполнять следующие требования к именам файлов и путям.

Методы пользовательского советника и вызов функций

Конструктор (предоставляемый базовым классом советника)

void ADV_Base Constructor (
        string sName;
        string sVersion;
        int iDefaultPort;
        int iInterval;
        string sDefaultLogFileName;
        boolean replace
)
sName
Имя пользовательского советника.
sVersion
Версия пользовательского советника.
iDefaultPort
Номер порта для подключения к серверу, если в вызове функции номер порта не указан.
iInterval
Интервал между запросами на сервер.
sDefaultLogFileName
Этот параметр является обязательным, однако он не используется. Он может принимать только одно значение: "" (нулевая строка)
replace
Определяет, работает ли советник в режиме замены. Допустимые значения:

ADV_AdvisorInitialize()

void  ADV_AdvisorInitialize()

Этот метод применяется для инициализации пользовательского советника. Этот метод вызывается после запуска базового модуля советника.

Обычно (в том числе и в стандартных советниках) этот метод не используется и содержит только оператор return. Этот метод может применяться для вызова метода suppressBaseOpeningSocket, который действителен только при вызове из метода ADV_AdvisorInitialize().

getLoad()

int getLoad(
        int iConnectTime;
        ADV_Thread *caller
)
iConnectTime
Продолжительность времени (в мс), необходимая для установления соединения. Этот параметр измеряется основным кодом советника и передается коду пользовательского советника, который может принять или проигнорировать его при возвращении значения нагрузки. Если соединение не установлено, возвращается значение -1.
caller
Экземпляр базового класса советника, содержащего основные методы советника.

Вызов функций из пользовательских советников

В следующих разделах описываются методы (или функции), вызываемые из пользовательских советников. Эти методы поддерживаются основным кодом советника.

Некоторые из этих функций могут быть вызваны напрямую, например, имя_функции(), а для других необходимо указывать приставку caller. Приставка Caller обозначает экземпляр базового советника, который поддерживает запущенный пользовательский советник.

ADVLOG()

Функция ADVLOG применяется для записи текстового сообщения в файл журнала советника. Формат:

void  ADVLOG  (int logLevel, string message)
logLevel
Значение статуса сообщения, записываемого в файл журнала. Файл протокола советника состоит из нескольких частей; самые срочные сообщения имеют статус 0, менее срочные сообщения имеют более высокие значения статуса. Наиболее подробные сообщения имеют статус 5. Статусы применяются для управления типами сообщений, которые пользователь получает в режиме реального времени (Для установки уровня детальности сообщений используется команда dscontrol). Неисправимые ошибки всегда должны иметь уровень 0.
message
Сообщение, записываемое в файл журнала. Значение данного параметра представляет собой обычную Java-строку.

getAdvisorName()

Функция getAdvisorName возвращает Java-строку с суффиксом, который указывает имя пользовательского советника. Например, для советника ADV_cdload.java эта функция возвращает значение cdload.

У этой функции нет параметров.

Обратите внимание, что это значение не изменяется в процессе создания одного экземпляра советника.

getAdviseOnPort()

Функция getAdviseOnPort возвращает номер порта, к которому подключен пользовательский советник. Возвращаемое значение представляет собой целое число Java (int). У этой функции нет параметров.

Обратите внимание, что это значение не изменяется в процессе создания одного экземпляра советника.

caller.getCurrentServer()

Функция getCurrentServer возвращает IP-адрес текущего сервера. Возвращаемое значение представляет собой строку Java в формате IP-адреса, например, 128.0.72.139

Обычно этот адрес изменяется при каждом вызове пользовательского советника, поскольку основной код советника последовательно отпрашивает все серверы.

У этой функции нет параметров.

caller.getCurrentCluster()

Функция getCurrentCluster возвращает IP-адрес кластера сервера. Возвращаемое значение представляет собой строку Java в формате IP-адреса, например, 128.0.72.139

Обычно этот адрес изменяется при каждом вызове пользовательского советника, поскольку основной код советника последовательно опрашивает все кластеры сервера.

У этой функции нет параметров.

getInterval()

Функция getInterval возвращает интервал советника, т.е. число секунд между циклами советника. Это значение равно значению по умолчанию, указанному в конструкторе пользовательского советника, если оно не было изменено во время выполнения с помощью команды dscontrol.

Возвращаемое значение представляет собой целое число Java (int). У этой функции нет параметров.

caller.getLatestLoad()

Функция getLatestLoad позволяет получить последнее значение нагрузки для заданного сервера. Значения нагрузки сохраняются во внутренних таблицах основным кодом советника и демоном диспетчера.

int caller.getLatestLoad (string cluster_IP, int port, string server_IP)

Для определения одного объекта сервера необходимо три аргумента.

cluster_IP
IP-адрес кластера объекта сервера, для которого необходимо получить текущее значение нагрузки. Этот аргумент должен представлять собой строку Java в формате IP-адреса, например, 245.145.62.81
port
Номер порта объекта сервера, для которого необходимо получить текущее значение нагрузки.
server_IP
IP-адрес объекта сервера, для которого необходимо получить текущее значение нагрузки. Этот аргумент должен представлять собой строку Java в формате IP-адреса, например, 192.255.201.3

Возвращаемое значение представляет собой целое число.

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

caller.receive()

Функция receive принимает данные от сокета.

caller.receive(stringbuffer *response)

Параметр response представляет собой буфер, в который помещаются принятые данные. Функция возвращает одно из следующих значений:

caller.send()

Функция send использует установленное соединение для отправки пакета данных на сервер через указанный порт.

caller.send(string command)

Параметр command представляет собой строку, содержащую данные для передачи серверу. Функция возвращает одно из следующих значений:

suppressBaseOpeningSocket()

Функция suppressBaseOpeningSocket позволяет основному коду советника установить TCP-соединение с сервером от имени пользовательского советника. Если советник не использует прямое соединение с сервером для определения его состояния, создавать данный сокет не требуется.

Данная функция вызывается из процедуры ADV_AdvisorInitialize, причем только один раз.

У этой функции нет параметров.

Примеры

Ниже приведены примеры использования пользовательских советников.

Стандартный советник

Следующий пример исходного кода похож на код для стандартного советника компонента Load Balancer на базе HTTP-протокола. Процедура выполнения:

  1. Отправляется запрос на передачу, команда "HEAD/HTTP".
  2. Принимается ответ. Информация не анализируется, но после получения ответа выполнение функции getLoad прекращается.
  3. Функция getLoad возвращает 0 в случае успеха или -1 в случае ошибки.

Этот советник работает в обычном режиме, поэтому значение нагрузки вычисляется на основе времени (в мс), необходимого для создания сокета и выполнения операций отправки, приема и закрытия.

package CustomAdvisors;
import com.ibm.internet.lb.advisors.*;
public class ADV_sample extends ADV_Base implements ADV_MethodInterface {
  static final String ADV_NAME ="Sample";
  static final int ADV_DEF_ADV_ON_PORT = 80;
  static final int ADV_DEF_INTERVAL = 7;
  static final string ADV_SEND_REQUEST =
    "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " +
    "IBM_Load_Balancer_HTTP_Advisor\r\n\r\n";

//--------
// Конструктор

  public ADV_sample() {
    super(ADV_NAME, "3.0.0.0-03.31.00",
          ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "",
          false);
    super.setAdvisor( this );
  }

//--------
// ADV_AdvisorInitialize

  public void ADV_AdvisorInitialize() {
    return;                                  // обычно пустая процедура
  }

//--------
// getLoad

  public int getLoad(int iConnectTime, ADV_Thread caller) {
    int iRc;
    int iLoad = ADV_HOST_INACCESSIBLE;     // инициализируется
                                           // значением inaccessible

    iRc = caller.send(ADV_SEND_REQUEST);   // отправляет HTTP-запрос
                                             // серверу
    if (0 <= iRc) {    // если операция отправки выполнена успешно
      StringBuffer sbReceiveData = new StringBuffer(""); // выделение буфера
                                                           // для ответа
      iRc = caller.receive(sbReceiveData);   // получение результата

      // анализ полученного результата

      if (0 <= iRc) {       // если операция приема выполнена успешно
        iLoad = 0;          // возвращает 0 в случае успеха
      }                     // (значение нагрузки советника игнорируется
    }                       //  в обычном режиме)
    return iLoad;
  }
}

Советник с побочным потоком

Этот пример демонстрирует закрытие стандартного сокета, созданного основным кодом советника. Вместо него советник открывает сокет с побочным потоком Java для соединения с сервером. Данная процедура применяется в том случае, если сервер использует для приема запросов советника нестандартный порт.

В данном примере сервер использует порт 11999 и при получении запроса возвращает значение нагрузки с шестнадцатеричным целым числом "4". В этом случае советник работает в режиме замены, т.е. последнему параметру конструктора советника присвоено значение true, и основной код советника использует вместо прошедшего времени возвращаемое значение нагрузки.

Обратите внимание на функцию supressBaseOpeningSocket() в процедуре инициализации. Закрывать сокет, если данные не отправляются, не требуется. Например, создание сокета может потребоваться для проверки возможности установления соединения с сервером. Перед использованием данного примера определите назначение вашего приложения.

package CustomAdvisors;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Date;
import com.ibm.internet.lb.advisors.*;
import com.ibm.internet.lb.common.*;
import com.ibm.internet.lb.server.SRV_ConfigServer;

public class ADV_sidea extends ADV_Base implements ADV_MethodInterface {
  static final String ADV_NAME = "sidea";
  static final int ADV_DEF_ADV_ON_PORT = 12345;
  static final int ADV_DEF_INTERVAL = 7;

  // создание массива байт с сообщением-запросом о нагрузке
  static final byte[] abHealth = {(byte)0x00, (byte)0x00, (byte)0x00,
                                  (byte)0x04};

  public ADV_sidea() {
    super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT,
          ADV_DEF_INTERVAL, "",
          true);         // значение параметра режима замены равно true
    super.setAdvisor( this );
  }

//--------
// ADV_AdvisorInitialize

  public void ADV_AdvisorInitialize()
  { 
    suppressBaseOpeningSocket();   // сообщает основному коду о том, что не нужно
                                   // создавать стандартный сокет
    return;
  }

//--------
// getLoad

  public int getLoad(int iConnectTime, ADV_Thread caller) {
    int iRc;
    int iLoad = ADV_HOST_INACCESSIBLE;    // -1
    int iControlPort = 11999;   // порт для подключения к серверу

    string sServer = caller.getCurrentServer();   // адреса сервера
    try {
      socket soServer = new Socket(sServer, iControlPort);  // создать сокет
                                                            // для сервера
      DataInputStream disServer = new DataInputStream(
                                      soServer.getInputStream());
      DataOutputStream dosServer = new DataOutputStream(
                                       soServer.getOutputStream());
      
      int iRecvTimeout = 10000;  // задает значение тайм-аута (в мс)
                                 // для приема данных
      soServer.setSoTimeout(iRecvTimeout);

      dosServer.writeInt(4);     // отправляет сообщение серверу
      dosServer.flush();

      iLoad = disServer.readByte();   // получает ответ от сервера

    } catch (exception e) {
      system.out.println("Caught exception " + e);
    }
    return iLoad;    // возвращает значение нагрузки для сервера
  }
}

Посредник с двумя портами

Следующий пример пользовательского советника демонстрирует возможность обнаружения сбоя одного порта сервера на основании его собственного состояния и состояния другого демона сервера, запущенного для другого порта того же сервера. Например, если демон HTTP перестает отвечать через порт 80, может потребоваться остановить перенаправление трафика демону SSL через порт 443.

Этот советник ведет себя агрессивнее, чем стандартные советники, поскольку любой сервер, который не отправляет ответ на его запрос, рассматривается ним как приостановленный и помечается как отключенный. Стандартные советники считают, что если сервер не отвечает, то он очень медленный. Этот же советник помечает сервер как отключенный как для порта HTTP, так и для порта SSL на основании отсутствия ответа от одного из них.

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

Используются следующие методы:

Обнаруживаются следующие условия возникновения ошибок:

В следующем примере программы используется порт 80 для протокола HTTP и порт 443 для протокола SSL, однако вместо них можно указать любую другую комбинацию портов.

package CustomAdvisors;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Date;
import com.ibm.internet.lb.advisors.*;
import com.ibm.internet.lb.common.*;
import com.ibm.internet.lb.manager.*;
import com.ibm.internet.lb.server.SRV_ConfigServer;

//--------
// Определение элементов хэш-таблиц в пользовательском советнике

class ADV_nte implements Cloneable {
  private string  sCluster;
  private int     iPort;
  private string  sServer;
  private int     iLoad;
  private Date    dTimestamp;

//--------
// конструктор

  public ADV_nte(string sClusterIn, int iPortIn, string sServerIn,
                 int iLoadIn) {
    sCluster = sClusterIn;
    iPort = iPortIn;
    sServer = sServerIn;
    iLoad = iLoadIn;
    dTimestamp = new Date();
  }

//--------
// проверка срока действия элемента
  public boolean isCurrent(ADV_twop oThis) {
    boolean bCurrent;
    int iLifetimeMs = 3 * 1000 * oThis.getInterval();
         // присвоить параметру срока действия
                                                        // значение, равное трем циклам советника
    Date dNow = new Date();
    Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs);

    if (dNow.after(dExpires)) {
      bCurrent = false;
    } else {
      bCurrent = true;
    }
    return bCurrent;
  }

//--------
// получение значения

  public int getLoadValue() { return iLoad; }
  
//--------
// дубликат (позволяет избежать повреждения между нитями)

  public synchronized Object Clone() {
    try {
      return super.clone();
    } catch (cloneNotSupportedException e) {
      return null;
    }
  }

}

//--------
// определение пользовательского советника

public class ADV_twop extends ADV_Base
   implements ADV_MethodInterface, ADV_AdvisorVersionInterface {
 
  static final int ADV_TWOP_PORT_HTTP = 80;
  static final int ADV_TWOP_PORT_SSL = 443;

  //--------
  // определение таблиц для хранения информации о портах

  static HashTable htTwopHTTP = new Hashtable();
  static HashTable htTwopSSL = new Hashtable();

  static final String ADV_TWOP_NAME = "twop";
  static final int ADV_TWOP_DEF_ADV_ON_PORT = 80;
  static final int ADV_TWOP_DEF_INTERVAL = 7;
  static final string ADV_HTTP_REQUEST_STRING =
    "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " +
    "IBM_LB_Custom_Advisor\r\n\r\n";

  //--------
  // создание массива байт с приветственным сообщением SSL-клиента
  
  public static final byte[] abClientHello = {
    (byte)0x80, (byte)0x1c,
    (byte)0x01,               // приветственное сообщение клиента
    (byte)0x03, (byte)0x00,   // версия протокола SSL
    (byte)0x00, (byte)0x03,   // длина ключа (в байтах)
    (byte)0x00, (byte)0x00,   // длина ИД сеанса (в байтах)
    (byte)0x00, (byte)0x10,   // длина данных вызова (в байтах)
    (byte)0x00, (byte)0x00, (byte)0x03,   // спецификация шифра
    (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20,  // данные вызова
    (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18,
    (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52,
    (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A };

  //--------
  // конструктор

  public ADV_twop() {
    super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT,
          ADV_TWOP_DEF_INTERVAL, "",
          false);    // false = load balancer измеряет время ответа
    setAdvisor ( this );
  }

  //--------
  // ADV_AdvisorInitialize

  public void ADV_AdvisorInitialize() {
    return;
  }

  //--------
  // синхронизированные процедуры доступа PUT и GET для хэш-таблиц

  synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) {
    ADV_nte nte = (ADV_nte)(ht.get(sHashKey));
    if (null != nte) {
      nte = (ADV_nte)nte.clone();
    }
    return nte;
  }
 synchronized void putNte(Hashtable ht, String sName, String sHashKey,
                          ADV_nte nte) {
   ht.put(sHashKey,nte);
   return;
 }

  //--------
  // getLoadHTTP - определение нагрузки HTTP на основе ответа сервера

  int getLoadHTTP(int iConnectTime, ADV_Thread caller) {
    int iLoad = ADV_HOST_INACCESSIBLE;

    int iRc = caller.send(ADV_HTTP_REQUEST_STRING);  // отправляет сообщение-запрос
                                                     // для сервера
    if (0 <= iRc) {    // произошел сбой?
      StringBuffer sbReceiveData = new StringBuffer("")    // выделение буфера
                                                           // для ответа
      iRc = caller.receive(sbReceiveData);    // получение ответа от сервера

      if (0 <= iRc) {     // произошел сбой?
        if (0 < sbReceiveData.length()) {    // приняты ли данные?
          iLoad = SUCCESS;        // игнорирует принятые данные и
                                  // возвращает код SUCCESS
        }
      }
    }
    return iLoad;
  }

  //--------
  // getLoadSSL() - определение нагрузки SSL на основе ответа сервера

  int getLoadSSL(int iConnectTime, ASV_Thread caller) {
    int iLoad = ADV_HOST_INACCESSIBLE;

    int iSocket = caller.getAdvisorSocket();   // отправляет запрос серверу
    CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper(
                                                  abClientHello);
    int iRc = SRV_ConfigServer.socketapi.sendBytes(iSocket, cbawClientHello);

    if (0 <= iRc) {    // произошел сбой?
      StringBuffer sbReceiveData = new StringBuffer("");  // выделение буфера
                                                          // для ответа
      iRc = caller.receive(sbReceiveData);     // получение ответа от
                                               // серверу
      if (0 <= iRc) {     // произошел сбой?
        if (0 < sbReceiveData.length()) {    // приняты ли данные?
          iLoad = SUCCESS;   // игнорирует принятые данные и возвращает код SUCCESS
        }
      }
    }
    return iLoad;
  }

  //--------
  // getLoad - объединение результатов методов HTTP и SSL

  public int getLoad(int iConnectTime, ADV_Thread caller) {
    int iLoadHTTP;
    int iLoadSSL;
    int iLoad;
    int iRc;

    String sCluster = caller.getCurrentCluster();   // текущий адрес кластера
    int iPort = getAdviseOnPort();
    String sServer = caller.getCurrentServer();
    String sHashKey = sCluster = ":" + sServer;     // ключ хэш-таблицы

    if (ADV_TWOP_PORT_HTTP == iPort) {              // обработка HTTP-сервера
      iLoadHTTP = getLoadHTTP(iConnectTime, caller);
                  // получение значения нагрузки для HTTP

      ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP);
      putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP);
                 // сохранение значения нагрузки
                                                      // о протоколе SSL
      ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey);
                 // получение информации
                                                            // для протокола HTTP
      if (null != nteSSL) {
        if (true == nteSSL.isCurrent(this)) {
                 // проверка временной метки
          if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) {
                 // работает ли                                                                    SSL?
            iLoad = iLoadHTTP;
          } else {    // SSL не работает, поэтому HTTP-сервер
                      // помечается как отключенный
            iLoad= ADV_HOST_INACCESSIBLE;
          }
        } else {      // срок действия информации SSL истек, поэтому
                      // HTTP-сервер помечается как отключенный
          iLoad = ADV_HOST_INACCESSIBLE;
        }
      } else {        // значение нагрузки для SSL отсутствует, передача
                      // результатов выполнения метода getLoadHTTP()
        iLoad = iLoadHTTP;
      }
    }
    else if (ADV_TWOP_PORT_SSL == iPort) {
                 // обработка SSL-сервера
      iLoadSSL = getLoadSSL(iConnectTime, caller);
                 // получение значения нагрузки для SSL

      ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL);
      putNte(htTwopSSL, "SSL", sHashKey, nteSSL);
                 // сохранение информации о нагрузке для SSL

      ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey);   // получение информации
                                                               // для протокола HTTP
      if (null != nteHTTP) {
        if (true == nteHTTP.isCurrent(this)) {
                 // проверка временной метки
          if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) {  // работает ли
                                                                  SSL?
            iLoad = iLoadSSL;
          } else {   // HTTP-сервер не работает, поэтому он
                     // помечается как отключенный
            iLoad = ADV_HOST_INACCESSIBLE;
          }
        } else {     // срок действия информации HTTP истек,
                     // сервер помечается как отключенный
          iLoad = ADV_HOST_INACCESSIBLE;
        }
      } else {       // значение нагрузки для HTTP отсутствует, передача
                     // результатов выполнения метода getLoadSSL()
        iLoad = iLoadSSL;
      }
    }

  //--------
  // обработчик ошибок

    else {
      iLoad = ADV_HOST_INACCESSIBLE;
    }
    return iLoad;
  }
}

Советник WebSphere Application Server

Пример пользовательского советника для сервера WebSphere Application Server расположен в каталоге установочный_каталог/servers/samples/CustomAdvisors/. В этом документе приводится только часть исходного кода.

Полный текст исходного кода советника намного сложнее приведенного здесь отрывка. В него добавлена специальная процедура анализа, более компактная по сравнению с процедурой StringTokenizer (см. пример выше).

Более сложная часть исходного кода содержится в файле сервлета Java. Кроме того, сервлет содержит два метода, необходимых в соответствии со спецификацией сервлета: init() и service(), и еще один метод: run(), необходимый для класса Java.lang.thread.

Ниже приведены некоторые фрагменты кода сервлета.

...

  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    ...
    _checker = new Thread(this);
    _checker.start();
  }
  
  public void run() {
    setStatus(GOOD);

    while (true) {
      if (!getKeepRunning())
        return;
      setStatus(figureLoad());
      setLastUpdate(new java.util.Date());

      try {
        _checker.sleep(_interval * 1000);
      } catch (Exception ignore) { ; }
    }
  }

  public void service(HttpServletRequest req, HttpServletResponse res)
                      throws ServletException, IOException {

    ServletOutputStream out = null;
    try {
      out = res.getOutputStream();
    } catch (Exception e) { ... }
    ...
    res.setContentType("text/x-application-LBAdvisor");
    out.println(getStatusString());
    out.println(getLastUpdate().toString());
    out.flush();
    return;
  }

  ...

Использование данных, полученных от советников

Как при использовании стандартных функций, так и при добавлении новых функций к исходному коду пользовательского советника возникает необходимость проверить возвращаемые значения нагрузки и выполнить соответствующие действия. Для этой цели используются Java-класс StringTokenizer и связанные методы.

Пример стандартной команды HTTP: GET /index.html HTTP/1.0

Стандартный ответ на эту команду выглядит следующим образом:

HTTP/1.1 200 OK
Date: Mon, 20 November 2000 14:09:57 GMT
Server: Apache/1.3.12 (Linux and UNIX)
Content-Location: index.html.en
Vary: negotiate
TCN: choice
Last-Modified: Fri, 20 Oct 2000 15:58:35 GMT
ETag: "14f3e5-1a8-39f06bab;39f06a02"
Accept-Ranges: bytes
Content-Length: 424
Connection: close
Content-Type: text/html
Content-Language: en

<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 3.2 Final//EN">
<HTML><HEAD><TITLE>Test Page</TITLE></HEAD>
<BODY><H1>Apache server</H1>
<HR>
<P><P>This Web server is running Apache 1.3.12.
<P><HR>
<P><IMG SRC="apache_pb.gif" ALT="">
</BODY></HTML>

Наиболее важные элементы указаны в первой строке, в частности код возврата HTTP.

В соответствии со спецификацией протокола HTTP существуют следующие группы кодов возврата:

Если вам заранее известны возможные коды возврата сервера, такой уровень детализации данных, как в этом примере, вам может и не потребоваться. Следует отметить, что ограничение списка отслеживаемых кодов возврата может снизить гибкость вашей программы в будущем.

Ниже приведен пример автономной программы на языке Java, содержащей минимальный HTTP-клиент. Этот пример вызывает простой универсальный анализатор для проверки ответов HTTP.

import java.io.*;
import java.util.*;
import java.net.*;

public class ParseTest {
  static final int iPort = 80;
  static final String sServer = "www.ibm.com";
  static final String sQuery = "GET /index.html HTTP/1.0\r\n\r\n";
  static final String sHTTP10 = "HTTP/1.0";
  static final String sHTTP11 = "HTTP/1.1";

  public static void main(String[] Arg) {
    String sHTTPVersion = null;
    String sHTTPReturnCode = null;
    String sResponse = null;
    int iRc = 0;
    BufferedReader brIn = null;
    PrintWriter psOut = null;
    Socket soServer= null;
    StringBuffer sbText = new StringBuffer(40);

    try {
      soServer = new Socket(sServer, iPort);
      brIn = new BufferedReader(new InputStreamReader(
                                    soServer.getInputStream()));
      psOut = new PrintWriter(soServer.getOutputStream());
      psOut.println(sQuery);
      psOut.flush();
      sResponse = brIn.readLine();
      try {
        soServer.close();
      } catch (Exception sc) {;}
    }  catch (Exception swr) {;}
    
    StringTokenizer st = new StringTokenizer(sResponse, " ");
    if (true == st.hasMoreTokens()) {
      sHTTPVersion = st.nextToken();
      if (sHTTPVersion.equals(sHTTP110) || sHTTPVersion.equals(sHTTP11)) {
        System.out.println("HTTP Version: " + sHTTPVersion);
      } else {
        System.out.println("Invalid HTTP Version: " + sHTTPVersion);
      }
    } else {
      System.out.println("Nothing was returned");
      return;
    }

    if (true == st.hasMoreTokens()) {
      sHTTPReturnCode = st.nextToken();
      try {
        iRc = Integer.parseInt(sHTTPReturnCode);
      } catch (NumberFormatException ne) {;}

      switch (iRc) {
      case(200):
        System.out.println("HTTP Response code: OK, " + iRc);
        break;
      case(400): case(401): case(402): case(403): case(404):
        System.out.println("HTTP Response code: Client Error, " + iRc);
        break;
      case(500): case(501): case(502): case(503):
        System.out.println("HTTP Response code: Server Error, " + iRc);
        break;
      default:
        System.out.println("HTTP Response code: Unknown, " + iRc);
        break;
      }
    }

    if (true == st.hasMoreTokens()) {
      while (true == st.hasMoreTokens()) {
        sbText.append(st.nextToken());
        sbText.append("  ");
        }
      System.out.println("HTTP Response phrase: " + sbText.toString());
    }
  }
}
  

Индекс

A C E G H I L M N O P R S T W Б Д З И К О П Р С Ф Ц Ш Э
A C E G H I L M N O P R S T W Б Д З И К О П Р С Ф Ц Ш Э