GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/swissknife_lease_curl.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 0 80 0.0%
Branches: 0 168 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "swissknife_lease_curl.h"
6
7 #include "cvmfs_config.h"
8
9 #include "crypto/hash.h"
10 #include "gateway_util.h"
11 #include "json_document.h"
12 #include "ssl.h"
13 #include "util/logging.h"
14 #include "util/pointer.h"
15 #include "util/posix.h"
16 #include "util/string.h"
17
18 namespace {
19
20 CURL* PrepareCurl(const std::string& method) {
21 const char* user_agent_string = "cvmfs/" VERSION;
22
23 CURL* h_curl = curl_easy_init();
24
25 if (h_curl) {
26 curl_easy_setopt(h_curl, CURLOPT_NOPROGRESS, 1L);
27 curl_easy_setopt(h_curl, CURLOPT_USERAGENT, user_agent_string);
28 curl_easy_setopt(h_curl, CURLOPT_MAXREDIRS, 50L);
29 curl_easy_setopt(h_curl, CURLOPT_CUSTOMREQUEST, method.c_str());
30 }
31
32 return h_curl;
33 }
34
35 size_t RecvCB(void* buffer, size_t size, size_t nmemb, void* userp) {
36 CurlBuffer* my_buffer = static_cast<CurlBuffer*>(userp);
37
38 if (size * nmemb < 1) {
39 return 0;
40 }
41
42 my_buffer->data = static_cast<char*>(buffer);
43
44 return my_buffer->data.size();
45 }
46
47 } // namespace
48
49 bool MakeAcquireRequest(const std::string& key_id, const std::string& secret,
50 const std::string& repo_path,
51 const std::string& repo_service_url,
52 CurlBuffer* buffer) {
53 CURLcode ret = static_cast<CURLcode>(0);
54
55 CURL* h_curl = PrepareCurl("POST");
56 if (!h_curl) {
57 return false;
58 }
59
60 const std::string payload = "{\"path\" : \"" + repo_path +
61 "\", \"api_version\" : \"" +
62 StringifyInt(gateway::APIVersion()) + "\"" +
63 ", \"hostname\" : \"" + GetHostname() + "\"}";
64
65 shash::Any hmac(shash::kSha1);
66 shash::HmacString(secret, payload, &hmac);
67
68 SslCertificateStore cs;
69 cs.UseSystemCertificatePath();
70 cs.ApplySslCertificatePath(h_curl);
71
72 const std::string header_str = std::string("Authorization: ") + key_id + " " +
73 Base64(hmac.ToString(false));
74 struct curl_slist* auth_header = NULL;
75 auth_header = curl_slist_append(auth_header, header_str.c_str());
76 curl_easy_setopt(h_curl, CURLOPT_HTTPHEADER, auth_header);
77
78 // Make request to acquire lease from repo services
79 curl_easy_setopt(h_curl, CURLOPT_URL, (repo_service_url + "/leases").c_str());
80 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDSIZE_LARGE,
81 static_cast<curl_off_t>(payload.length()));
82 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDS, payload.c_str());
83 curl_easy_setopt(h_curl, CURLOPT_WRITEFUNCTION, RecvCB);
84 curl_easy_setopt(h_curl, CURLOPT_WRITEDATA, buffer);
85
86 ret = curl_easy_perform(h_curl);
87 if (ret) {
88 LogCvmfs(kLogUploadGateway, kLogStderr,
89 "Make lease acquire request failed: %d. Reply: %s", ret,
90 buffer->data.c_str());
91 }
92
93 curl_easy_cleanup(h_curl);
94 h_curl = NULL;
95
96 return !ret;
97 }
98
99 bool MakeEndRequest(const std::string& method, const std::string& key_id,
100 const std::string& secret, const std::string& session_token,
101 const std::string& repo_service_url,
102 const std::string& request_payload, CurlBuffer* reply) {
103 CURLcode ret = static_cast<CURLcode>(0);
104
105 CURL* h_curl = PrepareCurl(method);
106 if (!h_curl) {
107 return false;
108 }
109
110 shash::Any hmac(shash::kSha1);
111 shash::HmacString(secret, session_token, &hmac);
112
113 SslCertificateStore cs;
114 cs.UseSystemCertificatePath();
115 cs.ApplySslCertificatePath(h_curl);
116
117 const std::string header_str = std::string("Authorization: ") + key_id + " " +
118 Base64(hmac.ToString(false));
119 struct curl_slist* auth_header = NULL;
120 auth_header = curl_slist_append(auth_header, header_str.c_str());
121 curl_easy_setopt(h_curl, CURLOPT_HTTPHEADER, auth_header);
122
123 curl_easy_setopt(h_curl, CURLOPT_URL,
124 (repo_service_url + "/leases/" + session_token).c_str());
125 if (request_payload != "") {
126 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDSIZE_LARGE,
127 static_cast<curl_off_t>(request_payload.length()));
128 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDS, request_payload.c_str());
129 } else {
130 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDSIZE_LARGE,
131 static_cast<curl_off_t>(0));
132 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDS, NULL);
133 }
134 curl_easy_setopt(h_curl, CURLOPT_WRITEFUNCTION, RecvCB);
135 curl_easy_setopt(h_curl, CURLOPT_WRITEDATA, reply);
136
137 ret = curl_easy_perform(h_curl);
138 if (ret) {
139 LogCvmfs(kLogUploadGateway, kLogStderr,
140 "Lease end request - curl_easy_perform failed: %d", ret);
141 }
142
143 UniquePtr<JsonDocument> reply_json(JsonDocument::Create(reply->data));
144 const JSON *reply_status =
145 JsonDocument::SearchInObject(reply_json->root(), "status", JSON_STRING);
146 const bool ok = (reply_status != NULL &&
147 std::string(reply_status->string_value) == "ok");
148 if (!ok) {
149 LogCvmfs(kLogUploadGateway, kLogStderr,
150 "Lease end request - error reply: %s",
151 reply->data.c_str());
152 }
153
154 curl_easy_cleanup(h_curl);
155 h_curl = NULL;
156
157 return ok && !ret;
158 }
159