Обратный вызов записи libcurl не вызывается для сообщения http сообщения - PullRequest
0 голосов
/ 08 мая 2018

Введение

Я отправляю POST-запрос на сервер, который отвечает чанк-сообщениями. Поэтому я пытаюсь вызывать функцию writecallback для каждого полученного фрагментированного http-сообщения.

код

#include <iostream>
#include <string>
#include <curl/curl.h>

using namespace std;

size_t write_callback(char *d, size_t n, size_t l, void *userp)
{
    cerr << ""--- Called once" << endl;
    return n*l;
}

string xml_msg()
{
    return "<<some request data>>";
}

curl_slist* get_header(size_t content_length)
{
    auto list = curl_slist_append(nullptr, "<<protocol version>>");
    list = curl_slist_append(list, "Content-Type: text/xml");
    list = curl_slist_append(list, "Content-Length: " + content_length);
    return list;
}

void main()
{
    auto xml = xml_msg();

    curl_global_init(CURL_GLOBAL_ALL);

    auto curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "<<server url>>");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, nullptr);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0)");
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_easy_setopt(curl, CURLOPT_USERPWD, "<<user credentials>>");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, get_header(xml.size()));
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, xml.data());
    curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);

    curl_easy_perform(curl);

    curl_easy_cleanup(curl);
    curl_global_cleanup();
}

Подробный журнал

* STATE: INIT => CONNECT handle 0x15c4de0; line 1422 (connection #-5000)
* Added connection 0. The cache now contains 1 members
* STATE: CONNECT => WAITRESOLVE handle 0x15c4de0; line 1458 (connection #0)
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* STATE: WAITRESOLVE => WAITCONNECT handle 0x15c4de0; line 1539 (connection #0)
* Connected to <<host>> (xxx.xxx.xxx.xxx) port 80 (#0)
* STATE: WAITCONNECT => SENDPROTOCONNECT handle 0x15c4de0; line 1591 (connection #0)
* Marked for [keep alive]: HTTP default
* STATE: SENDPROTOCONNECT => PROTOCONNECT handle 0x15c4de0; line 1605 (connection #0)
* STATE: PROTOCONNECT => DO handle 0x15c4de0; line 1626 (connection #0)
* Server auth using Basic with user '<<credentials>>'
> POST <<URL>>
Host: <<host>>
Authorization: Basic <<base64 credentials>>
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0)
Accept: */*
Content-Type: text/xml
Content-Length: 204

* upload completely sent off: 204 out of 204 bytes
* STATE: DO => DO_DONE handle 0x15c4de0; line 1688 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x15c4de0; line 1813 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x15c4de0; line 1823 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Tue, 08 May 2018 12:29:49 GMT
* Server is not blacklisted
< Server: <<server>>
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Content-Language: en-US
< Cache-Control: no-cache, no-store
< Pragma: no-cache
< Content-Type: application/xml;charset=UTF-8
< Set-Cookie: <<cookie>>
< Transfer-Encoding: chunked
<
--- Called once
* STATE: PERFORM => DONE handle 0x15c4de0; line 1992 (connection #0)
* multi_done
* Connection #0 to <<server>> left intact

Задача

Writecallback был вызван, когда соединение было закрыто сервером из-за тайм-аута с пакетом FIN tcp вместо момента, когда был получен ответ http.

Интервал между этими событиями составляет около 30 секунд.

Вопрос

Что я делаю не так?

Обновление 1

Сервер возвращает сегмент tcp с флагом PUSH и сообщение http с кодированной передачей, содержащей XML. Сообщение заканчивается на CLRF. Между тем, сокет Win API не позволяет читать его, а select () возвращает 0, что означает, что на этом сокете нечего читать / писать.

После 30-секундной задержки перед закрытием соединения из-за тайм-аута сердцебиения (то есть внутренней реализации сервера) сервер отправляет завершающее сообщение http с кодированной передачей, которая содержит 0 и CLRF. После этого сообщения select () отображает новое состояние сокета, а libcurl вызывает обратный вызов write с возвратом содержимого фрагментированного сообщения.

Это то, что я вижу после отладки libcurl. Мне нужно выяснить способ получения chunked http-сообщения, возвращаемого libcurl после его получения, а не после получения окончательного http-сообщения.

1 Ответ

0 голосов
/ 11 мая 2018

Хорошо, я смог выяснить, что проблема с розетками Win Api. В сборках linux libcurl вызывает writecallback сразу после получения chuncked-сообщения. Я не уверен, как решить эту проблему с помощью сборок Win, но по крайней мере я нашел причину проблемы.

...