Print This Post Классы для работы с HTTP(S) на C++

Пятница, 6. Январь 2012
Раздел: C/C++, Софт, автор:

Написал кроссплатформенную библиотеку (набор классов) для работы с HTTP(S) на C++, используя последние концепции программирования. Пока что это, пожалуй, beta, так как тестировал я ее совсем мало.

Для сборки библиотеки потребуется собранный Boost (желательно версии 1.48 или выше). Если планируется включение функционала для работы с SSL (HTTPS), то потребуется еще собранная библиотека OpenSSL. Также в обязательном порядке требуется поддержка компилятором C++11. Сами заголовочные файлы библиотеки не включают ни заголовочные файлы boost, ни OpenSSL.

Для тех, кто захочет использовать библиотеку для написания чего-то жестоко многопоточного (конечно, спамеров, а что же еще подобное пишут с дохера потоками), учтите, что каждый запрос создает 1 дополнительный фоновый поток, т.е. количество потоков, используемых приложением, увеличивается вдвое. Такая особенность работы связана с тем, что в своем ядре библиотека использует boost::asio::io_service для контроля времени выполнения запроса (словом, внутри библиотеки всё происходит асинхронно).

Краткое описание возможностей класса:
[+] GET/POST/прочие запросы с использованием HTTP/1.0
[+] Поддержка HTTPS
[+] Поддержка multipart-POST запросов с возможностью загрузки произвольного количества файлов любого размера
[+] Автоматический менеджмент Cookies
[+] Автоматические переходы по Location-редиректам
[+] Поддержка скачивания больших файлов
[+] Поддержка HTTP/HTTPS/SOCKS5-прокси с авторизацией и без
[+] Возможность добавлять собственные HTTP-заголовки в запрос
[+] Поддержка автоматической обработки параметров (urlencode)
[+] Возможность задать таймаут на любой запрос
[+] Множество вспомогательных функций (urlencode, base64 и т.п.)

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

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

1. Простой пример HTTP GET-запроса.

Пара строк кода, чтобы совершить GET-запрос. Что может быть проще? Дальнейшие примеры не будут уступать этому по простоте.

На заметку. Метод simple_http::http_endpoint::from_string создает экземпляр класса http_endpoint, который разделяет переданную ему строку URL на следующие независимые элементы:
- HTTP/HTTPS
- HOST/IP address
- порт (если есть)
- URI (если есть)
- параметры запроса (если есть)

Если передать объект класса http_endpoint в метод get, то параметры будут переданы методом GET, а если в post, то, соответственно, методом POST.

2. Запросы с автоматическим менеджментом Cookies.
Для автоматического менеджмента Cookies существует класс cookie_manager.

Далее могут следовать любые HTTP(S)-запросы, кукисы для них будут автоматически сохраняться менеджером и подставляться, когда это необходимо. Класс менеджера Cookies позволяет получить действительные Cookies для заданного домена, пути и т.д. Также можно добавлять собственные Cookies, они будут использоваться при HTTP(S)-запросах.

Для отключения автоматического менеджмента Cookies используется функция remove_auto_cookie_manager.

Класс cookie_manager имеет множество методов, позволяющих получить определенные Cookies, добавить новые, удалить какие-то определенные или все сразу и т.д. Описание я приводить не буду, так как они имеют достаточно очевидные названия и прототипы.

3. Установка таймаута на запрос.
Для того, чтобы установить максимальное время, которое может выполняться запрос, используется функция set_query_timeout, которая принимает как аргумент максимальное значение времени в секундах. По умолчанию на каждый запрос отводится 60 секунд. Если при запросе используются прокси, то время их отклика включается в этот таймаут.

4. Использование http proxy/socks5 с авторизацией или без для запросов.
Для установки proxy для запросов используются следующие методы класса http_sync_connection:

address - строка адреса прокси (IP-адрес или имя хоста).
port - порт прокси
ptype - тип прокси: proxy_none - убрать прокси, proxy_http - HTTP-прокси, proxy_socks5 - SOCKS5-прокси.
login, password - логин и пароль прокси-сервера.

Позволяет очистить текущий прокси-сервер.

5. Использование автоматических переходов по редиректам.

Включает/отключает автоматические переходы по редиректам (Location). По умолчанию выключено.

Включает/отключает переходы по Location на другие домены (например, если встретится редирект с mail.ru на yandex.ru, то при выключенной опции он не будет произведен автоматически). По умолчанию включено.

Устанавливает максимальное количество автоматических переходов по редиректам. По умолчанию 10.

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

Позволяет получить количество сделанных авторедиректов во время последнего HTTP(S)-запроса.

Если библиотека собрана без поддержки SSL, и в каком-либо ответе от сервера встречается редирект с HTTP на HTTPS, он произведен не будет, даже если включена опция автоматического перехода по редиректам.

6. Дополнительные заголовки запроса.
Для добавления/удаления дополнительных заголовков в запрос используются следующие функции:

Первая добавляет дополнительный заголовок с именем name и значением value.
Вторая удаляет дополнительный заголовок с именем name.
Третья удаляет все дополнительные заголовки.

7. User-agent.
Для установки заголовка User-agent есть удобная функция

Если ей передана пустая строка, заголовок User-agent отсылаться не будет.

8. Отправка запросов без использования http_endpoint.
Иногда может потребоваться отправка запросов без использования данного упрощающего класса (например, если требуется передать HTTP Referer или часть параметров методом GET, а другую часть - методом POST).

Класс http_sync_connection имеет следующие функции:

Первые две отправляют на сервер, соответственно, GET и POST запрос. Третья позволяет явно задать тип запроса (например, "GET", "POST", "HEAD").
uri - Service-URI
parameters - параметры, которые необходимо передать на сервер. Функция get передаст их методом GET, а post - методом POST.
cookies - cookie, которые необходимо добавить в запрос. Если включен автоматический менеджмент Cookies, эти кукисы будут добавлены к тем, которые отсылаются менеджером cookies.
referer - HTTP-Referer.

Три последние функции отличаются от первых трех только тем, что позволяют задать домен, порт, URI и параметры запроса с помощью класса http_endpoint.

9. Отправка файлов на сервер (Multipart POST-запросы).
Класс http_sync_connection поддерживает загрузку файлов на сервер с помощью multipart-запросов. Имеется три функции:

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

Второй вариант имеет дополнительные параметры:
multipart_file_parameter_name - имя прикрепляемого к запросу файла
file - сам файл (объект класса multipart_file).

Третий вариант позволяет прикрепить сразу несколько файлов к запросу. Для этого используется параметр files - список файлов с именами.

Три последние функции отличаются от первых трех только тем, что позволяют задать домен, порт, URI и параметры запроса с помощью класса http_endpoint.

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

Пример загрузки файла на сервер:

10. Кеширование DNS-запросов.

Эта функция позволяет включить или отключить кеширование DNS-запросов. По умолчанию кеширование включено. Если вы делаете много запросов подряд на один и тот же сервер, и данная функция включена, определение IP-адреса хоста будет производиться только один раз при первом запросе.

11. Автоматическая обработка параметров запроса (urlencode).
По умолчанию данная возможность выключена. Для ее включения/отключения используется функция

Если данная функция включена, будет производиться автоматическая обработка (urlencode) параметров запросов HTTP(S).

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

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

Данная функция отключает callback на чтение данных.

Данная функция устанавливает, должно ли очищаться возвращаемое значение функций get, post, query, multipart_post при использовании коллбека. По умолчанию включено.

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

Данная функция позволяет настроить поведение коллбека. По умолчанию это get_everything, т.е. из сокета читается весь контент. Доступны также значения get_headers_only (будут считаны только заголовки) и get_body_only (будет считано только тело).

Сам коллбек должен представлять из себя функтор, возвращающий bool. Чтение данных из сокета будет продолжаться до тех пор, пока коллбек возвращает true.

Пример использования коллбека для скачивания большого файла (при этом оперативной памяти будет расходоваться совсем немного):

13. Вспомогательные функции.
Файл utils.h содержит объявления различных вспомогательных функций для перекодирования base64, urlencode и т.д.
Файл functions.h содержит объявления вспомогательных функций для работы с ответами HTTP.

14. Исключения
Файл http_error.h содержит объявление класса, используемого для возбуждения исключений, возникающих при работе классов simple_http. Все примеры приведены без обработки исключений, чтобы сосредоточиться на их сути. Вообще, все вызовы функций и методов классов неймспейса simple_http должны оборачиваться в обработчик исключений. Класс http_error позволяет получить как текст сообщения об ошибке, так и его код (они перечислены внутри класса).

15. Сборка с поддержкой SSL.
Для того, чтобы собрать библиотеку с поддержкой SSL (чтобы работали HTTPS-запросы), необходимо задать директиву препроцессора SSL_SUPPORT. Если поддержка SSL отключена, класс http_sync_connection будет бросать исключение при попытке произвести HTTPS-запрос.

Наконец, последний пример - авторизуемся на Форуме АНТИЧАТ и получаем количество новых приватных сообщений и общее их количество.

Вот и всё! Приведенной информации вполне достаточно, чтобы полноценно работать с библиотекой.

Выкладываю исходники библиотеки и последнего примера: simple_http.zip. В комплекте - файл солюшена и проектов Visual Studio 2010. Не забудьте прописать свои пути к boost'у и OpenSSL (если вам потребуется поддержка HTTPS).

UPD 06.05.2013 - поправлен недочет при парсинге cookies.

 Обсудить на форуме


Получать обновления на почту:     

Комментариев: 92 к “Классы для работы с HTTP(S) на C++”


  1. Александр :

    Здравствуйте, какая-то ошибка в куки менеджере, при запросе отправляется только первая кука

    [Ответить]

    dx:

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

    [Ответить]


  2. Александр :

    Здравствуйте, ошибки не было, просто оказалось что сайт часть куков передаёт для домена с http://www., а часть без него, это я поправил в куки мэнеджере храня все куки без www. Но я немного не понял как отправлять post запрос, когда имеются и GET параметры, они автоматом в POST уходят, хотя это не требуется

    [Ответить]

    dx:

    Не уверен, что cookies для сайта с www могут быть валидны для сайта без www и наоборот (скорее всего нет). Нужно смотреть.

    Отправить POST с дополнительными GET-параметрами можно так:
    std::cout << conn.query("POST", "http://localhost/simple.php?c=3&d=4", "a=1&b=2"); //"c" и "d" уйдут в GET, "a" и "b" - в POST

    [Ответить]


  3. Александр :

    Всё-таки есть ошибка с куками есть, но не в менеджере, например, при авторизации на яндексе из 7 кук, в куки менеджер поступает только 5, хотя формат оставшихся 2-ух такой же.

    [Ответить]


  4. Александр :

    И еще ошибку нашёл: при запросе по ssl, если включен авторедирект, то при редиректе он почему-то делает запрос на 80-ый порт

    [Ответить]

    dx:

    Эта ошибка вроде бы действительно есть, поправлю. С кукисами еще посмотрю. Неплохо бы пример кода, который работает не так, как должен.

    [Ответить]


  5. Александр :

    И еще если можно, то добавить вывод последнего запроса (как респонс выводится, так же и реквест перед нем)

    [Ответить]


  6. Индустриалист :

    А в этой библиотеки есть аналог функции get_headers() из PHP?

    [Ответить]

    dx:

    Я не помню, библиотека старая очень +)

    [Ответить]


Оставьте ваш комментарий