Do not allow SearchRendered to work on a delete nameMapper/Library.

By moving the nameMapper/library arguments in `getHtml`/`getXml` we avoid
any potential "use after free" of name mapper or library as they are not
stored.
This commit is contained in:
Matthieu Gautier 2023-09-19 16:45:11 +02:00
parent 1dc9705597
commit 9166b67c47
3 changed files with 36 additions and 45 deletions

View File

@ -37,29 +37,11 @@ class SearchRenderer
/** /**
* Construct a SearchRenderer from a SearchResultSet. * Construct a SearchRenderer from a SearchResultSet.
* *
* The constructed version of the SearchRenderer will not introduce
* the book name for each result. It is better to use the other constructor
* with a Library pointer to have a better html page.
*
* @param srs The `SearchResultSet` to render. * @param srs The `SearchResultSet` to render.
* @param mapper The `NameMapper` to use to do the rendering.
* @param start The start offset used for the srs. * @param start The start offset used for the srs.
* @param estimatedResultCount The estimatedResultCount of the whole search * @param estimatedResultCount The estimatedResultCount of the whole search
*/ */
SearchRenderer(zim::SearchResultSet srs, const NameMapper* mapper, SearchRenderer(zim::SearchResultSet srs, unsigned int start, unsigned int estimatedResultCount);
unsigned int start, unsigned int estimatedResultCount);
/**
* Construct a SearchRenderer from a SearchResultSet.
*
* @param srs The `SearchResultSet` to render.
* @param mapper The `NameMapper` to use to do the rendering.
* @param library The `Library` to use to look up book details for search results.
* @param start The start offset used for the srs.
* @param estimatedResultCount The estimatedResultCount of the whole search
*/
SearchRenderer(zim::SearchResultSet srs, const NameMapper* mapper, Library* library,
unsigned int start, unsigned int estimatedResultCount);
~SearchRenderer(); ~SearchRenderer();
@ -90,24 +72,32 @@ class SearchRenderer
this->pageLength = pageLength; this->pageLength = pageLength;
} }
std::string renderTemplate(const std::string& tmpl_str);
/** /**
* Generate the html page with the resutls of the search. * Generate the html page with the resutls of the search.
*
* @param mapper The `NameMapper` to use to do the rendering.
* @param library The `Library` to use to look up book details for search results.
May be nullptr. In this case, bookName is not set in the rendered string.
* @return The html string
*/ */
std::string getHtml(); std::string getHtml(const NameMapper& mapper, const Library* library);
/** /**
* Generate the xml page with the resutls of the search. * Generate the xml page with the resutls of the search.
*
* @param mapper The `NameMapper` to use to do the rendering.
* @param library The `Library` to use to look up book details for search results.
May be nullptr. In this case, bookName is not set in the rendered string.
* @return The xml string
*/ */
std::string getXml(); std::string getXml(const NameMapper& mapper, const Library* library);
protected: // function
std::string renderTemplate(const std::string& tmpl_str, const NameMapper& mapper, const Library *library);
protected: protected:
std::string beautifyInteger(const unsigned int number); std::string beautifyInteger(const unsigned int number);
zim::SearchResultSet m_srs; zim::SearchResultSet m_srs;
const NameMapper* mp_nameMapper;
Library* mp_library;
std::string searchBookQuery; std::string searchBookQuery;
std::string searchPattern; std::string searchPattern;
std::string protocolPrefix; std::string protocolPrefix;

View File

@ -36,16 +36,9 @@ namespace kiwix
{ {
/* Constructor */ /* Constructor */
SearchRenderer::SearchRenderer(zim::SearchResultSet srs, const NameMapper* mapper, SearchRenderer::SearchRenderer(zim::SearchResultSet srs,
unsigned int start, unsigned int estimatedResultCount)
: SearchRenderer(srs, mapper, nullptr, start, estimatedResultCount)
{}
SearchRenderer::SearchRenderer(zim::SearchResultSet srs, const NameMapper* mapper, Library* library,
unsigned int start, unsigned int estimatedResultCount) unsigned int start, unsigned int estimatedResultCount)
: m_srs(srs), : m_srs(srs),
mp_nameMapper(mapper),
mp_library(library),
protocolPrefix("zim://"), protocolPrefix("zim://"),
searchProtocolPrefix("search://"), searchProtocolPrefix("search://"),
estimatedResultCount(estimatedResultCount), estimatedResultCount(estimatedResultCount),
@ -164,7 +157,7 @@ kainjow::mustache::data buildPagination(
return pagination; return pagination;
} }
std::string SearchRenderer::renderTemplate(const std::string& tmpl_str) std::string SearchRenderer::renderTemplate(const std::string& tmpl_str, const NameMapper& nameMapper, const Library* library)
{ {
const std::string absPathPrefix = protocolPrefix; const std::string absPathPrefix = protocolPrefix;
// Build the results list // Build the results list
@ -172,12 +165,12 @@ std::string SearchRenderer::renderTemplate(const std::string& tmpl_str)
for (auto it = m_srs.begin(); it != m_srs.end(); it++) { for (auto it = m_srs.begin(); it != m_srs.end(); it++) {
kainjow::mustache::data result; kainjow::mustache::data result;
const std::string zim_id(it.getZimId()); const std::string zim_id(it.getZimId());
const auto path = mp_nameMapper->getNameForId(zim_id) + "/" + it.getPath(); const auto path = nameMapper.getNameForId(zim_id) + "/" + it.getPath();
result.set("title", it.getTitle()); result.set("title", it.getTitle());
result.set("absolutePath", absPathPrefix + urlEncode(path)); result.set("absolutePath", absPathPrefix + urlEncode(path));
result.set("snippet", it.getSnippet()); result.set("snippet", it.getSnippet());
if (mp_library) { if (library) {
result.set("bookTitle", mp_library->getBookById(zim_id).getTitle()); result.set("bookTitle", library->getBookById(zim_id).getTitle());
} }
if (it.getWordCount() >= 0) { if (it.getWordCount() >= 0) {
result.set("wordCount", kiwix::beautifyInteger(it.getWordCount())); result.set("wordCount", kiwix::beautifyInteger(it.getWordCount()));
@ -222,14 +215,14 @@ std::string SearchRenderer::renderTemplate(const std::string& tmpl_str)
return ss.str(); return ss.str();
} }
std::string SearchRenderer::getHtml() std::string SearchRenderer::getHtml(const NameMapper& mapper, const Library* library)
{ {
return renderTemplate(RESOURCE::templates::search_result_html); return renderTemplate(RESOURCE::templates::search_result_html, mapper, library);
} }
std::string SearchRenderer::getXml() std::string SearchRenderer::getXml(const NameMapper& mapper, const Library* library)
{ {
return renderTemplate(RESOURCE::templates::search_result_xml); return renderTemplate(RESOURCE::templates::search_result_xml, mapper, library);
} }

View File

@ -963,7 +963,7 @@ std::unique_ptr<Response> InternalServer::handle_search_request(const RequestCon
const auto pageLength = getSearchPageSize(request); const auto pageLength = getSearchPageSize(request);
/* Get the results */ /* Get the results */
SearchRenderer renderer(search->getResults(start-1, pageLength), mp_nameMapper.get(), mp_library.get(), start, SearchRenderer renderer(search->getResults(start-1, pageLength), start,
search->getEstimatedMatches()); search->getEstimatedMatches());
renderer.setSearchPattern(searchInfo.pattern); renderer.setSearchPattern(searchInfo.pattern);
renderer.setSearchBookQuery(searchInfo.bookFilterQuery); renderer.setSearchBookQuery(searchInfo.bookFilterQuery);
@ -971,9 +971,17 @@ std::unique_ptr<Response> InternalServer::handle_search_request(const RequestCon
renderer.setSearchProtocolPrefix(m_root + "/search"); renderer.setSearchProtocolPrefix(m_root + "/search");
renderer.setPageLength(pageLength); renderer.setPageLength(pageLength);
if (request.get_requested_format() == "xml") { if (request.get_requested_format() == "xml") {
return ContentResponse::build(*this, renderer.getXml(), "application/rss+xml; charset=utf-8"); return ContentResponse::build(
*this,
renderer.getXml(*mp_nameMapper, mp_library.get()),
"application/rss+xml; charset=utf-8"
);
} }
auto response = ContentResponse::build(*this, renderer.getHtml(), "text/html; charset=utf-8"); auto response = ContentResponse::build(
*this,
renderer.getHtml(*mp_nameMapper, mp_library.get()),
"text/html; charset=utf-8"
);
// XXX: Now this has to be handled by the iframe-based viewer which // XXX: Now this has to be handled by the iframe-based viewer which
// XXX: has to resolve if the book selection resulted in a single book. // XXX: has to resolve if the book selection resulted in a single book.
/* /*