wsd: extract wopi upload response handling

This is in preparation for asynchronous uploading.

Change-Id: Ibd0ff0fa8edfc08ad2755a45227891ed40e09d1c
Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
This commit is contained in:
Ashod Nakashian 2020-11-15 15:40:21 -05:00 committed by Ashod Nakashian
parent a6cadbcba3
commit 06a45e6db9
2 changed files with 78 additions and 26 deletions

View file

@ -1011,7 +1011,6 @@ WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string
LOG_INF("Uploading " << size << " bytes from [" << filePathAnonym << "] to URI via WOPI ["
<< uriAnonym << "].");
StorageBase::SaveResult saveResult(StorageBase::SaveResult::Result::FAILED);
const auto startTime = std::chrono::steady_clock::now();
try
{
@ -1100,12 +1099,41 @@ WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string
_wopiSaveDuration = std::chrono::steady_clock::now() - startTime;
WopiUploadDetails details
= { filePathAnonym, uriAnonym, response.getReason(), response.getStatus(), size,
isSaveAs, isRename };
std::ostringstream oss;
Poco::StreamCopier::copyStream(rs, oss);
std::string responseString = oss.str();
return handleUploadToStorageResponse(details, oss.str());
}
catch (const Poco::Exception& pexc)
{
LOG_ERR("Cannot save file to WOPI storage uri [" << uriAnonym << "]. Error: " <<
pexc.displayText() << (pexc.nested() ? " (" + pexc.nested()->displayText() + ')' : ""));
}
catch (const BadRequestException& exc)
{
LOG_ERR("Cannot save file to WOPI storage uri [" + uriAnonym + "]. Error: " << exc.what());
}
return StorageBase::SaveResult::Result::FAILED;
}
StorageBase::SaveResult WopiStorage::handleUploadToStorageResponse(const WopiUploadDetails& details,
std::string responseString)
{
// Assume we failed, unless we have confirmation of success.
StorageBase::SaveResult saveResult(StorageBase::SaveResult::Result::FAILED);
try
{
const std::string origResponseString = responseString;
saveResult.setErrorMsg(responseString);
const std::string wopiLog(isSaveAs ? "WOPI::PutRelativeFile" : (isRename ? "WOPI::RenameFile":"WOPI::PutFile"));
const std::string wopiLog(details.isSaveAs
? "WOPI::PutRelativeFile"
: (details.isRename ? "WOPI::RenameFile" : "WOPI::PutFile"));
if (Log::infoEnabled())
{
@ -1117,14 +1145,15 @@ WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string
// Anonymize the filename
std::string url;
std::string filename;
if (JsonUtil::findJSONValue(object, "Url", url) &&
JsonUtil::findJSONValue(object, "Name", filename))
if (JsonUtil::findJSONValue(object, "Url", url)
&& JsonUtil::findJSONValue(object, "Name", filename))
{
// Get the FileId form the URL, which we use as the anonymized filename.
std::string decodedUrl;
Poco::URI::decode(url, decodedUrl);
const std::string obfuscatedFileId = Util::getFilenameFromURL(decodedUrl);
Util::mapAnonymized(obfuscatedFileId, obfuscatedFileId); // Identity, to avoid re-anonymizing.
Util::mapAnonymized(obfuscatedFileId,
obfuscatedFileId); // Identity, to avoid re-anonymizing.
const std::string filenameOnly = Util::getFilenameFromURL(filename);
Util::mapAnonymized(filenameOnly, obfuscatedFileId);
@ -1138,22 +1167,25 @@ WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string
}
}
LOG_INF(wopiLog << " uploaded " << size << " bytes from [" << filePathAnonym << "] -> ["
<< uriAnonym << "]: " << response.getStatus() << ' '
<< response.getReason() << ": " << responseString);
LOG_INF(wopiLog << " uploaded " << details.size << " bytes from ["
<< details.filePathAnonym << "] -> [" << details.uriAnonym
<< "]: " << details.httpResponseCode << ' '
<< details.httpResponseReason << ": " << responseString);
}
if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK)
if (details.httpResponseCode == Poco::Net::HTTPResponse::HTTP_OK)
{
saveResult.setResult(StorageBase::SaveResult::Result::OK);
Poco::JSON::Object::Ptr object;
if (JsonUtil::parseJSON(oss.str(), object))
if (JsonUtil::parseJSON(origResponseString, object))
{
const std::string lastModifiedTime = JsonUtil::getJSONValue<std::string>(object, "LastModifiedTime");
const std::string lastModifiedTime
= JsonUtil::getJSONValue<std::string>(object, "LastModifiedTime");
LOG_TRC(wopiLog << " returns LastModifiedTime [" << lastModifiedTime << "].");
getFileInfo().setModifiedTime(Util::iso8601ToTimestamp(lastModifiedTime, "LastModifiedTime"));
getFileInfo().setModifiedTime(
Util::iso8601ToTimestamp(lastModifiedTime, "LastModifiedTime"));
if (isSaveAs || isRename)
if (details.isSaveAs || details.isRename)
{
const std::string name = JsonUtil::getJSONValue<std::string>(object, "Name");
LOG_TRC(wopiLog << " returns Name [" << LOOLWSD::anonymizeUrl(name) << "].");
@ -1172,22 +1204,23 @@ WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string
LOG_WRN("Invalid or missing JSON in " << wopiLog << " HTTP_OK response.");
}
}
else if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_REQUESTENTITYTOOLARGE)
else if (details.httpResponseCode == Poco::Net::HTTPResponse::HTTP_REQUEST_ENTITY_TOO_LARGE)
{
saveResult.setResult(StorageBase::SaveResult::Result::DISKFULL);
}
else if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_UNAUTHORIZED ||
response.getStatus() == Poco::Net::HTTPResponse::HTTP_FORBIDDEN)
else if (details.httpResponseCode == Poco::Net::HTTPResponse::HTTP_UNAUTHORIZED
|| details.httpResponseCode == Poco::Net::HTTPResponse::HTTP_FORBIDDEN)
{
saveResult.setResult(StorageBase::SaveResult::Result::UNAUTHORIZED);
}
else if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_CONFLICT)
else if (details.httpResponseCode == Poco::Net::HTTPResponse::HTTP_CONFLICT)
{
saveResult.setResult(StorageBase::SaveResult::Result::CONFLICT);
Poco::JSON::Object::Ptr object;
if (JsonUtil::parseJSON(oss.str(), object))
if (JsonUtil::parseJSON(origResponseString, object))
{
const unsigned loolStatusCode = JsonUtil::getJSONValue<unsigned>(object, "LOOLStatusCode");
const unsigned loolStatusCode
= JsonUtil::getJSONValue<unsigned>(object, "LOOLStatusCode");
if (loolStatusCode == static_cast<unsigned>(LOOLStatusCode::DOC_CHANGED))
{
saveResult.setResult(StorageBase::SaveResult::Result::DOC_CHANGED);
@ -1202,21 +1235,24 @@ WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string
{
// Internal server error, and other failures.
LOG_ERR("Unexpected response to "
<< wopiLog << ". Cannot upload file to WOPI storage uri [" << uriAnonym
<< "]: " << response.getStatus() << ' ' << response.getReason() << ": "
<< responseString);
<< wopiLog << ". Cannot upload file to WOPI storage uri [" << details.uriAnonym
<< "]: " << details.httpResponseCode << ' ' << details.httpResponseReason
<< ": " << responseString);
saveResult.setResult(StorageBase::SaveResult::Result::FAILED);
}
}
catch (const Poco::Exception& pexc)
{
LOG_ERR("Cannot save file to WOPI storage uri [" << uriAnonym << "]. Error: " <<
pexc.displayText() << (pexc.nested() ? " (" + pexc.nested()->displayText() + ')' : ""));
LOG_ERR("Cannot save file to WOPI storage uri ["
<< details.uriAnonym << "]. Error: " << pexc.displayText()
<< (pexc.nested() ? " (" + pexc.nested()->displayText() + ')' : ""));
saveResult.setResult(StorageBase::SaveResult::Result::FAILED);
}
catch (const BadRequestException& exc)
{
LOG_ERR("Cannot save file to WOPI storage uri [" + uriAnonym + "]. Error: " << exc.what());
LOG_ERR("Cannot save file to WOPI storage uri [" + details.uriAnonym + "]. Error: "
<< exc.what());
saveResult.setResult(StorageBase::SaveResult::Result::FAILED);
}
return saveResult;

View file

@ -525,6 +525,22 @@ public:
std::chrono::duration<double> getWopiLoadDuration() const { return _wopiLoadDuration; }
std::chrono::duration<double> getWopiSaveDuration() const { return _wopiSaveDuration; }
protected:
struct WopiUploadDetails
{
const std::string filePathAnonym;
const std::string uriAnonym;
const std::string httpResponseReason;
const long httpResponseCode;
const std::size_t size;
const bool isSaveAs;
const bool isRename;
};
/// Handles the response from the server when uploading the document.
SaveResult handleUploadToStorageResponse(const WopiUploadDetails& details,
std::string responseString);
private:
/// Initialize an HTTPRequest instance with the common settings and headers.
/// Older Poco versions don't support copying HTTPRequest objects, so we can't generate them.