WebDAV: moved common href and etag handling into common parser

The handling of href and etag data had to be done by all
classes using initResponseHandler(). Now it is in the XML
handler itself.

In addition, users of the class process the gathered results
at the end of the results XML element. At that point, all
the response parts are guaranteed to be processed.
This commit is contained in:
Patrick Ohly 2011-06-25 15:12:18 +02:00
parent 7e542c596d
commit 8d038294b8
4 changed files with 60 additions and 39 deletions

View file

@ -82,15 +82,14 @@ void CalDAVSource::listAllSubItems(SubRevisionMap_t &revisions)
getSession()->startOperation("REPORT 'meta data'", deadline);
while (true) {
string result;
string href, etag, data;
string data;
Neon::XMLParser parser;
parser.initReportParser(href, etag);
parser.initReportParser(boost::bind(&CalDAVSource::appendItem, this,
boost::ref(revisions),
_1, _2, boost::ref(data)));
m_cache.clear();
parser.pushHandler(boost::bind(Neon::XMLParser::accept, "urn:ietf:params:xml:ns:caldav", "calendar-data", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(data), _2, _3),
boost::bind(&CalDAVSource::appendItem, this,
boost::ref(revisions),
boost::ref(href), boost::ref(etag), boost::ref(data)));
boost::bind(Neon::XMLParser::append, boost::ref(data), _2, _3));
Neon::Request report(*getSession(), "REPORT", getCalendar().m_path, query, parser);
report.addHeader("Depth", "1");
report.addHeader("Content-Type", "application/xml; charset=\"utf-8\"");
@ -103,8 +102,8 @@ void CalDAVSource::listAllSubItems(SubRevisionMap_t &revisions)
}
int CalDAVSource::appendItem(SubRevisionMap_t &revisions,
std::string &href,
std::string &etag,
const std::string &href,
const std::string &etag,
std::string &data)
{
Event::unescapeRecurrenceID(data);
@ -150,8 +149,6 @@ int CalDAVSource::appendItem(SubRevisionMap_t &revisions,
// reset data for next item
data.clear();
href.clear();
etag.clear();
return 0;
}
@ -753,9 +750,8 @@ CalDAVSource::Event &CalDAVSource::loadItem(Event &event)
getSession()->startOperation("REPORT 'single item'", deadline);
while (true) {
string result;
string href, etag;
Neon::XMLParser parser;
parser.initReportParser(href, etag);
parser.initReportParser();
item = "";
parser.pushHandler(boost::bind(Neon::XMLParser::accept, "urn:ietf:params:xml:ns:caldav", "calendar-data", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(item), _2, _3));
@ -924,14 +920,13 @@ void CalDAVSource::backupData(const SyncSource::Operations::ConstBackupInfo &old
"</C:filter>\n"
"</C:calendar-query>\n";
string result;
string href, etag, data;
string data;
Neon::XMLParser parser;
parser.initReportParser(href, etag);
parser.initReportParser(boost::bind(&CalDAVSource::backupItem, this,
boost::ref(cache),
_1, _2, boost::ref(data)));
parser.pushHandler(boost::bind(Neon::XMLParser::accept, "urn:ietf:params:xml:ns:caldav", "calendar-data", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(data), _2, _3),
boost::bind(&CalDAVSource::backupItem, this,
boost::ref(cache),
boost::ref(href), boost::ref(etag), boost::ref(data)));
boost::bind(Neon::XMLParser::append, boost::ref(data), _2, _3));
Timespec deadline = createDeadline();
getSession()->startOperation("REPORT 'full calendar'", deadline);
while (true) {
@ -947,8 +942,8 @@ void CalDAVSource::backupData(const SyncSource::Operations::ConstBackupInfo &old
}
int CalDAVSource::backupItem(ItemCache &cache,
std::string &href,
std::string &etag,
const std::string &href,
const std::string &etag,
std::string &data)
{
Event::unescapeRecurrenceID(data);
@ -958,8 +953,6 @@ int CalDAVSource::backupItem(ItemCache &cache,
// reset data for next item
data.clear();
href.clear();
etag.clear();
return 0;
}

View file

@ -171,14 +171,14 @@ class CalDAVSource : public WebDAVSource,
/** callback for listAllSubItems: parse and add new item */
int appendItem(SubRevisionMap_t &revisions,
std::string &href,
std::string &etag,
const std::string &href,
const std::string &etag,
std::string &data);
/** callback for backupData(): dump into backup */
int backupItem(ItemCache &cache,
std::string &href,
std::string &etag,
const std::string &href,
const std::string &etag,
std::string &data);
};

View file

@ -777,18 +777,20 @@ int XMLParser::reset(std::string &buffer)
return 0;
}
void XMLParser::initReportParser(std::string &href,
std::string &etag)
void XMLParser::initReportParser(const ResponseEndCB_t &responseEnd)
{
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "multistatus", _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "response", _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "response", _2, _3),
Neon::XMLParser::DataCB_t(),
boost::bind(&Neon::XMLParser::doResponseEnd,
this, responseEnd));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "href", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(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:", "prop", _2, _3));
pushHandler(boost::bind(Neon::XMLParser::accept, "DAV:", "getetag", _2, _3),
boost::bind(Neon::XMLParser::append, boost::ref(etag), _2, _3));
boost::bind(Neon::XMLParser::append, boost::ref(m_etag), _2, _3));
}
Request::Request(Session &session,

View file

@ -417,15 +417,30 @@ class XMLParser
static int reset(std::string &buffer);
/**
* Setup parser for handling REPORT result.
* Caller still needs to push a handler for
* "urn:ietf:params:xml:ns:caldav", "calendar-data".
*
* @param href caller's buffer for DAV:href
* @param etag caller's buffer for DAV:getetag
* called once a response is completely parse
*
* @param href the path for which the response was sent
* @param etag it's etag, empty if not requested or available
*/
void initReportParser(std::string &href,
std::string &etag);
typedef boost::function<void (const std::string &, const std::string &)> ResponseEndCB_t;
/**
* Setup parser for handling REPORT result.
* Already deals with href and etag, caching it
* for each response and passing it to the "response
* complete" callback.
*
* Caller still needs to push a handler for
* "urn:ietf:params:xml:ns:caldav", "calendar-data",
* or any other elements that it wants to know about.
*
* @param responseEnd called at the end of processing each response;
* this is the only time when all relevant
* parts of the response are guaranteed to have been seen;
* when expecting only one response, the callback
* is not needed
*/
void initReportParser(const ResponseEndCB_t &responseEnd = ResponseEndCB_t());
private:
ne_xml_parser *m_parser;
@ -443,6 +458,17 @@ class XMLParser
};
std::list<Callbacks> m_stack;
/** buffers for initReportParser() */
std::string m_href, m_etag;
int doResponseEnd(const ResponseEndCB_t &responseEnd) {
responseEnd(m_href, m_etag);
// clean up for next response
m_href.clear();
m_etag.clear();
return 0;
}
static int startCB(void *userdata, int parent,
const char *nspace, const char *name,
const char **atts);