Сертификат проверки электронной подписи не пригоден для шифрования
В 1С необходимо перейти в настройки учетной записи https://help.astral.ru/v/129672362 и нажать кнопку «Настроить автоматически сейчас».
После переотправьте отчет.
Произошла ошибка при выполнении криптоопераций над запросом к серверу СЭДО ФСС
Проверьте, пожалуйста, сертификаты СФР (бывший ФСС) по инструкции https://help.astral.ru/v/158111787.
Проверить доступность, там где расположена база 1C до ресурса: sedo.fss.ru (193.148.44.114) — используется для получения и отправки СЭДО.
Необходимо открыть ресурс https://sedo.fss.ru/sedo-gateway/api/soap/SedoGateway?wsdl в браузере, у Вас откроется страница с XML кодом.
Проверить доступность до сервера, измените регистрационный номер СФР (бывший ФСС) в реквизитах организации (например, поменяйте один символ).
Если при нажатии на «Получить из ФСС» поступит ошибка, связанная с некорректным регистрационным номером, значит доступность до сервера есть.
При получении извещений от СФР (бывший ФСС), в разделе Извещения от ФСС нажмите Ещё → «Получить сообщения за период», «Выберите период»
и нажмите «Получить сообщения».
Сертификат проверки электронной подписи не пригоден для шифрования
В 1С необходимо перейти в настройки учетной записи https://help.astral.ru/v/129672362 и нажать кнопку «Настроить автоматически сейчас».
После переотправьте отчет.
Cведения об операторе отличаются от сведений об операторе, к которому подключен страхователь
Перед отправкой отчетов в СФР (бывший ПФР) необходимо отправить «Заявление на подключение к ЭДО СФР»
по инструкции в нашей базе знаний https://help.astral.ru/v/129668635.
Далее дождитесь обработки и повторите отправку отчёта.
Не удалось проверить этот сертификат, поскольку не получен правильный список отзыва сертификатов от центра сертификации
Ошибка поступает с приемного комплекса СФР (бывш.ПФР), если по отчету есть квитанция — ошибку нужно игнорировать, если квитанции нет — ожидать 4 рабочих дня с момента отправки отчета
Как подписать pdf файл электронно-цифровой подпись вне сервиса 1С-Отчетность
Можно подписать с помощью КриптоАРМ https://help.astral.ru/v/151552830 или КриптоПро CSP 5 версии
https://help.astral.ru/1c-o/podklyuchenie-k-servisu/algoritm-podklyucheniya-k-1s-otchetnosti#id-Алгоритмподключенияк1СОтчетности-Решение2.Загрузкаэлектроннойдоверенности,подписаннойстороннимисредствами
// Коннектор: удобный HTTP-клиент для 1С:Предприятие 8
//
// Copyright 2017-2023 Vladimir Bondarevskiy
//
// Licensed under the Apache License, Version 2.0 (the «License»);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an «AS IS» BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// URL: https://github.com/vbondarevsky/Connector
// e-mail: vbondarevsky@gmail.com
// Версия: 2.6.0
//
// Требования: платформа 1С версии 8.3.10 и выше
Область ПрограммныйИнтерфейс
Область МетодыHTTP
Область МетодыОбщегоНазначения
// Отправляет GET запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// ПараметрыЗапроса — Структура, Соответствие — параметры, которые будут отправлены в URL (часть после ?):
// * Ключ — Строка — ключ параметра в URL.
// * Значение — Строка — значение параметра URL
// — Массив — сформирует строку из нескольких параметров: key=value1&key=value2 и т.д.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Get(URL, ПараметрыЗапроса = Неопределено, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(ПараметрыЗапроса, Неопределено, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "GET", URL, Параметры);
КонецФункции
// Отправляет OPTIONS запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Options(URL, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Неопределено, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "OPTIONS", URL, Параметры);
КонецФункции
// Отправляет HEAD запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Head(URL, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Неопределено, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "HEAD", URL, Параметры);
КонецФункции
// Отправляет POST запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Данные — Структура, Соответствие, Строка, ДвоичныеДанные — см. описание ДополнительныеПараметры.Данные.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Post(URL, Данные = Неопределено, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Данные, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "POST", URL, Параметры);
КонецФункции
// Отправляет PUT запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Данные — Структура, Соответствие, Строка, ДвоичныеДанные — см. описание ДополнительныеПараметры.Данные.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Put(URL, Данные = Неопределено, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Данные, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "PUT", URL, Параметры);
КонецФункции
// Отправляет PATCH запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Данные — Структура, Соответствие, Строка, ДвоичныеДанные — см. описание ДополнительныеПараметры.Данные.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Patch(URL, Данные = Неопределено, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Данные, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "PATCH", URL, Параметры);
КонецФункции
// Отправляет DELETE запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Данные — Структура, Соответствие, Строка, ДвоичныеДанные — см. описание ДополнительныеПараметры.Данные.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Delete(URL, Данные = Неопределено, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Данные, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "DELETE", URL, Параметры);
КонецФункции
// Отправляет MKCOL запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// См. ВызватьМетод
//
Функция Mkcol(URL, Данные = Неопределено, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Данные, Неопределено));
Возврат ВызватьHTTPМетод(ТекущаяСессия, "MKCOL", URL, Параметры);
КонецФункции
// Отправляет данные на указанный адрес для обработки с использованием указанного HTTP-метода.
//
// Параметры:
// Метод — Строка — имя HTTP-метода для запроса.
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// Структура — ответ на выполненный запрос:
// * ВремяВыполнения — Число — время выполнения запроса в миллисекундах.
// * Cookies — Соответствие — cookies полученные с сервера.
// * Заголовки — Соответствие — HTTP заголовки ответа.
// * ЭтоПостоянныйРедирект — Булево — признак постоянного редиректа.
// * ЭтоРедирект — Булево — признак редиректа.
// * Кодировка — Строка — кодировка текста ответа.
// * Тело — ДвоичныеДанные — тело ответа.
// * КодСостояния — Число — код состояния ответа.
// * URL — Строка — итоговый URL, по которому был выполнен запрос.
//
Функция ВызватьМетод(Метод, URL, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Неопределено, Неопределено));
Дополнить(Параметры, ДополнительныеПараметры);
Возврат ВызватьHTTPМетод(ТекущаяСессия, Метод, URL, Параметры);
КонецФункции
КонецОбласти
Область УпрощенныеМетодыДляРаботыСЗапросамиВФорматеJSON
// Отправляет GET запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// ПараметрыЗапроса — Структура, Соответствие — параметры, которые будут отправлены в URL (часть после ?).
// См. описание Сессия.ПараметрыЗапроса.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// Соответствие, Структура — ответ, десериализованный из JSON.
// Параметры преобразования см. ДополнительныеПараметры.ПараметрыПреобразованияJSON.
//
Функция GetJson(URL,
ПараметрыЗапроса = Неопределено,
ДополнительныеПараметры = Неопределено,
Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(ПараметрыЗапроса, Неопределено, Неопределено));
ПараметрыПреобразованияJSON =
ВыбратьЗначение(Неопределено, Параметры, "ПараметрыПреобразованияJSON", Неопределено);
Возврат КакJson(ВызватьHTTPМетод(ТекущаяСессия, "GET", URL, Параметры), ПараметрыПреобразованияJSON);
КонецФункции
// Отправляет POST запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Json — Структура, Соответствие — данные, которые необходимо сериализовать в JSON.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// Соответствие, Структура — ответ, десериализованный из JSON.
// Параметры преобразования см. ДополнительныеПараметры.ПараметрыПреобразованияJSON
//
Функция PostJson(URL, Json, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Неопределено, Json));
ПараметрыПреобразованияJSON =
ВыбратьЗначение(Неопределено, Параметры, "ПараметрыПреобразованияJSON", Неопределено);
Возврат КакJson(ВызватьHTTPМетод(ТекущаяСессия, "POST", URL, Параметры), ПараметрыПреобразованияJSON);
КонецФункции
// Отправляет PUT запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Json — Структура, Соответствие — данные, которые необходимо сериализовать в JSON.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// Соответствие, Структура — ответ, десериализованный из JSON.
// Параметры преобразования см. ДополнительныеПараметры.ПараметрыПреобразованияJSON
//
Функция PutJson(URL, Json, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Неопределено, Json));
ПараметрыПреобразованияJSON =
ВыбратьЗначение(Неопределено, Параметры, "ПараметрыПреобразованияJSON", Неопределено);
Возврат КакJson(ВызватьHTTPМетод(ТекущаяСессия, "PUT", URL, Параметры), ПараметрыПреобразованияJSON);
КонецФункции
// Отправляет DELETE запрос
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
// Json — Структура, Соответствие — данные, которые необходимо сериализовать в JSON.
// ДополнительныеПараметры — См. НовыеПараметры
// Сессия — См. СоздатьСессию
//
// Возвращаемое значение:
// Соответствие, Структура — ответ, десериализованный из JSON.
// Параметры преобразования см. ДополнительныеПараметры.ПараметрыПреобразованияJSON
//
Функция DeleteJson(URL, Json, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт
ТекущаяСессия = ТекущаяСессия(Сессия);
Параметры = НовыеПараметры();
Дополнить(Параметры, ДополнительныеПараметры);
Дополнить(Параметры, ПараметрыИзАргументов(Неопределено, Неопределено, Json));
ПараметрыПреобразованияJSON =
ВыбратьЗначение(Неопределено, Параметры, "ПараметрыПреобразованияJSON", Неопределено);
Возврат КакJson(ВызватьHTTPМетод(ТекущаяСессия, "DELETE", URL, Параметры), ПараметрыПреобразованияJSON);
КонецФункции
КонецОбласти
Область Конструкторы
// Конструктор дополнительных параметров
//
// Возвращаемое значение:
// Структура — позволяет задать дополнительные параметры:
// * Заголовки — Соответствие — см. описание Сессия.Заголовки.
// * Аутентификация — Структура — см. описание Сессия.Аутентификация
// * Прокси — ИнтернетПрокси — см. описание Сессия.Прокси.
// * ПараметрыЗапроса — Структура, Соответствие — см. описание Сессия.ПараметрыЗапроса.
// * ПроверятьSSL — Булево — см. описание Сессия.ПроверятьSSL.
// * КлиентскийСертификатSSL — СертификатКлиентаФайл, СертификатКлиентаWindows — Значение по умолчанию: Неопределено.
// * Cookies — Массив — см. описание Сессия.Cookies.
// * Таймаут — Число — время ожидания осуществляемого соединения и операций, в секундах.
// Значение по умолчанию — 30 сек.
// * РазрешитьПеренаправление — Булево — Истина — редиректы будут автоматически разрешены.
// Ложь — будет выполнен только один запрос к серверу.
// * Json — Структура, Соответствие — данные, которые необходимо сериализовать в JSON.
// * ПараметрыПреобразованияJSON — Структура — задает параметры преобразования JSON:
// ** ПрочитатьВСоответствие — Булево — Если Истина, чтение объекта JSON будет выполнено в Соответствие.
// Если Ложь, объекты будут считываться в объект типа Структура.
// ** ФорматДатыJSON — ФорматДатыJSON — формат, в котором представлена дата в строке,
// подлежащей преобразованию.
// ** ИменаСвойствСоЗначениямиДата — Строка, Массив Из Строка — имена свойств JSON,
// для которых нужно вызывать восстановление даты из строки.
// ** ИмяФункцииВосстановления — Строка — определяет имя функции, которая будет вызывается при чтении
// каждого свойства и должна иметь следующие параметры:
// ** Свойство — Строка — указывается только при чтении объектов JSON
// ** Значение — Произвольный — значение допустимого для сериализации типа
// ** ДополнительныеПараметры — Произвольный
// Возвращаемое значение:
// Произвольный — значение, десериализованное из JSON.
// ** МодульФункцииВосстановления — Произвольный — определяет модуль, процедура которого будет использована для
// восстановления значения.
// ** ДополнительныеПараметрыФункцииВосстановления — Произвольный — определяет дополнительные параметры, которые
// будут переданы в функцию восстановления значений.
// ** ИменаСвойствДляОбработкиВосстановления — Массив — определяет массив имен свойств JSON, для которых
// будет вызвана функция восстановления.
// ** МаксимальнаяВложенность — Число — определяет максимальный уровень вложенности объекта JSON.
// * ПараметрыЗаписиJSON — ПараметрыЗаписиJSON — используемые при записи объекта JSON.
// * Данные — Строка, ДвоичныеДанные — произвольные данные, которые необходимо отправить в запросе.
// — Структура, Соответствие — поля формы, которые необходимо отправить в запрос:
// ** Ключ — Строка — имя поля.
// ** Значение — Строка — значение поля.
// * Файлы — См. НовыйОтправляемыйФайл, Массив Из См. НовыйОтправляемыйФайл — файлы, к отправке
// * МаксимальноеКоличествоПовторов — Число — количество повторных попыток соединения/отправки запроса.
// Между попытками выполняется задержка, растущая по экспоненте.
// Но если код состояния один из 413, 429, 503
// и в ответе есть заголовок Retry-After,
// то время задержки формируется из значения этого заголовка
// Значение по умолчанию: 0 — повторы не выполняются.
// * МаксимальноеВремяПовторов — Число — максимальное общее время (в секундах) отправки запроса с учетом повторов.
// Значение по умолчанию: 600.
// * КоэффициентЭкспоненциальнойЗадержки — Число — коэффициент изменения экспоненциальной задержки.
// 1 формирует последовательность задержек: 1, 2, 4, 8 и т.д.
// 2 формируется последовательность задержек: 2, 4, 8, 16 и т.д.
// …
// Значение по умолчанию: 1.
// * ПовторятьДляКодовСостояний — Неопределено — повторы будут выполняться для кодов состояний >= 500.
// — Массив — повторы будут выполняться для конкретных кодов состояний.
// Значение по умолчанию: Неопределено.
//
Функция НовыеПараметры() Экспорт
Параметры = Новый Структура;
Параметры.Вставить("Заголовки", Новый Соответствие);
Параметры.Вставить("Аутентификация", Неопределено);
Параметры.Вставить("Прокси", Неопределено);
Параметры.Вставить("ПараметрыЗапроса", Неопределено);
Параметры.Вставить("ПроверятьSSL", Истина);
Параметры.Вставить("КлиентскийСертификатSSL", Неопределено);
Параметры.Вставить("Cookies", Новый Соответствие);
Параметры.Вставить("Таймаут", СтандартныйТаймаут());
Параметры.Вставить("РазрешитьПеренаправление", Истина);
Параметры.Вставить("Json", Неопределено);
Параметры.Вставить("ПараметрыПреобразованияJSON", ПараметрыПреобразованияJSONПоУмолчанию());
Параметры.Вставить("Данные", Неопределено);
Параметры.Вставить("Файлы", Новый Массив);
Параметры.Вставить("МаксимальноеКоличествоПовторов", 0);
Параметры.Вставить("МаксимальноеВремяПовторов", 600);
Параметры.Вставить("КоэффициентЭкспоненциальнойЗадержки", 1);
Параметры.Вставить("ПовторятьДляКодовСостояний", Неопределено);
Возврат Параметры;
КонецФункции
// Конструктор описания отправляемого файла.
//
// Параметры:
// Имя — Строка — имя поля формы.
// ИмяФайла — Строка — имя файла.
// Данные — ДвоичныеДанные — двоичные данные файла.
// Тип — Строка — MIME-тип файла
//
// Возвращаемое значение:
// Структура:
// * Имя — Строка — имя поля формы.
// * ИмяФайла — Строка — имя файла.
// * Данные — ДвоичныеДанные — двоичные данные файла.
// * Тип — Строка — MIME-тип файла.
// * Заголовки — Соответствие — HTTP заголовки запроса.
//
Функция НовыйОтправляемыйФайл(Имя, ИмяФайла, Данные = Неопределено, Тип = Неопределено) Экспорт
Файл = Новый Структура;
Файл.Вставить("Имя", Имя);
Файл.Вставить("ИмяФайла", ИмяФайла);
Файл.Вставить("Данные", ?(Данные = Неопределено, Base64Значение(""), Данные));
Файл.Вставить("Тип", Тип);
Файл.Вставить("Заголовки", Новый Соответствие);
Возврат Файл;
КонецФункции
// Создает объект для хранения параметров сессии.
//
// Возвращаемое значение:
// Структура — параметры сессии:
// * Заголовки — Соответствие — HTTP заголовки запроса.
// * Аутентификация — Структура — параметры аутентификации запроса.
// ** ИспользоватьАутентификациюОС — Булево — включает использование аутентификации NTLM или Negotiate.
// Значение по умолчанию: Ложь.
// ** Тип — Строка — тип аутентификации. Для Basic Тип можно не указывать.
// Если Тип = Digest или Basic:
// ** Пользователь — Строка — имя пользователя.
// ** Пароль — Строка — пароль пользователя.
// Если Тип = Bearer:
// ** Токен — Строка — токен.
// Если Тип = AWS4-HMAC-SHA256:
// ** ИдентификаторКлючаДоступа — Строка — идентификатор ключа доступа.
// ** СекретныйКлюч — Строка — секретный ключ.
// ** Сервис — Строка — сервис, к которому выполняется подключение.
// ** Регион — Строка — регион, к которому выполняется подключение.
// * Прокси — ИнтернетПрокси — параметры прокси, которые будут использованы при отправке запроса.
// Значение по умолчанию: Неопределено. При этом если в конфигурации используется БСП,
// то значения прокси будет взято из БСП.
// * ПараметрыЗапроса — Структура, Соответствие — параметры, которые будут отправлены в URL (часть после ?):
// * Ключ — Строка — ключ параметра в URL.
// * Значение — Строка — значение параметра URL
// — Массив — сформирует строку из нескольких параметров: key=value1&key=value2 и т.д.
// * ПроверятьSSL — Булево — Ложь — проверка сертификата сервера не выполняется.
// — Истина — используется значение СертификатыУдостоверяющихЦентровОС.
// — СертификатыУдостоверяющихЦентровФайл — См. СертификатыУдостоверяющихЦентровФайл.
// Значение по умолчанию: Истина.
// * КлиентскийСертификатSSL — СертификатКлиентаФайл, СертификатКлиентаWindows — Значение по умолчанию: Неопределено.
// * МаксимальноеКоличествоПеренаправлений — Число — максимальное количество редиректов. Защита от зацикливания.
// Значение по умолчанию: 30
// * Cookies — Соответствие — хранилище cookies.
//
Функция СоздатьСессию() Экспорт
Сессия = Новый Структура;
Сессия.Вставить("Заголовки", ЗаголовкиПоУмолчанию());
Сессия.Вставить("Аутентификация", Неопределено);
Сессия.Вставить("Прокси", Неопределено);
Сессия.Вставить("ПараметрыЗапроса", Новый Соответствие);
Сессия.Вставить("ПроверятьSSL", Истина);
Сессия.Вставить("КлиентскийСертификатSSL", Неопределено);
Сессия.Вставить("МаксимальноеКоличествоПеренаправлений", МаксимальноеКоличествоПеренаправлений());
Сессия.Вставить("Cookies", Новый Соответствие);
Сессия.Вставить("СлужебныеДанные", Новый Структура("ПараметрыDigest"));
Возврат Сессия;
КонецФункции
// Пакет ответа результата вызова метода HTTP.
//
// Возвращаемое значение:
// * Метод — Строка — имя HTTP-метода запроса
// * URL — Строка — итоговый URL, по которому был выполнен запрос.
// * КодСостояния — Число — Код состояния ответа..
// * Заголовки — Соответствие — Заголовки ответа.
// * Тело — ДвоичныеДанные — Тело ответа.
// * Кодировка — Строка — код кодировки ответа.
// * ВремяВыполнения — Число — время выполнения запроса в миллисекундах.
// * ЭтоПостоянныйРедирект — Булево — указывает что это постоянный редирект.
// * ЭтоРедирект — Булево — указывает что это редирект.
// * Cookies — Соответствие — хранилище cookies.
// * Ошибки — Массив Из Строка — Список ошибок возникших в ходе выполнения запроса.
//
Функция НовыйОтвет() Экспорт
Результат = Новый Структура;
Результат.Вставить("Метод", "GET");
Результат.Вставить("URL", "");
Результат.Вставить("КодСостояния", 600); // Сетевая ошибка (>500)
Результат.Вставить("Заголовки", Новый Соответствие);
Результат.Вставить("Тело", Base64Значение(""));
Результат.Вставить("Кодировка", "utf-8");
Результат.Вставить("ВремяВыполнения", Неопределено);
Результат.Вставить("ЭтоПостоянныйРедирект", Ложь);
Результат.Вставить("ЭтоРедирект", Ложь);
Результат.Вставить("Cookies", Новый Соответствие);
Результат.Вставить("Ошибки", Новый Массив);
Возврат Результат;
КонецФункции
// Конструктор аутентификации операционной системы
//
// Возвращаемое значение:
// Структура:
// * ИспользоватьАутентификациюОС — Строка — включает использование аутентификации NTLM или Negotiate.
//
Функция НоваяАутентификацияОС() Экспорт
Результат = Новый Структура;
Результат.Вставить("ИспользоватьАутентификациюОС", Истина);
Возврат Результат;
КонецФункции
// Конструктор аутентификации Basic
//
// Возвращаемое значение:
// Структура:
// * Пользователь — Строка — имя пользователя.
// * Пароль — Строка — пароль пользователя.
//
Функция НоваяАутентификацияBasic(Пользователь = «», Пароль = «») Экспорт
Результат = Новый Структура;
Результат.Вставить("Тип", "Basic");
Результат.Вставить("Пользователь", Пользователь);
Результат.Вставить("Пароль", Пароль);
Возврат Результат;
КонецФункции
// Конструктор аутентификации Digest
//
// Возвращаемое значение:
// Структура:
// * Тип — Строка — Код типа аутентификации. Всегда «Digest».
// * Пользователь — Строка — имя пользователя.
// * Пароль — Строка — пароль пользователя.
//
Функция НоваяАутентификацияDigest(Пользователь = «», Пароль = «») Экспорт
Результат = Новый Структура;
Результат.Вставить("Тип", "Digest");
Результат.Вставить("Пользователь", Пользователь);
Результат.Вставить("Пароль", Пароль);
Возврат Результат;
КонецФункции
// Конструктор аутентификации Bearer
//
// Возвращаемое значение:
// Структура:
// * Тип — Строка — Код типа аутентификации. Всегда «Bearer».
// * Токен — Строка — Bearer-токен.
//
Функция НоваяАутентификацияBearer(Токен = «») Экспорт
Результат = Новый Структура;
Результат.Вставить("Тип", "Bearer");
Результат.Вставить("Токен", Токен);
Возврат Результат;
КонецФункции
// Конструктор аутентификации AWS4-HMAC-SHA256
//
// Возвращаемое значение:
// Структура:
// * Тип — Строка — Код типа аутентификации. Всегда «AWS4-HMAC-SHA256».
// * ИдентификаторКлючаДоступа — Строка — идентификатор ключа доступа (AccessKey).
// * СекретныйКлюч — Строка — секретный ключ (SecretKey).
// * Сервис — Строка — сервис, к которому выполняется подключение.
// * Регион — Строка — регион, к которому выполняется подключение.
//
Функция НоваяАутентификацияAWS4(КлючДоступа = «», СекретныйКлюч = «», Сервис = «», Регион = «») Экспорт
Результат = Новый Структура;
Результат.Вставить("Тип", "AWS4-HMAC-SHA256");
Результат.Вставить("ИдентификаторКлючаДоступа", КлючДоступа);
Результат.Вставить("СекретныйКлюч", СекретныйКлюч);
Результат.Вставить("Сервис", Сервис);
Результат.Вставить("Регион", Регион);
Возврат Результат;
КонецФункции
КонецОбласти
КонецОбласти
Область ФорматыОтветов
// Возвращает ответ сервера в виде десериализованного значения JSON.
//
// Параметры:
// Ответ — См. НовыйОтвет
// ПараметрыПреобразованияJSON — Структура — задает параметры преобразования JSON.
// * ПрочитатьВСоответствие — Булево — Если Истина, чтение объекта JSON будет выполнено в Соответствие.
// Если Ложь, объекты будут считываться в объект типа Структура.
// * ФорматДатыJSON — ФорматДатыJSON — формат, в котором представлена дата в строке, подлежащей преобразованию.
// * ИменаСвойствСоЗначениямиДата — Массив, Строка — имена свойств JSON,
// для которых нужно вызывать восстановление даты из строки.
// * ИмяФункцииВосстановления — Строка — определяет имя функции, которая будет вызывается при чтении
// каждого свойства и должна иметь следующие параметры:
// ** Свойство — Строка — указывается только при чтении объектов JSON
// ** Значение — Произвольный — значение допустимого для сериализации типа
// ** ДополнительныеПараметры — Произвольный
// Возвращаемое значение:
// Произвольный — значение, десериализованное из JSON.
// * МодульФункцииВосстановления — Произвольный — определяет модуль, процедура которого будет использована для
// восстановления значения.
// * ДополнительныеПараметрыФункцииВосстановления — Произвольный — определяет дополнительные параметры, которые
// будут переданы в функцию восстановления значений.
// * ИменаСвойствДляОбработкиВосстановления — Массив — определяет массив имен свойств JSON, для которых
// будет вызвана функция восстановления.
// * МаксимальнаяВложенность — Число — определяет максимальный уровень вложенности объекта JSON.
//
// Возвращаемое значение:
// Соответствие — ответ сервера в виде десериализованного значения JSON.
// Если ПараметрыПреобразования.ПрочитатьВСоответствие = Истина (по умолчанию).
// Структура — если ПараметрыПреобразования.ПрочитатьВСоответствие = Ложь.
//
Функция КакJson(Ответ, ПараметрыПреобразованияJSON = Неопределено) Экспорт
Попытка
Возврат JsonВОбъект(РаспаковатьОтвет(Ответ), Ответ.Кодировка, ПараметрыПреобразованияJSON);
Исключение
ВызватьИсключение КакИсключение(Ответ, НСтр("ru = 'Ошибка при десериализации JSON.'"));
КонецПопытки;
КонецФункции
// Возвращает ответ сервера в виде текста.
//
// Параметры:
// Ответ — См. НовыйОтвет
// Кодировка — Строка, КодировкаТекста — определяет кодировку текста.
// Если значение не задано, то кодировка извлекается из Ответ.Кодировка.
//
// Возвращаемое значение:
// Строка — ответ сервера в виде текста.
//
Функция КакТекст(Ответ, Кодировка = Неопределено) Экспорт
Если Не ЗначениеЗаполнено(Кодировка) Тогда
Кодировка = Ответ.Кодировка;
КонецЕсли;
ЧтениеТекста = Новый ЧтениеТекста(РаспаковатьОтвет(Ответ).ОткрытьПотокДляЧтения(), Кодировка);
Текст = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
Если Текст = Неопределено Тогда
Текст = "";
КонецЕсли;
Возврат Текст;
КонецФункции
// Возвращает ответ сервера в двоичных данных.
//
// Параметры:
// Ответ — См. НовыйОтвет
//
// Возвращаемое значение:
// Строка — ответ сервера в виде двоичных данных.
//
Функция КакДвоичныеДанные(Ответ) Экспорт
Возврат РаспаковатьОтвет(Ответ);
КонецФункции
// Возвращает ответ сервера в XDTO.
//
// Параметры:
// Ответ — См. НовыйОтвет
// ПараметрыЧтенияXML — ПараметрыЧтенияXML — Параметры чтения, которые будут использованы при чтении данных XML
// Подробнее см. в синтакс помощнике метод ЧтениеXML.ОткрытьПоток
// НаборСхемXML — НаборСхемXML — Набор схем XML, используемых при проверке читаемого документа XML.
// Если набор схем указан, но не проверен и включена проверка документа XML,
// то будет выполнена проверка набора схем
// Подробнее см. в синтакс помощнике метод ЧтениеXML.ОткрытьПоток
// Кодировка — Строка, КодировкаТекста — Позволяет задать кодировку.
// Подробнее см. в синтакс помощнике метод ЧтениеXML.ОткрытьПоток
//
// Возвращаемое значение:
// ОбъектXDTO, СписокXDTO — тип возвращаемого значения может быть любым из поддерживаемых сериализацию в XDTO.
//
Функция КакXDTO(Ответ,
ПараметрыЧтенияXML = Неопределено,
НаборСхемXML = Неопределено,
Кодировка = Неопределено) Экспорт
Попытка
ДвоичныеДанные = РаспаковатьОтвет(Ответ);
ПотокДляЧтения = ДвоичныеДанные.ОткрытьПотокДляЧтения();
Если Не ЗначениеЗаполнено(Кодировка) Тогда
Кодировка = Ответ.Кодировка;
КонецЕсли;
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьПоток(ПотокДляЧтения, ПараметрыЧтенияXML, НаборСхемXML, Кодировка);
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
Исключение
ВызватьИсключение КакИсключение(Ответ, НСтр("ru = 'Ошибка при десериализации XDTO.'"));
КонецПопытки;
Возврат ОбъектXDTO;
КонецФункции
// Возвращает ответ сервера в виде текста предназначенного для использования в ВызватьИсключение.
//
// Параметры:
// Ответ — См. НовыйОтвет.
// ТекстДляПользователя — Строка — Текст пояснения причины для пользователя.
//
// Возвращаемое значение:
// Строка — ответ сервера в виде текста исключения.
//
Функция КакИсключение(Ответ, Знач ТекстДляПользователя = Неопределено) Экспорт
ТекстИсключения = СтрШаблон(
НСтр("ru = 'HTTP %1 %2
|%3'"),
Ответ.Метод,
Ответ.URL,
ПредставлениеКодаСостоянияHTTP(Ответ.КодСостояния)
);
ТелоОтвета = ВырезатьТекст(КакТекст(Ответ));
Если Не ПустаяСтрока(ТелоОтвета) Тогда
ТекстИсключения = ТекстИсключения + Символы.ПС + СтрШаблон(
НСтр("ru = 'Тело ответа:
|%1'"),
ТелоОтвета);
КонецЕсли;
Если Ответ.Ошибки.Количество() Тогда
ТекстИсключения = ТекстИсключения + Символы.ПС + Символы.ПС
+ СтрСоединить(Ответ.Ошибки, Символы.ПС + Символы.ПС);
КонецЕсли;
Если Не ПустаяСтрока(ТекстДляПользователя) Тогда
ТекстИсключения = ТекстДляПользователя + Символы.ПС + Символы.ПС + ТекстИсключения;
КонецЕсли;
Возврат ТекстИсключения;
КонецФункции
КонецОбласти
Область ВспомогательныеФункции
// Возвращает структурированное представление URL.
//
// Параметры:
// URL — Строка — URL ресурса, к которому будет отправлен запрос.
//
// Возвращаемое значение:
// Структура — структура URL:
// * Схема — Строка — схема обращения к серверу (http, https).
// * Аутентификация — Структура — параметры аутентификации:
// ** Пользователь — Строка — имя пользователя.
// ** Пароль — Строка — пароль пользователя.
// * Сервер — Строка — адрес сервера.
// * Порт — Число — порт сервера.
// * Путь — Строка — адрес ресурса на сервере.
// * ПараметрыЗапроса — Соответствие — параметры запроса передаваемые на сервер в URL (часть после ?):
// ** Ключ — Строка — ключ параметра в URL.
// ** Значение — Строка — значение параметра URL;
// — Массив — значения параметра (key=value1&key=value2).
// * Фрагмент — Строка — часть URL после #.
//
Функция РазобратьURL(Знач URL) Экспорт
Схема = "";
Путь = "";
Аутентификация = Новый Структура("Пользователь, Пароль", "", "");
Сервер = "";
Порт = "";
Фрагмент = "";
ДопустимыеСхемы = СтрРазделить("http,https", ",");
URLБезСхемы = URL;
РазбитьСтрокуПоРазделителю(Схема, URLБезСхемы, "://");
Если ДопустимыеСхемы.Найти(НРег(Схема)) <> Неопределено Тогда
URL = URLБезСхемы;
Иначе
Схема = "";
КонецЕсли;
Результат = РазделитьПоПервомуНайденномуРазделителю(URL, СтрРазделить("/,?,#", ","));
URL = Результат[0];
Если ЗначениеЗаполнено(Результат[2]) Тогда
Путь = Результат[2] + Результат[1];
КонецЕсли;
АутентификацияСтрока = "";
РазбитьСтрокуПоРазделителю(АутентификацияСтрока, URL, "@");
Если ЗначениеЗаполнено(АутентификацияСтрока) Тогда
АутентификацияЧасти = СтрРазделить(АутентификацияСтрока, ":");
Аутентификация.Пользователь = АутентификацияЧасти[0];
Если АутентификацияЧасти.Количество() > 1 Тогда
Аутентификация.Пароль = АутентификацияЧасти[1];
КонецЕсли;
КонецЕсли;
// IPv6
РазбитьСтрокуПоРазделителю(Сервер, URL, "]");
Если ЗначениеЗаполнено(Сервер) Тогда
Сервер = Сервер + "]";
КонецЕсли;
URL = СтрЗаменить(URL, "/", "");
РазбитьСтрокуПоРазделителю(Порт, URL, ":", Истина);
Если Не ЗначениеЗаполнено(Сервер) Тогда
Сервер = URL;
КонецЕсли;
Если ЗначениеЗаполнено(Порт) Тогда
Порт = Число(Порт);
Иначе
Порт = 0;
КонецЕсли;
РазбитьСтрокуПоРазделителю(Фрагмент, Путь, "#", Истина);
ПараметрыЗапроса = ЗаполнитьПараметрыЗапроса(Путь);
Если Не ЗначениеЗаполнено(Схема) Тогда
Схема = "http";
КонецЕсли;
Если Не ЗначениеЗаполнено(Путь) Тогда
Путь = "/";
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("Схема", Схема);
Результат.Вставить("Аутентификация", Аутентификация);
Результат.Вставить("Сервер", Сервер);
Результат.Вставить("Порт", Порт);
Результат.Вставить("Путь", Путь);
Результат.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
Результат.Вставить("Фрагмент", Фрагмент);
Возврат Результат;
КонецФункции
// Преобразование Объекта в JSON.
//
// Параметры:
// Объект — Произвольный — данные, которые необходимо преобразовать в JSON.
// ПараметрыПреобразования — Структура — кодировка текста JSON. Значение по умолчанию — utf-8.
// * ФорматДатыJSON — ФорматДатыJSON — определяет формат сериализации дат JSON-объектов.
// * ВариантЗаписиДатыJSON — ВариантЗаписиДатыJSON — определяет вариант записи даты в формате JSON.
// * ИмяФункцииПреобразования — Строка — функция, которая вызывается для всех свойств,
// тип которых не поддерживает автоматическую сериализацию в JSON.
// Функция должна быть экспортируемая и иметь следующие параметры:
// ** Свойство — Строка — свойство структуры данных, которое не может быть
// автоматически сериализовано в JSON.
// ** Значение — Строка — значение свойства структуры данных, которое
// не может быть автоматически сериализовано в JSON.
// ** ДополнительныеПараметры — Произвольный — в этом параметре будет передан
// ДополнительныеПараметрыФункцииПреобразования.
// ** Отказ — Булево — отменяет операцию записи свойства.
// Возвращаемое значение функции:
// Произвольный — результат преобразования.
// * МодульФункцииПреобразования — Произвольный — модуль, в котором определена функция ИмяФункцииПреобразования.
// * ДополнительныеПараметрыФункцииПреобразования — Произвольный — параметры, которые будут переданы
// в функцию ИмяФункцииПреобразования.
// ПараметрыЗаписи — Структура — параметры преобразования JSON:
// * ПереносСтрок — ПереносСтрокJSON — определяет способ переноса строк,
// который будет использован при записи данных JSON.
// * СимволыОтступа — Строка — определяет символы отступа, используемые при записи данных JSON.
// * ИспользоватьДвойныеКавычки — Булево — определяет, будут ли при записи имена свойств JSON
// записываться в двойных кавычках.
// * ЭкранированиеСимволов — ЭкранированиеСимволовJSON — определяет используемый способ экранирования (замены)
// символов при записи данных JSON.
// * ЭкранироватьУгловыеСкобки — Булево — определяет, будут ли при записи экранироваться символы «<» и «>».
// * ЭкранироватьРазделителиСтрок — Булево — определяет, будут ли экранироваться разделители строк
// U+2028 (line-separator) и U+2029 (page-separator).
// * ЭкранироватьАмперсанд — Булево — определяет, будет ли при записи экранироваться символ амперсанда «&».
// * ЭкранироватьОдинарныеКавычки — Булево — определяет, будут ли экранироваться одинарные кавычки.
// * ЭкранироватьСлеш — Булево — определяет, будет ли экранироваться слеш (косая черта) при записи значения.
//
// Возвращаемое значение:
// Строка — объект в формате JSON.
//
Функция ОбъектВJson(Объект, Знач ПараметрыПреобразования = Неопределено, Знач ПараметрыЗаписи = Неопределено) Экспорт
ПараметрыПреобразованияJSON = Объединить(ПараметрыПреобразованияJSONПоУмолчанию(), ПараметрыПреобразования);
НастройкиСериализации = Новый НастройкиСериализацииJSON;
НастройкиСериализации.ФорматСериализацииДаты = ПараметрыПреобразованияJSON.ФорматДатыJSON;
НастройкиСериализации.ВариантЗаписиДаты = ПараметрыПреобразованияJSON.ВариантЗаписиДатыJSON;
ПараметрыЗаписи = Объединить(ПараметрыЗаписиJSONПоУмолчанию(), ПараметрыЗаписи);
ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(
ПараметрыЗаписи.ПереносСтрок,
ПараметрыЗаписи.СимволыОтступа,
ПараметрыЗаписи.ИспользоватьДвойныеКавычки,
ПараметрыЗаписи.ЭкранированиеСимволов,
ПараметрыЗаписи.ЭкранироватьУгловыеСкобки,
ПараметрыЗаписи.ЭкранироватьРазделителиСтрок,
ПараметрыЗаписи.ЭкранироватьАмперсанд,
ПараметрыЗаписи.ЭкранироватьОдинарныеКавычки,
ПараметрыЗаписи.ЭкранироватьСлеш);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписиJSON);
Если ПараметрыПреобразованияJSON.ИмяФункцииПреобразования <> Неопределено
И ПараметрыПреобразованияJSON.МодульФункцииПреобразования <> Неопределено Тогда
ЗаписатьJSON(ЗаписьJSON, Объект, НастройкиСериализации,
ПараметрыПреобразованияJSON.ИмяФункцииПреобразования,
ПараметрыПреобразованияJSON.МодульФункцииПреобразования,
ПараметрыПреобразованияJSON.ДополнительныеПараметрыФункцииПреобразования);
Иначе
ЗаписатьJSON(ЗаписьJSON, Объект, НастройкиСериализации);
КонецЕсли;
Возврат ЗаписьJSON.Закрыть();
КонецФункции
// Преобразование JSON в Объект.
//
// Параметры:
// Json — Поток, ДвоичныеДанные, Строка — данные в формате JSON.
// Кодировка — Строка — кодировка текста JSON. Значение по умолчанию — utf-8.
// ПараметрыПреобразования — Структура — параметры преобразования JSON:
// * ПрочитатьВСоответствие — Булево — если Истина, чтение объекта JSON будет выполнено в Соответствие,
// иначе в Структура.
// * ИменаСвойствСоЗначениямиДата — Массив, Строка, ФиксированныйМассив — имена свойств JSON,
// для которых нужно вызывать восстановление даты из строки.
// * ФорматДатыJSON — ФорматДатыJSON — определяет формат десериализации дат JSON-объектов.
// * ИмяФункцииВосстановления — Строка — определяет имя функции, которая будет вызывается при чтении
// каждого свойства и должна иметь следующие параметры:
// ** Свойство — Строка — указывается только при чтении объектов JSON
// ** Значение — Произвольный — значение допустимого для сериализации типа
// ** ДополнительныеПараметры — Произвольный
// Возвращаемое значение:
// Произвольный — значение, десериализованное из JSON.
// * МодульФункцииВосстановления — Произвольный — определяет модуль, процедура которого будет использована для
// восстановления значения.
// * ДополнительныеПараметрыФункцииВосстановления — Произвольный — определяет дополнительные параметры, которые
// будут переданы в функцию восстановления значений.
// * ИменаСвойствДляОбработкиВосстановления — Массив — определяет массив имен свойств JSON, для которых
// будет вызвана функция восстановления.
// * МаксимальнаяВложенность — Число — определяет максимальный уровень вложенности объекта JSON.
//
// Возвращаемое значение:
// Произвольный — значение, десериализованное из JSON.
//
Функция JsonВОбъект(Json, Кодировка = «utf-8», ПараметрыПреобразования = Неопределено) Экспорт
ПараметрыПреобразованияJSON = Объединить(ПараметрыПреобразованияJSONПоУмолчанию(), ПараметрыПреобразования);
ЧтениеJSON = Новый ЧтениеJSON;
Если ТипЗнч(Json) = Тип("ДвоичныеДанные") Тогда
ЧтениеJSON.ОткрытьПоток(Json.ОткрытьПотокДляЧтения(), Кодировка);
ИначеЕсли ТипЗнч(Json) = Тип("Строка") Тогда
ЧтениеJSON.УстановитьСтроку(Json);
Иначе
ЧтениеJSON.ОткрытьПоток(Json, Кодировка);
КонецЕсли;
Объект = ПрочитатьJSON(
ЧтениеJSON,
ПараметрыПреобразованияJSON.ПрочитатьВСоответствие,
ПараметрыПреобразованияJSON.ИменаСвойствСоЗначениямиДата,
ПараметрыПреобразованияJSON.ФорматДатыJSON,
ПараметрыПреобразованияJSON.ИмяФункцииВосстановления,
ПараметрыПреобразованияJSON.МодульФункцииВосстановления,
ПараметрыПреобразованияJSON.ДополнительныеПараметрыФункцииВосстановления,
ПараметрыПреобразованияJSON.ИменаСвойствДляОбработкиВосстановления,
ПараметрыПреобразованияJSON.МаксимальнаяВложенность);
ЧтениеJSON.Закрыть();
Возврат Объект;
КонецФункции
// Вычисляет HMAC (hash-based message authentication code).
//
// Параметры:
// Ключ — ДвоичныеДанные — секретный ключ.
// Данные — ДвоичныеДанные — данные, для которых нужно посчитать HMAC.
// Алгоритм — ХешФункция — алгоритм, используемый для вычисления хеша.
//
// Возвращаемое значение:
// ДвоичныеДанные — вычисленное значение HMAC.
//
Функция HMAC(Ключ, Данные, Алгоритм) Экспорт
ДлинаБлока = 64;
Если Ключ.Размер() > ДлинаБлока Тогда
Хеширование = Новый ХешированиеДанных(Алгоритм);
Хеширование.Добавить(Ключ);
КлючБуфер = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Хеширование.ХешСумма);
Иначе
КлючБуфер = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Ключ);
КонецЕсли;
ИзмененныйКлюч = Новый БуферДвоичныхДанных(ДлинаБлока);
ИзмененныйКлюч.Записать(0, КлючБуфер);
ВнутреннийКлюч = ИзмененныйКлюч.Скопировать();
ВнешнийКлюч = ИзмененныйКлюч;
ВнутреннееВыравнивание = Новый БуферДвоичныхДанных(ДлинаБлока);
ВнешнееВыравнивание = Новый БуферДвоичныхДанных(ДлинаБлока);
Для Индекс = 0 По ДлинаБлока - 1 Цикл
ВнутреннееВыравнивание.Установить(Индекс, 54);
ВнешнееВыравнивание.Установить(Индекс, 92);
КонецЦикла;
ВнутреннееХеширование = Новый ХешированиеДанных(Алгоритм);
ВнешнееХеширование = Новый ХешированиеДанных(Алгоритм);
ВнутреннийКлюч.ЗаписатьПобитовоеИсключительноеИли(0, ВнутреннееВыравнивание);
ВнешнийКлюч.ЗаписатьПобитовоеИсключительноеИли(0, ВнешнееВыравнивание);
ВнешнееХеширование.Добавить(ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ВнешнийКлюч));
ВнутреннееХеширование.Добавить(ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ВнутреннийКлюч));
Если ЗначениеЗаполнено(Данные) Тогда
ВнутреннееХеширование.Добавить(Данные);
КонецЕсли;
ВнешнееХеширование.Добавить(ВнутреннееХеширование.ХешСумма);
Возврат ВнешнееХеширование.ХешСумма;
КонецФункции
// Возвращает структуру именованных кодов состояний HTTP.
//
// Возвращаемое значение:
// Структура — именованные коды состояний HTTP.
//
Функция КодыСостоянияHTTP() Экспорт
КодыСостояния = Новый Структура;
Для Каждого Описание Из ОписанияКодовСостоянийHTTP() Цикл
КодыСостояния.Вставить(Описание.Ключ, Описание.Код);
КонецЦикла;
Возврат КодыСостояния;
КонецФункции
// Возвращает текстовое представление переданного кода состояния HTTP.
//
// Параметры:
// КодСостояния — Число — код состояния HTTP, для которого нужно получить текстовое представление.
//
// Возвращаемое значение:
// Строка — текстовое представление кода состояния HTTP.
//
Функция ПредставлениеКодаСостоянияHTTP(КодСостояния) Экспорт
ОписаниеКодаСостояния = Неопределено;
Для Каждого Описание Из ОписанияКодовСостоянийHTTP() Цикл
Если Описание.Код = КодСостояния Тогда
ОписаниеКодаСостояния = Описание;
Прервать;
КонецЕсли;
КонецЦикла;
Если ОписаниеКодаСостояния = Неопределено Тогда
Возврат СтрШаблон(НСтр("ru = '%1: Неизвестный код состояния HTTP'"), КодСостояния);
Иначе
Возврат СтрШаблон("%1: %2", ОписаниеКодаСостояния.Код, ОписаниеКодаСостояния.Описание);
КонецЕсли;
КонецФункции
// Выполняет чтение данных из архива GZip.
//
// Параметры:
// СжатыеДанные — ДвоичныеДанные — данные упакованные GZip.
//
// Возвращаемое значение:
// ДвоичныеДанные — распакованные данные.
//
Функция ПрочитатьGZip(СжатыеДанные) Экспорт
РазмерПрефиксаGZip = 10;
РазмерПостфиксаGZip = 8;
ЧтениеДанных = Новый ЧтениеДанных(СжатыеДанные);
ЧтениеДанных.Пропустить(РазмерПрефиксаGZip);
РазмерСжатыхДанных = ЧтениеДанных.ИсходныйПоток().Размер() - РазмерПрефиксаGZip - РазмерПостфиксаGZip;
ПотокZip = Новый ПотокВПамяти(ZipРазмерLFH() + РазмерСжатыхДанных + ZipРазмерDD() + ZipРазмерCDH() + ZipРазмерEOCD());
ЗаписьДанных = Новый ЗаписьДанных(ПотокZip);
ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipLFH());
ЧтениеДанных.КопироватьВ(ЗаписьДанных, РазмерСжатыхДанных);
ЗаписьДанных.Закрыть();
ЗаписьДанных = Новый ЗаписьДанных(ПотокZip);
CRC32 = ЧтениеДанных.ПрочитатьЦелое32();
РазмерНесжатыхДанных = ЧтениеДанных.ПрочитатьЦелое32();
ЧтениеДанных.Закрыть();
ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipDD(CRC32, РазмерСжатыхДанных, РазмерНесжатыхДанных));
ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipCDH(CRC32, РазмерСжатыхДанных, РазмерНесжатыхДанных));
ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipEOCD(РазмерСжатыхДанных));
ЗаписьДанных.Закрыть();
Возврат ПрочитатьZip(ПотокZip);
КонецФункции
// Выполняет запись данных в архив GZip.
//
// Параметры:
// Данные — ДвоичныеДанные — исходные данные.
//
// Возвращаемое значение:
// ДвоичныеДанные — данные упакованные GZip.
//
Функция ЗаписатьGZip(Данные) Экспорт
ЧтениеДанных = Новый ЧтениеДанных(ЗаписатьZip(Данные));
НачальноеСмещение = 14;
ЧтениеДанных.Пропустить(НачальноеСмещение);
CRC32 = ЧтениеДанных.ПрочитатьЦелое32();
РазмерСжатыхДанных = ЧтениеДанных.ПрочитатьЦелое32();
РазмерИсходныхДанных = ЧтениеДанных.ПрочитатьЦелое32();
РазмерИмениФайла = ЧтениеДанных.ПрочитатьЦелое16();
РазмерДополнительногоПоля = ЧтениеДанных.ПрочитатьЦелое16();
ЧтениеДанных.Пропустить(РазмерИмениФайла + РазмерДополнительногоПоля);
ПотокGZip = Новый ПотокВПамяти;
ЗаписьДанных = Новый ЗаписьДанных(ПотокGZip);
ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(GZipHeader());
ЧтениеДанных.КопироватьВ(ЗаписьДанных, РазмерСжатыхДанных);
ЗаписьДанных.Закрыть();
ЗаписьДанных = Новый ЗаписьДанных(ПотокGZip);
ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(GZipFooter(CRC32, РазмерИсходныхДанных));
Возврат ПотокGZip.ЗакрытьИПолучитьДвоичныеДанные();
КонецФункции
КонецОбласти
КонецОбласти
Область СлужебныйПрограммныйИнтерфейс
Функция ПодготовитьЗапрос(Сессия, Метод, URL, ДополнительныеПараметры) Экспорт
Cookies = ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "Cookies", Новый Массив);
Cookies = ОбъединитьCookies(ДозаполнитьCookie(Сессия.Cookies, URL), ДозаполнитьCookie(Cookies, URL));
АутентификацияИзДополнительныхПараметров =
ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "Аутентификация", Новый Структура);
ПараметрыЗапросаИзДополнительныхПараметров =
ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "ПараметрыЗапроса", Новый Соответствие);
ЗаголовкиИзДополнительныхПараметров =
ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "Заголовки", Новый Соответствие);
Аутентификация = Объединить(Скопировать(АутентификацияИзДополнительныхПараметров), Сессия.Аутентификация);
ПараметрыЗапроса = Объединить(Скопировать(ПараметрыЗапросаИзДополнительныхПараметров), Сессия.ПараметрыЗапроса);
Заголовки = Объединить(Скопировать(ЗаголовкиИзДополнительныхПараметров), Сессия.Заголовки);
ПараметрыПреобразованияJSON =
ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "ПараметрыПреобразованияJSON", Неопределено);
ПодготовленныйЗапрос = Новый Структура;
ПодготовленныйЗапрос.Вставить("Cookies", Cookies);
ПодготовленныйЗапрос.Вставить("Аутентификация", Аутентификация);
ПодготовленныйЗапрос.Вставить("Метод", Метод);
ПодготовленныйЗапрос.Вставить("Заголовки", Заголовки);
ПодготовленныйЗапрос.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
ПодготовленныйЗапрос.Вставить("URL", ПодготовитьURL(URL, ПараметрыЗапроса));
ПодготовленныйЗапрос.Вставить("ПараметрыПреобразованияJSON", ПараметрыПреобразованияJSON);
ПодготовитьCookies(ПодготовленныйЗапрос);
Данные = ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "Данные", Новый Структура);
Файлы = ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "Файлы", Новый Массив);
Json = ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "Json", Неопределено);
ПараметрыЗаписиJSON = ВыбратьЗначение(Неопределено, ДополнительныеПараметры, "ПараметрыЗаписиJSON", Неопределено);
ПодготовитьТелоЗапроса(ПодготовленныйЗапрос, Данные, Файлы, Json, ПараметрыЗаписиJSON);
ПодготовитьАутентификацию(ПодготовленныйЗапрос);
Возврат ПодготовленныйЗапрос;
КонецФункции
КонецОбласти
Область СлужебныеПроцедурыИФункции
Область РаботаСHTTPЗапросами
Функция ПараметрыИзАргументов(ПараметрыЗапроса, Данные, Json)
Результат = Новый Структура;
Результат.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
Результат.Вставить("Данные", Данные);
Результат.Вставить("Json", Json);
Возврат Результат;
КонецФункции
Функция ВызватьHTTPМетод(Сессия, Метод, URL, ДополнительныеПараметры)
ПодготовленныйЗапрос = ПодготовитьЗапрос(Сессия, Метод, URL, ДополнительныеПараметры);
НастройкиПодключения = НастройкиПодключения(Метод, URL, ДополнительныеПараметры);
Ответ = ОтправитьЗапрос(Сессия, ПодготовленныйЗапрос, НастройкиПодключения);
Если НастройкиПодключения.РазрешитьПеренаправление И Ответ.ЭтоРедирект Тогда
// INFO: по хорошему аутентификацию нужно привести к новых параметрам, но пока будем игнорировать.
Ответ = ПеренаправитьЗапрос(Сессия, НастройкиПодключения, ПодготовленныйЗапрос, Ответ);
КонецЕсли;
Возврат Ответ;
КонецФункции
Функция ПеренаправитьЗапрос(Сессия, НастройкиПодключения, ПодготовленныйЗапрос, ПеренаправленныйОтвет)
Перенаправление = 0;
Пока ПеренаправленныйОтвет.ЭтоРедирект Цикл
ПодготовитьЗапросДляРедиректа(Сессия, ПодготовленныйЗапрос, ПеренаправленныйОтвет);
ПеренаправленныйОтвет = ОтправитьЗапрос(Сессия, ПодготовленныйЗапрос, НастройкиПодключения);
Перенаправление = Перенаправление + 1;
Если Перенаправление > Сессия.МаксимальноеКоличествоПеренаправлений Тогда
ВызватьИсключение("СлишкомМногоПеренаправлений");
КонецЕсли;
КонецЦикла;
Возврат ПеренаправленныйОтвет;
КонецФункции
Процедура ПодготовитьЗапросДляРедиректа(Сессия, ПодготовленныйЗапрос, ПеренаправленныйОтвет)
КодыСостоянияHTTP = КодыСостоянияHTTP();
НовыйURL = СформироватьНовыйURLПриПеренаправлении(ПеренаправленныйОтвет);
ПодготовленныйЗапрос.URL = КодироватьСтроку(НовыйURL, СпособКодированияСтроки.URLВКодировкеURL);
НовыйHTTPЗапрос = Новый HTTPЗапрос(СобратьАдресРесурса(РазобратьURL(НовыйURL), Новый Соответствие));
ПереопределитьМетод(ПодготовленныйЗапрос, ПеренаправленныйОтвет);
Если ПеренаправленныйОтвет.КодСостояния <> КодыСостоянияHTTP.ВременноеПеренаправление_307
И ПеренаправленныйОтвет.КодСостояния <> КодыСостоянияHTTP.ПостоянноеПеренаправление_308 Тогда
УдалитьЗаголовки(ПодготовленныйЗапрос.Заголовки, "content-length,content-type,transfer-encoding");
НовыйHTTPЗапрос.Заголовки = ПодготовленныйЗапрос.Заголовки;
Иначе
ИсходныйПоток = ПодготовленныйЗапрос.HTTPЗапрос.ПолучитьТелоКакПоток();
ИсходныйПоток.КопироватьВ(НовыйHTTPЗапрос.ПолучитьТелоКакПоток());
КонецЕсли;
ПодготовленныйЗапрос.HTTPЗапрос = НовыйHTTPЗапрос;
УдалитьЗаголовки(ПодготовленныйЗапрос.Заголовки, "cookies");
ПодготовленныйЗапрос.Cookies = ОбъединитьCookies(ПодготовленныйЗапрос.Cookies, Сессия.Cookies);
ПодготовитьCookies(ПодготовленныйЗапрос);
КонецПроцедуры
Процедура ПодготовитьАутентификацию(ПодготовленныйЗапрос)
ПодготовленныйЗапрос.Вставить("СобытияНаОтвет", Новый Массив);
Если Не ЗначениеЗаполнено(ПодготовленныйЗапрос.Аутентификация) Тогда
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL);
Если ЗначениеЗаполнено(СтруктураURL.Аутентификация) Тогда
ПодготовленныйЗапрос.Аутентификация = СтруктураURL.Аутентификация;
КонецЕсли;
КонецЕсли;
Если ЗначениеЗаполнено(ПодготовленныйЗапрос.Аутентификация) Тогда
Если ПодготовленныйЗапрос.Аутентификация.Свойство("Тип") Тогда
ТипАутентификации = НРег(ПодготовленныйЗапрос.Аутентификация.Тип);
Если ТипАутентификации = "digest" Тогда
ПодготовленныйЗапрос.СобытияНаОтвет.Добавить("ОбработкаОтветаСКодом401");
КонецЕсли;
Если ТипАутентификации = "aws4-hmac-sha256" Тогда
ПодготовитьАутентификациюAWS4(ПодготовленныйЗапрос);
КонецЕсли;
Если ТипАутентификации = "bearer" Тогда
ПодготовитьАутентификациюBearer(ПодготовленныйЗапрос);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ПодготовитьТелоЗапроса(ПодготовленныйЗапрос, Данные, Файлы, Json, ПараметрыЗаписиJSON)
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL);
HTTPЗапрос = Новый HTTPЗапрос;
HTTPЗапрос.АдресРесурса = СобратьАдресРесурса(СтруктураURL, ПодготовленныйЗапрос.ПараметрыЗапроса);
Если ЗначениеЗаполнено(Файлы) Тогда
ContentType = ЗакодироватьФайлы(HTTPЗапрос, Файлы, Данные);
ИначеЕсли ЗначениеЗаполнено(Данные) Тогда
ContentType = "application/x-www-form-urlencoded";
Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(Данные);
Иначе
Если ТипЗнч(Данные) = Тип("Строка") Тогда
Тело = Данные;
Иначе
Тело = КодироватьПараметрыЗапроса(Данные);
КонецЕсли;
ContentType = "application/x-www-form-urlencoded; charset=utf-8";
HTTPЗапрос.УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
КонецЕсли;
ИначеЕсли Json <> Неопределено Тогда
ContentType = "application/json; charset=utf-8";
СтрокаJson = ОбъектВJson(Json, ПодготовленныйЗапрос.ПараметрыПреобразованияJSON, ПараметрыЗаписиJSON);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJson, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Иначе
ContentType = Неопределено;
КонецЕсли;
ЗначениеЗаголовка = ЗначениеЗаголовка("content-type", ПодготовленныйЗапрос.Заголовки);
Если ЗначениеЗаголовка = Ложь И ЗначениеЗаполнено(ContentType) Тогда
ПодготовленныйЗапрос.Заголовки.Вставить("Content-Type", ContentType);
КонецЕсли;
HTTPЗапрос.Заголовки = ПодготовленныйЗапрос.Заголовки;
УпаковатьЗапрос(HTTPЗапрос);
ПодготовленныйЗапрос.Вставить("HTTPЗапрос", HTTPЗапрос);
КонецПроцедуры
Функция ЗакодироватьФайлы(HTTPЗапрос, Файлы, Данные)
Части = Новый Массив;
Если ЗначениеЗаполнено(Данные) Тогда
Для Каждого Поле Из Данные Цикл
Части.Добавить(СоздатьПолеФормы(Новый Структура("Имя,Данные", Поле.Ключ, Поле.Значение)));
КонецЦикла;
КонецЕсли;
Если ТипЗнч(Файлы) = Тип("Массив") Тогда
Для Каждого Файл Из Файлы Цикл
Части.Добавить(СоздатьПолеФормы(Файл));
КонецЦикла;
Иначе
Части.Добавить(СоздатьПолеФормы(Файлы));
КонецЕсли;
Разделитель = СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
РазделительСтрок = Символы.ВК + Символы.ПС;
ТелоЗапроса = HTTPЗапрос.ПолучитьТелоКакПоток();
ЗаписьДанных = Новый ЗаписьДанных(ТелоЗапроса, КодировкаТекста.UTF8, ПорядокБайтов.LittleEndian, "", "", Ложь);
Для Каждого Часть Из Части Цикл
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + РазделительСтрок);
ЗаписьДанных.ЗаписатьСтроку(ЗаголовкиВСтроку(Часть.Заголовки));
Если ТипЗнч(Часть.Данные) = Тип("ДвоичныеДанные") Тогда
ЗаписьДанных.Записать(Часть.Данные);
Иначе
ЗаписьДанных.ЗаписатьСтроку(Часть.Данные);
КонецЕсли;
ЗаписьДанных.ЗаписатьСтроку(РазделительСтрок);
КонецЦикла;
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--" + РазделительСтрок);
ЗаписьДанных.Закрыть();
Возврат СтрШаблон("multipart/form-data; boundary=%1", Разделитель);
КонецФункции
Функция СоздатьПолеФормы(ИсходныеПараметры)
Поле = Новый Структура("Имя,ИмяФайла,Данные,Тип,Заголовки");
Поле.Имя = ИсходныеПараметры.Имя;
Поле.Данные = ИсходныеПараметры.Данные;
Поле.Тип = ЗначениеПоКлючу(ИсходныеПараметры, "Тип");
Поле.Заголовки = ЗначениеПоКлючу(ИсходныеПараметры, "Заголовки", Новый Соответствие);
Поле.ИмяФайла = ЗначениеПоКлючу(ИсходныеПараметры, "ИмяФайла");
Ключ = "Content-Disposition";
Если ЗначениеЗаголовка("content-disposition", Поле.Заголовки, Ключ) = Ложь Тогда
Поле.Заголовки.Вставить("Content-Disposition", "form-data");
КонецЕсли;
Части = Новый Массив;
Части.Добавить(Поле.Заголовки[Ключ]);
Части.Добавить(СтрШаблон("name=""%1""", Поле.Имя));
Если ЗначениеЗаполнено(Поле.ИмяФайла) Тогда
Части.Добавить(СтрШаблон("filename=""%1""", Поле.ИмяФайла));
КонецЕсли;
Поле.Заголовки[Ключ] = СтрСоединить(Части, "; ");
Поле.Заголовки["Content-Type"] = Поле.Тип;
Возврат Поле;
КонецФункции
Функция ЗаполнитьПараметрыЗапроса(Путь)
ПараметрыЗапроса = Новый Соответствие;
Запрос = "";
РазбитьСтрокуПоРазделителю(Запрос, Путь, "?", Истина);
Для Каждого СтрокаКлючРавноПараметр Из СтрРазделить(Запрос, "&", Ложь) Цикл
СтрокаКлючРавноПараметр = РаскодироватьСтроку(
СтрокаКлючРавноПараметр, СпособКодированияСтроки.URLВКодировкеURL);
ПозицияРавно = СтрНайти(СтрокаКлючРавноПараметр, "=");
Если ПозицияРавно = 0 Тогда
Ключ = СтрокаКлючРавноПараметр;
Значение = Неопределено;
Иначе
Ключ = Лев(СтрокаКлючРавноПараметр, ПозицияРавно - 1);
Значение = Сред(СтрокаКлючРавноПараметр, ПозицияРавно + 1);
КонецЕсли;
Если ПараметрыЗапроса.Получить(Ключ) <> Неопределено Тогда
Если ТипЗнч(ПараметрыЗапроса[Ключ]) = Тип("Массив") Тогда
ПараметрыЗапроса[Ключ].Добавить(Значение);
Иначе
Значения = Новый Массив;
Значения.Добавить(ПараметрыЗапроса[Ключ]);
Значения.Добавить(Значение);
ПараметрыЗапроса[Ключ] = Значения;
КонецЕсли;
Иначе
ПараметрыЗапроса.Вставить(Ключ, Значение);
КонецЕсли;
КонецЦикла;
Возврат ПараметрыЗапроса;
КонецФункции
Функция КодироватьПараметрыЗапроса(ПараметрыЗапроса)
ЧастиПараметрыЗапроса = Новый Массив;
Для Каждого Параметр Из ПараметрыЗапроса Цикл
Если ТипЗнч(Параметр.Значение) = Тип("Массив") Тогда
Значения = Параметр.Значение;
Иначе
Значения = Новый Массив;
Значения.Добавить(Параметр.Значение);
КонецЕсли;
Если Параметр.Значение = Неопределено Тогда
ЧастиПараметрыЗапроса.Добавить(Параметр.Ключ);
Иначе
Для Каждого Значение Из Значения Цикл
ЗначениеПараметра = КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL);
ЧастиПараметрыЗапроса.Добавить(СтрШаблон("%1=%2", Параметр.Ключ, ЗначениеПараметра));
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат СтрСоединить(ЧастиПараметрыЗапроса, "&");
КонецФункции
Процедура ПереопределитьМетод(ПодготовленныйЗапрос, Ответ)
КодыСостоянияHTTP = КодыСостоянияHTTP();
Метод = ПодготовленныйЗапрос.Метод;
// http://tools.ietf.org/html/rfc7231#section-6.4.4
Если Ответ.КодСостояния = КодыСостоянияHTTP.СмотретьДругое_303 И Метод <> "HEAD" Тогда
Метод = "GET";
КонецЕсли;
// Поведение браузеров
Если Ответ.КодСостояния = КодыСостоянияHTTP.ПеремещеноВременно_302 И Метод <> "HEAD" Тогда
Метод = "GET";
КонецЕсли;
ПодготовленныйЗапрос.Метод = Метод;
КонецПроцедуры
Функция ОтправитьЗапрос(Сессия, ПодготовленныйЗапрос, Настройки)
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
МиллисекундВСекунде = 1000;
Повтор = 0;
Длительность = 0;
Ошибки = Новый Массив;
Пока Истина Цикл
Попытка
Ответ = ОтправитьHTTPЗапрос(Сессия, ПодготовленныйЗапрос, Настройки);
ОшибкаВыполненияЗапроса = Неопределено;
Исключение
Ответ = Неопределено;
ОшибкаВыполненияЗапроса = ИнформацияОбОшибке();
ТекстОшибки = СтрШаблон(
НСтр("ru = 'HTTP %1 %2
|Network error:
|%3'"),
ПодготовленныйЗапрос.Метод,
ПодготовленныйЗапрос.URL,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())
);
Ошибки.Добавить(ТекстОшибки);
КонецПопытки;
Повтор = Повтор + 1;
Длительность = (ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало) / МиллисекундВСекунде;
Если Не НеобходимоПовторитьЗапрос(Ответ, Настройки, ОшибкаВыполненияЗапроса) Тогда
Прервать;
КонецЕсли;
Если Повтор > Настройки.МаксимальноеКоличествоПовторов
ИЛИ Длительность > Настройки.МаксимальноеВремяПовторов Тогда
Прервать;
КонецЕсли;
Если ОшибкаВыполненияЗапроса <> Неопределено
ИЛИ НЕ ЭтоКодСостоянияПриКоторомНужноУчитыватьЗаголовокRetryAfter(Ответ.КодСостояния) Тогда
ЗаголовокRetryAfter = Ложь;
Иначе
ЗаголовокRetryAfter = ЗначениеЗаголовка("retry-after", Ответ.Заголовки);
КонецЕсли;
ДлительностьПриостановки = РассчитатьДлительностьПриостановки(
Повтор,
Настройки.КоэффициентЭкспоненциальнойЗадержки,
ЗаголовокRetryAfter,
Настройки.МаксимальноеВремяПовторов - Длительность);
Приостановить(ДлительностьПриостановки);
КонецЦикла;
Если ОшибкаВыполненияЗапроса <> Неопределено Тогда
ВызватьИсключение(ПодробноеПредставлениеОшибки(ОшибкаВыполненияЗапроса));
КонецЕсли;
ЗаголовокContentType = ЗначениеЗаголовка("content-type", Ответ.Заголовки);
Если ЗаголовокContentType = Ложь Тогда
ЗаголовокContentType = "";
КонецЕсли;
ПодготовленныйОтвет = НовыйОтвет();
ПодготовленныйОтвет.Метод = ПодготовленныйЗапрос.Метод;
ПодготовленныйОтвет.URL = ПодготовленныйЗапрос.URL;
ПодготовленныйОтвет.КодСостояния = Ответ.КодСостояния;
ПодготовленныйОтвет.Заголовки = Ответ.Заголовки;
ПодготовленныйОтвет.Тело = Ответ.ПолучитьТелоКакДвоичныеДанные();
ПодготовленныйОтвет.Кодировка = КодировкаИзЗаголовка(ЗаголовокContentType);
ПодготовленныйОтвет.ВремяВыполнения = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало;
ПодготовленныйОтвет.ЭтоПостоянныйРедирект = ЭтоПостоянныйРедирект(Ответ.КодСостояния, Ответ.Заголовки);
ПодготовленныйОтвет.ЭтоРедирект = ЭтоРедирект(Ответ.КодСостояния, Ответ.Заголовки);
ПодготовленныйОтвет.Cookies = ИзвлечьCookies(Ответ.Заголовки, ПодготовленныйЗапрос.URL);
Сессия.Cookies = ОбъединитьCookies(Сессия.Cookies, ПодготовленныйОтвет.Cookies);
Возврат ПодготовленныйОтвет;
КонецФункции
Функция ОтправитьHTTPЗапрос(Сессия, ПодготовленныйЗапрос, Настройки)
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL);
Соединение = Соединение(СтруктураURL, ПодготовленныйЗапрос.Аутентификация, Настройки, Сессия);
Ответ = Соединение.ВызватьHTTPМетод(ПодготовленныйЗапрос.Метод, ПодготовленныйЗапрос.HTTPЗапрос);
Для Каждого Обработчик Из ПодготовленныйЗапрос.СобытияНаОтвет Цикл
Если Обработчик = "ОбработкаОтветаСКодом401" Тогда
ОбработкаОтветаСКодом401(Сессия, ПодготовленныйЗапрос, Настройки, Ответ);
КонецЕсли;
КонецЦикла;
Возврат Ответ;
КонецФункции
Функция НеобходимоПовторитьЗапрос(Ответ, Настройки, ОшибкаВыполненияЗапроса)
Если Настройки.МаксимальноеКоличествоПовторов < 1 Тогда
ПовторитьЗапрос = Ложь;
ИначеЕсли ОшибкаВыполненияЗапроса <> Неопределено ИЛИ ПовторятьПриКодеСостояния(Ответ.КодСостояния, Настройки) Тогда
ПовторитьЗапрос = Истина;
Иначе
ЗаголовокRetryAfter = ЗначениеЗаголовка("retry-after", Ответ.Заголовки);
ПовторитьЗапрос = ЗаголовокRetryAfter <> Ложь
И ЭтоКодСостоянияПриКоторомНужноУчитыватьЗаголовокRetryAfter(Ответ.КодСостояния);
КонецЕсли;
Возврат ПовторитьЗапрос;
КонецФункции
Функция ПовторятьПриКодеСостояния(КодСостояния, Настройки)
ПовторПриЛюбомКодеСостоянияБольшеИлиРавным500 = Настройки.ПовторятьДляКодовСостояний = Неопределено
И КодСостояния >= КодыСостоянияHTTP().ВнутренняяОшибкаСервера_500;
КодСостоянияСоответствуетКодуСостоянияПовтора = ТипЗнч(Настройки.ПовторятьДляКодовСостояний) = Тип("Массив")
И Настройки.ПовторятьДляКодовСостояний.Найти(КодСостояния) <> Неопределено;
Возврат ПовторПриЛюбомКодеСостоянияБольшеИлиРавным500 ИЛИ КодСостоянияСоответствуетКодуСостоянияПовтора;
КонецФункции
Функция ЭтоПостоянныйРедирект(КодСостояния, Заголовки)
КодыСостоянияHTTP = КодыСостоянияHTTP();
Возврат ЕстьЗаголовокLocation(Заголовки)
И (КодСостояния = КодыСостоянияHTTP.ПеремещеноНавсегда_301
ИЛИ КодСостояния = КодыСостоянияHTTP.ПостоянноеПеренаправление_308);
КонецФункции
Функция ЭтоРедирект(КодСостояния, Заголовки)
КодыСостоянияHTTP = КодыСостоянияHTTP();
СостоянияРедиректа = Новый Массив;
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ПеремещеноНавсегда_301);
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ПеремещеноВременно_302);
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.СмотретьДругое_303);
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ВременноеПеренаправление_307);
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ПостоянноеПеренаправление_308);
Возврат ЕстьЗаголовокLocation(Заголовки) И СостоянияРедиректа.Найти(КодСостояния) <> Неопределено;
КонецФункции
Процедура УпаковатьЗапрос(Запрос)
Заголовок = ЗначениеЗаголовка("content-encoding", Запрос.Заголовки);
Если Заголовок <> Ложь Тогда
Если НРег(Заголовок) = "gzip" Тогда
Запрос.УстановитьТелоИзДвоичныхДанных(ЗаписатьGZip(Запрос.ПолучитьТелоКакДвоичныеДанные()));
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция РаспаковатьОтвет(Ответ)
Заголовок = ЗначениеЗаголовка("content-encoding", Ответ.Заголовки);
Если Заголовок <> Ложь Тогда
Если НРег(Заголовок) = "gzip" Тогда
Возврат ПрочитатьGZip(Ответ.Тело);
КонецЕсли;
КонецЕсли;
Возврат Ответ.Тело;
КонецФункции
КонецОбласти
Область ОбработчикиСобытий
Процедура ОбработкаОтветаСКодом401(Сессия, ПодготовленныйЗапрос, Настройки, Ответ)
Если ЭтоРедирект(Ответ.КодСостояния, Ответ.Заголовки) Тогда
Возврат;
КонецЕсли;
КодыСостоянияHTTP = КодыСостоянияHTTP();
Если Ответ.КодСостояния < КодыСостоянияHTTP.НеверныйЗапрос_400
ИЛИ Ответ.КодСостояния >= КодыСостоянияHTTP.ВнутренняяОшибкаСервера_500 Тогда
Возврат;
КонецЕсли;
Значение = ЗначениеЗаголовка("www-authenticate", Ответ.Заголовки);
Если Значение <> Ложь И СтрНайти(НРег(Значение), "digest") Тогда
Позиция = СтрНайти(НРег(Значение), "digest");
Значение = Сред(Значение, Позиция + СтрДлина("digest") + 1);
Значение = СтрЗаменить(Значение, """", "");
Значение = СтрЗаменить(Значение, Символы.ПС, "");
ПараметрыDigest = Новый Структура("algorithm,realm,nonce,qop,opaque");
Для Каждого Часть Из РазбитьСтрокуПоСтроке(Значение, ", ") Цикл
КлючЗначение = СтрРазделить(Часть, "=");
ПараметрыDigest.Вставить(КлючЗначение[0], КлючЗначение[1]);
КонецЦикла;
Сессия.СлужебныеДанные.ПараметрыDigest = ПараметрыDigest;
ПодготовленныйЗапрос.Заголовки.Вставить("Authorization", ПодготовитьЗаголовокDigest(Сессия, ПодготовленныйЗапрос));
ПодготовленныйЗапрос.HTTPЗапрос.Заголовки = ПодготовленныйЗапрос.Заголовки;
Ответ = ОтправитьHTTPЗапрос(Сессия, ПодготовленныйЗапрос, Настройки);
КонецЕсли;
КонецПроцедуры
КонецОбласти
Область URL
Функция ПодготовитьURL(Знач URL, ПараметрыЗапроса = Неопределено)
URL = СокрЛ(URL);
СтруктураURL = РазобратьURL(URL);
ПодготовленныйURL = СтруктураURL.Схема + "://";
Если ЗначениеЗаполнено(СтруктураURL.Аутентификация.Пользователь) Тогда
ПодготовленныйURL = ПодготовленныйURL
+ СтруктураURL.Аутентификация.Пользователь + ":"
+ СтруктураURL.Аутентификация.Пароль + "@";
КонецЕсли;
ПодготовленныйURL = ПодготовленныйURL + СтруктураURL.Сервер;
Если ЗначениеЗаполнено(СтруктураURL.Порт) Тогда
ПодготовленныйURL = ПодготовленныйURL + ":" + Формат(СтруктураURL.Порт, "ЧРГ=; ЧГ=");
КонецЕсли;
ПодготовленныйURL = ПодготовленныйURL + СобратьАдресРесурса(СтруктураURL, ПараметрыЗапроса);
Возврат ПодготовленныйURL;
КонецФункции
Функция СобратьАдресРесурса(СтруктураURL, ПараметрыЗапроса)
АдресРесурса = СтруктураURL.Путь;
ОбъединенныеПараметрыЗапроса = Объединить(Скопировать(ПараметрыЗапроса), СтруктураURL.ПараметрыЗапроса);
Если ЗначениеЗаполнено(ОбъединенныеПараметрыЗапроса) Тогда
АдресРесурса = АдресРесурса + "?" + КодироватьПараметрыЗапроса(ОбъединенныеПараметрыЗапроса);
КонецЕсли;
Если ЗначениеЗаполнено(СтруктураURL.Фрагмент) Тогда
АдресРесурса = АдресРесурса + "#" + СтруктураURL.Фрагмент;
КонецЕсли;
Возврат АдресРесурса;
КонецФункции
Функция СформироватьНовыйURLПриПеренаправлении(Ответ)
НовыйURL = ЗначениеЗаголовка("location", Ответ.Заголовки);
НовыйURL = РаскодироватьСтроку(НовыйURL, СпособКодированияСтроки.URLВКодировкеURL);
// Редирект без схемы
Если СтрНачинаетсяС(НовыйURL, "//") Тогда
СтруктураURL = РазобратьURL(Ответ.URL);
НовыйURL = СтруктураURL.Схема + ":" + НовыйURL;
КонецЕсли;
СтруктураURL = РазобратьURL(НовыйURL);
Если РазбитьСтрокуПоСтроке(НовыйURL, "://").Количество() < 2 Тогда
СтруктураURLОтвета = РазобратьURL(Ответ.URL);
БазовыйURL = СтрШаблон("%1://%2", СтруктураURLОтвета.Схема, СтруктураURLОтвета.Сервер);
Если ЗначениеЗаполнено(СтруктураURLОтвета.Порт) Тогда
БазовыйURL = БазовыйURL + ":" + Формат(СтруктураURLОтвета.Порт, "ЧРГ=; ЧГ=");
КонецЕсли;
Если СтрНачинаетсяС(НовыйURL, "/") Тогда
НовыйURL = БазовыйURL + НовыйURL;
Иначе
ИндексПоследнегоСлеша = СтрНайти(СтруктураURLОтвета.Путь, "/", НаправлениеПоиска.СКонца);
РодительскаяДиректория = Лев(СтруктураURLОтвета.Путь, ИндексПоследнегоСлеша);
НовыйURL = БазовыйURL + РодительскаяДиректория + НовыйURL;
КонецЕсли;
КонецЕсли;
Возврат НовыйURL;
КонецФункции
Функция ЭтоСтандартныйПорт(СтруктураURL)
СтандартныйПортHTTP = 80;
СтандартныйПортHTTPS = 443;
Возврат (СтруктураURL.Схема = "http" И СтруктураURL.Порт = СтандартныйПортHTTP)
ИЛИ (СтруктураURL.Схема = "https" И СтруктураURL.Порт = СтандартныйПортHTTPS);
КонецФункции
КонецОбласти
Область РаботаССоединением
Функция НастройкиПодключения(Метод, URL, ДополнительныеПараметры)
РазрешитьПеренаправление =
ЗначениеПоКлючу(ДополнительныеПараметры, "РазрешитьПеренаправление", ВРег(Метод) <> "HEAD");
ПроверятьSSL = ЗначениеПоКлючу(ДополнительныеПараметры, "ПроверятьSSL", Истина);
КлиентскийСертификатSSL = ЗначениеПоКлючу(ДополнительныеПараметры, "КлиентскийСертификатSSL");
Прокси = ЗначениеПоКлючу(ДополнительныеПараметры, "Прокси", ПроксиПоУмолчанию(URL));
МаксимальноеКоличествоПовторов = ЗначениеПоКлючу(ДополнительныеПараметры, "МаксимальноеКоличествоПовторов", 0);
ПовторятьДляКодовСостояний =
ЗначениеПоКлючу(ДополнительныеПараметры, "ПовторятьДляКодовСостояний", Неопределено);
КоэффициентЭкспоненциальнойЗадержки =
ЗначениеПоКлючу(ДополнительныеПараметры, "КоэффициентЭкспоненциальнойЗадержки", 1);
МаксимальноеВремяПовторов = ЗначениеПоКлючу(ДополнительныеПараметры, "МаксимальноеВремяПовторов", 600);
Настройки = Новый Структура;
Настройки.Вставить("Таймаут", Таймаут(ДополнительныеПараметры));
Настройки.Вставить("РазрешитьПеренаправление", РазрешитьПеренаправление);
Настройки.Вставить("ПроверятьSSL", ПроверятьSSL);
Настройки.Вставить("КлиентскийСертификатSSL", КлиентскийСертификатSSL);
Настройки.Вставить("Прокси", Прокси);
Настройки.Вставить("МаксимальноеКоличествоПовторов", МаксимальноеКоличествоПовторов);
Настройки.Вставить("ПовторятьДляКодовСостояний", ПовторятьДляКодовСостояний);
Настройки.Вставить("КоэффициентЭкспоненциальнойЗадержки", КоэффициентЭкспоненциальнойЗадержки);
Настройки.Вставить("МаксимальноеВремяПовторов", МаксимальноеВремяПовторов);
Возврат Настройки;
КонецФункции
Функция Соединение(ПараметрыСоединения, Аутентификация, ДополнительныеПараметры, Сессия)
Если Не ЗначениеЗаполнено(ПараметрыСоединения.Порт) Тогда
Если ПараметрыСоединения.Схема = "https" Тогда
ПараметрыСоединения.Порт = 443;
Иначе
ПараметрыСоединения.Порт = 80;
КонецЕсли;
КонецЕсли;
ЗащищенноеСоединение = Неопределено;
Если ПараметрыСоединения.Схема = "https" Тогда
ЗащищенноеСоединение = ОбъектЗащищенногоСоединения(ДополнительныеПараметры);
КонецЕсли;
Пользователь = "";
Пароль = "";
Если ЗначениеЗаполнено(Аутентификация) Тогда
Если Аутентификация.Свойство("Пользователь") И Аутентификация.Свойство("Пароль") Тогда
Пользователь = Аутентификация.Пользователь;
Пароль = Аутентификация.Пароль;
КонецЕсли;
КонецЕсли;
ИспользоватьАутентификациюОС = Аутентификация.Свойство("ИспользоватьАутентификациюОС")
И Аутентификация.ИспользоватьАутентификациюОС = Истина;
ПараметрыДляРасчетаИдентификатора = Новый Массив;
ПараметрыДляРасчетаИдентификатора.Добавить(ПараметрыСоединения.Сервер);
ПараметрыДляРасчетаИдентификатора.Добавить(ПараметрыСоединения.Порт);
ПараметрыДляРасчетаИдентификатора.Добавить(Пользователь);
ПараметрыДляРасчетаИдентификатора.Добавить(Пароль);
ПараметрыДляРасчетаИдентификатора.Добавить(ДополнительныеПараметры.Таймаут);
ПараметрыДляРасчетаИдентификатора.Добавить(ИспользоватьАутентификациюОС);
ПараметрыДляРасчетаИдентификатора.Добавить(ЗащищенноеСоединение);
ПараметрыДляРасчетаИдентификатора.Добавить(ДополнительныеПараметры.Прокси);
Если Не Сессия.Свойство("СлужебныеДанные") ИЛИ ТипЗнч(Сессия.СлужебныеДанные) <> Тип("Структура") Тогда
Сессия.Вставить("СлужебныеДанные", Новый Структура);
КонецЕсли;
Если Не Сессия.СлужебныеДанные.Свойство("ПулСоединений") Тогда
Сессия.СлужебныеДанные.Вставить("ПулСоединений", Новый Соответствие);
КонецЕсли;
ПулСоединений = Сессия.СлужебныеДанные.ПулСоединений;
ИдентификаторСоединения = ИдентификаторСоединения(ПараметрыДляРасчетаИдентификатора);
Если ПулСоединений.Получить(ИдентификаторСоединения) = Неопределено Тогда
НовоеСоединение = Новый HTTPСоединение(
ПараметрыСоединения.Сервер,
ПараметрыСоединения.Порт,
Пользователь, Пароль,
ДополнительныеПараметры.Прокси,
ДополнительныеПараметры.Таймаут,
ЗащищенноеСоединение,
ИспользоватьАутентификациюОС);
ПулСоединений.Вставить(ИдентификаторСоединения, НовоеСоединение);
КонецЕсли;
Возврат ПулСоединений[ИдентификаторСоединения];
КонецФункции
Функция ИдентификаторСоединения(ПараметрыСоединения)
ПараметрыДляРасчетаИдентификатора = Новый Массив;
Для Каждого Элемент Из ПараметрыСоединения Цикл
ТипЭлемента = ТипЗнч(Элемент);
Если ТипЭлемента = Тип("ИнтернетПрокси") Тогда
ПараметрыДляРасчетаИдентификатора.Добавить(СтрСоединить(Элемент.НеИспользоватьПроксиДляАдресов, ""));
ПараметрыДляРасчетаИдентификатора.Добавить(XMLСтрока(Элемент.НеИспользоватьПроксиДляЛокальныхАдресов));
ПараметрыДляРасчетаИдентификатора.Добавить(Элемент.Пользователь);
ПараметрыДляРасчетаИдентификатора.Добавить(Элемент.Пароль);
ИначеЕсли ТипЭлемента = Тип("ЗащищенноеСоединениеOpenSSL") Тогда
// Для упрощения будет считать, что сертификаты в рамках сессии не меняются
Если Элемент.СертификатКлиента = Неопределено Тогда
ПараметрыДляРасчетаИдентификатора.Добавить("");
Иначе
ПараметрыДляРасчетаИдентификатора.Добавить(Строка(ТипЗнч(Элемент.СертификатКлиента)));
КонецЕсли;
Если Элемент.СертификатыУдостоверяющихЦентров = Неопределено Тогда
ПараметрыДляРасчетаИдентификатора.Добавить("");
Иначе
ПараметрыДляРасчетаИдентификатора.Добавить(Строка(ТипЗнч(Элемент.СертификатыУдостоверяющихЦентров)));
КонецЕсли;
Иначе
ПараметрыДляРасчетаИдентификатора.Добавить(XMLСтрока(Элемент));
КонецЕсли;
КонецЦикла;
Возврат ХешированиеДанных(ХешФункция.MD5, СтрСоединить(ПараметрыДляРасчетаИдентификатора, ""));
КонецФункции
Функция ОбъектЗащищенногоСоединения(ДополнительныеПараметры)
Если ДополнительныеПараметры.ПроверятьSSL = Ложь Тогда
СертификатыУЦ = Неопределено;
ИначеЕсли ТипЗнч(ДополнительныеПараметры.ПроверятьSSL) = Тип("СертификатыУдостоверяющихЦентровФайл") Тогда
СертификатыУЦ = ДополнительныеПараметры.ПроверятьSSL;
Иначе
СертификатыУЦ = Новый СертификатыУдостоверяющихЦентровОС;
КонецЕсли;
КлиентскийСертификат = Неопределено;
Если ТипЗнч(ДополнительныеПараметры.КлиентскийСертификатSSL) = Тип("СертификатКлиентаФайл")
ИЛИ ТипЗнч(ДополнительныеПараметры.КлиентскийСертификатSSL) = Тип("СертификатКлиентаWindows") Тогда
КлиентскийСертификат = ДополнительныеПараметры.КлиентскийСертификатSSL;
КонецЕсли;
Возврат Новый ЗащищенноеСоединениеOpenSSL(КлиентскийСертификат, СертификатыУЦ);
КонецФункции
Функция Таймаут(ДополнительныеПараметры)
Если ДополнительныеПараметры.Свойство("Таймаут") И ДополнительныеПараметры.Таймаут <> Неопределено Тогда
Таймаут = ДополнительныеПараметры.Таймаут;
Иначе
Таймаут = СтандартныйТаймаут();
КонецЕсли;
Возврат Таймаут;
КонецФункции
Функция ПроксиПоУмолчанию(URL)
ПроксиПоУмолчанию = Новый ИнтернетПрокси;
// BSLLS:ExecuteExternalCodeInCommonModule-off
ИмяОМПолученияФайловБСП = "ПолучениеФайловИзИнтернета";
Если Метаданные.ОбщиеМодули.Найти(ИмяОМПолученияФайловБСП) <> Неопределено Тогда
СтруктураURL = РазобратьURL(URL);
Модуль = Вычислить(ИмяОМПолученияФайловБСП);
ПроксиПоУмолчанию = Модуль.ПолучитьПрокси(СтруктураURL.Схема);
КонецЕсли;
// BSLLS:ExecuteExternalCodeInCommonModule-on
Возврат ПроксиПоУмолчанию;
КонецФункции
Функция ТекущаяСессия(Сессия)
Если Сессия = Неопределено Тогда
Сессия = СоздатьСессию();
КонецЕсли;
Возврат Сессия;
КонецФункции
КонецОбласти
Область Заголовки
Функция ЗаголовкиВСтроку(Заголовки)
РазделительСтрок = Символы.ВК + Символы.ПС;
Строки = Новый Массив;
СортированныеЗаголовки = "Content-Disposition,Content-Type,Content-Location";
Для Каждого Ключ Из СтрРазделить(СортированныеЗаголовки, ",") Цикл
Значение = ЗначениеЗаголовка(Ключ, Заголовки);
Если Значение <> Ложь И ЗначениеЗаполнено(Значение) Тогда
Строки.Добавить(СтрШаблон("%1: %2", Ключ, Значение));
КонецЕсли;
КонецЦикла;
Ключи = СтрРазделить(ВРег(СортированныеЗаголовки), ",");
Для Каждого Заголовок Из Заголовки Цикл
Если Ключи.Найти(ВРег(Заголовок.Ключ)) = Неопределено Тогда
Строки.Добавить(СтрШаблон("%1: %2", Заголовок.Ключ, Заголовок.Значение));
КонецЕсли;
КонецЦикла;
Строки.Добавить(РазделительСтрок);
Возврат СтрСоединить(Строки, РазделительСтрок);
КонецФункции
Процедура УдалитьЗаголовки(Заголовки, СписокЗаголовковСтрокой)
ЗаголовкиДляУдаления = Новый Массив;
СписокЗаголовков = СтрРазделить(СписокЗаголовковСтрокой, ",", Ложь);
Для Каждого Заголовок Из Заголовки Цикл
Если СписокЗаголовков.Найти(НРег(Заголовок.Ключ)) <> Неопределено Тогда
ЗаголовкиДляУдаления.Добавить(Заголовок.Ключ);
КонецЕсли;
КонецЦикла;
Для Каждого ЗаголовокДляУдаления Из ЗаголовкиДляУдаления Цикл
Заголовки.Удалить(ЗаголовокДляУдаления);
КонецЦикла;
КонецПроцедуры
Функция ЕстьЗаголовокLocation(Заголовки)
Возврат ЗначениеЗаголовка("location", Заголовки) <> Ложь;
КонецФункции
Функция КодировкаИзЗаголовка(Знач Заголовок)
Кодировка = Неопределено;
Заголовок = НРег(СокрЛП(Заголовок));
ИндексРазделителя = СтрНайти(Заголовок, ";");
Если ИндексРазделителя Тогда
ТипСодержимого = СокрЛП(Лев(Заголовок, ИндексРазделителя - 1));
КлючКодировки = "charset=";
ИндексКодировки = СтрНайти(Заголовок, КлючКодировки);
Если ИндексКодировки Тогда
ИндексРазделителя = СтрНайти(Заголовок, ";", НаправлениеПоиска.СНачала, ИндексКодировки);
НачальнаяПозиция = ИндексКодировки + СтрДлина(КлючКодировки);
Если ИндексРазделителя Тогда
ДлинаКодировки = ИндексРазделителя - НачальнаяПозиция;
Иначе
ДлинаКодировки = СтрДлина(Заголовок);
КонецЕсли;
Кодировка = Сред(Заголовок, НачальнаяПозиция, ДлинаКодировки);
Кодировка = СтрЗаменить(Кодировка, """", "");
Кодировка = СтрЗаменить(Кодировка, "'", "");
КонецЕсли;
Иначе
ТипСодержимого = Заголовок;
КонецЕсли;
Если Кодировка = Неопределено И СтрНайти(ТипСодержимого, "text") Тогда
Кодировка = "iso-8859-1";
КонецЕсли;
Возврат Кодировка;
КонецФункции
Функция ЗначениеЗаголовка(Заголовок, ВсеЗаголовки, Ключ = Неопределено)
Для Каждого ОчереднойЗаголовок Из ВсеЗаголовки Цикл
Если НРег(ОчереднойЗаголовок.Ключ) = НРег(Заголовок) Тогда
Ключ = ОчереднойЗаголовок.Ключ;
Возврат ОчереднойЗаголовок.Значение;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Функция СформироватьЗначениеЗаголовкаHost(СтруктураURL)
Host = СтруктураURL.Сервер;
Если ЗначениеЗаполнено(СтруктураURL.Порт) И НЕ ЭтоСтандартныйПорт(СтруктураURL) Тогда
Host = Host + ":" + Формат(СтруктураURL.Порт, "ЧРГ=; ЧГ=");
КонецЕсли;
Возврат Host;
КонецФункции
Функция ПодготовитьЗаголовокDigest(Сессия, ПодготовленныйЗапрос)
ПараметрыDigest = Сессия.СлужебныеДанные.ПараметрыDigest;
Алгоритм = ОпределитьХешФункцию(ПараметрыDigest.algorithm);
АлгоритмСтрокой = ВРег(ПараметрыDigest.algorithm);
Если Алгоритм = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL);
Путь = СтруктураURL.Путь;
Если ЗначениеЗаполнено(СтруктураURL.ПараметрыЗапроса) Тогда
Путь = Путь + "?" + КодироватьПараметрыЗапроса(СтруктураURL.ПараметрыЗапроса);
КонецЕсли;
A1 = СтрШаблон("%1:%2:%3",
ПодготовленныйЗапрос.Аутентификация.Пользователь,
ПараметрыDigest.realm,
ПодготовленныйЗапрос.Аутентификация.Пароль);
A2 = СтрШаблон("%1:%2", ПодготовленныйЗапрос.Метод, Путь);
HA1 = ХешированиеДанных(Алгоритм, A1);
HA2 = ХешированиеДанных(Алгоритм, A2);
Если Не ПараметрыDigest.Свойство("last_nonce") Тогда
ПараметрыDigest.Вставить("last_nonce");
КонецЕсли;
Если ПараметрыDigest.nonce = ПараметрыDigest.last_nonce Тогда
ПараметрыDigest.nonce_count = ПараметрыDigest.nonce_count + 1;
Иначе
ПараметрыDigest.Вставить("nonce_count", 1);
КонецЕсли;
ЗначениеNC = Формат(ПараметрыDigest.nonce_count, "ЧЦ=8; ЧВН=; ЧГ=");
ЗначениеNonce = Лев(СтрЗаменить(НРег(Новый УникальныйИдентификатор), "-", ""), 16);
Если АлгоритмСтрокой = "MD5-SESS" Тогда
HA1 = ХешированиеДанных(Алгоритм, СтрШаблон("%1:%2:%3", HA1, ПараметрыDigest.nonce, ЗначениеNonce));
КонецЕсли;
Если Не ЗначениеЗаполнено(ПараметрыDigest.qop) Тогда
ЗначениеResponse = ХешированиеДанных(Алгоритм, СтрШаблон("%1:%2:%3", HA1, ПараметрыDigest.nonce, HA2));
ИначеЕсли ПараметрыDigest.qop = "auth"
ИЛИ СтрРазделить(ПараметрыDigest.qop, ",", Ложь).Найти("auth") <> Неопределено Тогда
ЗначениеNonceBit = СтрШаблон("%1:%2:%3:%4:%5", ПараметрыDigest.nonce, ЗначениеNC, ЗначениеNonce, "auth", HA2);
ЗначениеResponse = ХешированиеДанных(Алгоритм, СтрШаблон("%1:%2", HA1, ЗначениеNonceBit));
Иначе
// INFO: auth-int не реализовано
Возврат Неопределено;
КонецЕсли;
ПараметрыDigest.last_nonce = ПараметрыDigest.nonce;
База = СтрШаблон("username=""%1"", realm=""%2"", nonce=""%3"", uri=""%4"", response=""%5""",
ПодготовленныйЗапрос.Аутентификация.Пользователь,
ПараметрыDigest.realm,
ПараметрыDigest.nonce,
Путь,
ЗначениеResponse);
Строки = Новый Массив;
Строки.Добавить(База);
Если ЗначениеЗаполнено(ПараметрыDigest.opaque) Тогда
Строки.Добавить(СтрШаблон(", opaque=""%1""", ПараметрыDigest.opaque));
КонецЕсли;
Если ЗначениеЗаполнено(ПараметрыDigest.algorithm) Тогда
Строки.Добавить(СтрШаблон(", algorithm=""%1""", ПараметрыDigest.algorithm));
КонецЕсли;
Если ЗначениеЗаполнено(ПараметрыDigest.qop) Тогда
Строки.Добавить(СтрШаблон(", qop=""auth"", nc=%1, cnonce=""%2""", ЗначениеNC, ЗначениеNonce));
КонецЕсли;
Возврат СтрШаблон("Digest %1", СтрСоединить(Строки, ""));
КонецФункции
КонецОбласти
Область Cookies
Процедура ПодготовитьCookies(ПодготовленныйЗапрос)
ЗаголовокCookie = ПодготовитьЗаголовокCookie(ПодготовленныйЗапрос);
Если ЗначениеЗаполнено(ЗаголовокCookie) Тогда
ПодготовленныйЗапрос.Заголовки["Cookie"] = ЗаголовокCookie;
КонецЕсли;
КонецПроцедуры
Функция ПодготовитьЗаголовокCookie(ПодготовленныйЗапрос)
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL);
Cookies = Новый Массив;
Для Каждого Cookie Из ОтобратьCookiesДляЗапроса(СтруктураURL, ПодготовленныйЗапрос.Cookies) Цикл
Cookies.Добавить(СтрШаблон("%1=%2", Cookie.Наименование, Cookie.Значение));
КонецЦикла;
Возврат СтрСоединить(Cookies, "; ");
КонецФункции
Функция ОбъединитьCookies(ГлавныйИсточник, ДополнительныйИсточник)
Cookies = Новый Соответствие;
Для Каждого Cookie Из ПреобразоватьХранилищеCookiesВМассивCookies(ГлавныйИсточник) Цикл
ДобавитьCookieВХранилище(Cookies, Cookie, Истина);
КонецЦикла;
Для Каждого Cookie Из ПреобразоватьХранилищеCookiesВМассивCookies(ДополнительныйИсточник) Цикл
ДобавитьCookieВХранилище(Cookies, Cookie, Истина);
КонецЦикла;
Возврат Cookies;
КонецФункции
Функция ПреобразоватьХранилищеCookiesВМассивCookies(ХранилищеCookies)
Cookies = Новый Массив;
Если ТипЗнч(ХранилищеCookies) = Тип("Массив") Тогда
Для Каждого Cookie Из ХранилищеCookies Цикл
НоваяCookie = КонструкторCookie();
ЗаполнитьЗначенияСвойств(НоваяCookie, Cookie);
Cookies.Добавить(НоваяCookie);
КонецЦикла;
Возврат Cookies;
КонецЕсли;
Для Каждого Домен Из ХранилищеCookies Цикл
Для Каждого Путь Из Домен.Значение Цикл
Для Каждого Наименование Из Путь.Значение Цикл
Cookies.Добавить(Наименование.Значение);
КонецЦикла;
КонецЦикла;
КонецЦикла;
Возврат Cookies;
КонецФункции
Функция ОтобратьCookiesДляЗапроса(СтруктураURL, Cookies)
СерверВЗапросе = ДобавитьЛидирующуюТочку(СтруктураURL.Сервер);
Результат = Новый Массив;
Для Каждого Домен Из Cookies Цикл
Если Не СтрЗаканчиваетсяНа(СерверВЗапросе, Домен.Ключ) Тогда
Продолжить;
КонецЕсли;
Для Каждого Путь Из Домен.Значение Цикл
Если Не СтрНачинаетсяС(СтруктураURL.Путь, Путь.Ключ) Тогда
Продолжить;
КонецЕсли;
ЗаполнитьСписокОтфильтрованнымиCookies(Путь.Значение, СтруктураURL, Результат);
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ЗаполнитьСписокОтфильтрованнымиCookies(Cookies, СтруктураURL, Список)
Для Каждого Cookie Из Cookies Цикл
Если Cookie.Значение.ТолькоБезопасноеСоединение = Истина И СтруктураURL.Схема <> "https" Тогда
Продолжить;
КонецЕсли;
// INFO: проверка срока действия игнорируется (Cookie.Значение.СрокДействия)
// INFO: проверка порта игнорируется
Список.Добавить(Cookie.Значение);
КонецЦикла;
КонецПроцедуры
Функция ДозаполнитьCookie(Cookies, URL)
СтруктураURL = РазобратьURL(URL);
НовыеCookies = Новый Массив;
Если ТипЗнч(Cookies) = Тип("Массив") Тогда
Для Каждого Cookie Из Cookies Цикл
НовыйCookie = КонструкторCookie(Cookie.Наименование, Cookie.Значение);
ЗаполнитьЗначенияСвойств(НовыйCookie, Cookie);
Если Не ЗначениеЗаполнено(НовыйCookie.Домен) Тогда
НовыйCookie.Домен = СтруктураURL.Сервер;
КонецЕсли;
Если Не ЗначениеЗаполнено(НовыйCookie.Путь) Тогда
НовыйCookie.Путь = "/";
КонецЕсли;
НовыеCookies.Добавить(НовыйCookie);
КонецЦикла;
Возврат НовыеCookies;
КонецЕсли;
Возврат Cookies;
КонецФункции
Функция ИзвлечьCookies(Заголовки, URL)
ТекущееВремя = ТекущаяУниверсальнаяДата();
Cookies = Новый Соответствие;
Для Каждого ОчереднойЗаголовок Из Заголовки Цикл
Если НРег(ОчереднойЗаголовок.Ключ) = "set-cookie" Тогда
Для Каждого ЗаголовокCookie Из РазбитьНаОтдельныеЗаголовкиCookies(ОчереднойЗаголовок.Значение) Цикл
Cookie = РаспарситьCookie(ЗаголовокCookie, URL, ТекущееВремя);
Если Cookie = Неопределено Тогда
Продолжить;
КонецЕсли;
Если Cookie.СрокДействия <= ТекущееВремя Тогда
УдалитьCookieИзХранилища(Cookies, Cookie);
Иначе
ДобавитьCookieВХранилище(Cookies, Cookie);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат Cookies;
КонецФункции
Функция РазбитьНаОтдельныеЗаголовкиCookies(Знач Заголовок)
Заголовки = Новый Массив;
Если Не ЗначениеЗаполнено(Заголовок) Тогда
Возврат Заголовки;
КонецЕсли;
ЗапчастиЗаголовков = СтрРазделить(Заголовок, ",", Ложь);
ОтдельныйЗаголовок = ЗапчастиЗаголовков[0];
Для Индекс = 1 По ЗапчастиЗаголовков.ВГраница() Цикл
ТочкаСЗапятой = СтрНайти(ЗапчастиЗаголовков[Индекс], ";");
Равно = СтрНайти(ЗапчастиЗаголовков[Индекс], "=");
Если ТочкаСЗапятой И Равно И Равно < ТочкаСЗапятой Тогда
Заголовки.Добавить(ОтдельныйЗаголовок);
ОтдельныйЗаголовок = ЗапчастиЗаголовков[Индекс];
Иначе
ОтдельныйЗаголовок = ОтдельныйЗаголовок + ЗапчастиЗаголовков[Индекс];
КонецЕсли;
КонецЦикла;
Заголовки.Добавить(ОтдельныйЗаголовок);
Возврат Заголовки;
КонецФункции
Процедура ДобавитьCookieВХранилище(ХранилищеCookies, Cookie, Замещать = Ложь)
Если ХранилищеCookies.Получить(Cookie.Домен) = Неопределено Тогда
ХранилищеCookies[Cookie.Домен] = Новый Соответствие;
КонецЕсли;
Если ХранилищеCookies[Cookie.Домен].Получить(Cookie.Путь) = Неопределено Тогда
ХранилищеCookies[Cookie.Домен][Cookie.Путь] = Новый Соответствие;
КонецЕсли;
Если ХранилищеCookies[Cookie.Домен][Cookie.Путь].Получить(Cookie.Наименование) = Неопределено ИЛИ Замещать Тогда
ХранилищеCookies[Cookie.Домен][Cookie.Путь][Cookie.Наименование] = Cookie;
КонецЕсли;
КонецПроцедуры
Процедура УдалитьCookieИзХранилища(ХранилищеCookies, Cookie)
Если ХранилищеCookies.Получить(Cookie.Домен) <> Неопределено
И ХранилищеCookies[Cookie.Домен].Получить(Cookie.Путь) <> Неопределено
И ХранилищеCookies[Cookie.Домен][Cookie.Путь].Получить(Cookie.Наименование) <> Неопределено Тогда
ХранилищеCookies[Cookie.Домен][Cookie.Путь].Удалить(Cookie.Наименование);
КонецЕсли;
КонецПроцедуры
Функция РаспарситьCookie(Заголовок, URL, ТекущееВремя)
Cookie = Неопределено;
Индекс = 0;
Для Каждого Параметр Из СтрРазделить(Заголовок, ";", Ложь) Цикл
Индекс = Индекс + 1;
Параметр = СокрЛП(Параметр);
Если Индекс = 1 Тогда
Cookie = СоздатьCookieИЗаполнитьОсновныеПараметры(Параметр);
Продолжить;
КонецЕсли;
Части = СтрРазделить(Параметр, "=", Ложь);
Ключ = НРег(Части[0]);
Если Части.Количество() > 1 Тогда
Значение = Части[1];
КонецЕсли;
Если Ключ = "domain" Тогда
Cookie.Домен = Значение;
ИначеЕсли Ключ = "path" Тогда
Cookie.Путь = Значение;
ИначеЕсли Ключ = "secure" Тогда
Cookie.ТолькоБезопасноеСоединение = Истина;
ИначеЕсли Ключ = "max-age" Тогда
СрокДействияMaxAge = ТекущееВремя + ЧислоИзСтроки(Значение);
ИначеЕсли Ключ = "expires" Тогда
Cookie.СрокДействия = ДатаИзСтрокиRFC7231(Значение);
Иначе
Продолжить;
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(Cookie) И ЗначениеЗаполнено(СрокДействияMaxAge) Тогда
Cookie.СрокДействия = СрокДействияMaxAge;
КонецЕсли;
ДозаполнитьCookieНеявнымиЗначениями(Cookie, URL);
Возврат Cookie;
КонецФункции
Функция СоздатьCookieИЗаполнитьОсновныеПараметры(Параметр)
Части = СтрРазделить(Параметр, "=", Ложь);
Наименование = Части[0];
Если Части.Количество() > 1 Тогда
Значение = Сред(Параметр, СтрДлина(Наименование) + 2);
КонецЕсли;
Возврат КонструкторCookie(Наименование, Значение);
КонецФункции
Процедура ДозаполнитьCookieНеявнымиЗначениями(Cookie, URL)
Если Cookie = Неопределено Тогда
Возврат;
КонецЕсли;
СтруктураURL = РазобратьURL(URL);
Если Не ЗначениеЗаполнено(Cookie.Домен) Тогда
Cookie.Домен = СтруктураURL.Сервер;
КонецЕсли;
Если Не ЗначениеЗаполнено(Cookie.Порт) И ЗначениеЗаполнено(СтруктураURL.Порт) Тогда
Cookie.Порт = СтруктураURL.Порт;
КонецЕсли;
Если Не ЗначениеЗаполнено(Cookie.Путь) Тогда
ПозицияПоследнегоСлеша = СтрНайти(СтруктураURL.Путь, "/", НаправлениеПоиска.СКонца);
Если ПозицияПоследнегоСлеша <= 1 Тогда
Cookie.Путь = "/";
Иначе
Cookie.Путь = Лев(СтруктураURL.Путь, ПозицияПоследнегоСлеша - 1);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция КонструкторCookie(Наименование = «», Значение = Неопределено)
НовыйCookie = Новый Структура;
НовыйCookie.Вставить("Наименование", Наименование);
НовыйCookie.Вставить("Значение", Значение);
НовыйCookie.Вставить("Домен", "");
НовыйCookie.Вставить("Путь", "");
НовыйCookie.Вставить("Порт");
НовыйCookie.Вставить("СрокДействия", '39990101');
НовыйCookie.Вставить("ТолькоБезопасноеСоединение");
Возврат НовыйCookie;
КонецФункции
КонецОбласти
Область ПараметрыРаботыСJSON
// Преобразует значение типа к типу, сериализация которого поддерживается.
//
// Параметры:
// Свойство — Строка — имя свойства, если выполняется запись структуры или соответствия.
// Значение — Произвольный — исходное значение.
// ДополнительныеПараметры — Произвольный — дополнительные параметры, которые указаны в вызове метода ЗаписатьJSON.
// Отказ — Булево — отказ от записи свойства.
//
// Возвращаемое значение:
// Произвольный — см. типы ЗаписатьJSON.
//
Функция ПреобразованиеJson(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
Возврат Строка(Значение);
ИначеЕсли ТипЗнч(Значение) = Тип("ДвоичныеДанные") Тогда
Возврат ПолучитьBase64СтрокуИзДвоичныхДанных(Значение);
Иначе
// Если значение не поддерживает сериализацию в JSON, то будет выброшено исключение
Возврат Значение;
КонецЕсли;
КонецФункции
// Восстанавливает значение типа, десериализация которого не поддерживается.
//
// Параметры:
// Свойство — Строка — имя свойства, значение которого нужно восстановить.
// Значение — Строка — значение, которое нужно восстановить.
// ТипыСвойств — Соответствие — типы свойств, которые нужно восстановить.
// * Ключ — Строка — имя свойства. Равно значению параметра Свойство.
// * Значение — Тип — исходный тип значения.
//
// Возвращаемое значение:
// Произвольный — восстановленное значение.
//
Функция ВосстановлениеJson(Свойство, Значение, ТипыСвойств) Экспорт
ТипСвойства = ТипыСвойств.Получить(Свойство);
Если ТипСвойства = Тип("УникальныйИдентификатор") Тогда
Возврат Новый УникальныйИдентификатор(Значение);
ИначеЕсли ТипСвойства = Тип("ДвоичныеДанные") Тогда
Возврат ПолучитьДвоичныеДанныеИзBase64Строки(Значение);
Иначе
Возврат Значение;
КонецЕсли;
КонецФункции
КонецОбласти
Область АутентификацияAWS4
Функция КлючПодписиAWS4(СекретныйКлюч, Дата, Регион, Сервис)
КлючДата = ПодписатьСообщениеHMAC("AWS4" + СекретныйКлюч, Дата);
КлючРегион = ПодписатьСообщениеHMAC(КлючДата, Регион);
КлючСервис = ПодписатьСообщениеHMAC(КлючРегион, Сервис);
Возврат ПодписатьСообщениеHMAC(КлючСервис, "aws4_request");
КонецФункции
Функция ПодписатьСообщениеHMAC(Знач Ключ, Знач Сообщение, Знач Алгоритм = Неопределено)
Если Алгоритм = Неопределено Тогда
Алгоритм = ХешФункция.SHA256;
КонецЕсли;
Если ТипЗнч(Ключ) = Тип("Строка") Тогда
Ключ = ПолучитьДвоичныеДанныеИзСтроки(Ключ, КодировкаТекста.UTF8, Ложь);
КонецЕсли;
Если ТипЗнч(Сообщение) = Тип("Строка") Тогда
Сообщение = ПолучитьДвоичныеДанныеИзСтроки(Сообщение, КодировкаТекста.UTF8, Ложь);
КонецЕсли;
Возврат HMAC(Ключ, Сообщение, Алгоритм);
КонецФункции
Процедура ПодготовитьАутентификациюAWS4(ПодготовленныйЗапрос)
ЗначениеЗаголовка = ЗначениеЗаголовка("x-amz-date", ПодготовленныйЗапрос.Заголовки);
Если ЗначениеЗаголовка <> Ложь Тогда
ТекущееВремя = Дата(СтрЗаменить(СтрЗаменить(ЗначениеЗаголовка, "T", ""), "Z", ""));
Иначе
ТекущееВремя = ТекущаяУниверсальнаяДата();
КонецЕсли;
ПодготовленныйЗапрос.Заголовки["x-amz-date"] = Формат(ТекущееВремя, "ДФ=yyyyMMddTHHmmssZ");
ОбластьДействияДата = Формат(ТекущееВремя, "ДФ=yyyyMMdd");
ПодготовленныйЗапрос.Заголовки["x-amz-content-sha256"] =
ХешированиеДанных(ХешФункция.SHA256, ПодготовленныйЗапрос.HTTPЗапрос.ПолучитьТелоКакПоток());
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL);
КаноническиеЗаголовки = КаноническиеЗаголовкиAWS4(ПодготовленныйЗапрос.Заголовки, СтруктураURL);
КаноническийПуть = СтруктураURL.Путь;
КаноническиеПараметрыЗапроса = КаноническиеПараметрыЗапросаAWS4(СтруктураURL.ПараметрыЗапроса);
ЧастиЗапроса = Новый Массив;
ЧастиЗапроса.Добавить(ПодготовленныйЗапрос.Метод);
ЧастиЗапроса.Добавить(КаноническийПуть);
ЧастиЗапроса.Добавить(КаноническиеПараметрыЗапроса);
ЧастиЗапроса.Добавить(КаноническиеЗаголовки.КаноническиеЗаголовки);
ЧастиЗапроса.Добавить(КаноническиеЗаголовки.ПодписываемыеЗаголовки);
ЧастиЗапроса.Добавить(ПодготовленныйЗапрос.Заголовки["x-amz-content-sha256"]);
КаноническийЗапрос = СтрСоединить(ЧастиЗапроса, Символы.ПС);
ЧастиОбластиДействия = Новый Массив;
ЧастиОбластиДействия.Добавить(ОбластьДействияДата);
ЧастиОбластиДействия.Добавить(ПодготовленныйЗапрос.Аутентификация.Регион);
ЧастиОбластиДействия.Добавить(ПодготовленныйЗапрос.Аутентификация.Сервис);
ЧастиОбластиДействия.Добавить("aws4_request");
ОбластьДействия = СтрСоединить(ЧастиОбластиДействия, "/");
ЧастиСтрокиДляПодписи = Новый Массив;
ЧастиСтрокиДляПодписи.Добавить(ПодготовленныйЗапрос.Аутентификация.Тип);
ЧастиСтрокиДляПодписи.Добавить(ПодготовленныйЗапрос.Заголовки["x-amz-date"]);
ЧастиСтрокиДляПодписи.Добавить(ОбластьДействия);
ЧастиСтрокиДляПодписи.Добавить(ХешированиеДанных(ХешФункция.SHA256, КаноническийЗапрос));
СтрокаДляПодписи = СтрСоединить(ЧастиСтрокиДляПодписи, Символы.ПС);
Ключ = КлючПодписиAWS4(
ПодготовленныйЗапрос.Аутентификация.СекретныйКлюч,
ОбластьДействияДата,
ПодготовленныйЗапрос.Аутентификация.Регион,
ПодготовленныйЗапрос.Аутентификация.Сервис);
Подпись = НРег(ПолучитьHexСтрокуИзДвоичныхДанных(ПодписатьСообщениеHMAC(Ключ, СтрокаДляПодписи)));
ПодготовленныйЗапрос.Заголовки["Authorization"] = СтрШаблон(
"%1 Credential=%2/%3, SignedHeaders=%4, Signature=%5",
ПодготовленныйЗапрос.Аутентификация.Тип,
ПодготовленныйЗапрос.Аутентификация.ИдентификаторКлючаДоступа,
ОбластьДействия,
КаноническиеЗаголовки.ПодписываемыеЗаголовки,
Подпись);
ПодготовленныйЗапрос.HTTPЗапрос.Заголовки = ПодготовленныйЗапрос.Заголовки;
КонецПроцедуры
Функция КаноническиеЗаголовкиAWS4(Заголовки, СтруктураURL)
Список = Новый СписокЗначений;
ЗаголовокHostЕстьВЗапросе = Ложь;
ЗаголовкиПоУмолчанию = ЗаголовкиПоУмолчаниюAWS4();
Для Каждого ОчереднойЗаголовок Из Заголовки Цикл
Заголовок = НРег(ОчереднойЗаголовок.Ключ);
Если ЗаголовкиПоУмолчанию.Исключения.Найти(Заголовок) <> Неопределено Тогда
Продолжить;
КонецЕсли;
ЗаголовокHostЕстьВЗапросе = Макс(ЗаголовокHostЕстьВЗапросе, Заголовок = "host");
Если ЗаголовкиПоУмолчанию.Равно.Найти(Заголовок) <> Неопределено Тогда
Список.Добавить(Заголовок, СокрЛП(ОчереднойЗаголовок.Значение));
Иначе
Для Каждого Префикс Из ЗаголовкиПоУмолчанию.НачинаетсяС Цикл
Если СтрНачинаетсяС(Заголовок, Префикс) Тогда
Список.Добавить(Заголовок, СокрЛП(ОчереднойЗаголовок.Значение));
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Если Не ЗаголовокHostЕстьВЗапросе Тогда
Список.Добавить("host", СформироватьЗначениеЗаголовкаHost(СтруктураURL));
КонецЕсли;
Список.СортироватьПоЗначению(НаправлениеСортировки.Возр);
КаноническиеЗаголовки = Новый Массив;
ПодписываемыеЗаголовки = Новый Массив;
Для Каждого ЭлементСписка Из Список Цикл
КаноническиеЗаголовки.Добавить(ЭлементСписка.Значение + ":" + ЭлементСписка.Представление);
ПодписываемыеЗаголовки.Добавить(ЭлементСписка.Значение);
КонецЦикла;
КаноническиеЗаголовки.Добавить("");
КаноническиеЗаголовки = СтрСоединить(КаноническиеЗаголовки, Символы.ПС);
ПодписываемыеЗаголовки = СтрСоединить(ПодписываемыеЗаголовки, ";");
Возврат Новый Структура(
"КаноническиеЗаголовки, ПодписываемыеЗаголовки",
КаноническиеЗаголовки, ПодписываемыеЗаголовки);
КонецФункции
Функция КаноническиеПараметрыЗапросаAWS4(ПараметрыЗапроса)
Список = Новый СписокЗначений;
Для Каждого ОчереднойПараметрЗапроса Из ПараметрыЗапроса Цикл
Список.Добавить(ОчереднойПараметрЗапроса.Ключ, СокрЛП(ОчереднойПараметрЗапроса.Значение));
КонецЦикла;
Список.СортироватьПоЗначению(НаправлениеСортировки.Возр);
КаноническиеПараметры = Новый Массив;
Для Каждого ЭлементСписка Из Список Цикл
ЗначениеПараметра = КодироватьСтроку(ЭлементСписка.Представление, СпособКодированияСтроки.КодировкаURL);
КаноническиеПараметры.Добавить(ЭлементСписка.Значение + "=" + ЗначениеПараметра);
КонецЦикла;
Возврат СтрСоединить(КаноническиеПараметры, "&");
КонецФункции
Функция ЗаголовкиПоУмолчаниюAWS4()
Заголовки = Новый Структура;
Заголовки.Вставить("Равно", СтрРазделить("host,content-type,date", ","));
Заголовки.Вставить("НачинаетсяС", СтрРазделить("x-amz-", ","));
Заголовки.Вставить("Исключения", СтрРазделить("x-amz-client-context", ","));
Возврат Заголовки;
КонецФункции
КонецОбласти
Процедура ПодготовитьАутентификациюBearer(ПодготовленныйЗапрос)
Если Не ПодготовленныйЗапрос.Аутентификация.Свойство("Токен") или не ЗначениеЗаполнено(ПодготовленныйЗапрос.Аутентификация.Токен) Тогда
// Токен не заполнен.
Возврат;
КонецЕсли;
ПодготовленныйЗапрос.Заголовки.Вставить("Authorization", СтрШаблон("Bearer %1", ПодготовленныйЗапрос.Аутентификация.Токен));
КонецПроцедуры
Область КодированиеДекодированиеДанных
Область СлужебныеСтруктурыZip
// Описание структур см. здесь https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
Функция ZipРазмерLFH()
Возврат 34;
КонецФункции
Функция ZipРазмерDD()
Возврат 16;
КонецФункции
Функция ZipРазмерCDH()
Возврат 50;
КонецФункции
Функция ZipРазмерEOCD()
Возврат 22;
КонецФункции
Функция ZipLFH()
// Local file header
Буфер = Новый БуферДвоичныхДанных(ZipРазмерLFH());
Буфер.ЗаписатьЦелое32(0, 67324752); // signature 0x04034b50
Буфер.ЗаписатьЦелое16(4, 20); // version
Буфер.ЗаписатьЦелое16(6, 10); // bit flags
Буфер.ЗаписатьЦелое16(8, 8); // compression method
Буфер.ЗаписатьЦелое16(10, 0); // time
Буфер.ЗаписатьЦелое16(12, 0); // date
Буфер.ЗаписатьЦелое32(14, 0); // crc-32
Буфер.ЗаписатьЦелое32(18, 0); // compressed size
Буфер.ЗаписатьЦелое32(22, 0); // uncompressed size
Буфер.ЗаписатьЦелое16(26, 4); // filename legth - "data"
Буфер.ЗаписатьЦелое16(28, 0); // extra field length
Буфер.Записать(30, ПолучитьБуферДвоичныхДанныхИзСтроки("data", "ascii", Ложь));
Возврат Буфер;
КонецФункции
Функция ZipDD(CRC32, РазмерСжатыхДанных, РазмерНесжатыхДанных)
// Data descriptor
Буфер = Новый БуферДвоичныхДанных(ZipРазмерDD());
Буфер.ЗаписатьЦелое32(0, 134695760);
Буфер.ЗаписатьЦелое32(4, CRC32);
Буфер.ЗаписатьЦелое32(8, РазмерСжатыхДанных);
Буфер.ЗаписатьЦелое32(12, РазмерНесжатыхДанных);
Возврат Буфер;
КонецФункции
Функция ZipCDH(CRC32, РазмерСжатыхДанных, РазмерНесжатыхДанных)
// Central directory header
Буфер = Новый БуферДвоичныхДанных(ZipРазмерCDH());
Буфер.ЗаписатьЦелое32(0, 33639248); // signature 0x02014b50
Буфер.ЗаписатьЦелое16(4, 798); // version made by
Буфер.ЗаписатьЦелое16(6, 20); // version needed to extract
Буфер.ЗаписатьЦелое16(8, 10); // bit flags
Буфер.ЗаписатьЦелое16(10, 8); // compression method
Буфер.ЗаписатьЦелое16(12, 0); // time
Буфер.ЗаписатьЦелое16(14, 0); // date
Буфер.ЗаписатьЦелое32(16, CRC32); // crc-32
Буфер.ЗаписатьЦелое32(20, РазмерСжатыхДанных); // compressed size
Буфер.ЗаписатьЦелое32(24, РазмерНесжатыхДанных); // uncompressed size
Буфер.ЗаписатьЦелое16(28, 4); // file name length
Буфер.ЗаписатьЦелое16(30, 0); // extra field length
Буфер.ЗаписатьЦелое16(32, 0); // file comment length
Буфер.ЗаписатьЦелое16(34, 0); // disk number start
Буфер.ЗаписатьЦелое16(36, 0); // internal file attributes
Буфер.ЗаписатьЦелое32(38, 2176057344); // external file attributes
Буфер.ЗаписатьЦелое32(42, 0); // relative offset of local header
Буфер.Записать(46, ПолучитьБуферДвоичныхДанныхИзСтроки("data", "ascii", Ложь));
Возврат Буфер;
КонецФункции
Функция ZipEOCD(РазмерСжатыхДанных)
// End of central directory
РазмерCDH = 50;
Буфер = Новый БуферДвоичныхДанных(ZipРазмерEOCD());
Буфер.ЗаписатьЦелое32(0, 101010256); // signature 0x06054b50
Буфер.ЗаписатьЦелое16(4, 0); // number of this disk
Буфер.ЗаписатьЦелое16(6, 0); // number of the disk with the start of the central directory
Буфер.ЗаписатьЦелое16(8, 1); // total number of entries in the central directory on this disk
Буфер.ЗаписатьЦелое16(10, 1); // total number of entries in the central directory
Буфер.ЗаписатьЦелое32(12, РазмерCDH); // size of the central directory
// offset of start of central directory with respect to the starting disk number
Буфер.ЗаписатьЦелое32(16, ZipРазмерLFH() + РазмерСжатыхДанных + ZipРазмерDD());
Буфер.ЗаписатьЦелое16(20, 0); // the starting disk number
Возврат Буфер;
КонецФункции
КонецОбласти
Область СлужебныеСтруктурыGZip
// Описание структур см. здесь https://www.ietf.org/rfc/rfc1952.txt
Функция GZipРазмерHeader()
Возврат 10;
КонецФункции
Функция GZipРазмерFooter()
Возврат 8;
КонецФункции
Функция GZipHeader()
Буфер = Новый БуферДвоичныхДанных(GZipРазмерHeader());
Буфер[0] = 31; // ID1 0x1f
Буфер[1] = 139; // ID2 0x8b
Буфер[2] = 8; // compression method (08 for DEFLATE)
Буфер[3] = 0; // header flags
Буфер.ЗаписатьЦелое32(4, 0); // timestamp
Буфер[8] = 0; // compression flags
Буфер[9] = 255; // operating system ID
Возврат Буфер;
КонецФункции
Функция GZipFooter(CRC32, РазмерИсходныхДанных)
Буфер = Новый БуферДвоичныхДанных(GZipРазмерFooter());
Буфер.ЗаписатьЦелое32(0, CRC32);
Буфер.ЗаписатьЦелое32(4, РазмерИсходныхДанных);
Возврат Буфер;
КонецФункции
КонецОбласти
Функция ПрочитатьZip(СжатыеДанные, ТекстОшибки = Неопределено)
Если МобильноеПриложениеСервер Тогда
ВызватьИсключение(НСтр("ru = 'Работа с Zip-файлами в мобильной платформе не поддерживается'"));
Иначе
Каталог = ПолучитьИмяВременногоФайла();
ЧтениеZip = Новый ЧтениеZipФайла(СжатыеДанные);
ИмяФайла = ЧтениеZip.Элементы[0].Имя;
Попытка
ЧтениеZip.Извлечь(ЧтениеZip.Элементы[0], Каталог, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
Исключение
// Игнорируем проверку целостности архива, просто читаем результат
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
ЧтениеZip.Закрыть();
Результат = Новый ДвоичныеДанные(Каталог + ПолучитьРазделительПути() + ИмяФайла);
УдалитьФайлы(Каталог);
Возврат Результат;
КонецЕсли
КонецФункции
Функция ЗаписатьZip(Данные)
Если МобильноеПриложениеСервер Тогда
ВызватьИсключение(НСтр("ru = 'Работа с Zip-файлами в мобильной платформе не поддерживается'"));
Иначе
ВременныйФайл = ПолучитьИмяВременногоФайла(".bin");
Данные.Записать(ВременныйФайл);
ПотокZip = Новый ПотокВПамяти;
ЗаписьZip = Новый ЗаписьZipФайла(ПотокZip);
ЗаписьZip.Добавить(ВременныйФайл);
ЗаписьZip.Записать();
УдалитьФайлы(ВременныйФайл);
Возврат ПотокZip.ЗакрытьИПолучитьДвоичныеДанные();
КонецЕсли
КонецФункции
КонецОбласти
Область ПараметрыПоУмолчанию
Функция ЗаголовкиПоУмолчанию()
Заголовки = Новый Соответствие;
Если МобильноеПриложениеСервер Тогда
Заголовки.Вставить("Accept-Encoding", "identity");
Иначе
Заголовки.Вставить("Accept-Encoding", "gzip");
КонецЕсли
Заголовки.Вставить("Accept", "*/*");
Заголовки.Вставить("Connection", "keep-alive");
Возврат Заголовки;
КонецФункции
Функция МаксимальноеКоличествоПеренаправлений()
Возврат 30;
КонецФункции
Функция СтандартныйТаймаут()
Возврат 30;
КонецФункции
Функция ПараметрыПреобразованияJSONПоУмолчанию()
ПараметрыПреобразованияПоУмолчанию = Новый Структура;
ПараметрыПреобразованияПоУмолчанию.Вставить("ПрочитатьВСоответствие", Истина);
ПараметрыПреобразованияПоУмолчанию.Вставить("ФорматДатыJSON", ФорматДатыJSON.ISO);
ПараметрыПреобразованияПоУмолчанию.Вставить("ИменаСвойствСоЗначениямиДата", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("ВариантЗаписиДатыJSON", ВариантЗаписиДатыJSON.ЛокальнаяДата);
ПараметрыПреобразованияПоУмолчанию.Вставить("ИмяФункцииПреобразования", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("МодульФункцииПреобразования", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("ДополнительныеПараметрыФункцииПреобразования", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("ИмяФункцииВосстановления", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("МодульФункцииВосстановления", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("ДополнительныеПараметрыФункцииВосстановления", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("ИменаСвойствДляОбработкиВосстановления", Неопределено);
ПараметрыПреобразованияПоУмолчанию.Вставить("МаксимальнаяВложенность", 500);
Возврат ПараметрыПреобразованияПоУмолчанию;
КонецФункции
Функция ПараметрыЗаписиJSONПоУмолчанию()
ПараметрыЗаписиJSONПоУмолчанию = Новый Структура;
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ПереносСтрок", ПереносСтрокJSON.Авто);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("СимволыОтступа", " ");
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ИспользоватьДвойныеКавычки", Истина);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранированиеСимволов", ЭкранированиеСимволовJSON.Нет);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьУгловыеСкобки", Ложь);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьРазделителиСтрок", Истина);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьАмперсанд", Ложь);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьОдинарныеКавычки", Ложь);
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьСлеш", Ложь);
Возврат ПараметрыЗаписиJSONПоУмолчанию;
КонецФункции
КонецОбласти
Область КодыСостояний
Функция ОписанияКодовСостоянийHTTP()
Коды = Новый Массив;
Коды.Добавить(НовыйКодHTTP(100, "Продолжай_100", "Continue"));
Коды.Добавить(НовыйКодHTTP(101, "ПереключениеПротокола_101", "Switching Protocols"));
Коды.Добавить(НовыйКодHTTP(102, "ИдетОбработка_102", "Processing"));
Коды.Добавить(НовыйКодHTTP(103, "РанняяМетаинформация_103", "Early Hints"));
Коды.Добавить(НовыйКодHTTP(200, "ОК_200", "OK"));
Коды.Добавить(НовыйКодHTTP(201, "Создано_201", "Created"));
Коды.Добавить(НовыйКодHTTP(202, "Принято_202", "Accepted"));
Коды.Добавить(НовыйКодHTTP(203, "ИнформацияНеАвторитетна_203", "Non-Authoritative Information"));
Коды.Добавить(НовыйКодHTTP(204, "НетСодержимого_204", "No Content"));
Коды.Добавить(НовыйКодHTTP(205, "СброситьСодержимое_205", "Reset Content"));
Коды.Добавить(НовыйКодHTTP(206, "ЧастичноеСодержимое_206", "Partial Content"));
Коды.Добавить(НовыйКодHTTP(207, "Многостатусный_207", "Multi-Status"));
Коды.Добавить(НовыйКодHTTP(208, "УжеСообщалось_208", "Already Reported"));
Коды.Добавить(НовыйКодHTTP(226, "ИспользованоIM_226", "IM Used"));
Коды.Добавить(НовыйКодHTTP(300, "МножествоВыборов_300", "Multiple Choices"));
Коды.Добавить(НовыйКодHTTP(301, "ПеремещеноНавсегда_301", "Moved Permanently"));
Коды.Добавить(НовыйКодHTTP(302, "ПеремещеноВременно_302", "Moved Temporarily"));
Коды.Добавить(НовыйКодHTTP(303, "СмотретьДругое_303", "See Other"));
Коды.Добавить(НовыйКодHTTP(304, "НеИзменялось_304", "Not Modified"));
Коды.Добавить(НовыйКодHTTP(305, "ИспользоватьПрокси_305", "Use Proxy"));
Коды.Добавить(НовыйКодHTTP(307, "ВременноеПеренаправление_307", "Temporary Redirect"));
Коды.Добавить(НовыйКодHTTP(308, "ПостоянноеПеренаправление_308", "Permanent Redirect"));
Коды.Добавить(НовыйКодHTTP(400, "НеверныйЗапрос_400", "Bad Request"));
Коды.Добавить(НовыйКодHTTP(401, "НеАвторизован_401", "Unauthorized"));
Коды.Добавить(НовыйКодHTTP(402, "НеобходимаОплата_402", "Payment Required"));
Коды.Добавить(НовыйКодHTTP(403, "Запрещено_403", "Forbidden"));
Коды.Добавить(НовыйКодHTTP(404, "НеНайдено_404", "Not Found"));
Коды.Добавить(НовыйКодHTTP(405, "МетодНеПоддерживается_405", "Method Not Allowed"));
Коды.Добавить(НовыйКодHTTP(406, "Неприемлемо_406", "Not Acceptable"));
Коды.Добавить(НовыйКодHTTP(407, "НеобходимаАутентификацияПрокси_407", "Proxy Authentication Required"));
Коды.Добавить(НовыйКодHTTP(408, "ИстеклоВремяОжидания_408", "Request Timeout"));
Коды.Добавить(НовыйКодHTTP(409, "Конфликт_409", "Conflict"));
Коды.Добавить(НовыйКодHTTP(410, "Удален_410", "Gone"));
Коды.Добавить(НовыйКодHTTP(411, "НеобходимаДлина_411", "Length Required"));
Коды.Добавить(НовыйКодHTTP(412, "УсловиеЛожно_412", "Precondition Failed"));
Коды.Добавить(НовыйКодHTTP(413, "ПолезнаяНагрузкаСлишкомВелика_413", "Payload Too Large"));
Коды.Добавить(НовыйКодHTTP(414, "СлишкомДлинныйURI_414", "URI Too Long"));
Коды.Добавить(НовыйКодHTTP(415, "НеподдерживаемыйТипДанных_415", "Unsupported Media Type"));
Коды.Добавить(НовыйКодHTTP(416, "ДиапазонНеДостижим_416", "Range Not Satisfiable"));
Коды.Добавить(НовыйКодHTTP(417, "ОжиданиеНеУдалось_417", "Expectation Failed"));
Коды.Добавить(НовыйКодHTTP(419, "ОшибкаПроверкиCSRF_419", "Authentication Timeout"));
Коды.Добавить(НовыйКодHTTP(421, "НеправильноНаправленныйЗапрос_421", "Misdirected Request"));
Коды.Добавить(НовыйКодHTTP(422, "НеобрабатываемыйЭкземпляр_422", "Unprocessable Entity"));
Коды.Добавить(НовыйКодHTTP(423, "Заблокировано_423", "Locked"));
Коды.Добавить(НовыйКодHTTP(424, "НевыполненнаяЗависимость_424", "Failed Dependency"));
Коды.Добавить(НовыйКодHTTP(425, "СлишкомРано_425", "Too Early"));
Коды.Добавить(НовыйКодHTTP(426, "НеобходимоОбновление_426", "Upgrade Required"));
Коды.Добавить(НовыйКодHTTP(428, "НеобходимоПредусловие_428", "Precondition Required"));
Коды.Добавить(НовыйКодHTTP(429, "СлишкомМногоЗапросов_429", "Too Many Requests"));
Коды.Добавить(НовыйКодHTTP(431, "ПоляЗаголовкаЗапросаСлишкомБольшие_431", "Request Header Fields Too Large"));
Коды.Добавить(НовыйКодHTTP(449, "ПовторитьС_449", "Retry With"));
Коды.Добавить(НовыйКодHTTP(451, "НедоступноПоЮридическимПричинам_451", "Unavailable For Legal Reasons"));
Коды.Добавить(НовыйКодHTTP(499, "КлиентЗакрылСоединение_499", "Client Closed Request"));
Коды.Добавить(НовыйКодHTTP(500, "ВнутренняяОшибкаСервера_500", "Internal Server Error"));
Коды.Добавить(НовыйКодHTTP(501, "НеРеализовано_501", "Not Implemented"));
Коды.Добавить(НовыйКодHTTP(502, "ОшибочныйШлюз_502", "Bad Gateway"));
Коды.Добавить(НовыйКодHTTP(503, "СервисНедоступен_503", "Service Unavailable"));
Коды.Добавить(НовыйКодHTTP(504, "ШлюзНеОтвечает_504", "Gateway Timeout"));
Коды.Добавить(НовыйКодHTTP(505, "ВерсияHTTPНеПоддерживается_505", "HTTP Version Not Supported"));
Коды.Добавить(НовыйКодHTTP(506, "ВариантТожеПроводитСогласование_506", "Variant Also Negotiates"));
Коды.Добавить(НовыйКодHTTP(507, "ПереполнениеХранилища_507", "Insufficient Storage"));
Коды.Добавить(НовыйКодHTTP(508, "ОбнаруженоБесконечноеПеренаправление_508", "Loop Detected"));
Коды.Добавить(НовыйКодHTTP(509, "ИсчерпанаПропускнаяШиринаКанала_509", "Bandwidth Limit Exceeded"));
Коды.Добавить(НовыйКодHTTP(510, "НеРасширено_510", "Not Extended"));
Коды.Добавить(НовыйКодHTTP(511, "ТребуетсяСетеваяАутентификация_511", "Network Authentication Required"));
Коды.Добавить(НовыйКодHTTP(520, "НеизвестнаяОшибка_520", "Unknown Error"));
Коды.Добавить(НовыйКодHTTP(521, "ВебСерверНеРаботает_521", "Web Server Is Down"));
Коды.Добавить(НовыйКодHTTP(522, "СоединениеНеОтвечает_522", "Connection Timed Out"));
Коды.Добавить(НовыйКодHTTP(523, "ИсточникНедоступен_523", "Origin Is Unreachable"));
Коды.Добавить(НовыйКодHTTP(524, "ВремяОжиданияИстекло_524", "A Timeout Occurred"));
Коды.Добавить(НовыйКодHTTP(525, "КвитированиеSSНеУдалось_525", "SSL Handshake Failed"));
Коды.Добавить(НовыйКодHTTP(526, "НедействительныйСертификатSSL_526", "Invalid SSL Certificate"));
Возврат Коды;
КонецФункции
Функция НовыйКодHTTP(Код, Ключ, Описание)
Возврат Новый Структура("Код, Ключ, Описание", Код, Ключ, Описание);
КонецФункции
Функция ЭтоКодСостоянияПриКоторомНужноУчитыватьЗаголовокRetryAfter(КодСостояния)
Коды = КодыСостоянияHTTP();
Возврат КодСостояния = Коды.ПолезнаяНагрузкаСлишкомВелика_413
ИЛИ КодСостояния = Коды.СлишкомМногоЗапросов_429
ИЛИ КодСостояния = Коды.СервисНедоступен_503;
КонецФункции
КонецОбласти
Область Прочие
Функция ОпределитьХешФункцию(Знач Алгоритм)
Алгоритм = ВРег(Алгоритм);
Если Не ЗначениеЗаполнено(Алгоритм) ИЛИ Алгоритм = "MD5" ИЛИ Алгоритм = "MD5-SESS" Тогда
АлгоритмХеширования = ХешФункция.MD5;
ИначеЕсли Алгоритм = "SHA" Тогда
АлгоритмХеширования = ХешФункция.SHA1;
ИначеЕсли Алгоритм = "SHA-256" Тогда
АлгоритмХеширования = ХешФункция.SHA256;
Иначе
АлгоритмХеширования = Неопределено;
КонецЕсли;
Возврат АлгоритмХеширования;
КонецФункции
Функция ХешированиеДанных(Знач Алгоритм, Знач Данные)
Если ТипЗнч(Данные) = Тип("Строка") Тогда
Данные = ПолучитьДвоичныеДанныеИзСтроки(Данные, КодировкаТекста.UTF8, Ложь);
КонецЕсли;
Хеширование = Новый ХешированиеДанных(Алгоритм);
Хеширование.Добавить(Данные);
Возврат НРег(ПолучитьHexСтрокуИзДвоичныхДанных(Хеширование.ХешСумма));
КонецФункции
Процедура Приостановить(ДлительностьОстановкиВСекундах)
// Когда-нибудь в платформе сделают паузу и это можно будет выкинуть
Если ДлительностьОстановкиВСекундах < 1 Тогда
Возврат;
КонецЕсли;
ТекущаяДата = ТекущаяУниверсальнаяДата();
ЖдатьДо = ТекущаяДата + ДлительностьОстановкиВСекундах;
// BSLLS:UsingHardcodeNetworkAddress-off
ЛокальныйХост = "127.0.0.0";
КакойНибудьСвободныйПорт = 56476;
// BSLLS:UsingHardcodeNetworkAddress-on
Пока ТекущаяДата < ЖдатьДо Цикл
Таймаут = ЖдатьДо - ТекущаяДата;
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
Попытка
Соединение = Новый HTTPСоединение(
ЛокальныйХост, КакойНибудьСвободныйПорт, Неопределено, Неопределено, Новый ИнтернетПрокси(Ложь), Таймаут);
Соединение.Получить(Новый HTTPЗапрос("/does_not_matter"));
Исключение
РеальныйТаймаут = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало;
КонецПопытки;
МинимальныйТаймаутВМиллисекундах = 1000;
Если РеальныйТаймаут < МинимальныйТаймаутВМиллисекундах Тогда
ВызватьИсключение(НСтр("ru = 'Процедура Приостановить не работает должным образом'"));
КонецЕсли;
ТекущаяДата = ТекущаяУниверсальнаяДата();
КонецЦикла;
КонецПроцедуры
Функция РассчитатьДлительностьПриостановки(Повтор, КоэффициентЭкспоненциальнойЗадержки, ЗаголовокRetryAfter, Остаток)
Если ЗаголовокRetryAfter <> Ложь Тогда
Длительность = ЧислоИзСтроки(ЗаголовокRetryAfter);
Если Длительность = 0 Тогда
Дата = ДатаИзСтрокиRFC7231(ЗаголовокRetryAfter);
Если ЗначениеЗаполнено(Дата) Тогда
Длительность = Дата - ТекущаяУниверсальнаяДата();
КонецЕсли;
Если Длительность <= 0 Тогда
Длительность = 1;
КонецЕсли
КонецЕсли;
Иначе
Длительность = КоэффициентЭкспоненциальнойЗадержки * Pow(2, Повтор - 1);
КонецЕсли;
Длительность = Мин(Длительность, Остаток);
Если Длительность < 0 Тогда
Длительность = 0;
КонецЕсли;
Возврат Длительность;
КонецФункции
КонецОбласти
Область УниверсальныеСтруктурыДанных
Функция ВыбратьЗначение(ОсновноеЗначение, ДополнительныеЗначения, Ключ, ЗначениеПоУмолчанию)
Если ОсновноеЗначение <> Неопределено Тогда
Возврат ОсновноеЗначение;
КонецЕсли;
Значение = ЗначениеПоКлючу(ДополнительныеЗначения, Ключ);
Если Значение <> Неопределено Тогда
Возврат Значение;
КонецЕсли;
Возврат ЗначениеПоУмолчанию;
КонецФункции
Функция ЗначениеПоКлючу(Структура, Ключ, ЗначениеПоУмолчанию = Неопределено)
Если ТипЗнч(Структура) = Тип("Структура") И Структура.Свойство(Ключ) Тогда
Значение = Структура[Ключ];
ИначеЕсли ТипЗнч(Структура) = Тип("Соответствие") И Структура.Получить(Ключ) <> Неопределено Тогда
Значение = Структура.Получить(Ключ);
Иначе
Значение = ЗначениеПоУмолчанию;
КонецЕсли;
Возврат Значение;
КонецФункции
КонецОбласти
Область РаботаСоСтроками
Функция ЧислоИзСтроки(Знач Строка) Экспорт
ОписаниеТипа = Новый ОписаниеТипов("Число");
Возврат ОписаниеТипа.ПривестиЗначение(Строка);
КонецФункции
Функция ДатаИзСтроки(Знач Строка) Экспорт
КвалификаторДаты = Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя);
ОписаниеТипа = Новый ОписаниеТипов("Дата", Неопределено, Неопределено, КвалификаторДаты);
Возврат ОписаниеТипа.ПривестиЗначение(Строка);
КонецФункции
Функция ДатаИзСтрокиRFC7231(Знач Строка) Экспорт
Разделители = ",-:/\.";
Для Индекс = 1 По СтрДлина(Разделители) Цикл
Разделитель = Сред(Разделители, Индекс, 1);
Строка = СтрЗаменить(Строка, Разделитель, " ");
КонецЦикла;
Строка = СтрЗаменить(Строка, " ", " ");
СоставляющиеДаты = СтрРазделить(Строка, " ");
Если СоставляющиеДаты.Количество() < 7 Тогда
Возврат '00010101';
КонецЕсли;
МесяцСтр = СоставляющиеДаты[2];
Месяцы = СтрРазделить("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", ",");
Месяц = Месяцы.Найти(МесяцСтр);
Если Месяц = Неопределено Тогда
Возврат '00010101';
КонецЕсли;
Дата = СоставляющиеДаты[3] + Формат(Месяц + 1, "ЧЦ=2; ЧВН=;") + СоставляющиеДаты[1];
Время = СоставляющиеДаты[4] + СоставляющиеДаты[5] + СоставляющиеДаты[6];
Возврат ДатаИзСтроки(Дата + Время);
КонецФункции
Процедура РазбитьСтрокуПоРазделителю(ИзвлекаемаяЧасть, ОстальнаяЧасть, Разделитель, Инверсия = Ложь)
Индекс = СтрНайти(ОстальнаяЧасть, Разделитель);
Если Индекс Тогда
ИзвлекаемаяЧасть = Лев(ОстальнаяЧасть, Индекс - 1);
ОстальнаяЧасть = Сред(ОстальнаяЧасть, Индекс + СтрДлина(Разделитель));
Если Инверсия Тогда
ДляОбмена = ИзвлекаемаяЧасть;
ИзвлекаемаяЧасть = ОстальнаяЧасть;
ОстальнаяЧасть = ДляОбмена;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция РазделитьПоПервомуНайденномуРазделителю(Строка, Разделители)
МинимальныйИндекс = СтрДлина(Строка);
ПервыйРазделитель = "";
Для Каждого Разделитель Из Разделители Цикл
Индекс = СтрНайти(Строка, Разделитель);
Если Индекс = 0 Тогда
Продолжить;
КонецЕсли;
Если Индекс < МинимальныйИндекс Тогда
МинимальныйИндекс = Индекс;
ПервыйРазделитель = Разделитель;
КонецЕсли;
КонецЦикла;
Результат = Новый Массив;
Если ЗначениеЗаполнено(ПервыйРазделитель) Тогда
Результат.Добавить(Лев(Строка, МинимальныйИндекс - 1));
Результат.Добавить(Сред(Строка, МинимальныйИндекс + СтрДлина(ПервыйРазделитель)));
Результат.Добавить(ПервыйРазделитель);
Иначе
Результат.Добавить(Строка);
Результат.Добавить("");
Результат.Добавить(Неопределено);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция РазбитьСтрокуПоСтроке(Знач Строка, Разделитель)
Результат = Новый Массив;
Пока Истина Цикл
Позиция = СтрНайти(Строка, Разделитель);
Если Позиция = 0 И ЗначениеЗаполнено(Строка) Тогда
Результат.Добавить(Строка);
Прервать;
КонецЕсли;
ПерваяЧасть = Лев(Строка, Позиция - СтрДлина(Разделитель) + 1);
Результат.Добавить(ПерваяЧасть);
Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ДобавитьЛидирующуюТочку(Знач Домен)
Если Не СтрНачинаетсяС(Домен, ".") Тогда
Домен = "." + Домен;
КонецЕсли;
Возврат Домен;
КонецФункции
Функция ВырезатьТекст(Текст, МаксимальнаяДлинаТекста = 1000)
Если НайтиНедопустимыеСимволыXML(Текст) Тогда
Возврат НСтр("ru ='<Данные>'");
КонецЕсли;
Если СтрДлина(Текст) <= МаксимальнаяДлинаТекста Тогда
Результат = Текст;
Иначе
ПоловинаМаксимальнойДлиныТекста = МаксимальнаяДлинаТекста / 2;
Результат = Лев(Текст, ПоловинаМаксимальнойДлиныТекста);
Результат = Результат + Символы.ПС + "..." + Символы.ПС;
Результат = Результат + Прав(Текст, ПоловинаМаксимальнойДлиныТекста);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция Объединить(ГлавныйИсточник, ДополнительныйИсточник)
Результат = ГлавныйИсточник;
Дополнить(ГлавныйИсточник, ДополнительныйИсточник);
Возврат Результат;
КонецФункции
Функция Скопировать(Источник)
#Если МобильноеПриложениеСервер Тогда
ПараметрыПреобразования = Неопределено;
Если ТипЗнч(Источник) = Тип("Структура") Тогда
ПараметрыПреобразования = Новый Структура("ПрочитатьВСоответствие", Ложь);
КонецЕсли;
Возврат JsonВОбъект(ОбъектВJson(Источник),, ПараметрыПреобразования);
#Иначе
Возврат ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(Источник));
#КонецЕсли
КонецФункции
Процедура Дополнить(Приемник, Источник)
Если Источник = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого ЭлементИсточника Из Источник Цикл
ПараметрНайден = Ложь;
Если ТипЗнч(Приемник) = Тип("Соответствие") Тогда
ПараметрНайден = Приемник.Получить(ЭлементИсточника.Ключ) <> Неопределено;
КонецЕсли;
Если ТипЗнч(Приемник) = Тип("Структура") Тогда
ПараметрНайден = Приемник.Свойство(ЭлементИсточника.Ключ);
КонецЕсли;
Если Не ПараметрНайден ИЛИ ПараметрНайден И ЭлементИсточника.Значение <> Неопределено Тогда
Приемник.Вставить(ЭлементИсточника.Ключ, ЭлементИсточника.Значение);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
