ucb/source/ucp/webdav-curl/CurlSession.cxx       |   25 +++++++++++++++++------
 ucb/source/ucp/webdav-curl/CurlSession.hxx       |    3 ++
 ucb/source/ucp/webdav-curl/DAVResourceAccess.cxx |   14 +++++++++---
 ucb/source/ucp/webdav-curl/DAVResourceAccess.hxx |    2 -
 ucb/source/ucp/webdav-curl/webdavcontent.cxx     |    2 -
 5 files changed, 34 insertions(+), 12 deletions(-)

New commits:
commit 5d845fd02700c43352740cc9e675c91a6876e7d9
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Oct 26 13:52:29 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Nov 1 19:01:33 2021 +0100

    ucb: webdav-curl: implement CurlSession::abort()
    
    It looks like libcurl has an API to wake up a transfer in another
    thread, but have to use curl_multi_poll() instead of curl_multi_wait()
    to enable that.
    
    Change-Id: I728416eba45eb6665b0041955cdce8bee07e845e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124220
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/ucb/source/ucp/webdav-curl/CurlSession.cxx 
b/ucb/source/ucp/webdav-curl/CurlSession.cxx
index 76fdbce1bac5..6fb54998c531 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.cxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.cxx
@@ -589,11 +589,16 @@ auto CurlSession::UsesProxy() -> bool
 
 auto CurlSession::abort() -> void
 {
-    // this is using synchronous libcurl apis - no way to abort?
-    // might be possible with more complexity and CURLOPT_CONNECT_ONLY
-    // or curl_multi API, but is it worth the complexity?
-    // ... it looks like CURLOPT_CONNECT_ONLY would disable all HTTP handling.
-    // abort() was a no-op since OOo 3.2 and before that it crashed.
+    // note: abort() was a no-op since OOo 3.2 and before that it crashed.
+    bool expected(false);
+    // it would be pointless to lock m_Mutex here as the other thread holds it
+    if (m_AbortFlag.compare_exchange_strong(expected, true))
+    {
+        // This function looks safe to call without m_Mutex as long as the
+        // m_pCurlMulti handle is not destroyed, and the caller must own a ref
+        // to this object which keeps it alive; it should cause poll to return.
+        curl_multi_wakeup(m_pCurlMulti.get());
+    }
 }
 
 /// this is just a bunch of static member functions called from CurlSession
@@ -663,6 +668,10 @@ auto CurlProcessor::ProcessRequestImpl(
     ::std::pair<::std::vector<OUString> const&, DAVResource&> const* const 
pRequestedHeaders)
     -> void
 {
+    // Clear flag before transfer starts; only a transfer started before
+    // calling abort() will be aborted, not one started later.
+    rSession.m_AbortFlag.store(false);
+
     if (pEnv)
     { // add custom request headers passed by caller
         for (auto const& rHeader : pEnv->m_aRequestHeaders)
@@ -887,7 +896,7 @@ auto CurlProcessor::ProcessRequestImpl(
                 break;
             }
             int nFDs;
-            mc = curl_multi_wait(rSession.m_pCurlMulti.get(), nullptr, 0, 
rSession.m_nReadTimeout,
+            mc = curl_multi_poll(rSession.m_pCurlMulti.get(), nullptr, 0, 
rSession.m_nReadTimeout,
                                  &nFDs);
             if (mc != CURLM_OK)
             {
@@ -897,6 +906,10 @@ auto CurlProcessor::ProcessRequestImpl(
                     DAVException::DAV_HTTP_CONNECT,
                     ConnectionEndPointString(rSession.m_URI.GetHost(), 
rSession.m_URI.GetPort()));
             }
+            if (rSession.m_AbortFlag.load())
+            { // flag was set by abort() -> not sure what exception to throw?
+                throw DAVException(DAVException::DAV_HTTP_ERROR, "abort() was 
called", 0);
+            }
         } while (nRunning != 0);
         // there should be exactly 1 CURLMsg now, but the interface is
         // extensible so future libcurl versions could yield additional things
diff --git a/ucb/source/ucp/webdav-curl/CurlSession.hxx 
b/ucb/source/ucp/webdav-curl/CurlSession.hxx
index 67e4e3616aab..73b32096f6ea 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.hxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.hxx
@@ -14,6 +14,7 @@
 
 #include <curl/curl.h>
 
+#include <atomic>
 #include <mutex>
 
 namespace http_dav_ucp
@@ -37,6 +38,8 @@ private:
     bool m_isAuthenticatedProxy = false;
     /// read timeout in milliseconds (connection timeout is stored in m_pCurl)
     int m_nReadTimeout = 0;
+    /// flag to signal abort to transferring thread
+    ::std::atomic<bool> m_AbortFlag;
 
     /// libcurl multi handle
     ::std::unique_ptr<CURLM, deleter_from_fn<curl_multi_cleanup>> m_pCurlMulti;
diff --git a/ucb/source/ucp/webdav-curl/DAVResourceAccess.cxx 
b/ucb/source/ucp/webdav-curl/DAVResourceAccess.cxx
index a6bfd7d79642..248d65b8c60c 100644
--- a/ucb/source/ucp/webdav-curl/DAVResourceAccess.cxx
+++ b/ucb/source/ucp/webdav-curl/DAVResourceAccess.cxx
@@ -570,10 +570,16 @@ void DAVResourceAccess::GET(
 
 void DAVResourceAccess::abort()
 {
-    // 17.11.09 (tkr): abort currently disabled caused by issue i106766
-    // initialize();
-    // m_xSession->abort();
-    SAL_INFO("ucb.ucp.webdav",  "Not implemented. -> #i106766#" );
+    // seems pointless to call initialize() here, but prepare for nullptr
+    decltype(m_xSession) xSession;
+    {
+        osl::Guard<osl::Mutex> const g(m_aMutex);
+        xSession = m_xSession;
+    }
+    if (xSession.is())
+    {
+        xSession->abort();
+    }
 }
 
 
diff --git a/ucb/source/ucp/webdav-curl/DAVResourceAccess.hxx 
b/ucb/source/ucp/webdav-curl/DAVResourceAccess.hxx
index 1abde0fe2d8e..df27713a936d 100644
--- a/ucb/source/ucp/webdav-curl/DAVResourceAccess.hxx
+++ b/ucb/source/ucp/webdav-curl/DAVResourceAccess.hxx
@@ -194,7 +194,7 @@ public:
 
     /// @throws DAVException
     void
-    static abort();
+    abort();
 
     // helper
     static void
diff --git a/ucb/source/ucp/webdav-curl/webdavcontent.cxx 
b/ucb/source/ucp/webdav-curl/webdavcontent.cxx
index dc9b373ed5b1..a49969f3902f 100644
--- a/ucb/source/ucp/webdav-curl/webdavcontent.cxx
+++ b/ucb/source/ucp/webdav-curl/webdavcontent.cxx
@@ -781,7 +781,7 @@ void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
             osl::MutexGuard aGuard( m_aMutex );
             xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
         }
-        DAVResourceAccess::abort();
+        xResAccess->abort();
         {
             osl::Guard< osl::Mutex > aGuard( m_aMutex );
             m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );

Reply via email to