1 /********************************************************************** 2 * $Id: cpl_aws.h f87673d2ac225e117fd6f6d5b32443cab1c7460b 2020-07-21 15:14:42 +0200 Even Rouault $ 3 * 4 * Name: cpl_aws.h 5 * Project: CPL - Common Portability Library 6 * Purpose: Amazon Web Services routines 7 * Author: Even Rouault <even.rouault at spatialys.com> 8 * 9 ********************************************************************** 10 * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com> 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included 20 * in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 * DEALINGS IN THE SOFTWARE. 29 ****************************************************************************/ 30 31 #ifndef CPL_AWS_INCLUDED_H 32 #define CPL_AWS_INCLUDED_H 33 34 #ifndef DOXYGEN_SKIP 35 36 #ifdef HAVE_CURL 37 38 #include <cstddef> 39 #include <mutex> 40 41 #include "cpl_string.h" 42 43 #include <curl/curl.h> 44 #include <map> 45 46 CPLString CPLGetLowerCaseHexSHA256( const void *pabyData, size_t nBytes ); 47 CPLString CPLGetLowerCaseHexSHA256( const CPLString& osStr ); 48 49 CPLString CPLGetAWS_SIGN4_Timestamp(); 50 51 CPLString CPLAWSURLEncode(const CPLString& osURL, bool bEncodeSlash = true); 52 53 CPLString CPLAWSGetHeaderVal(const struct curl_slist* psExistingHeaders, 54 const char* pszKey); 55 56 CPLString 57 CPLGetAWS_SIGN4_Signature( const CPLString& osSecretAccessKey, 58 const CPLString& osAccessToken, 59 const CPLString& osRegion, 60 const CPLString& osRequestPayer, 61 const CPLString& osService, 62 const CPLString& osVerb, 63 const struct curl_slist* psExistingHeaders, 64 const CPLString& osHost, 65 const CPLString& osCanonicalURI, 66 const CPLString& osCanonicalQueryString, 67 const CPLString& osXAMZContentSHA256, 68 const CPLString& osTimestamp, 69 CPLString& osSignedHeaders ); 70 71 CPLString CPLGetAWS_SIGN4_Authorization(const CPLString& osSecretAccessKey, 72 const CPLString& osAccessKeyId, 73 const CPLString& osAccessToken, 74 const CPLString& osRegion, 75 const CPLString& osRequestPayer, 76 const CPLString& osService, 77 const CPLString& osVerb, 78 const struct curl_slist* psExistingHeaders, 79 const CPLString& osHost, 80 const CPLString& osCanonicalURI, 81 const CPLString& osCanonicalQueryString, 82 const CPLString& osXAMZContentSHA256, 83 const CPLString& osTimestamp); 84 85 class IVSIS3LikeHandleHelper 86 { CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandleHelper)87 CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandleHelper) 88 89 protected: 90 std::map<CPLString, CPLString> m_oMapQueryParameters{}; 91 92 virtual void RebuildURL() = 0; 93 CPLString GetQueryString(bool bAddEmptyValueAfterEqual) const; 94 95 public: 96 IVSIS3LikeHandleHelper() = default; 97 virtual ~IVSIS3LikeHandleHelper() = default; 98 99 void ResetQueryParameters(); 100 void AddQueryParameter(const CPLString& osKey, const CPLString& osValue); 101 102 virtual struct curl_slist* GetCurlHeaders(const CPLString& osVerb, 103 const struct curl_slist* psExistingHeaders, 104 const void *pabyDataContent = nullptr, 105 size_t nBytesContent = 0) const = 0; 106 AllowAutomaticRedirection()107 virtual bool AllowAutomaticRedirection() { return true; } 108 virtual bool CanRestartOnError(const char*, const char* /* pszHeaders*/, 109 bool /*bSetError*/, bool* /*pbUpdateMap*/ = nullptr) { return false;} 110 111 virtual const CPLString& GetURL() const = 0; 112 CPLString GetURLNoKVP() const; 113 GetCopySourceHeader()114 virtual CPLString GetCopySourceHeader() const { return std::string(); } 115 116 static bool GetBucketAndObjectKey(const char* pszURI, 117 const char* pszFSPrefix, 118 bool bAllowNoObject, 119 CPLString &osBucketOut, 120 CPLString &osObjectKeyOut); 121 122 static CPLString BuildCanonicalizedHeaders( 123 std::map<CPLString, CPLString>& oSortedMapHeaders, 124 const struct curl_slist* psExistingHeaders, 125 const char* pszHeaderPrefix); 126 127 static CPLString GetRFC822DateTime(); 128 }; 129 130 class VSIS3HandleHelper final: public IVSIS3LikeHandleHelper 131 { CPL_DISALLOW_COPY_ASSIGN(VSIS3HandleHelper)132 CPL_DISALLOW_COPY_ASSIGN(VSIS3HandleHelper) 133 134 CPLString m_osURL{}; 135 mutable CPLString m_osSecretAccessKey{}; 136 mutable CPLString m_osAccessKeyId{}; 137 mutable CPLString m_osSessionToken{}; 138 CPLString m_osEndpoint{}; 139 CPLString m_osRegion{}; 140 CPLString m_osRequestPayer{}; 141 CPLString m_osBucket{}; 142 CPLString m_osObjectKey{}; 143 bool m_bUseHTTPS = false; 144 bool m_bUseVirtualHosting = false; 145 bool m_bFromEC2 = false; 146 147 void RebuildURL() override; 148 149 static bool GetConfigurationFromEC2(CPLString& osSecretAccessKey, 150 CPLString& osAccessKeyId, 151 CPLString& osSessionToken); 152 153 static bool GetConfigurationFromAWSConfigFiles( 154 CPLString& osSecretAccessKey, 155 CPLString& osAccessKeyId, 156 CPLString& osSessionToken, 157 CPLString& osRegion, 158 CPLString& osCredentials); 159 160 static bool GetConfiguration(CSLConstList papszOptions, 161 CPLString& osSecretAccessKey, 162 CPLString& osAccessKeyId, 163 CPLString& osSessionToken, 164 CPLString& osRegion, 165 bool& bFromEC2); 166 protected: 167 168 public: 169 VSIS3HandleHelper(const CPLString& osSecretAccessKey, 170 const CPLString& osAccessKeyId, 171 const CPLString& osSessionToken, 172 const CPLString& osEndpoint, 173 const CPLString& osRegion, 174 const CPLString& osRequestPayer, 175 const CPLString& osBucket, 176 const CPLString& osObjectKey, 177 bool bUseHTTPS, bool bUseVirtualHosting, bool bFromEC2); 178 ~VSIS3HandleHelper(); 179 180 static VSIS3HandleHelper* BuildFromURI(const char* pszURI, 181 const char* pszFSPrefix, 182 bool bAllowNoObject, 183 CSLConstList papszOptions = nullptr); 184 static CPLString BuildURL(const CPLString& osEndpoint, 185 const CPLString& osBucket, 186 const CPLString& osObjectKey, 187 bool bUseHTTPS, bool bUseVirtualHosting); 188 189 struct curl_slist* GetCurlHeaders( 190 const CPLString& osVerb, 191 const struct curl_slist* psExistingHeaders, 192 const void *pabyDataContent = nullptr, 193 size_t nBytesContent = 0) const override; 194 AllowAutomaticRedirection()195 bool AllowAutomaticRedirection() override { return false; } 196 bool CanRestartOnError(const char*, const char* pszHeaders, 197 bool bSetError, 198 bool* pbUpdateMap = nullptr) override; 199 GetURL()200 const CPLString& GetURL() const override { return m_osURL; } GetBucket()201 const CPLString& GetBucket() const { return m_osBucket; } GetObjectKey()202 const CPLString& GetObjectKey() const { return m_osObjectKey; } GetEndpoint()203 const CPLString& GetEndpoint()const { return m_osEndpoint; } GetRegion()204 const CPLString& GetRegion() const { return m_osRegion; } GetRequestPayer()205 const CPLString& GetRequestPayer() const { return m_osRequestPayer; } GetVirtualHosting()206 bool GetVirtualHosting() const { return m_bUseVirtualHosting; } 207 void SetEndpoint(const CPLString &osStr); 208 void SetRegion(const CPLString &osStr); 209 void SetRequestPayer(const CPLString &osStr); 210 void SetVirtualHosting(bool b); 211 GetCopySourceHeader()212 CPLString GetCopySourceHeader() const override { return "x-amz-copy-source"; } 213 214 CPLString GetSignedURL(CSLConstList papszOptions); 215 216 static void CleanMutex(); 217 static void ClearCache(); 218 }; 219 220 class VSIS3UpdateParams 221 { 222 public: 223 CPLString m_osRegion{}; 224 CPLString m_osEndpoint{}; 225 CPLString m_osRequestPayer{}; 226 bool m_bUseVirtualHosting = false; 227 228 VSIS3UpdateParams() = default; 229 VSIS3UpdateParams(const VSIS3HandleHelper * poHelper)230 explicit VSIS3UpdateParams(const VSIS3HandleHelper* poHelper) : 231 m_osRegion(poHelper->GetRegion()), 232 m_osEndpoint(poHelper->GetEndpoint()), 233 m_osRequestPayer(poHelper->GetRequestPayer()), 234 m_bUseVirtualHosting(poHelper->GetVirtualHosting()) {} 235 UpdateHandlerHelper(VSIS3HandleHelper * poHelper)236 void UpdateHandlerHelper(VSIS3HandleHelper* poHelper) { 237 poHelper->SetRegion(m_osRegion); 238 poHelper->SetEndpoint(m_osEndpoint); 239 poHelper->SetRequestPayer(m_osRequestPayer); 240 poHelper->SetVirtualHosting(m_bUseVirtualHosting); 241 } 242 243 static std::mutex gsMutex; 244 static std::map< CPLString, VSIS3UpdateParams > goMapBucketsToS3Params; 245 static void UpdateMapFromHandle( IVSIS3LikeHandleHelper* poHandleHelper ); 246 static void UpdateHandleFromMap( IVSIS3LikeHandleHelper* poHandleHelper ); 247 static void ClearCache(); 248 }; 249 250 #endif /* HAVE_CURL */ 251 252 #endif /* #ifndef DOXYGEN_SKIP */ 253 254 #endif /* CPL_AWS_INCLUDED_H */ 255