453 lines
14 KiB
C++
453 lines
14 KiB
C++
/* -*-c++-*- */
|
|
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
* Copyright 2020 Pelican Mapping
|
|
* http://osgearth.org
|
|
*
|
|
* osgEarth is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
*/
|
|
#ifndef OSGEARTH_HTTP_CLIENT_H
|
|
#define OSGEARTH_HTTP_CLIENT_H 1
|
|
|
|
#include <osgEarth/Common>
|
|
#include <osgEarth/IOTypes>
|
|
#include <osg/ref_ptr>
|
|
#include <osg/Referenced>
|
|
#include <osgDB/ReaderWriter>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
namespace osgEarth
|
|
{
|
|
class ProgressCallback;
|
|
}
|
|
|
|
namespace osgEarth { namespace Util
|
|
{
|
|
using namespace osgEarth;
|
|
|
|
/**
|
|
* An HTTP request for use with the HTTPClient class.
|
|
*/
|
|
class OSGEARTH_EXPORT HTTPRequest
|
|
{
|
|
public:
|
|
/** Constructs a new HTTP request that will acces the specified base URL. */
|
|
HTTPRequest( const std::string& url );
|
|
|
|
/** copy constructor. */
|
|
HTTPRequest( const HTTPRequest& rhs );
|
|
|
|
/** dtor */
|
|
virtual ~HTTPRequest() { }
|
|
|
|
/** Adds an HTTP parameter to the request query string. */
|
|
void addParameter( const std::string& name, const std::string& value );
|
|
void addParameter( const std::string& name, int value );
|
|
void addParameter( const std::string& name, double value );
|
|
|
|
using Parameters = std::unordered_map<std::string, std::string>;
|
|
|
|
/** Ready-only access to the parameter list (as built with addParameter) */
|
|
const Parameters& getParameters() const;
|
|
|
|
//! Add a header name/value pair to an HTTP request
|
|
void addHeader( const std::string& name, const std::string& value );
|
|
|
|
//! Collection of headers in this request
|
|
const Headers& getHeaders() const;
|
|
|
|
//! Collection of headers in this request
|
|
Headers& getHeaders();
|
|
|
|
/**
|
|
* Sets the last modified date of any locally cached data for this request. This will
|
|
* automatically add a If-Modified-Since header to the request
|
|
*/
|
|
void setLastModified( const DateTime &lastModified );
|
|
|
|
/** Gets a copy of the complete URL (base URL + query string) for this request */
|
|
std::string getURL() const;
|
|
|
|
private:
|
|
Parameters _parameters;
|
|
Headers _headers;
|
|
std::string _url;
|
|
};
|
|
|
|
/**
|
|
* An HTTP response object for use with the HTTPClient class - supports
|
|
* multi-part mime responses.
|
|
*/
|
|
class OSGEARTH_EXPORT HTTPResponse
|
|
{
|
|
public:
|
|
enum Code {
|
|
NONE = 0,
|
|
OK = 200,
|
|
NOT_MODIFIED = 304,
|
|
BAD_REQUEST = 400,
|
|
FORBIDDEN = 403,
|
|
NOT_FOUND = 404,
|
|
CONFLICT = 409,
|
|
INTERNAL_SERVER_ERROR = 500
|
|
};
|
|
enum CodeCategory {
|
|
CATEGORY_UNKNOWN = 0,
|
|
CATEGORY_INFORMATIONAL = 100,
|
|
CATEGORY_SUCCESS = 200,
|
|
CATEGORY_REDIRECTION = 300,
|
|
CATEGORY_CLIENT_ERROR = 400,
|
|
CATEGORY_SERVER_ERROR = 500
|
|
};
|
|
|
|
public:
|
|
/** Constructs a response with the specified HTTP response code */
|
|
HTTPResponse( long code =0L );
|
|
|
|
/** Copy constructor */
|
|
HTTPResponse( const HTTPResponse& rhs );
|
|
|
|
/** dtor */
|
|
virtual ~HTTPResponse() { }
|
|
|
|
/** Gets the HTTP response code (Code) in this response */
|
|
unsigned getCode() const;
|
|
|
|
/** Gets the HTTP response code category for this response */
|
|
unsigned getCodeCategory() const;
|
|
|
|
/** True is the HTTP response code is OK (200) */
|
|
bool isOK() const;
|
|
|
|
/** True if the request associated with this response was cancelled before it completed */
|
|
void setCanceled(bool value) { _canceled = value; }
|
|
bool isCanceled() const { return _canceled; }
|
|
|
|
/** Gets the number of parts in a (possibly multipart mime) response */
|
|
unsigned int getNumParts() const;
|
|
|
|
/** Gets the input stream for the nth part in the response */
|
|
std::istream& getPartStream( unsigned int n ) const;
|
|
|
|
/** Gets the nth response part as a string */
|
|
std::string getPartAsString( unsigned int n ) const;
|
|
|
|
/** Gets the length of the nth response part */
|
|
unsigned int getPartSize( unsigned int n ) const;
|
|
|
|
/** Gets the HTTP header associated with the nth multipart/mime response part */
|
|
const std::string& getPartHeader( unsigned int n, const std::string& name ) const;
|
|
|
|
/** Gets the master mime-type returned by the request */
|
|
void setMimeType(const std::string& value) { _mimeType = value; }
|
|
const std::string& getMimeType() const;
|
|
|
|
/** How long did it take to fetch this response (in seconds) */
|
|
void setDuration(double value) { _duration_s = value; }
|
|
double getDuration() const { return _duration_s; }
|
|
|
|
void setMessage(const std::string& value) { _message = value; }
|
|
const std::string& getMessage() const { return _message; }
|
|
|
|
void setLastModified(TimeStamp value) { _lastModified = value; }
|
|
TimeStamp getLastModified() const { return _lastModified; }
|
|
|
|
bool getFromCache() const { return _fromCache; }
|
|
void setFromCache(bool fromCache) { _fromCache = fromCache; }
|
|
|
|
struct Part : public osg::Referenced
|
|
{
|
|
Part() : _size(0) { }
|
|
Headers _headers;
|
|
unsigned int _size;
|
|
std::stringstream _stream;
|
|
};
|
|
typedef std::vector< osg::ref_ptr<Part> > Parts;
|
|
|
|
Parts& getParts() { return _parts; }
|
|
|
|
private:
|
|
Parts _parts;
|
|
long _response_code;
|
|
std::string _mimeType;
|
|
bool _canceled;
|
|
double _duration_s;
|
|
TimeStamp _lastModified;
|
|
std::string _message;
|
|
bool _fromCache;
|
|
|
|
Config getHeadersAsConfig() const;
|
|
void setHeadersFromConfig(const Config& conf);
|
|
|
|
friend class HTTPClient;
|
|
};
|
|
|
|
/**
|
|
* Object that lets you modify and incoming URL before it's passed to the server
|
|
*/
|
|
struct OSGEARTH_EXPORT URLRewriter : public osg::Referenced
|
|
{
|
|
virtual std::string rewrite( const std::string& url ) = 0;
|
|
};
|
|
|
|
/**
|
|
* A configuration handler to apply settings. It can be used for setting client certificates
|
|
*/
|
|
struct OSGEARTH_EXPORT ConfigHandler : public osg::Referenced
|
|
{
|
|
virtual void onInitialize(void* handle) = 0;
|
|
virtual void onGet(void* handle) = 0;
|
|
};
|
|
|
|
/**
|
|
* Utility class for making HTTP requests.
|
|
*/
|
|
class OSGEARTH_EXPORT HTTPClient
|
|
{
|
|
public:
|
|
//! Interface for pluggable HTTP implementations
|
|
class Implementation : public osg::Referenced
|
|
{
|
|
public:
|
|
virtual void initialize() = 0;
|
|
|
|
virtual HTTPResponse doGet(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* options,
|
|
ProgressCallback* progress ) const = 0;
|
|
|
|
virtual void setUserAgent(const std::string&) { }
|
|
|
|
virtual void setTimeout(long) { }
|
|
|
|
virtual void setConnectTimeout(long) { }
|
|
|
|
//! Implementation-specific handle if applicable
|
|
virtual void* getHandle() const { return NULL; }
|
|
|
|
protected:
|
|
virtual ~Implementation() {}
|
|
};
|
|
|
|
//! Factory object to create implementation instances.
|
|
class ImplementationFactory
|
|
{
|
|
public:
|
|
virtual Implementation* create() const = 0;
|
|
|
|
virtual ~ImplementationFactory() {};
|
|
};
|
|
|
|
//! Install an implementation factory. Do this before anything else
|
|
static void setImplementationFactory(ImplementationFactory* factory);
|
|
|
|
/**
|
|
* Returns true is the result code represents a recoverable situation,
|
|
* i.e. one in which retrying might work.
|
|
*/
|
|
static bool isRecoverable(ReadResult::Code code)
|
|
{
|
|
return
|
|
code == ReadResult::RESULT_OK ||
|
|
code == ReadResult::RESULT_SERVER_ERROR ||
|
|
code == ReadResult::RESULT_TIMEOUT ||
|
|
code == ReadResult::RESULT_CANCELED;
|
|
}
|
|
|
|
/** Gets the user-agent string that all HTTP requests will use. */
|
|
static const std::string& getUserAgent();
|
|
|
|
/** Sets a user-agent string to use in all HTTP requests. */
|
|
static void setUserAgent(const std::string& userAgent);
|
|
|
|
/** Sets up proxy info to use in all HTTP requests. */
|
|
static void setProxySettings( const optional<ProxySettings> &proxySettings );
|
|
|
|
/** Gets up proxy info to use in all HTTP requests. */
|
|
static const optional<ProxySettings> & getProxySettings();
|
|
|
|
/**
|
|
Gets the timeout in seconds to use for HTTP requests.*/
|
|
static long getTimeout();
|
|
|
|
/**
|
|
Sets the timeout in seconds to use for HTTP requests.
|
|
Setting to 0 (default) is infinite timeout */
|
|
static void setTimeout( long timeout );
|
|
|
|
/** Sets the suggested delay (in seconds) before a retry should be attempted
|
|
in the case of a canceled request */
|
|
static void setRetryDelay(float value_seconds);
|
|
static float getRetryDelay();
|
|
|
|
/**
|
|
Gets the timeout in seconds to use for HTTP connect requests.*/
|
|
static long getConnectTimeout();
|
|
|
|
/**
|
|
Sets the timeout in seconds to use for HTTP connect requests.
|
|
Setting to 0 (default) is infinite timeout */
|
|
static void setConnectTimeout( long timeout );
|
|
|
|
/**
|
|
* Gets the URLRewriter that is used to modify urls before sending them to the server
|
|
*/
|
|
static URLRewriter* getURLRewriter();
|
|
|
|
/**
|
|
* Sets the URLRewriter that is used to modify urls before sending them to the server
|
|
*/
|
|
static void setURLRewriter( URLRewriter* rewriter );
|
|
|
|
static ConfigHandler* getConfigHandler();
|
|
|
|
/**
|
|
* Sets the CurlConfigHandler to configurate the CURL library. It can be used for apply client certificates
|
|
*/
|
|
static void setConfigHandler(ConfigHandler* handler);
|
|
|
|
/**
|
|
* One time thread safe initialization. In osgEarth, you don't need
|
|
* to call this directly; osgEarth::Registry will call it at
|
|
* startup.
|
|
*/
|
|
static void globalInit();
|
|
|
|
|
|
public:
|
|
/**
|
|
* Reads an image.
|
|
*/
|
|
static ReadResult readImage(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions =0L,
|
|
ProgressCallback* progress =0L );
|
|
|
|
/**
|
|
* Reads an osg::Node.
|
|
*/
|
|
static ReadResult readNode(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions =0L,
|
|
ProgressCallback* progress =0L );
|
|
|
|
/**
|
|
* Reads an object.
|
|
*/
|
|
static ReadResult readObject(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions =0L,
|
|
ProgressCallback* progress =0L );
|
|
|
|
/**
|
|
* Reads a string.
|
|
*/
|
|
static ReadResult readString(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions =0L,
|
|
ProgressCallback* progress =0L );
|
|
|
|
/**
|
|
* Downloads a file directly to disk.
|
|
*/
|
|
static bool download(
|
|
const std::string& uri,
|
|
const std::string& localPath );
|
|
|
|
public:
|
|
|
|
/**
|
|
* Performs an HTTP "GET".
|
|
*/
|
|
static HTTPResponse get( const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions =0L,
|
|
ProgressCallback* progress =0L );
|
|
|
|
static HTTPResponse get( const std::string& url,
|
|
const osgDB::Options* options =0L,
|
|
ProgressCallback* progress =0L );
|
|
|
|
public:
|
|
HTTPClient();
|
|
virtual ~HTTPClient();
|
|
|
|
private:
|
|
|
|
void readOptions( const osgDB::ReaderWriter::Options* options, std::string &proxy_host, std::string &proxy_port ) const;
|
|
|
|
HTTPResponse doGet( const HTTPRequest& request,
|
|
const osgDB::Options* options =0L,
|
|
ProgressCallback* callback =0L ) const;
|
|
|
|
ReadResult doReadObject(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions,
|
|
ProgressCallback* progress );
|
|
|
|
ReadResult doReadImage(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions,
|
|
ProgressCallback* progress );
|
|
|
|
ReadResult doReadNode(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions,
|
|
ProgressCallback* progress );
|
|
|
|
ReadResult doReadString(
|
|
const HTTPRequest& request,
|
|
const osgDB::Options* dbOptions,
|
|
ProgressCallback* progress );
|
|
|
|
/**
|
|
* Convenience method for downloading a URL directly to a file
|
|
*/
|
|
bool doDownload(const std::string& url, const std::string& filename);
|
|
|
|
private:
|
|
void* _curl_handle;
|
|
std::string _previousPassword;
|
|
long _previousHttpAuthentication;
|
|
bool _initialized;
|
|
long _simResponseCode;
|
|
|
|
osg::ref_ptr<Implementation> _impl;
|
|
|
|
void initialize() const;
|
|
void initializeImpl();
|
|
|
|
static ImplementationFactory* _implFactory;
|
|
|
|
static HTTPClient& getClient();
|
|
};
|
|
|
|
|
|
class OSGEARTH_EXPORT CURLHTTPImplementationFactory : public HTTPClient::ImplementationFactory
|
|
{
|
|
public:
|
|
HTTPClient::Implementation* create() const;
|
|
};
|
|
|
|
class OSGEARTH_EXPORT WinInetHTTPImplementationFactory : public HTTPClient::ImplementationFactory
|
|
{
|
|
public:
|
|
HTTPClient::Implementation* create() const;
|
|
};
|
|
} }
|
|
|
|
#endif // OSGEARTH_HTTP_CLIENT_H
|