2
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
3
* Copyright 2008-2010 Pelican Mapping
6
* osgEarth is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>
20
#include <curl/curl.h>
21
#include <curl/types.h>
22
#include <osgEarth/HTTPClient>
23
#include <osgEarth/Registry>
24
#include <osgEarth/Version>
25
#include <osgDB/Registry>
26
#include <osgDB/FileNameUtils>
35
#define LC "[HTTPClient] "
38
#define OE_DEBUG OE_NULL
40
using namespace osgEarth;
42
//----------------------------------------------------------------------------
44
ProxySettings::ProxySettings( const Config& conf )
49
ProxySettings::ProxySettings( const std::string& host, int port ) :
57
ProxySettings::mergeConfig( const Config& conf )
59
_hostName = conf.value<std::string>( "host", "" );
60
_port = conf.value<int>( "port", 8080 );
61
_userName = conf.value<std::string>( "username", "" );
62
_password = conf.value<std::string>( "password", "" );
66
ProxySettings::getConfig() const
68
Config conf( "proxy" );
69
conf.add( "host", _hostName );
70
conf.add( "port", toString(_port) );
71
conf.add( "username", _userName);
72
conf.add( "password", _password);
77
/****************************************************************************/
83
StreamObject(std::ostream* stream) : _stream(stream) { }
85
void write(const char* ptr, size_t realsize)
87
if (_stream) _stream->write(ptr, realsize);
90
std::ostream* _stream;
91
std::string _resultMimeType;
95
StreamObjectReadCallback(void* ptr, size_t size, size_t nmemb, void* data)
97
size_t realsize = size* nmemb;
98
StreamObject* sp = (StreamObject*)data;
99
sp->write((const char*)ptr, realsize);
104
static int CurlProgressCallback(void *clientp,double dltotal,double dlnow,double ultotal,double ulnow)
106
ProgressCallback* callback = (ProgressCallback*)clientp;
107
bool cancelled = false;
110
cancelled = callback->isCanceled() || callback->reportProgress(dlnow, dltotal);
115
/****************************************************************************/
117
HTTPRequest::HTTPRequest( const std::string& url )
123
HTTPRequest::HTTPRequest( const HTTPRequest& rhs ) :
124
_parameters( rhs._parameters ),
131
HTTPRequest::addParameter( const std::string& name, const std::string& value )
133
_parameters[name] = value;
137
HTTPRequest::addParameter( const std::string& name, int value )
139
std::stringstream buf;
143
_parameters[name] = bufStr;
147
HTTPRequest::addParameter( const std::string& name, double value )
149
std::stringstream buf;
153
_parameters[name] = bufStr;
156
const HTTPRequest::Parameters&
157
HTTPRequest::getParameters() const
163
HTTPRequest::getURL() const
165
if ( _parameters.size() == 0 )
171
std::stringstream buf;
173
for( Parameters::const_iterator i = _parameters.begin(); i != _parameters.end(); i++ )
175
buf << ( i == _parameters.begin() && _url.find( "?" ) == std::string::npos? "?" : "&" );
176
buf << i->first << "=" << i->second;
184
/****************************************************************************/
186
HTTPResponse::HTTPResponse( long _code )
187
: _response_code( _code ),
193
HTTPResponse::HTTPResponse( const HTTPResponse& rhs ) :
194
_response_code( rhs._response_code ),
195
_parts( rhs._parts ),
196
_mimeType( rhs._mimeType ),
197
_cancelled( rhs._cancelled )
203
HTTPResponse::getCode() const {
204
return _response_code;
208
HTTPResponse::isOK() const {
209
return _response_code == 200L && !isCancelled();
213
HTTPResponse::isCancelled() const {
218
HTTPResponse::getNumParts() const {
219
return _parts.size();
223
HTTPResponse::getPartSize( unsigned int n ) const {
224
return _parts[n]->_size;
228
HTTPResponse::getPartHeader( unsigned int n, const std::string& name ) const {
229
return _parts[n]->_headers[name];
233
HTTPResponse::getPartStream( unsigned int n ) const {
234
return _parts[n]->_stream;
238
HTTPResponse::getPartAsString( unsigned int n ) const {
239
std::string streamStr;
240
streamStr = _parts[n]->_stream.str();
245
HTTPResponse::getMimeType() const {
249
/****************************************************************************/
252
#define QUOTE(X) QUOTE_(X)
253
#define USER_AGENT "osgearth" QUOTE(OSGEARTH_MAJOR_VERSION) "." QUOTE(OSGEARTH_MINOR_VERSION)
255
typedef std::map< OpenThreads::Thread*, osg::ref_ptr<HTTPClient> > ThreadClientMap;
256
static OpenThreads::Mutex _threadClientMapMutex;
257
static ThreadClientMap _threadClientMap;
258
static optional<ProxySettings> _proxySettings;
259
static std::string _userAgent = USER_AGENT;
261
HTTPClient& HTTPClient::getClient()
263
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadClientMapMutex);
264
static unsigned int numClients = 0;
265
osg::ref_ptr<HTTPClient>& client = _threadClientMap[OpenThreads::Thread::CurrentThread()];
268
client = new HTTPClient();
275
HTTPClient::HTTPClient()
277
_previousHttpAuthentication = 0;
278
_curl_handle = curl_easy_init();
282
std::string userAgent = _userAgent;
283
const char* userAgentEnv = getenv("OSGEARTH_USERAGENT");
286
userAgent = std::string(userAgentEnv);
289
OE_DEBUG << LC << "HTTPClient setting userAgent=" << userAgent << std::endl;
291
curl_easy_setopt( _curl_handle, CURLOPT_USERAGENT, userAgent.c_str() );
292
curl_easy_setopt( _curl_handle, CURLOPT_WRITEFUNCTION, osgEarth::StreamObjectReadCallback );
293
curl_easy_setopt( _curl_handle, CURLOPT_FOLLOWLOCATION, (void*)1 );
294
curl_easy_setopt( _curl_handle, CURLOPT_MAXREDIRS, (void*)5 );
295
curl_easy_setopt( _curl_handle, CURLOPT_PROGRESSFUNCTION, &CurlProgressCallback);
296
curl_easy_setopt( _curl_handle, CURLOPT_NOPROGRESS, (void*)0 ); //FALSE);
297
//curl_easy_setopt( _curl_handle, CURLOPT_TIMEOUT, 1L );
300
HTTPClient::~HTTPClient()
302
if (_curl_handle) curl_easy_cleanup( _curl_handle );
307
HTTPClient::setProxySettings( const ProxySettings &proxySettings )
309
_proxySettings = proxySettings;
312
const std::string& HTTPClient::getUserAgent()
317
void HTTPClient::setUserAgent(const std::string& userAgent)
319
_userAgent = userAgent;
323
HTTPClient::readOptions( const osgDB::ReaderWriter::Options* options, std::string& proxy_host, std::string& proxy_port) const
325
// try to set proxy host/port by reading the CURL proxy options
328
std::istringstream iss( options->getOptionString() );
332
int index = opt.find( "=" );
333
if( opt.substr( 0, index ) == "OSG_CURL_PROXY" )
335
proxy_host = opt.substr( index+1 );
337
else if ( opt.substr( 0, index ) == "OSG_CURL_PROXYPORT" )
339
proxy_port = opt.substr( index+1 );
345
// from: http://www.rosettacode.org/wiki/Tokenizing_A_String#C.2B.2B
346
static std::vector<std::string>
347
tokenize_str(const std::string & str, const std::string & delims=", \t")
350
// Skip delims at beginning, find start of first token
351
string::size_type lastPos = str.find_first_not_of(delims, 0);
352
// Find next delimiter @ end of token
353
string::size_type pos = str.find_first_of(delims, lastPos);
356
vector<string> tokens;
358
while (string::npos != pos || string::npos != lastPos)
360
// Found a token, add it to the vector.
361
tokens.push_back(str.substr(lastPos, pos - lastPos));
362
// Skip delims. Note the "not_of". this is beginning of token
363
lastPos = str.find_first_not_of(delims, pos);
364
// Find next delimiter at end of token.
365
pos = str.find_first_of(delims, lastPos);
373
HTTPClient::decodeMultipartStream(const std::string& boundary,
374
HTTPResponse::Part* input,
375
HTTPResponse::Parts& output) const
377
std::string bstr = std::string("--") + boundary;
381
// first thing in the stream should be the boundary.
382
input->_stream.read( tempbuf, bstr.length() );
383
tempbuf[bstr.length()] = 0;
388
<< "decodeMultipartStream: protocol violation; "
389
<< "expecting boundary; instead got: \""
391
<< "\"" << std::endl;
395
for( bool done=false; !done; )
397
osg::ref_ptr<HTTPResponse::Part> next_part = new HTTPResponse::Part();
399
// first finish off the boundary.
400
std::getline( input->_stream, line );
407
// read all headers. this ends with a blank line.
409
while( line.length() > 0 && !done )
411
std::getline( input->_stream, line );
420
std::vector<std::string> tized = tokenize_str( line, ":" );
421
if ( tized.size() >= 2 )
422
next_part->_headers[tized[0]] = tized[1];
429
// read data until we reach the boundary
430
unsigned int bstr_ptr = 0;
432
//unsigned int c = 0;
433
while( bstr_ptr < bstr.length() )
436
input->_stream.read( &b, 1 );
437
if ( b == bstr[bstr_ptr] )
443
for( unsigned int i=0; i<bstr_ptr; i++ )
445
next_part->_stream << bstr[i];
447
next_part->_stream << b;
448
next_part->_size += bstr_ptr + 1;
452
output.push_back( next_part.get() );
458
HTTPClient::get( const HTTPRequest& request,
459
const osgDB::ReaderWriter::Options* options,
460
ProgressCallback* callback)
462
return getClient().doGet( request, options, callback );
466
HTTPClient::get( const std::string &url,
467
const osgDB::ReaderWriter::Options* options,
468
ProgressCallback* callback)
470
return getClient().doGet( url, options, callback);
473
HTTPClient::ResultCode
474
HTTPClient::readImageFile(const std::string &filename,
475
osg::ref_ptr<osg::Image>& output,
476
const osgDB::ReaderWriter::Options *options,
477
osgEarth::ProgressCallback *callback)
479
return getClient().doReadImageFile( filename, output, options, callback );
482
HTTPClient::ResultCode
483
HTTPClient::readNodeFile(const std::string& filename,
484
osg::ref_ptr<osg::Node>& output,
485
const osgDB::ReaderWriter::Options *options,
486
osgEarth::ProgressCallback *callback)
488
return getClient().doReadNodeFile( filename, output, options, callback );
491
HTTPClient::ResultCode
492
HTTPClient::readString(const std::string& filename,
494
osgEarth::ProgressCallback* callback)
496
return getClient().doReadString( filename, output, callback );
500
HTTPClient::doGet( const HTTPRequest& request, const osgDB::ReaderWriter::Options* options, ProgressCallback* callback) const
502
OE_DEBUG << LC << "doGet " << request.getURL() << std::endl;
504
const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ?
505
options->getAuthenticationMap() :
506
osgDB::Registry::instance()->getAuthenticationMap();
508
std::string proxy_host;
509
std::string proxy_port = "8080";
511
std::string proxy_auth;
513
//Try to get the proxy settings from the global settings
514
if (_proxySettings.isSet())
516
proxy_host = _proxySettings.get().hostName();
517
std::stringstream buf;
518
buf << _proxySettings.get().port();
519
proxy_port = buf.str();
521
std::string proxy_username = _proxySettings.get().userName();
522
std::string proxy_password = _proxySettings.get().password();
523
if (!proxy_username.empty() && !proxy_password.empty())
525
proxy_auth = proxy_username + ":" + proxy_password;
529
//Try to get the proxy settings from the local options that are passed in.
530
readOptions( options, proxy_host, proxy_port );
532
//Try to get the proxy settings from the environment variable
533
const char* proxyEnvAddress = getenv("OSG_CURL_PROXY");
534
if (proxyEnvAddress) //Env Proxy Settings
536
proxy_host = std::string(proxyEnvAddress);
538
const char* proxyEnvPort = getenv("OSG_CURL_PROXYPORT"); //Searching Proxy Port on Env
541
proxy_port = std::string( proxyEnvPort );
545
const char* proxyEnvAuth = getenv("OSGEARTH_CURL_PROXYAUTH");
548
proxy_auth = std::string(proxyEnvAuth);
551
// Set up proxy server:
552
std::string proxy_addr;
553
if ( !proxy_host.empty() )
555
std::stringstream buf;
556
buf << proxy_host << ":" << proxy_port;
561
OE_DEBUG << LC << "setting proxy: " << proxy_addr << std::endl;
562
//curl_easy_setopt( _curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1 );
563
curl_easy_setopt( _curl_handle, CURLOPT_PROXY, proxy_addr.c_str() );
565
//Setup the proxy authentication if setup
566
if (!proxy_auth.empty())
568
OE_DEBUG << LC << "Setting up proxy authentication " << proxy_auth << std::endl;
569
curl_easy_setopt( _curl_handle, CURLOPT_PROXYUSERPWD, proxy_auth.c_str());
573
const osgDB::AuthenticationDetails* details = authenticationMap ?
574
authenticationMap->getAuthenticationDetails(request.getURL()) :
579
const std::string colon(":");
580
std::string password(details->username + colon + details->password);
581
curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, password.c_str());
582
const_cast<HTTPClient*>(this)->_previousPassword = password;
585
// curl_easy_setopt(_curl, CURLOPT_KEYPASSWD, password.c_str());
587
#if LIBCURL_VERSION_NUM >= 0x070a07
588
if (details->httpAuthentication != _previousHttpAuthentication)
590
curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, details->httpAuthentication);
591
const_cast<HTTPClient*>(this)->_previousHttpAuthentication = details->httpAuthentication;
597
if (!_previousPassword.empty())
599
curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, 0);
600
const_cast<HTTPClient*>(this)->_previousPassword.clear();
603
#if LIBCURL_VERSION_NUM >= 0x070a07
604
// need to reset if previously set.
605
if (_previousHttpAuthentication!=0)
607
curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, 0);
608
const_cast<HTTPClient*>(this)->_previousHttpAuthentication = 0;
613
osg::ref_ptr<HTTPResponse::Part> part = new HTTPResponse::Part();
614
StreamObject sp( &part->_stream );
616
//Take a temporary ref to the callback
617
osg::ref_ptr<ProgressCallback> progressCallback = callback;
618
curl_easy_setopt( _curl_handle, CURLOPT_URL, request.getURL().c_str() );
621
curl_easy_setopt(_curl_handle, CURLOPT_PROGRESSDATA, progressCallback.get());
624
char errorBuf[CURL_ERROR_SIZE];
626
curl_easy_setopt( _curl_handle, CURLOPT_ERRORBUFFER, (void*)errorBuf );
628
curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)&sp);
629
CURLcode res = curl_easy_perform( _curl_handle );
630
curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)0 );
631
curl_easy_setopt( _curl_handle, CURLOPT_PROGRESSDATA, (void*)0);
633
long response_code = 0L;
634
if (!proxy_addr.empty())
636
long connect_code = 0L;
637
curl_easy_getinfo( _curl_handle, CURLINFO_HTTP_CONNECTCODE, &connect_code );
638
OE_DEBUG << LC << "proxy connect code " << connect_code << std::endl;
641
curl_easy_getinfo( _curl_handle, CURLINFO_RESPONSE_CODE, &response_code );
643
OE_DEBUG << LC << "got response, code = " << response_code << std::endl;
645
HTTPResponse response( response_code );
647
if ( response_code == 200L && res != CURLE_ABORTED_BY_CALLBACK && res != CURLE_OPERATION_TIMEDOUT ) //res == 0 )
649
// check for multipart content:
650
char* content_type_cp;
651
curl_easy_getinfo( _curl_handle, CURLINFO_CONTENT_TYPE, &content_type_cp );
652
if ( content_type_cp == NULL )
655
<< "NULL Content-Type (protocol violation) "
656
<< "URL=" << request.getURL() << std::endl;
661
// WCS 1.1 specified a "multipart/mixed" response, but ArcGIS Server gives a "multipart/related"
664
std::string content_type( content_type_cp );
665
//OE_NOTICE << "[osgEarth.HTTPClient] content-type = \"" << content_type << "\"" << std::endl;
666
if ( content_type.length() > 9 && ::strstr( content_type.c_str(), "multipart" ) == content_type.c_str() )
667
//if ( content_type == "multipart/mixed; boundary=wcs" ) //todo: parse this.
669
//OE_NOTICE << "[osgEarth.HTTPClient] detected multipart data; decoding..." << std::endl;
670
//TODO: parse out the "wcs" -- this is WCS-specific
671
decodeMultipartStream( "wcs", part.get(), response._parts );
675
//OE_NOTICE << "[osgEarth.HTTPClient] detected single part data" << std::endl;
676
response._parts.push_back( part.get() );
679
else if (res == CURLE_ABORTED_BY_CALLBACK || res == CURLE_OPERATION_TIMEDOUT)
681
//If we were aborted by a callback, then it was cancelled by a user
682
response._cancelled = true;
688
// if ( errorBuf[0] ) {
689
// callback->message() = errorBuf;
692
// std::stringstream buf;
693
// buf << "HTTP Code " << response.getCode();
694
// callback->message() = buf.str();
698
// OE_NOTICE << "[osgEarth] [HTTP] error, code = " << code << std::endl;
702
// Store the mime-type, if any. (Note: CURL manages the buffer returned by
705
if ( curl_easy_getinfo(_curl_handle, CURLINFO_CONTENT_TYPE, &ctbuf) == 0 && ctbuf )
707
response._mimeType = ctbuf;
715
HTTPClient::doGet( const std::string& url, const osgDB::ReaderWriter::Options* options, ProgressCallback* callback) const
717
return doGet( HTTPRequest( url ), options, callback );
721
HTTPClient::downloadFile(const std::string &url, const std::string &filename)
724
HTTPResponse response = this->doGet( HTTPRequest(url) );
726
if ( response.isOK() )
728
unsigned int part_num = response.getNumParts() > 1? 1 : 0;
729
std::istream& input_stream = response.getPartStream( part_num );
732
fout.open(filename.c_str(), std::ios::out | std::ios::binary);
734
input_stream.seekg (0, std::ios::end);
735
int length = input_stream.tellg();
736
input_stream.seekg (0, std::ios::beg);
738
char *buffer = new char[length];
739
input_stream.read(buffer, length);
740
fout.write(buffer, length);
747
OE_WARN << LC << "Error downloading file " << filename << std::endl;
752
HTTPClient::ResultCode
753
HTTPClient::doReadImageFile(const std::string& filename,
754
osg::ref_ptr<osg::Image>& output,
755
const osgDB::ReaderWriter::Options *options,
756
osgEarth::ProgressCallback *callback)
758
ResultCode result = RESULT_OK;
760
if ( osgDB::containsServerAddress( filename ) )
762
HTTPResponse response = this->doGet(filename, options, callback);
766
osgDB::ReaderWriter* reader = 0L;
768
// try to look up a reader by mime-type first:
769
std::string mimeType = response.getMimeType();
770
OE_DEBUG << LC << "Looking up extension for mime-type " << mimeType << std::endl;
771
if ( !mimeType.empty() )
773
reader = osgEarth::Registry::instance()->getReaderWriterForMimeType(mimeType);
778
// Try to find a reader by file extension. If this fails, we will fetch the file
779
// anyway and try to get a reader via mime-type.
780
std::string ext = osgDB::getFileExtension( filename );
781
reader = osgDB::Registry::instance()->getReaderWriterForExtension( ext );
782
//OE_NOTICE << "Reading " << filename << " with mime " << response.getMimeType() << std::endl;
787
OE_WARN << LC << "Can't find an OSG plugin to read "<<filename<<std::endl;
788
result = RESULT_NO_READER;
793
osgDB::ReaderWriter::ReadResult rr = reader->readImage(response.getPartStream(0), options);
794
if ( rr.validImage() )
796
output = rr.takeImage();
800
if ( !rr.message().empty() )
802
OE_WARN << LC << "HTTP error: " << rr.message() << std::endl;
804
OE_WARN << LC << reader->className() << " failed to read image from " << filename << std::endl;
805
result = RESULT_READER_ERROR;
812
response.isCancelled() ? RESULT_CANCELED :
813
response.getCode() == HTTPResponse::NOT_FOUND ? RESULT_NOT_FOUND :
814
response.getCode() == HTTPResponse::SERVER_ERROR ? RESULT_SERVER_ERROR :
815
RESULT_UNKNOWN_ERROR;
817
//If we have an error but it's recoverable, like a server error or timeout then set the callback to retry.
818
if (HTTPClient::isRecoverable( result ) )
822
OE_DEBUG << "Error in HTTPClient for " << filename << " but it's recoverable" << std::endl;
823
callback->setNeedsRetry( true );
827
//if ( response.isCancelled() )
828
// OE_NOTICE << "HTTP cancel: " << filename << std::endl;
830
// OE_NOTICE << "HTTP ERROR " << response.getCode() << ": " << filename << std::endl;
832
/*if (response.isCancelled())
833
OE_NOTICE << "Request for " << filename << " was cancelled " << std::endl;*/
838
output = osgDB::readImageFile( filename, options );
839
if ( !output.valid() )
840
result = RESULT_NOT_FOUND;
846
HTTPClient::ResultCode
847
HTTPClient::doReadNodeFile(const std::string& filename,
848
osg::ref_ptr<osg::Node>& output,
849
const osgDB::ReaderWriter::Options *options,
850
osgEarth::ProgressCallback *callback)
852
ResultCode result = RESULT_OK;
854
if ( osgDB::containsServerAddress( filename ) )
856
HTTPResponse response = this->doGet(filename, options, callback);
859
// Try to find a reader by file extension. If this fails, we will fetch the file
860
// anyway and try to get a reader via mime-type.
861
std::string ext = osgDB::getFileExtension( filename );
862
osgDB::ReaderWriter *reader =
863
osgDB::Registry::instance()->getReaderWriterForExtension( ext );
865
//If we didn't get a reader by extension, try to get it via mime type
868
std::string mimeType = response.getMimeType();
869
OE_DEBUG << LC << "Looking up extension for mime-type " << mimeType << std::endl;
870
if ( mimeType.length() > 0 )
872
reader = osgEarth::Registry::instance()->getReaderWriterForMimeType(mimeType);
876
// if we still didn't get it, bad news
879
OE_NOTICE<<LC<<"Error: No ReaderWriter for file "<<filename<<std::endl;
880
result = RESULT_NO_READER;
885
osgDB::ReaderWriter::ReadResult rr = reader->readNode(response.getPartStream(0), options);
886
if ( rr.validNode() )
888
output = rr.takeNode();
894
OE_WARN << LC << "HTTP Reader Error: " << rr.message() << std::endl;
896
result = RESULT_READER_ERROR;
903
response.isCancelled() ? RESULT_CANCELED :
904
response.getCode() == HTTPResponse::NOT_FOUND ? RESULT_NOT_FOUND :
905
response.getCode() == HTTPResponse::SERVER_ERROR ? RESULT_SERVER_ERROR :
906
RESULT_UNKNOWN_ERROR;
908
//If we have an error but it's recoverable, like a server error or timeout then set the callback to retry.
909
if (HTTPClient::isRecoverable( result ) )
913
OE_DEBUG << "Error in HTTPClient for " << filename << " but it's recoverable" << std::endl;
914
callback->setNeedsRetry( true );
918
/*if (response.isCancelled())
919
OE_NOTICE << "Request for " << filename << " was cancelled " << std::endl;*/
924
output = osgDB::readNodeFile( filename, options );
925
if ( !output.valid() )
926
result = RESULT_NOT_FOUND;
933
HTTPClient::ResultCode
934
HTTPClient::doReadString(const std::string& filename,
936
osgEarth::ProgressCallback* callback )
938
ResultCode result = RESULT_OK;
940
if ( osgDB::containsServerAddress( filename ) )
942
HTTPResponse response = this->doGet( filename, NULL, callback );
943
if ( response.isOK() )
945
output = response.getPartAsString( 0 );
950
response.isCancelled() ? RESULT_CANCELED :
951
response.getCode() == HTTPResponse::NOT_FOUND ? RESULT_NOT_FOUND :
952
response.getCode() == HTTPResponse::SERVER_ERROR ? RESULT_SERVER_ERROR :
953
RESULT_UNKNOWN_ERROR;
955
//If we have an error but it's recoverable, like a server error or timeout then set the callback to retry.
956
if (HTTPClient::isRecoverable( result ) )
960
OE_DEBUG << "Error in HTTPClient for " << filename << " but it's recoverable" << std::endl;
961
callback->setNeedsRetry( true );
968
std::ifstream input( filename.c_str() );
969
if ( input.is_open() )
971
input >> std::noskipws;
972
std::stringstream buf;
973
buf << input.rdbuf();
980
result = RESULT_NOT_FOUND;