Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: CPL - Common Portability Library 4 : * Purpose: Implement VSI large file api for Alibaba Object Storage Service 5 : * Author: Even Rouault, even.rouault at spatialys.com 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2017-2018, Even Rouault <even.rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "cpl_port.h" 14 : #include "cpl_http.h" 15 : #include "cpl_minixml.h" 16 : #include "cpl_vsil_curl_priv.h" 17 : #include "cpl_vsil_curl_class.h" 18 : 19 : #include <errno.h> 20 : 21 : #include <algorithm> 22 : #include <set> 23 : #include <map> 24 : #include <memory> 25 : 26 : #include "cpl_alibaba_oss.h" 27 : 28 : #ifndef HAVE_CURL 29 : 30 : void VSIInstallOSSFileHandler(void) 31 : { 32 : // Not supported 33 : } 34 : 35 : #else 36 : 37 : //! @cond Doxygen_Suppress 38 : #ifndef DOXYGEN_SKIP 39 : 40 : #define ENABLE_DEBUG 0 41 : 42 : namespace cpl 43 : { 44 : 45 : /************************************************************************/ 46 : /* VSIOSSFSHandler */ 47 : /************************************************************************/ 48 : 49 : class VSIOSSFSHandler final : public IVSIS3LikeFSHandlerWithMultipartUpload 50 : { 51 : CPL_DISALLOW_COPY_ASSIGN(VSIOSSFSHandler) 52 : 53 : protected: 54 : VSICurlHandle *CreateFileHandle(const char *pszFilename) override; 55 : std::string 56 : GetURLFromFilename(const std::string &osFilename) const override; 57 : 58 77 : const char *GetDebugKey() const override 59 : { 60 77 : return "OSS"; 61 : } 62 : 63 : IVSIS3LikeHandleHelper *CreateHandleHelper(const char *pszURI, 64 : bool bAllowNoObject) override; 65 : 66 990 : std::string GetFSPrefix() const override 67 : { 68 990 : return "/vsioss/"; 69 : } 70 : 71 : void ClearCache() override; 72 : 73 : VSIVirtualHandleUniquePtr 74 : CreateWriteHandle(const char *pszFilename, 75 : CSLConstList papszOptions) override; 76 : 77 : public: 78 1694 : VSIOSSFSHandler() = default; 79 : ~VSIOSSFSHandler() override; 80 : 81 : const char *GetOptions() override; 82 : 83 : char *GetSignedURL(const char *pszFilename, 84 : CSLConstList papszOptions) override; 85 : 86 : std::string 87 0 : GetStreamingFilename(const std::string &osFilename) const override 88 : { 89 0 : return osFilename; 90 : } 91 : 92 1 : bool SupportsMultipartAbort() const override 93 : { 94 1 : return true; 95 : } 96 : }; 97 : 98 : /************************************************************************/ 99 : /* VSIOSSHandle */ 100 : /************************************************************************/ 101 : 102 : class VSIOSSHandle final : public IVSIS3LikeHandle 103 : { 104 : CPL_DISALLOW_COPY_ASSIGN(VSIOSSHandle) 105 : 106 : VSIOSSHandleHelper *m_poHandleHelper = nullptr; 107 : 108 : protected: 109 : struct curl_slist *GetCurlHeaders(const std::string &osVerb, 110 : struct curl_slist *psHeaders) override; 111 : bool CanRestartOnError(const char *, const char *, bool) override; 112 : 113 : public: 114 : VSIOSSHandle(VSIOSSFSHandler *poFS, const char *pszFilename, 115 : VSIOSSHandleHelper *poHandleHelper); 116 : ~VSIOSSHandle() override; 117 : }; 118 : 119 : /************************************************************************/ 120 : /* ~VSIOSSFSHandler() */ 121 : /************************************************************************/ 122 : 123 2244 : VSIOSSFSHandler::~VSIOSSFSHandler() 124 : { 125 1122 : VSIOSSFSHandler::ClearCache(); 126 2244 : } 127 : 128 : /************************************************************************/ 129 : /* CreateWriteHandle() */ 130 : /************************************************************************/ 131 : 132 : VSIVirtualHandleUniquePtr 133 7 : VSIOSSFSHandler::CreateWriteHandle(const char *pszFilename, 134 : CSLConstList papszOptions) 135 : { 136 : auto poHandleHelper = 137 7 : CreateHandleHelper(pszFilename + GetFSPrefix().size(), false); 138 7 : if (poHandleHelper == nullptr) 139 1 : return nullptr; 140 : auto poHandle = std::make_unique<VSIMultipartWriteHandle>( 141 12 : this, pszFilename, poHandleHelper, papszOptions); 142 6 : if (!poHandle->IsOK()) 143 : { 144 0 : return nullptr; 145 : } 146 6 : return VSIVirtualHandleUniquePtr(poHandle.release()); 147 : } 148 : 149 : /************************************************************************/ 150 : /* ClearCache() */ 151 : /************************************************************************/ 152 : 153 1457 : void VSIOSSFSHandler::ClearCache() 154 : { 155 1457 : VSICurlFilesystemHandlerBase::ClearCache(); 156 : 157 1457 : VSIOSSUpdateParams::ClearCache(); 158 1457 : } 159 : 160 : /************************************************************************/ 161 : /* GetOptions() */ 162 : /************************************************************************/ 163 : 164 2 : const char *VSIOSSFSHandler::GetOptions() 165 : { 166 : static std::string osOptions( 167 2 : std::string("<Options>") + 168 : " <Option name='OSS_SECRET_ACCESS_KEY' type='string' " 169 : "description='Secret access key. To use with OSS_ACCESS_KEY_ID'/>" 170 : " <Option name='OSS_ACCESS_KEY_ID' type='string' " 171 : "description='Access key id'/>" 172 : " <Option name='OSS_ENDPOINT' type='string' " 173 : "description='Default endpoint' default='oss-us-east-1.aliyuncs.com'/>" 174 : " <Option name='VSIOSS_CHUNK_SIZE' type='int' " 175 : "description='Size in MB for chunks of files that are uploaded. The" 176 : "default value of 50 MB allows for files up to 500 GB each' " 177 3 : "default='50' min='1' max='1000'/>" + 178 3 : VSICurlFilesystemHandlerBase::GetOptionsStatic() + "</Options>"); 179 2 : return osOptions.c_str(); 180 : } 181 : 182 : /************************************************************************/ 183 : /* GetSignedURL() */ 184 : /************************************************************************/ 185 : 186 2 : char *VSIOSSFSHandler::GetSignedURL(const char *pszFilename, 187 : CSLConstList papszOptions) 188 : { 189 2 : if (!STARTS_WITH_CI(pszFilename, GetFSPrefix().c_str())) 190 0 : return nullptr; 191 : 192 4 : VSIOSSHandleHelper *poHandleHelper = VSIOSSHandleHelper::BuildFromURI( 193 6 : pszFilename + GetFSPrefix().size(), GetFSPrefix().c_str(), false, 194 : papszOptions); 195 2 : if (poHandleHelper == nullptr) 196 : { 197 1 : return nullptr; 198 : } 199 : 200 2 : std::string osRet(poHandleHelper->GetSignedURL(papszOptions)); 201 : 202 1 : delete poHandleHelper; 203 1 : return CPLStrdup(osRet.c_str()); 204 : } 205 : 206 : /************************************************************************/ 207 : /* CreateFileHandle() */ 208 : /************************************************************************/ 209 : 210 57 : VSICurlHandle *VSIOSSFSHandler::CreateFileHandle(const char *pszFilename) 211 : { 212 114 : VSIOSSHandleHelper *poHandleHelper = VSIOSSHandleHelper::BuildFromURI( 213 171 : pszFilename + GetFSPrefix().size(), GetFSPrefix().c_str(), false); 214 57 : if (poHandleHelper) 215 : { 216 43 : return new VSIOSSHandle(this, pszFilename, poHandleHelper); 217 : } 218 14 : return nullptr; 219 : } 220 : 221 : /************************************************************************/ 222 : /* GetURLFromFilename() */ 223 : /************************************************************************/ 224 : 225 : std::string 226 29 : VSIOSSFSHandler::GetURLFromFilename(const std::string &osFilename) const 227 : { 228 : const std::string osFilenameWithoutPrefix = 229 58 : osFilename.substr(GetFSPrefix().size()); 230 : 231 : auto poHandleHelper = 232 : std::unique_ptr<VSIOSSHandleHelper>(VSIOSSHandleHelper::BuildFromURI( 233 58 : osFilenameWithoutPrefix.c_str(), GetFSPrefix().c_str(), true)); 234 29 : if (!poHandleHelper) 235 : { 236 12 : return std::string(); 237 : } 238 : 239 34 : std::string osBaseURL(poHandleHelper->GetURL()); 240 17 : if (!osBaseURL.empty() && osBaseURL.back() == '/') 241 7 : osBaseURL.pop_back(); 242 17 : return osBaseURL; 243 : } 244 : 245 : /************************************************************************/ 246 : /* CreateHandleHelper() */ 247 : /************************************************************************/ 248 : 249 22 : IVSIS3LikeHandleHelper *VSIOSSFSHandler::CreateHandleHelper(const char *pszURI, 250 : bool bAllowNoObject) 251 : { 252 44 : return VSIOSSHandleHelper::BuildFromURI(pszURI, GetFSPrefix().c_str(), 253 44 : bAllowNoObject); 254 : } 255 : 256 : /************************************************************************/ 257 : /* VSIOSSHandle() */ 258 : /************************************************************************/ 259 : 260 43 : VSIOSSHandle::VSIOSSHandle(VSIOSSFSHandler *poFSIn, const char *pszFilename, 261 43 : VSIOSSHandleHelper *poHandleHelper) 262 43 : : IVSIS3LikeHandle(poFSIn, pszFilename, poHandleHelper->GetURL().c_str()), 263 43 : m_poHandleHelper(poHandleHelper) 264 : { 265 43 : } 266 : 267 : /************************************************************************/ 268 : /* ~VSIOSSHandle() */ 269 : /************************************************************************/ 270 : 271 86 : VSIOSSHandle::~VSIOSSHandle() 272 : { 273 43 : delete m_poHandleHelper; 274 86 : } 275 : 276 : /************************************************************************/ 277 : /* GetCurlHeaders() */ 278 : /************************************************************************/ 279 : 280 43 : struct curl_slist *VSIOSSHandle::GetCurlHeaders(const std::string &osVerb, 281 : struct curl_slist *psHeaders) 282 : { 283 43 : return m_poHandleHelper->GetCurlHeaders(osVerb, psHeaders); 284 : } 285 : 286 : /************************************************************************/ 287 : /* CanRestartOnError() */ 288 : /************************************************************************/ 289 : 290 3 : bool VSIOSSHandle::CanRestartOnError(const char *pszErrorMsg, 291 : const char *pszHeaders, bool bSetError) 292 : { 293 3 : if (m_poHandleHelper->CanRestartOnError(pszErrorMsg, pszHeaders, bSetError)) 294 : { 295 1 : SetURL(m_poHandleHelper->GetURL().c_str()); 296 1 : return true; 297 : } 298 2 : return false; 299 : } 300 : 301 : } /* end of namespace cpl */ 302 : 303 : #endif // DOXYGEN_SKIP 304 : //! @endcond 305 : 306 : /************************************************************************/ 307 : /* VSIInstallOSSFileHandler() */ 308 : /************************************************************************/ 309 : 310 : /*! 311 : \brief Install /vsioss/ Alibaba Cloud Object Storage Service (OSS) file 312 : system handler (requires libcurl) 313 : 314 : \verbatim embed:rst 315 : See :ref:`/vsioss/ documentation <vsioss>` 316 : \endverbatim 317 : 318 : @since GDAL 2.3 319 : */ 320 1694 : void VSIInstallOSSFileHandler(void) 321 : { 322 1694 : VSIFileManager::InstallHandler("/vsioss/", new cpl::VSIOSSFSHandler); 323 1694 : } 324 : 325 : #endif /* HAVE_CURL */