93
126
* <li>TIMEOUT=val, where val is in seconds</li>
94
127
* <li>HEADERS=val, where val is an extra header to use when getting a web page.
95
128
* For example "Accept: application/x-ogcwkt"
96
* <li>HTTPAUTH=[BASIC/NTLM/ANY] to specify an authentication scheme to use.
129
* <li>HTTPAUTH=[BASIC/NTLM/GSSNEGOTIATE/ANY] to specify an authentication scheme to use.
97
130
* <li>USERPWD=userid:password to specify a user and password for authentication
131
* <li>POSTFIELDS=val, where val is a nul-terminated string to be passed to the server
132
* with a POST request.
133
* <li>PROXY=val, to make requests go through a proxy server, where val is of the
134
* form proxy.server.com:port_number
135
* <li>PROXYUSERPWD=val, where val is of the form username:password
136
* <li>CUSTOMREQUEST=val, where val is GET, PUT, POST, DELETE, etc.. (GDAL >= 1.9.0)
100
* @return a CPLHTTPResult* structure that must be freed by CPLHTTPDestroyResult(),
101
* or NULL if libcurl support is diabled
139
* Alternatively, if not defined in the papszOptions arguments, the PROXY and
140
* PROXYUSERPWD values are searched in the configuration options named
141
* GDAL_HTTP_PROXY and GDAL_HTTP_PROXYUSERPWD, as proxy configuration belongs
142
* to networking setup and makes more sense at the configuration option level
143
* than at the connection level.
145
* @return a CPLHTTPResult* structure that must be freed by
146
* CPLHTTPDestroyResult(), or NULL if libcurl support is disabled
103
148
CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
106
151
#ifndef HAVE_CURL
107
155
CPLError( CE_Failure, CPLE_NotSupported,
108
156
"GDAL/OGR not compiled with libcurl support, remote requests not supported." );
159
/* -------------------------------------------------------------------- */
160
/* Are we using a persistent named session? If so, search for */
163
/* Currently this code does not attempt to protect against */
164
/* multiple threads asking for the same named session. If that */
165
/* occurs it will be in use in multiple threads at once which */
166
/* might have bad consequences depending on what guarantees */
167
/* libcurl gives - which I have not investigated. */
168
/* -------------------------------------------------------------------- */
169
CURL *http_handle = NULL;
171
const char *pszPersistent = CSLFetchNameValue( papszOptions, "PERSISTENT" );
172
const char *pszClosePersistent = CSLFetchNameValue( papszOptions, "CLOSE_PERSISTENT" );
175
CPLString osSessionName = pszPersistent;
176
CPLMutexHolder oHolder( &hSessionMapMutex );
178
if( oSessionMap.count( osSessionName ) == 0 )
180
oSessionMap[osSessionName] = curl_easy_init();
181
CPLDebug( "HTTP", "Establish persistent session named '%s'.",
182
osSessionName.c_str() );
185
http_handle = oSessionMap[osSessionName];
187
/* -------------------------------------------------------------------- */
188
/* Are we requested to close a persistent named session? */
189
/* -------------------------------------------------------------------- */
190
else if (pszClosePersistent)
192
CPLString osSessionName = pszClosePersistent;
193
CPLMutexHolder oHolder( &hSessionMapMutex );
195
std::map<CPLString,CURL*>::iterator oIter = oSessionMap.find( osSessionName );
196
if( oIter != oSessionMap.end() )
198
curl_easy_cleanup(oIter->second);
199
oSessionMap.erase(oIter);
200
CPLDebug( "HTTP", "Ended persistent session named '%s'.",
201
osSessionName.c_str() );
205
CPLDebug( "HTTP", "Could not find persistent session named '%s'.",
206
osSessionName.c_str() );
212
http_handle = curl_easy_init();
214
/* -------------------------------------------------------------------- */
215
/* Setup the request. */
216
/* -------------------------------------------------------------------- */
112
217
char szCurlErrBuf[CURL_ERROR_SIZE+1];
113
218
CPLHTTPResult *psResult;
114
219
struct curl_slist *headers=NULL;
117
CPLDebug( "HTTP", "Fetch(%s)", pszURL );
221
const char* pszArobase = strchr(pszURL, '@');
222
const char* pszSlash = strchr(pszURL, '/');
223
const char* pszColon = (pszSlash) ? strchr(pszSlash, ':') : NULL;
224
if (pszArobase != NULL && pszColon != NULL && pszArobase - pszColon > 0)
226
/* http://user:password@www.example.com */
227
char* pszSanitizedURL = CPLStrdup(pszURL);
228
pszSanitizedURL[pszColon-pszURL] = 0;
229
CPLDebug( "HTTP", "Fetch(%s:#password#%s)", pszSanitizedURL, pszArobase );
230
CPLFree(pszSanitizedURL);
234
CPLDebug( "HTTP", "Fetch(%s)", pszURL );
119
237
psResult = (CPLHTTPResult *) CPLCalloc(1,sizeof(CPLHTTPResult));
121
http_handle = curl_easy_init();
123
239
curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );
241
if (CSLTestBoolean(CPLGetConfigOption("CPL_CURL_VERBOSE", "NO")))
242
curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1);
244
const char *pszHttpVersion = CSLFetchNameValue( papszOptions, "HTTP_VERSION");
245
if( pszHttpVersion && strcmp(pszHttpVersion, "1.0") == 0 )
246
curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
125
248
/* Support control over HTTPAUTH */
126
249
const char *pszHttpAuth = CSLFetchNameValue( papszOptions, "HTTPAUTH" );
127
250
if( pszHttpAuth == NULL )
154
281
if( pszUserPwd != NULL )
155
282
curl_easy_setopt(http_handle, CURLOPT_USERPWD, pszUserPwd );
284
/* Set Proxy parameters */
285
const char* pszProxy = CSLFetchNameValue( papszOptions, "PROXY" );
286
if (pszProxy == NULL)
287
pszProxy = CPLGetConfigOption("GDAL_HTTP_PROXY", NULL);
289
curl_easy_setopt(http_handle,CURLOPT_PROXY,pszProxy);
291
const char* pszProxyUserPwd = CSLFetchNameValue( papszOptions, "PROXYUSERPWD" );
292
if (pszProxyUserPwd == NULL)
293
pszProxyUserPwd = CPLGetConfigOption("GDAL_HTTP_PROXYUSERPWD", NULL);
295
curl_easy_setopt(http_handle,CURLOPT_PROXYUSERPWD,pszProxyUserPwd);
297
// turn off SSL verification, accept all servers with ssl
298
curl_easy_setopt(http_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
301
const char* pszPost = CSLFetchNameValue( papszOptions, "POSTFIELDS" );
302
if( pszPost != NULL )
304
curl_easy_setopt(http_handle, CURLOPT_POST, 1 );
305
curl_easy_setopt(http_handle, CURLOPT_POSTFIELDS, pszPost );
308
const char* pszCustomRequest = CSLFetchNameValue( papszOptions, "CUSTOMREQUEST" );
309
if( pszCustomRequest != NULL )
311
curl_easy_setopt(http_handle, CURLOPT_CUSTOMREQUEST, pszCustomRequest );
157
314
/* Enable following redirections. Requires libcurl 7.10.1 at least */
158
315
curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1 );
159
316
curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10 );
205
383
/* -------------------------------------------------------------------- */
206
384
if( strlen(szCurlErrBuf) > 0 )
208
psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
209
CPLError( CE_Failure, CPLE_AppDefined,
210
"%s", szCurlErrBuf );
213
curl_easy_cleanup( http_handle );
386
int bSkipError = FALSE;
388
/* Some servers such as http://115.113.193.14/cgi-bin/world/qgis_mapserv.fcgi?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities */
389
/* invalidly return Content-Length as the uncompressed size, with makes curl to wait for more data */
390
/* and time-out finally. If we got the expected data size, then we don't emit an error */
391
/* but turn off GZip requests */
392
if (bGZipRequested &&
393
strstr(szCurlErrBuf, "transfer closed with") &&
394
strstr(szCurlErrBuf, "bytes remaining to read"))
396
const char* pszContentLength =
397
CSLFetchNameValue(psResult->papszHeaders, "Content-Length");
398
if (pszContentLength && psResult->nDataLen != 0 &&
399
atoi(pszContentLength) == psResult->nDataLen)
401
const char* pszCurlGZIPOption = CPLGetConfigOption("CPL_CURL_GZIP", NULL);
402
if (pszCurlGZIPOption == NULL)
404
CPLSetConfigOption("CPL_CURL_GZIP", "NO");
405
CPLDebug("HTTP", "Disabling CPL_CURL_GZIP, because %s doesn't support it properly",
408
psResult->nStatus = 0;
414
psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
415
CPLError( CE_Failure, CPLE_AppDefined,
416
"%s", szCurlErrBuf );
421
/* HTTP errors do not trigger curl errors. But we need to */
422
/* propagate them to the caller though */
423
long response_code = 0;
424
curl_easy_getinfo(http_handle, CURLINFO_RESPONSE_CODE, &response_code);
425
if (response_code >= 400 && response_code < 600)
427
psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", (int)response_code));
428
CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
433
curl_easy_cleanup( http_handle );
214
435
curl_slist_free_all(headers);