libcurl игнорирует тело в случае, если HTTP не в порядке - PullRequest
1 голос
/ 03 марта 2020

Я обычно скачиваю файл с помощью curl. Тем не менее, сервер делает хитрую вещь: он возвращает код не-200 и по-прежнему отправляет некоторые данные. Проблема в том, что у меня есть HTTP-код после записи данных, но я не хочу ничего писать, если это не 200. Кто-нибудь знает способ сделать это без сохранения данных на диске или в памяти?

curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteHandler);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr);
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
    return 0;
}

long response_code;
curl_easy_getinfo(curl_.get(), CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200) {
    return 0;
}

size_t curlWriteHandler(char* chars, size_t size, size_t nmemb, void* userp) {
    // write to file

    return size * nmemb;
}

1 Ответ

2 голосов
/ 03 марта 2020

Настройка CURLOPT_FAILONERROR должна сделать это для ошибок 4xx и 5xx.

Когда эта опция используется и обнаружена ошибка, это приведет к закрытию соединения и CURLE_HTTP_RETURNED_ERROR возвращается

curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);

Закрытие соединения не очень хорошо для меня, важно его повторно использовать. Вы можете думать о чем-нибудь еще?

К сожалению, я не могу найти способ заставить CURLOPT_FAILONERROR не закрывать соединение.

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

Мы можем сделать переменную curl глобальной. Или же мы можем воспользоваться опцией void *userdata для обратного вызова write и передать структуру, содержащую как дескриптор curl, так и буфер.

Вот примерный набросок, демонстрирующий, как обратный вызов write может получить доступ к ответу. код, а также сохранить тело ответа.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>

typedef struct {
    CURL *curl;
    char *buf;
} curl_write_data;

size_t curlWriteHandler(char* chars, size_t size, size_t nmemb, void* userp) {
    curl_write_data *curl_data = (curl_write_data*)userp;
    long response_code;
    curl_easy_getinfo(curl_data->curl, CURLINFO_RESPONSE_CODE, &response_code);
    printf("Response: %ld\n", response_code);

    // Now we can save if we like.
    if( response_code < 300 ) {
        curl_data->buf = malloc(size*(nmemb+1));
        strcpy(curl_data->buf, chars);
        strcat(curl_data->buf, "\0");
        return size * nmemb;
    }
    else {
        return  0;
    }
}

int main() {
    CURL *curl = curl_easy_init();
    if(!curl) {
        perror("Cant' init curl");
    }

    curl_write_data curl_data = { .curl = curl, .buf = NULL };
    curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/alsdfjalj");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteHandler);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curl_data);

    curl_easy_perform(curl);

    if( curl_data.buf ) {
        puts(curl_data.buf);
    }
}

Я не уверен, что это лучшая идея, то, что я придумал.

...