libreoffice-online/test/UnitCopyPasteWriter.cpp

140 lines
4.9 KiB
C++
Raw Normal View History

cool#8465 clipboard: improve handling of plain text copy, complex case In case the selection is complex (not simple), we used to just request HTML, and then the browser converted that to plain text, which has the downsides already mentioned in commit 7f9de46688a64b42ba8f65cceb9fe2c6ddab89ef (cool#8465 clipboard: improve handling of plain text copy, simple case, 2024-03-08). Steps to support this: 1) Clipboard.js now asks for the text/html,text/plain;charset=utf-8 MIME types. 2) wsd: ClientRequestDispatcher::handleClipboardRequest() now maps this to DocumentBroker::CLIP_REQUEST_GET_HTML_PLAIN_ONLY 3) ClientSession::handleClipboardRequest() maps this to the HTML+plain text MIME type list. 4) kit: ChildSession::getClipboard() is now improved to take a list of MIME types, not just 1 or everything. 5) kit: ChildSession::getClipboard() now emits JSON in case not all, but multiple MIME types are requested. 6) wsd: ClientSession::postProcessCopyPayload() now knows how to postprocess clipboardcontent messages, which may or may not be JSON (it's JSON if more formats are requested explicitly, leaving the 1 format or all format cases unchanged) 7) Control.DownloadProgress.js now handles the case when we get JSON and sets the core-provided plain text next to the HTML. Leave the handling of non-JSON case in, because this means we can copy from an old COOL server to a new one. Note that this approach has the benefit that once the clipboard marker is inserted, the length of the text/html format would change, which means we can't parse the clipboard data till the marker is removed. Emitting JSON for html+text means adding the marker keeps the ability to parse the HTML and the plain text part of the clipboard in JS. Signed-off-by: Miklos Vajna <vmiklos@collabora.com> Change-Id: I67a1f669e8a638d34cc25a2f288a7b30884b9892
2024-03-19 06:12:16 -05:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* Copyright the Collabora Online contributors.
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// Test various copy/paste pieces ...
#include <config.h>
#include <HttpRequest.hpp>
cool#8465 clipboard: improve handling of plain text copy, complex case In case the selection is complex (not simple), we used to just request HTML, and then the browser converted that to plain text, which has the downsides already mentioned in commit 7f9de46688a64b42ba8f65cceb9fe2c6ddab89ef (cool#8465 clipboard: improve handling of plain text copy, simple case, 2024-03-08). Steps to support this: 1) Clipboard.js now asks for the text/html,text/plain;charset=utf-8 MIME types. 2) wsd: ClientRequestDispatcher::handleClipboardRequest() now maps this to DocumentBroker::CLIP_REQUEST_GET_HTML_PLAIN_ONLY 3) ClientSession::handleClipboardRequest() maps this to the HTML+plain text MIME type list. 4) kit: ChildSession::getClipboard() is now improved to take a list of MIME types, not just 1 or everything. 5) kit: ChildSession::getClipboard() now emits JSON in case not all, but multiple MIME types are requested. 6) wsd: ClientSession::postProcessCopyPayload() now knows how to postprocess clipboardcontent messages, which may or may not be JSON (it's JSON if more formats are requested explicitly, leaving the 1 format or all format cases unchanged) 7) Control.DownloadProgress.js now handles the case when we get JSON and sets the core-provided plain text next to the HTML. Leave the handling of non-JSON case in, because this means we can copy from an old COOL server to a new one. Note that this approach has the benefit that once the clipboard marker is inserted, the length of the text/html format would change, which means we can't parse the clipboard data till the marker is removed. Emitting JSON for html+text means adding the marker keeps the ability to parse the HTML and the plain text part of the clipboard in JS. Signed-off-by: Miklos Vajna <vmiklos@collabora.com> Change-Id: I67a1f669e8a638d34cc25a2f288a7b30884b9892
2024-03-19 06:12:16 -05:00
#include <Unit.hpp>
#include <WebSocketSession.hpp>
cool#8465 clipboard: improve handling of plain text copy, complex case In case the selection is complex (not simple), we used to just request HTML, and then the browser converted that to plain text, which has the downsides already mentioned in commit 7f9de46688a64b42ba8f65cceb9fe2c6ddab89ef (cool#8465 clipboard: improve handling of plain text copy, simple case, 2024-03-08). Steps to support this: 1) Clipboard.js now asks for the text/html,text/plain;charset=utf-8 MIME types. 2) wsd: ClientRequestDispatcher::handleClipboardRequest() now maps this to DocumentBroker::CLIP_REQUEST_GET_HTML_PLAIN_ONLY 3) ClientSession::handleClipboardRequest() maps this to the HTML+plain text MIME type list. 4) kit: ChildSession::getClipboard() is now improved to take a list of MIME types, not just 1 or everything. 5) kit: ChildSession::getClipboard() now emits JSON in case not all, but multiple MIME types are requested. 6) wsd: ClientSession::postProcessCopyPayload() now knows how to postprocess clipboardcontent messages, which may or may not be JSON (it's JSON if more formats are requested explicitly, leaving the 1 format or all format cases unchanged) 7) Control.DownloadProgress.js now handles the case when we get JSON and sets the core-provided plain text next to the HTML. Leave the handling of non-JSON case in, because this means we can copy from an old COOL server to a new one. Note that this approach has the benefit that once the clipboard marker is inserted, the length of the text/html format would change, which means we can't parse the clipboard data till the marker is removed. Emitting JSON for html+text means adding the marker keeps the ability to parse the HTML and the plain text part of the clipboard in JS. Signed-off-by: Miklos Vajna <vmiklos@collabora.com> Change-Id: I67a1f669e8a638d34cc25a2f288a7b30884b9892
2024-03-19 06:12:16 -05:00
#include <common/JsonUtil.hpp>
#include <helpers.hpp>
#include <lokassert.hpp>
#include <wsd/COOLWSD.hpp>
#include <wsd/ClientSession.hpp>
cool#8465 clipboard: improve handling of plain text copy, complex case In case the selection is complex (not simple), we used to just request HTML, and then the browser converted that to plain text, which has the downsides already mentioned in commit 7f9de46688a64b42ba8f65cceb9fe2c6ddab89ef (cool#8465 clipboard: improve handling of plain text copy, simple case, 2024-03-08). Steps to support this: 1) Clipboard.js now asks for the text/html,text/plain;charset=utf-8 MIME types. 2) wsd: ClientRequestDispatcher::handleClipboardRequest() now maps this to DocumentBroker::CLIP_REQUEST_GET_HTML_PLAIN_ONLY 3) ClientSession::handleClipboardRequest() maps this to the HTML+plain text MIME type list. 4) kit: ChildSession::getClipboard() is now improved to take a list of MIME types, not just 1 or everything. 5) kit: ChildSession::getClipboard() now emits JSON in case not all, but multiple MIME types are requested. 6) wsd: ClientSession::postProcessCopyPayload() now knows how to postprocess clipboardcontent messages, which may or may not be JSON (it's JSON if more formats are requested explicitly, leaving the 1 format or all format cases unchanged) 7) Control.DownloadProgress.js now handles the case when we get JSON and sets the core-provided plain text next to the HTML. Leave the handling of non-JSON case in, because this means we can copy from an old COOL server to a new one. Note that this approach has the benefit that once the clipboard marker is inserted, the length of the text/html format would change, which means we can't parse the clipboard data till the marker is removed. Emitting JSON for html+text means adding the marker keeps the ability to parse the HTML and the plain text part of the clipboard in JS. Signed-off-by: Miklos Vajna <vmiklos@collabora.com> Change-Id: I67a1f669e8a638d34cc25a2f288a7b30884b9892
2024-03-19 06:12:16 -05:00
using namespace Poco::Net;
std::shared_ptr<ClientSession> getChildSession(size_t session)
{
std::shared_ptr<DocumentBroker> broker;
std::shared_ptr<ClientSession> clientSession;
std::vector<std::shared_ptr<DocumentBroker>> brokers = COOLWSD::getBrokersTestOnly();
assert(brokers.size() > 0);
broker = brokers[0];
auto sessions = broker->getSessionsTestOnlyUnsafe();
assert(sessions.size() > 0 && session < sessions.size());
return sessions[session];
}
std::string getSessionClipboardURI(size_t session)
{
std::shared_ptr<ClientSession> clientSession = getChildSession(session);
std::string tag = clientSession->getClipboardURI(false); // nominally thread unsafe
return tag;
}
// Inside the WSD process
class UnitCopyPasteWriter : public UnitWSD
{
STATE_ENUM(Phase, RunTest, WaitDocClose, PostCloseTest, Done) _phase;
public:
UnitCopyPasteWriter()
: UnitWSD("UnitCopyPasteWriter")
, _phase(Phase::RunTest)
{
}
void onDocBrokerDestroy(const std::string& /*docKey*/) override
{
LOK_ASSERT_STATE(_phase, Phase::WaitDocClose);
TRANSITION_STATE(_phase, Phase::PostCloseTest);
}
void runTest()
{
// Given a Writer document with bullets:
std::string documentPath, documentURL;
helpers::getDocumentPathAndURL("bullets.odt", documentPath, documentURL, testname);
std::shared_ptr<http::WebSocketSession> socket = helpers::loadDocAndGetSession(
socketPoll(), Poco::URI(helpers::getTestServerURI()), documentURL, testname);
helpers::sendTextFrame(socket, "uno .uno:SelectAll", testname);
// When copying the cnotent of the document:
helpers::sendAndDrain(socket, testname, "uno .uno:Copy", "statechanged:");
// Then make sure asking for multiple, specific formats results in a JSON answer, it's what
// JS expects:
{
std::string clipURI = getSessionClipboardURI(0);
clipURI += "&MimeType=text/html,text/plain;charset=utf-8";
std::shared_ptr<http::Session> httpSession = http::Session::create(clipURI);
std::shared_ptr<const http::Response> httpResponse =
httpSession->syncRequest(http::Request(Poco::URI(clipURI).getPathAndQuery()));
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
std::string body = httpResponse->getBody();
Poco::JSON::Object::Ptr object;
// This failed, we didn't return JSON.
LOK_ASSERT(JsonUtil::parseJSON(body, object));
LOK_ASSERT(object->has("text/html"));
std::string expectedPlainText(" • first\n • second\n • third");
std::string actualPlainText = object->get("text/plain;charset=utf-8").toString();
LOK_ASSERT_EQUAL(actualPlainText, expectedPlainText);
}
// Now also test HTML only:
{
std::string clipURI = getSessionClipboardURI(0);
clipURI += "&MimeType=text/html";
std::shared_ptr<http::Session> httpSession = http::Session::create(clipURI);
std::shared_ptr<const http::Response> httpResponse =
httpSession->syncRequest(http::Request(Poco::URI(clipURI).getPathAndQuery()));
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
std::string body = httpResponse->getBody();
Poco::JSON::Object::Ptr object;
LOK_ASSERT(JsonUtil::parseJSON(body, object));
LOK_ASSERT(object->has("text/html"));
}
cool#8465 clipboard: improve handling of plain text copy, complex case In case the selection is complex (not simple), we used to just request HTML, and then the browser converted that to plain text, which has the downsides already mentioned in commit 7f9de46688a64b42ba8f65cceb9fe2c6ddab89ef (cool#8465 clipboard: improve handling of plain text copy, simple case, 2024-03-08). Steps to support this: 1) Clipboard.js now asks for the text/html,text/plain;charset=utf-8 MIME types. 2) wsd: ClientRequestDispatcher::handleClipboardRequest() now maps this to DocumentBroker::CLIP_REQUEST_GET_HTML_PLAIN_ONLY 3) ClientSession::handleClipboardRequest() maps this to the HTML+plain text MIME type list. 4) kit: ChildSession::getClipboard() is now improved to take a list of MIME types, not just 1 or everything. 5) kit: ChildSession::getClipboard() now emits JSON in case not all, but multiple MIME types are requested. 6) wsd: ClientSession::postProcessCopyPayload() now knows how to postprocess clipboardcontent messages, which may or may not be JSON (it's JSON if more formats are requested explicitly, leaving the 1 format or all format cases unchanged) 7) Control.DownloadProgress.js now handles the case when we get JSON and sets the core-provided plain text next to the HTML. Leave the handling of non-JSON case in, because this means we can copy from an old COOL server to a new one. Note that this approach has the benefit that once the clipboard marker is inserted, the length of the text/html format would change, which means we can't parse the clipboard data till the marker is removed. Emitting JSON for html+text means adding the marker keeps the ability to parse the HTML and the plain text part of the clipboard in JS. Signed-off-by: Miklos Vajna <vmiklos@collabora.com> Change-Id: I67a1f669e8a638d34cc25a2f288a7b30884b9892
2024-03-19 06:12:16 -05:00
TRANSITION_STATE(_phase, Phase::WaitDocClose);
socket->asyncShutdown();
LOK_ASSERT(socket->waitForDisconnection(std::chrono::seconds(5)));
}
void invokeWSDTest() override
{
switch (_phase)
{
case Phase::RunTest:
{
runTest();
break;
}
case Phase::WaitDocClose:
break;
case Phase::PostCloseTest:
TRANSITION_STATE(_phase, Phase::Done);
passTest();
break;
case Phase::Done:
break;
}
}
};
UnitBase* unit_create_wsd(void) { return new UnitCopyPasteWriter(); }
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */