Skip to content

Commit b31eb2a

Browse files
committed
New POST service to render a search result + unit and integ. tests
This adds a new service render-search-result, which renders an image of the position where, the search fund a hit. The search result contains the information in which object or paragraph, which is just the node id and node type from the document model. The service takes the document and the search result (xml file) as the input and returns a PNG image as the output. Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> Change-Id: Iffc158c5b0a3c9a63f8d05830314c9bc1616b3b1 Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
1 parent 6f6ccbf commit b31eb2a

11 files changed

+488
-38
lines changed

Diff for: kit/ChildSession.cpp

+61-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ bool ChildSession::_handleInput(const char *buffer, int length)
343343
tokens.equals(0, "completefunction")||
344344
tokens.equals(0, "formfieldevent") ||
345345
tokens.equals(0, "traceeventrecording") ||
346-
tokens.equals(0, "sallogoverride"));
346+
tokens.equals(0, "sallogoverride") ||
347+
tokens.equals(0, "rendersearchresult"));
347348

348349
std::string pzName("ChildSession::_handleInput:" + tokens[0]);
349350
ProfileZone pz(pzName.c_str());
@@ -534,6 +535,10 @@ bool ChildSession::_handleInput(const char *buffer, int length)
534535
getLOKit()->setOption("sallogoverride", tokens[1].c_str());
535536
}
536537
}
538+
else if (tokens.equals(0, "rendersearchresult"))
539+
{
540+
return renderSearchResult(buffer, length, tokens);
541+
}
537542
else
538543
{
539544
assert(false && "Unknown command token.");
@@ -1658,6 +1663,61 @@ bool ChildSession::formFieldEvent(const char* buffer, int length, const StringVe
16581663
return true;
16591664
}
16601665

1666+
bool ChildSession::renderSearchResult(const char* buffer, int length, const StringVector& /*tokens*/)
1667+
{
1668+
std::string sContent(buffer, length);
1669+
std::string sCommand("rendersearchresult ");
1670+
std::string sArguments = sContent.substr(sCommand.size());
1671+
1672+
if (sArguments.empty())
1673+
{
1674+
sendTextFrameAndLogError("error: cmd=rendersearchresult kind=syntax");
1675+
return false;
1676+
}
1677+
1678+
getLOKitDocument()->setView(_viewId);
1679+
1680+
const auto eTileMode = static_cast<LibreOfficeKitTileMode>(getLOKitDocument()->getTileMode());
1681+
1682+
unsigned char* pBitmapBuffer = nullptr;
1683+
1684+
int nWidth = 0;
1685+
int nHeight = 0;
1686+
size_t nByteSize = 0;
1687+
1688+
bool bSuccess = getLOKitDocument()->renderSearchResult(sArguments.c_str(), &pBitmapBuffer, &nWidth, &nHeight, &nByteSize);
1689+
1690+
if (bSuccess && nByteSize > 0)
1691+
{
1692+
std::vector<char> aOutput;
1693+
aOutput.reserve(nByteSize * 3 / 4); // reserve 75% of original size
1694+
1695+
if (Png::encodeBufferToPNG(pBitmapBuffer, nWidth, nHeight, aOutput, eTileMode))
1696+
{
1697+
static const std::string aHeader = "rendersearchresult:";
1698+
size_t nResponseSize = aHeader.size() + aOutput.size();
1699+
std::vector<char> aResponse(nResponseSize);
1700+
std::copy(aHeader.begin(), aHeader.end(), aResponse.begin());
1701+
std::copy(aOutput.begin(), aOutput.end(), aResponse.begin() + aHeader.size());
1702+
sendBinaryFrame(aResponse.data(), aResponse.size());
1703+
}
1704+
else
1705+
{
1706+
sendTextFrameAndLogError("error: cmd=rendersearchresult kind=failure");
1707+
}
1708+
}
1709+
else
1710+
{
1711+
sendTextFrameAndLogError("error: cmd=rendersearchresult kind=failure");
1712+
}
1713+
1714+
if (pBitmapBuffer)
1715+
free(pBitmapBuffer);
1716+
1717+
return true;
1718+
}
1719+
1720+
16611721
bool ChildSession::completeFunction(const char* /*buffer*/, int /*length*/, const StringVector& tokens)
16621722
{
16631723
std::string functionName;

Diff for: kit/ChildSession.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,10 @@ class ChildSession final : public Session
321321
#ifdef ENABLE_FREEMIUM
322322
bool updateFreemiumStatus(const char* buffer, int length, const StringVector& tokens);
323323
#endif
324+
bool formFieldEvent(const char* buffer, int length, const StringVector& tokens);
325+
bool renderSearchResult(const char* buffer, int length, const StringVector& tokens);
324326

325327
void rememberEventsForInactiveUser(const int type, const std::string& payload);
326-
bool formFieldEvent(const char* buffer, int length, const StringVector& tokens);
327328

328329
virtual void disconnect() override;
329330
virtual bool _handleInput(const char* buffer, int length) override;

Diff for: test/Makefile.am

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ noinst_LTLIBRARIES = \
3333
unit-load-torture.la \
3434
unit-rendering-options.la \
3535
unit-password-protected.la \
36+
unit-render-search-result.la \
3637
unit-render-shape.la \
3738
unit-each-view.la \
3839
unit-session.la \
@@ -199,6 +200,8 @@ unit_rendering_options_la_SOURCES = UnitRenderingOptions.cpp
199200
unit_rendering_options_la_LIBADD = $(CPPUNIT_LIBS)
200201
unit_password_protected_la_SOURCES = UnitPasswordProtected.cpp
201202
unit_password_protected_la_LIBADD = $(CPPUNIT_LIBS)
203+
unit_render_search_result_la_SOURCES = UnitRenderSearchResult.cpp
204+
unit_render_search_result_la_LIBADD = $(CPPUNIT_LIBS)
202205
unit_render_shape_la_SOURCES = UnitRenderShape.cpp
203206
unit_render_shape_la_LIBADD = $(CPPUNIT_LIBS)
204207
unit_each_view_la_SOURCES = UnitEachView.cpp
@@ -254,6 +257,7 @@ TESTS = \
254257
unit-load-torture.la \
255258
unit-rendering-options.la \
256259
unit-password-protected.la \
260+
unit-render-search-result.la \
257261
unit-render-shape.la \
258262
unit-each-view.la \
259263
unit-session.la \

Diff for: test/UnitRenderSearchResult.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2+
/*
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
#include <config.h>
9+
10+
#include <memory>
11+
#include <string>
12+
13+
#include <Poco/URI.h>
14+
#include <test/lokassert.hpp>
15+
16+
#include <Unit.hpp>
17+
#include <Util.hpp>
18+
#include <helpers.hpp>
19+
20+
class LOOLWebSocket;
21+
22+
class UnitRenderSearchResult : public UnitWSD
23+
{
24+
public:
25+
void invokeWSDTest() override;
26+
};
27+
28+
void UnitRenderSearchResult::invokeWSDTest()
29+
{
30+
const char testname[] = "UnitRenderSearchResult";
31+
32+
try
33+
{
34+
std::string documentPath;
35+
std::string documentURL;
36+
helpers::getDocumentPathAndURL("RenderSearchResultTest.odt", documentPath, documentURL, testname);
37+
38+
std::shared_ptr<LOOLWebSocket> socket = helpers::loadDocAndGetSocket(Poco::URI(helpers::getTestServerURI()), documentURL, testname);
39+
40+
helpers::sendTextFrame(socket, "rendersearchresult <indexing><paragraph node_type=\"writer\" index=\"19\"/></indexing>");
41+
std::vector<char> responseMessage = helpers::getResponseMessage(socket, "rendersearchresult:", testname);
42+
43+
// LOK_ASSERT(responseMessage.size() >= 100);
44+
// LOK_ASSERT_EQUAL(responseMessage[1], 'P');
45+
// LOK_ASSERT_EQUAL(responseMessage[2], 'N');
46+
// LOK_ASSERT_EQUAL(responseMessage[3], 'G');
47+
}
48+
catch (const Poco::Exception& exc)
49+
{
50+
LOK_ASSERT_FAIL(exc.displayText());
51+
}
52+
53+
exitTest(TestResult::Ok);
54+
}
55+
56+
UnitBase* unit_create_wsd(void) { return new UnitRenderSearchResult(); }
57+
58+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Diff for: test/data/RenderSearchResultFragment.xml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<indexing>
3+
<paragraph node_type="writer" index="19"></paragraph>
4+
</indexing>

Diff for: test/data/RenderSearchResultTest.odt

124 KB
Binary file not shown.

Diff for: test/integration-http-server.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class HTTPServerTest : public CPPUNIT_NS::TestFixture
4646
CPPUNIT_TEST(testConvertToWithForwardedIP_Deny);
4747
CPPUNIT_TEST(testConvertToWithForwardedIP_Allow);
4848
CPPUNIT_TEST(testConvertToWithForwardedIP_DenyMulti);
49+
CPPUNIT_TEST(testRenderSearchResult);
4950

5051
CPPUNIT_TEST_SUITE_END();
5152

@@ -58,6 +59,7 @@ class HTTPServerTest : public CPPUNIT_NS::TestFixture
5859
void testConvertToWithForwardedIP_Deny();
5960
void testConvertToWithForwardedIP_Allow();
6061
void testConvertToWithForwardedIP_DenyMulti();
62+
void testRenderSearchResult();
6163

6264
protected:
6365
void assertHTTPFilesExist(const Poco::URI& uri,
@@ -484,6 +486,48 @@ void HTTPServerTest::testConvertToWithForwardedIP_DenyMulti()
484486
}
485487
}
486488

489+
void HTTPServerTest::testRenderSearchResult()
490+
{
491+
const char* testname = "testRenderSearchResult";
492+
const std::string srcPathDoc = FileUtil::getTempFileCopyPath(TDOC, "RenderSearchResultTest.odt", testname);
493+
const std::string srcPathXml = FileUtil::getTempFileCopyPath(TDOC, "RenderSearchResultFragment.xml", testname);
494+
std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
495+
session->setTimeout(Poco::Timespan(10, 0)); // 10 seconds.
496+
497+
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/lool/render-search-result");
498+
Poco::Net::HTMLForm form;
499+
form.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART);
500+
form.addPart("document", new Poco::Net::FilePartSource(srcPathDoc));
501+
form.addPart("result", new Poco::Net::FilePartSource(srcPathXml));
502+
form.prepareSubmit(request);
503+
try
504+
{
505+
form.write(session->sendRequest(request));
506+
}
507+
catch (const std::exception& ex)
508+
{
509+
// In case the server is still starting up.
510+
sleep(5);
511+
form.write(session->sendRequest(request));
512+
}
513+
514+
Poco::Net::HTTPResponse response;
515+
std::stringstream actualStream;
516+
std::istream& responseStream = session->receiveResponse(response);
517+
Poco::StreamCopier::copyStream(responseStream, actualStream);
518+
519+
// Remove the temp files.
520+
FileUtil::removeFile(srcPathDoc);
521+
FileUtil::removeFile(srcPathXml);
522+
523+
std::string actualString = actualStream.str();
524+
525+
LOK_ASSERT(actualString.size() >= 100);
526+
LOK_ASSERT_EQUAL(actualString[1], 'P');
527+
LOK_ASSERT_EQUAL(actualString[2], 'N');
528+
LOK_ASSERT_EQUAL(actualString[3], 'G');
529+
}
530+
487531
CPPUNIT_TEST_SUITE_REGISTRATION(HTTPServerTest);
488532

489533
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Diff for: wsd/ClientSession.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,8 @@ bool ClientSession::_handleInput(const char *buffer, int length)
986986
tokens[0] == "exportsignanduploaddocument" ||
987987
tokens[0] == "rendershapeselection" ||
988988
tokens[0] == "resizewindow" ||
989-
tokens[0] == "removetextcontext")
989+
tokens[0] == "removetextcontext" ||
990+
tokens[0] == "rendersearchresult")
990991
{
991992
if (tokens.equals(0, "key"))
992993
_keyEvents++;
@@ -1260,7 +1261,7 @@ bool ClientSession::filterMessage(const std::string& message) const
12601261
{
12611262
// By default, don't allow anything
12621263
allowed = false;
1263-
if (tokens.equals(0, "userinactive") || tokens.equals(0, "useractive") || tokens.equals(0, "saveas"))
1264+
if (tokens.equals(0, "userinactive") || tokens.equals(0, "useractive") || tokens.equals(0, "saveas") || tokens.equals(0, "rendersearchresult"))
12641265
{
12651266
allowed = true;
12661267
}

0 commit comments

Comments
 (0)