summaryrefslogtreecommitdiff
path: root/src/mongo/util/net/http_client_curl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/net/http_client_curl.cpp')
-rw-r--r--src/mongo/util/net/http_client_curl.cpp100
1 files changed, 86 insertions, 14 deletions
diff --git a/src/mongo/util/net/http_client_curl.cpp b/src/mongo/util/net/http_client_curl.cpp
index fa1834c8bde..9db3c06f73f 100644
--- a/src/mongo/util/net/http_client_curl.cpp
+++ b/src/mongo/util/net/http_client_curl.cpp
@@ -27,6 +27,8 @@
* it in the license file.
*/
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kNetwork
+
#include "mongo/platform/basic.h"
#include <cstddef>
@@ -47,22 +49,24 @@
#include "mongo/db/commands/server_status.h"
#include "mongo/executor/connection_pool.h"
#include "mongo/executor/connection_pool_stats.h"
+#include "mongo/logv2/log.h"
#include "mongo/platform/mutex.h"
#include "mongo/stdx/unordered_map.h"
#include "mongo/transport/transport_layer.h"
#include "mongo/util/alarm.h"
#include "mongo/util/alarm_runner_background_thread.h"
#include "mongo/util/assert_util.h"
+#include "mongo/util/bufreader.h"
#include "mongo/util/concurrency/thread_pool.h"
#include "mongo/util/functional.h"
#include "mongo/util/net/hostandport.h"
#include "mongo/util/net/http_client.h"
+#include "mongo/util/net/http_client_options.h"
#include "mongo/util/processinfo.h"
#include "mongo/util/strong_weak_finish_line.h"
#include "mongo/util/system_clock_source.h"
#include "mongo/util/timer.h"
-
namespace mongo {
namespace {
@@ -159,20 +163,40 @@ size_t WriteMemoryCallback(void* ptr, size_t size, size_t nmemb, void* data) {
*/
size_t ReadMemoryCallback(char* buffer, size_t size, size_t nitems, void* instream) {
- auto* cdrc = reinterpret_cast<ConstDataRangeCursor*>(instream);
+ auto* bufReader = reinterpret_cast<BufReader*>(instream);
size_t ret = 0;
- if (cdrc->length() > 0) {
- size_t readSize = std::min(size * nitems, cdrc->length());
- memcpy(buffer, cdrc->data(), readSize);
- invariant(cdrc->advanceNoThrow(readSize).isOK());
+ if (bufReader->remaining() > 0) {
+ size_t readSize =
+ std::min(size * nitems, static_cast<unsigned long>(bufReader->remaining()));
+ auto buf = bufReader->readBytes(readSize);
+ memcpy(buffer, buf.rawData(), readSize);
ret = readSize;
}
return ret;
}
+/**
+ * Seek into for data to the remote side
+ */
+size_t SeekMemoryCallback(void* clientp, curl_off_t offset, int origin) {
+
+ // Curl will call this in readrewind but only to reset the stream to the beginning
+ // In other protocols (like FTP, SSH) or HTTP resumption they may ask for partial buffers which
+ // we do not support.
+ if (offset != 0 || origin != SEEK_SET) {
+ return CURL_SEEKFUNC_CANTSEEK;
+ }
+
+ auto* bufReader = reinterpret_cast<BufReader*>(clientp);
+
+ bufReader->rewindToStart();
+
+ return CURL_SEEKFUNC_OK;
+}
+
struct CurlEasyCleanup {
void operator()(CURL* handle) {
if (handle) {
@@ -196,6 +220,47 @@ long longSeconds(Seconds tm) {
return static_cast<long>(durationCount<Seconds>(tm));
}
+
+StringData enumToString(curl_infotype type) {
+ switch (type) {
+ case CURLINFO_TEXT:
+ return "TEXT"_sd;
+ case CURLINFO_HEADER_IN:
+ return "HEADER_IN"_sd;
+ case CURLINFO_HEADER_OUT:
+ return "HEADER_OUT"_sd;
+ case CURLINFO_DATA_IN:
+ return "DATA_IN"_sd;
+ case CURLINFO_DATA_OUT:
+ return "DATA_OUT"_sd;
+ case CURLINFO_SSL_DATA_IN:
+ return "SSL_DATA_IN"_sd;
+ case CURLINFO_SSL_DATA_OUT:
+ return "SSL_DATA_OUT"_sd;
+ default:
+ return "unknown"_sd;
+ }
+}
+
+int curlDebugCallback(CURL* handle, curl_infotype type, char* data, size_t size, void* clientp) {
+ switch (type) {
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_IN:
+ case CURLINFO_HEADER_OUT:
+ case CURLINFO_DATA_IN:
+ case CURLINFO_DATA_OUT:
+ LOGV2_DEBUG(7661901,
+ 1,
+ "Curl",
+ "type"_attr = enumToString(type),
+ "message"_attr = StringData(data, size));
+ [[fallthrough]];
+
+ default:
+ return 0;
+ }
+}
+
CurlEasyHandle createCurlEasyHandle(Protocols protocol) {
CurlEasyHandle handle(curl_easy_init());
uassert(ErrorCodes::InternalError, "Curl initialization failed", handle);
@@ -226,9 +291,10 @@ CurlEasyHandle createCurlEasyHandle(Protocols protocol) {
}
// TODO: CURLOPT_EXPECT_100_TIMEOUT_MS?
- // TODO: consider making this configurable, defaults to stderr
- // curl_easy_setopt(handle.get(), CURLOPT_VERBOSE, 1);
- // curl_easy_setopt(_handle.get(), CURLOPT_DEBUGFUNCTION , ???);
+ if (httpClientOptions.verboseLogging.loadRelaxed()) {
+ curl_easy_setopt(handle.get(), CURLOPT_VERBOSE, 1);
+ curl_easy_setopt(handle.get(), CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ }
return handle;
}
@@ -630,7 +696,7 @@ private:
curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, longSeconds(_connectTimeout));
- ConstDataRangeCursor cdrc(cdr);
+ BufReader bufReader(cdr.data(), cdr.length());
switch (method) {
case HttpMethod::kGET:
uassert(ErrorCodes::BadValue,
@@ -645,16 +711,22 @@ private:
curl_easy_setopt(handle, CURLOPT_POST, 1);
curl_easy_setopt(handle, CURLOPT_READFUNCTION, ReadMemoryCallback);
- curl_easy_setopt(handle, CURLOPT_READDATA, &cdrc);
- curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)cdrc.length());
+ curl_easy_setopt(handle, CURLOPT_READDATA, &bufReader);
+ curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)bufReader.remaining());
+
+ curl_easy_setopt(handle, CURLOPT_SEEKFUNCTION, SeekMemoryCallback);
+ curl_easy_setopt(handle, CURLOPT_SEEKDATA, &bufReader);
break;
case HttpMethod::kPUT:
curl_easy_setopt(handle, CURLOPT_POST, 0);
curl_easy_setopt(handle, CURLOPT_PUT, 1);
curl_easy_setopt(handle, CURLOPT_READFUNCTION, ReadMemoryCallback);
- curl_easy_setopt(handle, CURLOPT_READDATA, &cdrc);
- curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (long)cdrc.length());
+ curl_easy_setopt(handle, CURLOPT_READDATA, &bufReader);
+ curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (long)bufReader.remaining());
+
+ curl_easy_setopt(handle, CURLOPT_SEEKFUNCTION, SeekMemoryCallback);
+ curl_easy_setopt(handle, CURLOPT_SEEKDATA, &bufReader);
break;
default:
MONGO_UNREACHABLE;