LCOV - code coverage report
Current view: top level - core/network - SPNetworkHandle.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 7 131 5.3 %
Date: 2024-05-12 00:16:13 Functions: 2 10 20.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2021 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 "SPNetworkHandle.h"
      25             : 
      26             : #include "SPString.h"
      27             : #include "SPStringView.h"
      28             : #include "SPLog.h"
      29             : #include "SPValid.h"
      30             : #include "SPCrypto.h"
      31             : #include "SPFilesystem.h"
      32             : #include "SPNetworkContext.h"
      33             : 
      34             : #if MODULE_STAPPLER_BITMAP
      35             : #include "SPBitmap.h"
      36             : #endif
      37             : 
      38             : #include "curl/curl.h"
      39             : 
      40             : namespace STAPPLER_VERSIONIZED stappler::network {
      41             : 
      42             : SPUNUSED static CURL *CurlHandle_alloc();
      43             : SPUNUSED static void CurlHandle_release(CURL *curl);
      44             : 
      45             : template <>
      46           0 : bool Handle<memory::PoolInterface>::init(Method method, StringView url) {
      47           0 :         if (url.size() == 0 || method == Method::Unknown) {
      48           0 :                 return false;
      49             :         }
      50             : 
      51           0 :         send.url = url.str<memory::PoolInterface>();
      52           0 :         send.method = method;
      53           0 :         return true;
      54             : }
      55             : 
      56             : template <>
      57        3025 : bool Handle<memory::StandartInterface>::init(Method method, StringView url) {
      58        3025 :         if (url.size() == 0 || method == Method::Unknown) {
      59           0 :                 return false;
      60             :         }
      61             : 
      62        3025 :         send.url = url.str<memory::StandartInterface>();
      63        3025 :         send.method = method;
      64        3025 :         return true;
      65             : }
      66             : 
      67             : template <>
      68           0 : bool Handle<memory::PoolInterface>::perform() {
      69           0 :         return network::perform(*this, nullptr, nullptr);
      70             : }
      71             : 
      72             : template <>
      73        3000 : bool Handle<memory::StandartInterface>::perform() {
      74        3000 :         return network::perform(*this, nullptr, nullptr);
      75             : }
      76             : 
      77             : template <>
      78           0 : bool MultiHandle<memory::PoolInterface>::perform(const Callback<bool(Handle<memory::PoolInterface> *, RefBase<memory::PoolInterface> *)> &cb) {
      79           0 :         auto m = curl_multi_init();
      80           0 :         memory::PoolInterface::MapType<CURL *, Context<memory::PoolInterface>> handles;
      81             : 
      82           0 :         auto initPending = [&, this] {
      83           0 :                 for (auto &it : pending) {
      84           0 :                         auto h = CurlHandle_alloc();
      85           0 :                         auto i = handles.emplace(h, Context<memory::PoolInterface>()).first;
      86           0 :                         i->second.userdata = it.second;
      87           0 :                         i->second.curl = h;
      88           0 :                         i->second.origHandle = it.first;
      89           0 :                         network::prepare(*it.first->getData(), &i->second, nullptr);
      90             : 
      91           0 :                         curl_multi_add_handle(m, h);
      92             :                 }
      93           0 :                 auto s = pending.size();
      94           0 :                 pending.clear();
      95           0 :                 return s;
      96           0 :         };
      97             : 
      98           0 :         auto cancel = [&] {
      99           0 :                 for (auto &it : handles) {
     100           0 :                         curl_multi_remove_handle(m, it.first);
     101           0 :                         it.second.code = CURLE_FAILED_INIT;
     102           0 :                         network::finalize(*it.second.handle, &it.second, nullptr);
     103             : 
     104           0 :                         CurlHandle_release(it.first);
     105             :                 }
     106           0 :                 curl_multi_cleanup(m);
     107           0 :         };
     108             : 
     109           0 :         handles.reserve(pending.size()); // mem_pool has non-std map::reserve
     110             : 
     111           0 :         int running = initPending();
     112             :         do {
     113           0 :                 auto err = curl_multi_perform(m, &running);
     114           0 :                 if (err != CURLM_OK) {
     115           0 :                         log::error("CURL", "Fail to perform multi: ", err);
     116           0 :                         return false;
     117             :                 }
     118             : 
     119           0 :                 if (running > 0) {
     120           0 :                         err = curl_multi_poll(m, NULL, 0, 1000, nullptr);
     121           0 :                         if (err != CURLM_OK) {
     122           0 :                                 log::error("CURL", "Fail to poll multi: ", err);
     123           0 :                                 return false;
     124             :                         }
     125             :                 }
     126             : 
     127           0 :                 struct CURLMsg *msg = nullptr;
     128             :                 do {
     129           0 :                         int msgq = 0;
     130           0 :                         msg = curl_multi_info_read(m, &msgq);
     131           0 :                         if (msg && (msg->msg == CURLMSG_DONE)) {
     132           0 :                                 CURL *e = msg->easy_handle;
     133           0 :                                 curl_multi_remove_handle(m, e);
     134             : 
     135           0 :                                 auto it = handles.find(e);
     136           0 :                                 if (it != handles.end()) {
     137           0 :                                         it->second.code = msg->data.result;
     138           0 :                                         network::finalize(*it->second.handle, &it->second, nullptr);
     139           0 :                                         if (cb) {
     140           0 :                                                 if (!cb(it->second.origHandle, it->second.userdata)) {
     141           0 :                                                         handles.erase(it);
     142           0 :                                                         cancel();
     143           0 :                                                         return false;
     144             :                                                 }
     145             :                                         }
     146           0 :                                         handles.erase(it);
     147             :                                 }
     148             : 
     149           0 :                                 CurlHandle_release(e);
     150             :                         }
     151           0 :                 } while (msg);
     152             : 
     153           0 :                 running += initPending();
     154           0 :         } while (running > 0);
     155             : 
     156           0 :         curl_multi_cleanup(m);
     157           0 :         return true;
     158           0 : }
     159             : 
     160             : template <>
     161           0 : bool MultiHandle<memory::StandartInterface>::perform(const Callback<bool(Handle<memory::StandartInterface> *, RefBase<memory::StandartInterface> *)> &cb) {
     162           0 :         auto m = curl_multi_init();
     163           0 :         memory::StandartInterface::MapType<CURL *, Context<memory::StandartInterface>> handles;
     164             : 
     165           0 :         auto initPending = [&, this] {
     166           0 :                 for (auto &it : pending) {
     167           0 :                         auto h = CurlHandle_alloc();
     168           0 :                         auto i = handles.emplace(h, Context<memory::StandartInterface>()).first;
     169           0 :                         i->second.userdata = it.second;
     170           0 :                         i->second.curl = h;
     171           0 :                         i->second.origHandle = it.first;
     172           0 :                         network::prepare(*it.first->getData(), &i->second, nullptr);
     173             : 
     174           0 :                         curl_multi_add_handle(m, h);
     175             :                 }
     176           0 :                 auto s = pending.size();
     177           0 :                 pending.clear();
     178           0 :                 return s;
     179           0 :         };
     180             : 
     181           0 :         auto cancel = [&] {
     182           0 :                 for (auto &it : handles) {
     183           0 :                         curl_multi_remove_handle(m, it.first);
     184           0 :                         it.second.code = CURLE_FAILED_INIT;
     185           0 :                         network::finalize(*it.second.handle, &it.second, nullptr);
     186             : 
     187           0 :                         CurlHandle_release(it.first);
     188             :                 }
     189           0 :                 curl_multi_cleanup(m);
     190           0 :         };
     191             : 
     192             :         // handles.reserve(pending.size());
     193             : 
     194           0 :         int running = initPending();
     195             :         do {
     196           0 :                 auto err = curl_multi_perform(m, &running);
     197           0 :                 if (err != CURLM_OK) {
     198           0 :                         log::error("CURL", string::toString<memory::StandartInterface>("Fail to perform multi: ", err));
     199           0 :                         return false;
     200             :                 }
     201             : 
     202           0 :                 if (running > 0) {
     203           0 :                         err = curl_multi_poll(m, NULL, 0, 1000, nullptr);
     204           0 :                         if (err != CURLM_OK) {
     205           0 :                                 log::error("CURL", string::toString<memory::StandartInterface>("Fail to poll multi: ", err));
     206           0 :                                 return false;
     207             :                         }
     208             :                 }
     209             : 
     210           0 :                 struct CURLMsg *msg = nullptr;
     211             :                 do {
     212           0 :                         int msgq = 0;
     213           0 :                         msg = curl_multi_info_read(m, &msgq);
     214           0 :                         if (msg && (msg->msg == CURLMSG_DONE)) {
     215           0 :                                 CURL *e = msg->easy_handle;
     216           0 :                                 curl_multi_remove_handle(m, e);
     217             : 
     218           0 :                                 auto it = handles.find(e);
     219           0 :                                 if (it != handles.end()) {
     220           0 :                                         it->second.code = msg->data.result;
     221           0 :                                         network::finalize(*it->second.handle, &it->second, nullptr);
     222           0 :                                         if (cb) {
     223           0 :                                                 if (!cb(it->second.origHandle, it->second.userdata)) {
     224           0 :                                                         handles.erase(it);
     225           0 :                                                         cancel();
     226           0 :                                                         return false;
     227             :                                                 }
     228             :                                         }
     229           0 :                                         handles.erase(it);
     230             :                                 }
     231             : 
     232           0 :                                 CurlHandle_release(e);
     233             :                         }
     234           0 :                 } while (msg);
     235             : 
     236           0 :                 running += initPending();
     237           0 :         } while (running > 0);
     238             : 
     239           0 :         curl_multi_cleanup(m);
     240           0 :         return true;
     241           0 : }
     242             : 
     243             : }

Generated by: LCOV version 1.14