summaryrefslogtreecommitdiff
path: root/ucb
diff options
context:
space:
mode:
authorMichael Stahl <michael.stahl@allotropia.de>2021-10-22 17:09:30 +0200
committerMichael Stahl <michael.stahl@allotropia.de>2021-11-01 18:56:07 +0100
commitcd3daf7f6e7842e96f60a85cb791b18bfcc0d7b3 (patch)
tree6645c0e2ac3d30548156435a03f0425035a52c67 /ucb
parent3f2c3acfac2c699820f1a7e66a485ad98d5d92ab (diff)
ucb: webdav-curl: convert URI reference to URI as early as possible
Ensure that LockStore uses the full URL as key, not just the path. Change-Id: I84caf0d22e8c0ba176c19d004ee8ffcd2fdd05c8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124077 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'ucb')
-rw-r--r--ucb/source/ucp/webdav-curl/CurlSession.cxx248
-rw-r--r--ucb/source/ucp/webdav-curl/CurlSession.hxx6
-rw-r--r--ucb/source/ucp/webdav-curl/CurlUri.cxx41
-rw-r--r--ucb/source/ucp/webdav-curl/CurlUri.hxx5
-rw-r--r--ucb/source/ucp/webdav-curl/SerfLockStore.cxx22
-rw-r--r--ucb/source/ucp/webdav-curl/SerfLockStore.hxx6
6 files changed, 207 insertions, 121 deletions
diff --git a/ucb/source/ucp/webdav-curl/CurlSession.cxx b/ucb/source/ucp/webdav-curl/CurlSession.cxx
index b0c1c4c7e2ac..7c5bd5fe5973 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.cxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.cxx
@@ -588,16 +588,17 @@ auto CurlSession::abort() -> void
/// this is just a bunch of static member functions called from CurlSession
struct CurlProcessor
{
+ static auto URIReferenceToURI(CurlSession& rSession, OUString const& rURIReference) -> CurlUri;
+
static auto ProcessRequestImpl(
- CurlSession& rSession, ::std::u16string_view rURIReference,
- DAVRequestEnvironment const* pEnv,
+ CurlSession& rSession, CurlUri const& rURI, DAVRequestEnvironment const* pEnv,
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pRequestHeaderList,
uno::Reference<io::XOutputStream> const* pxOutStream,
uno::Reference<io::XInputStream> const* pxInStream,
::std::pair<::std::vector<OUString> const&, DAVResource&> const* pRequestedHeaders) -> void;
static auto ProcessRequest(
- Guard& rGuard, CurlSession& rSession, OUString const& rURIReference,
+ Guard& rGuard, CurlSession& rSession, CurlUri const& rURI,
DAVRequestEnvironment const* pEnv,
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pRequestHeaderList,
uno::Reference<io::XOutputStream> const* pxOutStream,
@@ -605,7 +606,7 @@ struct CurlProcessor
::std::pair<::std::vector<OUString> const&, DAVResource&> const* pRequestedHeaders) -> void;
static auto
- PropFind(CurlSession& rSession, OUString const& rURIReference, Depth depth,
+ PropFind(CurlSession& rSession, CurlUri const& rURI, Depth depth,
::std::tuple<::std::vector<OUString> const&, ::std::vector<DAVResource>* const,
::std::vector<ucb::Lock>* const> const* o_pRequestedProperties,
::std::vector<DAVResourceInfo>* const o_pResourceInfos,
@@ -616,19 +617,35 @@ struct CurlProcessor
bool isOverwrite, char const* pMethod) -> void;
static auto
- Lock(CurlSession& rSession, OUString const& rURIReference, DAVRequestEnvironment const* pEnv,
+ Lock(CurlSession& rSession, CurlUri const& rURI, DAVRequestEnvironment const* pEnv,
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pRequestHeaderList,
uno::Reference<io::XInputStream> const* pxInStream)
-> ::std::vector<::std::pair<ucb::Lock, sal_Int32>>;
- static auto Unlock(CurlSession& rSession, OUString const& rURIReference,
+ static auto Unlock(CurlSession& rSession, CurlUri const& rURI,
DAVRequestEnvironment const* pEnv) -> void;
};
+auto CurlProcessor::URIReferenceToURI(CurlSession& rSession, OUString const& rURIReference)
+ -> CurlUri
+{
+ // No need to acquire rSession.m_Mutex because accessed members are const.
+ if (rSession.UsesProxy())
+ // very odd, but see DAVResourceAccess::getRequestURI() :-/
+ {
+ assert(rURIReference.startsWith("http://") || rURIReference.startsWith("https://"));
+ return CurlUri(rURIReference);
+ }
+ else
+ {
+ assert(rURIReference.startsWith("/") && !rURIReference.startsWith("//"));
+ return rSession.m_URI.CloneWithRelativeRefPathAbsolute(rURIReference);
+ }
+}
+
/// main function to initiate libcurl requests
auto CurlProcessor::ProcessRequestImpl(
- CurlSession& rSession, ::std::u16string_view const rURIReference,
- DAVRequestEnvironment const* const pEnv,
+ CurlSession& rSession, CurlUri const& rURI, DAVRequestEnvironment const* const pEnv,
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pRequestHeaderList,
uno::Reference<io::XOutputStream> const* const pxOutStream,
uno::Reference<io::XInputStream> const* const pxInStream,
@@ -681,20 +698,7 @@ auto CurlProcessor::ProcessRequestImpl(
(void)rc;
}
- ::std::unique_ptr<CURLU, deleter_from_fn<curl_url_cleanup>> const pUrl(
- rSession.m_URI.CloneCURLU());
- OString const utf8URIRef(OUStringToOString(rURIReference, RTL_TEXTENCODING_UTF8));
- auto uc = curl_url_set(pUrl.get(),
- // very odd, but see DAVResourceAccess::getRequestURI() :-/
- rSession.UsesProxy() ? CURLUPART_URL : CURLUPART_PATH,
- utf8URIRef.getStr(), 0);
- if (uc != CURLUE_OK)
- {
- SAL_WARN("ucb.ucp.webdav.curl", "curl_url_set failed: " << uc);
- throw DAVException(DAVException::DAV_INVALID_ARG);
- }
-
- auto rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_CURLU, pUrl.get());
+ auto rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_CURLU, rURI.GetCURLU());
assert(rc == CURLE_OK); // can't fail since 7.63.0
// authentication data may be in the URI, or requested via XInteractionHandler
@@ -730,16 +734,15 @@ auto CurlProcessor::ProcessRequestImpl(
// TODO: why is there this m_aRequestURI and also rURIReference argument?
// ... only caller is DAVResourceAccess - always identical except MOVE/COPY
// which doesn't work if it's just a URI reference so let's just use
- // rURIReference via pUrl instead
+ // rURIReference via rURI instead
#if 0
CurlUri const uri(pEnv->m_aRequestURI);
#endif
- CurlUri const uri(*pUrl);
// note: due to parsing bug pwd didn't work in previous webdav ucps
if (pEnv && !rSession.m_isAuthenticated
- && (!uri.GetUser().isEmpty() || !uri.GetPassword().isEmpty()))
+ && (!rURI.GetUser().isEmpty() || !rURI.GetPassword().isEmpty()))
{
- oAuth.emplace(uri.GetUser(), uri.GetPassword(), CURLAUTH_ANY);
+ oAuth.emplace(rURI.GetUser(), rURI.GetPassword(), CURLAUTH_ANY);
}
if (pRequestedHeaders)
{
@@ -748,7 +751,7 @@ auto CurlProcessor::ProcessRequestImpl(
// But it looks like all consumers of this .uri are interested
// only in the path, so it shouldn't make a difference to give
// the entire URI when the caller extracts the path anyway.
- pRequestedHeaders->second.uri = uri.GetURI();
+ pRequestedHeaders->second.uri = rURI.GetURI();
pRequestedHeaders->second.properties.clear();
}
}
@@ -1007,7 +1010,7 @@ auto CurlProcessor::ProcessRequestImpl(
}
}
-static auto TryRemoveExpiredLockToken(CurlSession& rSession, OUString const& rURIReference,
+static auto TryRemoveExpiredLockToken(CurlSession& rSession, CurlUri const& rURI,
DAVRequestEnvironment const* const pEnv) -> bool
{
if (!pEnv)
@@ -1015,7 +1018,7 @@ static auto TryRemoveExpiredLockToken(CurlSession& rSession, OUString const& rUR
// caller was a NonInteractive_*LOCK function anyway, its caller is LockStore
return false;
}
- OUString const* const pToken(g_Init.LockStore.getLockTokenForURI(rURIReference, nullptr));
+ OUString const* const pToken(g_Init.LockStore.getLockTokenForURI(rURI.GetURI(), nullptr));
if (!pToken)
{
return false;
@@ -1028,7 +1031,7 @@ static auto TryRemoveExpiredLockToken(CurlSession& rSession, OUString const& rUR
::std::tuple<::std::vector<OUString> const&, ::std::vector<DAVResource>* const,
::std::vector<ucb::Lock>* const> const args(propertyNames, nullptr, &locks);
- CurlProcessor::PropFind(rSession, rURIReference, DAVZERO, &args, nullptr, *pEnv);
+ CurlProcessor::PropFind(rSession, rURI, DAVZERO, &args, nullptr, *pEnv);
// https://datatracker.ietf.org/doc/html/rfc4918#section-15.8
// The response MAY not contain tokens, but hopefully it
@@ -1043,8 +1046,8 @@ static auto TryRemoveExpiredLockToken(CurlSession& rSession, OUString const& rUR
}
SAL_INFO("ucb.ucp.webdav.curl",
- "lock token expired, removing: " << rURIReference << " " << *pToken);
- g_Init.LockStore.removeLock(rURIReference);
+ "lock token expired, removing: " << rURI.GetURI() << " " << *pToken);
+ g_Init.LockStore.removeLock(rURI.GetURI());
return true;
}
catch (DAVException const&)
@@ -1054,7 +1057,7 @@ static auto TryRemoveExpiredLockToken(CurlSession& rSession, OUString const& rUR
}
auto CurlProcessor::ProcessRequest(
- Guard& rGuard, CurlSession& rSession, OUString const& rURIReference,
+ Guard& rGuard, CurlSession& rSession, CurlUri const& rURI,
DAVRequestEnvironment const* const pEnv,
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pRequestHeaderList,
uno::Reference<io::XOutputStream> const* const pxOutStream,
@@ -1064,8 +1067,8 @@ auto CurlProcessor::ProcessRequest(
{
try
{
- ProcessRequestImpl(rSession, rURIReference, pEnv, ::std::move(pRequestHeaderList),
- pxOutStream, pxInStream, pRequestedHeaders);
+ ProcessRequestImpl(rSession, rURI, pEnv, ::std::move(pRequestHeaderList), pxOutStream,
+ pxInStream, pRequestedHeaders);
}
catch (DAVException const& rException)
{
@@ -1077,7 +1080,7 @@ auto CurlProcessor::ProcessRequest(
case SC_LOCKED:
{
rGuard.unlock(); // release m_Mutex before accessing LockStore
- if (g_Init.LockStore.getLockTokenForURI(rURIReference, nullptr))
+ if (g_Init.LockStore.getLockTokenForURI(rURI.GetURI(), nullptr))
{
throw DAVException(DAVException::DAV_LOCKED_SELF);
}
@@ -1095,7 +1098,7 @@ auto CurlProcessor::ProcessRequest(
// the expiration of a lock.
// Initiate a new request *outside* ProcessRequestImpl
// *after* rGuard.unlock() to avoid messing up m_pCurl state.
- if (TryRemoveExpiredLockToken(rSession, rURIReference, pEnv))
+ if (TryRemoveExpiredLockToken(rSession, rURI, pEnv))
{
throw DAVException(DAVException::DAV_LOCK_EXPIRED);
}
@@ -1115,6 +1118,8 @@ auto CurlSession::OPTIONS(OUString const& rURIReference,
rOptions.init();
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
::std::vector<OUString> const headerNames{ "allow", "dav" };
DAVResource result;
::std::pair<::std::vector<OUString> const&, DAVResource&> const headers(headerNames, result);
@@ -1140,8 +1145,7 @@ auto CurlSession::OPTIONS(OUString const& rURIReference,
ConnectionEndPointString(m_URI.GetHost(), m_URI.GetPort()));
}
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, nullptr, nullptr,
- &headers);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, nullptr, nullptr, &headers);
}
for (auto const& it : result.properties)
@@ -1180,7 +1184,7 @@ auto CurlSession::OPTIONS(OUString const& rURIReference,
}
if (rOptions.isClass2() || rOptions.isClass3())
{
- if (g_Init.LockStore.getLockTokenForURI(rURIReference, nullptr))
+ if (g_Init.LockStore.getLockTokenForURI(uri.GetURI(), nullptr))
{
rOptions.setLocked();
}
@@ -1188,7 +1192,7 @@ auto CurlSession::OPTIONS(OUString const& rURIReference,
}
auto CurlProcessor::PropFind(
- CurlSession& rSession, OUString const& rURIReference, Depth const nDepth,
+ CurlSession& rSession, CurlUri const& rURI, Depth const nDepth,
::std::tuple<::std::vector<OUString> const&, ::std::vector<DAVResource>* const,
::std::vector<ucb::Lock>* const> const* const o_pRequestedProperties,
::std::vector<DAVResourceInfo>* const o_pResourceInfos, DAVRequestEnvironment const& rEnv)
@@ -1294,8 +1298,8 @@ auto CurlProcessor::PropFind(
assert(xResponseInStream.is());
assert(xResponseOutStream.is());
- CurlProcessor::ProcessRequest(g, rSession, rURIReference, &rEnv, ::std::move(pList),
- &xResponseOutStream, &xRequestInStream, nullptr);
+ CurlProcessor::ProcessRequest(g, rSession, rURI, &rEnv, ::std::move(pList), &xResponseOutStream,
+ &xRequestInStream, nullptr);
if (o_pResourceInfos)
{
@@ -1322,10 +1326,13 @@ auto CurlSession::PROPFIND(OUString const& rURIReference, Depth const depth,
DAVRequestEnvironment const& rEnv) -> void
{
SAL_INFO("ucb.ucp.webdav.curl", "PROPFIND: " << rURIReference << " " << depth);
+
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
::std::tuple<::std::vector<OUString> const&, ::std::vector<DAVResource>* const,
::std::vector<ucb::Lock>* const> const args(rPropertyNames, &o_rResources,
nullptr);
- return CurlProcessor::PropFind(*this, rURIReference, depth, &args, nullptr, rEnv);
+ return CurlProcessor::PropFind(*this, uri, depth, &args, nullptr, rEnv);
}
auto CurlSession::PROPFIND(OUString const& rURIReference, Depth const depth,
@@ -1333,7 +1340,10 @@ auto CurlSession::PROPFIND(OUString const& rURIReference, Depth const depth,
DAVRequestEnvironment const& rEnv) -> void
{
SAL_INFO("ucb.ucp.webdav.curl", "PROPFIND: " << rURIReference << " " << depth);
- return CurlProcessor::PropFind(*this, rURIReference, depth, nullptr, &o_rResourceInfos, rEnv);
+
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
+ return CurlProcessor::PropFind(*this, uri, depth, nullptr, &o_rResourceInfos, rEnv);
}
auto CurlSession::PROPPATCH(OUString const& rURIReference,
@@ -1342,6 +1352,8 @@ auto CurlSession::PROPPATCH(OUString const& rURIReference,
{
SAL_INFO("ucb.ucp.webdav.curl", "PROPPATCH: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
//FIXME why does toXML encode stuff which parser ignores
//isUCBDeadProperty case not handled
@@ -1416,7 +1428,7 @@ auto CurlSession::PROPPATCH(OUString const& rURIReference,
xWriter->endDocument();
xRequestOutStream->closeOutput();
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, ::std::move(pList), nullptr,
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, ::std::move(pList), nullptr,
&xRequestInStream, nullptr);
}
@@ -1425,6 +1437,8 @@ auto CurlSession::HEAD(OUString const& rURIReference, ::std::vector<OUString> co
{
SAL_INFO("ucb.ucp.webdav.curl", "HEAD: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
Guard g(m_Mutex, [&]() {
auto rc = curl_easy_setopt(m_pCurl.get(), CURLOPT_NOBODY, 0L);
assert(rc == CURLE_OK);
@@ -1437,8 +1451,7 @@ auto CurlSession::HEAD(OUString const& rURIReference, ::std::vector<OUString> co
::std::pair<::std::vector<OUString> const&, DAVResource&> const headers(rHeaderNames,
io_rResource);
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, nullptr, nullptr,
- &headers);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, nullptr, nullptr, &headers);
}
auto CurlSession::GET(OUString const& rURIReference, DAVRequestEnvironment const& rEnv)
@@ -1446,6 +1459,8 @@ auto CurlSession::GET(OUString const& rURIReference, DAVRequestEnvironment const
{
SAL_INFO("ucb.ucp.webdav.curl", "GET: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
// could use either com.sun.star.io.Pipe or com.sun.star.io.SequenceInputStream?
// Pipe can just write into its XOuputStream, which is simpler.
// Both resize exponentially, so performance should be fine.
@@ -1465,8 +1480,8 @@ auto CurlSession::GET(OUString const& rURIReference, DAVRequestEnvironment const
assert(rc == CURLE_OK);
(void)rc;
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, &xResponseOutStream,
- nullptr, nullptr);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, &xResponseOutStream, nullptr,
+ nullptr);
uno::Reference<io::XInputStream> const xResponseInStream(
io::SequenceInputStream::createStreamFromSequence(m_xContext,
@@ -1481,6 +1496,8 @@ auto CurlSession::GET(OUString const& rURIReference, uno::Reference<io::XOutputS
{
SAL_INFO("ucb.ucp.webdav.curl", "GET: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
Guard g(m_Mutex, [&]() {
auto rc = curl_easy_setopt(m_pCurl.get(), CURLOPT_HTTPGET, 0L);
assert(rc == CURLE_OK);
@@ -1490,8 +1507,7 @@ auto CurlSession::GET(OUString const& rURIReference, uno::Reference<io::XOutputS
assert(rc == CURLE_OK);
(void)rc;
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, &rxOutStream, nullptr,
- nullptr);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, &rxOutStream, nullptr, nullptr);
}
auto CurlSession::GET(OUString const& rURIReference, ::std::vector<OUString> const& rHeaderNames,
@@ -1500,6 +1516,8 @@ auto CurlSession::GET(OUString const& rURIReference, ::std::vector<OUString> con
{
SAL_INFO("ucb.ucp.webdav.curl", "GET: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
Guard g(m_Mutex, [&]() {
auto rc = curl_easy_setopt(m_pCurl.get(), CURLOPT_HTTPGET, 0L);
assert(rc == CURLE_OK);
@@ -1517,8 +1535,8 @@ auto CurlSession::GET(OUString const& rURIReference, ::std::vector<OUString> con
::std::pair<::std::vector<OUString> const&, DAVResource&> const headers(rHeaderNames,
io_rResource);
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, &xResponseOutStream,
- nullptr, &headers);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, &xResponseOutStream, nullptr,
+ &headers);
uno::Reference<io::XInputStream> const xResponseInStream(
io::SequenceInputStream::createStreamFromSequence(m_xContext,
@@ -1534,6 +1552,8 @@ auto CurlSession::GET(OUString const& rURIReference, uno::Reference<io::XOutputS
{
SAL_INFO("ucb.ucp.webdav.curl", "GET: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
Guard g(m_Mutex, [&]() {
auto rc = curl_easy_setopt(m_pCurl.get(), CURLOPT_HTTPGET, 0L);
assert(rc == CURLE_OK);
@@ -1546,8 +1566,7 @@ auto CurlSession::GET(OUString const& rURIReference, uno::Reference<io::XOutputS
::std::pair<::std::vector<OUString> const&, DAVResource&> const headers(rHeaderNames,
io_rResource);
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, &rxOutStream, nullptr,
- &headers);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, &rxOutStream, nullptr, &headers);
}
auto CurlSession::PUT(OUString const& rURIReference,
@@ -1556,6 +1575,8 @@ auto CurlSession::PUT(OUString const& rURIReference,
{
SAL_INFO("ucb.ucp.webdav.curl", "PUT: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
// TODO: either set CURLOPT_INFILESIZE_LARGE or chunked?
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pList(
curl_slist_append(nullptr, "Transfer-Encoding: chunked"));
@@ -1563,8 +1584,7 @@ auto CurlSession::PUT(OUString const& rURIReference,
{
throw uno::RuntimeException("curl_slist_append failed");
}
- // TODO: why is a *global* LockStore keyed by *path*?
- OUString const token(g_Init.LockStore.getLockToken(rURIReference));
+ OUString const token(g_Init.LockStore.getLockToken(uri.GetURI()));
if (!token.isEmpty())
{
OString const utf8If("If: <" + OUStringToOString(rURIReference, RTL_TEXTENCODING_ASCII_US)
@@ -1579,8 +1599,8 @@ auto CurlSession::PUT(OUString const& rURIReference,
// lock m_Mutex after accessing global LockStore to avoid deadlock
Guard g(m_Mutex);
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, ::std::move(pList), nullptr,
- &rxInStream, nullptr);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, ::std::move(pList), nullptr, &rxInStream,
+ nullptr);
}
auto CurlSession::POST(OUString const& rURIReference, OUString const& rContentType,
@@ -1589,6 +1609,8 @@ auto CurlSession::POST(OUString const& rURIReference, OUString const& rContentTy
{
SAL_INFO("ucb.ucp.webdav.curl", "POST: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
// TODO: either set CURLOPT_POSTFIELDSIZE_LARGE or chunked?
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pList(
curl_slist_append(nullptr, "Transfer-Encoding: chunked"));
@@ -1625,8 +1647,8 @@ auto CurlSession::POST(OUString const& rURIReference, OUString const& rContentTy
uno::Reference<io::XOutputStream> const xResponseOutStream(xSeqOutStream);
assert(xResponseOutStream.is());
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, ::std::move(pList),
- &xResponseOutStream, &rxInStream, nullptr);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, ::std::move(pList), &xResponseOutStream,
+ &rxInStream, nullptr);
uno::Reference<io::XInputStream> const xResponseInStream(
io::SequenceInputStream::createStreamFromSequence(m_xContext,
@@ -1643,6 +1665,8 @@ auto CurlSession::POST(OUString const& rURIReference, OUString const& rContentTy
{
SAL_INFO("ucb.ucp.webdav.curl", "POST: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
// TODO: either set CURLOPT_POSTFIELDSIZE_LARGE or chunked?
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pList(
curl_slist_append(nullptr, "Transfer-Encoding: chunked"));
@@ -1674,7 +1698,7 @@ auto CurlSession::POST(OUString const& rURIReference, OUString const& rContentTy
assert(rc == CURLE_OK);
(void)rc;
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, ::std::move(pList), &rxOutStream,
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, ::std::move(pList), &rxOutStream,
&rxInStream, nullptr);
}
@@ -1682,6 +1706,8 @@ auto CurlSession::MKCOL(OUString const& rURIReference, DAVRequestEnvironment con
{
SAL_INFO("ucb.ucp.webdav.curl", "MKCOL: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
Guard g(m_Mutex, [&]() {
auto rc = curl_easy_setopt(m_pCurl.get(), CURLOPT_CUSTOMREQUEST, nullptr);
assert(rc == CURLE_OK);
@@ -1695,8 +1721,7 @@ auto CurlSession::MKCOL(OUString const& rURIReference, DAVRequestEnvironment con
ConnectionEndPointString(m_URI.GetHost(), m_URI.GetPort()));
}
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, nullptr, nullptr,
- nullptr);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, nullptr, nullptr, nullptr);
}
auto CurlProcessor::MoveOrCopy(CurlSession& rSession, OUString const& rSourceURIReference,
@@ -1704,6 +1729,8 @@ auto CurlProcessor::MoveOrCopy(CurlSession& rSession, OUString const& rSourceURI
DAVRequestEnvironment const& rEnv, bool const isOverwrite,
char const* const pMethod) -> void
{
+ CurlUri const uriSource(CurlProcessor::URIReferenceToURI(rSession, rSourceURIReference));
+
OString const utf8Destination("Destination: "
+ OUStringToOString(rDestinationURI, RTL_TEXTENCODING_ASCII_US));
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pList(
@@ -1729,8 +1756,8 @@ auto CurlProcessor::MoveOrCopy(CurlSession& rSession, OUString const& rSourceURI
assert(rc == CURLE_OK);
(void)rc;
- CurlProcessor::ProcessRequest(g, rSession, rSourceURIReference, &rEnv, ::std::move(pList),
- nullptr, nullptr, nullptr);
+ CurlProcessor::ProcessRequest(g, rSession, uriSource, &rEnv, ::std::move(pList), nullptr,
+ nullptr, nullptr);
}
auto CurlSession::COPY(OUString const& rSourceURIReference, OUString const& rDestinationURI,
@@ -1755,6 +1782,8 @@ auto CurlSession::DESTROY(OUString const& rURIReference, DAVRequestEnvironment c
{
SAL_INFO("ucb.ucp.webdav.curl", "DESTROY: " << rURIReference);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
Guard g(m_Mutex, [&]() {
auto rc = curl_easy_setopt(m_pCurl.get(), CURLOPT_CUSTOMREQUEST, nullptr);
assert(rc == CURLE_OK);
@@ -1768,12 +1797,11 @@ auto CurlSession::DESTROY(OUString const& rURIReference, DAVRequestEnvironment c
ConnectionEndPointString(m_URI.GetHost(), m_URI.GetPort()));
}
- CurlProcessor::ProcessRequest(g, *this, rURIReference, &rEnv, nullptr, nullptr, nullptr,
- nullptr);
+ CurlProcessor::ProcessRequest(g, *this, uri, &rEnv, nullptr, nullptr, nullptr, nullptr);
}
auto CurlProcessor::Lock(
- CurlSession& rSession, OUString const& rURIReference, DAVRequestEnvironment const* const pEnv,
+ CurlSession& rSession, CurlUri const& rURI, DAVRequestEnvironment const* const pEnv,
::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pRequestHeaderList,
uno::Reference<io::XInputStream> const* const pxRequestInStream)
-> ::std::vector<::std::pair<ucb::Lock, sal_Int32>>
@@ -1801,12 +1829,12 @@ auto CurlProcessor::Lock(
TimeValue startTime;
osl_getSystemTime(&startTime);
- CurlProcessor::ProcessRequest(g, rSession, rURIReference, pEnv, ::std::move(pRequestHeaderList),
+ CurlProcessor::ProcessRequest(g, rSession, rURI, pEnv, ::std::move(pRequestHeaderList),
&xResponseOutStream, pxRequestInStream, nullptr);
::std::vector<ucb::Lock> const acquiredLocks(parseWebDAVLockResponse(xResponseInStream));
SAL_WARN_IF(acquiredLocks.empty(), "ucb.ucp.webdav.curl",
- "could not get LOCK for " << rURIReference);
+ "could not get LOCK for " << rURI.GetURI());
TimeValue endTime;
osl_getSystemTime(&endTime);
@@ -1826,7 +1854,7 @@ auto CurlProcessor::Lock(
{
SAL_WARN("ucb.ucp.webdav.curl",
"LOCK timeout already expired when receiving LOCK response for "
- << rURIReference);
+ << rURI.GetURI());
lockExpirationTimeSeconds = 0;
}
else
@@ -1844,8 +1872,9 @@ auto CurlSession::LOCK(OUString const& rURIReference, ucb::Lock /*const*/& rLock
{
SAL_INFO("ucb.ucp.webdav.curl", "LOCK: " << rURIReference);
- // FIXME: why is a *global* LockStore keyed by *path*?
- if (g_Init.LockStore.getLockTokenForURI(rURIReference, &rLock))
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
+
+ if (g_Init.LockStore.getLockTokenForURI(uri.GetURI(), &rLock))
{
// already have a lock that covers the requirement
// TODO: maybe use DAV:lockdiscovery to ensure it's valid
@@ -1948,21 +1977,20 @@ auto CurlSession::LOCK(OUString const& rURIReference, ucb::Lock /*const*/& rLock
}
auto const acquiredLocks
- = CurlProcessor::Lock(*this, rURIReference, &rEnv, ::std::move(pList), &xRequestInStream);
+ = CurlProcessor::Lock(*this, uri, &rEnv, ::std::move(pList), &xRequestInStream);
for (auto const& rAcquiredLock : acquiredLocks)
{
- g_Init.LockStore.addLock(rURIReference, rAcquiredLock.first,
+ g_Init.LockStore.addLock(uri.GetURI(), rAcquiredLock.first,
rAcquiredLock.first.LockTokens[0], this, rAcquiredLock.second);
SAL_INFO("ucb.ucp.webdav.curl", "created LOCK for " << rURIReference);
}
}
-auto CurlProcessor::Unlock(CurlSession& rSession, OUString const& rURIReference,
+auto CurlProcessor::Unlock(CurlSession& rSession, CurlUri const& rURI,
DAVRequestEnvironment const* const pEnv) -> void
{
- // TODO: why is a *global* LockStore keyed by *path*?
- OUString const token(g_Init.LockStore.getLockToken(rURIReference));
+ OUString const token(g_Init.LockStore.getLockToken(rURI.GetURI()));
if (token.isEmpty())
{
SAL_WARN("ucb.ucp.webdav.curl", "attempt to unlock but not locked");
@@ -1992,8 +2020,8 @@ auto CurlProcessor::Unlock(CurlSession& rSession, OUString const& rURIReference,
ConnectionEndPointString(rSession.m_URI.GetHost(), rSession.m_URI.GetPort()));
}
- CurlProcessor::ProcessRequest(g, rSession, rURIReference, pEnv, ::std::move(pList), nullptr,
- nullptr, nullptr);
+ CurlProcessor::ProcessRequest(g, rSession, rURI, pEnv, ::std::move(pList), nullptr, nullptr,
+ nullptr);
}
auto CurlSession::UNLOCK(OUString const& rURIReference, DAVRequestEnvironment const& rEnv) -> void
@@ -2002,68 +2030,72 @@ auto CurlSession::UNLOCK(OUString const& rURIReference, DAVRequestEnvironment co
// note: no m_Mutex lock needed here, only in CurlProcessor::Unlock()
- CurlProcessor::Unlock(*this, rURIReference, &rEnv);
+ CurlUri const uri(CurlProcessor::URIReferenceToURI(*this, rURIReference));
- g_Init.LockStore.removeLock(rURIReference);
+ CurlProcessor::Unlock(*this, uri, &rEnv);
+
+ g_Init.LockStore.removeLock(uri.GetURI());
}
-auto CurlSession::NonInteractive_LOCK(OUString const& rURIReference,
+auto CurlSession::NonInteractive_LOCK(OUString const& rURI,
sal_Int32& o_rLastChanceToSendRefreshRequest) -> bool
{
- SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_LOCK: " << rURIReference);
+ SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_LOCK: " << rURI);
// note: no m_Mutex lock needed here, only in CurlProcessor::Lock()
- ::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pList(
- curl_slist_append(nullptr, "Timeout: Second-180"));
-
- // TODO: why is a *global* LockStore keyed by *path*?
- OUString const token(g_Init.LockStore.getLockToken(rURIReference));
- assert(!token.isEmpty()); // LockStore is the caller
- OString const utf8If("If: (<" + OUStringToOString(token, RTL_TEXTENCODING_ASCII_US) + ">)");
- pList.reset(curl_slist_append(pList.release(), utf8If.getStr()));
- if (!pList)
- {
- throw uno::RuntimeException("curl_slist_append failed");
- }
-
try
{
+ CurlUri const uri(rURI);
+ ::std::unique_ptr<curl_slist, deleter_from_fn<curl_slist_free_all>> pList(
+ curl_slist_append(nullptr, "Timeout: Second-180"));
+
+ OUString const token(g_Init.LockStore.getLockToken(rURI));
+ assert(!token.isEmpty()); // LockStore is the caller
+ OString const utf8If("If: (<" + OUStringToOString(token, RTL_TEXTENCODING_ASCII_US) + ">)");
+ pList.reset(curl_slist_append(pList.release(), utf8If.getStr()));
+ if (!pList)
+ {
+ throw uno::RuntimeException("curl_slist_append failed");
+ }
+
auto const acquiredLocks
- = CurlProcessor::Lock(*this, rURIReference, nullptr, ::std::move(pList), nullptr);
+ = CurlProcessor::Lock(*this, uri, nullptr, ::std::move(pList), nullptr);
SAL_WARN_IF(1 < acquiredLocks.size(), "ucb.ucp.webdav.curl",
- "multiple locks acquired on refresh for " << rURIReference);
+ "multiple locks acquired on refresh for " << rURI);
if (!acquiredLocks.empty())
{
o_rLastChanceToSendRefreshRequest = acquiredLocks.begin()->second;
}
- SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_LOCK succeeded on " << rURIReference);
+ SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_LOCK succeeded on " << rURI);
return true;
}
catch (...)
{
- SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_LOCK failed on " << rURIReference);
+ SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_LOCK failed on " << rURI);
return false;
}
}
-auto CurlSession::NonInteractive_UNLOCK(OUString const& rURIReference) -> void
+auto CurlSession::NonInteractive_UNLOCK(OUString const& rURI) -> void
{
- SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_UNLOCK: " << rURIReference);
+ SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_UNLOCK: " << rURI);
// note: no m_Mutex lock needed here, only in CurlProcessor::Unlock()
try
{
- CurlProcessor::Unlock(*this, rURIReference, nullptr);
+ CurlUri const uri(rURI);
+
+ CurlProcessor::Unlock(*this, uri, nullptr);
// the only caller is the dtor of the LockStore, don't call remove!
- SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_UNLOCK succeeded on " << rURIReference);
+ SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_UNLOCK succeeded on " << rURI);
}
catch (...)
{
- SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_UNLOCK failed on " << rURIReference);
+ SAL_INFO("ucb.ucp.webdav.curl", "NonInteractive_UNLOCK failed on " << rURI);
}
}
diff --git a/ucb/source/ucp/webdav-curl/CurlSession.hxx b/ucb/source/ucp/webdav-curl/CurlSession.hxx
index 58a828b29f14..88496308a947 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.hxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.hxx
@@ -127,9 +127,9 @@ public:
virtual auto abort() -> void override;
- auto NonInteractive_LOCK(OUString const& rURIReference,
- sal_Int32& o_rLastChanceToSendRefreshRequest) -> bool;
- auto NonInteractive_UNLOCK(OUString const& rURIReference) -> void;
+ auto NonInteractive_LOCK(OUString const& rURI, sal_Int32& o_rLastChanceToSendRefreshRequest)
+ -> bool;
+ auto NonInteractive_UNLOCK(OUString const& rURI) -> void;
};
} // namespace http_dav_ucp
diff --git a/ucb/source/ucp/webdav-curl/CurlUri.cxx b/ucb/source/ucp/webdav-curl/CurlUri.cxx
index 5ab41db8d756..1c596dfcd299 100644
--- a/ucb/source/ucp/webdav-curl/CurlUri.cxx
+++ b/ucb/source/ucp/webdav-curl/CurlUri.cxx
@@ -245,6 +245,47 @@ void CurlUri::AppendPath(::std::u16string_view const rPath)
m_Path = *oPath;
}
+CurlUri CurlUri::CloneWithRelativeRefPathAbsolute(OUString const& rRelativeRef) const
+{
+ ::std::unique_ptr<CURLU, deleter_from_fn<curl_url_cleanup>> pUrl(curl_url_dup(m_pUrl.get()));
+ sal_Int32 indexEnd(rRelativeRef.getLength());
+ auto const indexQuery(rRelativeRef.indexOf('?'));
+ auto const indexFragment(rRelativeRef.indexOf('#'));
+ if (indexFragment != -1)
+ {
+ OUString const fragment(rRelativeRef.copy(indexFragment));
+ indexEnd = indexFragment;
+ OString const utf8Fragment(OUStringToOString(fragment, RTL_TEXTENCODING_UTF8));
+ auto const uc = curl_url_set(pUrl.get(), CURLUPART_QUERY, utf8Fragment.getStr(), 0);
+ if (uc != CURLUE_OK)
+ {
+ SAL_WARN("ucb.ucp.webdav.curl", "curl_url_set failed: " << uc);
+ throw DAVException(DAVException::DAV_INVALID_ARG);
+ }
+ }
+ if (indexQuery != -1 && (indexFragment == -1 || indexQuery < indexFragment))
+ {
+ OUString const query(rRelativeRef.copy(indexQuery, indexEnd - indexQuery));
+ indexEnd = indexQuery;
+ OString const utf8Query(OUStringToOString(query, RTL_TEXTENCODING_UTF8));
+ auto const uc = curl_url_set(pUrl.get(), CURLUPART_QUERY, utf8Query.getStr(), 0);
+ if (uc != CURLUE_OK)
+ {
+ SAL_WARN("ucb.ucp.webdav.curl", "curl_url_set failed: " << uc);
+ throw DAVException(DAVException::DAV_INVALID_ARG);
+ }
+ }
+ OUString const path(rRelativeRef.copy(0, indexEnd));
+ OString const utf8Path(OUStringToOString(path, RTL_TEXTENCODING_UTF8));
+ auto const uc = curl_url_set(pUrl.get(), CURLUPART_PATH, utf8Path.getStr(), 0);
+ if (uc != CURLUE_OK)
+ {
+ SAL_WARN("ucb.ucp.webdav.curl", "curl_url_set failed: " << uc);
+ throw DAVException(DAVException::DAV_INVALID_ARG);
+ }
+ return CurlUri(*pUrl.release());
+}
+
OUString EncodeSegment(OUString const& rSegment)
{
return rtl::Uri::encode(rSegment, rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes,
diff --git a/ucb/source/ucp/webdav-curl/CurlUri.hxx b/ucb/source/ucp/webdav-curl/CurlUri.hxx
index 13859666bc79..4071991c904e 100644
--- a/ucb/source/ucp/webdav-curl/CurlUri.hxx
+++ b/ucb/source/ucp/webdav-curl/CurlUri.hxx
@@ -59,7 +59,7 @@ public:
bool operator==(CurlUri const& rOther) const;
- CURLU* CloneCURLU() const { return curl_url_dup(m_pUrl.get()); }
+ CURLU const* GetCURLU() const { return m_pUrl.get(); }
OUString const& GetURI() const { return m_URI; }
OUString const& GetScheme() const { return m_Scheme; }
OUString const& GetUser() const { return m_User; }
@@ -76,6 +76,9 @@ public:
void SetScheme(::std::u16string_view rScheme);
/// @throws DAVException
void AppendPath(::std::u16string_view rPath);
+ /// @param matches: relative-ref = path-absolute [ "?" query ] [ "#" fragment ]
+ /// @throws DAVException
+ CurlUri CloneWithRelativeRefPathAbsolute(OUString const& rRelativeRef) const;
};
OUString EncodeSegment(OUString const& rSegment);
diff --git a/ucb/source/ucp/webdav-curl/SerfLockStore.cxx b/ucb/source/ucp/webdav-curl/SerfLockStore.cxx
index 62526bd873fc..93cca865eb1b 100644
--- a/ucb/source/ucp/webdav-curl/SerfLockStore.cxx
+++ b/ucb/source/ucp/webdav-curl/SerfLockStore.cxx
@@ -139,11 +139,13 @@ void SerfLockStore::stopTicker(osl::ClearableMutexGuard & rGuard)
pTickerThread->join(); // without m_aMutex locked (to prevent deadlock)
}
-OUString SerfLockStore::getLockToken( const OUString& rLock )
+OUString SerfLockStore::getLockToken(const OUString& rURI)
{
+ assert(rURI.startsWith("http://") || rURI.startsWith("https://"));
+
osl::MutexGuard aGuard( m_aMutex );
- LockInfoMap::const_iterator it( m_aLockInfoMap.find( rLock ) );
+ LockInfoMap::const_iterator const it( m_aLockInfoMap.find(rURI) );
if ( it != m_aLockInfoMap.end() )
return (*it).second.m_sToken;
@@ -154,6 +156,8 @@ OUString SerfLockStore::getLockToken( const OUString& rLock )
OUString const*
SerfLockStore::getLockTokenForURI(OUString const& rURI, css::ucb::Lock const*const pLock)
{
+ assert(rURI.startsWith("http://") || rURI.startsWith("https://"));
+
osl::MutexGuard aGuard( m_aMutex );
auto const it(m_aLockInfoMap.find(rURI));
@@ -187,6 +191,8 @@ void SerfLockStore::addLock( const OUString& rURI,
rtl::Reference<CurlSession> const & xSession,
sal_Int32 nLastChanceToSendRefreshRequest )
{
+ assert(rURI.startsWith("http://") || rURI.startsWith("https://"));
+
osl::MutexGuard aGuard( m_aMutex );
m_aLockInfoMap[ rURI ]
@@ -196,12 +202,14 @@ void SerfLockStore::addLock( const OUString& rURI,
}
-void SerfLockStore::updateLock( const OUString& rLock,
+void SerfLockStore::updateLock( const OUString& rURI,
sal_Int32 nLastChanceToSendRefreshRequest )
{
+ assert(rURI.startsWith("http://") || rURI.startsWith("https://"));
+
osl::MutexGuard aGuard( m_aMutex );
- LockInfoMap::iterator it( m_aLockInfoMap.find( rLock ) );
+ LockInfoMap::iterator const it(m_aLockInfoMap.find(rURI));
SAL_WARN_IF( it == m_aLockInfoMap.end(), "ucb.ucp.webdav",
"SerfLockStore::updateLock: lock not found!" );
@@ -213,11 +221,13 @@ void SerfLockStore::updateLock( const OUString& rLock,
}
-void SerfLockStore::removeLock( const OUString& rLock )
+void SerfLockStore::removeLock(const OUString& rURI)
{
+ assert(rURI.startsWith("http://") || rURI.startsWith("https://"));
+
osl::ClearableMutexGuard aGuard( m_aMutex );
- m_aLockInfoMap.erase( rLock );
+ m_aLockInfoMap.erase(rURI);
if ( m_aLockInfoMap.empty() )
stopTicker(aGuard);
diff --git a/ucb/source/ucp/webdav-curl/SerfLockStore.hxx b/ucb/source/ucp/webdav-curl/SerfLockStore.hxx
index 4aeb3a020dbc..7a420187813c 100644
--- a/ucb/source/ucp/webdav-curl/SerfLockStore.hxx
+++ b/ucb/source/ucp/webdav-curl/SerfLockStore.hxx
@@ -68,7 +68,7 @@ public:
~SerfLockStore();
bool finishing() const;
- OUString getLockToken( const OUString& rLock );
+ OUString getLockToken(const OUString& rURI);
OUString const* getLockTokenForURI(OUString const& rURI, css::ucb::Lock const* pLock);
@@ -80,10 +80,10 @@ public:
// -1: infinite lock, no refresh
sal_Int32 nLastChanceToSendRefreshRequest );
- void updateLock( const OUString& rLock,
+ void updateLock( const OUString& rURI,
sal_Int32 nLastChanceToSendRefreshRequest );
- void removeLock( const OUString& rLock );
+ void removeLock(const OUString& rURI);
void refreshLocks();