diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-12-25 20:13:03 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2019-12-27 11:14:16 +0100 |
| commit | 2093aca0720949303410280912b61efd791d2f01 (patch) | |
| tree | a69c5392ed6689a88d9d959ddb41107413efacc6 /src | |
| parent | c4589fbe42e5fea07a03919d3484164f5fb70dd3 (diff) | |
| download | PROJ-2093aca0720949303410280912b61efd791d2f01.tar.gz PROJ-2093aca0720949303410280912b61efd791d2f01.zip | |
Network: make CDN endpoint configurable either in proj.ini, PROJ_NETWORK_ENDPOINT or proj_context_set_url_endpoint()
Diffstat (limited to 'src')
| -rw-r--r-- | src/filemanager.cpp | 25 | ||||
| -rw-r--r-- | src/open_lib.cpp | 113 | ||||
| -rw-r--r-- | src/proj.h | 2 | ||||
| -rw-r--r-- | src/proj_internal.h | 7 |
4 files changed, 137 insertions, 10 deletions
diff --git a/src/filemanager.cpp b/src/filemanager.cpp index d9a02632..97d7369e 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -772,6 +772,9 @@ int proj_context_set_network_callbacks( /** Enable or disable network access. * +* This overrides the default endpoint in the PROJ configuration file or with +* the PROJ_NETWORK environment variable. +* * @param ctx PROJ context, or NULL * @param enable TRUE if network access is allowed. * @return TRUE if network access is possible. That is either libcurl is @@ -781,6 +784,8 @@ int proj_context_set_enable_network(PJ_CONTEXT *ctx, int enable) { if (ctx == nullptr) { ctx = pj_get_default_ctx(); } + // Load ini file, now so as to override its network settings + pj_load_ini(ctx); ctx->networking.enabled_env_variable_checked = true; ctx->networking.enabled = enable != FALSE; #ifdef CURL_ENABLED @@ -793,6 +798,25 @@ int proj_context_set_enable_network(PJ_CONTEXT *ctx, int enable) { // --------------------------------------------------------------------------- +/** Define the URL endpoint to query for remote grids. +* +* This overrides the default endpoint in the PROJ configuration file or with +* the PROJ_NETWORK_ENDPOINT environment variable. +* +* @param ctx PROJ context, or NULL +* @param url Endpoint URL. Must NOT be NULL. +*/ +void proj_context_set_url_endpoint(PJ_CONTEXT *ctx, const char *url) { + if (ctx == nullptr) { + ctx = pj_get_default_ctx(); + } + // Load ini file, now so as to override its network settings + pj_load_ini(ctx); + ctx->endpoint = url; +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool pj_context_is_network_enabled(PJ_CONTEXT *ctx) { @@ -808,6 +832,7 @@ bool pj_context_is_network_enabled(PJ_CONTEXT *ctx) { ci_equal(enabled, "YES") || ci_equal(enabled, "TRUE"); } + pj_load_ini(ctx); ctx->networking.enabled_env_variable_checked = true; return ctx->networking.enabled; } diff --git a/src/open_lib.cpp b/src/open_lib.cpp index 926505ba..cde5be7b 100644 --- a/src/open_lib.cpp +++ b/src/open_lib.cpp @@ -366,16 +366,21 @@ std::unique_ptr<NS_PROJ::File> NS_PROJ::FileManager::open_resource_file( !starts_with(name, "http://") && !starts_with(name, "https://") && pj_context_is_network_enabled(ctx) ) { - std::string remote_file("https://cdn.proj.org/"); - remote_file += name; - auto pos = remote_file.rfind('.'); - if( pos + 4 == remote_file.size() ) { - remote_file = remote_file.substr(0, pos) + ".tif"; - file = open(ctx, remote_file.c_str()); - if( file ) { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "Using %s", remote_file.c_str() ); - pj_ctx_set_errno( ctx, 0 ); + std::string remote_file(pj_context_get_url_endpoint(ctx)); + if( !remote_file.empty() ) { + if( remote_file.back() != '/' ) { + remote_file += '/'; + } + remote_file += name; + auto pos = remote_file.rfind('.'); + if( pos + 4 == remote_file.size() ) { + remote_file = remote_file.substr(0, pos) + ".tif"; + file = open(ctx, remote_file.c_str()); + if( file ) { + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "Using %s", remote_file.c_str() ); + pj_ctx_set_errno( ctx, 0 ); + } } } } @@ -433,3 +438,91 @@ int pj_find_file(projCtx ctx, const char *short_filename, } return 0; } + +/************************************************************************/ +/* pj_context_get_url_endpoint() */ +/************************************************************************/ + +std::string pj_context_get_url_endpoint(PJ_CONTEXT* ctx) +{ + if( !ctx->endpoint.empty() ) { + return ctx->endpoint; + } + pj_load_ini(ctx); + return ctx->endpoint; +} + +/************************************************************************/ +/* trim() */ +/************************************************************************/ + +static std::string trim(const std::string& s) { + const auto first = s.find_first_not_of(' '); + const auto last = s.find_last_not_of(' '); + if( first == std::string::npos || last == std::string::npos ) { + return std::string(); + } + return s.substr(first, last - first + 1); +} + +/************************************************************************/ +/* pj_load_ini() */ +/************************************************************************/ + +void pj_load_ini(projCtx ctx) +{ + if( ctx->iniFileLoaded ) + return; + + const char* endpoint_from_env = getenv("PROJ_NETWORK_ENDPOINT"); + if( endpoint_from_env && endpoint_from_env[0] != '\0' ) { + ctx->endpoint = endpoint_from_env; + } + + ctx->iniFileLoaded = true; + auto file = std::unique_ptr<NS_PROJ::File>( + reinterpret_cast<NS_PROJ::File*>( + pj_open_lib_internal(ctx, "proj.ini", "rb", + pj_open_file_with_manager, + nullptr, 0))); + if( !file ) + return; + file->seek(0, SEEK_END); + const auto filesize = file->tell(); + if( filesize == 0 || filesize > 100 * 1024U ) + return; + file->seek(0, SEEK_SET); + std::string content; + content.resize(static_cast<size_t>(filesize)); + const auto nread = file->read(&content[0], content.size()); + if( nread != content.size() ) + return; + content += '\n'; + size_t pos = 0; + while( pos != std::string::npos ) { + const auto eol = content.find_first_of("\r\n", pos); + if( eol == std::string::npos ) { + break; + } + + const auto equal = content.find('=', pos); + if( equal < eol ) + { + const auto key = trim(content.substr(pos, equal-pos)); + const auto value = trim(content.substr(equal + 1, + eol - (equal+1))); + if( ctx->endpoint.empty() && key == "cdn_endpoint" ) { + ctx->endpoint = value; + } else if ( key == "network" ) { + const char *enabled = getenv("PROJ_NETWORK"); + if (enabled == nullptr || enabled[0] == '\0') { + ctx->networking.enabled = ci_equal(value, "ON") || + ci_equal(value, "YES") || + ci_equal(value, "TRUE"); + } + } + } + + pos = content.find_first_not_of("\r\n", eol); + } +} @@ -424,6 +424,8 @@ int PROJ_DLL proj_context_set_network_callbacks( int PROJ_DLL proj_context_set_enable_network(PJ_CONTEXT* ctx, int enabled); +void PROJ_DLL proj_context_set_url_endpoint(PJ_CONTEXT* ctx, const char* url); + /*! @cond Doxygen_Suppress */ /* Manage the transformation definition object PJ */ diff --git a/src/proj_internal.h b/src/proj_internal.h index 983f1c07..669fd2b5 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -699,6 +699,9 @@ struct projCtx_t { projNetworkCallbacksAndData networking{}; bool defer_grid_opening = false; // set by pj_obj_create() + bool iniFileLoaded = false; + std::string endpoint{}; + int projStringParserCreateFromPROJStringRecursionCounter = 0; // to avoid potential infinite recursion in PROJStringParser::createFromPROJString() projCtx_t() = default; @@ -830,6 +833,10 @@ void pj_pipeline_assign_context_to_steps( PJ* P, PJ_CONTEXT* ctx ); // For use by projinfo bool PROJ_DLL pj_context_is_network_enabled(PJ_CONTEXT* ctx); +std::string pj_context_get_url_endpoint(PJ_CONTEXT* ctx); + +void pj_load_ini(PJ_CONTEXT* ctx); + /* classic public API */ #include "proj_api.h" |
