utl_http — это расширение Postgres Pro, которое позволяет получать доступ к данным в Интернете по протоколу HTTP (HTTP/1.0 и HTTP/1.1), выполняя HTTP-вызовы из SQL и PL/pgSQL. Функциональность, предоставляемая этим модулем, во многом пересекается с функциональностью пакета UTL_HTTP в Oracle. С помощью utl_http можно писать программы, взаимодействующие с HTTP-серверами. Кроме того, расширение utl_http содержит функции, которые можно использовать в запросах SQL, поддерживает протокол HTTP через SSL, также известный как HTTPS, и HTTP-методы GET, POST, PUT, UPLOAD, PATCH, HEAD, OPTIONS, DELETE, TRACE (см. https://datatracker.ietf.org/doc/html/rfc9110#name-methods), а также любые пользовательские HTTP-методы.
Расширение utl_http обычно используется следующим образом:
Запрос создаётся функцией begin_request.
Задаются параметры запроса, подробнее они описаны в Подразделе G.7.3.3.
Ответ обрабатывается функцией get_response.
Полученный ответ обрабатывается с использованием процедур из Подраздел G.7.3.5.
Расширение utl_http поставляется вместе с Postgres Pro Enterprise в отдельном пакете pgpro-orautl-ent-17 (подробные инструкции по установке приведены в Главе 17). Чтобы включить utl_http, создайте расширение с помощью следующего запроса:
CREATE EXTENSION utl_http;
Для корректной работы utl_http с SSL необходима библиотека libcurl с поддержкой OpenSSL. Например, libcurl4-openssl-dev для Ubuntu.
Расширение utl_http предоставляет несколько типов данных:
Тип req представляет собой HTTP-запрос.
CREATE TYPE req AS ( url varchar(32767), method varchar(64), http_version varchar(64) );
Таблица G.93. Параметры req
| Параметр | Описание |
|---|---|
url | URL-адрес HTTP-запроса. Задаётся после создания запроса функцией begin_request. |
method | Метод, который будет применяться для ресурса, определяемого URL-адресом. Он задаётся после создания запроса функцией begin_request |
http_version | Версия HTTP-протокола, используемая для отправки запроса. Она задаётся после создания запроса функцией begin_request. |
Тип resp представляет собой HTTP-ответ.
CREATE TYPE resp AS ( status_code integer, reason_phrase varchar(256), http_version varchar(64) );
Таблица G.94. Параметры resp
| Параметр | Описание |
|---|---|
status_code | Код состояния, возвращаемый веб-сервером. Это трёхзначное целое число, показывающее результаты HTTP-запроса, обработанного веб-сервером. Этот код задаётся после обработки ответа функцией get_response. |
reason_phrase | Короткое текстовое сообщение, возвращаемое веб-сервером и описывающее код состояния. Оно содержит краткое описание результатов HTTP-запроса, обработанного веб-сервером, и задаётся после обработки ответа функцией get_response. |
http_version | Версия HTTP-протокола, используемая в HTTP-ответе. Она задаётся после обработки ответа функцией get_response. |
Тип cookie представляет собой данные cookie HTTP. Тип cookie_table — это набор cookie данных HTTP. По сути, это тип данных массива, создаваемого на основе автоматически созданного массива.
CREATE TYPE cookie AS ( name varchar(256), value varchar(1024), domain varchar(256), expire timestamp with time zone, path varchar(1024), secure bool, version int, comment varchar(1024) ); CREATE DOMAIN cookie_table AS _cookie;
Таблица G.95. Поля типов cookie и cookie_table
| Параметр | Описание |
|---|---|
name | Имя cookie HTTP. |
value | Значение cookie. |
domain | Домен, для которого действительны cookie. |
expire | Время истечения срока действия cookie. |
path | Подмножество URL-адресов, к которым относятся cookie. |
secure | Должны ли cookie возвращаться на веб-сервер только с использованием защищённых средств. |
version | Версия спецификации cookie, которой соответствуют cookie. |
comment | Комментарий, описывающий предполагаемое использование cookie. |
Тип request_context_key используется для определения ключа контекста запроса. В Postgres Pro он представлен типом integer и сохраняется из соображений совместимости для миграции из Oracle.
Обратите внимание, что параметр request_context в функциях и процедурах ниже сохраняется для совместимости при миграции из Oracle и не влияет на результат.
Функции request_function и request_pieces_function берут URL-адрес в виде строки, подключаются к указанному в ней сайту и возвращают данные (обычно HTML), полученные с этого сайта.
request(url text, proxy text default null) returns text
#Получает веб-страницу и возвращает не более первых 2000 байт этой страницы.
request_pieces(url text, max_pieces int default 32767, proxy text default null) returns text
#Эта функция возвращает таблицу PL/pgSQL, состоящую из фрагментов данных по 2000 байт, полученных по заданному URL-адресу. Элементы таблицы, возвращаемые request_pieces, представляют собой последовательные фрагменты данных, полученные в результате HTTP-запроса к этому URL-адресу.
Расширение utl_http предоставляет функции и процедуры для работы с конфигурацией и поведением по умолчанию при выполнении HTTP-запросов в сеансе пользователя базы данных. Когда запрос создаётся, он наследует параметры по умолчанию в отношении поддержки cookie, перенаправления, набора символов тела сообщения и тайм-аута передачи текущего сеанса. Когда создаётся ответ на запрос, он наследует эти параметры из запроса.
set_response_error_check(enable bool default false)
#Эта процедура определяет, будет ли функция get_response выдавать исключение, когда веб-сервер возвращает код состояния, указывающий на ошибку — код состояния в диапазоне 4xx или 5xx.
get_response_error_check(enable bool)
#Эта процедура проверяет, установлена ли проверка ошибок ответа.
set_transfer_timeout(timeout int4 default 60)
#Эта процедура устанавливает значение тайм-аута по умолчанию для всех будущих HTTP-запросов, который должен соблюдаться расширением utl_http перед чтением HTTP-ответа с веб-сервера или прокси-сервера. Это значение тайм-аута можно использовать, чтобы избежать блокировки программ при загрузке веб-серверов или интенсивном сетевом трафике во время получения получении веб-страниц с веб-серверов. Значение тайм-аута по умолчанию — 60 секунд.
get_transfer_timeout(timeout int4)
#Эта процедура получает значение тайм-аута по умолчанию для всех будущих HTTP-запросов.
set_detailed_excp_support(enable bool default false)
#Эта процедура определяет, выдаёт ли расширение utl_http подробное исключение. По умолчанию она выдаёт исключение REQUEST_FAILED при сбое HTTP-запроса. Используйте get_detailed_sqlcode и get_detailed_sqlerrm для получения более подробной информации об ошибке.
Доступные исключения перечислены в Таблице G.96.
Таблица G.96. Исключения utl_http
| Исключение | Код ошибки | Причина | Где выдаётся исключение |
|---|---|---|---|
BAD_ARGUMENT | 29265 | Передан некорректный аргумент | Любой интерфейс HTTP-запроса или ответа, если включена выдача подробных исключений |
HEADER_NOT_FOUND | 29261 | Заголовок не найден | get_header, get_header_by_name, когда включена выдача подробных исключений |
END_OF_BODY | 29266 | Достигнут конец тела HTTP-ответа | read_raw, read_text и read_line, когда включена выдача подробных исключений |
HTTP_CLIENT_ERROR | 29268 | Код состояния ответа из get_response указывает на то, что произошла ошибка клиента (код состояния в диапазоне 4xx). Из функции begin_request HTTP-прокси возвращает код состояния в диапазоне 4xx при выполнении HTTPS-запроса через прокси. | get_response, begin_request, когда включена выдача подробных исключений |
HTTP_SERVER_ERROR | 29269 | Код состояния ответа из get_response указывает на то, что произошла ошибка сервера (код состояния в диапазоне 5xx). Из функции begin_request HTTP-прокси возвращает код состояния в диапазоне 5xx при выполнении HTTPS-запроса через прокси. | get_response, begin_request, когда включена выдача подробных исключений |
REQUEST_FAILED | 29273 | Ошибка выполнения запроса | Любой интерфейс HTTP-запроса или ответа, если отключена выдача подробных исключений |
get_detailed_excp_support(enable bool)
#Эта процедура проверяет, выдаст ли utl_http подробное исключение или нет.
Расширение utl_http предоставляет функции и процедуры для запуска HTTP-запроса, работы с атрибутами и отправки информации запроса на веб-сервер. Когда запрос создаётся, он наследует параметры по умолчанию в отношении поддержки cookie, перенаправления, набора символов тела сообщения и тайм-аута передачи текущего сеанса. Параметры можно изменить, вызвав интерфейс запроса.
begin_request(url text, method text default 'GET', http_version text default null, request_context request_context_key default null) returns req
#Эта функция начинает новый HTTP-запрос.
set_header(r req, name text, value text)
#Эта процедура устанавливает заголовок HTTP-запроса для будущего запроса.
set_authentication(r req, username text, password text, scheme text default 'Basic', for_proxy boolean default false)
#Эта процедура устанавливает информацию о HTTP-аутентификации в заголовке HTTP-запроса. Веб-серверу эта информация нужна для авторизации запроса.
set_body_charset(r req, charset name default null)
#Эта процедура устанавливает набор символов, когда тип носителя — text, но набор символов не указан в заголовке Content-Type и может принимать одну из следующих форм:
Устанавливает набор символов по умолчанию для тела всех будущих HTTP-запросов.
set_body_charset( charset IN name DEFAULT NULL)
Устанавливает набор символов тела запроса.
set_body_charset( r INOUT req, charset IN name DEFAULT NULL)
set_cookie_support(r req, enable bool)
#Эта процедура определяет поддержку cookie и может принимать одну из следующих форм:
Включает или отключает поддержку cookie HTTP в запросе.
set_cookie_support( r INOUT req, enable IN bool DEFAULT true)
Устанавливает, будут ли будущие HTTP-запросы поддерживать cookie HTTP, а также максимальное количество cookie, поддерживаемых в текущем сеансе пользователя базы данных.
set_cookie_support( enable IN bool, max_cookies IN int4 DEFAULT 300, max_cookies_per_site IN int4 DEFAULT 20)
set_follow_redirect(r req, max_redirects int4 default 3)
#Эта процедура устанавливает максимальное количество раз, когда utl_http должен следовать инструкции HTTP-перенаправления в HTTP-ответах на запросы в get_response. По умолчанию — 3.
set_proxy(proxy text, no_proxy_domains text)
#Эта процедура устанавливает прокси-сервер, который будет использоваться для HTTP-запросов или других протоколов. Обратите внимание, что прокси-сервер не будет работать без корректного сертификата.
write_raw(r req, data bytea)
#Эта процедура записывает двоичные данные в тело HTTP-запроса для будущего запроса.
write_text(r req, data text)
#Эта процедура записывает текстовые данные в тело HTTP-запроса для будущего запроса.
end_request(r req)
#Эта процедура завершает HTTP-запрос путём сброса параметров запроса.
set_option(text text)
#Задать параметры для всех будущих запросов в сеансе.
PROCEDURE set_option(
option IN text,
value IN text
);set_option(r req text text)
#Задать параметр для указанного запроса.
PROCEDURE set_option(
r IN req,
option IN text,
value IN text
);get_option(text)
#Показать значение по умолчанию, установленное для всех будущих запросов в этом сеансе.
FUNCTION get_option(
option IN text
) RETURNS text;get_option(r req text)
#Показать значение параметра по умолчанию, установленное для существующего запроса.
FUNCTION get_option(
r IN req,
option IN text
)У данных функций есть следующие параметры:
OPT_SSL_VERIFYPEER проверяет SSL-сертификат удалённой стороны. Этот параметр можно задать для запроса или в качестве значения по умолчанию для всех будущих запросов. Возможные значения: 0 или 1 (по умолчанию).
OPT_SSL_VERIFYHOST сверяет имя сертификата с именем компьютера. Этот параметр можно задать для конкретного запроса или в качестве значения по умолчанию для всех будущих запросов.
Этот параметр доступен только для версии libcurl 7.8.1 и выше. Возможные значения: 0, 1 или 2 (значение по умолчанию). Когда для параметра задано значение 0, соединение устанавливается независимо от соответствия имён в сертификате. Используйте это значение с осторожностью.
Также не рекомендуется использовать значение 1, поскольку это может привести к неожиданным результатам в зависимости от версии libcurl. За дополнительной информацией обратитесь к официальной документации libcurl.
Расширение utl_http предоставляет функции и процедуры для управления HTTP-ответом, полученным из get_response, и получения информации об ответе от веб-сервера. Когда создаётся ответ на запрос, он наследует параметры поддержки cookie, перенаправления, набора символов тела сообщения и тайм-аута передачи из запроса. Вызвав интерфейс ответа, можно изменить только набор символов тела.
end_response(r resp)
#Эта процедура завершает HTTP-ответ путём сброса параметров запроса.
get_authentication(r resp, scheme text, realm text, for_proxy bool default false)
#Эта процедура получает информацию о HTTP-аутентификации, необходимую для принятия запроса веб-сервером, как указано в заголовке HTTP-ответа.
get_header(r resp, n int4, name text, value text)
#Эта процедура возвращает n-е имя заголовка HTTP-ответа и значение, возвращаемое в ответе.
get_header_by_name(r resp, name text, value text, n int4 default 1)
#Эта процедура возвращает значение заголовка HTTP-ответа, возвращаемое в ответе, по заданному имени заголовка.
get_header_count(r resp) returns int4
#Эта функция возвращает количество заголовков HTTP-ответа, возвращаемых в ответе.
get_response(r req, return_info_response bool default false) returns resp
#Эта функция завершает HTTP-запрос и ответ: читает HTTP-ответ и обрабатывает строку состояния и заголовки ответа. Код состояния, описание причины и версия HTTP-протокола сохраняются в записи ответа.
read_raw(r resp, data bytea, len int4 default null)
#Эта процедура считывает тело HTTP-ответа в двоичной форме и возвращает выходные данные в буфер со стороны вызывающего.
read_line(r resp, data text, remove_crlf bool default false)
#Эта процедура считывает тело HTTP-ответа в текстовой форме до конца строки, и возвращает выходные данные в буфер со стороны вызывающего.
read_text(r resp, data text, len int4 default null)
#Эта процедура считывает тело HTTP-ответа в текстовой форме и возвращает выходные данные в буфер со стороны вызывающего.
Расширение utl_http предоставляет функции и процедуры для управления cookie.
add_cookies(cookies cookie_table, request_context request_context_key default null)
#Эта процедура добавляет cookie, поддерживаемые расширением utl_http.
clear_cookies(request_context request_context_key default null)
#Эта процедура удаляет все cookie с которые в настоящее время работает расширение utl_http.
get_cookie_count(request_context request_context_key default null) returns int4
#Эта функция возвращает объём cookie, с которым и в настоящее время работает расширение utl_http для всех веб-серверов.
get_cookies(cookies cookie_table, request_context request_context_key default null) returns cookie_table
#Эта функция возвращает полный объём cookie, с которым в настоящее время работает расширение utl_http для всех веб-серверов.
Расширение utl_http предоставляет функции для получения информации об ошибках.
get_detailed_sqlcode() returns int4
#Получает код SQLCODE с описанием последнего выданного исключения (см. Таблицу G.96).
get_detailed_sqlerrm() returns text
#Получает код SQLERRM с описанием последнего выданного исключения (см. Таблицу G.96).
DO $$
DECLARE
request utl_http.req;
response utl_http.resp;
text_body text;
BEGIN
CALL utl_http.set_body_charset('WIN1251');
request := utl_http.begin_request('https://postgrespro.ru/', 'GET');
CALL utl_http.set_authentication(request, 'admin', 'qwerty', 'Basic', FALSE);
response := utl_http.get_response(request);
CALL utl_http.read_text(response, text_body);
text_body = substring(text_body FROM 720 FOR 245);
RAISE NOTICE '%', text_body;
END$$;Схему utl_http можно явно задать в параметре search_path и опускать в теле запроса:
SET search_path =utl_http, public;
Тогда пример выше будет выглядеть так:
DO $$
DECLARE
request req;
response resp;
text_body text;
BEGIN
CALL set_body_charset('WIN1251');
request := begin_request('https://postgrespro.ru/docs/enterprise/17/utl-http', 'GET');
CALL set_authentication(request, 'admin', 'qwerty', 'Basic', FALSE);
response := get_response(request);
CALL read_text(response, text_body);
text_body = substring(text_body FROM 720 FOR 245);
RAISE NOTICE '%', text_body;
END$$;Пример самоподписанного сертификата:
test=# SELECT * FROM utl_http.request('https://localhost:5001');
ERROR: utl_http failed while handling the request to "https://localhost:5001".
Details: "SSL peer certificate or SSH remote key was not OK"
test=# call utl_http.set_option('OPT_SSL_VERIFYPEER', '0');
test=# call utl_http.set_option('OPT_SSL_VERIFYHOST', '0');
test=# SELECT * FROM substr(utl_http.request('https://localhost:5001'), 0, 50);
substr
------------------
<!DOCTYPE html> +
<html lang="en">+
+
<head> +
<met
(1 row)Пример клиентской аутентификации по ключу:
SELECT * FROM utl_http.begin_request('https://some_server');
CALL utl_http.set_option((NULL, NULL, NULL), 'OPT_CAINFO_BLOB', '-----BEGIN CERTIFICATE-----
...
Y7707nS0spc1qVPMSQ==
-----END CERTIFICATE-----
');
CALL utl_http.set_option((NULL, NULL, NULL), 'OPT_SSLCERT_BLOB', '-----BEGIN CERTIFICATE-----
...
GMNTQVzSHmuu8tw5W4GjNUQL2Wx5h/yuMD5dS+vCeQ==
-----END CERTIFICATE-----
');
CALL utl_http.set_option((NULL, NULL, NULL), 'OPT_SSLKEY_BLOB', '-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,2557386B35596227304F2F017F07B467
...
-----END RSA PRIVATE KEY-----
');
CALL utl_http.set_option((NULL, NULL, NULL), 'OPT_KEYPASSWD', 'superpassword');
SELECT * FROM utl_http.get_response((NULL, NULL, NULL));