wsd: use RequestVettingStation for async loading
This replaces the synchronous loading logic with the new asynchronous one. Change-Id: I20fd7903cffbbd7c524d8051295113439ef75d5b Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>pull/8389/head
parent
597bb4c1ee
commit
7570dd299c
|
@ -28,6 +28,7 @@ add_library(androidapp SHARED
|
|||
../../../../../wsd/COOLWSD.cpp
|
||||
../../../../../wsd/ClientRequestDispatcher.cpp
|
||||
../../../../../wsd/RequestDetails.cpp
|
||||
../../../../../wsd/RequestVettingStation.cpp
|
||||
../../../../../wsd/Storage.cpp
|
||||
../../../../../wsd/TileCache.cpp
|
||||
../../../../../wsd/coolwsd-fork.cpp)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
BE5EB5D22140039100E0826C /* COOLWSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826C /* COOLWSD.cpp */; };
|
||||
BE5EB5D22140039100E0826D /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */; };
|
||||
BE5EB5D421400DC100E0826C /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */; };
|
||||
BE5EB5E721401E0F00E0826C /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5E621401E0F00E0826C /* RequestVettingStation.cpp */; };
|
||||
BE5EB5D621401E0F00E0826C /* Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D521401E0F00E0826C /* Storage.cpp */; };
|
||||
BE5EB5DA2140363100E0826C /* ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D92140363100E0826C /* ios.mm */; };
|
||||
BE5EB5DC2140480B00E0826C /* ICU.dat in Resources */ = {isa = PBXBuildFile; fileRef = BE5EB5DB2140480B00E0826C /* ICU.dat */; };
|
||||
|
@ -580,6 +581,7 @@
|
|||
BE5EB5D12140039100E0826C /* COOLWSD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COOLWSD.cpp; sourceTree = "<group>"; };
|
||||
BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientRequestDispatcher.cpp; sourceTree = "<group>"; };
|
||||
BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentBroker.cpp; sourceTree = "<group>"; };
|
||||
BE5EB5E621401E0F00E0826C /* RequestVettingStation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RequestVettingStation.cpp; sourceTree = "<group>"; };
|
||||
BE5EB5D521401E0F00E0826C /* Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storage.cpp; sourceTree = "<group>"; };
|
||||
BE5EB5D92140363100E0826C /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios.mm; path = ../../ios/ios.mm; sourceTree = "<group>"; };
|
||||
BE5EB5DB2140480B00E0826C /* ICU.dat */ = {isa = PBXFileReference; lastKnownFileType = file; name = ICU.dat; path = ../../../ICU.dat; sourceTree = "<group>"; };
|
||||
|
@ -2215,6 +2217,7 @@
|
|||
BE484B71228D8622001EE76C /* DocumentBroker.hpp */,
|
||||
BE5EB5D12140039100E0826C /* COOLWSD.cpp */,
|
||||
BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */,
|
||||
BE5EB5E621401E0F00E0826C /* RequestVettingStation.cpp */,
|
||||
BE5EB5D521401E0F00E0826C /* Storage.cpp */,
|
||||
BE5EB5CD213FE2D000E0826C /* TileCache.cpp */,
|
||||
);
|
||||
|
@ -3668,6 +3671,8 @@
|
|||
BE5EB5C5213FE29900E0826C /* MessageQueue.cpp in Sources */,
|
||||
BE7228E22417BC9F000ADABD /* StringVector.cpp in Sources */,
|
||||
BE55E0EB2653FCCB007DDF29 /* ConfigUtil.cpp in Sources */,
|
||||
BE5EB5E721401E0F00E0826C /* RequestVettingStation.cpp in Sources */,
|
||||
BE5EB5F821401E0F00E0826C /* Storage.cpp in Sources */,
|
||||
BE5EB5D621401E0F00E0826C /* Storage.cpp in Sources */,
|
||||
BEA2835621467FDD00848631 /* Kit.cpp in Sources */,
|
||||
BE8D77322136762500AC58EA /* DocumentViewController.mm in Sources */,
|
||||
|
|
|
@ -147,6 +147,7 @@ using Poco::Net::PartHandler;
|
|||
|
||||
#include <common/SigUtil.hpp>
|
||||
|
||||
#include <RequestVettingStation.hpp>
|
||||
#include <ServerSocket.hpp>
|
||||
|
||||
#if MOBILEAPP
|
||||
|
|
|
@ -58,26 +58,6 @@ extern std::mutex DocBrokersMutex;
|
|||
|
||||
extern void cleanupDocBrokers();
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void sendLoadResult(const std::shared_ptr<ClientSession>& clientSession, bool success,
|
||||
const std::string& errorMsg)
|
||||
{
|
||||
const std::string result = success ? "" : "Error while loading document";
|
||||
const std::string resultstr = success ? "true" : "false";
|
||||
// Some sane limit, otherwise we get problems transferring this
|
||||
// to the client with large strings (can be a whole webpage)
|
||||
// Replace reserved characters
|
||||
std::string errorMsgFormatted = COOLProtocol::getAbbreviatedMessage(errorMsg);
|
||||
errorMsgFormatted = Poco::translate(errorMsg, "\"", "'");
|
||||
clientSession->sendMessage("commandresult: { \"command\": \"load\", \"success\": " + resultstr +
|
||||
", \"result\": \"" + result + "\", \"errorMsg\": \"" +
|
||||
errorMsgFormatted + "\"}");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/// Find the DocumentBroker for the given docKey, if one exists.
|
||||
/// Otherwise, creates and adds a new one to DocBrokers.
|
||||
/// May return null if terminating or MaxDocuments limit is reached.
|
||||
|
@ -1655,119 +1635,10 @@ void ClientRequestDispatcher::handleClientWsUpgrade(const Poco::Net::HTTPRequest
|
|||
#endif
|
||||
}
|
||||
|
||||
LOG_INF("URL [" << url << "] for WS Request.");
|
||||
const auto uriPublic = RequestDetails::sanitizeURI(url);
|
||||
const auto docKey = RequestDetails::getDocKey(uriPublic);
|
||||
const std::string fileId = Util::getFilenameFromURL(docKey);
|
||||
Util::mapAnonymized(fileId,
|
||||
fileId); // Identity mapping, since fileId is already obfuscated
|
||||
|
||||
LOG_INF("Starting GET request handler for session [" << _id << "] on url ["
|
||||
<< COOLWSD::anonymizeUrl(url) << "].");
|
||||
|
||||
// Indicate to the client that document broker is searching.
|
||||
static const std::string status("statusindicator: find");
|
||||
LOG_TRC("Sending to Client [" << status << "].");
|
||||
ws->sendMessage(status);
|
||||
|
||||
LOG_INF("Sanitized URI [" << COOLWSD::anonymizeUrl(url) << "] to ["
|
||||
<< COOLWSD::anonymizeUrl(uriPublic.toString())
|
||||
<< "] and mapped to docKey [" << docKey << "] for session ["
|
||||
<< _id << "].");
|
||||
|
||||
// Check if readonly session is required
|
||||
bool isReadOnly = false;
|
||||
for (const auto& param : uriPublic.getQueryParameters())
|
||||
{
|
||||
LOG_TRC("Query param: " << param.first << ", value: " << param.second);
|
||||
if (param.first == "permission" && param.second == "readonly")
|
||||
{
|
||||
isReadOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INF("URL [" << COOLWSD::anonymizeUrl(url) << "] is "
|
||||
<< (isReadOnly ? "readonly" : "writable"));
|
||||
|
||||
// Request a kit process for this doc.
|
||||
std::shared_ptr<DocumentBroker> docBroker = findOrCreateDocBroker(
|
||||
std::static_pointer_cast<ProtocolHandlerInterface>(ws),
|
||||
DocumentBroker::ChildType::Interactive, url, docKey, _id, uriPublic, mobileAppDocId);
|
||||
if (docBroker)
|
||||
{
|
||||
std::shared_ptr<ClientSession> clientSession =
|
||||
docBroker->createNewClientSession(ws, _id, uriPublic, isReadOnly, requestDetails);
|
||||
if (clientSession)
|
||||
{
|
||||
// Transfer the client socket to the DocumentBroker when we get back to the poll:
|
||||
docBroker->setupTransfer(
|
||||
disposition,
|
||||
[docBroker, clientSession, ws](const std::shared_ptr<Socket>& moveSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto streamSocket = std::static_pointer_cast<StreamSocket>(moveSocket);
|
||||
|
||||
// Set WebSocketHandler's socket after its construction for shared_ptr goodness.
|
||||
streamSocket->setHandler(ws);
|
||||
|
||||
LOG_DBG_S('#' << moveSocket->getFD() << " handler is "
|
||||
<< clientSession->getName());
|
||||
|
||||
// Add and load the session.
|
||||
docBroker->addSession(clientSession);
|
||||
|
||||
COOLWSD::checkDiskSpaceAndWarnClients(true);
|
||||
// Users of development versions get just an info
|
||||
// when reaching max documents or connections
|
||||
COOLWSD::checkSessionLimitsAndWarnClients();
|
||||
|
||||
sendLoadResult(clientSession, true, "");
|
||||
}
|
||||
catch (const UnauthorizedRequestException& exc)
|
||||
{
|
||||
LOG_ERR_S("Unauthorized Request while starting session on "
|
||||
<< docBroker->getDocKey() << " for socket #"
|
||||
<< moveSocket->getFD()
|
||||
<< ". Terminating connection. Error: " << exc.what());
|
||||
const std::string msg = "error: cmd=internal kind=unauthorized";
|
||||
ws->shutdown(WebSocketHandler::StatusCodes::POLICY_VIOLATION, msg);
|
||||
moveSocket->ignoreInput();
|
||||
}
|
||||
catch (const StorageConnectionException& exc)
|
||||
{
|
||||
LOG_ERR_S("Storage error while starting session on "
|
||||
<< docBroker->getDocKey() << " for socket #"
|
||||
<< moveSocket->getFD()
|
||||
<< ". Terminating connection. Error: " << exc.what());
|
||||
const std::string msg = "error: cmd=storage kind=loadfailed";
|
||||
ws->shutdown(WebSocketHandler::StatusCodes::POLICY_VIOLATION, msg);
|
||||
moveSocket->ignoreInput();
|
||||
}
|
||||
catch (const std::exception& exc)
|
||||
{
|
||||
LOG_ERR_S("Error while starting session on "
|
||||
<< docBroker->getDocKey() << " for socket #"
|
||||
<< moveSocket->getFD()
|
||||
<< ". Terminating connection. Error: " << exc.what());
|
||||
const std::string msg = "error: cmd=storage kind=loadfailed";
|
||||
ws->shutdown(WebSocketHandler::StatusCodes::POLICY_VIOLATION, msg);
|
||||
moveSocket->ignoreInput();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WRN("Failed to create Client Session with id [" << _id << "] on docKey ["
|
||||
<< docKey << "].");
|
||||
throw std::runtime_error("Cannot create client session for doc " + docKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ServiceUnavailableException("Failed to create DocBroker with docKey [" + docKey +
|
||||
"].");
|
||||
}
|
||||
auto rvs = std::make_shared<RequestVettingStation>(_id, ws, requestDetails, socket,
|
||||
mobileAppDocId);
|
||||
_requestVettingStations.emplace(_id, rvs);
|
||||
rvs->handleRequest(*COOLWSD::getWebServerPoll(), disposition);
|
||||
}
|
||||
catch (const std::exception& exc)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <RequestVettingStation.hpp>
|
||||
#include <RequestDetails.hpp>
|
||||
#include <Socket.hpp>
|
||||
#include <WopiProxy.hpp>
|
||||
|
@ -18,8 +19,6 @@
|
|||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
class WopiProxy;
|
||||
|
||||
/// Handles incoming connections and dispatches to the appropriate handler.
|
||||
class ClientRequestDispatcher final : public SimpleSocketHandler
|
||||
{
|
||||
|
@ -114,6 +113,10 @@ private:
|
|||
/// WASM document request handler. Used only when WASM is enabled.
|
||||
std::unique_ptr<WopiProxy> _wopiProxy;
|
||||
|
||||
/// External requests are first vetted before allocating DocBroker and Kit process.
|
||||
/// This is a map of the request URI to the RequestVettingStation for vetting.
|
||||
std::unordered_map<std::string, std::shared_ptr<RequestVettingStation>> _requestVettingStations;
|
||||
|
||||
/// Cache for static files, to avoid reading and processing from disk.
|
||||
static std::map<std::string, std::string> StaticFileContentCache;
|
||||
};
|
|
@ -853,8 +853,7 @@ bool DocumentBroker::download(const std::shared_ptr<ClientSession>& session,
|
|||
{
|
||||
LOG_DBG("CheckFileInfo for docKey [" << _docKey << ']');
|
||||
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
|
||||
if (!wopiFileInfo)
|
||||
wopiFileInfo = wopiStorage->getWOPIFileInfo(session->getAuthorization(), *_lockCtx);
|
||||
wopiStorage->handleWOPIFileInfo(*wopiFileInfo, *_lockCtx);
|
||||
|
||||
checkFileInfoCallDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RequestDetails.hpp"
|
||||
#include <Storage.hpp>
|
||||
#include "WebSocketHandler.hpp"
|
||||
|
|
141
wsd/Storage.cpp
141
wsd/Storage.cpp
|
@ -640,142 +640,19 @@ http::Request WopiStorage::initHttpRequest(const Poco::URI& uri, const Authoriza
|
|||
return httpRequest;
|
||||
}
|
||||
|
||||
std::unique_ptr<WopiStorage::WOPIFileInfo>
|
||||
WopiStorage::getWOPIFileInfoForUri(Poco::URI uriObject, const Authorization& auth,
|
||||
LockContext& lockCtx, unsigned redirectLimit)
|
||||
void WopiStorage::handleWOPIFileInfo(const WOPIFileInfo& wopiFileInfo, LockContext& lockCtx)
|
||||
{
|
||||
ProfileZone profileZone("WopiStorage::getWOPIFileInfo", { {"url", _fileUrl} });
|
||||
setFileInfo(wopiFileInfo);
|
||||
|
||||
// update the access_token to the one matching to the session
|
||||
auth.authorizeURI(uriObject);
|
||||
const std::string uriAnonym = COOLWSD::anonymizeUrl(uriObject.toString());
|
||||
if (COOLWSD::AnonymizeUserData)
|
||||
Util::mapAnonymized(Util::getFilenameFromURL(wopiFileInfo.getFilename()),
|
||||
Util::getFilenameFromURL(getUri().toString()));
|
||||
|
||||
LOG_DBG("Getting info for wopi uri [" << uriAnonym << "].");
|
||||
if (wopiFileInfo.getSupportsLocks())
|
||||
lockCtx.initSupportsLocks();
|
||||
|
||||
std::string wopiResponse;
|
||||
std::chrono::milliseconds callDurationMs;
|
||||
try
|
||||
{
|
||||
std::shared_ptr<http::Session> httpSession = getHttpSession(uriObject);
|
||||
http::Request httpRequest = initHttpRequest(uriObject, auth);
|
||||
|
||||
const auto startTime = std::chrono::steady_clock::now();
|
||||
|
||||
LOG_TRC("WOPI::CheckFileInfo request header for URI [" << uriAnonym << "]:\n"
|
||||
<< httpRequest.header());
|
||||
|
||||
const std::shared_ptr<const http::Response> httpResponse
|
||||
= httpSession->syncRequest(httpRequest);
|
||||
|
||||
callDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - startTime);
|
||||
|
||||
const http::StatusCode statusCode = httpResponse->statusLine().statusCode();
|
||||
if (statusCode == http::StatusCode::MovedPermanently ||
|
||||
statusCode == http::StatusCode::Found ||
|
||||
statusCode == http::StatusCode::TemporaryRedirect ||
|
||||
statusCode == http::StatusCode::PermanentRedirect)
|
||||
{
|
||||
if (redirectLimit)
|
||||
{
|
||||
const std::string& location = httpResponse->get("Location");
|
||||
LOG_TRC("WOPI::CheckFileInfo redirect to URI [" << COOLWSD::anonymizeUrl(location) << "]");
|
||||
|
||||
Poco::URI redirectUriObject(location);
|
||||
setUri(redirectUriObject);
|
||||
return getWOPIFileInfoForUri(redirectUriObject, auth, lockCtx, redirectLimit - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WRN("WOPI::CheckFileInfo redirected too many times - URI [" << uriAnonym << "]");
|
||||
}
|
||||
}
|
||||
|
||||
// Note: we don't log the response if obfuscation is enabled, except for failures.
|
||||
wopiResponse = httpResponse->getBody();
|
||||
const bool failed = (httpResponse->statusLine().statusCode() != http::StatusCode::OK);
|
||||
|
||||
Log::StreamLogger logRes = failed ? Log::error() : Log::trace();
|
||||
if (logRes.enabled())
|
||||
{
|
||||
logRes << "WOPI::CheckFileInfo " << (failed ? "failed" : "returned") << " for URI ["
|
||||
<< uriAnonym << "]: " << httpResponse->statusLine().statusCode() << ' '
|
||||
<< httpResponse->statusLine().reasonPhrase()
|
||||
<< ". Headers: " << httpResponse->header()
|
||||
<< (failed ? "\tBody: [" + wopiResponse + ']' : std::string());
|
||||
|
||||
LOG_END_FLUSH(logRes);
|
||||
}
|
||||
|
||||
if (failed)
|
||||
{
|
||||
if (httpResponse->statusLine().statusCode() == http::StatusCode::Forbidden)
|
||||
throw UnauthorizedRequestException(
|
||||
"Access denied, 403. WOPI::CheckFileInfo failed on: " + uriAnonym);
|
||||
|
||||
throw StorageConnectionException("WOPI::CheckFileInfo failed: " + wopiResponse);
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& pexc)
|
||||
{
|
||||
LOG_ERR("Cannot get file info from WOPI storage uri [" << uriAnonym << "]. Error: " <<
|
||||
pexc.displayText() << (pexc.nested() ? " (" + pexc.nested()->displayText() + ')' : ""));
|
||||
throw;
|
||||
}
|
||||
catch (const BadRequestException& exc)
|
||||
{
|
||||
LOG_ERR("Cannot get file info from WOPI storage uri [" << uriAnonym << "]. Error: " << exc.what());
|
||||
}
|
||||
|
||||
Poco::JSON::Object::Ptr object;
|
||||
if (JsonUtil::parseJSON(wopiResponse, object))
|
||||
{
|
||||
if (COOLWSD::AnonymizeUserData)
|
||||
LOG_DBG("WOPI::CheckFileInfo (" << callDurationMs << "): anonymizing...");
|
||||
else
|
||||
LOG_DBG("WOPI::CheckFileInfo (" << callDurationMs << "): " << wopiResponse);
|
||||
|
||||
std::size_t size = 0;
|
||||
std::string filename, ownerId, lastModifiedTime;
|
||||
|
||||
JsonUtil::findJSONValue(object, "Size", size);
|
||||
JsonUtil::findJSONValue(object, "OwnerId", ownerId);
|
||||
JsonUtil::findJSONValue(object, "BaseFileName", filename);
|
||||
JsonUtil::findJSONValue(object, "LastModifiedTime", lastModifiedTime);
|
||||
|
||||
FileInfo fileInfo = FileInfo({filename, ownerId, lastModifiedTime});
|
||||
setFileInfo(fileInfo);
|
||||
|
||||
if (COOLWSD::AnonymizeUserData)
|
||||
Util::mapAnonymized(Util::getFilenameFromURL(filename), Util::getFilenameFromURL(getUri().toString()));
|
||||
|
||||
auto wopiInfo = std::make_unique<WopiStorage::WOPIFileInfo>(fileInfo, object, uriObject);
|
||||
if (wopiInfo->getSupportsLocks())
|
||||
lockCtx.initSupportsLocks();
|
||||
|
||||
// If FileUrl is set, we use it for GetFile.
|
||||
_fileUrl = wopiInfo->getFileUrl();
|
||||
|
||||
return wopiInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (COOLWSD::AnonymizeUserData)
|
||||
wopiResponse = "obfuscated";
|
||||
|
||||
LOG_ERR("WOPI::CheckFileInfo ("
|
||||
<< callDurationMs
|
||||
<< ") failed or no valid JSON payload returned. Access denied. Original response: ["
|
||||
<< wopiResponse << "].");
|
||||
|
||||
throw UnauthorizedRequestException("Access denied. WOPI::CheckFileInfo failed on: " + uriAnonym);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Authorization& auth,
|
||||
LockContext& lockCtx)
|
||||
{
|
||||
return getWOPIFileInfoForUri(getUri(), auth, lockCtx, RedirectionLimit);
|
||||
// If FileUrl is set, we use it for GetFile.
|
||||
_fileUrl = wopiFileInfo.getFileUrl();
|
||||
}
|
||||
|
||||
WopiStorage::WOPIFileInfo::WOPIFileInfo(const FileInfo& fileInfo,
|
||||
|
|
|
@ -704,17 +704,11 @@ public:
|
|||
<< COOLWSD::anonymizeUrl(uri.toString()) << ']');
|
||||
}
|
||||
|
||||
/// Returns the response of CheckFileInfo WOPI call for URI that was
|
||||
/// provided during the initial creation of the WOPI storage.
|
||||
/// Handles the response from CheckFileInfo, as converted into WOPIFileInfo.
|
||||
/// Also extracts the basic file information from the response
|
||||
/// which can then be obtained using getFileInfo()
|
||||
/// Also sets up the locking context for future operations.
|
||||
std::unique_ptr<WOPIFileInfo> getWOPIFileInfo(const Authorization& auth, LockContext& lockCtx);
|
||||
/// Implementation of getWOPIFileInfo for specific URI
|
||||
std::unique_ptr<WOPIFileInfo> getWOPIFileInfoForUri(Poco::URI uriObject,
|
||||
const Authorization& auth,
|
||||
LockContext& lockCtx,
|
||||
unsigned redirectLimit);
|
||||
void handleWOPIFileInfo(const WOPIFileInfo& wopiFileInfo, LockContext& lockCtx);
|
||||
|
||||
/// Update the locking state (check-in/out) of the associated file
|
||||
LockUpdateResult updateLockState(const Authorization& auth, LockContext& lockCtx, bool lock,
|
||||
|
|
Loading…
Reference in New Issue