LCOV - code coverage report
Current view: top level - core/network - SPNetwork.scu.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 35 94 37.2 %
Date: 2024-05-12 00:16:13 Functions: 9 19 47.4 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPCommon.h"
      25             : #include "SPNetworkContext.h"
      26             : #include "SPNetworkData.h"
      27             : #include "SPNetworkHandle.h"
      28             : 
      29             : #ifdef __MINGW32__
      30             : #define CURL_STATICLIB 1
      31             : #endif
      32             : 
      33             : #ifdef LINUX
      34             : // In linux, MIME types for downloaded files defined in extra FS attributes
      35             : #include <sys/types.h>
      36             : #include <sys/xattr.h>
      37             : #include <sys/stat.h>
      38             : #include <fcntl.h>
      39             : #endif
      40             : 
      41             : #define SP_NETWORK_LOG(...)
      42             : //#define SP_NETWORK_LOG(...) log::format("Network", __VA_ARGS__)
      43             : 
      44             : namespace STAPPLER_VERSIONIZED stappler::network {
      45             : 
      46             : static constexpr auto NetworkUserdataKey = "org.stappler.Network.Handle";
      47             : 
      48             : struct CurlHandle {
      49             : public:
      50          25 :         static CURL *alloc() {
      51          25 :                 ++ s_activeHandles;
      52          25 :                 return curl_easy_init();
      53             :         }
      54             : 
      55           0 :         static void release(CURL *curl) {
      56           0 :                 -- s_activeHandles;
      57           0 :                 curl_easy_cleanup(curl);
      58           0 :         }
      59             : 
      60        3000 :         static CURL * getHandle(bool reuse, memory::pool_t *pool) {
      61        3000 :                 if (reuse) {
      62        3000 :                         if (pool) {
      63           0 :                                 void *data = nullptr;
      64           0 :                                 memory::pool::userdata_get(&data, NetworkUserdataKey, pool);
      65           0 :                                 if (!data) {
      66           0 :                                         data = new CurlHandle();
      67           0 :                                         memory::pool::userdata_set(data, NetworkUserdataKey, [] (void *obj) {
      68           0 :                                                 ((CurlHandle *)obj)->~CurlHandle();
      69           0 :                                                 return 0;
      70             :                                         }, pool);
      71             :                                 }
      72             : 
      73           0 :                                 return ((CurlHandle *)data)->get();
      74        3000 :                         } else if (!tl_handle) {
      75          25 :                                 tl_handle = new CurlHandle();
      76             :                         }
      77        3000 :                         return tl_handle->get();
      78             :                 } else {
      79           0 :                         return CurlHandle::alloc();
      80             :                 }
      81             :         }
      82             : 
      83        3000 :         static void releaseHandle(CURL *curl, bool reuse, bool success, memory::pool_t *pool) {
      84        3000 :                 if (!reuse) {
      85           0 :                         CurlHandle::release(curl);
      86        3000 :                 } else if (pool) {
      87           0 :                         void *data = nullptr;
      88           0 :                         memory::pool::userdata_get(&data, NetworkUserdataKey, pool);
      89           0 :                         if (data) {
      90           0 :                                 if (!success) {
      91           0 :                                         ((CurlHandle *)data)->invalidate(curl);
      92             :                                 } else {
      93           0 :                                         ((CurlHandle *)data)->reset();
      94             :                                 }
      95             :                         } else {
      96           0 :                                 CurlHandle::release(curl);
      97             :                         }
      98        3000 :                 } else if (tl_handle) {
      99        3000 :                         if (!success) {
     100          75 :                                 tl_handle->invalidate(curl);
     101             :                         } else {
     102        2925 :                                 tl_handle->reset();
     103             :                         }
     104             :                 } else {
     105           0 :                         CurlHandle::release(curl);
     106             :                 }
     107        3000 :         }
     108             : 
     109           0 :         static uint32_t getActiveHandles() {
     110           0 :                 return s_activeHandles;
     111             :         }
     112             : 
     113          25 :         CurlHandle() {
     114          25 :                 _curl = alloc();
     115          25 :         }
     116             : 
     117             :         CurlHandle(CurlHandle &&other) : _curl(other._curl) {
     118             :                 other._curl = nullptr;
     119             :         }
     120             : 
     121             :         CurlHandle & operator = (CurlHandle &&other) {
     122             :                 _curl = other._curl;
     123             :                 other._curl = nullptr;
     124             :                 return *this;
     125             :         }
     126             : 
     127             :         CurlHandle(const CurlHandle &) = delete;
     128             :         CurlHandle & operator = (const CurlHandle &) = delete;
     129             : 
     130           0 :         ~CurlHandle() {
     131           0 :                 if (_curl) {
     132           0 :                         release(_curl);
     133           0 :                         _curl = nullptr;
     134             :                 }
     135           0 :         }
     136             : 
     137        3000 :         CURL *get() { return _curl; }
     138             :         explicit operator bool () { return _curl != nullptr; }
     139             : 
     140          75 :         void invalidate(CURL * curl) {
     141          75 :                 if (_curl == curl) {
     142          75 :                         curl_easy_cleanup(_curl);
     143          75 :                         _curl = curl_easy_init();
     144             :                 }
     145          75 :         }
     146             : 
     147        2925 :         void reset() {
     148        2925 :                 if (_curl) {
     149        2925 :                         curl_easy_reset(_curl);
     150             :                 }
     151        2925 :         }
     152             : 
     153             : protected:
     154             :         CURL *_curl = nullptr;
     155             :         static std::atomic<uint32_t> s_activeHandles;
     156             :         static thread_local CurlHandle *tl_handle;
     157             : };
     158             : 
     159             : std::atomic<uint32_t> CurlHandle::s_activeHandles = 0;
     160             : thread_local CurlHandle *CurlHandle::tl_handle = nullptr;
     161             : 
     162           0 : SPUNUSED static CURL *CurlHandle_alloc() {
     163           0 :         return CurlHandle::alloc();
     164             : }
     165             : 
     166           0 : SPUNUSED static void CurlHandle_release(CURL *curl) {
     167           0 :         CurlHandle::release(curl);
     168           0 : }
     169             : 
     170        3000 : SPUNUSED static CURL * CurlHandle_getHandle(bool reuse, memory::pool_t *pool) {
     171        3000 :         return CurlHandle::getHandle(reuse, pool);
     172             : }
     173             : 
     174        3000 : SPUNUSED static void CurlHandle_releaseHandle(CURL *curl, bool reuse, bool success, memory::pool_t *pool) {
     175        3000 :         CurlHandle::releaseHandle(curl, reuse, success, pool);
     176        3000 : }
     177             : 
     178           0 : uint32_t getActiveHandles() {
     179           0 :         return CurlHandle::getActiveHandles();
     180             : }
     181             : 
     182             : #ifdef LINUX
     183             : 
     184           0 : static bool network_setUserAttributes(FILE *file, const StringView &str, Time mtime) {
     185           0 :         if (int fd = fileno(file)) {
     186           0 :                 auto err = fsetxattr(fd, "user.mime_type", str.data(), str.size(), XATTR_CREATE);
     187           0 :                 if (err != 0) {
     188           0 :                         err = fsetxattr(fd, "user.mime_type", str.data(), str.size(), XATTR_REPLACE);
     189           0 :                         if (err != 0) {
     190           0 :                                 std::cout << "Fail to set mime type attribute (" << err << ")\n";
     191           0 :                                 return false;
     192             :                         }
     193             :                 }
     194             : 
     195           0 :                 if (mtime != nullptr) {
     196             :                         struct timespec times[2];
     197           0 :                         times[0].tv_nsec = UTIME_OMIT;
     198             : 
     199           0 :                         times[1].tv_sec = time_t(mtime.sec());
     200           0 :                         times[1].tv_nsec = (mtime.toMicroseconds() - Time::seconds(mtime.sec()).toMicroseconds()) * 1000;
     201           0 :                         futimens(fd, times);
     202             :                 }
     203             : 
     204           0 :                 return true;
     205             :         }
     206           0 :         return false;
     207             : }
     208             : 
     209             : template <typename Interface>
     210           0 : static auto network_getUserMime(const StringView &filename) -> typename Interface::StringType {
     211           0 :         auto path = filepath::absolute<Interface>(filename);
     212             : 
     213           0 :         char buf[1_KiB] = { 0 };
     214           0 :         auto vallen = getxattr(path.data(), "user.mime_type", buf, 1_KiB);
     215           0 :         if (vallen == -1) {
     216           0 :                 return typename Interface::StringType();
     217             :         }
     218             : 
     219           0 :         return StringView(buf, vallen).str<Interface>();
     220           0 : }
     221             : 
     222             : #endif
     223             : 
     224             : 
     225             : }
     226             : 
     227             : #include "SPNetworkCABundle.cc"
     228             : #include "SPNetworkSetup.cc"
     229             : #include "SPNetworkData.cc"
     230             : #include "SPNetworkHandle.cc"
     231             : 
     232             : //#include "SPNetworkMultiHandle.cc"

Generated by: LCOV version 1.14