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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #8
0
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;
}
Exemple #9
0
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;
}