std::string OAuth::createSignatureBaseString(HTTPRequest& r) { HTTPURL url = r.getURL(); std::string method = (r.getMethod() == HTTP_METHOD_POST) ? "POST" : "GET"; // Get the percent encoded parameters HTTPParameters collected_parameters = collectParameters(r); collected_parameters.percentEncode(); // We need to encode the parameter string (again) PercentEncode encoder; std::string parameter_string = collected_parameters.getQueryString(); std::string normalized_url = createNormalizedURL(r.getURL()); std::string signature_string = method +"&" +encoder.encode(normalized_url) +"&" +encoder.encode(parameter_string); return signature_string; }
ReadResult HTTPClient::doReadString(const HTTPRequest& request, const osgDB::Options* options, ProgressCallback* callback ) { initialize(); ReadResult result; HTTPResponse response = this->doGet( request, options, callback ); if ( response.isOK() ) { result = ReadResult( new StringObject(response.getPartAsString(0)) ); } else if ( response.getCode() >= 400 && response.getCode() < 500 && response.getCode() != 404 ) { // for request errors, return an error result with the part data intact // so the user can parse it as needed. We only do this for readString. result = ReadResult( ReadResult::RESULT_SERVER_ERROR, new StringObject(response.getPartAsString(0)) ); } else { result = ReadResult( response.isCancelled() ? ReadResult::RESULT_CANCELED : response.getCode() == HTTPResponse::NOT_FOUND ? ReadResult::RESULT_NOT_FOUND : response.getCode() == HTTPResponse::SERVER_ERROR ? ReadResult::RESULT_SERVER_ERROR : response.getCode() == HTTPResponse::NOT_MODIFIED ? ReadResult::RESULT_NOT_MODIFIED : ReadResult::RESULT_UNKNOWN_ERROR ); //If we have an error but it's recoverable, like a server error or timeout then set the callback to retry. if (HTTPClient::isRecoverable( result.code() ) ) { if (callback) { if ( s_HTTP_DEBUG ) { OE_NOTICE << LC << "Error in HTTPClient for " << request.getURL() << " but it's recoverable" << std::endl; } callback->setNeedsRetry( true ); } } } // encode headers result.setMetadata( response.getHeadersAsConfig() ); // last-modified (file time) result.setLastModifiedTime( getCurlFileTime(_curl_handle) ); return result; }
HTTPParameters OAuth::collectParameters(HTTPRequest& r) { setParameters(); HTTPParameters collected_parameters; HTTPParameters body_parameters = r.getContentParameters(); HTTPParameters querystring_parameters = r.getURL().getQueryParameters(); copyParametersForSignature(body_parameters, collected_parameters); copyParametersForSignature(querystring_parameters, collected_parameters); copyParametersForSignature(auth_params, collected_parameters); return collected_parameters; }
osg::Image* WCS11Source::createImage(const TileKey& key, ProgressCallback* progress) { HTTPRequest request = createRequest( key ); OE_INFO << "[osgEarth::WCS1.1] Key=" << key.str() << " URL = " << request.getURL() << std::endl; double lon0,lat0,lon1,lat1; key.getExtent().getBounds( lon0, lat0, lon1, lat1 ); // download the data. It's a multipart-mime stream, so we have to use HTTP directly. HTTPResponse response = HTTPClient::get( request, _dbOptions.get(), progress ); if ( !response.isOK() ) { OE_WARN << "[osgEarth::WCS1.1] WARNING: HTTP request failed" << std::endl; return NULL; } //TODO: Make WCS driver use progress callback unsigned int part_num = response.getNumParts() > 1? 1 : 0; std::istream& input_stream = response.getPartStream( part_num ); //TODO: un-hard-code TIFFs osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension( "tiff" ); if ( !reader ) { OE_NOTICE << "[osgEarth::WCS1.1] WARNING: no reader for \"tiff\"" << std::endl; return NULL; } osgDB::ReaderWriter::ReadResult result = reader->readImage( input_stream ); //, getOptions() ); if ( !result.success() ) { OE_NOTICE << "[osgEarth::WCS1.1] WARNING: readImage() failed for Reader " << reader->getName() << std::endl; return NULL; } osg::Image* image = result.getImage(); //OE_NOTICE << "Returned grid is " << image->s() << "x" << image->t() << std::endl; if ( image ) image->ref(); return image; }
osg::Image* WCS11Source::createImage(const TileKey& key, ProgressCallback* progress) { HTTPRequest request = createRequest( key ); double lon0,lat0,lon1,lat1; key.getExtent().getBounds( lon0, lat0, lon1, lat1 ); ReadResult out_response = URI(request.getURL()).readImage(_dbOptions.get(), progress); if (!out_response.failed()) { return out_response.releaseImage(); } else { OSG_INFO << LC << "Unable to create image: " << out_response.errorDetail() << ". Set OSGEARTH_HTTP_DEBUG=1 for details." << std::endl; return NULL; } }
HTTPResponse HTTPClient::doGet(const HTTPRequest& request, const osgDB::Options* options, ProgressCallback* progress) const { initialize(); OE_START_TIMER(http_get); const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ? options->getAuthenticationMap() : osgDB::Registry::instance()->getAuthenticationMap(); std::string proxy_host; std::string proxy_port = "8080"; std::string proxy_auth; //TODO: don't do all this proxy setup on every GET. Just do it once per client, or only when // the proxy information changes. //Try to get the proxy settings from the global settings if (s_proxySettings.isSet()) { proxy_host = s_proxySettings.get().hostName(); std::stringstream buf; buf << s_proxySettings.get().port(); proxy_port = buf.str(); std::string proxy_username = s_proxySettings.get().userName(); std::string proxy_password = s_proxySettings.get().password(); if (!proxy_username.empty() && !proxy_password.empty()) { proxy_auth = proxy_username + std::string(":") + proxy_password; } } //Try to get the proxy settings from the local options that are passed in. readOptions( options, proxy_host, proxy_port ); optional< ProxySettings > proxySettings; ProxySettings::fromOptions( options, proxySettings ); if (proxySettings.isSet()) { proxy_host = proxySettings.get().hostName(); proxy_port = toString<int>(proxySettings.get().port()); OE_DEBUG << LC << "Read proxy settings from options " << proxy_host << " " << proxy_port << std::endl; } //Try to get the proxy settings from the environment variable const char* proxyEnvAddress = getenv("OSG_CURL_PROXY"); if (proxyEnvAddress) //Env Proxy Settings { proxy_host = std::string(proxyEnvAddress); const char* proxyEnvPort = getenv("OSG_CURL_PROXYPORT"); //Searching Proxy Port on Env if (proxyEnvPort) { proxy_port = std::string( proxyEnvPort ); } } const char* proxyEnvAuth = getenv("OSGEARTH_CURL_PROXYAUTH"); if (proxyEnvAuth) { proxy_auth = std::string(proxyEnvAuth); } // Set up proxy server: std::string proxy_addr; if ( !proxy_host.empty() ) { std::stringstream buf; buf << proxy_host << ":" << proxy_port; std::string bufStr; bufStr = buf.str(); proxy_addr = bufStr; if ( s_HTTP_DEBUG ) { OE_NOTICE << LC << "Using proxy: " << proxy_addr << std::endl; } //curl_easy_setopt( _curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1 ); curl_easy_setopt( _curl_handle, CURLOPT_PROXY, proxy_addr.c_str() ); //Setup the proxy authentication if setup if (!proxy_auth.empty()) { if ( s_HTTP_DEBUG ) { OE_NOTICE << LC << "Using proxy authentication " << proxy_auth << std::endl; } curl_easy_setopt( _curl_handle, CURLOPT_PROXYUSERPWD, proxy_auth.c_str()); } } else { OE_DEBUG << LC << "Removing proxy settings" << std::endl; curl_easy_setopt( _curl_handle, CURLOPT_PROXY, 0 ); } std::string url = request.getURL(); // Rewrite the url if the url rewriter is available osg::ref_ptr< URLRewriter > rewriter = getURLRewriter(); if ( rewriter.valid() ) { std::string oldURL = url; url = rewriter->rewrite( oldURL ); OE_DEBUG << LC << "Rewrote URL " << oldURL << " to " << url << std::endl; } const osgDB::AuthenticationDetails* details = authenticationMap ? authenticationMap->getAuthenticationDetails( url ) : 0; if (details) { const std::string colon(":"); std::string password(details->username + colon + details->password); curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, password.c_str()); const_cast<HTTPClient*>(this)->_previousPassword = password; // use for https. // curl_easy_setopt(_curl, CURLOPT_KEYPASSWD, password.c_str()); #if LIBCURL_VERSION_NUM >= 0x070a07 if (details->httpAuthentication != _previousHttpAuthentication) { curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, details->httpAuthentication); const_cast<HTTPClient*>(this)->_previousHttpAuthentication = details->httpAuthentication; } #endif } else { if (!_previousPassword.empty()) { curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, 0); const_cast<HTTPClient*>(this)->_previousPassword.clear(); } #if LIBCURL_VERSION_NUM >= 0x070a07 // need to reset if previously set. if (_previousHttpAuthentication!=0) { curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, 0); const_cast<HTTPClient*>(this)->_previousHttpAuthentication = 0; } #endif } // Set any headers struct curl_slist *headers=NULL; if (!request.getHeaders().empty()) { for (HTTPRequest::Parameters::const_iterator itr = request.getHeaders().begin(); itr != request.getHeaders().end(); ++itr) { std::stringstream buf; buf << itr->first << ": " << itr->second; headers = curl_slist_append(headers, buf.str().c_str()); } } // Disable the default Pragma: no-cache that curl adds by default. headers = curl_slist_append(headers, "Pragma: "); curl_easy_setopt(_curl_handle, CURLOPT_HTTPHEADER, headers); osg::ref_ptr<HTTPResponse::Part> part = new HTTPResponse::Part(); StreamObject sp( &part->_stream ); //Take a temporary ref to the callback (why? dangerous.) //osg::ref_ptr<ProgressCallback> progressCallback = callback; curl_easy_setopt( _curl_handle, CURLOPT_URL, url.c_str() ); if (progress) { curl_easy_setopt(_curl_handle, CURLOPT_PROGRESSDATA, progress); } CURLcode res; long response_code = 0L; OE_START_TIMER(get_duration); if ( _simResponseCode < 0 ) { char errorBuf[CURL_ERROR_SIZE]; errorBuf[0] = 0; curl_easy_setopt( _curl_handle, CURLOPT_ERRORBUFFER, (void*)errorBuf ); curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)&sp); curl_easy_setopt( _curl_handle, CURLOPT_HEADERDATA, (void*)&sp); //Disable peer certificate verification to allow us to access in https servers where the peer certificate cannot be verified. curl_easy_setopt( _curl_handle, CURLOPT_SSL_VERIFYPEER, (void*)0 ); osg::ref_ptr< CurlConfigHandler > curlConfigHandler = getCurlConfigHandler(); if (curlConfigHandler.valid()) { curlConfigHandler->onGet(_curl_handle); } res = curl_easy_perform(_curl_handle); curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)0 ); curl_easy_setopt( _curl_handle, CURLOPT_PROGRESSDATA, (void*)0); if (!proxy_addr.empty()) { long connect_code = 0L; CURLcode r = curl_easy_getinfo(_curl_handle, CURLINFO_HTTP_CONNECTCODE, &connect_code); if ( r != CURLE_OK ) { OE_WARN << LC << "Proxy connect error: " << curl_easy_strerror(r) << std::endl; return HTTPResponse(0); } } curl_easy_getinfo( _curl_handle, CURLINFO_RESPONSE_CODE, &response_code ); } else { // simulate failure with a custom response code response_code = _simResponseCode; res = response_code == 408 ? CURLE_OPERATION_TIMEDOUT : CURLE_COULDNT_CONNECT; } HTTPResponse response( response_code ); // read the response content type: char* content_type_cp; curl_easy_getinfo( _curl_handle, CURLINFO_CONTENT_TYPE, &content_type_cp ); if ( content_type_cp != NULL ) { response._mimeType = content_type_cp; } // upon success, parse the data: if ( res != CURLE_ABORTED_BY_CALLBACK && res != CURLE_OPERATION_TIMEDOUT ) { // check for multipart content if (response._mimeType.length() > 9 && ::strstr( response._mimeType.c_str(), "multipart" ) == response._mimeType.c_str() ) { OE_DEBUG << LC << "detected multipart data; decoding..." << std::endl; //TODO: parse out the "wcs" -- this is WCS-specific if ( !decodeMultipartStream( "wcs", part.get(), response._parts ) ) { // error decoding an invalid multipart stream. // should we do anything, or just leave the response empty? } } else { for (Headers::iterator itr = sp._headers.begin(); itr != sp._headers.end(); ++itr) { part->_headers[itr->first] = itr->second; } // Write the headers to the metadata response._parts.push_back( part.get() ); } } else /*if (res == CURLE_ABORTED_BY_CALLBACK || res == CURLE_OPERATION_TIMEDOUT) */ { //If we were aborted by a callback, then it was cancelled by a user response._cancelled = true; } response._duration_s = OE_STOP_TIMER(get_duration); if ( progress ) { progress->stats()["http_get_time"] += OE_STOP_TIMER(http_get); progress->stats()["http_get_count"] += 1; if ( response._cancelled ) progress->stats()["http_cancel_count"] += 1; } if ( s_HTTP_DEBUG ) { TimeStamp filetime = getCurlFileTime(_curl_handle); OE_NOTICE << LC << "GET(" << response_code << ", " << response._mimeType << ") : \"" << url << "\" (" << DateTime(filetime).asRFC1123() << ") t=" << std::setprecision(4) << response.getDuration() << "s" << std::endl; { Threading::ScopedMutexLock lock(s_HTTP_DEBUG_mutex); s_HTTP_DEBUG_request_count++; s_HTTP_DEBUG_total_duration += response.getDuration(); if ( s_HTTP_DEBUG_request_count % 60 == 0 ) { OE_NOTICE << LC << "Average duration = " << s_HTTP_DEBUG_total_duration/(double)s_HTTP_DEBUG_request_count << std::endl; } } #if 0 // time details - almost 100% of the time is spent in // STARTTRANSFER, which is the time until the first byte is received. double td[7]; curl_easy_getinfo(_curl_handle, CURLINFO_TOTAL_TIME, &td[0]); curl_easy_getinfo(_curl_handle, CURLINFO_NAMELOOKUP_TIME, &td[1]); curl_easy_getinfo(_curl_handle, CURLINFO_CONNECT_TIME, &td[2]); curl_easy_getinfo(_curl_handle, CURLINFO_APPCONNECT_TIME, &td[3]); curl_easy_getinfo(_curl_handle, CURLINFO_PRETRANSFER_TIME, &td[4]); curl_easy_getinfo(_curl_handle, CURLINFO_STARTTRANSFER_TIME, &td[5]); curl_easy_getinfo(_curl_handle, CURLINFO_REDIRECT_TIME, &td[6]); for(int i=0; i<7; ++i) { OE_NOTICE << LC << std::setprecision(4) << "TIMES: total=" <<td[0] << ", lookup=" <<td[1]<<" ("<<(int)((td[1]/td[0])*100)<<"%)" << ", connect=" <<td[2]<<" ("<<(int)((td[2]/td[0])*100)<<"%)" << ", appconn=" <<td[3]<<" ("<<(int)((td[3]/td[0])*100)<<"%)" << ", prexfer=" <<td[4]<<" ("<<(int)((td[4]/td[0])*100)<<"%)" << ", startxfer=" <<td[5]<<" ("<<(int)((td[5]/td[0])*100)<<"%)" << ", redir=" <<td[6]<<" ("<<(int)((td[6]/td[0])*100)<<"%)" << std::endl; } #endif // Free the headers if (headers) { curl_slist_free_all(headers); } } return response; }
ReadResult HTTPClient::doReadObject(const HTTPRequest& request, const osgDB::Options* options, ProgressCallback* callback) { initialize(); ReadResult result; HTTPResponse response = this->doGet(request, options, callback); if (response.isOK()) { osgDB::ReaderWriter* reader = getReader(request.getURL(), response); if (!reader) { result = ReadResult(ReadResult::RESULT_NO_READER); } else { osgDB::ReaderWriter::ReadResult rr = reader->readObject(response.getPartStream(0), options); if ( rr.validObject() ) { result = ReadResult(rr.takeObject()); } else { if ( s_HTTP_DEBUG ) { OE_WARN << LC << reader->className() << " failed to read object from " << request.getURL() << "; message = " << rr.message() << std::endl; } result = ReadResult(ReadResult::RESULT_READER_ERROR); result.setErrorDetail( rr.message() ); } } // last-modified (file time) result.setLastModifiedTime( getCurlFileTime(_curl_handle) ); } else { result = ReadResult( response.isCancelled() ? ReadResult::RESULT_CANCELED : response.getCode() == HTTPResponse::NOT_FOUND ? ReadResult::RESULT_NOT_FOUND : response.getCode() == HTTPResponse::SERVER_ERROR ? ReadResult::RESULT_SERVER_ERROR : response.getCode() == HTTPResponse::NOT_MODIFIED ? ReadResult::RESULT_NOT_MODIFIED : ReadResult::RESULT_UNKNOWN_ERROR ); //If we have an error but it's recoverable, like a server error or timeout then set the callback to retry. if (HTTPClient::isRecoverable( result.code() ) ) { if (callback) { if ( s_HTTP_DEBUG ) { OE_NOTICE << LC << "Error in HTTPClient for " << request.getURL() << " but it's recoverable" << std::endl; } callback->setNeedsRetry( true ); } } } result.setMetadata( response.getHeadersAsConfig() ); return result; }
HTTPResponse HTTPClient::doGet( const HTTPRequest& request, const osgDB::Options* options, ProgressCallback* callback) const { initialize(); OE_TEST << LC << "doGet " << request.getURL() << std::endl; const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ? options->getAuthenticationMap() : osgDB::Registry::instance()->getAuthenticationMap(); std::string proxy_host; std::string proxy_port = "8080"; std::string proxy_auth; //TODO: don't do all this proxy setup on every GET. Just do it once per client, or only when // the proxy information changes. //Try to get the proxy settings from the global settings if (_proxySettings.isSet()) { proxy_host = _proxySettings.get().hostName(); std::stringstream buf; buf << _proxySettings.get().port(); proxy_port = buf.str(); std::string proxy_username = _proxySettings.get().userName(); std::string proxy_password = _proxySettings.get().password(); if (!proxy_username.empty() && !proxy_password.empty()) { proxy_auth = proxy_username + std::string(":") + proxy_password; } } //Try to get the proxy settings from the local options that are passed in. readOptions( options, proxy_host, proxy_port ); optional< ProxySettings > proxySettings; ProxySettings::fromOptions( options, proxySettings ); if (proxySettings.isSet()) { proxy_host = proxySettings.get().hostName(); proxy_port = toString<int>(proxySettings.get().port()); OE_DEBUG << "Read proxy settings from options " << proxy_host << " " << proxy_port << std::endl; } //Try to get the proxy settings from the environment variable const char* proxyEnvAddress = getenv("OSG_CURL_PROXY"); if (proxyEnvAddress) //Env Proxy Settings { proxy_host = std::string(proxyEnvAddress); const char* proxyEnvPort = getenv("OSG_CURL_PROXYPORT"); //Searching Proxy Port on Env if (proxyEnvPort) { proxy_port = std::string( proxyEnvPort ); } } const char* proxyEnvAuth = getenv("OSGEARTH_CURL_PROXYAUTH"); if (proxyEnvAuth) { proxy_auth = std::string(proxyEnvAuth); } // Set up proxy server: std::string proxy_addr; if ( !proxy_host.empty() ) { std::stringstream buf; buf << proxy_host << ":" << proxy_port; std::string bufStr; bufStr = buf.str(); proxy_addr = bufStr; OE_DEBUG << LC << "setting proxy: " << proxy_addr << std::endl; //curl_easy_setopt( _curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1 ); curl_easy_setopt( _curl_handle, CURLOPT_PROXY, proxy_addr.c_str() ); //Setup the proxy authentication if setup if (!proxy_auth.empty()) { OE_DEBUG << LC << "Setting up proxy authentication " << proxy_auth << std::endl; curl_easy_setopt( _curl_handle, CURLOPT_PROXYUSERPWD, proxy_auth.c_str()); } } else { OE_DEBUG << "Removing proxy settings" << std::endl; curl_easy_setopt( _curl_handle, CURLOPT_PROXY, 0 ); } const osgDB::AuthenticationDetails* details = authenticationMap ? authenticationMap->getAuthenticationDetails(request.getURL()) : 0; if (details) { const std::string colon(":"); std::string password(details->username + colon + details->password); curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, password.c_str()); const_cast<HTTPClient*>(this)->_previousPassword = password; // use for https. // curl_easy_setopt(_curl, CURLOPT_KEYPASSWD, password.c_str()); #if LIBCURL_VERSION_NUM >= 0x070a07 if (details->httpAuthentication != _previousHttpAuthentication) { curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, details->httpAuthentication); const_cast<HTTPClient*>(this)->_previousHttpAuthentication = details->httpAuthentication; } #endif } else { if (!_previousPassword.empty()) { curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, 0); const_cast<HTTPClient*>(this)->_previousPassword.clear(); } #if LIBCURL_VERSION_NUM >= 0x070a07 // need to reset if previously set. if (_previousHttpAuthentication!=0) { curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, 0); const_cast<HTTPClient*>(this)->_previousHttpAuthentication = 0; } #endif } osg::ref_ptr<HTTPResponse::Part> part = new HTTPResponse::Part(); StreamObject sp( &part->_stream ); //Take a temporary ref to the callback osg::ref_ptr<ProgressCallback> progressCallback = callback; curl_easy_setopt( _curl_handle, CURLOPT_URL, request.getURL().c_str() ); if (callback) { curl_easy_setopt(_curl_handle, CURLOPT_PROGRESSDATA, progressCallback.get()); } CURLcode res; long response_code = 0L; if ( _simResponseCode < 0 ) { char errorBuf[CURL_ERROR_SIZE]; errorBuf[0] = 0; curl_easy_setopt( _curl_handle, CURLOPT_ERRORBUFFER, (void*)errorBuf ); curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)&sp); res = curl_easy_perform( _curl_handle ); curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)0 ); curl_easy_setopt( _curl_handle, CURLOPT_PROGRESSDATA, (void*)0); //Disable peer certificate verification to allow us to access in https servers where the peer certificate cannot be verified. curl_easy_setopt( _curl_handle, CURLOPT_SSL_VERIFYPEER, (void*)0 ); if (!proxy_addr.empty()) { long connect_code = 0L; curl_easy_getinfo( _curl_handle, CURLINFO_HTTP_CONNECTCODE, &connect_code ); OE_DEBUG << LC << "proxy connect code " << connect_code << std::endl; } curl_easy_getinfo( _curl_handle, CURLINFO_RESPONSE_CODE, &response_code ); } else { // simulate failure with a custom response code response_code = _simResponseCode; res = response_code == 408 ? CURLE_OPERATION_TIMEDOUT : CURLE_COULDNT_CONNECT; } //OE_DEBUG << LC << "got response, code = " << response_code << std::endl; HTTPResponse response( response_code ); if ( response_code == 200L && res != CURLE_ABORTED_BY_CALLBACK && res != CURLE_OPERATION_TIMEDOUT ) //res == 0 ) { // check for multipart content: char* content_type_cp; curl_easy_getinfo( _curl_handle, CURLINFO_CONTENT_TYPE, &content_type_cp ); if ( content_type_cp == NULL ) { OE_NOTICE << LC << "NULL Content-Type (protocol violation) " << "URL=" << request.getURL() << std::endl; return NULL; } // NOTE: // WCS 1.1 specified a "multipart/mixed" response, but ArcGIS Server gives a "multipart/related" // content type ... std::string content_type( content_type_cp ); //OE_DEBUG << LC << "content-type = \"" << content_type << "\"" << std::endl; if ( content_type.length() > 9 && ::strstr( content_type.c_str(), "multipart" ) == content_type.c_str() ) //if ( content_type == "multipart/mixed; boundary=wcs" ) //todo: parse this. { OE_DEBUG << LC << "detected multipart data; decoding..." << std::endl; //TODO: parse out the "wcs" -- this is WCS-specific decodeMultipartStream( "wcs", part.get(), response._parts ); } else { // store headers that we care about part->_headers[IOMetadata::CONTENT_TYPE] = content_type; response._parts.push_back( part.get() ); } } else if (res == CURLE_ABORTED_BY_CALLBACK || res == CURLE_OPERATION_TIMEDOUT) { //If we were aborted by a callback, then it was cancelled by a user response._cancelled = true; } // Store the mime-type, if any. (Note: CURL manages the buffer returned by // this call.) char* ctbuf = NULL; if ( curl_easy_getinfo(_curl_handle, CURLINFO_CONTENT_TYPE, &ctbuf) == 0 && ctbuf ) { response._mimeType = ctbuf; } return response; }
HTTPResponse HTTPClient::doGet( const HTTPRequest& request, const osgDB::Options* options, ProgressCallback* callback) const { initialize(); const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ? options->getAuthenticationMap() : osgDB::Registry::instance()->getAuthenticationMap(); std::string proxy_host; std::string proxy_port = "8080"; std::string proxy_auth; //TODO: don't do all this proxy setup on every GET. Just do it once per client, or only when // the proxy information changes. //Try to get the proxy settings from the global settings if (s_proxySettings.isSet()) { proxy_host = s_proxySettings.get().hostName(); std::stringstream buf; buf << s_proxySettings.get().port(); proxy_port = buf.str(); std::string proxy_username = s_proxySettings.get().userName(); std::string proxy_password = s_proxySettings.get().password(); if (!proxy_username.empty() && !proxy_password.empty()) { proxy_auth = proxy_username + std::string(":") + proxy_password; } } //Try to get the proxy settings from the local options that are passed in. readOptions( options, proxy_host, proxy_port ); optional< ProxySettings > proxySettings; ProxySettings::fromOptions( options, proxySettings ); if (proxySettings.isSet()) { proxy_host = proxySettings.get().hostName(); proxy_port = toString<int>(proxySettings.get().port()); OE_DEBUG << "Read proxy settings from options " << proxy_host << " " << proxy_port << std::endl; } //Try to get the proxy settings from the environment variable const char* proxyEnvAddress = getenv("OSG_CURL_PROXY"); if (proxyEnvAddress) //Env Proxy Settings { proxy_host = std::string(proxyEnvAddress); const char* proxyEnvPort = getenv("OSG_CURL_PROXYPORT"); //Searching Proxy Port on Env if (proxyEnvPort) { proxy_port = std::string( proxyEnvPort ); } } const char* proxyEnvAuth = getenv("OSGEARTH_CURL_PROXYAUTH"); if (proxyEnvAuth) { proxy_auth = std::string(proxyEnvAuth); } // Set up proxy server: std::string proxy_addr; if ( !proxy_host.empty() ) { std::stringstream buf; buf << proxy_host << ":" << proxy_port; std::string bufStr; bufStr = buf.str(); proxy_addr = bufStr; if ( s_HTTP_DEBUG ) OE_NOTICE << LC << "Using proxy: " << proxy_addr << std::endl; //curl_easy_setopt( _curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1 ); curl_easy_setopt( _curl_handle, CURLOPT_PROXY, proxy_addr.c_str() ); //Setup the proxy authentication if setup if (!proxy_auth.empty()) { if ( s_HTTP_DEBUG ) OE_NOTICE << LC << "Using proxy authentication " << proxy_auth << std::endl; curl_easy_setopt( _curl_handle, CURLOPT_PROXYUSERPWD, proxy_auth.c_str()); } } else { OE_DEBUG << "Removing proxy settings" << std::endl; curl_easy_setopt( _curl_handle, CURLOPT_PROXY, 0 ); } std::string url = request.getURL(); // Rewrite the url if the url rewriter is available osg::ref_ptr< URLRewriter > rewriter = getURLRewriter(); if ( rewriter.valid() ) { std::string oldURL = url; url = rewriter->rewrite( oldURL ); OE_INFO << "Rewrote URL " << oldURL << " to " << url << std::endl; } const osgDB::AuthenticationDetails* details = authenticationMap ? authenticationMap->getAuthenticationDetails( url ) : 0; if (details) { const std::string colon(":"); std::string password(details->username + colon + details->password); curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, password.c_str()); const_cast<HTTPClient*>(this)->_previousPassword = password; // use for https. // curl_easy_setopt(_curl, CURLOPT_KEYPASSWD, password.c_str()); #if LIBCURL_VERSION_NUM >= 0x070a07 if (details->httpAuthentication != _previousHttpAuthentication) { curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, details->httpAuthentication); const_cast<HTTPClient*>(this)->_previousHttpAuthentication = details->httpAuthentication; } #endif } else { if (!_previousPassword.empty()) { curl_easy_setopt(_curl_handle, CURLOPT_USERPWD, 0); const_cast<HTTPClient*>(this)->_previousPassword.clear(); } #if LIBCURL_VERSION_NUM >= 0x070a07 // need to reset if previously set. if (_previousHttpAuthentication!=0) { curl_easy_setopt(_curl_handle, CURLOPT_HTTPAUTH, 0); const_cast<HTTPClient*>(this)->_previousHttpAuthentication = 0; } #endif } osg::ref_ptr<HTTPResponse::Part> part = new HTTPResponse::Part(); StreamObject sp( &part->_stream ); //Take a temporary ref to the callback osg::ref_ptr<ProgressCallback> progressCallback = callback; curl_easy_setopt( _curl_handle, CURLOPT_URL, url.c_str() ); if (callback) { curl_easy_setopt(_curl_handle, CURLOPT_PROGRESSDATA, progressCallback.get()); } CURLcode res; long response_code = 0L; if ( _simResponseCode < 0 ) { char errorBuf[CURL_ERROR_SIZE]; errorBuf[0] = 0; curl_easy_setopt( _curl_handle, CURLOPT_ERRORBUFFER, (void*)errorBuf ); curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)&sp); res = curl_easy_perform( _curl_handle ); curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA, (void*)0 ); curl_easy_setopt( _curl_handle, CURLOPT_PROGRESSDATA, (void*)0); //Disable peer certificate verification to allow us to access in https servers where the peer certificate cannot be verified. curl_easy_setopt( _curl_handle, CURLOPT_SSL_VERIFYPEER, (void*)0 ); if (!proxy_addr.empty()) { long connect_code = 0L; CURLcode r = curl_easy_getinfo(_curl_handle, CURLINFO_HTTP_CONNECTCODE, &connect_code); if ( r != CURLE_OK ) { OE_WARN << LC << "Proxy connect error: " << curl_easy_strerror(r) << std::endl; return HTTPResponse(0); } } curl_easy_getinfo( _curl_handle, CURLINFO_RESPONSE_CODE, &response_code ); } else { // simulate failure with a custom response code response_code = _simResponseCode; res = response_code == 408 ? CURLE_OPERATION_TIMEDOUT : CURLE_COULDNT_CONNECT; } HTTPResponse response( response_code ); // read the response content type: char* content_type_cp; curl_easy_getinfo( _curl_handle, CURLINFO_CONTENT_TYPE, &content_type_cp ); if ( content_type_cp != NULL ) { response._mimeType = content_type_cp; } if ( s_HTTP_DEBUG ) { TimeStamp filetime = 0; if (CURLE_OK != curl_easy_getinfo(_curl_handle, CURLINFO_FILETIME, &filetime)) filetime = 0; OE_NOTICE << LC << "GET(" << response_code << ", " << response._mimeType << ") : \"" << url << "\" (" << DateTime(filetime).asRFC1123() << ")"<< std::endl; } // upon success, parse the data: if ( res != CURLE_ABORTED_BY_CALLBACK && res != CURLE_OPERATION_TIMEDOUT ) { // check for multipart content if (response._mimeType.length() > 9 && ::strstr( response._mimeType.c_str(), "multipart" ) == response._mimeType.c_str() ) { OE_DEBUG << LC << "detected multipart data; decoding..." << std::endl; //TODO: parse out the "wcs" -- this is WCS-specific decodeMultipartStream( "wcs", part.get(), response._parts ); } else { // store headers that we care about part->_headers[IOMetadata::CONTENT_TYPE] = response._mimeType; response._parts.push_back( part.get() ); } } else /*if (res == CURLE_ABORTED_BY_CALLBACK || res == CURLE_OPERATION_TIMEDOUT) */ { //If we were aborted by a callback, then it was cancelled by a user response._cancelled = true; } return response; }