text: /**********************************************************************
   * $Id$
   *
   * Name:     cpl_aws.h
   * Project:  CPL - Common Portability Library
   * Purpose:  Amazon Web Services routines
   * Author:   Even Rouault <even.rouault at spatialys.com>
   *
   **********************************************************************
   * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included
   * in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   * DEALINGS IN THE SOFTWARE.
   ****************************************************************************/
  
  #ifndef CPL_AWS_INCLUDED_H
  #define CPL_AWS_INCLUDED_H
  
  #ifndef DOXYGEN_SKIP
  
  #ifdef HAVE_CURL
  
  #include <cstddef>
  
  #include "cpl_string.h"
  
  #include <curl/curl.h>
  #include <map>
  
  CPLString CPLGetLowerCaseHexSHA256( const void *pabyData, size_t nBytes );
  CPLString CPLGetLowerCaseHexSHA256( const CPLString& osStr );
  
  CPLString CPLGetAWS_SIGN4_Timestamp();
  
  CPLString CPLAWSURLEncode(const CPLString& osURL, bool bEncodeSlash = true);
  
  CPLString CPLAWSGetHeaderVal(const struct curl_slist* psExistingHeaders,
                               const char* pszKey);
  
  CPLString CPLGetAWS_SIGN4_Authorization(const CPLString& osSecretAccessKey,
                                          const CPLString& osAccessKeyId,
                                          const CPLString& osAccessToken,
                                          const CPLString& osRegion,
                                          const CPLString& osRequestPayer,
                                          const CPLString& osService,
                                          const CPLString& osVerb,
                                          const struct curl_slist* psExistingHeaders,
                                          const CPLString& osHost,
                                          const CPLString& osCanonicalURI,
                                          const CPLString& osCanonicalQueryString,
                                          const CPLString& osXAMZContentSHA256,
                                          const CPLString& osTimestamp);
  
  class IVSIS3LikeHandleHelper
  {
  protected:
          std::map<CPLString, CPLString> m_oMapQueryParameters;
  
          virtual void RebuildURL() = 0;
          CPLString GetQueryString() const;
  
  public:
          IVSIS3LikeHandleHelper() {}
          virtual ~IVSIS3LikeHandleHelper() {}
  
          void ResetQueryParameters();
          void AddQueryParameter(const CPLString& osKey, const CPLString& osValue);
  
          virtual struct curl_slist* GetCurlHeaders(const CPLString& osVerb,
                                            const struct curl_slist* psExistingHeaders,
                                            const void *pabyDataContent = nullptr,
                                            size_t nBytesContent = 0) const = 0;
  
          virtual bool AllowAutomaticRedirection() { return true; }
          virtual bool CanRestartOnError(const char*, const char* /* pszHeaders*/,
                                         bool /*bSetError*/, bool* /*pbUpdateMap*/ = nullptr) { return false;}
  
          virtual const CPLString& GetURL() const = 0;
  
          static bool GetBucketAndObjectKey(const char* pszURI,
                                            const char* pszFSPrefix,
                                            bool bAllowNoObject,
                                            CPLString &osBucketOut,
                                            CPLString &osObjectKeyOut);
  
          static CPLString BuildCanonicalizedHeaders(
                              std::map<CPLString, CPLString>& oSortedMapHeaders,
                              const struct curl_slist* psExistingHeaders,
                              const char* pszHeaderPrefix);
  };
  
  class VSIS3HandleHelper: public IVSIS3LikeHandleHelper
  {
          CPLString m_osURL;
          CPLString m_osSecretAccessKey;
          CPLString m_osAccessKeyId;
          CPLString m_osSessionToken;
          CPLString m_osEndpoint;
          CPLString m_osRegion;
          CPLString m_osRequestPayer;
          CPLString m_osBucket;
          CPLString m_osObjectKey;
          bool m_bUseHTTPS;
          bool m_bUseVirtualHosting;
  
          void RebuildURL() override;
  
          static bool GetConfigurationFromEC2(CPLString& osSecretAccessKey,
                                              CPLString& osAccessKeyId,
                                              CPLString& osSessionToken);
  
          static bool GetConfigurationFromAWSConfigFiles(
                                       CPLString& osSecretAccessKey,
                                       CPLString& osAccessKeyId,
                                       CPLString& osSessionToken,
                                       CPLString& osRegion,
                                       CPLString& osCredentials);
    protected:
  
      public:
          VSIS3HandleHelper(const CPLString& osSecretAccessKey,
                      const CPLString& osAccessKeyId,
                      const CPLString& osSessionToken,
                      const CPLString& osEndpoint,
                      const CPLString& osRegion,
                      const CPLString& osRequestPayer,
                      const CPLString& osBucket,
                      const CPLString& osObjectKey,
                      bool bUseHTTPS, bool bUseVirtualHosting);
         ~VSIS3HandleHelper();
  
          static VSIS3HandleHelper* BuildFromURI(const char* pszURI, const char* pszFSPrefix,
                                                 bool bAllowNoObject);
          static CPLString BuildURL(const CPLString& osEndpoint,
                                    const CPLString& osBucket,
                                    const CPLString& osObjectKey,
                                    bool bUseHTTPS, bool bUseVirtualHosting);
  
          struct curl_slist* GetCurlHeaders(
              const CPLString& osVerb,
              const struct curl_slist* psExistingHeaders,
              const void *pabyDataContent = nullptr,
              size_t nBytesContent = 0) const override;
  
          bool AllowAutomaticRedirection() override { return false; }
          bool CanRestartOnError(const char*, const char* pszHeaders,
                                 bool bSetError,
                                 bool* pbUpdateMap = nullptr) override;
  
          const CPLString& GetURL() const override { return m_osURL; }
          const CPLString& GetBucket() const { return m_osBucket; }
          const CPLString& GetObjectKey() const { return m_osObjectKey; }
          const CPLString& GetEndpoint()const  { return m_osEndpoint; }
          const CPLString& GetRegion() const { return m_osRegion; }
          const CPLString& GetRequestPayer() const { return m_osRequestPayer; }
          bool GetVirtualHosting() const { return m_bUseVirtualHosting; }
          void SetEndpoint(const CPLString &osStr);
          void SetRegion(const CPLString &osStr);
          void SetRequestPayer(const CPLString &osStr);
          void SetVirtualHosting(bool b);
  
          static bool GetConfiguration(CPLString& osSecretAccessKey,
                                       CPLString& osAccessKeyId,
                                       CPLString& osSessionToken,
                                       CPLString& osRegion);
          static void CleanMutex();
          static void ClearCache();
  };
  
  class VSIS3UpdateParams
  {
      public:
          CPLString m_osRegion;
          CPLString m_osEndpoint;
          CPLString m_osRequestPayer;
          bool m_bUseVirtualHosting;
  
          VSIS3UpdateParams() :
              m_bUseVirtualHosting(false) {}
  
          explicit VSIS3UpdateParams(const VSIS3HandleHelper* poHelper) :
              m_osRegion(poHelper->GetRegion()),
              m_osEndpoint(poHelper->GetEndpoint()),
              m_osRequestPayer(poHelper->GetRequestPayer()),
              m_bUseVirtualHosting(poHelper->GetVirtualHosting()) {}
  
          void UpdateHandlerHelper(VSIS3HandleHelper* poHelper) {
              poHelper->SetRegion(m_osRegion);
              poHelper->SetEndpoint(m_osEndpoint);
              poHelper->SetRequestPayer(m_osRequestPayer);
              poHelper->SetVirtualHosting(m_bUseVirtualHosting);
          }
  };
  
  #endif /* HAVE_CURL */
  
  #endif /* #ifndef DOXYGEN_SKIP */
  
  #endif /* CPL_AWS_INCLUDED_H */
  