Coverage Report

Created: 2025-12-31 08:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/port/cpl_swift.cpp
Line
Count
Source
1
/**********************************************************************
2
 * Project:  CPL - Common Portability Library
3
 * Purpose:  OpenStack Swift Object Storage routines
4
 * Author:   Even Rouault <even.rouault at spatialys.com>
5
 *
6
 **********************************************************************
7
 * Copyright (c) 2018, Even Rouault <even.rouault at spatialys.com>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
 * DEALINSwift IN THE SOFTWARE.
26
 ****************************************************************************/
27
28
#include "cpl_swift.h"
29
#include "cpl_vsi_error.h"
30
#include "cpl_http.h"
31
#include "cpl_multiproc.h"
32
#include "cpl_json.h"
33
34
// HOWTO setup a Docker-based SWIFT server:
35
// https://github.com/MorrisJobke/docker-swift-onlyone
36
37
//! @cond Doxygen_Suppress
38
39
#ifdef HAVE_CURL
40
41
static CPLMutex *g_hMutex = nullptr;
42
static std::string g_osLastAuthURL;
43
static std::string g_osLastUser;
44
static std::string g_osLastKey;
45
static std::string g_osLastStorageURL;
46
static std::string g_osLastAuthToken;
47
48
/************************************************************************/
49
/*                          GetSwiftHeaders()                           */
50
/************************************************************************/
51
52
static struct curl_slist *GetSwiftHeaders(const std::string &osAuthToken,
53
                                          struct curl_slist *headers)
54
0
{
55
0
    headers = curl_slist_append(headers, "Accept: application/json");
56
0
    headers = curl_slist_append(
57
0
        headers, CPLSPrintf("x-auth-token: %s", osAuthToken.c_str()));
58
0
    return headers;
59
0
}
60
61
/************************************************************************/
62
/*                     VSISwiftHandleHelper()                           */
63
/************************************************************************/
64
VSISwiftHandleHelper::VSISwiftHandleHelper(const std::string &osStorageURL,
65
                                           const std::string &osAuthToken,
66
                                           const std::string &osBucket,
67
                                           const std::string &osObjectKey)
68
0
    : m_osURL(BuildURL(osStorageURL, osBucket, osObjectKey)),
69
0
      m_osStorageURL(osStorageURL), m_osAuthToken(osAuthToken),
70
0
      m_osBucket(osBucket), m_osObjectKey(osObjectKey)
71
0
{
72
0
}
73
74
/************************************************************************/
75
/*                      ~VSISwiftHandleHelper()                         */
76
/************************************************************************/
77
78
VSISwiftHandleHelper::~VSISwiftHandleHelper()
79
0
{
80
0
}
81
82
/************************************************************************/
83
/*                        GetConfiguration()                            */
84
/************************************************************************/
85
86
bool VSISwiftHandleHelper::GetConfiguration(const std::string &osPathForOption,
87
                                            std::string &osStorageURL,
88
                                            std::string &osAuthToken)
89
23.9k
{
90
23.9k
    osStorageURL = VSIGetPathSpecificOption(osPathForOption.c_str(),
91
23.9k
                                            "SWIFT_STORAGE_URL", "");
92
23.9k
    if (!osStorageURL.empty())
93
0
    {
94
0
        osAuthToken = VSIGetPathSpecificOption(osPathForOption.c_str(),
95
0
                                               "SWIFT_AUTH_TOKEN", "");
96
0
        if (osAuthToken.empty())
97
0
        {
98
0
            const char *pszMsg = "Missing SWIFT_AUTH_TOKEN";
99
0
            CPLDebug("SWIFT", "%s", pszMsg);
100
0
            VSIError(VSIE_InvalidCredentials, "%s", pszMsg);
101
0
            return false;
102
0
        }
103
0
        return true;
104
0
    }
105
106
23.9k
    const std::string osAuthVersion = VSIGetPathSpecificOption(
107
23.9k
        osPathForOption.c_str(), "OS_IDENTITY_API_VERSION", "");
108
23.9k
    if (osAuthVersion == "3")
109
0
    {
110
0
        const std::string osAuthType = VSIGetPathSpecificOption(
111
0
            osPathForOption.c_str(), "OS_AUTH_TYPE", "");
112
0
        if (!CheckCredentialsV3(osPathForOption, osAuthType))
113
0
            return false;
114
0
        if (osAuthType == "v3applicationcredential")
115
0
        {
116
0
            if (GetCached(osPathForOption, "OS_AUTH_URL",
117
0
                          "OS_APPLICATION_CREDENTIAL_ID",
118
0
                          "OS_APPLICATION_CREDENTIAL_SECRET", osStorageURL,
119
0
                          osAuthToken))
120
0
                return true;
121
0
        }
122
0
        else
123
0
        {
124
0
            if (GetCached(osPathForOption, "OS_AUTH_URL", "OS_USERNAME",
125
0
                          "OS_PASSWORD", osStorageURL, osAuthToken))
126
0
                return true;
127
0
        }
128
0
        if (AuthV3(osPathForOption, osAuthType, osStorageURL, osAuthToken))
129
0
            return true;
130
0
    }
131
23.9k
    else
132
23.9k
    {
133
23.9k
        const std::string osAuthV1URL = VSIGetPathSpecificOption(
134
23.9k
            osPathForOption.c_str(), "SWIFT_AUTH_V1_URL", "");
135
23.9k
        if (!osAuthV1URL.empty())
136
0
        {
137
0
            if (!CheckCredentialsV1(osPathForOption))
138
0
                return false;
139
0
            if (GetCached(osPathForOption, "SWIFT_AUTH_V1_URL", "SWIFT_USER",
140
0
                          "SWIFT_KEY", osStorageURL, osAuthToken))
141
0
                return true;
142
0
            if (AuthV1(osPathForOption, osStorageURL, osAuthToken))
143
0
                return true;
144
0
        }
145
23.9k
    }
146
147
23.9k
    const char *pszMsg = "Missing SWIFT_STORAGE_URL+SWIFT_AUTH_TOKEN or "
148
23.9k
                         "appropriate authentication options";
149
23.9k
    CPLDebug("SWIFT", "%s", pszMsg);
150
23.9k
    VSIError(VSIE_InvalidCredentials, "%s", pszMsg);
151
152
23.9k
    return false;
153
23.9k
}
154
155
/************************************************************************/
156
/*                               AuthV1()                               */
157
/************************************************************************/
158
159
bool VSISwiftHandleHelper::AuthV1(const std::string &osPathForOption,
160
                                  std::string &osStorageURL,
161
                                  std::string &osAuthToken)
162
0
{
163
0
    std::string osAuthURL = VSIGetPathSpecificOption(osPathForOption.c_str(),
164
0
                                                     "SWIFT_AUTH_V1_URL", "");
165
0
    std::string osUser =
166
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_USER", "");
167
0
    std::string osKey =
168
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_KEY", "");
169
0
    char **papszHeaders =
170
0
        CSLSetNameValue(nullptr, "HEADERS",
171
0
                        CPLSPrintf("X-Auth-User: %s\r\n"
172
0
                                   "X-Auth-Key: %s",
173
0
                                   osUser.c_str(), osKey.c_str()));
174
0
    CPLHTTPResult *psResult = CPLHTTPFetch(osAuthURL.c_str(), papszHeaders);
175
0
    CSLDestroy(papszHeaders);
176
0
    if (psResult == nullptr)
177
0
        return false;
178
0
    osStorageURL =
179
0
        CSLFetchNameValueDef(psResult->papszHeaders, "X-Storage-Url", "");
180
0
    osAuthToken =
181
0
        CSLFetchNameValueDef(psResult->papszHeaders, "X-Auth-Token", "");
182
0
    std::string osErrorMsg =
183
0
        psResult->pabyData ? reinterpret_cast<const char *>(psResult->pabyData)
184
0
                           : "";
185
0
    CPLHTTPDestroyResult(psResult);
186
0
    if (osStorageURL.empty() || osAuthToken.empty())
187
0
    {
188
0
        CPLDebug("SWIFT", "Authentication failed: %s", osErrorMsg.c_str());
189
0
        VSIError(VSIE_InvalidCredentials, "Authentication failed: %s",
190
0
                 osErrorMsg.c_str());
191
0
        return false;
192
0
    }
193
194
    // Cache credentials
195
0
    {
196
0
        CPLMutexHolder oHolder(&g_hMutex);
197
0
        g_osLastAuthURL = std::move(osAuthURL);
198
0
        g_osLastUser = std::move(osUser);
199
0
        g_osLastKey = std::move(osKey);
200
0
        g_osLastStorageURL = osStorageURL;
201
0
        g_osLastAuthToken = osAuthToken;
202
0
    }
203
204
0
    return true;
205
0
}
206
207
/************************************************************************/
208
/*                      CreateAuthV3RequestObject()                     */
209
/************************************************************************/
210
211
CPLJSONObject VSISwiftHandleHelper::CreateAuthV3RequestObject(
212
    const std::string &osPathForOption, const std::string &osAuthType)
213
0
{
214
0
    CPLJSONArray methods;
215
0
    CPLJSONObject identity;
216
0
    CPLJSONObject scope;
217
0
    if (osAuthType == "v3applicationcredential")
218
0
    {
219
0
        std::string osApplicationCredentialID = VSIGetPathSpecificOption(
220
0
            osPathForOption.c_str(), "OS_APPLICATION_CREDENTIAL_ID", "");
221
0
        std::string osApplicationCredentialSecret = VSIGetPathSpecificOption(
222
0
            osPathForOption.c_str(), "OS_APPLICATION_CREDENTIAL_SECRET", "");
223
0
        CPLJSONObject applicationCredential;
224
0
        applicationCredential.Add("id", osApplicationCredentialID);
225
0
        applicationCredential.Add("secret", osApplicationCredentialSecret);
226
0
        methods.Add("application_credential");
227
0
        identity.Add("application_credential", applicationCredential);
228
        // Application credentials cannot request a scope.
229
0
    }
230
0
    else
231
0
    {
232
0
        std::string osUser = VSIGetPathSpecificOption(osPathForOption.c_str(),
233
0
                                                      "OS_USERNAME", "");
234
0
        std::string osPassword = VSIGetPathSpecificOption(
235
0
            osPathForOption.c_str(), "OS_PASSWORD", "");
236
237
0
        CPLJSONObject user;
238
0
        user.Add("name", osUser);
239
0
        user.Add("password", osPassword);
240
241
0
        std::string osUserDomainName = VSIGetPathSpecificOption(
242
0
            osPathForOption.c_str(), "OS_USER_DOMAIN_NAME", "");
243
0
        if (!osUserDomainName.empty())
244
0
        {
245
0
            CPLJSONObject userDomain;
246
0
            userDomain.Add("name", osUserDomainName);
247
0
            user.Add("domain", userDomain);
248
0
        }
249
250
0
        CPLJSONObject password;
251
0
        password.Add("user", user);
252
0
        methods.Add("password");
253
0
        identity.Add("password", password);
254
255
        // Request a scope if one is specified in the configuration
256
0
        std::string osProjectName = VSIGetPathSpecificOption(
257
0
            osPathForOption.c_str(), "OS_PROJECT_NAME", "");
258
0
        if (!osProjectName.empty())
259
0
        {
260
0
            CPLJSONObject project;
261
0
            project.Add("name", osProjectName);
262
263
0
            std::string osProjectDomainName = VSIGetPathSpecificOption(
264
0
                osPathForOption.c_str(), "OS_PROJECT_DOMAIN_NAME", "");
265
0
            if (!osProjectDomainName.empty())
266
0
            {
267
0
                CPLJSONObject projectDomain;
268
0
                projectDomain.Add("name", osProjectDomainName);
269
0
                project.Add("domain", projectDomain);
270
0
            }
271
272
0
            scope.Add("project", project);
273
0
        }
274
0
    }
275
276
0
    identity.Add("methods", methods);
277
278
0
    CPLJSONObject auth;
279
0
    auth.Add("identity", identity);
280
0
    if (!scope.GetChildren().empty())
281
0
        auth.Add("scope", scope);
282
283
0
    CPLJSONObject obj;
284
0
    obj.Add("auth", auth);
285
0
    return obj;
286
0
}
287
288
/************************************************************************/
289
/*                      GetAuthV3StorageURL()                           */
290
/************************************************************************/
291
292
bool VSISwiftHandleHelper::GetAuthV3StorageURL(
293
    const std::string &osPathForOption, const CPLHTTPResult *psResult,
294
    std::string &storageURL)
295
0
{
296
0
    if (psResult->pabyData == nullptr)
297
0
        return false;
298
299
0
    CPLJSONDocument resultJson;
300
0
    resultJson.LoadMemory(psResult->pabyData);
301
0
    CPLJSONObject result(resultJson.GetRoot());
302
303
0
    CPLJSONObject token(result.GetObj("token"));
304
0
    if (!token.IsValid())
305
0
        return false;
306
307
0
    CPLJSONArray catalog(token.GetArray("catalog"));
308
0
    if (!catalog.IsValid())
309
0
        return false;
310
311
0
    CPLJSONArray endpoints;
312
0
    for (int i = 0; i < catalog.Size(); ++i)
313
0
    {
314
0
        CPLJSONObject item(catalog[i]);
315
0
        if (item.GetString("type") == "object-store")
316
0
        {
317
0
            endpoints = item.GetArray("endpoints");
318
0
            break;
319
0
        }
320
0
    }
321
322
0
    if (endpoints.Size() == 0)
323
0
        return false;
324
325
0
    std::string osRegionName =
326
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "OS_REGION_NAME", "");
327
0
    if (osRegionName.empty())
328
0
    {
329
0
        for (int i = 0; i < endpoints.Size(); ++i)
330
0
        {
331
0
            CPLJSONObject endpoint(endpoints[i]);
332
0
            std::string interfaceType =
333
0
                endpoint.GetString("interface", "");  // internal, admin, public
334
0
            if (interfaceType.empty() || interfaceType == "public")
335
0
            {
336
0
                storageURL = endpoint.GetString("url");
337
0
                return true;
338
0
            }
339
0
        }
340
0
        return false;
341
0
    }
342
343
0
    for (int i = 0; i < endpoints.Size(); ++i)
344
0
    {
345
0
        CPLJSONObject endpoint(endpoints[i]);
346
0
        if (endpoint.GetString("region") == osRegionName)
347
0
        {
348
0
            std::string interfaceType =
349
0
                endpoint.GetString("interface", "");  // internal, admin, public
350
0
            if (interfaceType.empty() || interfaceType == "public")
351
0
            {
352
0
                storageURL = endpoint.GetString("url");
353
0
                CPLDebug("SWIFT", "Storage URL '%s' for region '%s'",
354
0
                         storageURL.c_str(), osRegionName.c_str());
355
0
                return true;
356
0
            }
357
0
        }
358
0
    }
359
360
0
    return false;
361
0
}
362
363
/************************************************************************/
364
/*                                AuthV3()                              */
365
/************************************************************************/
366
367
bool VSISwiftHandleHelper::AuthV3(const std::string &osPathForOption,
368
                                  const std::string &osAuthType,
369
                                  std::string &osStorageURL,
370
                                  std::string &osAuthToken)
371
0
{
372
0
    std::string osAuthID;
373
0
    std::string osAuthKey;
374
0
    if (osAuthType.empty() || osAuthType == "password")
375
0
    {
376
0
        osAuthID = VSIGetPathSpecificOption(osPathForOption.c_str(),
377
0
                                            "OS_USERNAME", "");
378
0
        osAuthKey = VSIGetPathSpecificOption(osPathForOption.c_str(),
379
0
                                             "OS_PASSWORD", "");
380
0
    }
381
0
    else if (osAuthType == "v3applicationcredential")
382
0
    {
383
0
        osAuthID = VSIGetPathSpecificOption(osPathForOption.c_str(),
384
0
                                            "OS_APPLICATION_CREDENTIAL_ID", "");
385
0
        osAuthKey = VSIGetPathSpecificOption(
386
0
            osPathForOption.c_str(), "OS_APPLICATION_CREDENTIAL_SECRET", "");
387
0
    }
388
0
    else
389
0
    {
390
0
        CPLDebug("SWIFT", "Unsupported OS SWIFT Auth Type: %s",
391
0
                 osAuthType.c_str());
392
0
        VSIError(VSIE_InvalidCredentials, "%s", osAuthType.c_str());
393
0
        return false;
394
0
    }
395
0
    CPLJSONObject postObject(
396
0
        CreateAuthV3RequestObject(osPathForOption, osAuthType));
397
0
    std::string post = postObject.Format(CPLJSONObject::PrettyFormat::Plain);
398
399
    // coverity[tainted_data]
400
0
    std::string osAuthURL =
401
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "OS_AUTH_URL", "");
402
0
    std::string url = osAuthURL;
403
0
    if (!url.empty() && url.back() != '/')
404
0
        url += '/';
405
0
    url += "auth/tokens";
406
407
0
    char **papszOptions = CSLSetNameValue(nullptr, "POSTFIELDS", post.data());
408
0
    papszOptions = CSLSetNameValue(papszOptions, "HEADERS",
409
0
                                   "Content-Type: application/json");
410
0
    CPLHTTPResult *psResult = CPLHTTPFetchEx(url.c_str(), papszOptions, nullptr,
411
0
                                             nullptr, nullptr, nullptr);
412
0
    CSLDestroy(papszOptions);
413
414
0
    if (psResult == nullptr)
415
0
        return false;
416
417
0
    osAuthToken =
418
0
        CSLFetchNameValueDef(psResult->papszHeaders, "X-Subject-Token", "");
419
420
0
    if (!GetAuthV3StorageURL(osPathForOption, psResult, osStorageURL))
421
0
    {
422
0
        CPLHTTPDestroyResult(psResult);
423
0
        return false;
424
0
    }
425
426
0
    if (osStorageURL.empty() || osAuthToken.empty())
427
0
    {
428
0
        std::string osErrorMsg =
429
0
            reinterpret_cast<const char *>(psResult->pabyData);
430
0
        CPLDebug("SWIFT", "Authentication failed: %s", osErrorMsg.c_str());
431
0
        VSIError(VSIE_InvalidCredentials, "Authentication failed: %s",
432
0
                 osErrorMsg.c_str());
433
0
        CPLHTTPDestroyResult(psResult);
434
0
        return false;
435
0
    }
436
437
0
    CPLHTTPDestroyResult(psResult);
438
439
    // Cache credentials
440
0
    {
441
0
        CPLMutexHolder oHolder(&g_hMutex);
442
0
        g_osLastAuthURL = std::move(osAuthURL);
443
0
        g_osLastUser = std::move(osAuthID);
444
0
        g_osLastKey = std::move(osAuthKey);
445
0
        g_osLastStorageURL = osStorageURL;
446
0
        g_osLastAuthToken = osAuthToken;
447
0
    }
448
0
    return true;
449
0
}
450
451
/************************************************************************/
452
/*                           Authenticate()                             */
453
/************************************************************************/
454
455
bool VSISwiftHandleHelper::Authenticate(const std::string &osPathForOption)
456
0
{
457
0
    std::string osAuthV1URL = VSIGetPathSpecificOption(osPathForOption.c_str(),
458
0
                                                       "SWIFT_AUTH_V1_URL", "");
459
0
    if (!osAuthV1URL.empty() &&
460
0
        AuthV1(osPathForOption, m_osStorageURL, m_osAuthToken))
461
0
    {
462
0
        RebuildURL();
463
0
        return true;
464
0
    }
465
466
0
    const std::string osAuthVersion = VSIGetPathSpecificOption(
467
0
        osPathForOption.c_str(), "OS_IDENTITY_API_VERSION", "");
468
0
    const std::string osAuthType =
469
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "OS_AUTH_TYPE", "");
470
0
    if (osAuthVersion == "3" &&
471
0
        AuthV3(osPathForOption, osAuthType, m_osStorageURL, m_osAuthToken))
472
0
    {
473
0
        RebuildURL();
474
0
        return true;
475
0
    }
476
477
0
    return false;
478
0
}
479
480
/************************************************************************/
481
/*                         CheckCredentialsV1()                         */
482
/************************************************************************/
483
484
bool VSISwiftHandleHelper::CheckCredentialsV1(
485
    const std::string &osPathForOption)
486
0
{
487
0
    const char *pszMissingKey = nullptr;
488
0
    std::string osUser =
489
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_USER", "");
490
0
    std::string osKey =
491
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_KEY", "");
492
0
    if (osUser.empty())
493
0
    {
494
0
        pszMissingKey = "SWIFT_USER";
495
0
    }
496
0
    else if (osKey.empty())
497
0
    {
498
0
        pszMissingKey = "SWIFT_KEY";
499
0
    }
500
501
0
    if (pszMissingKey)
502
0
    {
503
0
        CPLDebug("SWIFT", "Missing %s configuration option", pszMissingKey);
504
0
        VSIError(VSIE_InvalidCredentials, "%s", pszMissingKey);
505
0
        return false;
506
0
    }
507
508
0
    return true;
509
0
}
510
511
/************************************************************************/
512
/*                         CheckCredentialsV3()                         */
513
/************************************************************************/
514
515
bool VSISwiftHandleHelper::CheckCredentialsV3(
516
    const std::string &osPathForOption, const std::string &osAuthType)
517
0
{
518
0
    const char *papszMandatoryOptionKeys[3] = {
519
0
        "OS_AUTH_URL",
520
0
        "",
521
0
        "",
522
0
    };
523
0
    if (osAuthType.empty() || osAuthType == "password")
524
0
    {
525
0
        papszMandatoryOptionKeys[1] = "OS_USERNAME";
526
0
        papszMandatoryOptionKeys[2] = "OS_PASSWORD";
527
0
    }
528
0
    else if (osAuthType == "v3applicationcredential")
529
0
    {
530
0
        papszMandatoryOptionKeys[1] = "OS_APPLICATION_CREDENTIAL_ID";
531
0
        papszMandatoryOptionKeys[2] = "OS_APPLICATION_CREDENTIAL_SECRET";
532
0
    }
533
0
    else
534
0
    {
535
0
        CPLDebug("SWIFT", "Unsupported OS SWIFT Auth Type: %s",
536
0
                 osAuthType.c_str());
537
0
        VSIError(VSIE_InvalidCredentials, "%s", osAuthType.c_str());
538
0
        return false;
539
0
    }
540
0
    for (auto const *pszOptionKey : papszMandatoryOptionKeys)
541
0
    {
542
0
        std::string option =
543
0
            VSIGetPathSpecificOption(osPathForOption.c_str(), pszOptionKey, "");
544
0
        if (option.empty())
545
0
        {
546
0
            CPLDebug("SWIFT", "Missing %s configuration option", pszOptionKey);
547
0
            VSIError(VSIE_InvalidCredentials, "%s", pszOptionKey);
548
0
            return false;
549
0
        }
550
0
    }
551
0
    return true;
552
0
}
553
554
/************************************************************************/
555
/*                            GetCached()                               */
556
/************************************************************************/
557
558
bool VSISwiftHandleHelper::GetCached(const std::string &osPathForOption,
559
                                     const char *pszURLKey,
560
                                     const char *pszUserKey,
561
                                     const char *pszPasswordKey,
562
                                     std::string &osStorageURL,
563
                                     std::string &osAuthToken)
564
0
{
565
0
    std::string osAuthURL =
566
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), pszURLKey, "");
567
0
    std::string osUser =
568
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), pszUserKey, "");
569
0
    std::string osKey =
570
0
        VSIGetPathSpecificOption(osPathForOption.c_str(), pszPasswordKey, "");
571
572
0
    CPLMutexHolder oHolder(&g_hMutex);
573
    // Re-use cached credentials if available
574
    // coverity[tainted_data]
575
0
    if (osAuthURL == g_osLastAuthURL && osUser == g_osLastUser &&
576
0
        osKey == g_osLastKey)
577
0
    {
578
0
        osStorageURL = g_osLastStorageURL;
579
0
        osAuthToken = g_osLastAuthToken;
580
0
        return true;
581
0
    }
582
0
    return false;
583
0
}
584
585
/************************************************************************/
586
/*                          BuildFromURI()                              */
587
/************************************************************************/
588
589
VSISwiftHandleHelper *
590
VSISwiftHandleHelper::BuildFromURI(const char *pszURI,
591
                                   const char * /*pszFSPrefix*/)
592
23.9k
{
593
23.9k
    std::string osPathForOption("/vsiswift/");
594
23.9k
    osPathForOption += pszURI;
595
596
23.9k
    std::string osStorageURL;
597
23.9k
    std::string osAuthToken;
598
599
23.9k
    if (!GetConfiguration(osPathForOption, osStorageURL, osAuthToken))
600
23.9k
    {
601
23.9k
        return nullptr;
602
23.9k
    }
603
604
    // pszURI == bucket/object
605
0
    const std::string osBucketObject(pszURI);
606
0
    std::string osBucket(osBucketObject);
607
0
    std::string osObjectKey;
608
0
    size_t nSlashPos = osBucketObject.find('/');
609
0
    if (nSlashPos != std::string::npos)
610
0
    {
611
0
        osBucket = osBucketObject.substr(0, nSlashPos);
612
0
        osObjectKey = osBucketObject.substr(nSlashPos + 1);
613
0
    }
614
615
0
    return new VSISwiftHandleHelper(osStorageURL, osAuthToken, osBucket,
616
0
                                    osObjectKey);
617
23.9k
}
618
619
/************************************************************************/
620
/*                            BuildURL()                                */
621
/************************************************************************/
622
623
std::string VSISwiftHandleHelper::BuildURL(const std::string &osStorageURL,
624
                                           const std::string &osBucket,
625
                                           const std::string &osObjectKey)
626
0
{
627
0
    std::string osURL = osStorageURL;
628
0
    if (!osBucket.empty())
629
0
        osURL += "/" + CPLAWSURLEncode(osBucket, false);
630
0
    if (!osObjectKey.empty())
631
0
        osURL += "/" + CPLAWSURLEncode(osObjectKey, false);
632
0
    return osURL;
633
0
}
634
635
/************************************************************************/
636
/*                           RebuildURL()                               */
637
/************************************************************************/
638
639
void VSISwiftHandleHelper::RebuildURL()
640
0
{
641
0
    m_osURL = BuildURL(m_osStorageURL, m_osBucket, m_osObjectKey);
642
0
    m_osURL += GetQueryString(false);
643
0
}
644
645
/************************************************************************/
646
/*                           GetCurlHeaders()                           */
647
/************************************************************************/
648
649
struct curl_slist *VSISwiftHandleHelper::GetCurlHeaders(
650
    const std::string &, struct curl_slist *headers, const void *, size_t) const
651
0
{
652
0
    return GetSwiftHeaders(m_osAuthToken, headers);
653
0
}
654
655
/************************************************************************/
656
/*                          CleanMutex()                                */
657
/************************************************************************/
658
659
void VSISwiftHandleHelper::CleanMutex()
660
0
{
661
0
    if (g_hMutex != nullptr)
662
0
        CPLDestroyMutex(g_hMutex);
663
0
    g_hMutex = nullptr;
664
0
}
665
666
/************************************************************************/
667
/*                          ClearCache()                                */
668
/************************************************************************/
669
670
void VSISwiftHandleHelper::ClearCache()
671
0
{
672
0
    CPLMutexHolder oHolder(&g_hMutex);
673
0
    g_osLastAuthURL.clear();
674
0
    g_osLastUser.clear();
675
0
    g_osLastKey.clear();
676
0
    g_osLastStorageURL.clear();
677
0
    g_osLastAuthToken.clear();
678
0
}
679
680
#endif
681
682
//! @endcond