GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/swissknife_lease_curl.cc
Date: 2026-08-30 02:40:36
Exec Total Coverage
Lines: 0 94 0.0%
Branches: 0 183 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 <unistd.h>
8
9 #include <memory>
10
11 #include "crypto/hash.h"
12 #include "gateway_util.h"
13 #include "json_document.h"
14 #include "json_document_write.h"
15 #include "ssl.h"
16 #include "util/logging.h"
17 #include "util/posix.h"
18 #include "util/string.h"
19
20 long g_final_revision = -1;
21
22 namespace {
23
24 CURL *PrepareCurl(const std::string &method) {
25 const char *user_agent_string = "cvmfs/" CVMFS_VERSION;
26
27 CURL *h_curl = curl_easy_init();
28
29 if (h_curl) {
30 curl_easy_setopt(h_curl, CURLOPT_NOPROGRESS, 1L);
31 curl_easy_setopt(h_curl, CURLOPT_USERAGENT, user_agent_string);
32 curl_easy_setopt(h_curl, CURLOPT_MAXREDIRS, 50L);
33 curl_easy_setopt(h_curl, CURLOPT_CUSTOMREQUEST, method.c_str());
34 }
35
36 return h_curl;
37 }
38
39 size_t RecvCB(void *buffer, size_t size, size_t nmemb, void *userp) {
40 CurlBuffer *my_buffer = static_cast<CurlBuffer *>(userp);
41
42 if (size * nmemb < 1) {
43 return 0;
44 }
45
46 my_buffer->data = my_buffer->data
47 + std::string(static_cast<char *>(buffer), nmemb);
48
49 return nmemb;
50 }
51
52 } // namespace
53
54 bool MakeAcquireRequest(const std::string &key_id, const std::string &secret,
55 const std::string &repo_path,
56 const std::string &repo_service_url, CurlBuffer *buffer,
57 const std::string &metadata) {
58 CURLcode ret = static_cast<CURLcode>(0);
59
60 CURL *h_curl = PrepareCurl("POST");
61 if (!h_curl) {
62 return false;
63 }
64
65 JsonStringGenerator payloadJson;
66 payloadJson.Add("path", repo_path);
67 payloadJson.Add("api_version", StringifyInt(gateway::APIVersion()));
68 payloadJson.Add("hostname", GetHostname());
69 if (!metadata.empty()) {
70 payloadJson.AddJsonObject("metadata", metadata);
71 }
72 const std::string payload = payloadJson.GenerateString();
73
74 shash::Any hmac(shash::kSha1);
75 shash::HmacString(secret, payload, &hmac);
76
77 SslCertificateStore cs;
78 cs.UseSystemCertificatePath();
79 cs.ApplySslCertificatePath(h_curl);
80
81 const std::string header_str = std::string("Authorization: ") + key_id + " "
82 + Base64(hmac.ToString(false));
83 struct curl_slist *auth_header = NULL;
84 auth_header = curl_slist_append(auth_header, header_str.c_str());
85 curl_easy_setopt(h_curl, CURLOPT_HTTPHEADER, auth_header);
86
87 // Make request to acquire lease from repo services
88 curl_easy_setopt(h_curl, CURLOPT_URL, (repo_service_url + "/leases").c_str());
89 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDSIZE_LARGE,
90 static_cast<curl_off_t>(payload.length()));
91 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDS, payload.c_str());
92 curl_easy_setopt(h_curl, CURLOPT_WRITEFUNCTION, RecvCB);
93 curl_easy_setopt(h_curl, CURLOPT_WRITEDATA, buffer);
94
95 ret = curl_easy_perform(h_curl);
96 if (ret) {
97 LogCvmfs(kLogUploadGateway, kLogStderr,
98 "Make lease acquire request failed: %d. Reply: %s", ret,
99 buffer->data.c_str());
100 }
101
102 curl_easy_cleanup(h_curl);
103 h_curl = NULL;
104
105 return !ret;
106 }
107
108 bool MakeEndRequest(const std::string &method, const std::string &key_id,
109 const std::string &secret, const std::string &session_token,
110 const std::string &repo_service_url,
111 const std::string &request_payload, CurlBuffer *reply,
112 bool expect_final_revision) {
113 CURLcode ret = static_cast<CURLcode>(0);
114
115 CURL *h_curl = PrepareCurl(method);
116 if (!h_curl) {
117 return false;
118 }
119
120 shash::Any hmac(shash::kSha1);
121 shash::HmacString(secret, session_token, &hmac);
122
123 SslCertificateStore cs;
124 cs.UseSystemCertificatePath();
125 cs.ApplySslCertificatePath(h_curl);
126
127 const std::string header_str = std::string("Authorization: ") + key_id + " "
128 + Base64(hmac.ToString(false));
129 struct curl_slist *auth_header = NULL;
130 auth_header = curl_slist_append(auth_header, header_str.c_str());
131 curl_easy_setopt(h_curl, CURLOPT_HTTPHEADER, auth_header);
132
133 curl_easy_setopt(h_curl, CURLOPT_URL,
134 (repo_service_url + "/leases/" + session_token).c_str());
135 if (request_payload != "") {
136 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDSIZE_LARGE,
137 static_cast<curl_off_t>(request_payload.length()));
138 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDS, request_payload.c_str());
139 } else {
140 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDSIZE_LARGE,
141 static_cast<curl_off_t>(0));
142 curl_easy_setopt(h_curl, CURLOPT_POSTFIELDS, NULL);
143 }
144 curl_easy_setopt(h_curl, CURLOPT_WRITEFUNCTION, RecvCB);
145 curl_easy_setopt(h_curl, CURLOPT_WRITEDATA, reply);
146
147 ret = curl_easy_perform(h_curl);
148 if (ret) {
149 LogCvmfs(kLogUploadGateway, kLogStderr,
150 "Lease end request - curl_easy_perform failed: %d", ret);
151 }
152
153 JsonDocument *doc = JsonDocument::Create(reply->data);
154 bool ok = true;
155 if (!doc) {
156 ok = false;
157 } else {
158 std::unique_ptr<JsonDocument> const reply_json(doc);
159 const JSON *reply_status = JsonDocument::SearchInObject(
160 reply_json->root(), "status", JSON_STRING);
161 ok = (reply_status != NULL
162 && std::string(reply_status->get<std::string>()) == "ok");
163 if (!ok) {
164 LogCvmfs(kLogUploadGateway, kLogStderr,
165 "Lease end request - error reply: %s", reply->data.c_str());
166 }
167 if (expect_final_revision) {
168 const JSON *reply_final_rev = JsonDocument::SearchInObject(
169 reply_json->root(), "final_revision", JSON_INT);
170 ok = (reply_final_rev != NULL);
171 if (ok) {
172 g_final_revision = reply_final_rev->get<int>();
173 } else {
174 g_final_revision = -1;
175 }
176 }
177 }
178
179 curl_easy_cleanup(h_curl);
180 h_curl = NULL;
181
182 return ok && !ret;
183 }
184