YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/curl_util.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include "yb/util/curl_util.h"
34
35
#include <curl/curl.h>
36
37
#include <vector>
38
39
#include <glog/logging.h>
40
41
#include "yb/gutil/casts.h"
42
43
#include "yb/util/faststring.h"
44
#include "yb/util/scope_exit.h"
45
#include "yb/util/status.h"
46
47
using std::string;
48
49
namespace yb {
50
51
namespace {
52
53
1.72k
inline Status TranslateError(CURLcode code) {
54
1.72k
  if (code == CURLE_OK) {
55
1.71k
    return Status::OK();
56
1.71k
  }
57
11
  return STATUS(NetworkError, "curl error", curl_easy_strerror(code));
58
11
}
59
60
extern "C" {
61
463
size_t WriteCallback(void* buffer, size_t size, size_t nmemb, void* user_ptr) {
62
463
  size_t real_size = size * nmemb;
63
463
  faststring* buf = reinterpret_cast<faststring*>(user_ptr);
64
463
  CHECK_NOTNULL(buf)->append(reinterpret_cast<const uint8_t*>(buffer), real_size);
65
463
  return real_size;
66
463
}
67
} // extern "C"
68
69
} // anonymous namespace
70
71
20.8k
EasyCurl::EasyCurl() {
72
20.8k
  curl_ = curl_easy_init();
73
0
  CHECK(curl_) << "Could not init curl";
74
20.8k
}
75
76
213
EasyCurl::~EasyCurl() {
77
213
  curl_easy_cleanup(curl_);
78
213
}
79
80
Status EasyCurl::FetchURL(const string& url,
81
                          faststring* buf,
82
                          int64_t timeout_sec,
83
239
                          const std::vector<std::string>& headers) {
84
239
  return DoRequest(url, boost::none, boost::none, timeout_sec, buf, headers);
85
239
}
86
87
Status EasyCurl::PostToURL(
88
2
    const string& url, const string& post_data, faststring* dst, int64_t timeout_sec) {
89
2
  return DoRequest(url, post_data, string("application/x-www-form-urlencoded"), timeout_sec, dst);
90
2
}
91
92
Status EasyCurl::PostToURL(
93
    const string& url,
94
    const string& post_data,
95
    const string& content_type,
96
    faststring* dst,
97
4
    int64_t timeout_sec) {
98
4
  return DoRequest(url, post_data, content_type, timeout_sec, dst);
99
4
}
100
101
0
string EasyCurl::EscapeString(const string& data) {
102
0
  string escaped_str;
103
0
  auto str = curl_easy_escape(curl_, data.c_str(), narrow_cast<int>(data.length()));
104
0
  if (str) {
105
0
    escaped_str = str;
106
0
    curl_free(str);
107
0
  }
108
0
  return escaped_str;
109
0
}
110
111
Status EasyCurl::DoRequest(
112
    const string& url,
113
    const boost::optional<const string>& post_data,
114
    const boost::optional<const string>& content_type,
115
    int64_t timeout_sec,
116
    faststring* dst,
117
245
    const std::vector<std::string>& headers) {
118
245
  CHECK_NOTNULL(dst)->clear();
119
120
  // Add headers if specified.
121
245
  struct curl_slist* curl_headers = nullptr;
122
245
  auto clean_up_curl_slist = ScopeExit([&]() {
123
245
    curl_slist_free_all(curl_headers);
124
245
  });
125
126
3
  for (const auto& header : headers) {
127
3
    curl_headers = CHECK_NOTNULL(curl_slist_append(curl_headers, header.c_str()));
128
3
  }
129
245
  RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, curl_headers)));
130
131
245
  RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_URL, url.c_str())));
132
245
  if (return_headers_) {
133
3
    RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_HEADER, 1)));
134
3
  }
135
245
  RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, WriteCallback)));
136
245
  RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_WRITEDATA,
137
245
                                                static_cast<void *>(dst))));
138
139
245
  typedef std::unique_ptr<curl_slist, std::function<void(curl_slist*)>> CurlSlistPtr;
140
245
  CurlSlistPtr http_header_list;
141
245
  if (content_type) {
142
6
    auto list =
143
6
        curl_slist_append(NULL, strings::Substitute("Content-Type: $0", *content_type).c_str());
144
145
6
    if (!list) {
146
0
      return STATUS(InternalError, "Unable to set Content-Type header field");
147
0
    }
148
149
6
    http_header_list = CurlSlistPtr(list, [](curl_slist *list) {
150
6
      if (list != nullptr) {
151
6
        curl_slist_free_all(list);
152
6
      }
153
6
    });
154
155
6
    RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_HTTPHEADER,
156
6
                                                  http_header_list.get())));
157
6
  }
158
159
245
  if (timeout_sec > 0) {
160
245
    RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_TIMEOUT, timeout_sec)));
161
245
  }
162
163
245
  if (post_data) {
164
6
    RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, post_data->c_str())));
165
6
    RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE,
166
6
                                                  post_data->size())));
167
6
  }
168
169
245
  RETURN_NOT_OK(TranslateError(curl_easy_perform(curl_)));
170
234
  long rc; // NOLINT(runtime/int) curl wants a long
171
234
  RETURN_NOT_OK(TranslateError(curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &rc)));
172
234
  if (rc != 200) {
173
3
    return STATUS(RemoteError, strings::Substitute("HTTP $0", rc));
174
3
  }
175
176
231
  return Status::OK();
177
231
}
178
179
} // namespace yb