Created
November 11, 2020 18:15
-
-
Save Kirill/590a855beb850cb184587c8916d56d4f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Коннектор: удобный HTTP-клиент для 1С:Предприятие 8 | |
// | |
// Copyright 2017-2020 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: [email protected] | |
// Версия: 2.1.3 | |
// | |
// Требования: платформа 1С версии 8.3.10 и выше | |
#Область ПрограммныйИнтерфейс | |
#Область МетодыHTTP | |
#Область МетодыОбщегоНазначения | |
// Отправляет GET запрос | |
// | |
// Параметры: | |
// URL - Строка - URL ресурса, к которому будет отправлен запрос. | |
// ПараметрыЗапроса - Структура, Соответствие - параметры, которые будут отправлены в URL (часть после ?). | |
// См. описание Сессия.ПараметрыЗапроса. | |
// ДополнительныеПараметры - Структура - см. описание параметра в ВызватьМетод. | |
// Сессия - Структура - см. возвращаемое значение функции СоздатьСессию. | |
// | |
// Возвращаемое значение: | |
// Структура - ответ на выполненный запрос. См. описание возвращаемого значения в ВызватьМетод. | |
// | |
Функция 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, ДополнительныеПараметры); | |
КонецФункции | |
#КонецОбласти | |
#Область УпрощенныеМетодыДляРаботыСЗапросамиВФормате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); | |
КонецФункции | |
#КонецОбласти | |
// Отправляет данные на указанный адрес для обработки с использованием указанного HTTP-метода. | |
// | |
// Параметры: | |
// Метод - Строка - имя HTTP-метода для запроса. | |
// URL - Строка - URL ресурса, к которому будет отправлен запрос. | |
// ДополнительныеПараметры - Структура - позволяет задать дополнительные параметры: | |
// *Заголовки - Соответствие - см. описание Сессия.Заголовки. | |
// *Аутентификация - Структура - см. описание Сессия.Аутентификация | |
// *Прокси - ИнтернетПрокси - см. описание Сессия.Прокси. | |
// *ПараметрыЗапроса - Структура, Соответствие - см. описание Сессия.ПараметрыЗапроса. | |
// *ПроверятьSSL - Булево - см. описание Сессия.ПроверятьSSL. | |
// *КлиентскийСертификатSSL - см. описание Сессия.КлиентскийСертификатSSL. | |
// *Cookies - Массив - см. описание Сессия.Cookies. | |
// *Таймаут - Число - время ожидания осуществляемого соединения и операций, в секундах. | |
// Значение по умолчанию - 30 сек. | |
// *РазрешитьПеренаправление - Булево - Истина - редиректы будут автоматически разрешены. | |
// Ложь - будет выполнен только один запрос к серверу. | |
// *Json - Структура, Соответствие - данные, которые необходимо сериализовать в JSON. | |
// *ПараметрыПреобразованияJSON - Структура - задает параметры преобразования JSON: | |
// **ПрочитатьВСоответствие - Булево - Если Истина, чтение объекта JSON будет выполнено в Соответствие. | |
// Если Ложь, объекты будут считываться в объект типа Структура. | |
// **ФорматДатыJSON - ФорматДатыJSON - формат, в котором представлена дата в строке, | |
// подлежащей преобразованию. | |
// **ИменаСвойствСоЗначениямиДата - Массив, Строка - имена свойств JSON, | |
// для которых нужно вызывать восстановление даты из строки. | |
// *ПараметрыЗаписиJSON - Структура - параметры, используемые при записи объекта JSON. | |
// См. в синтаксис-помощнике описание ПараметрыЗаписиJSON. | |
// *Данные - Структура, Соответствие - поля формы, которые необходимо отправить в запрос: | |
// **<Ключ> - Строка - имя поля. | |
// **<Значение> - Строка - значение поля. | |
// - Строка, ДвоичныеДанные - произвольные данные, которые необходимо отправить в запросе. | |
// *Файлы - Структура, Массив - файлы, которые необходимо отправить в запросе: | |
// **Имя - Строка - имя поля формы. | |
// **Данные - ДвоичныеДанные - двоичные данные файла. | |
// **ИмяФайла - Строка - имя файла. | |
// **Тип - Строка - MIME-тип файла. | |
// **Заголовки - Соответствие, Неопределено - HTTP заголовки запроса. | |
// *МаксимальноеКоличествоПовторов - Число - количество повторных попыток соединения/отправки запроса. | |
// Между попытками выполняется задержка, растущая по экспоненте. | |
// Но если код состояния один из 413, 429, 503 | |
// и в ответе есть заголовок Retry-After, | |
// то время задержки формируется из значения этого заголовка | |
// Значение по умолчанию: 0 - повторы не выполняются. | |
// *МаксимальноеВремяПовторов - Число - максимальное общее время (в секундах) отправки запроса с учетом повторов. | |
// Значение по умолчанию: 600. | |
// *КоэффициентЭкспоненциальнойЗадержки - Число - коэффициент изменения экспоненциальной задержки. | |
// 1 формирует последовательность задержек: 1, 2, 4, 8 и т.д. | |
// 2 формируется последовательность задержек: 2, 4, 8, 16 и т.д. | |
// ... | |
// Значение по умолчанию: 1. | |
// *ПовторятьДляКодовСостояний - Неопределено - повторы будут выполняться для кодов состояний >= 500. | |
// - Массив - повторы будут выполняться для конкретных кодов состояний. | |
// Значение по умолчанию: Неопределено. | |
// Сессия - Структура - см. возвращаемое значение функции СоздатьСессию. | |
// | |
// Возвращаемое значение: | |
// Структура - ответ на выполненный запрос: | |
// *ВремяВыполнения - Число - время выполнения запроса в миллисекундах. | |
// *Cookies - Соответствие - cookies полученные с сервера. | |
// *Заголовки - Соответствие - HTTP заголовки ответа. | |
// *ЭтоПостоянныйРедирект - Булево - признак постоянного редиректа. | |
// *ЭтоРедирект - Булево - признак редиректа. | |
// *Кодировка - Строка - кодировка текста ответа. | |
// *Тело - ДвоичныеДанные - тело ответа. | |
// *КодСостояния - Число - код состояния ответа. | |
// *URL - Строка - итоговый URL, по которому был выполнен запрос. | |
// | |
Функция ВызватьМетод(Метод, URL, ДополнительныеПараметры = Неопределено, Сессия = Неопределено) Экспорт | |
ТекущаяСессия = ТекущаяСессия(Сессия); | |
ЗаполнитьДополнительныеДанные(ДополнительныеПараметры, Неопределено, Неопределено, Неопределено); | |
Возврат ВызватьHTTPМетод(ТекущаяСессия, Метод, URL, ДополнительныеПараметры); | |
КонецФункции | |
// Создает объект для хранения параметров сессии. | |
// | |
// Возвращаемое значение: | |
// Структура - параметры сессии: | |
// *Заголовки - Соответствие - HTTP заголовки запроса. | |
// *Аутентификация - Структура - параметры аутентификации запроса. | |
// *ИспользоватьАутентификациюОС - Булево - включает использование аутентификации NTLM или Negotiate. | |
// Значение по умолчанию: Ложь. | |
// *Тип - Строка - тип аутентификации. Для Basic Тип можно не указывать. | |
// Если Тип = Digest или Basic: | |
// *Пользователь - Строка - имя пользователя. | |
// *Пароль - Строка - пароль пользователя. | |
// Если Тип = AWS4-HMAC-SHA256: | |
// *ИдентификаторКлючаДоступа - Строка - идентификатор ключа доступа. | |
// *СекретныйКлюч - Строка - секретный ключ. | |
// *Сервис - Строка - сервис, к которому выполняется подключение. | |
// *Регион - Строка - регион, к которому выполняется подключение. | |
// *Прокси - ИнтернетПрокси - параметры прокси, которые будут использованы при отправке запроса. | |
// Значение по умолчанию: Неопределено. При этом если в конфигурации используется БСП, | |
// то значения прокси будет взято из БСП. | |
// *ПараметрыЗапроса - Структура, Соответствие - параметры, которые будут отправлены в URL (часть после ?): | |
// *<Ключ> - Строка - ключ параметра в URL. | |
// *<Значение> - Строка - значение параметра URL | |
// - Массив - сформирует строку из нескольких параметров: key=value1&key=value2 и т.д. | |
// *ПроверятьSSL - Булево - Ложь - проверка сертификата сервера не выполняется. | |
// - Истина - используется значение СертификатыУдостоверяющихЦентровОС. | |
// - СертификатыУдостоверяющихЦентровФайл - см. в синтаксис-помощнике описание | |
// СертификатыУдостоверяющихЦентровФайл. | |
// Значение по умолчанию: Истина. | |
// *КлиентскийСертификатSSL - СертификатКлиентаФайл - см. в синтаксис-помощнике описание СертификатКлиентаФайл. | |
// - СертификатКлиентаWindows - см. в синтаксис-помощнике описание | |
// СертификатКлиентаWindows. | |
// Значение по умолчанию: Неопределено. | |
// *МаксимальноеКоличествоПеренаправлений - Число - максимальное количество редиректов. Защита от зацикливания. | |
// Значение по умолчанию: | |
// см. функцию МаксимальноеКоличествоПеренаправлений | |
// *Cookies - Соответствие - хранилище cookies. | |
// | |
Функция СоздатьСессию() Экспорт | |
Сессия = Новый Структура; | |
Сессия.Вставить("Заголовки", ЗаголовкиПоУмолчанию()); | |
Сессия.Вставить("Аутентификация", Неопределено); | |
Сессия.Вставить("Прокси", Неопределено); | |
Сессия.Вставить("ПараметрыЗапроса", Новый Структура); | |
Сессия.Вставить("ПроверятьSSL", Истина); | |
Сессия.Вставить("КлиентскийСертификатSSL", Неопределено); | |
Сессия.Вставить("МаксимальноеКоличествоПеренаправлений", МаксимальноеКоличествоПеренаправлений()); | |
Сессия.Вставить("Cookies", Новый Соответствие); | |
Сессия.Вставить("СлужебныеДанные", Новый Структура("ПараметрыDigest")); | |
Возврат Сессия; | |
КонецФункции | |
#КонецОбласти | |
#Область ФорматыОтветов | |
// Возвращает ответ сервера в виде десериализованного значения JSON. | |
// | |
// Параметры: | |
// Ответ - Структура - ответ сервера на отправленный запрос. | |
// См. описание возвращаемого значения ВызватьМетод. | |
// ПараметрыПреобразованияJSON - Структура - задает параметры преобразования JSON. | |
// *ПрочитатьВСоответствие - Булево - Если Истина, чтение объекта JSON будет выполнено в Соответствие. | |
// Если Ложь, объекты будут считываться в объект типа Структура. | |
// *ФорматДатыJSON - ФорматДатыJSON - формат, в котором представлена дата в строке, подлежащей преобразованию. | |
// *ИменаСвойствСоЗначениямиДата - Массив, Строка - имена свойств JSON, | |
// для которых нужно вызывать восстановление даты из строки. | |
// | |
// Возвращаемое значение: | |
// Соответствие - ответ сервера в виде десериализованного значения JSON. | |
// Если ПараметрыПреобразования.ПрочитатьВСоответствие = Истина (по умолчанию). | |
// Структура - если ПараметрыПреобразования.ПрочитатьВСоответствие = Ложь. | |
// | |
Функция КакJson(Ответ, ПараметрыПреобразованияJSON = Неопределено) Экспорт | |
Возврат JsonВОбъект(РаспаковатьОтвет(Ответ), Ответ.Кодировка, ПараметрыПреобразованияJSON); | |
КонецФункции | |
// Возвращает ответ сервера в виде текста. | |
// | |
// Параметры: | |
// Ответ - Структура - ответ сервера на отправленный запрос. | |
// См. описание возвращаемого значения ВызватьМетод. | |
// Кодировка - Строка, КодировкаТекста - определяет кодировку текста. | |
// Если значение не задано, то кодировка извлекается из Ответ.Кодировка. | |
// | |
// Возвращаемое значение: | |
// Строка - ответ сервера в виде текста. | |
// | |
Функция КакТекст(Ответ, Кодировка = Неопределено) Экспорт | |
Если Не ЗначениеЗаполнено(Кодировка) Тогда | |
Кодировка = Ответ.Кодировка; | |
КонецЕсли; | |
ЧтениеТекста = Новый ЧтениеТекста(РаспаковатьОтвет(Ответ).ОткрытьПотокДляЧтения(), Кодировка); | |
Текст = ЧтениеТекста.Прочитать(); | |
ЧтениеТекста.Закрыть(); | |
Если Текст = Неопределено Тогда | |
Текст = ""; | |
КонецЕсли; | |
Возврат Текст; | |
КонецФункции | |
// Возвращает ответ сервера в двоичных данных. | |
// | |
// Параметры: | |
// Ответ - Структура - ответ сервера на отправленный запрос. | |
// См. описание возвращаемого значения ВызватьМетод. | |
// | |
// Возвращаемое значение: | |
// Строка - ответ сервера в виде двоичных данных. | |
// | |
Функция КакДвоичныеДанные(Ответ) Экспорт | |
Возврат РаспаковатьОтвет(Ответ); | |
КонецФункции | |
#КонецОбласти | |
#Область ВспомогательныеФункции | |
// Возвращает структурированное представление 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]; | |
КонецЕсли; | |
// IPv6 | |
РазбитьСтрокуПоРазделителю(Сервер, URL, "]"); | |
Если ЗначениеЗаполнено(Сервер) Тогда | |
Сервер = Сервер + "]"; | |
КонецЕсли; | |
URL = СтрЗаменить(URL, "/", ""); | |
РазбитьСтрокуПоРазделителю(Порт, URL, ":", Истина); | |
Если Не ЗначениеЗаполнено(Сервер) Тогда | |
Сервер = URL; | |
КонецЕсли; | |
Если ЗначениеЗаполнено(Порт) Тогда | |
Порт = Число(Порт); | |
Иначе | |
Порт = 0; | |
КонецЕсли; | |
РазбитьСтрокуПоРазделителю(Фрагмент, Путь, "#", Истина); | |
ПараметрыЗапроса = ЗаполнитьПараметрыЗапроса(Путь); | |
Если Не ЗначениеЗаполнено(Схема) Тогда | |
Схема = "http"; | |
КонецЕсли; | |
Путь = ?(ЗначениеЗаполнено(Путь), Путь, "/"); | |
Результат = Новый Структура; | |
Результат.Вставить("Схема", Схема); | |
Результат.Вставить("Аутентификация", Аутентификация); | |
Результат.Вставить("Сервер", Сервер); | |
Результат.Вставить("Порт", Порт); | |
Результат.Вставить("Путь", Путь); | |
Результат.Вставить("ПараметрыЗапроса", ПараметрыЗапроса); | |
Результат.Вставить("Фрагмент", Фрагмент); | |
Возврат Результат; | |
КонецФункции | |
// Преобразование Объекта в JSON. | |
// | |
// Параметры: | |
// Объект - Произвольный - данные, которые необходимо преобразовать в JSON. | |
// ПараметрыПреобразования - Структура - кодировка текста JSON. Значение по умолчанию - utf-8. | |
// *ФорматДаты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. Значение по умолчанию - utf-8. | |
// ПараметрыПреобразования - Структура - параметры преобразования 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.Закрыть(); | |
Возврат Объект; | |
КонецФункции | |
// Вычисляет HMAC (hash-based message authentication code). | |
// | |
// Параметры: | |
// Ключ - ДвоичныеДанные - секретный ключ. | |
// Данные - ДвоичныеДанные - данные, для которых нужно посчитать HMAC. | |
// Алгоритм - ХешФункция - алгоритм, используемый для вычисления хеша. | |
// | |
// Возвращаемое значение: | |
// ДвоичныеДанные - вычисленное значение HMAC. | |
// | |
Функция HMAC(Ключ, Данные, Алгоритм) Экспорт | |
ДлинаБлока = 64; | |
Если Ключ.Размер() > ДлинаБлока Тогда | |
Хеширование = Новый ХешированиеДанных(Алгоритм); | |
Хеширование.Добавить(Ключ); | |
КлючБуфер = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Хеширование.ХешСумма); | |
Иначе | |
КлючБуфер = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Ключ); | |
КонецЕсли; | |
ИзмененныйКлюч = Новый БуферДвоичныхДанных(ДлинаБлока); | |
ИзмененныйКлюч.Записать(0, КлючБуфер); | |
ВнутреннийКлюч = ИзмененныйКлюч.Скопировать(); | |
ВнешнийКлюч = ИзмененныйКлюч; | |
ВнутреннееВыравнивание = Новый БуферДвоичныхДанных(ДлинаБлока); | |
ВнешнееВыравнивание = Новый БуферДвоичныхДанных(ДлинаБлока); | |
Для Индекс = 0 По ДлинаБлока - 1 Цикл | |
ВнутреннееВыравнивание.Установить(Индекс, 54); | |
ВнешнееВыравнивание.Установить(Индекс, 92); | |
КонецЦикла; | |
ВнутреннееХеширование = Новый ХешированиеДанных(Алгоритм); | |
ВнешнееХеширование = Новый ХешированиеДанных(Алгоритм); | |
ВнутреннийКлюч.ЗаписатьПобитовоеИсключительноеИли(0, ВнутреннееВыравнивание); | |
ВнешнийКлюч.ЗаписатьПобитовоеИсключительноеИли(0, ВнешнееВыравнивание); | |
ВнешнееХеширование.Добавить(ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ВнешнийКлюч)); | |
ВнутреннееХеширование.Добавить(ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ВнутреннийКлюч)); | |
Если ЗначениеЗаполнено(Данные) Тогда | |
ВнутреннееХеширование.Добавить(Данные); | |
КонецЕсли; | |
ВнешнееХеширование.Добавить(ВнутреннееХеширование.ХешСумма); | |
Возврат ВнешнееХеширование.ХешСумма; | |
КонецФункции | |
// Возвращает структуру именованных кодов состояний HTTP. | |
// | |
// Возвращаемое значение: | |
// Структура - именованные коды состояний HTTP. | |
// | |
Функция КодыСостоянияHTTP() Экспорт | |
КодыСостояния = Новый Структура; | |
КодыСостояния.Вставить("ОК_200", 200); | |
КодыСостояния.Вставить("Принято_202", 202); | |
КодыСостояния.Вставить("ПеремещеноНавсегда_301", 301); | |
КодыСостояния.Вставить("ПеремещеноВременно_302", 302); | |
КодыСостояния.Вставить("СмотретьДругое_303", 303); | |
КодыСостояния.Вставить("ВременноеПеренаправление_307", 307); | |
КодыСостояния.Вставить("ПостоянноеПеренаправление_308", 308); | |
КодыСостояния.Вставить("НеверныйЗапрос_400", 400); | |
КодыСостояния.Вставить("НеАвторизован_401", 401); | |
КодыСостояния.Вставить("НеобходимаОплата_402", 402); | |
КодыСостояния.Вставить("Запрещено_403", 403); | |
КодыСостояния.Вставить("ПолезнаяНагрузкаСлишкомВелика_413", 413); | |
КодыСостояния.Вставить("СлишкомМногоЗапросов_429", 429); | |
КодыСостояния.Вставить("ВнутренняяОшибкаСервера_500", 500); | |
КодыСостояния.Вставить("ОшибочныйШлюз_502", 502); | |
КодыСостояния.Вставить("СервисНедоступен_503", 503); | |
КодыСостояния.Вставить("ШлюзНеОтвечает_504", 504); | |
Возврат КодыСостояния; | |
КонецФункции | |
// Выполняет чтение данных из архива 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); | |
ПодготовитьАутентификацию(ПодготовленныйЗапрос); | |
Возврат ПодготовленныйЗапрос; | |
КонецФункции | |
#КонецОбласти | |
#Область СлужебныеПроцедурыИФункции | |
Функция ЭтоКодСостоянияПриКоторомНужноУчитыватьЗаголовокRetryAfter(КодСостояния) | |
Коды = КодыСостоянияHTTP(); | |
Возврат КодСостояния = Коды.ПолезнаяНагрузкаСлишкомВелика_413 | |
ИЛИ КодСостояния = Коды.СлишкомМногоЗапросов_429 | |
ИЛИ КодСостояния = Коды.СервисНедоступен_503; | |
КонецФункции | |
Функция ЧислоИзСтроки(Знач Строка) Экспорт | |
ОписаниеТипа = Новый ОписаниеТипов("Число"); | |
Возврат ОписаниеТипа.ПривестиЗначение(Строка); | |
КонецФункции | |
Функция ДатаИзСтроки(Знач Строка) Экспорт | |
КвалификаторДаты = Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя); | |
ОписаниеТипа = Новый ОписаниеТипов("Дата", Неопределено, Неопределено, КвалификаторДаты); | |
Возврат ОписаниеТипа.ПривестиЗначение(Строка); | |
КонецФункции | |
Функция ДатаИзСтрокиRFC7231(Знач Строка) Экспорт | |
Разделители = ",-:/\."; | |
Для Индекс = 1 По СтрДлина(Разделители) Цикл | |
Разделитель = Сред(Разделители, Индекс, 1); | |
Строка = СтрЗаменить(Строка, Разделитель, " "); | |
КонецЦикла; | |
Строка = СтрЗаменить(Строка, " ", " "); | |
СоставляющиеДаты = СтрРазделить(Строка, " "); | |
МесяцСтр = СоставляющиеДаты[2]; | |
Месяцы = СтрРазделить("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", ","); | |
Месяц = Месяцы.Найти(МесяцСтр); | |
Если Месяц = Неопределено Тогда | |
Возврат '00010101'; | |
КонецЕсли; | |
Дата = СоставляющиеДаты[3] + Формат(Месяц + 1, "ЧЦ=2; ЧВН=;") + СоставляющиеДаты[1]; | |
Время = СоставляющиеДаты[4] + СоставляющиеДаты[5] + СоставляющиеДаты[6]; | |
Возврат ДатаИзСтроки(Дата + Время); | |
КонецФункции | |
Функция ВызватьHTTPМетод(Сессия, Метод, URL, ДополнительныеПараметры) | |
КодыСостоянияHTTP = КодыСостоянияHTTP(); | |
ПодготовленныйЗапрос = ПодготовитьЗапрос(Сессия, Метод, URL, ДополнительныеПараметры); | |
НастройкиПодключения = НастройкиПодключения(Метод, URL, ДополнительныеПараметры); | |
Ответ = ОтправитьЗапрос(Сессия, ПодготовленныйЗапрос, НастройкиПодключения); | |
Перенаправление = 0; | |
Пока Перенаправление < Сессия.МаксимальноеКоличествоПеренаправлений Цикл | |
Если Не НастройкиПодключения.РазрешитьПеренаправление ИЛИ Не Ответ.ЭтоРедирект Тогда | |
Возврат Ответ; | |
КонецЕсли; | |
Новый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(ПодготовленныйЗапрос); | |
// INFO: по хорошему аутентификацию нужно привести к новых параметрам, но пока будем игнорировать. | |
Ответ = ОтправитьЗапрос(Сессия, ПодготовленныйЗапрос, НастройкиПодключения); | |
Перенаправление = Перенаправление + 1; | |
КонецЦикла; | |
ВызватьИсключение("СлишкомМногоПеренаправлений"); | |
КонецФункции | |
Функция СформироватьНовыйURLПриПеренаправлении(Ответ) | |
НовыйURL = ЗначениеЗаголовка("location", Ответ.Заголовки); | |
НовыйURL = РаскодироватьСтроку(НовыйURL, СпособКодированияСтроки.URLВКодировкеURL); | |
// Редирект без схемы | |
Если СтрНачинаетсяС(НовыйURL, "//") Тогда | |
СтруктураURL = РазобратьURL(Ответ.URL); | |
НовыйURL = СтруктураURL.Схема + ":" + НовыйURL; | |
КонецЕсли; | |
СтруктураURL = РазобратьURL(НовыйURL); | |
Если Не ЗначениеЗаполнено(СтруктураURL.Сервер) Тогда | |
СтруктураURLОтвета = РазобратьURL(Ответ.URL); | |
БазовыйURL = СтрШаблон("%1://%2", СтруктураURLОтвета.Схема, СтруктураURLОтвета.Сервер); | |
Если ЗначениеЗаполнено(СтруктураURLОтвета.Порт) Тогда | |
БазовыйURL = БазовыйURL + Формат(СтруктураURLОтвета.Порт, "ЧРГ=; ЧГ="); | |
КонецЕсли; | |
НовыйURL = БазовыйURL + НовыйURL; | |
КонецЕсли; | |
Возврат НовыйURL; | |
КонецФункции | |
Процедура УдалитьЗаголовки(Заголовки, СписокЗаголовковСтрокой) | |
ЗаголовкиДляУдаления = Новый Массив; | |
СписокЗаголовков = СтрРазделить(СписокЗаголовковСтрокой, ",", Ложь); | |
Для Каждого Заголовок Из Заголовки Цикл | |
Если СписокЗаголовков.Найти(НРег(Заголовок.Ключ)) <> Неопределено Тогда | |
ЗаголовкиДляУдаления.Добавить(Заголовок.Ключ); | |
КонецЕсли; | |
КонецЦикла; | |
Для Каждого ЗаголовокДляУдаления Из ЗаголовкиДляУдаления Цикл | |
Заголовки.Удалить(ЗаголовокДляУдаления); | |
КонецЦикла; | |
КонецПроцедуры | |
Функция НастройкиПодключения(Метод, URL, ДополнительныеПараметры) | |
РазрешитьПеренаправление = | |
ЗначениеПоКлючу(ДополнительныеПараметры, "РазрешитьПеренаправление", ВРег(Метод) <> "HEAD"); | |
ПроверятьSSL = ЗначениеПоКлючу(ДополнительныеПараметры, "ПроверятьSSL", Истина); | |
КлиентскийСертификатSSL = ЗначениеПоКлючу(ДополнительныеПараметры, "КлиентскийСертификатSSL"); | |
Прокси = ЗначениеПоКлючу(ДополнительныеПараметры, "Прокси", ПроксиПоУмолчанию(URL)); | |
МаксимальноеКоличествоПовторов = ЗначениеПоКлючу(ДополнительныеПараметры, "МаксимальноеКоличествоПовторов", 0); | |
ПовторятьДляКодовСостояний = | |
ЗначениеПоКлючу(ДополнительныеПараметры, "ПовторятьДляКодовСостояний", Неопределено); | |
КоэффициентЭкспоненциальнойЗадержки = | |
ЗначениеПоКлючу(ДополнительныеПараметры, "КоэффициентЭкспоненциальнойЗадержки", 1); | |
МаксимальноеВремяПовторов = ЗначениеПоКлючу(ДополнительныеПараметры, "МаксимальноеВремяПовторов", 600); | |
Настройки = Новый Структура; | |
Настройки.Вставить("Таймаут", Таймаут(ДополнительныеПараметры)); | |
Настройки.Вставить("РазрешитьПеренаправление", РазрешитьПеренаправление); | |
Настройки.Вставить("ПроверятьSSL", ПроверятьSSL); | |
Настройки.Вставить("КлиентскийСертификатSSL", КлиентскийСертификатSSL); | |
Настройки.Вставить("Прокси", Прокси); | |
Настройки.Вставить("МаксимальноеКоличествоПовторов", МаксимальноеКоличествоПовторов); | |
Настройки.Вставить("ПовторятьДляКодовСостояний", ПовторятьДляКодовСостояний); | |
Настройки.Вставить("КоэффициентЭкспоненциальнойЗадержки", КоэффициентЭкспоненциальнойЗадержки); | |
Настройки.Вставить("МаксимальноеВремяПовторов", МаксимальноеВремяПовторов); | |
Возврат Настройки; | |
КонецФункции | |
Функция Таймаут(ДополнительныеПараметры) | |
Если ДополнительныеПараметры.Свойство("Таймаут") И ЗначениеЗаполнено(ДополнительныеПараметры.Таймаут) Тогда | |
Таймаут = ДополнительныеПараметры.Таймаут; | |
Иначе | |
Таймаут = СтандартныйТаймаут(); | |
КонецЕсли; | |
Возврат Таймаут; | |
КонецФункции | |
Функция ПроксиПоУмолчанию(URL) | |
ПроксиПоУмолчанию = Новый ИнтернетПрокси; | |
// BSLLS:ExecuteExternalCodeInCommonModule-off | |
ИмяОМПолученияФайловБСП = "ПолучениеФайловИзИнтернета"; | |
Если Метаданные.ОбщиеМодули.Найти(ИмяОМПолученияФайловБСП) <> Неопределено Тогда | |
СтруктураURL = РазобратьURL(URL); | |
Модуль = Вычислить(ИмяОМПолученияФайловБСП); | |
ПроксиПоУмолчанию = Модуль.ПолучитьПрокси(СтруктураURL.Схема); | |
КонецЕсли; | |
// BSLLS:ExecuteExternalCodeInCommonModule-on | |
Возврат ПроксиПоУмолчанию; | |
КонецФункции | |
Функция Дозаполнить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; | |
КонецФункции | |
Процедура УдалитьCookieИзХранилища(ХранилищеCookies, Cookie) | |
Если ХранилищеCookies.Получить(Cookie.Домен) <> Неопределено | |
И ХранилищеCookies[Cookie.Домен].Получить(Cookie.Путь) <> Неопределено | |
И ХранилищеCookies[Cookie.Домен][Cookie.Путь].Получить(Cookie.Наименование) <> Неопределено Тогда | |
ХранилищеCookies[Cookie.Домен][Cookie.Путь].Удалить(Cookie.Наименование); | |
КонецЕсли; | |
КонецПроцедуры | |
Процедура ДобавитьCookieВХранилище(ХранилищеCookies, Cookie, Замещать = Ложь) | |
Если ХранилищеCookies.Получить(Cookie.Домен) = Неопределено Тогда | |
ХранилищеCookies[Cookie.Домен] = Новый Соответствие; | |
КонецЕсли; | |
Если ХранилищеCookies[Cookie.Домен].Получить(Cookie.Путь) = Неопределено Тогда | |
ХранилищеCookies[Cookie.Домен][Cookie.Путь] = Новый Соответствие; | |
КонецЕсли; | |
Если ХранилищеCookies[Cookie.Домен][Cookie.Путь].Получить(Cookie.Наименование) = Неопределено ИЛИ Замещать Тогда | |
ХранилищеCookies[Cookie.Домен][Cookie.Путь][Cookie.Наименование] = Cookie; | |
КонецЕсли; | |
КонецПроцедуры | |
Функция ДобавитьЛидирующуюТочку(Знач Домен) | |
Если Не СтрНачинаетсяС(Домен, ".") Тогда | |
Домен = "." + Домен; | |
КонецЕсли; | |
Возврат Домен; | |
КонецФункции | |
Процедура ЗаполнитьСписокОтфильтрованнымиCookies(Cookies, СтруктураURL, Список) | |
Для Каждого Cookie Из Cookies Цикл | |
Если Cookie.Значение.ТолькоБезопасноеСоединение = Истина И СтруктураURL.Схема <> "https" Тогда | |
Продолжить; | |
КонецЕсли; | |
// INFO: проверка срока действия игнорируется (Cookie.Значение.СрокДействия) | |
// INFO: проверка порта игнорируется | |
Список.Добавить(Cookie.Значение); | |
КонецЦикла; | |
КонецПроцедуры | |
Функция ОтобратьCookiesДляЗапроса(СтруктураURL, Cookies) | |
СерверВЗапросе = ДобавитьЛидирующуюТочку(СтруктураURL.Сервер); | |
Результат = Новый Массив; | |
Для Каждого Домен Из Cookies Цикл | |
Если Не СтрЗаканчиваетсяНа(СерверВЗапросе, Домен.Ключ) Тогда | |
Продолжить; | |
КонецЕсли; | |
Для Каждого Путь Из Домен.Значение Цикл | |
Если Не СтрНачинаетсяС(СтруктураURL.Путь, Путь.Ключ) Тогда | |
Продолжить; | |
КонецЕсли; | |
ЗаполнитьСписокОтфильтрованнымиCookies(Путь.Значение, СтруктураURL, Результат); | |
КонецЦикла; | |
КонецЦикла; | |
Возврат Результат; | |
КонецФункции | |
Функция ПодготовитьЗаголовокCookie(ПодготовленныйЗапрос) | |
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL); | |
Cookies = Новый Массив; | |
Для Каждого Cookie Из ОтобратьCookiesДляЗапроса(СтруктураURL, ПодготовленныйЗапрос.Cookies) Цикл | |
Cookies.Добавить(СтрШаблон("%1=%2", Cookie.Наименование, Cookie.Значение)); | |
КонецЦикла; | |
Возврат СтрСоединить(Cookies, "; "); | |
КонецФункции | |
Процедура ПодготовитьCookies(ПодготовленныйЗапрос) | |
ЗаголовокCookie = ПодготовитьЗаголовокCookie(ПодготовленныйЗапрос); | |
Если ЗначениеЗаполнено(ЗаголовокCookie) Тогда | |
ПодготовленныйЗапрос.Заголовки["Cookie"] = ЗаголовокCookie; | |
КонецЕсли; | |
КонецПроцедуры | |
Функция КодироватьПараметрыЗапроса(ПараметрыЗапроса) | |
ЧастиПараметрыЗапроса = Новый Массив; | |
Для Каждого Параметр Из ПараметрыЗапроса Цикл | |
Если ТипЗнч(Параметр.Значение) = Тип("Массив") Тогда | |
Значения = Параметр.Значение; | |
Иначе | |
Значения = Новый Массив; | |
Значения.Добавить(Параметр.Значение); | |
КонецЕсли; | |
Если Параметр.Значение = Неопределено Тогда | |
ЧастиПараметрыЗапроса.Добавить(Параметр.Ключ); | |
Иначе | |
Для Каждого Значение Из Значения Цикл | |
ЗначениеПараметра = КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL); | |
ЧастиПараметрыЗапроса.Добавить(СтрШаблон("%1=%2", Параметр.Ключ, ЗначениеПараметра)); | |
КонецЦикла; | |
КонецЕсли; | |
КонецЦикла; | |
Возврат СтрСоединить(ЧастиПараметрыЗапроса, "&"); | |
КонецФункции | |
Функция Подготовить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; | |
КонецФункции | |
Функция ЗаголовкиВСтроку(Заголовки) | |
РазделительСтрок = Символы.ВК + Символы.ПС; | |
Строки = Новый Массив; | |
СортированныеЗаголовки = "Content-Disposition,Content-Type,Content-Location"; | |
Для Каждого Ключ Из СтрРазделить(СортированныеЗаголовки, ",") Цикл | |
Значение = ЗначениеЗаголовка(Ключ, Заголовки); | |
Если Значение <> Ложь И ЗначениеЗаполнено(Значение) Тогда | |
Строки.Добавить(СтрШаблон("%1: %2", Ключ, Значение)); | |
КонецЕсли; | |
КонецЦикла; | |
Ключи = СтрРазделить(ВРег(СортированныеЗаголовки), ","); | |
Для Каждого Заголовок Из Заголовки Цикл | |
Если Ключи.Найти(ВРег(Заголовок.Ключ)) = Неопределено Тогда | |
Строки.Добавить(СтрШаблон("%1: %2", Заголовок.Ключ, Заголовок.Значение)); | |
КонецЕсли; | |
КонецЦикла; | |
Строки.Добавить(РазделительСтрок); | |
Возврат СтрСоединить(Строки, РазделительСтрок); | |
КонецФункции | |
Функция ЗначениеПоКлючу(Структура, Ключ, ЗначениеПоУмолчанию = Неопределено) | |
Если ТипЗнч(Структура) = Тип("Структура") И Структура.Свойство(Ключ) Тогда | |
Значение = Структура[Ключ]; | |
ИначеЕсли ТипЗнч(Структура) = Тип("Соответствие") И Структура.Получить(Ключ) <> Неопределено Тогда | |
Значение = Структура.Получить(Ключ); | |
Иначе | |
Значение = ЗначениеПоУмолчанию; | |
КонецЕсли; | |
Возврат Значение; | |
КонецФункции | |
Функция СоздатьПолеФормы(ИсходныеПараметры) | |
Поле = Новый Структура("Имя,ИмяФайла,Данные,Тип,Заголовки"); | |
Поле.Имя = ИсходныеПараметры.Имя; | |
Поле.Данные = ИсходныеПараметры.Данные; | |
Поле.Тип = ЗначениеПоКлючу(ИсходныеПараметры, "Тип"); | |
Поле.Заголовки = ЗначениеПоКлючу(ИсходныеПараметры, "Заголовки", Новый Соответствие); | |
Поле.ИмяФайла = ЗначениеПоКлючу(ИсходныеПараметры, "ИмяФайла"); | |
Ключ = "Content-Disposition"; | |
Если ЗначениеЗаголовка("content-disposition", Поле.Заголовки, Ключ) = Ложь Тогда | |
Поле.Заголовки.Вставить("Content-Disposition", "form-data"); | |
КонецЕсли; | |
Части = Новый Массив; | |
Части.Добавить(Поле.Заголовки[Ключ]); | |
Части.Добавить(СтрШаблон("name=""%1""", Поле.Имя)); | |
Если ЗначениеЗаполнено(Поле.ИмяФайла) Тогда | |
Части.Добавить(СтрШаблон("filename=""%1""", Поле.ИмяФайла)); | |
КонецЕсли; | |
Поле.Заголовки[Ключ] = СтрСоединить(Части, "; "); | |
Поле.Заголовки["Content-Type"] = Поле.Тип; | |
Возврат Поле; | |
КонецФункции | |
Функция ЗакодироватьФайлы(HTTPЗапрос, Файлы, Данные) | |
Части = Новый Массив; | |
Если ЗначениеЗаполнено(Данные) Тогда | |
Для Каждого Поле Из Данные Цикл | |
Части.Добавить(СоздатьПолеФормы(Новый Структура("Имя,Данные", Поле.Ключ, Поле.Значение))); | |
КонецЦикла; | |
КонецЕсли; | |
Если ТипЗнч(Файлы) = Тип("Массив") Тогда | |
Для Каждого Файл Из Файлы Цикл | |
Части.Добавить(СоздатьПолеФормы(Файл)); | |
КонецЦикла; | |
Иначе | |
Части.Добавить(СоздатьПолеФормы(Файлы)); | |
КонецЕсли; | |
Разделитель = СтрЗаменить(Новый УникальныйИдентификатор, "-", ""); | |
РазделительСтрок = Символы.ВК + Символы.ПС; | |
ТелоЗапроса = HTTPЗапрос.ПолучитьТелоКакПоток(); | |
ЗаписьДанных = Новый ЗаписьДанных(ТелоЗапроса, КодировкаТекста.UTF8, ПорядокБайтов.LittleEndian, "", "", Ложь); | |
Для Каждого Часть Из Части Цикл | |
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + РазделительСтрок); | |
ЗаписьДанных.ЗаписатьСтроку(ЗаголовкиВСтроку(Часть.Заголовки)); | |
Если ТипЗнч(Часть.Данные) = Тип("ДвоичныеДанные") Тогда | |
ЗаписьДанных.Записать(Часть.Данные); | |
Иначе | |
ЗаписьДанных.ЗаписатьСтроку(Часть.Данные); | |
КонецЕсли; | |
ЗаписьДанных.ЗаписатьСтроку(РазделительСтрок); | |
КонецЦикла; | |
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--" + РазделительСтрок); | |
ЗаписьДанных.Закрыть(); | |
Возврат СтрШаблон("multipart/form-data; boundary=%1", Разделитель); | |
КонецФункции | |
Процедура ПодготовитьТелоЗапроса(ПодготовленныйЗапрос, Данные, Файлы, Json, ПараметрыЗаписиJSON) | |
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL); | |
HTTPЗапрос = Новый HTTPЗапрос; | |
HTTPЗапрос.АдресРесурса = СобратьАдресРесурса(СтруктураURL, ПодготовленныйЗапрос.ПараметрыЗапроса); | |
Если ЗначениеЗаполнено(Файлы) Тогда | |
ContentType = ЗакодироватьФайлы(HTTPЗапрос, Файлы, Данные); | |
ИначеЕсли ЗначениеЗаполнено(Данные) Тогда | |
ContentType = "application/x-www-form-urlencoded"; | |
Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда | |
HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(Данные); | |
Иначе | |
Если ТипЗнч(Данные) = Тип("Строка") Тогда | |
Тело = Данные; | |
Иначе | |
Тело = КодироватьПараметрыЗапроса(Данные); | |
КонецЕсли; | |
HTTPЗапрос.УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать); | |
КонецЕсли; | |
ИначеЕсли Json <> Неопределено Тогда | |
ContentType = "application/json"; | |
СтрокаJson = ОбъектВJson(Json, ПодготовленныйЗапрос.ПараметрыПреобразованияJSON, ПараметрыЗаписиJSON); | |
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJson, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать); | |
Иначе | |
ContentType = Неопределено; | |
КонецЕсли; | |
ЗначениеЗаголовка = ЗначениеЗаголовка("content-type", ПодготовленныйЗапрос.Заголовки); | |
Если ЗначениеЗаголовка = Ложь И ЗначениеЗаполнено(ContentType) Тогда | |
ПодготовленныйЗапрос.Заголовки.Вставить("Content-Type", ContentType); | |
КонецЕсли; | |
HTTPЗапрос.Заголовки = ПодготовленныйЗапрос.Заголовки; | |
УпаковатьЗапрос(HTTPЗапрос); | |
ПодготовленныйЗапрос.Вставить("HTTPЗапрос", HTTPЗапрос); | |
КонецПроцедуры | |
Процедура ПодготовитьАутентификацию(ПодготовленныйЗапрос) | |
ПодготовленныйЗапрос.Вставить("СобытияНаОтвет", Новый Массив); | |
Если Не ЗначениеЗаполнено(ПодготовленныйЗапрос.Аутентификация) Тогда | |
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL); | |
Если ЗначениеЗаполнено(СтруктураURL.Аутентификация) Тогда | |
ПодготовленныйЗапрос.Аутентификация = СтруктураURL.Аутентификация; | |
КонецЕсли; | |
КонецЕсли; | |
Если ЗначениеЗаполнено(ПодготовленныйЗапрос.Аутентификация) Тогда | |
Если ПодготовленныйЗапрос.Аутентификация.Свойство("Тип") Тогда | |
ТипАутентификации = НРег(ПодготовленныйЗапрос.Аутентификация.Тип); | |
Если ТипАутентификации = "digest" Тогда | |
ПодготовленныйЗапрос.СобытияНаОтвет.Добавить("ОбработкаОтветаСКодом401"); | |
КонецЕсли; | |
Если ТипАутентификации = "aws4-hmac-sha256" Тогда | |
ПодготовитьАутентификациюAWS4(ПодготовленныйЗапрос); | |
КонецЕсли; | |
КонецЕсли; | |
КонецЕсли; | |
КонецПроцедуры | |
Функция Объединить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; | |
КонецФункции | |
Функция ОбъединитьПараметрыАутентификации(ГлавныйИсточник, ДополнительныйИсточник) | |
ПараметрыАутентификации = Новый Структура; | |
Если ТипЗнч(ГлавныйИсточник) = Тип("Структура") Тогда | |
Для Каждого Параметр Из ГлавныйИсточник Цикл | |
ПараметрыАутентификации.Вставить(Параметр.Ключ, Параметр.Значение); | |
КонецЦикла; | |
КонецЕсли; | |
Если ТипЗнч(ДополнительныйИсточник) = Тип("Структура") Тогда | |
Для Каждого Параметр Из ДополнительныйИсточник Цикл | |
Если Не ПараметрыАутентификации.Свойство(Параметр) Тогда | |
ПараметрыАутентификации.Вставить(Параметр.Ключ, Параметр.Значение); | |
КонецЕсли; | |
КонецЦикла; | |
КонецЕсли; | |
Возврат ПараметрыАутентификации; | |
КонецФункции | |
Функция ОбъединитьЗаголовки(ГлавныйИсточник, ДополнительныйИсточник) | |
Заголовки = Новый Соответствие; | |
Для Каждого Заголовок Из ГлавныйИсточник Цикл | |
Заголовки.Вставить(Заголовок.Ключ, Заголовок.Значение); | |
КонецЦикла; | |
Для Каждого Заголовок Из ДополнительныйИсточник Цикл | |
Если Заголовки.Получить(Заголовок.Ключ) = Неопределено Тогда | |
Заголовки.Вставить(Заголовок.Ключ, Заголовок.Значение); | |
КонецЕсли; | |
КонецЦикла; | |
Возврат Заголовки; | |
КонецФункции | |
Функция ОбъединитьПараметрыЗапроса(ГлавныйИсточник, ДополнительныйИсточник) | |
ПараметрыЗапроса = Новый Соответствие; | |
Если ТипЗнч(ГлавныйИсточник) = Тип("Структура") ИЛИ ТипЗнч(ГлавныйИсточник) = Тип("Соответствие") Тогда | |
Для Каждого Параметр Из ГлавныйИсточник Цикл | |
ПараметрыЗапроса.Вставить(Параметр.Ключ, Параметр.Значение); | |
КонецЦикла; | |
КонецЕсли; | |
Если ТипЗнч(ДополнительныйИсточник) = Тип("Структура") ИЛИ ТипЗнч(ДополнительныйИсточник) = Тип("Соответствие") Тогда | |
Для Каждого Параметр Из ДополнительныйИсточник Цикл | |
Если ПараметрыЗапроса.Получить(Параметр) = Неопределено Тогда | |
ПараметрыЗапроса.Вставить(Параметр.Ключ, Параметр.Значение); | |
КонецЕсли; | |
КонецЦикла; | |
КонецЕсли; | |
Возврат ПараметрыЗапроса; | |
КонецФункции | |
Функция ОтправитьHTTPЗапрос(Сессия, ПодготовленныйЗапрос, Настройки) | |
СтруктураURL = РазобратьURL(ПодготовленныйЗапрос.URL); | |
Соединение = Соединение(СтруктураURL, ПодготовленныйЗапрос.Аутентификация, Настройки, Сессия); | |
Ответ = Соединение.ВызватьHTTPМетод(ПодготовленныйЗапрос.Метод, ПодготовленныйЗапрос.HTTPЗапрос); | |
Для Каждого Обработчик Из ПодготовленныйЗапрос.СобытияНаОтвет Цикл | |
Если Обработчик = "ОбработкаОтветаСКодом401" Тогда | |
ОбработкаОтветаСКодом401(Сессия, ПодготовленныйЗапрос, Настройки, Ответ); | |
КонецЕсли; | |
КонецЦикла; | |
Возврат Ответ; | |
КонецФункции | |
Функция РассчитатьДлительностьПриостановки(Повтор, КоэффициентЭкспоненциальнойЗадержки, ЗаголовокRetryAfter, Остаток) | |
Если ЗаголовокRetryAfter <> Ложь Тогда | |
Длительность = ЧислоИзСтроки(ЗаголовокRetryAfter); | |
Если Длительность = 0 Тогда | |
Дата = ДатаИзСтрокиRFC7231(ЗаголовокRetryAfter); | |
Если ЗначениеЗаполнено(Дата) Тогда | |
Длительность = Дата - ТекущаяУниверсальнаяДата(); | |
КонецЕсли; | |
КонецЕсли; | |
Иначе | |
Длительность = КоэффициентЭкспоненциальнойЗадержки * Pow(2, Повтор - 1); | |
КонецЕсли; | |
Длительность = Мин(Длительность, Остаток); | |
Если Длительность < 0 Тогда | |
Длительность = 0; | |
КонецЕсли; | |
Возврат Длительность; | |
КонецФункции | |
Функция НеобходимоПовторитьЗапрос(Ответ, Настройки, ОшибкаВыполненияЗапроса) | |
Если Настройки.МаксимальноеКоличествоПовторов < 1 Тогда | |
Возврат Ложь; | |
КонецЕсли; | |
Если ОшибкаВыполненияЗапроса <> Неопределено Тогда | |
Возврат Истина; | |
КонецЕсли; | |
ПовторПриЛюбомКодеСостоянияБольшеИлиРавным500 = Настройки.ПовторятьДляКодовСостояний = Неопределено | |
И Ответ.КодСостояния >= КодыСостоянияHTTP().ВнутренняяОшибкаСервера_500; | |
КодСостоянияСоответствуетКодуСостоянияПовтора = ТипЗнч(Настройки.ПовторятьДляКодовСостояний) = Тип("Массив") | |
И Настройки.ПовторятьДляКодовСостояний.Найти(Ответ.КодСостояния) <> Неопределено; | |
Если ПовторПриЛюбомКодеСостоянияБольшеИлиРавным500 ИЛИ КодСостоянияСоответствуетКодуСостоянияПовтора Тогда | |
Возврат Истина; | |
КонецЕсли; | |
ЗаголовокRetryAfter = ЗначениеЗаголовка("retry-after", Ответ.Заголовки); | |
Возврат ЗаголовокRetryAfter <> Ложь | |
И ЭтоКодСостоянияПриКоторомНужноУчитыватьЗаголовокRetryAfter(Ответ.КодСостояния); | |
КонецФункции | |
Функция ОтправитьЗапрос(Сессия, ПодготовленныйЗапрос, Настройки) | |
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах(); | |
МиллисекундВСекунде = 1000; | |
Повтор = 0; | |
Длительность = 0; | |
Пока Истина Цикл | |
Попытка | |
Ответ = ОтправитьHTTPЗапрос(Сессия, ПодготовленныйЗапрос, Настройки); | |
Исключение | |
ОшибкаВыполненияЗапроса = ИнформацияОбОшибке(); | |
КонецПопытки; | |
Повтор = Повтор + 1; | |
Длительность = (ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало) / МиллисекундВСекунде; | |
Если Не НеобходимоПовторитьЗапрос(Ответ, Настройки, ОшибкаВыполненияЗапроса) Тогда | |
Прервать; | |
КонецЕсли; | |
Если Повтор > Настройки.МаксимальноеКоличествоПовторов | |
ИЛИ Длительность > Настройки.МаксимальноеВремяПовторов Тогда | |
Прервать; | |
КонецЕсли; | |
Если ОшибкаВыполненияЗапроса <> Неопределено | |
ИЛИ НЕ ЭтоКодСостоянияПриКоторомНужноУчитыватьЗаголовокRetryAfter(Ответ.КодСостояния) Тогда | |
ЗаголовокRetryAfter = Ложь; | |
Иначе | |
ЗаголовокRetryAfter = ЗначениеЗаголовка("retry-after", Ответ.Заголовки); | |
КонецЕсли; | |
ДлительностьПриостановки = РассчитатьДлительностьПриостановки( | |
Повтор, | |
Настройки.КоэффициентЭкспоненциальнойЗадержки, | |
ЗаголовокRetryAfter, | |
Настройки.МаксимальноеВремяПовторов - Длительность); | |
Приостановить(ДлительностьПриостановки); | |
КонецЦикла; | |
Если ОшибкаВыполненияЗапроса <> Неопределено Тогда | |
ВызватьИсключение(ПодробноеПредставлениеОшибки(ОшибкаВыполненияЗапроса)); | |
КонецЕсли; | |
ЗаголовокContentType = ЗначениеЗаголовка("content-type", Ответ.Заголовки); | |
Если ЗаголовокContentType = Ложь Тогда | |
ЗаголовокContentType = ""; | |
КонецЕсли; | |
ПодготовленныйОтвет = Новый Структура; | |
ПодготовленныйОтвет.Вставить("ВремяВыполнения", ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало); | |
ПодготовленныйОтвет.Вставить("Cookies", ИзвлечьCookies(Ответ.Заголовки, ПодготовленныйЗапрос.URL)); | |
ПодготовленныйОтвет.Вставить("Заголовки", Ответ.Заголовки); | |
ПодготовленныйОтвет.Вставить("ЭтоПостоянныйРедирект", ЭтоПостоянныйРедирект(Ответ.КодСостояния, Ответ.Заголовки)); | |
ПодготовленныйОтвет.Вставить("ЭтоРедирект", ЭтоРедирект(Ответ.КодСостояния, Ответ.Заголовки)); | |
ПодготовленныйОтвет.Вставить("Кодировка", КодировкаИзЗаголовка(ЗаголовокContentType)); | |
ПодготовленныйОтвет.Вставить("Тело", Ответ.ПолучитьТелоКакДвоичныеДанные()); | |
ПодготовленныйОтвет.Вставить("КодСостояния", Ответ.КодСостояния); | |
ПодготовленныйОтвет.Вставить("URL", ПодготовленныйЗапрос.URL); | |
Сессия.Cookies = ОбъединитьCookies(Сессия.Cookies, ПодготовленныйОтвет.Cookies); | |
Возврат ПодготовленныйОтвет; | |
КонецФункции | |
Процедура ПереопределитьМетод(ПодготовленныйЗапрос, Ответ) | |
КодыСостоянияHTTP = КодыСостоянияHTTP(); | |
Метод = ПодготовленныйЗапрос.Метод; | |
// http://tools.ietf.org/html/rfc7231#section-6.4.4 | |
Если Ответ.КодСостояния = КодыСостоянияHTTP.СмотретьДругое_303 И Метод <> "HEAD" Тогда | |
Метод = "GET"; | |
КонецЕсли; | |
// Поведение браузеров | |
Если Ответ.КодСостояния = КодыСостоянияHTTP.ПеремещеноВременно_302 И Метод <> "HEAD" Тогда | |
Метод = "GET"; | |
КонецЕсли; | |
ПодготовленныйЗапрос.Метод = Метод; | |
КонецПроцедуры | |
Функция ИзвлечьCookies(Заголовки, URL) | |
ТекущееВремя = ТекущаяУниверсальнаяДата(); | |
Cookies = Новый Соответствие; | |
Для Каждого ОчереднойЗаголовок Из Заголовки Цикл | |
Если НРег(ОчереднойЗаголовок.Ключ) = "set-cookie" Тогда | |
Для Каждого ЗаголовокCookie Из РазбитьНаОтдельныеЗаголовкиCookies(ОчереднойЗаголовок.Значение) Цикл | |
Cookie = РаспарситьCookie(ЗаголовокCookie, URL, ТекущееВремя); | |
Если Cookie = Неопределено Тогда | |
Продолжить; | |
КонецЕсли; | |
Если Cookie.СрокДействия <= ТекущееВремя Тогда | |
УдалитьCookieИзХранилища(Cookies, Cookie); | |
Иначе | |
ДобавитьCookieВХранилище(Cookies, Cookie); | |
КонецЕсли; | |
КонецЦикла; | |
КонецЕсли; | |
КонецЦикла; | |
Возврат Cookies; | |
КонецФункции | |
Функция РазбитьНаОтдельныеЗаголовкиCookies(Знач Заголовок) | |
Заголовки = Новый Массив; | |
Если Не ЗначениеЗаполнено(Заголовок) Тогда | |
Возврат Заголовки; | |
КонецЕсли; | |
ЗапчастиЗаголовков = СтрРазделить(Заголовок, ",", Ложь); | |
ОтдельныйЗаголовок = ЗапчастиЗаголовков[0]; | |
Для Индекс = 1 По ЗапчастиЗаголовков.ВГраница() Цикл | |
ТочкаСЗапятой = СтрНайти(ЗапчастиЗаголовков[Индекс], ";"); | |
Равно = СтрНайти(ЗапчастиЗаголовков[Индекс], "="); | |
Если ТочкаСЗапятой И Равно И Равно < ТочкаСЗапятой Тогда | |
Заголовки.Добавить(ОтдельныйЗаголовок); | |
ОтдельныйЗаголовок = ЗапчастиЗаголовков[Индекс]; | |
Иначе | |
ОтдельныйЗаголовок = ОтдельныйЗаголовок + ЗапчастиЗаголовков[Индекс]; | |
КонецЕсли; | |
КонецЦикла; | |
Заголовки.Добавить(ОтдельныйЗаголовок); | |
Возврат Заголовки; | |
КонецФункции | |
Функция КонструкторCookie(Наименование = "", Значение = Неопределено) | |
НовыйCookie = Новый Структура; | |
НовыйCookie.Вставить("Наименование", Наименование); | |
НовыйCookie.Вставить("Значение", Значение); | |
НовыйCookie.Вставить("Домен", ""); | |
НовыйCookie.Вставить("Путь", ""); | |
НовыйCookie.Вставить("Порт"); | |
НовыйCookie.Вставить("СрокДействия", '39990101'); | |
НовыйCookie.Вставить("ТолькоБезопасноеСоединение"); | |
Возврат НовыйCookie; | |
КонецФункции | |
Функция СоздатьCookieИЗаполнитьОсновныеПараметры(Параметр) | |
Части = СтрРазделить(Параметр, "=", Ложь); | |
Наименование = Части[0]; | |
Если Части.Количество() > 1 Тогда | |
Значение = Части[1]; | |
КонецЕсли; | |
Возврат Конструктор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НеявнымиЗначениями(Cookie, URL) | |
Если Cookie = Неопределено Тогда | |
Возврат; | |
КонецЕсли; | |
СтруктураURL = РазобратьURL(URL); | |
Если Не ЗначениеЗаполнено(Cookie.Домен) Тогда | |
Cookie.Домен = СтруктураURL.Сервер; | |
КонецЕсли; | |
Если Не ЗначениеЗаполнено(Cookie.Порт) И ЗначениеЗаполнено(СтруктураURL.Порт) Тогда | |
Cookie.Порт = СтруктураURL.Порт; | |
КонецЕсли; | |
Если Не ЗначениеЗаполнено(Cookie.Путь) Тогда | |
ПозицияПоследнегоСлеша = СтрНайти(СтруктураURL.Путь, "/", НаправлениеПоиска.СКонца); | |
Если ПозицияПоследнегоСлеша <= 1 Тогда | |
Cookie.Путь = "/"; | |
Иначе | |
Cookie.Путь = Лев(СтруктураURL.Путь, ПозицияПоследнегоСлеша - 1); | |
КонецЕсли; | |
КонецЕсли; | |
КонецПроцедуры | |
Функция ЗначениеЗаголовка(Заголовок, ВсеЗаголовки, Ключ = Неопределено) | |
Для Каждого ОчереднойЗаголовок Из ВсеЗаголовки Цикл | |
Если НРег(ОчереднойЗаголовок.Ключ) = НРег(Заголовок) Тогда | |
Ключ = ОчереднойЗаголовок.Ключ; | |
Возврат ОчереднойЗаголовок.Значение; | |
КонецЕсли; | |
КонецЦикла; | |
Возврат Ложь; | |
КонецФункции | |
Функция ЭтоПостоянныйРедирект(КодСостояния, Заголовки) | |
КодыСостоянияHTTP = КодыСостоянияHTTP(); | |
Возврат ЕстьЗаголовокLocation(Заголовки) И | |
(КодСостояния = КодыСостоянияHTTP.ПеремещеноНавсегда_301 | |
ИЛИ КодСостояния = КодыСостоянияHTTP.ПостоянноеПеренаправление_308); | |
КонецФункции | |
Функция ЭтоРедирект(КодСостояния, Заголовки) | |
КодыСостоянияHTTP = КодыСостоянияHTTP(); | |
СостоянияРедиректа = Новый Массив; | |
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ПеремещеноНавсегда_301); | |
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ПеремещеноВременно_302); | |
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.СмотретьДругое_303); | |
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ВременноеПеренаправление_307); | |
СостоянияРедиректа.Добавить(КодыСостоянияHTTP.ПостоянноеПеренаправление_308); | |
Возврат ЕстьЗаголовокLocation(Заголовки) И СостоянияРедиректа.Найти(КодСостояния) <> Неопределено; | |
КонецФункции | |
Функция ЕстьЗаголовокLocation(Заголовки) | |
Возврат ЗначениеЗаголовка("location", Заголовки) <> Ложь; | |
КонецФункции | |
Функция КодировкаИзЗаголовка(Знач Заголовок) | |
Кодировка = Неопределено; | |
Заголовок = НРег(СокрЛП(Заголовок)); | |
ИндексРазделителя = СтрНайти(Заголовок, ";"); | |
Если ИндексРазделителя Тогда | |
ТипСодержимого = СокрЛП(Лев(Заголовок, ИндексРазделителя - 1)); | |
КлючКодировки = "charset="; | |
ИндексКодировки = СтрНайти(Заголовок, КлючКодировки); | |
Если ИндексКодировки Тогда | |
ИндексРазделителя = СтрНайти(Заголовок, ";", НаправлениеПоиска.СНачала, ИндексКодировки); | |
НачальнаяПозиция = ИндексКодировки + СтрДлина(КлючКодировки); | |
Если ИндексРазделителя Тогда | |
ДлинаКодировки = ИндексРазделителя - НачальнаяПозиция; | |
Иначе | |
ДлинаКодировки = СтрДлина(Заголовок); | |
КонецЕсли; | |
Кодировка = Сред(Заголовок, НачальнаяПозиция, ДлинаКодировки); | |
Кодировка = СтрЗаменить(Кодировка, """", ""); | |
Кодировка = СтрЗаменить(Кодировка, "'", ""); | |
КонецЕсли; | |
Иначе | |
ТипСодержимого = Заголовок; | |
КонецЕсли; | |
Если Кодировка = Неопределено И СтрНайти(ТипСодержимого, "text") Тогда | |
Кодировка = "iso-8859-1"; | |
КонецЕсли; | |
Возврат Кодировка; | |
КонецФункции | |
Функция СобратьАдресРесурса(СтруктураURL, ПараметрыЗапроса) | |
АдресРесурса = СтруктураURL.Путь; | |
ОбъединенныеПараметрыЗапроса = ОбъединитьПараметрыЗапроса(ПараметрыЗапроса, СтруктураURL.ПараметрыЗапроса); | |
Если ЗначениеЗаполнено(ОбъединенныеПараметрыЗапроса) Тогда | |
АдресРесурса = АдресРесурса + "?" + КодироватьПараметрыЗапроса(ОбъединенныеПараметрыЗапроса); | |
КонецЕсли; | |
Если ЗначениеЗаполнено(СтруктураURL.Фрагмент) Тогда | |
АдресРесурса = АдресРесурса + "#" + СтруктураURL.Фрагмент; | |
КонецЕсли; | |
Возврат АдресРесурса; | |
КонецФункции | |
Функция ЗащищенноеСоединение(ДополнительныеПараметры) | |
Если ДополнительныеПараметры.ПроверятьSSL = Ложь Тогда | |
СертификатыУЦ = Неопределено; | |
ИначеЕсли ТипЗнч(ДополнительныеПараметры.ПроверятьSSL) = Тип("СертификатыУдостоверяющихЦентровФайл") Тогда | |
СертификатыУЦ = ДополнительныеПараметры.ПроверятьSSL; | |
Иначе | |
СертификатыУЦ = Новый СертификатыУдостоверяющихЦентровОС; | |
КонецЕсли; | |
КлиентскийСертификат = Неопределено; | |
Если ДополнительныеПараметры.КлиентскийСертификатSSL = Тип("СертификатКлиентаФайл") | |
ИЛИ ДополнительныеПараметры.КлиентскийСертификатSSL = Тип("СертификатКлиентаWindows") Тогда | |
КлиентскийСертификат = ДополнительныеПараметры.КлиентскийСертификатSSL; | |
КонецЕсли; | |
Возврат Новый ЗащищенноеСоединениеOpenSSL(КлиентскийСертификат, СертификатыУЦ); | |
КонецФункции | |
Функция Соединение(ПараметрыСоединения, Аутентификация, ДополнительныеПараметры, Сессия) | |
Если Не ЗначениеЗаполнено(ПараметрыСоединения.Порт) Тогда | |
Если ПараметрыСоединения.Схема = "https" Тогда | |
ПараметрыСоединения.Порт = 443; | |
Иначе | |
ПараметрыСоединения.Порт = 80; | |
КонецЕсли; | |
КонецЕсли; | |
ЗащищенноеСоединение = Неопределено; | |
Если ПараметрыСоединения.Схема = "https" Тогда | |
ЗащищенноеСоединение = ЗащищенноеСоединение(ДополнительныеПараметры); | |
КонецЕсли; | |
Пользователь = ""; | |
Пароль = ""; | |
Если ЗначениеЗаполнено(Аутентификация) Тогда | |
Если Аутентификация.Свойство("Пользователь") И Аутентификация.Свойство("Пароль") Тогда | |
Пользователь = Аутентификация.Пользователь; | |
Пароль = Аутентификация.Пароль; | |
КонецЕсли; | |
КонецЕсли; | |
ИспользоватьАутентификациюОС = Аутентификация.Свойство("ИспользоватьАутентификациюОС") | |
И Аутентификация.ИспользоватьАутентификациюОС = Истина; | |
ПараметрыДляРасчетаИдентификатора = Новый Массив; | |
ПараметрыДляРасчетаИдентификатора.Добавить(ПараметрыСоединения.Сервер); | |
ПараметрыДляРасчетаИдентификатора.Добавить(ПараметрыСоединения.Порт); | |
ПараметрыДляРасчетаИдентификатора.Добавить(Пользователь); | |
ПараметрыДляРасчетаИдентификатора.Добавить(Пароль); | |
ПараметрыДляРасчетаИдентификатора.Добавить(ДополнительныеПараметры.Таймаут); | |
ПараметрыДляРасчетаИдентификатора.Добавить(ИспользоватьАутентификациюОС); | |
ПараметрыДляРасчетаИдентификатора.Добавить(ЗащищенноеСоединение); | |
ПараметрыДляРасчетаИдентификатора.Добавить(ДополнительныеПараметры.Прокси); | |
Если Не Сессия.Свойство("СлужебныеДанные") ИЛИ ТипЗнч(Сессия.СлужебныеДанные) <> Тип("Структура") Тогда | |
Сессия.Вставить("СлужебныеДанные", Новый Структура); | |
КонецЕсли; | |
Если Не Сессия.СлужебныеДанные.Свойство("ПулСоединений") Тогда | |
Сессия.СлужебныеДанные.Вставить("ПулСоединений", Новый Соответствие); | |
КонецЕсли; | |
ПулСоединений = Сессия.СлужебныеДанные.ПулСоединений; | |
ИдентификаторСоединения = ИдентификаторСоединения(ПараметрыДляРасчетаИдентификатора); | |
Если ПулСоединений.Получить(ИдентификаторСоединения) = Неопределено Тогда | |
НовоеСоединение = Новый HTTPСоединение( | |
ПараметрыСоединения.Сервер, | |
ПараметрыСоединения.Порт, | |
Пользователь, Пароль, | |
ДополнительныеПараметры.Прокси, | |
ДополнительныеПараметры.Таймаут, | |
ЗащищенноеСоединение, | |
ИспользоватьАутентификациюОС); | |
ПулСоединений.Вставить(ИдентификаторСоединения, НовоеСоединение); | |
КонецЕсли; | |
Возврат ПулСоединений[ИдентификаторСоединения]; | |
КонецФункции | |
Функция ИдентификаторСоединения(ПараметрыСоединения) | |
ПараметрыДляРасчетаИдентификатора = Новый Массив; | |
Для Каждого Элемент Из ПараметрыСоединения Цикл | |
ТипЭлемента = ТипЗнч(Элемент); | |
Если ТипЭлемента = Тип("ИнтернетПрокси") Тогда | |
ПараметрыДляРасчетаИдентификатора.Добавить(СтрСоединить(Элемент.НеИспользоватьПроксиДляАдресов, "")); | |
ПараметрыДляРасчетаИдентификатора.Добавить(XMLСтрока(Элемент.НеИспользоватьПроксиДляЛокальныхАдресов)); | |
ПараметрыДляРасчетаИдентификатора.Добавить(Элемент.Пользователь); | |
ПараметрыДляРасчетаИдентификатора.Добавить(Элемент.Пароль); | |
ИначеЕсли ТипЭлемента = Тип("ЗащищенноеСоединениеOpenSSL") Тогда | |
// Для упрощения будет считать, что сертификаты в рамках сессии не меняются | |
Если Элемент.СертификатКлиента = Неопределено Тогда | |
ПараметрыДляРасчетаИдентификатора.Добавить(""); | |
Иначе | |
ПараметрыДляРасчетаИдентификатора.Добавить(Строка(ТипЗнч(Элемент.СертификатКлиента))); | |
КонецЕсли; | |
Если Элемент.СертификатыУдостоверяющихЦентров = Неопределено Тогда | |
ПараметрыДляРасчетаИдентификатора.Добавить(""); | |
Иначе | |
ПараметрыДляРасчетаИдентификатора.Добавить(Строка(ТипЗнч(Элемент.СертификатыУдостоверяющихЦентров))); | |
КонецЕсли; | |
Иначе | |
ПараметрыДляРасчетаИдентификатора.Добавить(XMLСтрока(Элемент)); | |
КонецЕсли; | |
КонецЦикла; | |
Возврат ХешированиеДанных(ХешФункция.MD5, СтрСоединить(ПараметрыДляРасчетаИдентификатора, "")); | |
КонецФункции | |
Функция ВыбратьЗначение(ОсновноеЗначение, ДополнительныеЗначения, Ключ, ЗначениеПоУмолчанию) | |
Если ОсновноеЗначение <> Неопределено Тогда | |
Возврат ОсновноеЗначение; | |
КонецЕсли; | |
Значение = ЗначениеПоКлючу(ДополнительныеЗначения, Ключ); | |
Если Значение <> Неопределено Тогда | |
Возврат Значение; | |
КонецЕсли; | |
Возврат ЗначениеПоУмолчанию; | |
КонецФункции | |
Функция ЗаполнитьПараметрыЗапроса(Путь) | |
ПараметрыЗапроса = Новый Соответствие; | |
Запрос = ""; | |
РазбитьСтрокуПоРазделителю(Запрос, Путь, "?", Истина); | |
Для Каждого СтрокаКлючРавноПараметр Из СтрРазделить(Запрос, "&", Ложь) Цикл | |
СтрокаКлючРавноПараметр = РаскодироватьСтроку( | |
СтрокаКлючРавноПараметр, СпособКодированияСтроки.URLВКодировкеURL); | |
ПозицияРавно = СтрНайти(СтрокаКлючРавноПараметр, "="); | |
Если ПозицияРавно = 0 Тогда | |
Ключ = СтрокаКлючРавноПараметр; | |
Значение = Неопределено; | |
Иначе | |
Ключ = Лев(СтрокаКлючРавноПараметр, ПозицияРавно - 1); | |
Значение = Сред(СтрокаКлючРавноПараметр, ПозицияРавно + 1); | |
КонецЕсли; | |
Если ПараметрыЗапроса.Получить(Ключ) <> Неопределено Тогда | |
Если ТипЗнч(ПараметрыЗапроса[Ключ]) = Тип("Массив") Тогда | |
ПараметрыЗапроса[Ключ].Добавить(Значение); | |
Иначе | |
Значения = Новый Массив; | |
Значения.Добавить(ПараметрыЗапроса[Ключ]); | |
Значения.Добавить(Значение); | |
ПараметрыЗапроса[Ключ] = Значения; | |
КонецЕсли; | |
Иначе | |
ПараметрыЗапроса.Вставить(Ключ, Значение); | |
КонецЕсли; | |
КонецЦикла; | |
Возврат ПараметрыЗапроса; | |
КонецФункции | |
Процедура РазбитьСтрокуПоРазделителю(ИзвлекаемаяЧасть, ОстальнаяЧасть, Разделитель, Инверсия = Ложь) | |
Индекс = СтрНайти(ОстальнаяЧасть, Разделитель); | |
Если Индекс Тогда | |
ИзвлекаемаяЧасть = Лев(ОстальнаяЧасть, Индекс - 1); | |
ОстальнаяЧасть = Сред(ОстальнаяЧасть, Индекс + СтрДлина(Разделитель)); | |
Если Инверсия Тогда | |
ДляОбмена = ИзвлекаемаяЧасть; | |
ИзвлекаемаяЧасть = ОстальнаяЧасть; | |
ОстальнаяЧасть = ДляОбмена; | |
КонецЕсли; | |
КонецЕсли; | |
КонецПроцедуры | |
Функция РазделитьПоПервомуНайденномуРазделителю(Строка, Разделители) | |
МинимальныйИндекс = СтрДлина(Строка); | |
ПервыйРазделитель = ""; | |
Для Каждого Разделитель Из Разделители Цикл | |
Индекс = СтрНайти(Строка, Разделитель); | |
Если Индекс = 0 Тогда | |
Продолжить; | |
КонецЕсли; | |
Если Индекс < МинимальныйИндекс Тогда | |
МинимальныйИндекс = Индекс; | |
ПервыйРазделитель = Разделитель; | |
КонецЕсли; | |
КонецЦикла; | |
Результат = Новый Массив; | |
Если ЗначениеЗаполнено(ПервыйРазделитель) Тогда | |
Результат.Добавить(Лев(Строка, МинимальныйИндекс - 1)); | |
Результат.Добавить(Сред(Строка, МинимальныйИндекс + СтрДлина(ПервыйРазделитель))); | |
Результат.Добавить(ПервыйРазделитель); | |
Иначе | |
Результат.Добавить(Строка); | |
Результат.Добавить(""); | |
Результат.Добавить(Неопределено); | |
КонецЕсли; | |
Возврат Результат; | |
КонецФункции | |
Функция ДополнитьПараметрыПреобразованияJSON(ПараметрыПреобразования) | |
ПараметрыПреобразованияJSON = ПараметрыПреобразованияJSONПоУмолчанию(); | |
Если ЗначениеЗаполнено(ПараметрыПреобразования) Тогда | |
Для Каждого Параметр Из ПараметрыПреобразования Цикл | |
Если ПараметрыПреобразованияJSON.Свойство(Параметр.Ключ) Тогда | |
ПараметрыПреобразованияJSON.Вставить(Параметр.Ключ, Параметр.Значение); | |
КонецЕсли; | |
КонецЦикла; | |
КонецЕсли; | |
Возврат ПараметрыПреобразованияJSON; | |
КонецФункции | |
Функция ДополнитьПараметрыЗаписиJSON(ПараметрыЗаписи) | |
ПараметрыЗаписиJSON = ПараметрыЗаписиJSONПоУмолчанию(); | |
Если ЗначениеЗаполнено(ПараметрыЗаписи) Тогда | |
Для Каждого Параметр Из ПараметрыЗаписи Цикл | |
Если ПараметрыЗаписиJSON.Свойство(Параметр.Ключ) Тогда | |
ПараметрыЗаписиJSON.Вставить(Параметр.Ключ, Параметр.Значение); | |
КонецЕсли; | |
КонецЦикла; | |
КонецЕсли; | |
Возврат ПараметрыЗаписиJSON; | |
КонецФункции | |
#Область Аутентификация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Запрос.Заголовки = ПодготовленныйЗапрос.Заголовки; | |
КонецПроцедуры | |
Функция ЭтоСтандартныйПорт(СтруктураURL) | |
СтандартныйПортHTTP = 80; | |
СтандартныйПортHTTPS = 443; | |
Возврат (СтруктураURL.Схема = "http" И СтруктураURL.Порт = СтандартныйПортHTTP) | |
ИЛИ (СтруктураURL.Схема = "https" И СтруктураURL.Порт = СтандартныйПортHTTPS); | |
КонецФункции | |
Функция СформироватьЗначениеЗаголовкаHost(СтруктураURL) | |
Host = СтруктураURL.Сервер; | |
Если ЗначениеЗаполнено(СтруктураURL.Порт) И НЕ ЭтоСтандартныйПорт(СтруктураURL) Тогда | |
Host = Host + ":" + Формат(СтруктураURL.Порт, "ЧРГ=; ЧГ="); | |
КонецЕсли; | |
Возврат Host; | |
КонецФункции | |
Функция КаноническиеЗаголовкиAWS4(Заголовки, СтруктураURL) | |
Список = Новый СписокЗначений; | |
ЗаголовокHostЕстьВЗапросе = Ложь; | |
ЗаголовкиПоУмолчанию = ЗаголовкиПоУмолчаниюAWS4(); | |
Для Каждого ОчереднойЗаголовок Из Заголовки Цикл | |
Заголовок = НРег(ОчереднойЗаголовок.Ключ); | |
Если ЗаголовкиПоУмолчанию.Исключения.Найти(Заголовок) <> Неопределено Тогда | |
Продолжить; | |
КонецЕсли; | |
ЗаголовокHostЕстьВЗапросе = Макс(ЗаголовокHostЕстьВЗапросе, Заголовок = "host"); | |
Если ЗаголовкиПоУмолчанию.Равно.Найти(Заголовок) <> Неопределено Тогда | |
Список.Добавить(Заголовок, СокрЛП(ОчереднойЗаголовок.Значение)); | |
Иначе | |
Для Каждого Префикс Из ЗаголовкиПоУмолчанию.НачинаетсяС Цикл | |
Если СтрНачинаетсяС(Заголовок, Префикс) Тогда | |
Список.Добавить(Заголовок, СокрЛП(ОчереднойЗаголовок.Значение)); | |
Прервать; | |
КонецЕсли; | |
КонецЦикла; | |
КонецЕсли; | |
КонецЦикла; | |
Если Не ЗаголовокHostЕстьВЗапросе Тогда | |
Список.Добавить("host", СформироватьЗначениеЗаголовкаHost(СтруктураURL)); | |
КонецЕсли; | |
Список.СортироватьПоЗначению(НаправлениеСортировки.Возр); | |
КаноническиеЗаголовки = Новый Массив; | |
ПодписываемыеЗаголовки = Новый Массив; | |
Для Каждого ЭлементСписка Из Список Цикл | |
КаноническиеЗаголовки.Добавить(ЭлементСписка.Значение + ":" + ЭлементСписка.Представление); | |
ПодписываемыеЗаголовки.Добавить(ЭлементСписка.Значение); | |
КонецЦикла; | |
КаноническиеЗаголовки.Добавить(""); | |
КаноническиеЗаголовки = СтрСоединить(КаноническиеЗаголовки, Символы.ПС); | |
ПодписываемыеЗаголовки = СтрСоединить(ПодписываемыеЗаголовки, ";"); | |
Возврат Новый Структура( | |
"КаноническиеЗаголовки, ПодписываемыеЗаголовки", | |
КаноническиеЗаголовки, ПодписываемыеЗаголовки); | |
КонецФункции | |
Функция КаноническиеПараметрыЗапросаAWS4(ПараметрыЗапроса) | |
Список = Новый СписокЗначений; | |
Для Каждого ОчереднойПараметрЗапроса Из ПараметрыЗапроса Цикл | |
Список.Добавить(ОчереднойПараметрЗапроса.Ключ, СокрЛП(ОчереднойПараметрЗапроса.Значение)); | |
КонецЦикла; | |
Список.СортироватьПоЗначению(НаправлениеСортировки.Возр); | |
КаноническиеПараметры = Новый Массив; | |
Для Каждого ЭлементСписка Из Список Цикл | |
ЗначениеПараметра = КодироватьСтроку(ЭлементСписка.Представление, СпособКодированияСтроки.КодировкаURL); | |
КаноническиеПараметры.Добавить(ЭлементСписка.Значение + "=" + ЗначениеПараметра); | |
КонецЦикла; | |
Возврат СтрСоединить(КаноническиеПараметры, "&"); | |
КонецФункции | |
Функция ЗаголовкиПоУмолчаниюAWS4() | |
Заголовки = Новый Структура; | |
Заголовки.Вставить("Равно", СтрРазделить("host,content-type,date", ",")); | |
Заголовки.Вставить("НачинаетсяС", СтрРазделить("x-amz-", ",")); | |
Заголовки.Вставить("Исключения", СтрРазделить("x-amz-client-context", ",")); | |
Возврат Заголовки; | |
КонецФункции | |
#КонецОбласти | |
#Область КодированиеДекодированиеДанных | |
#Область СлужебныеСтруктуры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.ЗакрытьИПолучитьДвоичныеДанные(); | |
#КонецЕсли | |
КонецФункции | |
#КонецОбласти | |
#Область ОбработчикиСобытий | |
Процедура ОбработкаОтветаСКодом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Запрос(Сессия, ПодготовленныйЗапрос, Настройки); | |
КонецЕсли; | |
КонецПроцедуры | |
Функция ОпределитьХешФункцию(Знач Алгоритм) | |
Алгоритм = ВРег(Алгоритм); | |
Если Не ЗначениеЗаполнено(Алгоритм) ИЛИ Алгоритм = "MD5" ИЛИ Алгоритм = "MD5-SESS" Тогда | |
Возврат ХешФункция.MD5; | |
ИначеЕсли Алгоритм = "SHA" Тогда | |
Возврат ХешФункция.SHA1; | |
ИначеЕсли Алгоритм = "SHA-256" Тогда | |
Возврат ХешФункция.SHA256; | |
Иначе | |
Возврат Неопределено; | |
КонецЕсли; | |
КонецФункции | |
Функция ПодготовитьЗаголовок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", СтрСоединить(Строки, "")); | |
КонецФункции | |
Функция ХешированиеДанных(Знач Алгоритм, Знач Данные) | |
Если ТипЗнч(Данные) = Тип("Строка") Тогда | |
Данные = ПолучитьДвоичныеДанныеИзСтроки(Данные, КодировкаТекста.UTF8, Ложь); | |
КонецЕсли; | |
Хеширование = Новый ХешированиеДанных(Алгоритм); | |
Хеширование.Добавить(Данные); | |
Возврат НРег(ПолучитьHexСтрокуИзДвоичныхДанных(Хеширование.ХешСумма)); | |
КонецФункции | |
Функция РазбитьСтрокуПоСтроке(Знач Строка, Разделитель) | |
Результат = Новый Массив; | |
Пока Истина Цикл | |
Позиция = СтрНайти(Строка, Разделитель); | |
Если Позиция = 0 И ЗначениеЗаполнено(Строка) Тогда | |
Результат.Добавить(Строка); | |
Прервать; | |
КонецЕсли; | |
ПерваяЧасть = Лев(Строка, Позиция - СтрДлина(Разделитель) + 1); | |
Результат.Добавить(ПерваяЧасть); | |
Строка = Сред(Строка, Позиция + СтрДлина(Разделитель)); | |
КонецЦикла; | |
Возврат Результат; | |
КонецФункции | |
#КонецОбласти | |
Функция РаспаковатьОтвет(Ответ) | |
Заголовок = ЗначениеЗаголовка("content-encoding", Ответ.Заголовки); | |
Если Заголовок <> Ложь Тогда | |
Если НРег(Заголовок) = "gzip" Тогда | |
Возврат ПрочитатьGZip(Ответ.Тело); | |
КонецЕсли; | |
КонецЕсли; | |
Возврат Ответ.Тело; | |
КонецФункции | |
Процедура УпаковатьЗапрос(Запрос) | |
Заголовок = ЗначениеЗаголовка("content-encoding", Запрос.Заголовки); | |
Если Заголовок <> Ложь Тогда | |
Если НРег(Заголовок) = "gzip" Тогда | |
Запрос.УстановитьТелоИзДвоичныхДанных(ЗаписатьGZip(Запрос.ПолучитьТелоКакДвоичныеДанные())); | |
КонецЕсли; | |
КонецЕсли; | |
КонецПроцедуры | |
#Область ПараметрыПоУмолчанию | |
Функция ЗаголовкиПоУмолчанию() | |
Заголовки = Новый Соответствие; | |
#Если МобильноеПриложениеСервер Тогда | |
Заголовки.Вставить("Accept-Encoding", "identity"); | |
#Иначе | |
Заголовки.Вставить("Accept-Encoding", "gzip"); | |
#КонецЕсли | |
Заголовки.Вставить("Accept", "*/*"); | |
Заголовки.Вставить("Connection", "keep-alive"); | |
Возврат Заголовки; | |
КонецФункции | |
Функция МаксимальноеКоличествоПеренаправлений() | |
Возврат 30; | |
КонецФункции | |
Функция СтандартныйТаймаут() | |
Возврат 30; | |
КонецФункции | |
Функция ПараметрыПреобразованияJSONПоУмолчанию() | |
ПараметрыПреобразованияПоУмолчанию = Новый Структура; | |
ПараметрыПреобразованияПоУмолчанию.Вставить("ПрочитатьВСоответствие", Истина); | |
ПараметрыПреобразованияПоУмолчанию.Вставить("ФорматДатыJSON", ФорматДатыJSON.ISO); | |
ПараметрыПреобразованияПоУмолчанию.Вставить("ИменаСвойствСоЗначениямиДата", Неопределено); | |
Возврат ПараметрыПреобразованияПоУмолчанию; | |
КонецФункции | |
Функция ПараметрыЗаписиJSONПоУмолчанию() | |
ПараметрыЗаписиJSONПоУмолчанию = Новый Структура; | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ПереносСтрок", ПереносСтрокJSON.Авто); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("СимволыОтступа", " "); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ИспользоватьДвойныеКавычки", Истина); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранированиеСимволов", ЭкранированиеСимволовJSON.Нет); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьУгловыеСкобки", Ложь); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьРазделителиСтрок", Истина); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьАмперсанд", Ложь); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьОдинарныеКавычки", Ложь); | |
ПараметрыЗаписиJSONПоУмолчанию.Вставить("ЭкранироватьСлеш", Ложь); | |
Возврат ПараметрыЗаписиJSONПоУмолчанию; | |
КонецФункции | |
#КонецОбласти | |
Процедура ЗаполнитьДополнительныеДанные(ДополнительныеПараметры, ПараметрыЗапроса, Данные, Json) | |
Если ДополнительныеПараметры = Неопределено Тогда | |
ДополнительныеПараметры = Новый Структура(); | |
КонецЕсли; | |
Если Не ДополнительныеПараметры.Свойство("ПараметрыЗапроса") Тогда | |
ДополнительныеПараметры.Вставить("ПараметрыЗапроса", ПараметрыЗапроса); | |
КонецЕсли; | |
Если Не ДополнительныеПараметры.Свойство("Данные") Тогда | |
ДополнительныеПараметры.Вставить("Данные", Данные); | |
КонецЕсли; | |
Если Не ДополнительныеПараметры.Свойство("Json") Тогда | |
ДополнительныеПараметры.Вставить("Json", Json); | |
КонецЕсли; | |
КонецПроцедуры | |
// Когда-нибудь в платформе сделают паузу и это можно будет выкинуть | |
// | |
Процедура Приостановить(ДлительностьОстановкиВСекундах) | |
Если ДлительностьОстановкиВСекундах < 1 Тогда | |
Возврат; | |
КонецЕсли; | |
ТекущаяДата = ТекущаяУниверсальнаяДата(); | |
ЖдатьДо = ТекущаяДата + ДлительностьОстановкиВСекундах; | |
// BSLLS:UsingHardcodeNetworkAddress-off | |
ЛокальныйХост = "127.0.0.0"; | |
КакойНибудьСвободныйПорт = 56476; | |
// BSLLS:UsingHardcodeNetworkAddress-on | |
Пока ТекущаяДата < ЖдатьДо Цикл | |
Таймаут = ЖдатьДо - ТекущаяДата; | |
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах(); | |
Попытка | |
Соединение = Новый HTTPСоединение( | |
ЛокальныйХост, КакойНибудьСвободныйПорт, Неопределено, Неопределено, Неопределено, Таймаут); | |
Соединение.Получить(Новый HTTPЗапрос("/does_not_matter")); | |
Исключение | |
РеальныйТаймаут = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало; | |
КонецПопытки; | |
МинимальныйТаймаутВМиллисекундах = 1000; | |
Если РеальныйТаймаут < МинимальныйТаймаутВМиллисекундах Тогда | |
ВызватьИсключение(НСтр("ru = 'Процедура Приостановить не работает должным образом'")); | |
КонецЕсли; | |
ТекущаяДата = ТекущаяУниверсальнаяДата(); | |
КонецЦикла; | |
КонецПроцедуры | |
Функция ТекущаяСессия(Сессия) | |
Если Сессия = Неопределено Тогда | |
Сессия = СоздатьСессию(); | |
КонецЕсли; | |
Возврат Сессия; | |
КонецФункции | |
#КонецОбласти |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment