Написал кроссплатформенную библиотеку (набор классов) для работы с 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-запроса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <iostream> #include <string> #include <simple_http/simple_http.h> #include <simple_http/http_endpoint.h> #include <simple_http/functions.h> int main() { //Создали объект http_sync_connection simple_http::http_sync_connection conn; /* Отправили GET-запрос серверу и получили ответ Поддерживаемые адреса в функции from_string() имеют вид http://kaimi.io http://kaimi.io/test/ https://www.google.com/ -> если библиотека собрана с поддержкой SSL http://mail.ru:80/?xxx=123 http://test.ru/qwerty/xxx.php?a=1&b=2&c=3 */ std::string ret = conn.get(simple_http::http_endpoint::from_string("http://localhost/uploader/test.php?xxx=123&zzz=123")); //Получили тело ответа и вывели его в консоль std::cout << simple_http::get_body(ret) << std::endl; return 0; } |
Пара строк кода, чтобы совершить 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.
1 2 3 |
simple_http::http_sync_connection conn; simple_http::cookie_manager manager; //создали менеджер conn.set_auto_cookie_manager(manager); //прикрепили его к HTTP-классу |
Далее могут следовать любые 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:
1 2 |
void set_proxy(const std::string& address, unsigned short port, proxy_type ptype); void set_proxy(const std::string& address, unsigned short port, proxy_type ptype, const std::string& login, const std::string& password); |
address - строка адреса прокси (IP-адрес или имя хоста).
port - порт прокси
ptype - тип прокси: proxy_none - убрать прокси, proxy_http - HTTP-прокси, proxy_socks5 - SOCKS5-прокси.
login, password - логин и пароль прокси-сервера.
1 |
void clear_proxy(); |
Позволяет очистить текущий прокси-сервер.
5. Использование автоматических переходов по редиректам.
1 |
void enable_auto_redirect_follow(bool follow = true); |
Включает/отключает автоматические переходы по редиректам (Location). По умолчанию выключено.
1 |
void enable_cross_domain_redirects(bool allow = true); |
Включает/отключает переходы по Location на другие домены (например, если встретится редирект с mail.ru на yandex.ru, то при выключенной опции он не будет произведен автоматически). По умолчанию включено.
1 |
void set_max_redirect_count(unsigned long count = 10); |
Устанавливает максимальное количество автоматических переходов по редиректам. По умолчанию 10.
1 2 3 4 |
std::string get_last_redirect_domain() const; std::string get_last_redirect_uri() const; std::string get_last_redirect_line() const; unsigned short get_last_redirect_port() const; |
Данные функции позволяют получить информацию о последнем произведенном редиректе: домен, URI, строку адреса редиректа и порт соответственно.
1 |
unsigned long get_recent_redirect_count() const; |
Позволяет получить количество сделанных авторедиректов во время последнего HTTP(S)-запроса.
Если библиотека собрана без поддержки SSL, и в каком-либо ответе от сервера встречается редирект с HTTP на HTTPS, он произведен не будет, даже если включена опция автоматического перехода по редиректам.
6. Дополнительные заголовки запроса.
Для добавления/удаления дополнительных заголовков в запрос используются следующие функции:
1 2 3 |
void add_query_header(const std::string& name, const std::string& value); bool remove_query_header(const std::string& name); void clear_query_headers(); |
Первая добавляет дополнительный заголовок с именем name и значением value.
Вторая удаляет дополнительный заголовок с именем name.
Третья удаляет все дополнительные заголовки.
7. User-agent.
Для установки заголовка User-agent есть удобная функция
1 |
void set_user_agent(const std::string& user_agent = ""); |
Если ей передана пустая строка, заголовок User-agent отсылаться не будет.
8. Отправка запросов без использования http_endpoint.
Иногда может потребоваться отправка запросов без использования данного упрощающего класса (например, если требуется передать HTTP Referer или часть параметров методом GET, а другую часть - методом POST).
Класс http_sync_connection имеет следующие функции:
1 2 3 4 5 6 7 |
std::string get(const std::string& uri, const std::string& parameters = "", const std::string& cookies = "", const std::string& referer = ""); std::string post(const std::string& uri, const std::string& parameters = "", const std::string& cookies = "", const std::string& referer = ""); std::string query(const std::string& method, const std::string& uri, const std::string& parameters = "", const std::string& cookies = "", const std::string& referer = ""); std::string get(const http_endpoint& ep, const std::string& cookies = "", const std::string& referer = ""); std::string post(const http_endpoint& ep, const std::string& cookies = "", const std::string& referer = ""); std::string query(const std::string& method, const http_endpoint& ep, const std::string& cookies = "", const std::string& referer = ""); |
Первые две отправляют на сервер, соответственно, 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-запросов. Имеется три функции:
1 2 3 4 5 6 7 |
std::string multipart_post(const std::string& uri, const std::string& parameters = "", const std::string& cookies = "", const std::string& referer = ""); std::string multipart_post(const std::string& uri, const std::string& multipart_file_parameter_name, multipart_file& file, const std::string& parameters = "", const std::string& cookies = "", const std::string& referer = ""); std::string multipart_post(const std::string& uri, std::map<std::string, multipart_file*>& files, const std::string& parameters = "", const std::string& cookies = "", const std::string& referer = ""); std::string multipart_post(const http_endpoint& ep, const std::string& multipart_file_parameter_name, multipart_file& file, const std::string& cookies = "", const std::string& referer = ""); std::string multipart_post(const http_endpoint& ep, std::map<std::string, multipart_file*>& files, const std::string& cookies = "", const std::string& referer = ""); std::string multipart_post(const http_endpoint& ep, const std::string& cookies = "", const std::string& referer = ""); |
Их параметры аналогичны вышеописанным get, post, query. Первый вариант функции ничем не отличается от функции post за исключением того, что данные будут отсылаться multipart-запросом.
Второй вариант имеет дополнительные параметры:
multipart_file_parameter_name - имя прикрепляемого к запросу файла
file - сам файл (объект класса multipart_file).
Третий вариант позволяет прикрепить сразу несколько файлов к запросу. Для этого используется параметр files - список файлов с именами.
Три последние функции отличаются от первых трех только тем, что позволяют задать домен, порт, URI и параметры запроса с помощью класса http_endpoint.
Класс multipart_file объявлен в заголовочном файле multipart_file.h и позволяет задать файл либо по его пути (физический файл операционной системы), либо как буфер данных.
Пример загрузки файла на сервер:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
int main() { simple_http::http_sync_connection conn; //Создали объект класса multipart_file simple_http::multipart_file file("file.bmp", "C:\\image.bmp"); //Загрузили этот файл на сервер и считали ответ std::cout << conn.multipart_post(simple_http::http_endpoint::from_string("http://localhost/uploader/5.php"), "uploaded_file", file) << std::endl; return 0; } |
10. Кеширование DNS-запросов.
1 |
void set_connenction_cache(bool enabled = true); |
Эта функция позволяет включить или отключить кеширование DNS-запросов. По умолчанию кеширование включено. Если вы делаете много запросов подряд на один и тот же сервер, и данная функция включена, определение IP-адреса хоста будет производиться только один раз при первом запросе.
11. Автоматическая обработка параметров запроса (urlencode).
По умолчанию данная возможность выключена. Для ее включения/отключения используется функция
1 |
void enable_auto_urlencode(bool enable = true); |
Если данная функция включена, будет производиться автоматическая обработка (urlencode) параметров запросов HTTP(S).
12. Callback при загрузке контента.
Если вы скачиваете большой файл или общаетесь с очень медленным сервером, возможно, есть смысл настроить callback, который будет вызываться при загрузке содержимого страницы.
1 2 |
template<typename Handler> void set_http_load_callback(Handler handler) |
Данная функция позволяет установить коллбек, который будет вызываться в процессе загрузки контента с сервера.
1 |
void clear_http_load_callback(); |
Данная функция отключает callback на чтение данных.
1 |
void clear_input_after_callback(bool clear = true); |
Данная функция устанавливает, должно ли очищаться возвращаемое значение функций get, post, query, multipart_post при использовании коллбека. По умолчанию включено.
1 |
void set_callback_min_transfer_amount(unsigned long bytes); |
Данная функция позволяет установить минимальное количество байтов, которое должно быть принято с сервера до вызова коллбека. По умолчанию 1.
1 |
void set_callback_option(http_callback_option option = get_everything); |
Данная функция позволяет настроить поведение коллбека. По умолчанию это get_everything, т.е. из сокета читается весь контент. Доступны также значения get_headers_only (будут считаны только заголовки) и get_body_only (будет считано только тело).
Сам коллбек должен представлять из себя функтор, возвращающий bool. Чтение данных из сокета будет продолжаться до тех пор, пока коллбек возвращает true.
Пример использования коллбека для скачивания большого файла (при этом оперативной памяти будет расходоваться совсем немного):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <iostream> #include <string> #include <fstream> #include <boost/bind.hpp> #include <simple_http/simple_http.h> #include <simple_http/http_endpoint.h> #include <simple_http/functions.h> //Функция сохранения скачанной части данных в файл bool filereader(const std::string& s, std::ofstream& file, unsigned long& downloaded) { downloaded += s.length(); //Сохраняем кусок скачанного файла file.write(s.data(), s.length()); //Выводим количество скачанных байтов данных std::cout << "\rDownloaded: " << downloaded; return true; //Возвращаем true - продолжаем чтение } int main() { simple_http::http_sync_connection conn; //Открываем файл на запись std::ofstream file("downloaded_boost.7z", std::ios::out | std::ios::binary | std::ios::trunc); unsigned long downloaded = 0; //Устанавливаем коллбек conn.set_http_load_callback(boost::bind(filereader, _1, boost::ref(file), boost::ref(downloaded))); //Получаем только тело ответа (сам файл, заголовки нам не нужны сейчас) conn.set_callback_option(simple_http::get_body_only); //Читаем пачками минимум по 50 кб, чтобы было быстрее и коллбек реже вызывался conn.set_callback_min_transfer_amount(50000); //Запускаем чтение conn.get(simple_http::http_endpoint::from_string("http://localhost/boost.7z")); //Готово, файл скачался. Функция get в этом случае вернет пустую строку, так как это опция по умолчанию //Это необходимо для экономии оперативной памяти при скачивании больших файлов, да и результат мы уже получили //и сохранили, так что дополнительно получать контент нет смысла. std::cout << std::endl << "Finished!" << std::endl; return 0; } |
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-запрос.
Наконец, последний пример - авторизуемся на Форуме АНТИЧАТ и получаем количество новых приватных сообщений и общее их количество.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include <iostream> #include <string> #include <boost/regex.hpp> #include <simple_http/simple_http.h> #include <simple_http/http_endpoint.h> #include <simple_http/cookie_manager.h> #include <simple_http/http_error.h> #pragma comment(lib, "simple_http.lib") #pragma comment(lib, "libeay32.lib") #pragma comment(lib, "ssleay32.lib") int main() { std::string login = "ВАШ ЛОГИН"; std::string password = "ВАШ ПАРОЛЬ"; try { simple_http::http_sync_connection conn; //создали экземпляр класса http_sync_connection simple_http::cookie_manager manager; //создали менеджер cookies conn.set_auto_cookie_manager(manager); //прикрепили его к HTTP-классу //Делаем GET-запрос на главную страницу, чтобы получить начальные Cookies conn.get(simple_http::http_endpoint::from_string("https://forum.antichat.ru/index.php")); //Добавляем HTTP-Referer'а conn.add_query_header("Referer", "https://forum.antichat.ru/index.php?"); //Включаем автоматическую обработку параметров (urlencode) conn.enable_auto_urlencode(); //Делаем POST-запрос, чтобы авторизоваться std::string login_page = conn.post( simple_http::http_endpoint::from_string("https://forum.antichat.ru/login.php?do=login&cookieuser=1&forceredirect=1&s=&vb_login_username=" + login + "&vb_login_password=" + password)); //Если авторизация успешна if(login_page.find("Спасибо, что зашли, ") != std::string::npos) { std::cout << "Correct login and password" << std::endl; //Снова получаем главную страницу, будучи авторизованными std::string index_page = conn.get(simple_http::http_endpoint::from_string("https://forum.antichat.ru/index.php")); //Получаем количество ПМов static boost::regex pm_match("ЛИЧНАЯ ПОЧТА</a> \\(<b>(\\d+)</b>/(\\d+)\\)"); boost::smatch what; //И выводим, сколько у нас новых ПМов, и сколько их всего if(boost::regex_search(index_page, what, pm_match)) std::cout << "New PMs: " << what[1].str() << ", total PMs: " << what[2].str() << std::endl; } else { //Иначе говорим, что введен неправильный логин или пароль std::cout << "Incorrect login or password" << std::endl; } } catch(const simple_http::http_error& e) { //Если произошла какая-то ошибка, выведем ее и завершим работу std::cout << "Error: " << e.what() << std::endl; } return 0; } |
Вот и всё! Приведенной информации вполне достаточно, чтобы полноценно работать с библиотекой.
Выкладываю исходники библиотеки и последнего примера: simple_http.zip. В комплекте - файл солюшена и проектов Visual Studio 2010. Не забудьте прописать свои пути к boost'у и OpenSSL (если вам потребуется поддержка HTTPS).
UPD 06.05.2013 - поправлен недочет при парсинге cookies.
Мне кажется, или получить заголовки ответа с помощью данной библиотеки не получится?
Получится:
#include simple_http/functions.h
simple_http::get_headers
даже две перегрузки имеет
Потестим, позже отпишусь)
Изобрели CurlPP?
Типа того, только без Curl, а на boost::asio.
Спасибо за код, выглядит интересно. Но почему большинство функций статические? simple_http::http_endpoint::from_string и тд. И почему в примерах не юзаете неймспейсы? Повторяющегося кода было бы меньше.
Статические функции в коде олько те, которые могут работать вне класса. Зачем добавлять функциональность внутрь класса, если она, по сути, не зависимая? Об этом еще Скотт Мейерс писал, кажется, да или посмотри на буст: boost::asio::ip::tcp::endpoint::from_string и подобные вызовы.
В примерах на 5 строк юзать неймспейсы? Да и что подразумевается под использованием неймспейсов, написать строку "using namespace simple_http"? Я не сторонник разыменовывания всего подряд, тем более, что это может породить конфликты имен. Если много писать, лучше сделать укороченный алиас неймспейсу.
В общем попробовал я брут написать, вроде работает)
А никто не может рассказать как включать его в свои проекты? Положил в include в VS, при компиляции выдает "error LNK2028: ссылка на неразрешенную лексему (0A000089) "public: class std::basic_string<char,struct std::char_traits..."
Я же писал, что либа требует boost собранного, и сама тоже требует сборки.
Если требуется поддержка ssl, то необходима еще и OpenSSL собранная.
Пример включения в проект лежит в архиве.
[+] Поддержка multipart-POST запросов с возможностью загрузки произвольного количества файлов любого размера
Он вроде как загружает файлы в ОП перед отправкой, поэтому зависит от количества свободной ОП.
Трудно читать код на C++ после Delphi, очень непривычно, что можете посоветовать?
console.log('Hi, I am Justin')
Где можно прочитать про стандарты C/C++, желательно на русском и какую IDE можете посоветовать кроме MS Visual Studio.
Стандарт C++ - это обычный документ, который можно брать и читать. IDE - смотря под какую ОС. Visual Studio последних версий, имхо, одна из самых удобных.
http://cpp-netlib.github.com/
При попытки компиляции примера:
error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::http_sync_connection::http_sync_connection(void)" (??0http_sync_connection@simple_http@@QAE@XZ) в функции _main C:\Users\Denis\Downloads\Архивы\simple_http\examples\main.obj examples
Пути к бусту указаны
Путь к lib-файлу либы то тоже надо указать
странно , буст скомпилил и собрал , да и примеры бустовые идут на ура , вот только почемуто при компиле отправки потс запроса (1 ый ваш пример) , выдаёт типа от что :
1>c:\program files\microsoft visual studio 9.0\vc\include\simple_http\simple_http.h(110) : error C2039: function: не является членом "std"
1>c:\program files\microsoft visual studio 9.0\vc\include\simple_http\simple_http.h(110) : error C2143: синтаксическая ошибка: отсутствие ";" перед "c:\program files\microsoft visual studio 9.0\vc\include\simple_http\simple_http.h(110) : error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>c:\program files\microsoft visual studio 9.0\vc\include\simple_http\simple_http.h(110) : error C2238: непредвиденные лексемы перед ";"
В сём мб трабла ? Буст собран , SSL не нужен :)
Можно закомментировать этот момент (если коллбеки не нужны), он компилируется только в студии 2010 и выше и в последних gcc. Это C++11.
Ну или поставить новую студию)
simple_http::http_sync_connection conn -На это он выдает:
msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: __thiscall std::_Lockit::~_Lockit(void)" (??1_Lockit@std@@QAE@XZ) already defined in libcpmtd.lib(xlock.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: __thiscall std::_Lockit::_Lockit(int)" (??0_Lockit@std@@QAE@H@Z) already defined in libcpmtd.lib(xlock.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "void __cdecl std::_Debug_message(wchar_t const *,wchar_t const *,unsigned int)" (?_Debug_message@std@@YAXPB_W0I@Z) already defined in libcpmtd.lib(stdthrow.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "void __cdecl std::_Xout_of_range(char const *)" (?_Xout_of_range@std@@YAXPBD@Z) already defined in libcpmtd.lib(xthrow.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: __thiscall std::_Container_base12::~_Container_base12(void)" (??1_Container_base12@std@@QAE@XZ) already defined in main.obj
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: __thiscall std::_Container_base12::_Container_base12(void)" (??0_Container_base12@std@@QAE@XZ) already defined in main.obj
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: void __thiscall std::_Container_base12::_Orphan_all(void)" (?_Orphan_all@_Container_base12@std@@QAEXXZ) already defined in main.obj
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "void __cdecl std::_Xlength_error(char const *)" (?_Xlength_error@std@@YAXPBD@Z) already defined in libcpmtd.lib(xthrow.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: struct std::_Iterator_base12 * * __thiscall std::_Container_base12::_Getpfirst(void)const " (?_Getpfirst@_Container_base12@std@@QBEPAPAU_Iterator_base12@2@XZ) already defined in simple_http.lib(simple_http.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: static int __cdecl std::numeric_limits::max(void)" (?max@?$numeric_limits@H@std@@SAHXZ) already defined in simple_http.lib(simple_http_impl.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: void __thiscall std::_Container_base12::_Swap_all(struct std::_Container_base12 &)" (?_Swap_all@_Container_base12@std@@QAEXAAU12@@Z) already defined in simple_http.lib(utils.obj)
1>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: static unsigned int __cdecl std::numeric_limits::max(void)" (?max@?$numeric_limits@I@std@@SAIXZ) already defined in simple_http.lib(simple_http.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: "public: __thiscall std::exception::exception(char const * const &)" (??0exception@std@@QAE@ABQBD@Z) already defined in LIBCMTD.lib(stdexcpt.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: "public: virtual __thiscall std::exception::~exception(void)" (??1exception@std@@UAE@XZ) already defined in LIBCMTD.lib(stdexcpt.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: "public: __thiscall std::exception::exception(class std::exception const &)" (??0exception@std@@QAE@ABV01@@Z) already defined in LIBCMTD.lib(stdexcpt.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: __wassert already defined in LIBCMTD.lib(wassert.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: _memmove already defined in LIBCMTD.lib(memmove.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: _wcslen already defined in LIBCMTD.lib(wcslen.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: __invalid_parameter already defined in LIBCMTD.lib(invarg.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: __CrtDbgReportW already defined in LIBCMTD.lib(dbgrptw.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: "public: bool __thiscall type_info::operator==(class type_info const &)const " (??8type_info@@QBE_NABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: _tolower already defined in LIBCMTD.lib(tolower.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: _towlower already defined in LIBCMTD.lib(towlower.obj)
1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)
1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)
1>MSVCRTD.lib(MSVCR100D.dll) : error LNK2005: _strerror already defined in LIBCMTD.lib(strerror.obj)
1>LINK : warning LNK4098: defaultlib 'MSVCRTD' conflicts with use of other libs; use /NODEFAULTLIB:library
1>D:\example\simple_http (1)\Debug\examples.exe : fatal error LNK1169: one or more multiply defined symbols found
И еще в примерах вызывается либа "libboost_regex-vc100-mt-sgd-1_48.lib" (например), а boost (v.1.48) собрал "libboost_regex-vc100-mt-gd-1_48.lib" может в этом дело?
Как правильно подключить все?
Собрать всё с одинаковыми рантаймами (например, статические отладочные или статические релизные), и все без проблем слинкуется.
Примеры вообще никак не собраны и никакие либы там не вызываются. Надо ставить просто везде одинаковый параметр Code Generation в студии и собирать буст с теми же самыми настройками.
СтраHHо , устаHовил 10 студию , буст поставвил (всe примэры бустовскиe компилятся Hа ура !!), одHако пи выполHeHии вышe описаHHого кода , вылазиeт :
1>crea.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::http_sync_connection::~http_sync_connection(void)" (??1http_sync_connection@simple_http@@QAE@XZ) в функции _main
1>crea.obj : error LNK2019: ссылка на неразрешенный внешний символ "class std::basic_string<char,struct std::char_traits,class std::allocator > __cdecl simple_http::get_body(class std::basic_string<char,struct std::char_traits,class std::allocator > const &)" (?get_body@simple_http@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABV23@@Z) в функции _main
1>crea.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: class std::basic_string<char,struct std::char_traits,class std::allocator > __thiscall simple_http::http_sync_connection::get(class simple_http::http_endpoint const &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)" (?get@http_sync_connection@simple_http@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVhttp_endpoint@2@ABV34@1@Z) в функции _main
1>crea.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: static class simple_http::http_endpoint __cdecl simple_http::http_endpoint::from_string(class std::basic_string<char,struct std::char_traits,class std::allocator > const &)" (?from_string@http_endpoint@simple_http@@SA?AV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) в функции _main
1>crea.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::http_sync_connection::http_sync_connection(void)" (??0http_sync_connection@simple_http@@QAE@XZ) в функции _main
В чём мб трабла ??
П.с , КАими писал мол , Путь к lib-файлу либы то тоже надо указать.. Это как , и про какую лтбу ??Файлы из папки SТage буста , я указал ..
Если ты собираешь пример работы с либой, то перед этим как бы надо и саму либу собрать, а потом в примере указать путь к ее lib-файлу.
В отдельности в проекте работает и boost и openssl, но стоит добавить хотя бы "simple_http::http_sync_connection conn;" линкер выдает две ошибки!
1>asd.obj : error LNK2019: unresolved external symbol "public: __thiscall simple_http::http_sync_connection::~http_sync_connection(void)" (??1http_sync_connection@simple_http@@QAE@XZ) referenced in function _main
1>asd.obj : error LNK2019: unresolved external symbol "public: __thiscall simple_http::http_sync_connection::http_sync_connection(void)" (??0http_sync_connection@simple_http@@QAE@XZ) referenced in function _main
если же пишем #pragma comment (lib, "simple_http.lib") то вообще беда...
dx, выручайте))
Именно #pragma comment (lib, "simple_http.lib") и надо написать, учтя, чтобы буст и либа были собраны с одинаковыми параметрами Code generation (рантаймы студии).
Дык а как иё собрать ??Я так поHИмаю рeчь идёт о сборкe вашэй либы , а He бустовской ??Бустовая уж собраHа , я каHуч извиHяюсь за тупизHу , просто curl He качаицо ЫЫ
Качайте лучше curl
А как узнать/ посмотреть с какими рантаймами был создан boost?
собирал так:
1.bootstrap.bat
2.bjam.exe --toolset=msvc-10.0 --build-type=complete
Его boost из студии надо собрать? или в проекте Вашей библиотеке рантаймы поменять проще будет и пере собрать?
Советую собрать буст в двух вариантах:
bjam variant=debug link=static threading=multi runtime-link=static
bjam variant=release link=static threading=multi runtime-link=static
(ну и тулсет указать, если их несколько, да)
После этого ставить в проектах, в которых буст используется, параметр Code generation = MT для релизных сборок и MTd для отладочных.
Библиотеку, соответственно, в студии с такими флагами и собирать.
Собрал, флаги выставил. Все равно!
1>asd.obj : error LNK2019: unresolved external symbol "public: __thiscall simple_http::http_sync_connection::~http_sync_connection(void)" (??1http_sync_connection@simple_http@@QAE@XZ) referenced in function _main
1>asd.obj : error LNK2019: unresolved external symbol "public: __thiscall simple_http::http_sync_connection::http_sync_connection(void)" (??0http_sync_connection@simple_http@@QAE@XZ) referenced in function _main
1>C:\Users\Администратор\Downloads\simple_http\Debug\asd.exe : fatal error LNK1120: 2 unresolved externals
Ну блин, #pragma comment(lib, "simple_http") же, сколько раз писать еще
Собираю дебаг, тест тоже
command line в simple_http:
/I"C:\OpenSSL-Win32\include\openssl" /I"C:\OpenSSL-Win32\include" /ZI /nologo /W3 /WX- /Od /Oy- /D "SSL_SUPPORT" /D "_WIN32_WINNT=0x0501" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\simple_http.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue
Это командная строка компилятора. Ошибки, которые ты написал, выводятся линкером. Покажи командную строку линкера.
Подменю линкера в simple_http нет, есть подменю Librarian!Там командная строка
/OUT:"C:\Users\Администратор\Downloads\simple_http\Debug\simple_http.lib" /NOLOGO
Я говорю о сборке не либы, а твоего проекта, который либу использует блин. Туда надо подключить собранную мою либу.
А я вот либу собрать не могу, выдает: boost::asio::detail::make_read_until_expr_op(AsyncReadStream &,boost::asio::basic_streambuf &,const boost::regex &,ReadHandler)' : could not deduce template argument for 'RegEx'
boost_1_47_0\boost\asio\impl\read_until.hpp(881): error C2783: 'boost::asio::detail::read_until_expr_op
\boost_1_47_0\boost\asio\impl\read_until.hpp(862) : see declaration of 'boost::asio::detail::make_read_until_expr_op',boost::_bi::bind_t>(AsyncReadStream &,boost::asio::basic_streambuf<> &,const boost::regex &,const ReadHandler &)' being compiled...
1> \desktop\simple_http\simple_http\simple_http_socket_worker.h(96) : see reference to function template instantiation 'void boost::asio::async_read_until
ШОДЕЛАТЬ?!
Обновить буст до 1.48.00, блеать, это в нем бага.
Кхм... извиняюсь конечно, но до сих пор не могу собрать все в кучу! Вот строка линкера проекта, где хочу использовать либу!
/OUT:"D:\example\boost+openssl\Debug\boost+openssl.exe" /INCREMENTAL /NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"Debug\boost+openssl.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"D:\example\boost+openssl\Debug\boost+openssl.pdb" /SUBSYSTEM:CONSOLE /PGD:"D:\example\boost+openssl\Debug\boost+openssl.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
Как правильно настроить линкер?
Я тут не вижу линкования с simple_http.lib, собсна. Либо явно указать либу надо, либо прописать в исходнике проекта #pragma comment(lib, "simple_http")
Дык, 80 ошибок линкера при #pragma comment(lib,"simple_http.lib")...
За это время можно было бы уже 100 раз разобраться. Если нет умения работать с бустом и вообще со студией - лучше за это дело даже не браться, прежде чем научишься что-то делать.
Да я просто не понимаю почему не получается... simple_http::http_sync_connection conn именно с этим проблема!
Менеджер куков свободно создается, буст работает! Может быть из за SSL? Хочу разобраться и понять, с Вашей помощью...
Попробуй собрать из буста пример, работающий с SSL. Там есть вроде бы, в примерах для boost::asio.
Да и ты же говоришь, у тебя там 80 ошибок появляется, если слинковаться с моей либой... Значит, не только в конструкторе проблема, еще что-то не так?
Ошибки:
MSVCRTD.lib(ti_inst.obj) \\ на эти либы линковщик ругается
msvcprtd.lib(MSVCP100D.dll) \\ ошибкой errorLNK2005
после чего выдает error LNK1169: one or more multiply defined symbols found
Предупреждение:
warning LNK4098: defaultlib 'MSVCRTD' conflicts with use of other libs; use /NODEFAULTLIB:library
убирал эту либу- вообще беда)
simple_http::http_sync_connection conn; -это не работает
simple_http::cookie_manager manager;- это работает
либу и проект собирал с SSL_SUPPORT
Уже сто раз писал, что ты буст/мою библиотеку/проект примера собираешь с разными настройками рантаймов студии. Повторяю это в очередной раз.
а с яваскриптом через него как-нибудь работать можно?
Не
либкурл не требует никакого буста, уже собран, с минимальными затратами поддерживает потоки (правда когда его юзал последний раз там был глюк в библиотеке, связанный с указателями, сейчас ), создаёт всего один лишний поток, на всё (количество потоков = ваши потоки +1), есть неблокирующийся режим и тд.
зачем изобретать велосипед?
Дело в том, что если бы все имели такое мнение, как у тебя, то мы бы сейчас были лишены большого количества замечательных продуктов, а у тебя не было бы выбора, какие программы ставить на компьютер. Зачем было делать винамп, аимп и прочие плейеры, если есть виндовс медиа плеер, который тоже все играет? Ну и т.д.
Немного по теме: либкурл - это сишная библиотека, и плюсовые биндинги надо, во-первых, еще найти/выбрать, а потом еще и собрать, так как они собранными точно не будут поставляться - плюсовое abi в каждом компиляторе сильно отличается, поэтому каждый собирает для себя.
Не спорю, возможностей там больше, но это не значит, что не нужно делать никаких аналогов, свет клином на курле не сошелся.
А при режиме прокси socks5 он будет работать с socks4? Аналогичный вопрос ещё и про HTTP & HTTPS.
Не будет.
проект собирается переезжать на какую-нибудь CVS ?
Пока что вряд ли.
А Keep-Alive, chanked и gzip encoding реализованы ???
Неа. Из всего перечисленного реально может пригодиться только gzip.
Мне очень понравилась реализация работы с http в либе Poco, да и вообще она неплохая.
Здравствуйте, пытаюсь отправить фаил (точно так же как написано в примере) *.jpeg ругается:
1>SendDATA_test_console.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::http_sync_connection::~http_sync_connection(void)" (??1http_sync_connection@simple_http@@QAE@XZ) в функции _main
1>SendDATA_test_console.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::multipart_file::~multipart_file(void)" (??1multipart_file@simple_http@@QAE@XZ) в функции _main
1>SendDATA_test_console.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: class std::basic_string<char,struct std::char_traits,class std::allocator > __thiscall simple_http::http_sync_connection::multipart_post(class simple_http::http_endpoint const &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &,class simple_http::multipart_file &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)" (?multipart_post@http_sync_connection@simple_http@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVhttp_endpoint@2@ABV34@AAVmultipart_file@2@11@Z) в функции _main
1>SendDATA_test_console.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: static class simple_http::http_endpoint __cdecl simple_http::http_endpoint::from_string(class std::basic_string<char,struct std::char_traits,class std::allocator > const &)" (?from_string@http_endpoint@simple_http@@SA?AV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) в функции _main
1>SendDATA_test_console.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::multipart_file::multipart_file(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)" (??0multipart_file@simple_http@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z) в функции _main
1>SendDATA_test_console.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall simple_http::http_sync_connection::http_sync_connection(void)" (??0http_sync_connection@simple_http@@QAE@XZ) в функции _main
о чём это он? (VS10 C++)
Не указали в списке библиотек для линковки саму либу для работы с HTTP, поэтому компилятор функции оттуда не может найти.
снимаю вопрос, видимо нужна simple_http.lib...
Ага, сначала либу собрать же надо.
дико извиняюсь (наверное для вас) за глупые вопросы.. вопрос задал в следующем посте.
где взять simple_http.lib ?
та же ситуация с libeay32.lib и ssleay32.lib
если их нужно как то собирать то подскажите как?
simple_http.lib нужна для примера с передачей файла.
simple_http.lib - это та библиотека, которая собирается из моих исходников, выложенных в этом посте. Ее просто нужно собрать в студии и потом линковаться с ней.
libelay и ssleay нужны только в том случае, если необходима поддержка HTTPS, я писал об этом в посте. Их можно либо найти уже собранные где-нибудь в интернете, либо собрать самому из исходников OpenSSL.
Если все это звучит слишком сложно, то, вероятно, есть смысл использовать CURL, он есть в уже собранных исполнениях наверняка.
ок, вроде как разобрался (http://msdn.microsoft.com/ru-ru/library/ms235627%28v=vs.90%29.aspx была мне в помощь)
я так понимаю, для примера с передачей файлов в состак библиотеки (создаваемой simple_http.lib) можно включать не весь проект.
попробовал собрать с заголовочными simple_http.h, http_endpoint.h, multipart_file.h ну и их исходниками (*.cpp имею введу) и того 6 файлов. Библиотека собралась. подключил так: #pragma comment(lib, "simple_http.lib"). попытался скомпилировать ошибка не исчезла..
Можете сказать какие конкретно файлы должны входить в состав библиотеки.
Спасибо, за ранее.
или подскажите, хотя бы какие файлы можно исключить дабы избежать подключения openssl. Ну или может что то в коде поправить..
Нужно взять и собрать всю либу, в проекте уже есть все необходимые файлы же. Потом просто слинковаться, как Вы и пробовали. Если что-то не выходит, нужен текст ошибок из студии. Если OpenSSL не нужен, то собирайте мою библиотеку без директивы препроцессора SSL_SUPPORT. В посте есть такой текст, скопирую сюда, если не дочитали:
15. Сборка с поддержкой SSL.
Для того, чтобы собрать библиотеку с поддержкой SSL (чтобы работали HTTPS-запросы), необходимо задать директиву препроцессора SSL_SUPPORT. Если поддержка SSL отключена, класс http_sync_connection будет бросать исключение при попытке произвести HTTPS-запрос.
Если использовать сокс5, то при задании адреса через std::string (а не simple_http::http_endpoint) дял get/post - в прокси доходит ":80" т.е. вместо хоста имеем пустую строку.
Все нормально. Строка не должна содержать порт, для этого есть отдельный параметр функции.
std::string proxy("http://127.0.0.1:3737");
auto proxy_ep = simple_http::http_endpoint::from_string(proxy);
Error: Invalid HTTP(S) endpoint!
Этот кусок скомпилировал, проверил. Работает. Boost 1.52.
std::string proxy("http://127.0.0.1");
conn.set_proxy(proxy, proxy_port, simple_http::proxy_socks5);
Error: Address resolving error
Без http:// строка должна быть, чисто адрес. Причем без порта.
Большое спасибо, очень удобная библиотека. Вот только не получается отправить post запрос на авторизацию к mail.ru (SSL handshake error). Отладчик показал, что не парсятся куки... В чём может быть проблема? Заранее благодарен. (Брал код из примера, с античатом всё работает)
Не исключено, что баги в библиотеке есть. Хотелось бы небольшой пример кода увидеть, который не работает. Вообще, ssl handshake error говорит о том, что не удалось связаться с сервером по каким-то причинам, связанным с SSL сертификатом (т.е. не удалось получить ключи для шифрования, или что-то в этом роде).
Спасибо за оперативный ответ. SSL заработал. Это был мой косяк, надо было сразу отправлять пост на https, чтобы включилась поддержка SSL.(Приношу свои извинения за преждевременную панику =D) Но вот с куками по прежнему беда, куки парсятся, но не все. Прикладываю скриншот http://saveimg.ru/show-image.php?id=b05e9eeaa5ae86702ff62e5d081e06c3
Думаю, что проблема возникает при парсинге параметра expires в куках. Из-за невозможности распарсить этот параметр куки не добавляются в менеджер.
Дошли руки до правки багов. Действительно, регулярное выражение для парсинга даты кукисов не совсем корректное было, поправил. По идее, теперь должно сработать, можно перекачать архив с исходниками.
Привет, dx. Напиши, пожалуйста, соурси смс-бомбера. Хочу зделать эволюцинной бомбер.
Здравствуйте! А как решить проблему с многопоточностью? Хочу написать многопоточный брутфорс, не подскажите как решить мою задачу?
Использовать в каждом потоке отдельный инстанс класса...
Здравствуйте, какая-то ошибка в куки менеджере, при запросе отправляется только первая кука
Библиотекой почти никто не пользуется, так что не исключено, что там есть ошибки. Постараюсь посмотреть в ближайшие дни, как появится время.
Здравствуйте, ошибки не было, просто оказалось что сайт часть куков передаёт для домена с http://www., а часть без него, это я поправил в куки мэнеджере храня все куки без www. Но я немного не понял как отправлять post запрос, когда имеются и GET параметры, они автоматом в POST уходят, хотя это не требуется
Не уверен, что 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
Всё-таки есть ошибка с куками есть, но не в менеджере, например, при авторизации на яндексе из 7 кук, в куки менеджер поступает только 5, хотя формат оставшихся 2-ух такой же.
И еще ошибку нашёл: при запросе по ssl, если включен авторедирект, то при редиректе он почему-то делает запрос на 80-ый порт
Эта ошибка вроде бы действительно есть, поправлю. С кукисами еще посмотрю. Неплохо бы пример кода, который работает не так, как должен.
И еще если можно, то добавить вывод последнего запроса (как респонс выводится, так же и реквест перед нем)
А в этой библиотеки есть аналог функции get_headers() из PHP?
Я не помню, библиотека старая очень +)