summaryrefslogtreecommitdiff
path: root/ucb
diff options
context:
space:
mode:
authorMichael Stahl <michael.stahl@allotropia.de>2021-11-26 19:20:37 +0100
committerMichael Stahl <michael.stahl@allotropia.de>2021-11-29 15:23:42 +0100
commit2fae5ab2a8cefa758c631d6ae23847089b68800d (patch)
tree5135685aa080d12683522b3cde70e06add449d22 /ucb
parentac52c6b58d30e0124b27a5b928261db5a4592c28 (diff)
ucb: webdav-curl: don't read from XInputStream during upload
Nextcloud will reply to a PROPFIND request with "100 Continue" and then after the data is uploaded it will send a "401 Unauthorized" if the auth header is missing in the headers to which it replied with "100 Continue". In the next call to ProcessRequestImpl(), reading from the stream returns no data because it's at EOF, and because of the Content-Length header the server will hang forever waiting for data. So copy the stream to a temporary buffer and use that for multiple calls to ProcessRequestImpl(). Change-Id: If5943a32c4cf50259fe1f84013141765cb5bd891 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125923 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'ucb')
-rw-r--r--ucb/source/ucp/webdav-curl/CurlSession.cxx73
1 files changed, 57 insertions, 16 deletions
diff --git a/ucb/source/ucp/webdav-curl/CurlSession.cxx b/ucb/source/ucp/webdav-curl/CurlSession.cxx
index 43bfa6cb85f8..d63d3566bfaa 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.cxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.cxx
@@ -18,6 +18,8 @@
#include <comphelper/scopeguard.hxx>
#include <comphelper/string.hxx>
+#include <o3tl/safeint.hxx>
+
#include <officecfg/Inet.hxx>
#include <com/sun/star/beans/NamedValue.hpp>
@@ -89,12 +91,13 @@ struct DownloadTarget
struct UploadSource
{
- uno::Reference<io::XInputStream> xInStream;
+ uno::Sequence<sal_Int8> const& rInData;
ResponseHeaders const& rHeaders;
- UploadSource(uno::Reference<io::XInputStream> const& i_xInStream,
- ResponseHeaders const& i_rHeaders)
- : xInStream(i_xInStream)
+ size_t nPosition;
+ UploadSource(uno::Sequence<sal_Int8> const& i_rInData, ResponseHeaders const& i_rHeaders)
+ : rInData(i_rInData)
, rHeaders(i_rHeaders)
+ , nPosition(0)
{
}
};
@@ -348,15 +351,14 @@ static size_t read_callback(char* const buffer, size_t const size, size_t const
{
auto* const pSource(static_cast<UploadSource*>(userdata));
assert(pSource);
- assert(pSource->xInStream.is());
size_t const nBytes(size * nitems);
size_t nRet(0);
try
{
- uno::Sequence<sal_Int8> data;
- data.realloc(nBytes);
- nRet = pSource->xInStream->readSomeBytes(data, nBytes);
- ::std::memcpy(buffer, data.getConstArray(), nRet);
+ assert(pSource->nPosition <= o3tl::make_unsigned(pSource->rInData.getLength()));
+ nRet = ::std::min<size_t>(pSource->rInData.getLength() - pSource->nPosition, nBytes);
+ ::std::memcpy(buffer, pSource->rInData.getConstArray() + pSource->nPosition, nRet);
+ pSource->nPosition += nRet;
}
catch (...)
{
@@ -737,7 +739,7 @@ struct CurlProcessor
static auto ProcessRequestImpl(
CurlSession& rSession, CurlUri const& rURI, curl_slist* pRequestHeaderList,
uno::Reference<io::XOutputStream> const* pxOutStream,
- uno::Reference<io::XInputStream> const* pxInStream,
+ uno::Sequence<sal_Int8> const* pInData,
::std::pair<::std::vector<OUString> const&, DAVResource&> const* pRequestedHeaders,
ResponseHeaders& rHeaders) -> void;
@@ -792,7 +794,7 @@ auto CurlProcessor::URIReferenceToURI(CurlSession& rSession, OUString const& rUR
auto CurlProcessor::ProcessRequestImpl(
CurlSession& rSession, CurlUri const& rURI, curl_slist* const pRequestHeaderList,
uno::Reference<io::XOutputStream> const* const pxOutStream,
- uno::Reference<io::XInputStream> const* const pxInStream,
+ uno::Sequence<sal_Int8> const* const pInData,
::std::pair<::std::vector<OUString> const&, DAVResource&> const* const pRequestedHeaders,
ResponseHeaders& rHeaders) -> void
{
@@ -805,7 +807,7 @@ auto CurlProcessor::ProcessRequestImpl(
rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_WRITEDATA, nullptr);
assert(rc == CURLE_OK);
}
- if (pxInStream)
+ if (pInData)
{
rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_READDATA, nullptr);
assert(rc == CURLE_OK);
@@ -839,9 +841,9 @@ auto CurlProcessor::ProcessRequestImpl(
assert(rc == CURLE_OK);
}
::std::optional<UploadSource> oUploadSource;
- if (pxInStream)
+ if (pInData)
{
- oUploadSource.emplace(*pxInStream, rHeaders);
+ oUploadSource.emplace(*pInData, rHeaders);
rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_READDATA, &*oUploadSource);
assert(rc == CURLE_OK);
// libcurl won't upload without setting this
@@ -1103,6 +1105,45 @@ auto CurlProcessor::ProcessRequest(
}
}
+ uno::Sequence<sal_Int8> data;
+ if (pxInStream)
+ {
+ uno::Reference<io::XSeekable> const xSeekable(*pxInStream, uno::UNO_QUERY);
+ if (xSeekable.is())
+ {
+ auto const len(xSeekable->getLength() - xSeekable->getPosition());
+ if ((**pxInStream).readBytes(data, len) != len)
+ {
+ throw uno::RuntimeException("short readBytes");
+ }
+ }
+ else
+ {
+ ::std::vector<uno::Sequence<sal_Int8>> bufs;
+ bool isDone(false);
+ do
+ {
+ bufs.emplace_back();
+ isDone = (**pxInStream).readSomeBytes(bufs.back(), 65536) == 0;
+ } while (!isDone);
+ sal_Int32 nSize(0);
+ for (auto const& rBuf : bufs)
+ {
+ if (o3tl::checked_add(nSize, rBuf.getLength(), nSize))
+ {
+ throw std::bad_alloc(); // too large for Sequence
+ }
+ }
+ data.realloc(nSize);
+ size_t nCopied(0);
+ for (auto const& rBuf : bufs)
+ {
+ ::std::memcpy(data.getArray() + nCopied, rBuf.getConstArray(), rBuf.getLength());
+ nCopied += rBuf.getLength(); // can't overflow
+ }
+ }
+ }
+
// Clear flag before transfer starts; only a transfer started before
// calling abort() will be aborted, not one started later.
rSession.m_AbortFlag.store(false);
@@ -1227,8 +1268,8 @@ auto CurlProcessor::ProcessRequest(
try
{
- ProcessRequestImpl(rSession, rURI, pRequestHeaderList.get(), pxOutStream, pxInStream,
- pRequestedHeaders, headers);
+ ProcessRequestImpl(rSession, rURI, pRequestHeaderList.get(), pxOutStream,
+ pxInStream ? &data : nullptr, pRequestedHeaders, headers);
}
catch (DAVException const& rException)
{