Coverage Report

Created: 2025-06-13 06:29

/src/gdal/port/cpl_http.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  Common Portability Library
4
 * Purpose:  Function wrapper for libcurl HTTP access.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2006, Frank Warmerdam
9
 * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#ifndef CPL_HTTP_H_INCLUDED
15
#define CPL_HTTP_H_INCLUDED
16
17
#include "cpl_conv.h"
18
#include "cpl_string.h"
19
#include "cpl_progress.h"
20
#include "cpl_vsi.h"
21
22
/**
23
 * \file cpl_http.h
24
 *
25
 * Interface for downloading HTTP, FTP documents
26
 */
27
28
/*! @cond Doxygen_Suppress */
29
#ifndef CPL_HTTP_MAX_RETRY
30
0
#define CPL_HTTP_MAX_RETRY 0
31
#endif
32
33
#ifndef CPL_HTTP_RETRY_DELAY
34
0
#define CPL_HTTP_RETRY_DELAY 30.0
35
#endif
36
/*! @endcond */
37
38
CPL_C_START
39
40
/*! Describe a part of a multipart message */
41
typedef struct
42
{
43
    /*! NULL terminated array of headers */ char **papszHeaders;
44
45
    /*! Buffer with data of the part     */ GByte *pabyData;
46
    /*! Buffer length                    */ int nDataLen;
47
} CPLMimePart;
48
49
/*! Describe the result of a CPLHTTPFetch() call */
50
typedef struct
51
{
52
    /*! cURL error code : 0=success, non-zero if request failed */
53
    int nStatus;
54
55
    /*! Content-Type of the response */
56
    char *pszContentType;
57
58
    /*! Error message from curl, or NULL */
59
    char *pszErrBuf;
60
61
    /*! Length of the pabyData buffer */
62
    int nDataLen;
63
    /*! Allocated size of the pabyData buffer */
64
    int nDataAlloc;
65
66
    /*! Buffer with downloaded data */
67
    GByte *pabyData;
68
69
    /*! Headers returned */
70
    char **papszHeaders;
71
72
    /*! Number of parts in a multipart message */
73
    int nMimePartCount;
74
75
    /*! Array of parts (resolved by CPLHTTPParseMultipartMime()) */
76
    CPLMimePart *pasMimePart;
77
78
} CPLHTTPResult;
79
80
/*! @cond Doxygen_Suppress */
81
typedef size_t (*CPLHTTPFetchWriteFunc)(void *pBuffer, size_t nSize,
82
                                        size_t nMemb, void *pWriteArg);
83
/*! @endcond */
84
85
int CPL_DLL CPLHTTPEnabled(void);
86
CPLHTTPResult CPL_DLL *CPLHTTPFetch(const char *pszURL,
87
                                    CSLConstList papszOptions);
88
CPLHTTPResult CPL_DLL *
89
CPLHTTPFetchEx(const char *pszURL, CSLConstList papszOptions,
90
               GDALProgressFunc pfnProgress, void *pProgressArg,
91
               CPLHTTPFetchWriteFunc pfnWrite, void *pWriteArg);
92
CPLHTTPResult CPL_DLL **CPLHTTPMultiFetch(const char *const *papszURL,
93
                                          int nURLCount, int nMaxSimultaneous,
94
                                          CSLConstList papszOptions);
95
96
void CPL_DLL CPLHTTPCleanup(void);
97
void CPL_DLL CPLHTTPDestroyResult(CPLHTTPResult *psResult);
98
void CPL_DLL CPLHTTPDestroyMultiResult(CPLHTTPResult **papsResults, int nCount);
99
int CPL_DLL CPLHTTPParseMultipartMime(CPLHTTPResult *psResult);
100
101
void CPL_DLL CPLHTTPSetDefaultUserAgent(const char *pszUserAgent);
102
103
/* -------------------------------------------------------------------- */
104
/* To install an alternate network layer to the default Curl one        */
105
/* -------------------------------------------------------------------- */
106
/** Callback function to process network requests.
107
 *
108
 * If CLOSE_PERSISTENT is found in papszOptions, no network request should be
109
 * issued, but a dummy non-null CPLHTTPResult* should be returned by the
110
 * callback.
111
 *
112
 * Its first arguments are the same as CPLHTTPFetchEx()
113
 * @param pszURL See CPLHTTPFetchEx()
114
 * @param papszOptions See CPLHTTPFetchEx()
115
 * @param pfnProgress See CPLHTTPFetchEx()
116
 * @param pProgressArg See CPLHTTPFetchEx()
117
 * @param pfnWrite See CPLHTTPFetchEx()
118
 * @param pWriteArg See CPLHTTPFetchEx()
119
 * @param pUserData user data value that was passed during
120
 * CPLHTTPPushFetchCallback()
121
 * @return nullptr if the request cannot be processed, in which case the
122
 * previous handler will be used.
123
 */
124
typedef CPLHTTPResult *(*CPLHTTPFetchCallbackFunc)(
125
    const char *pszURL, CSLConstList papszOptions, GDALProgressFunc pfnProgress,
126
    void *pProgressArg, CPLHTTPFetchWriteFunc pfnWrite, void *pWriteArg,
127
    void *pUserData);
128
129
void CPL_DLL CPLHTTPSetFetchCallback(CPLHTTPFetchCallbackFunc pFunc,
130
                                     void *pUserData);
131
132
int CPL_DLL CPLHTTPPushFetchCallback(CPLHTTPFetchCallbackFunc pFunc,
133
                                     void *pUserData);
134
int CPL_DLL CPLHTTPPopFetchCallback(void);
135
136
/* -------------------------------------------------------------------- */
137
/*      The following is related to OAuth2 authorization around         */
138
/*      google services like fusion tables, and potentially others      */
139
/*      in the future.  Code in cpl_google_oauth2.cpp.                  */
140
/*                                                                      */
141
/*      These services are built on CPL HTTP services.                  */
142
/* -------------------------------------------------------------------- */
143
144
char CPL_DLL *GOA2GetAuthorizationURL(const char *pszScope);
145
char CPL_DLL *GOA2GetRefreshToken(const char *pszAuthToken,
146
                                  const char *pszScope);
147
char CPL_DLL *GOA2GetAccessToken(const char *pszRefreshToken,
148
                                 const char *pszScope);
149
150
char CPL_DLL **GOA2GetAccessTokenFromServiceAccount(
151
    const char *pszPrivateKey, const char *pszClientEmail, const char *pszScope,
152
    CSLConstList papszAdditionalClaims, CSLConstList papszOptions);
153
154
char CPL_DLL **GOA2GetAccessTokenFromCloudEngineVM(CSLConstList papszOptions);
155
156
CPL_C_END
157
158
#if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS)
159
/*! @cond Doxygen_Suppress */
160
// Not sure if this belong here, used in cpl_http.cpp, cpl_vsil_curl.cpp and
161
// frmts/wms/gdalhttp.cpp
162
void CPL_DLL *CPLHTTPSetOptions(void *pcurl, const char *pszURL,
163
                                const char *const *papszOptions);
164
char **CPLHTTPGetOptionsFromEnv(const char *pszFilename);
165
166
/** Stores HTTP retry parameters */
167
struct CPLHTTPRetryParameters
168
{
169
    int nMaxRetry = CPL_HTTP_MAX_RETRY;
170
    double dfInitialDelay = CPL_HTTP_RETRY_DELAY;
171
    std::string osRetryCodes{};
172
173
    CPLHTTPRetryParameters() = default;
174
    explicit CPLHTTPRetryParameters(const CPLStringList &aosHTTPOptions);
175
};
176
177
/** HTTP retry context */
178
class CPLHTTPRetryContext
179
{
180
  public:
181
    explicit CPLHTTPRetryContext(const CPLHTTPRetryParameters &oParams);
182
183
    bool CanRetry(int response_code, const char *pszErrBuf,
184
                  const char *pszCurlError);
185
    bool CanRetry();
186
187
    /** Returns the delay to apply. Only valid after a successful call to CanRetry() */
188
    double GetCurrentDelay() const;
189
190
    /** Reset retry counter. */
191
    void ResetCounter()
192
0
    {
193
0
        m_nRetryCount = 0;
194
0
    }
195
196
  private:
197
    CPLHTTPRetryParameters m_oParameters{};
198
    int m_nRetryCount = 0;
199
    double m_dfCurDelay = 0.0;
200
    double m_dfNextDelay = 0.0;
201
};
202
203
void CPL_DLL *CPLHTTPIgnoreSigPipe();
204
void CPL_DLL CPLHTTPRestoreSigPipeHandler(void *old_handler);
205
bool CPLMultiPerformWait(void *hCurlMultiHandle, int &repeats);
206
/*! @endcond */
207
208
bool CPL_DLL CPLIsMachinePotentiallyGCEInstance();
209
bool CPLIsMachineForSureGCEInstance();
210
211
/** Manager of Google OAuth2 authentication.
212
 *
213
 * This class handles different authentication methods and handles renewal
214
 * of access token.
215
 *
216
 * @since GDAL 2.3
217
 */
218
class GOA2Manager
219
{
220
  public:
221
    GOA2Manager();
222
223
    /** Authentication method */
224
    typedef enum
225
    {
226
        NONE,
227
        GCE,
228
        ACCESS_TOKEN_FROM_REFRESH,
229
        SERVICE_ACCOUNT
230
    } AuthMethod;
231
232
    bool SetAuthFromGCE(CSLConstList papszOptions);
233
    bool SetAuthFromRefreshToken(const char *pszRefreshToken,
234
                                 const char *pszClientId,
235
                                 const char *pszClientSecret,
236
                                 CSLConstList papszOptions);
237
    bool SetAuthFromServiceAccount(const char *pszPrivateKey,
238
                                   const char *pszClientEmail,
239
                                   const char *pszScope,
240
                                   CSLConstList papszAdditionalClaims,
241
                                   CSLConstList papszOptions);
242
243
    /** Returns the authentication method. */
244
    AuthMethod GetAuthMethod() const
245
0
    {
246
0
        return m_eMethod;
247
0
    }
248
249
    const char *GetBearer() const;
250
251
    /** Returns private key for SERVICE_ACCOUNT method */
252
    const CPLString &GetPrivateKey() const
253
0
    {
254
0
        return m_osPrivateKey;
255
0
    }
256
257
    /** Returns client email for SERVICE_ACCOUNT method */
258
    const CPLString &GetClientEmail() const
259
0
    {
260
0
        return m_osClientEmail;
261
0
    }
262
263
    /** Returns a key that can be used to uniquely identify the instance
264
     * parameters (excluding bearer)
265
     */
266
    std::string GetKey() const
267
0
    {
268
0
        std::string osKey(std::to_string(static_cast<int>(m_eMethod))
269
0
                              .append(",client-id=")
270
0
                              .append(m_osClientId)
271
0
                              .append(",client-secret=")
272
0
                              .append(m_osClientSecret)
273
0
                              .append(",refresh-token=")
274
0
                              .append(m_osRefreshToken)
275
0
                              .append(",private-key=")
276
0
                              .append(m_osPrivateKey)
277
0
                              .append(",client-email=")
278
0
                              .append(m_osClientEmail)
279
0
                              .append(",scope=")
280
0
                              .append(m_osScope));
281
0
        osKey.append(",additional-claims=");
282
0
        for (const auto *pszOption : m_aosAdditionalClaims)
283
0
        {
284
0
            osKey.append(pszOption);
285
0
            osKey.append("+");
286
0
        }
287
0
        osKey.append(",options=");
288
0
        for (const auto *pszOption : m_aosOptions)
289
0
        {
290
0
            osKey.append(pszOption);
291
0
            osKey.append("+");
292
0
        }
293
0
        return osKey;
294
0
    }
295
296
  private:
297
    mutable CPLString m_osCurrentBearer{};
298
    mutable time_t m_nExpirationTime = 0;
299
300
    AuthMethod m_eMethod = NONE;
301
302
    // for ACCESS_TOKEN_FROM_REFRESH
303
    CPLString m_osClientId{};
304
    CPLString m_osClientSecret{};
305
    CPLString m_osRefreshToken{};
306
307
    // for SERVICE_ACCOUNT
308
    CPLString m_osPrivateKey{};
309
    CPLString m_osClientEmail{};
310
    CPLString m_osScope{};
311
    CPLStringList m_aosAdditionalClaims{};
312
313
    CPLStringList m_aosOptions{};
314
};
315
316
#endif  // __cplusplus
317
318
#endif /* ndef CPL_HTTP_H_INCLUDED */