/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 */ |