summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-rw-r--r--service/api.ice4
-rw-r--r--service/apiImpl.cpp44
-rw-r--r--service/test.cpp5
-rw-r--r--service/uptr.cpp26
-rw-r--r--service/uptr.h38
5 files changed, 97 insertions, 20 deletions
diff --git a/service/api.ice b/service/api.ice
index c207c3d..64edfe7 100644
--- a/service/api.ice
+++ b/service/api.ice
@@ -10,8 +10,8 @@ module MirrorSearch {
interface Search {
idempotent SearchServices getServices();
- idempotent SearchHits getMatches(string filename);
- idempotent optional(0) string feelingLucky(string filename);
+ idempotent SearchHits getMatches(string filename) throws XmlError;
+ idempotent optional(0) string feelingLucky(string filename) throws XmlError;
};
};
diff --git a/service/apiImpl.cpp b/service/apiImpl.cpp
index 588d360..1de31cb 100644
--- a/service/apiImpl.cpp
+++ b/service/apiImpl.cpp
@@ -1,8 +1,9 @@
#include "apiImpl.h"
+#include "uptr.h"
#include <sql/getServices.sql.h>
#include <buffer.h>
-#include <memory>
+#include <compileTimeFormatter.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
@@ -21,35 +22,42 @@ namespace MirrorSearch {
return fetch<SearchServices>(sql::getServices);
}
- typedef std::shared_ptr<xmlDoc> xmlDocSPtr;
- typedef std::shared_ptr<xmlXPathContext> xmlXPathContextSPtr;
- typedef std::shared_ptr<xmlXPathObject> xmlXPathObjectSPtr;
+ template<typename Fmt, typename ... P>
+ void
+ libxmlErrorHandler(const std::string & fn, const P & ... p)
+ {
+ throw XmlError(Fmt::get(fn, xmlGetLastError()->message, p...));
+ }
+ template<typename Fmt, typename ... P>
+ auto lEHB(const P & ... p)
+ {
+ return std::bind(&libxmlErrorHandler<Fmt, P...>, std::placeholders::_1, p...);
+ }
+ typedef UPtr<xmlDoc> xmlDocSPtr;
+ typedef UPtr<xmlXPathContext> xmlXPathContextSPtr;
+ typedef UPtr<xmlXPathObject> xmlXPathObjectSPtr;
+
+ AdHocFormatter(Read, "Failed to read in %? (%?) [%?, %?]");
static auto getDoc(const ::std::string & url, int flags)
{
- if (auto doc = xmlDocSPtr(htmlReadFile(url.c_str(), NULL, flags), xmlFreeDoc)) {
- return doc;
- }
- throw XmlError("Failed to open " + url);
+ return make_unique(htmlReadFile, xmlFreeDoc, lEHB<Read>(url, flags), url.c_str(), (const char*)NULL, flags);
}
+ AdHocFormatter(XPathCtx, "Failed to create xpath context in %? (%?)");
static auto getXPathCxt(const xmlDocSPtr & doc)
{
- if (auto xpathCtx = xmlXPathContextSPtr(xmlXPathNewContext(doc.get()), xmlXPathFreeContext)) {
- return xpathCtx;
- }
- throw XmlError("Failed to create xpath context");
+ return make_unique(xmlXPathNewContext, xmlXPathFreeContext, lEHB<XPathCtx>(), doc.get());
}
+ AdHocFormatter(XPathEval, "Failed to evaluate xpath in %? (%?) [%?]");
static auto getXPathObj(const ::std::string & xpath, const xmlXPathContextSPtr & ctx, xmlXPathObjectType type)
{
- if (auto xpathObj = xmlXPathObjectSPtr(xmlXPathEvalExpression(BAD_CAST xpath.c_str(), ctx.get()), xmlXPathFreeObject)) {
- if (xpathObj->type != type) {
- throw XmlError("Xpath evaluates to wrong type " + xpath);
- }
- return xpathObj;
+ auto xpathObj = make_unique(xmlXPathEvalExpression, xmlXPathFreeObject, lEHB<XPathEval>(xpath), BAD_CAST xpath.c_str(), ctx.get());
+ if (xpathObj->type != type) {
+ throw XmlError("Xpath evaluates to wrong type " + xpath);
}
- throw XmlError("Failed to evaluate xpath " + xpath);
+ return xpathObj;
}
void SearchImpl::callService(const ::std::string & fn, const SearchServicePtr & s, SearchHits & sh) const
diff --git a/service/test.cpp b/service/test.cpp
index c115712..8b93cf8 100644
--- a/service/test.cpp
+++ b/service/test.cpp
@@ -47,6 +47,11 @@ BOOST_AUTO_TEST_CASE(getServices)
BOOST_CHECK(!ss.front()->urlxpath.empty());
}
+BOOST_AUTO_TEST_CASE(getMatches_failure)
+{
+ BOOST_REQUIRE_THROW(s->getMatches("no.fixture"), MirrorSearch::XmlError);
+}
+
BOOST_AUTO_TEST_CASE(getMatches_zstd_notfound)
{
auto ms = s->getMatches("zstd-1.3.3.tar.gz");
diff --git a/service/uptr.cpp b/service/uptr.cpp
new file mode 100644
index 0000000..1669a69
--- /dev/null
+++ b/service/uptr.cpp
@@ -0,0 +1,26 @@
+#include "uptr.h"
+#include <execinfo.h>
+#include <boost/assert.hpp>
+#include <string>
+#include <stdlib.h>
+#include <exception>
+
+namespace MirrorSearch {
+
+ std::string
+ failingFunction(void * const func)
+ {
+ char ** fn = backtrace_symbols(&func, 1);
+ BOOST_ASSERT(fn);
+ BOOST_ASSERT(*fn);
+ std::string funcName(*fn);
+ free(fn);
+ return funcName;
+ }
+
+ void
+ defaultErrorHandler(const std::string & fn)
+ {
+ throw std::runtime_error("Fatal error in " + fn);
+ }
+}
diff --git a/service/uptr.h b/service/uptr.h
new file mode 100644
index 0000000..1de1f99
--- /dev/null
+++ b/service/uptr.h
@@ -0,0 +1,38 @@
+#ifndef MIRRORSEARCH_UPTR_H
+#define MIRRORSEARCH_UPTR_H
+
+#include <memory>
+#include <functional>
+
+namespace MirrorSearch {
+ typedef std::function<void(const std::string &)> OnError;
+
+ std::string
+ failingFunction(void * const func);
+
+ void
+ defaultErrorHandler(const std::string &);
+
+ template<typename O> using UPtr = std::unique_ptr<O, void(*)(O*)>;
+
+ template<typename R, typename ... P, typename ... A>
+ R *
+ make_unique(R * (*func)(P...), OnError onError, A ... p)
+ {
+ if (auto obj = func(p...)) {
+ return obj;
+ }
+ onError(failingFunction((void * const)func));
+ throw std::runtime_error("Error handler did not throw");
+ }
+
+ template<typename R, typename ... P, typename ... A>
+ UPtr<R>
+ make_unique(R*(*get)(P...), void(*release)(R*), OnError onError, A ... p)
+ {
+ return std::unique_ptr<R, void(*)(R*)>(make_unique(get, onError, p...), release);
+ }
+}
+
+#endif
+