WebDAV: enhance report handling (status, aborting)

Capture the item status and pass it to the response handler.

Response handlers are allowed to return a non-zero integer when using
the initAbortingReportParser(), which then aborts processing of the
response.

This leads to errors being returned by
ne_xml_dispatch_request(). Session::run() needs to be told if the
request was aborted, in which case all errors are ignored.
This commit is contained in:
Patrick Ohly 2015-02-12 13:12:16 +01:00
parent 905ca53824
commit 85df49a68b
2 changed files with 43 additions and 10 deletions

View File

@ -16,6 +16,7 @@
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <syncevo/util.h>
#include <syncevo/Logging.h>
@ -889,7 +890,7 @@ int XMLParser::reset(std::string &buffer)
return 0;
}
void XMLParser::initReportParser(const ResponseEndCB_t &responseEnd)
void XMLParser::initAbortingReportParser(const ResponseEndCB_t &responseEnd)
{
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "multistatus", _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "response", _2, _3),
@ -899,12 +900,32 @@ void XMLParser::initReportParser(const ResponseEndCB_t &responseEnd)
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "href", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(m_href), _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "propstat", _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "status", _2, _3) /* check status? */);
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "status", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(m_status), _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "prop", _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "getetag", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(m_etag), _2, _3));
}
static int VoidResponseEndCBWrapper(const XMLParser::VoidResponseEndCB_t &responseEnd,
const std::string &href,
const std::string &etag,
const std::string &status)
{
responseEnd(href, etag, status);
return 0;
}
void XMLParser::initReportParser(const VoidResponseEndCB_t &responseEnd)
{
if (responseEnd) {
initAbortingReportParser(boost::bind(VoidResponseEndCBWrapper, responseEnd, _1, _2, _3));
} else {
initAbortingReportParser(ResponseEndCB_t());
}
}
Request::Request(Session &session,
const std::string &method,
const std::string &path,
@ -974,7 +995,7 @@ void Session::checkAuthorization()
}
}
bool Session::run(Request &request, const std::set<int> *expectedCodes)
bool Session::run(Request &request, const std::set<int> *expectedCodes, const boost::function<bool ()> &aborted)
{
int error;
@ -992,6 +1013,11 @@ bool Session::run(Request &request, const std::set<int> *expectedCodes)
error = ne_xml_dispatch_request(req, request.getParser()->get());
}
// Was request intentionally aborted?
if (error && aborted && aborted()) {
return true;
}
return checkError(error, request.getStatus()->code, request.getStatus(),
request.getResponseHeader("Location"),
request.getPath(),

View File

@ -375,7 +375,8 @@ class Session {
*
* @return result of Session::checkError()
*/
bool run(Request &request, const std::set<int> *expectedCodes);
bool run(Request &request, const std::set<int> *expectedCodes,
const boost::function<bool ()> &aborted = boost::function<bool ()>());
/**
* to be called after each operation which might have produced debugging output by neon;
@ -516,12 +517,15 @@ class XMLParser
static int reset(std::string &buffer);
/**
* called once a response is completely parse
* Called each time a response is completely parsed.
*
* @param href the path for which the response was sent
* @param etag it's etag, empty if not requested or available
* @param status it's status line, empty if not requested or unavailable
* @return non-zero for aborting the parsing
*/
typedef boost::function<void (const std::string &, const std::string &)> ResponseEndCB_t;
typedef boost::function<int (const std::string &, const std::string &, const std::string &)> ResponseEndCB_t;
typedef boost::function<void (const std::string &, const std::string &, const std::string &)> VoidResponseEndCB_t;
/**
* Setup parser for handling REPORT result.
@ -539,7 +543,8 @@ class XMLParser
* when expecting only one response, the callback
* is not needed
*/
void initReportParser(const ResponseEndCB_t &responseEnd = ResponseEndCB_t());
void initReportParser(const VoidResponseEndCB_t &responseEnd = VoidResponseEndCB_t());
void initAbortingReportParser(const ResponseEndCB_t &responseEnd);
private:
ne_xml_parser *m_parser;
@ -558,16 +563,18 @@ class XMLParser
std::list<Callbacks> m_stack;
/** buffers for initReportParser() */
std::string m_href, m_etag;
std::string m_href, m_etag, m_status;
int doResponseEnd(const ResponseEndCB_t &responseEnd) {
int abort = 0;
if (responseEnd) {
responseEnd(m_href, m_etag);
abort = responseEnd(m_href, m_etag, m_status);
}
// clean up for next response
m_href.clear();
m_etag.clear();
return 0;
m_status.clear();
return abort;
}
static int startCB(void *userdata, int parent,