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 729 : std::string GetFSPrefix() const override 67 : { 68 729 : return "/vsioss/"; 69 : } 70 : 71 : void ClearCache() override; 72 : 73 : VSIVirtualHandleUniquePtr 74 : CreateWriteHandle(const char *pszFilename, 75 : CSLConstList papszOptions) override; 76 : 77 : public: 78 1304 : 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 * 110 : GetCurlHeaders(const std::string &osVerb, 111 : const struct curl_slist *psExistingHeaders) override; 112 : bool CanRestartOnError(const char *, const char *, bool) override; 113 : 114 : public: 115 : VSIOSSHandle(VSIOSSFSHandler *poFS, const char *pszFilename, 116 : VSIOSSHandleHelper *poHandleHelper); 117 : ~VSIOSSHandle() override; 118 : }; 119 : 120 : /************************************************************************/ 121 : /* ~VSIOSSFSHandler() */ 122 : /************************************************************************/ 123 : 124 1866 : VSIOSSFSHandler::~VSIOSSFSHandler() 125 : { 126 933 : VSIOSSFSHandler::ClearCache(); 127 1866 : } 128 : 129 : /************************************************************************/ 130 : /* CreateWriteHandle() */ 131 : /************************************************************************/ 132 : 133 : VSIVirtualHandleUniquePtr 134 7 : VSIOSSFSHandler::CreateWriteHandle(const char *pszFilename, 135 : CSLConstList papszOptions) 136 : { 137 : auto poHandleHelper = 138 7 : CreateHandleHelper(pszFilename + GetFSPrefix().size(), false); 139 7 : if (poHandleHelper == nullptr) 140 1 : return nullptr; 141 : auto poHandle = std::make_unique<VSIMultipartWriteHandle>( 142 12 : this, pszFilename, poHandleHelper, papszOptions); 143 6 : if (!poHandle->IsOK()) 144 : { 145 0 : return nullptr; 146 : } 147 6 : return VSIVirtualHandleUniquePtr(poHandle.release()); 148 : } 149 : 150 : /************************************************************************/ 151 : /* ClearCache() */ 152 : /************************************************************************/ 153 : 154 1232 : void VSIOSSFSHandler::ClearCache() 155 : { 156 1232 : VSICurlFilesystemHandlerBase::ClearCache(); 157 : 158 1232 : VSIOSSUpdateParams::ClearCache(); 159 1232 : } 160 : 161 : /************************************************************************/ 162 : /* GetOptions() */ 163 : /************************************************************************/ 164 : 165 2 : const char *VSIOSSFSHandler::GetOptions() 166 : { 167 : static std::string osOptions( 168 2 : std::string("<Options>") + 169 : " <Option name='OSS_SECRET_ACCESS_KEY' type='string' " 170 : "description='Secret access key. To use with OSS_ACCESS_KEY_ID'/>" 171 : " <Option name='OSS_ACCESS_KEY_ID' type='string' " 172 : "description='Access key id'/>" 173 : " <Option name='OSS_ENDPOINT' type='string' " 174 : "description='Default endpoint' default='oss-us-east-1.aliyuncs.com'/>" 175 : " <Option name='VSIOSS_CHUNK_SIZE' type='int' " 176 : "description='Size in MB for chunks of files that are uploaded. The" 177 : "default value of 50 MB allows for files up to 500 GB each' " 178 3 : "default='50' min='1' max='1000'/>" + 179 3 : VSICurlFilesystemHandlerBase::GetOptionsStatic() + "</Options>"); 180 2 : return osOptions.c_str(); 181 : } 182 : 183 : /************************************************************************/ 184 : /* GetSignedURL() */ 185 : /************************************************************************/ 186 : 187 2 : char *VSIOSSFSHandler::GetSignedURL(const char *pszFilename, 188 : CSLConstList papszOptions) 189 : { 190 2 : if (!STARTS_WITH_CI(pszFilename, GetFSPrefix().c_str())) 191 0 : return nullptr; 192 : 193 4 : VSIOSSHandleHelper *poHandleHelper = VSIOSSHandleHelper::BuildFromURI( 194 6 : pszFilename + GetFSPrefix().size(), GetFSPrefix().c_str(), false, 195 : papszOptions); 196 2 : if (poHandleHelper == nullptr) 197 : { 198 1 : return nullptr; 199 : } 200 : 201 2 : std::string osRet(poHandleHelper->GetSignedURL(papszOptions)); 202 : 203 1 : delete poHandleHelper; 204 1 : return CPLStrdup(osRet.c_str()); 205 : } 206 : 207 : /************************************************************************/ 208 : /* CreateFileHandle() */ 209 : /************************************************************************/ 210 : 211 45 : VSICurlHandle *VSIOSSFSHandler::CreateFileHandle(const char *pszFilename) 212 : { 213 90 : VSIOSSHandleHelper *poHandleHelper = VSIOSSHandleHelper::BuildFromURI( 214 135 : pszFilename + GetFSPrefix().size(), GetFSPrefix().c_str(), false); 215 45 : if (poHandleHelper) 216 : { 217 43 : return new VSIOSSHandle(this, pszFilename, poHandleHelper); 218 : } 219 2 : return nullptr; 220 : } 221 : 222 : /************************************************************************/ 223 : /* GetURLFromFilename() */ 224 : /************************************************************************/ 225 : 226 : std::string 227 17 : VSIOSSFSHandler::GetURLFromFilename(const std::string &osFilename) const 228 : { 229 : const std::string osFilenameWithoutPrefix = 230 34 : osFilename.substr(GetFSPrefix().size()); 231 : 232 : auto poHandleHelper = 233 : std::unique_ptr<VSIOSSHandleHelper>(VSIOSSHandleHelper::BuildFromURI( 234 34 : osFilenameWithoutPrefix.c_str(), GetFSPrefix().c_str(), true)); 235 17 : if (!poHandleHelper) 236 : { 237 0 : return std::string(); 238 : } 239 : 240 34 : std::string osBaseURL(poHandleHelper->GetURL()); 241 17 : if (!osBaseURL.empty() && osBaseURL.back() == '/') 242 7 : osBaseURL.pop_back(); 243 17 : return osBaseURL; 244 : } 245 : 246 : /************************************************************************/ 247 : /* CreateHandleHelper() */ 248 : /************************************************************************/ 249 : 250 19 : IVSIS3LikeHandleHelper *VSIOSSFSHandler::CreateHandleHelper(const char *pszURI, 251 : bool bAllowNoObject) 252 : { 253 38 : return VSIOSSHandleHelper::BuildFromURI(pszURI, GetFSPrefix().c_str(), 254 38 : bAllowNoObject); 255 : } 256 : 257 : /************************************************************************/ 258 : /* VSIOSSHandle() */ 259 : /************************************************************************/ 260 : 261 43 : VSIOSSHandle::VSIOSSHandle(VSIOSSFSHandler *poFSIn, const char *pszFilename, 262 43 : VSIOSSHandleHelper *poHandleHelper) 263 43 : : IVSIS3LikeHandle(poFSIn, pszFilename, poHandleHelper->GetURL().c_str()), 264 43 : m_poHandleHelper(poHandleHelper) 265 : { 266 43 : } 267 : 268 : /************************************************************************/ 269 : /* ~VSIOSSHandle() */ 270 : /************************************************************************/ 271 : 272 86 : VSIOSSHandle::~VSIOSSHandle() 273 : { 274 43 : delete m_poHandleHelper; 275 86 : } 276 : 277 : /************************************************************************/ 278 : /* GetCurlHeaders() */ 279 : /************************************************************************/ 280 : 281 : struct curl_slist * 282 43 : VSIOSSHandle::GetCurlHeaders(const std::string &osVerb, 283 : const struct curl_slist *psExistingHeaders) 284 : { 285 43 : return m_poHandleHelper->GetCurlHeaders(osVerb, psExistingHeaders); 286 : } 287 : 288 : /************************************************************************/ 289 : /* CanRestartOnError() */ 290 : /************************************************************************/ 291 : 292 2 : bool VSIOSSHandle::CanRestartOnError(const char *pszErrorMsg, 293 : const char *pszHeaders, bool bSetError) 294 : { 295 2 : if (m_poHandleHelper->CanRestartOnError(pszErrorMsg, pszHeaders, bSetError)) 296 : { 297 1 : SetURL(m_poHandleHelper->GetURL().c_str()); 298 1 : return true; 299 : } 300 1 : return false; 301 : } 302 : 303 : } /* end of namespace cpl */ 304 : 305 : #endif // DOXYGEN_SKIP 306 : //! @endcond 307 : 308 : /************************************************************************/ 309 : /* VSIInstallOSSFileHandler() */ 310 : /************************************************************************/ 311 : 312 : /*! 313 : \brief Install /vsioss/ Alibaba Cloud Object Storage Service (OSS) file 314 : system handler (requires libcurl) 315 : 316 : \verbatim embed:rst 317 : See :ref:`/vsioss/ documentation <vsioss>` 318 : \endverbatim 319 : 320 : @since GDAL 2.3 321 : */ 322 1304 : void VSIInstallOSSFileHandler(void) 323 : { 324 1304 : VSIFileManager::InstallHandler("/vsioss/", new cpl::VSIOSSFSHandler); 325 1304 : } 326 : 327 : #endif /* HAVE_CURL */