prod/native/libcommon/code/transport/CurlSender.cpp (51 lines of code) (raw):
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "CurlSender.h"
using namespace std::literals;
namespace elasticapm::php::transport {
static int CurlDebugFunc(CURL *handle, curl_infotype type, char *data, size_t size, void *logger) {
auto &log = *static_cast<std::shared_ptr<LoggerInterface> *>(logger);
if (logger && log->doesFeatureMeetsLevelCondition(LogLevel::logLevel_trace, elasticapm::php::LogFeature::TRANSPORT) && type < 3) {
char prefix = type == CURLINFO_TEXT ? '*' : (type == CURLINFO_HEADER_IN ? '<' : '>');
log->printf(LogLevel::logLevel_trace, "CurlSender %c %.*s", prefix, size - 1, data);
}
return 0;
}
static size_t CurlWriteFunc(char *data, size_t size, size_t nmemb, void *clientp) {
return size * nmemb;
}
CurlSender::CurlSender(std::shared_ptr<LoggerInterface> logger, std::chrono::milliseconds timeout, bool verifyCert) : log_(std::move(logger)) {
handle_ = curl_easy_init();
if (!handle_) {
throw std::runtime_error("curl_easy_init() failed");
}
if (!verifyCert) {
curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYPEER, 0L);
}
curl_easy_setopt(handle_, CURLOPT_TIMEOUT_MS, static_cast<long>(timeout.count()));
curl_easy_setopt(handle_, CURLOPT_CONNECTTIMEOUT_MS, static_cast<long>(timeout.count()));
curl_easy_setopt(handle_, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(handle_, CURLOPT_FORBID_REUSE, 0L);
curl_easy_setopt(handle_, CURLOPT_WRITEFUNCTION, CurlWriteFunc);
if (log_ && log_->doesMeetsLevelCondition(LogLevel::logLevel_trace)) {
curl_easy_setopt(handle_, CURLOPT_DEBUGFUNCTION, CurlDebugFunc);
curl_easy_setopt(handle_, CURLOPT_DEBUGDATA, &log_);
curl_easy_setopt(handle_, CURLOPT_VERBOSE, 1L);
}
}
int16_t CurlSender::sendPayload(std::string const &endpointUrl, struct curl_slist *headers, std::vector<std::byte> const &payload) const {
curl_easy_setopt(handle_, CURLOPT_URL, endpointUrl.c_str());
curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(handle_, CURLOPT_POSTFIELDS, payload.data());
curl_easy_setopt(handle_, CURLOPT_POSTFIELDSIZE, payload.size());
curl_easy_setopt(handle_, CURLOPT_POST, 1L);
CURLcode res = curl_easy_perform(handle_);
if (res != CURLE_OK) {
std::string msg = "sendPayload failed: "s;
msg.append(curl_easy_strerror(res));
throw std::runtime_error(msg);
}
long responseCode = 0;
curl_easy_getinfo(handle_, CURLINFO_RESPONSE_CODE, &responseCode);
return responseCode;
}
} // namespace elasticapm::php::transport