Заголовки ответа в C++
Заголовки ответа приходят отдельно от тела и построчно попадают в колбэк libcurl.
Опция CURLOPT_HEADERFUNCTION принимает
функцию, которая видит каждую строку, включая
"Content-Type". Имена в HTTP не
чувствительны к регистру, но в коде удобно искать
вариант в нижнем регистре. Выведем тип содержимого
для example.com:
#include <iostream>
#include <string>
#include <cctype>
#include <curl/curl.h>
size_t writeBody(
char* ptr,
size_t size,
size_t nmemb,
void* userdata
) {
auto* body = static_cast<std::string*>(userdata);
body->append(ptr, size * nmemb);
return size * nmemb;
}
size_t captureHeader(
char* buffer,
size_t size,
size_t nitems,
void* userdata
) {
auto* type = static_cast<std::string*>(userdata);
size_t total = size * nitems;
std::string line(buffer, total);
const std::string key = "content-type:";
if (line.size() >= key.size()) {
std::string lower;
lower.reserve(line.size());
for (char ch : line) {
lower.push_back(
static_cast<char>(std::tolower(ch))
);
}
if (lower.rfind(key, 0) == 0) {
*type = line.substr(key.size());
while (
!type->empty() &&
(type->front() == ' ' || type->front() == '\t')
) {
type->erase(type->begin());
}
while (
!type->empty() &&
(type->back() == '\r' || type->back() == '\n')
) {
type->pop_back();
}
}
}
return total;
}
int main() {
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* curl = curl_easy_init();
std::string body;
std::string contentType;
curl_easy_setopt(
curl,
CURLOPT_URL,
"https://example.com/"
);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeBody);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &body);
curl_easy_setopt(
curl,
CURLOPT_HEADERFUNCTION,
captureHeader
);
curl_easy_setopt(
curl,
CURLOPT_HEADERDATA,
&contentType
);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
std::cout << contentType << "\n";
}
curl_easy_cleanup(curl);
curl_global_cleanup();
return res == CURLE_OK ? 0 : 1;
}
Число строк заголовков можно посчитать в том же
колбэке, пропуская пустые строки и стартовую
"HTTP/...":
#include <iostream>
#include <string>
#include <cctype>
#include <curl/curl.h>
size_t writeBody(
char* ptr,
size_t size,
size_t nmemb,
void* userdata
) {
auto* body = static_cast<std::string*>(userdata);
body->append(ptr, size * nmemb);
return size * nmemb;
}
size_t countHeader(
char* buffer,
size_t size,
size_t nitems,
void* userdata
) {
auto* count = static_cast<int*>(userdata);
size_t total = size * nitems;
std::string line(buffer, total);
bool blank = true;
for (char ch : line) {
if (ch != '\r' && ch != '\n' && ch != ' ') {
blank = false;
break;
}
}
if (blank) {
return total;
}
if (line.rfind("HTTP/", 0) == 0) {
return total;
}
++(*count);
return total;
}
int main() {
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* curl = curl_easy_init();
std::string body;
int headerCount = 0;
curl_easy_setopt(
curl,
CURLOPT_URL,
"https://example.com/"
);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeBody);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &body);
curl_easy_setopt(
curl,
CURLOPT_HEADERFUNCTION,
countHeader
);
curl_easy_setopt(
curl,
CURLOPT_HEADERDATA,
&headerCount
);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
std::cout << headerCount << "\n";
}
curl_easy_cleanup(curl);
curl_global_cleanup();
return res == CURLE_OK ? 0 : 1;
}
Выведите значение поля "content-type"
для ответа "https://example.com/".
Отправьте чтение на "https://example.com/"
и напечатайте первое значение заголовка
"date", если он пришел, иначе строку
"none".