Форум программистов, компьютерный форум, киберфорум
Наши страницы
Avazart
Войти
Регистрация
Восстановить пароль
Темы блога относятся к программированию на языке С++

В основном для C++Qt (Qt5.1) и C++ Builder (RAD 2009 и RAD XE3)
Рейтинг: 4.75. Голосов: 16.

Библиотека libcurl в С++ для работы по HTTP

Запись от Avazart размещена 07.02.2013 в 00:46
Обновил(-а) Avazart 01.07.2018 в 15:34
Метки http, с++, сurl

Цитата:
libcurl это свободная и простая в использовании клиентская библиотека по передачи данных по URL, она поддерживает DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET и TFTP. Также libcurl имеет поддержку SSL сертификатов, HTTP POST, HTTP PUT, FTP загрузку, HTTP form загрузку, proxy, cookies, user+password авторизацию (Basic, Digest, NTLM, Negotiate, Kerberos), докачивания файлов, http прокси туннелирования и многого другого!

libcurl легко переносима, она собирается и работает на многих платформах, включая Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS и остальные...

libcurl свободна, потокобезопасна, совместима с IPv6, функциональна, имеет хорошую поддержку, быстрая, тщательно задокументирована и уже используется во многих известных, крупных и успешных компаний и в многочисленных приложениях.[2]
Содержание
Нажмите на изображение для увеличения
Название: figure1.gif
Просмотров: 772
Размер:	7.3 Кб
ID:	1702


1. Установка библиотеки.
2. Основные принципы.
3. Простой пример.
4. Заголовки.
5. Обработка ошибок.
6. Загрузка в буфер
7. Загрузка в файл.
8. Перенаправление (редерикт).
9. Cookie.
10. Преобразование в URL вид.
11. POST-запрос для авторизации на форуме.
12. Получение страниц в сжатом виде.
13. Передача с использованием HTTPs (расширение протокола HTTP, поддерживающее шифрование).

Исходники.
Литература.
Темы.

1 Установка библиотеки

Ubuntu Linux

Достаточно стандартно выполнить команду
Bash
1
sudo apt-get install curl libcurl3 libcurl3-dev
В дальнейшем собирать исходники надо с опцией -lcurl, например
Bash
1
g++ main.o -o prog -lcurl
Windows

1. Заходим на сайт http://curl.haxx.se/download.html. Качаем версию библиотеки для Win32 - MSVC http://curl.haxx.se/download/libcurl-7.19.3-win32-ssl-msvc.zip

2. Распаковываем архив берем от туда все dll- файлы:
  1. curllib.dll ;
  2. libeay32.dll ;
  3. openldap.dll ;
  4. ssleay32.dll .
И папку curl ( там заголовойные файлы) находящуюся в папке .\libcurl-7.19.3-win32-ssl-msvc\include

Примечание:
На данный момент ссылки стали нерабочими, нужно качать исходники и собирать самому из исходников в MSVC. Но если влом - используйте библиотеки что в примерах (в архиве прикреплены).

3. Так же берем curllib.lib из папки .\libcurl-7.19.3-win32-ssl-msvc\lib\Release
Если у вас MSVC++ используем его, если С++Builder конвертируем файл curllib.lib в curllib-bcb.lib утилитой coff2omf.exe

Код:
coff2omf curllib.lib curllib-bcb.lib
Теперь для подключения curl нужно написать

C++
1
2
3
#include "curl/curl.h"
#pragma comment(lib,"curllib.lib")           // для MSVC++
// #pragma comment(lib,"curllib-bcb.lib") // для C++Builder
Для работы программы также может понадобиться libsasl.dll ( из OpenSSL ) и возможно какие-нибудь библиотеки из MSVC++(Если у вас C++Builder).В таком случае при запуске программы из IDE она сразу же будет прекращать работу после без какой либо ошибки. Если же запустить сам exe файл то вылезит окошко указывающее на недостающую библиотеку. Требуемые dll несложно найти и скачать с интернета.

2. Основные принципы

cUrl предоставляет несколько интерфейсов:
  1. Easy (Простой режим)
  2. Multi (Многопоточный режим)
  3. Share

Цитата:
При использовании в libcurl "простого" интерфейса вы инициализируете сеанс и получаете handle (часто упоминается как "easy handle"), который вы используете в качестве аргумента в функциях Easy интерфейса. Используйте curl_easy_init, чтобы получить handle.

После получения вы должны установить все нужные параметры в предстоящей передаче, наиболее важным среди которых является URL (передавать что-то без заданного URL невозможно). Вы можете задавать различные функции обратного вызова, которые будут вызываться из библиотеки, при получении данных и т.д. Для всего этого используется curl_easy_setopt.[2]
Список опций можно найти в документации [1]

Цитата:
После того как все настройки окончены, вы сообщаете libcurl выполнение передачи с помощью curl_easy_perform. Она проделает все операции и вернет результат своей работы типа перечисления CURLcode.

После передачи, вы можете установить новые настройки и сделать еще передачу, или, если вы уже закончили, вызовите очистку сессии curl_easy_cleanup. Если вы хотите иметь постоянное подключение, не освобождайте handle сразу, вместо этого выполните другие передачи с использованием этого же handle.

Никогда не используйте один и тот же хендл в разных потоках! (можно сделать синхронизацию, но это сведёт на нет плюсы многопоточности)[2]

3. Простой пример

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//---------------------------------------------------------------------------
int main()
{
    CURL *  curl_handle = curl_easy_init();
    if(curl_handle)
    {
        // задаем  url адрес
        curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.cyberforum.ru");
        // выполняем запрос
        CURLcode res = curl_easy_perform(curl_handle);
        // закрываем дескриптор curl
        curl_easy_cleanup(curl_handle);
    }
 
    getchar();
    return 0;
}
//---------------------------------------------------------------------------
В итоге в окне консоли получаем html-код страницы форума.
C++
1
CURL *curl_easy_init();
Начинает easy(простую) curl-сессию, возвращает её дескриптор, в случае неудачи NULL.
Каждому вызову такой ф-ции должен соответствовать вызов ф-ции
C++
1
void curl_easy_cleanup(CURL * curl);
для завершении работы.

C++
1
CURLcode curl_easy_setopt(CURL *curl, CURLoption option, parameter);
Задает соответствующего поведение через установку опций, возвращает CURLE_OK (0) если успешно, в противном случае код ошибки определенный константами в файле curl/curl.h.
Опция CURLOPT_URL относится NETWORK-опциям и задает url- адрес. Этот параметр должен иметь вид согласно RFC 3986 формата: "scheme://host:port/path" (смотри также Преобразование в URL вид.)

C++
1
CURLcode curl_easy_perform(CURL *curl);
Выполняет отправку запроса на сервер и возвращает CURLE_OK в случае успеха, в противном случае код ошибки. [1]

4. Заголовки.

Заголовки запроса можно также установить с помощью опций, но в зависимости от версии libcurl, константы определяющие опции могут отличаться.
C++
1
2
3
4
5
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT,"Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0");
curl_easy_setopt(curl_handle, CURLOPT_ENCODING, "gzip,deflate"); // если curl скомпилина вместе с gzip 
// curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPALIVE , 1);  // не нашло такой опции в версии 7.19.3
// curl_easy_setopt(curl_handle, CURLOPT_REFERER,"http://some.com"); // yстанавливает referer
curl_easy_setopt(curl_handle, CURLOPT_AUTOREFERER,1);// автоматически заполняет поле referer
Если установить
C++
1
curl_easy_setopt(curl_handle, CURLOPT_HEADER, 1);
то заголовки ответа сервера будут отображаться в месте с html-кодом страницы (заголовок + тело)

5. Обработка ошибок.

В случае возникновения ошибки при выполнении функции curl_easy_perform() можно получить её описание с помощью:
C++
1
const char *curl_easy_strerror(CURLcode errornum);
Эта функция возвращает строку с описанием кода ошибки CURLcode указанным в аргументе:
C++
1
2
3
CURLcode res = curl_easy_perform(curl_handle);
if(res != CURLE_OK)
     printf( "curl_easy_perform() failed: %s\n", curl_easy_strerror(res) );
Так же есть возможность получить сообщение об ошибке из буфера ошибок, для этого нужно включить параметр CURLOPT_ERRORBUFFER с помощью ф-ции curl_easy_setopt() указать буфер.

C++
1
2
3
4
5
6
7
static char ErrorBuffer[CURL_ERROR_SIZE]; // размер определяется константой curl
//...
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer); // указывает буфер ошибок
//...
CURLcode res = curl_easy_perform(curl_handle);
if(res != CURLE_OK)
     cout<<"Error!"<<ErrorBuffer<< endl;
6. Загрузка в буфер.

По умолчанию curl выводит данные в stdout т.е. в окно консоли. Для того что бы сохранить данные в отдельном буфере нужно указать этот буфер в опции CURLOPT_WRITEDATA и callback функцию которая будет записывать туда данные при их приёме с помощью опции CURLOPT_WRITEFUNCTION.

Функция должна иметь вид:

C++
1
size_t function( char *ptr, size_t size, size_t nmemb, void* userdata);
char * ptr - указатель на принимаемые данные.
size_t size - размер принимамого блока данных
size_t nmemb - общее количество блоков данных.
void* userdata - это параметр опции CURLOPT_WRITEDATA, в который производится запись - наш буфер.

Функция должна возвращать количество обработанных байт ( size*nmemb ). Если это количество будет отличаться от суммы, полученной на входе вашей функции, то будет отдан сигнал об ошибке в библиотеке. Это можно использовать для прервания передачи, с возвращемым значением CURLE_WRITE_ERROR.

Функция может вернуть значение CURL_WRITEFUNC_PAUSE, которое приведет к приостановке записи в этом соединении.

В качестве буфера можно использовать контейнер или поток STL что упростит задачу.
Для примера использование std::string :
C++
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
//----------------------------------------------------------------------------
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//----------------------------------------------------------------------------
static size_t write_data(char *ptr, size_t size, size_t nmemb, string* data)
{
    if (data)
    {
        data->append(ptr, size*nmemb);
        return size*nmemb;
    }
    else 
    return 0;  // будет ошибка
}
//-----------------------------------------------------------------------------
int main()
{
    CURL *curl_handle;
    curl_handle = curl_easy_init();
 
    if (curl_handle)
    {
        curl_easy_setopt(curl_handle, CURLOPT_URL, "google.com");
 
    std::string content;
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &content);
 
        CURLcode res = curl_easy_perform(curl_handle);
        if (res)  std::cout << content << std::endl;
        else      std::cerr << curl_easy_strerror(res) << std::endl;
 
        curl_easy_cleanup(curl_handle);
    }
 
    getchar();
    return 0;
}
//-----------------------------------------------------------------------------
7. Загрузка в файл

Следующий пример показывает как можно сохранить тело ответа сервера в один в файл, а заголовок в другой.
C++
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
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib")
//---------------------------------------------------------------------------
size_t write_data( char *ptr, size_t size, size_t nmemb, FILE* data)
{
    return fwrite(ptr, size, nmemb, data);
}
//---------------------------------------------------------------------------
int main()
{
    // Открываем файлы для заголовка и тела
 
    const std::string header_filename= "head.txt";
    const std::string body_filename  = "body.html";
 
    FILE *header_file= fopen(header_filename.c_str(),"w");
    if (header_file == NULL) 
    return -1;
 
    FILE *body_file =  fopen(body_filename.c_str(),"w");
    if (body_file == NULL)  
    return -1;
 
    // Выполняем  запрос
    CURL *curl_handle = curl_easy_init();
    if(curl_handle)
    {
    const std::string url= "http://www.cyberforum.ru";
        curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
 
        // сохраняем тело
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, body_file);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
 
        // сохраняем заголовок
        curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, header_file);
 
        CURLcode res = curl_easy_perform(curl_handle);
        if(res != CURLE_OK)
            std::cout<< "curl_easy_perform() failed: %s\n" << curl_easy_strerror(res) std::endl;
        curl_easy_cleanup(curl_handle);
    }
 
    std::cout<< "\nDone!"<<std::endl;
    getchar();
    return 0;
}
//--------------------------------------------------------------------------
8. Перенаправление ( редирикт ).

Для автоматического перехода на перенаправляемую страницу необходимо установить опцию CURLOPT_FOLLOWLOCATION в 1
C++
1
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
Для того что бы ограничить количество перенаправлений нужно установить опцию CURLOPT_MAXREDIRS
её параметр указывает их максимальное количество
C++
1
curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); //  останавливаться после 10-ого редиректа
9. Cookie

Далее описание опций для работы с Cookie

CURLOPT_COOKIE
C++
1
curl_easy_setopt(curl_handle, CURLOPT_COOKIE, cookiestring);
Параметр -указатель на строку в стиле Си для установки cookies в http-запросе .
Формат строки должен быть вида name=contents, где name имя cookie, а contents- её содержание.

Используется, когда вы хотите указать точное содержание cookie-заголовоков для отправки на сервер.

Если нужно передать несколько cookie, то строка должна выглядеть как "name1 = content1; name2 = content2;" и т. д.

CURLOPT_COOKIEFILE
C++
1
curl_easy_setopt(curl_handle, CURLOPT_COOKIEFILE, cookiefilename);
Принимает указатель на строку в стиле Си, которой хранится путь к файлу, который содержит cookies.
Сookies должны хранится в формате куков Netscape/Mozilla или в обычном HTTP-стиле заголовков (Set-Cookie: ...) помещенных в файл.

Если указать несуществующий файл или пустую строку (""), то это разрешит libcurl полученные использовать cookie в следующих запросах для данного дескриптора curl

Можно несколько раз устанавливать эту опцию для загрузки нескольких файлов с куками.

CURLOPT_COOKIEJAR
C++
1
curl_easy_setopt(curl_handle, CURLOPT_COOKIEJAR, cookiefilename);
Запишет все известные cookies в указанный файл. Если cookies нет файл не будет создан. Если указать "-" вместо имени файла cookies будут выведены в окно консоли ( stdout ), и будет разрешено использование cookies для этой сессии

Если файл не может быть создан или сохранен libcurl не выдаст ошибку.
Использование опций CURLOPT_VERBOSE или CURLOPT_DEBUGFUNCTION вызовет вывод предупреждения.

CURLOPT_COOKIESESSION
C++
1
curl_easy_setopt(curl_handle, CURLOPT_COOKIESESSION, 1);
Установка в 1 укажет текущему сеансу начать новую "сессию" cookies. Это заставит libcurl проигнорировать все "сессионные" cookies, которые она должна была бы загрузить, полученные из предыдущей сессии. По умолчанию, libcurl всегда сохраняет и загружает все cookies, вне зависимости от того, являются ли они "сессионными" или нет. "Сессионные" cookies - это cookies без срока истечения, которые должны существовать только для текущей "сессии".

CURLOPT_COOKIELIST
C++
1
curl_easy_setopt(curl_handle, CURLOPT_COOKIELIST, "ALL"); // Чистка cookies
Устанавливает cookies.

Если задать параметр "ALL" то все cookies будут очищены , если "FLUSH" будут сохранены в файл указанный в опции CURLOPT_COOKIEJAR

Для вывода информации о cookie можно воспользоваться функцией из примера cookie_interface.c
C++
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
static void print_cookies(CURL *curl)
{
    CURLcode res;
    struct curl_slist *cookies;
    struct curl_slist *nc;
    int i;
 
    printf("Cookies, curl knows:\n");
    res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
    if (res != CURLE_OK)
    {
        fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n",
                curl_easy_strerror(res ));
        exit(1);
    }
    nc= cookies, i = 1;
    while (nc)
    {
        printf("[%d]: %s\n", i, nc->data);
        nc = nc->next;
        i++;
    }
    if (i == 1)  printf("(none)\n");
 
    curl_slist_free_all(cookies);
}
10. Преобразование в URL вид.

Иногда возникает необходимость передавать GET/POST запросы параметры которые содержать в себе символы требующие "экранирования" ( кириллица, символ "@" ).
К примеру необходимо выполнить поиск в яндексе по слову "Программирование", если посмотреть в строку браузера, то там это будет выглядеть так:
HTML5
1
http://yandex.ua/yandsearch?text=Программирование
Слово "Программирование" должно экранироваться при запросе:
HTML5
1
http://yandex.ua/yandsearch?text=%CF%F0%EE%E3%F0%E0%EC%EC%E8%F0%EE%E2%E0%ED%E8%E5
Для этих целей в curl предусмотрена функция
C++
1
char* curl_easy_escape( CURL* curl , char* url , int length );
Цитата:
Эта функция преобразует входной строку в закодированную для URL строку и возвращает ее в качестве новой выделенной строки. Все входные символы, кроме a-z, A-Z или 0-9 преобразуются в их "замаскированные" версии (%NN, где NN - двузначное шестнадцатеричное число).

Если длина аргумента имеет значение 0 (ноль), curl_easy_escape использует strlen() на входной строке, чтобы вычислить размер.

Вы должны освободить полученную строку с помощью curl_free, после окончания работы с ней.[2]
C++
1
void curl_free ( char* ptr );
Цитата:
curl_free освобождает память, которая была выделена внутри функций curl. Необходимо использовать curl_free() вместо free(), чтобы избежать ошибок, которые могут возникнуть по причине возможных различий при управлении памятью в вашем приложении и curl.[2]
Код для рассматриваемого примера
C++
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
//---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
 
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")     // для VC++
//---------------------------------------------------------------------------
int main()
{
    CURL *curl_handle;
    CURLcode res;
 
    curl_handle = curl_easy_init();
 
    if(curl)
    {
        char ru_text[]= "Программирование";
        // Преобразование в URL- вид
        char* esc_text= curl_easy_escape( curl_handle, ru_text, 0);
        if(!esc_text)
        {
            std::cout<<"can not convert string to URL" <<std::endl;
            curl_easy_cleanup(curl_handle);
            getchar();
            return 1;
        }
 
        std::string url=  "http://yandex.ua/yandsearch?text=";
        url+= esc_text;
 
        curl_free(esc_text);
 
        // задаем  url адрес
        curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str() );
        // разрешаем перенаправление
        curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
        // выполняем запрос
        res = curl_easy_perform(curl_handle);
        curl_easy_cleanup(curl_handle);
    }
    getchar();
    return 0;
}
//--------------------------------------------------------------------------

Для удобства использования с std::string можно написать такую функцию
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
//---------------------------------------------------------------------------
std::string escape(CURL *curl_handle, const std::string& text)
{
    std::string result;
    char* esc_text= curl_easy_escape(curl_handle, text.c_str(), text.length());
    if(!esc_text) throw std::runtime_error("Can not convert string to URL");
 
    result = esc_text;
    curl_free(esc_text);
 
    return result;
}
//---------------------------------------------------------------------------
11. POST-запрос для авторизации на форуме.

В качестве примера приведу авторизацию на cyberforum.ru с последующим переходом в "Мой кабинет", для работы примера вам необходимо указать свой e-mail и пароль.

Результат выполнения программы приведен на рисунке справа.
Нажмите на изображение для увеличения
Название: Авторизация на форуме.jpg
Просмотров: 1208
Размер:	190.1 Кб
ID:	1800

C++
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdio.h>
#include <stdlib.h>
 
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//---------------------------------------------------------------------------
std::string escape(CURL *curl_handle, const std::string& text)
{
    std::string result;
    char* esc_text= curl_easy_escape(curl_handle, text.c_str(), text.length());
    if(!esc_text) throw std::runtime_error("Can not convert string to URL");
 
    result = esc_text;
    curl_free(esc_text);
 
    return result;
}
//----------------------------------------------------------------------------
static size_t write_data(char *ptr, size_t size, size_t nmemb, std::string* data)
{
    if (data)
    {
        data->append(ptr, size*nmemb);
        return size*nmemb;
    }
    else return 0;  // будет ошибка
}
//----------------------------------------------------------------------------
static size_t write_head(char *ptr, size_t size, size_t nmemb, std::ostream* stream)
{
    (*stream)<< std::string(ptr, size*nmemb);
    return size*nmemb;
}
//---------------------------------------------------------------------------
int main()
{
    /* Пользовательские данные */
    const std::string url_dologin= "http://www.cyberforum.ru/login.php?do=login";// страница авторизации
  const std::string url_user= "http://www.cyberforum.ru/usercp.php"; // Мой кабинет
  
    std::string user_name;  //  e-mail
    std::string password;   //  пароль
 
    std::cout<<"e-mail: ";
    getline(std::cin,user_name);
    std::cout<<password<<"password: ";
    getline(std::cin,password);
    std::cout<<std::endl;
 
    CURL *curl_handle = curl_easy_init();
    if(curl_handle)
    {
        /* Формирование  запроса на основе пользовательских данных */
        std::string post_data;
        post_data+= "vb_login_username="  + escape(curl_handle, user_name);
        post_data+= "&cookieuser=1";
        post_data+= "&vb_login_password=" + escape(curl_handle, password);
        post_data+= "&s=&securitytoken=guest";
        post_data+= "&do=login";
        post_data+= "&vb_login_md5password=";
        post_data+= "&vb_login_md5password_utf=";
 
        curl_easy_setopt(curl_handle, CURLOPT_URL, url_dologin.c_str() );
 
        //  сохраняем html код cтраницы в строку content
    std::string content;
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,     &content);
 
        // Загловок ответа сервера выводим в консоль
        curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, write_head);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER,    &std::cout);
 
        // авто перенаправление
        curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
        // max 5-ть перенаправлений
        curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 5);
        // разрешаем использовать куки
        curl_easy_setopt(curl_handle, CURLOPT_COOKIEFILE,"");
 
        /* POST- запрос c авторизацией ( происходит получение кукисов ) */
        curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, post_data.c_str() );
        curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, post_data.length() );
 
        CURLcode res = curl_easy_perform(curl_handle);
        if(res != CURLE_OK)
        {
            std::cout<< curl_easy_strerror(res) << std::endl;
            getchar();
            return 0;
        }
        // Проверяем успешно ли авторизировались
        if( content.find("Спасибо, что зашли") != std::string::npos )
            std::cout << "Authenticated!" <<std::endl<<std::endl;
        else
        {
            std::cout<< "Non-Authenticated!" <<std::endl;
            curl_easy_cleanup(curl_handle);
            getchar();
            return 0;
        }
        /* GET- запрос для перехода в "Мой кабинет" форума */
        content.clear();
        // меняем POST-режим на GET
        curl_easy_setopt(curl_handle, CURLOPT_POST, 0);
        curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1);
        // меняем url
        curl_easy_setopt(curl_handle, CURLOPT_URL, url_user.c_str() );
 
        res = curl_easy_perform(curl_handle);
        if(res != CURLE_OK)  std::cout<< curl_easy_strerror(res) <<std::endl;
 
        // Проверяем получили то что ожидали
        if( content.find("Мой кабинет") != std::string::npos)
            std::cout << ""My cabinet" downloaded."  <<std::endl
                      << "------------- Content -----------------" <<std::endl
                      << content <<std::endl;
        else  std::cout << "Is not "My cabinet" page" <<std::endl;
 
        curl_easy_cleanup(curl_handle);
    }
 
    getchar();
    return 0;
}
//--------------------------------------------------------------------------
Основные моменты:

1. Для успешной авторизации и перехода по страницам нужно:
  • разрешить использовать полученные cookie;
  • включить автоматический переход по перенаправлениям.

2. По умолчанию libcurl использует GET "режим" отправки запросов, после установки опции CURLOPT_POSTFIELDSIZE он переключается на POST, поэтому для осуществление последующего GET нужно переключить режим на GET:
C++
1
2
curl_easy_setopt(curl_handle, CURLOPT_POST, 0); // выключаем POST
curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1);// включаем GET
3. Для анализа того что отправляет/принимает ваше приложение удобно использовать снифер. Я пользуюсь к примеру HTTP Analyzer V5.

Нажмите на изображение для увеличения
Название: POST-header.jpg
Просмотров: 1041
Размер:	204.8 Кб
ID:	1703Нажмите на изображение для увеличения
Название: POST - post_data.jpg
Просмотров: 734
Размер:	167.9 Кб
ID:	1704Нажмите на изображение для увеличения
Название: Get-header.jpg
Просмотров: 732
Размер:	194.8 Кб
ID:	1705

12. Получение страниц в сжатом виде.
C++
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
//---------------------------------------------------------------------------
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//---------------------------------------------------------------------------
int main()
{
    const std::string url= "http://www.google.ru/";
 
    CURL *curl_handle = curl_easy_init();
    if(curl_handle)
    {
        curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str() );
        curl_easy_setopt(curl_handle, CURLOPT_ENCODING, "gzip,deflate"); // Принудительно ставим gzip
 
        CURLcode res = curl_easy_perform(curl_handle);
        if(res != CURLE_OK)
            std::cout<<"Error #"<<res<<" "<<curl_easy_strerror(res) <<std::endl;
 
        curl_easy_cleanup(curl_handle);
    }
 
    std::cout<<std::endl<<"Done!";
    getchar();
    return 0;
}
//--------------------------------------------------------------------------
13. Передача с использованием HTTPs.

Для работы с по протоколу HTTPs необходимо что бы libcurl была собрана с поддержкой SSL, а также необходимы соответствующие dll-ки ( из OpenSSL )
Если библиотека собрана без SSL, то ф-ция curl_easy_perform() вернет код CURLE_UNSUPPORTED_PROTOCOL (1) "Unsupported protocol"

Далее пример простого https- запроса :
C++
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
//---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
 
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//---------------------------------------------------------------------------
size_t write_data( char *ptr, size_t size, size_t nmemb, FILE* data)
{
    return fwrite(ptr, size, nmemb, data);
}
//---------------------------------------------------------------------------
int main()
{
    // Открываем файлы для заголовка и тела
    std::string body_filename  = "body.html";
    FILE *body_file =  fopen(body_filename.c_str(),"w");
    if (body_file == NULL)  return -1;
 
    std::string url= "https://my.webmoney.ru/login.aspx";
 
    CURL *curl_handle = curl_easy_init();
    if(curl)
        {
            // сохранение в файл html-страницу
            curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, body_file);
            curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
            // заголовки ответа выводим в консоль
            curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, stdout);
 
               /* HTTPs  Запрос */
            curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str() );
 
             // не проверять SSL сертификат
            curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
            // не проверять Host SSL сертификата
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
 
            CURLcode res = curl_easy_perform(curl_handle);
            if(res != CURLE_OK)
                 std::cout<<"Error #"<<res<<" "<<curl_easy_strerror(res) <<std::endl;
 
             curl_easy_cleanup(curl_handle);
        }
 
    std::cout<<std::endl<<"Done!";
    getchar();
    return 0;
}
//--------------------------------------------------------------------------
Разультат запроса будет сохранен в файле body.html, заголовок ответа сервера будет выведен на экран.

PDF вариант статьи:
Статья о curl.pdf (Прикреплено по просьбе пользователя reef213, составлял pdf тоже он cUrl в Dev C++)

Исходники:

HTTP, POST, авторизация на cyberforum (curl v7.19.3-ssl, C++Builder XE3).rar
Нажмите на изображение для увеличения
Название: MainWindow_001.png
Просмотров: 613
Размер:	34.4 Кб
ID:	1803

HTTP, GET, (curl v7.22.0, g++ 4.6.3, Makefile, Ubuntu x32).rar
HTTP, POST, авторизация на cyberforum(curl v7.22.0, Qt5, Ubuntu x32).zip

Литература:

1. http://curl.haxx.se/
2. http://ru.libcurl.wikia.com/wiki/Libcurlru_%D0%B2%D0%B8%D0%BA%D0%B8
3. cURL | System Development

Блоги :
Подключение Curl библиотеки. QtCreator, MinGW32, Windows

Темы :

1. Скачивание из интернета
2. Builder и curl
3. Замена строки
4. Опять кодировки
5. Работа с CURL
6. Curl без ssl или статическая линковка
7. Curl с нуля
Просмотров 33757 Комментарии 7
Всего комментариев 7
Комментарии
  1. Старый комментарий
    Аватар для ninja2
    Цитата:
    В папку с исполняемым файлом как и в других средах разработки.
    Я еще не одной среды разработки не знаю, просто скинул в папку Windows/System32 и все заработало.

    Да хорошая статья! Молодец! Все хорошо расписал! Благодаря ей я быстро разобрался и сделал авторизацию для контакта и можно по страницам шарить, тут идея возникла написать программку для рассылки сообщений для вк, попробовать хотябы, мб и получиться.
    Запись от ninja2 размещена 30.09.2013 в 07:16 ninja2 вне форума
  2. Старый комментарий
    Аватар для Avazart
    DLL-ки должны лежать рядом с исполняемым файлом *.EXE запускаемой программы.
    Что касается
    Цитата:
    У меня визуал студио 2010.
    Там кажется есть библиотека статической сборки, при которой не нужно будет таскать DLL вообще.
    Кроме того есть С++обвертки для работы с сurl что должно быть более удобным в использовании чем сама curl
    Запись от Avazart размещена 01.10.2013 в 00:12 Avazart на форуме
  3. Старый комментарий
    Аватар для ninja2
    Цитата:
    DLL-ки должны лежать рядом с исполняемым файлом *.EXE запускаемой программы.
    Мб с исходником? А как это понимать, программа что скомпилируется без длл, а потом что бы она исполнялась нужно длл добавить? Я вообще думал без длл не будет компилироваться. Ладно за длл еще ничего не знаю, как небудь почитаю.
    Запись от ninja2 размещена 02.10.2013 в 20:54 ninja2 вне форума
  4. Старый комментарий
    Аватар для Avazart
    Ну обычно есть две сборки статическая ( статический *.lib) и динамическая ( *.lib-импорта + *.dll ).
    Если сборка статическая то "код" используемых ф-ций как бы включается в *.exe программы.
    Если динамическая то ф-ции импортируются из *.dll во время запуска, что бы знать программе "как" их импортировать нужен *.lib-импорта.
    Запись от Avazart размещена 05.10.2013 в 21:56 Avazart на форуме
  5. Старый комментарий
    Я извиняюсь, но я, что то ни в одной ссылке не нашел curllib.lib
    .dll есть, а вот либ нет. Вы не дадите точную ссылку?
    Запись от Dr.Xank размещена 18.11.2014 в 20:23 Dr.Xank вне форума
  6. Старый комментарий
    Аватар для Avazart
    Ссылки стали нерабочими, нужно качать исходники и собирать самому из исходников в MSVC.
    Но если влом - используйте библиотеки что в примерах (в архиве прикреплены.)
    Запись от Avazart размещена 29.01.2015 в 18:40 Avazart на форуме
  7. Старый комментарий
    Интересная штукенция. Пользователи: 1С, адобы, CERN, гуглы с трубой, IBM, LG и т.д. и т.п. Надо будет тоже воспользоваться.
    Запись от svetogor размещена 24.02.2017 в 21:59 svetogor вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru