From c1ebae519210cd4d09eb63bde593d48e769ad7ca Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sat, 20 Apr 2013 21:28:50 +0200 Subject: Support for event.raw and more XPath datamodel refactorings --- README.md | 12 +- contrib/dom/idl/SCXMLEvent.idl | 1 + src/uscxml/Factory.h | 10 + src/uscxml/Interpreter.cpp | 21 +- src/uscxml/Message.h | 8 + src/uscxml/URL.cpp | 6 +- src/uscxml/URL.h | 2 +- .../datamodel/ecmascript/v8/V8DataModel.cpp | 21 +- .../plugins/datamodel/ecmascript/v8/V8DataModel.h | 4 + .../datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp | 9 + .../datamodel/ecmascript/v8/dom/V8SCXMLEvent.h | 3 + .../plugins/datamodel/null/NULLDataModel.cpp | 6 + src/uscxml/plugins/datamodel/null/NULLDataModel.h | 5 + .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 7 + .../plugins/datamodel/prolog/swi/SWIDataModel.h | 5 + .../plugins/datamodel/xpath/XPathDataModel.cpp | 245 ++++++++++++++++----- .../plugins/datamodel/xpath/XPathDataModel.h | 20 +- .../ioprocessor/basichttp/BasicHTTPIOProcessor.cpp | 57 +++-- .../plugins/ioprocessor/modality/MMIComponent.h | 4 +- .../plugins/ioprocessor/modality/MMIMessages.cpp | 40 ++-- .../plugins/ioprocessor/modality/MMIMessages.h | 40 ++-- src/uscxml/server/HTTPServer.cpp | 29 ++- test/src/test-mmi.cpp | 99 +++++---- test/src/test-url.cpp | 4 +- 24 files changed, 464 insertions(+), 194 deletions(-) diff --git a/README.md b/README.md index 1a520dc..d3741e0 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ There is no technical reason for it not to run on iOS and Android as well, but w the respective build-process and did not precompile required libraries. * Datamodels - * ECMAScript using Google's v8 and JavaScriptCore (JSC is incomplete) - * Prolog using SWI prolog - * NULL datamodel with required In predicate - * XPath datamodel as far as the tests require + * Full ECMAScript datamodel using Google's v8 and JavaScriptCore (JSC is incomplete) + * Full NULL datamodel with required In predicate + * Early Prolog datamodel using SWI prolog + * Rudimentary support for XPath datamodel (Draft and tests are in conflict imho) * Invokers * scxml: Invoke a nested scxml interpreter * dirmon: Watches a directory for changes to files @@ -25,7 +25,7 @@ the respective build-process and did not precompile required libraries. * Communication * Features the standard basichttp io-processor * Features the required SCXML io-processor - * No DOM io-processor yet + * No DOM io-processor * Can actually respond to HTTP requests with data via <response> * Language Bindings * PHP module for apache and cli interpreter @@ -36,7 +36,7 @@ the respective build-process and did not precompile required libraries. * Have a look at the [result](http://uscxml.tk.informatik.tu-darmstadt.de/cdash/index.php?project=uscxml) for the various platforms. * The manual tests are [excluded](https://github.com/tklab-tud/uscxml/blob/master/contrib/ctest/CTestCustom.ctest.in). -uSCXML still fails the following tests: +uSCXML still fails the following ecmascript tests: diff --git a/contrib/dom/idl/SCXMLEvent.idl b/contrib/dom/idl/SCXMLEvent.idl index c94560b..67f5070 100644 --- a/contrib/dom/idl/SCXMLEvent.idl +++ b/contrib/dom/idl/SCXMLEvent.idl @@ -11,6 +11,7 @@ readonly attribute DOMString name; [EmptyAsNull] readonly attribute DOMString origin; [EmptyAsNull] readonly attribute DOMString origintype; + [EmptyAsNull] readonly attribute DOMString raw; readonly attribute Node dom; [CustomGetter] readonly attribute DOMString sendid; [EmptyAsNull] readonly attribute DOMString invokeid; diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index e21fe72..59835b3 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -237,6 +237,10 @@ public: // foreach virtual uint32_t getLength(const std::string& expr) = 0; + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) = 0; virtual void pushContext() = 0; virtual void popContext() = 0; @@ -313,6 +317,12 @@ public: virtual uint32_t getLength(const std::string& expr) { return _impl->getLength(expr); } + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) { + return _impl->setForeach(item, array, index, iteration); + } virtual void assign(const Arabica::DOM::Element& assignElem, const Arabica::DOM::Document& doc, diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index bec2a2a..21f64cb 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -1033,22 +1033,11 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node& cont CATCH_AND_DISTRIBUTE("Syntax error in array attribute of foreach element:") try { _dataModel.pushContext(); // copy old and enter new context - if (!_dataModel.isDeclared(item)) { - _dataModel.init(item, Data()); - } +// if (!_dataModel.isDeclared(item)) { +// _dataModel.init(item, Data()); +// } for (uint32_t iteration = 0; iteration < iterations; iteration++) { - { - // assign array element to item - std::stringstream ss; - ss << array << "[" << iteration << "]"; - _dataModel.assign(item, ss.str()); - } - if (index.length() > 0) { - // assign iteration element to index - std::stringstream ss; - ss << iteration; - _dataModel.assign(index, ss.str()); - } + _dataModel.setForeach(item, array, index, iteration); if (content.hasChildNodes()) // execute content and have exception rethrown to break foreach executeContent(content.getChildNodes(), true); @@ -1166,7 +1155,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node& cont execContent = Factory::createExecutableContent(content.getLocalName(), content.getNamespaceURI(), this); if (!execContent) { LOG(ERROR) << "No custom executable content known for element '" - << content.getLocalName() << "' in namespace '" << content.getNamespaceURI() << "'"; + << content.getLocalName() << "' in namespace '" << content.getNamespaceURI() << "'"; return; } _executableContent[content] = execContent; diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 3d41f70..27bd071 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -140,6 +140,13 @@ public: this->dom = dom; } + std::string getRaw() { + return raw; + } + void setRaw(const std::string& raw) { + this->raw = raw; + } + std::string getContent() { return content; } @@ -227,6 +234,7 @@ public: protected: #endif + std::string raw; std::string name; Type type; std::string origin; diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index 83d3dcb..45aba88 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -266,11 +266,11 @@ URL URL::asBaseURL(const URL& uri) { return URL(baseUriStr); } - + const bool URLImpl::toAbsolute(const std::string& baseUrl) { if (_uri.is_absolute()) return true; - + std::string uriStr = _uri.as_string(); #ifdef _WIN32 if (baseUrl.find("file://") == 0) { @@ -281,7 +281,7 @@ const bool URLImpl::toAbsolute(const std::string& baseUrl) { #else _uri = Arabica::io::URI(baseUrl, _uri.as_string()); #endif - + if (!_uri.is_absolute()) return false; return true; diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index 37b0614..402666f 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -177,7 +177,7 @@ public: const std::string asLocalFile(const std::string& suffix, bool reload = false) { return _impl->asLocalFile(suffix, reload); } - + static URL asBaseURL(const URL& url); static void toBaseURL(URL& uri); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 22777fa..34dd524 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -339,11 +339,30 @@ uint32_t V8DataModel::getLength(const std::string& expr) { Event exceptionEvent; exceptionEvent.name = "error.execution"; - exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM);; + exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM); throw(exceptionEvent); } +void V8DataModel::setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) { + if (!isDeclared(item)) { + assign(item, Data()); + } + // assign array element to item + std::stringstream ss; + ss << array << "[" << iteration << "]"; + assign(item, ss.str()); + if (index.length() > 0) { + // assign iteration element to index + std::stringstream ss; + ss << iteration; + assign(index, ss.str()); + } +} + void V8DataModel::eval(const std::string& expr) { v8::Locker locker; v8::HandleScope handleScope; diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 7c4f2b3..548cf20 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -36,6 +36,10 @@ public: virtual bool validate(const std::string& location, const std::string& schema); virtual uint32_t getLength(const std::string& expr); + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration); virtual void pushContext(); virtual void popContext(); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp index 86fcfef..9679d74 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp @@ -32,6 +32,15 @@ v8::Handle V8SCXMLEvent::origintypeAttrGetter(v8::Local p return v8::String::New(privData->nativeObj->origintype.c_str()); } +v8::Handle V8SCXMLEvent::rawAttrGetter(v8::Local property, const v8::AccessorInfo& info) { + v8::Local self = info.Holder(); + struct V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); + + if (privData->nativeObj->raw.length() == 0) + return v8::Undefined(); + return v8::String::New(privData->nativeObj->raw.c_str()); +} + v8::Handle V8SCXMLEvent::domAttrGetter(v8::Local property, const v8::AccessorInfo& info) { v8::Local self = info.Holder(); struct V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h index e7dbacc..670d818 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h @@ -45,6 +45,7 @@ public: static v8::Handle nameAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle originAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle origintypeAttrGetter(v8::Local property, const v8::AccessorInfo& info); + static v8::Handle rawAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle domAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle sendidCustomAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle invokeidAttrGetter(v8::Local property, const v8::AccessorInfo& info); @@ -70,6 +71,8 @@ public: v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); instance->SetAccessor(v8::String::NewSymbol("origintype"), V8SCXMLEvent::origintypeAttrGetter, 0, v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); + instance->SetAccessor(v8::String::NewSymbol("raw"), V8SCXMLEvent::rawAttrGetter, 0, + v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); instance->SetAccessor(v8::String::NewSymbol("dom"), V8SCXMLEvent::domAttrGetter, 0, v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); instance->SetAccessor(v8::String::NewSymbol("sendid"), V8SCXMLEvent::sendidCustomAttrGetter, 0, diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp index 6911480..dac3386 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp @@ -55,6 +55,12 @@ uint32_t NULLDataModel::getLength(const std::string& expr) { return 0; } +void NULLDataModel::setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) { +} + void NULLDataModel::eval(const std::string& expr) { } diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.h b/src/uscxml/plugins/datamodel/null/NULLDataModel.h index 423c5ff..3d86bf2 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.h +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.h @@ -33,6 +33,11 @@ public: virtual bool validate(const std::string& location, const std::string& schema); virtual uint32_t getLength(const std::string& expr); + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration); + virtual void pushContext(); virtual void popContext(); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index cc1fb39..db91869 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -96,6 +96,13 @@ uint32_t SWIDataModel::getLength(const std::string& expr) { return 0; } +void SWIDataModel::setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) { + // std::cout << "SWIDataModel::setForeach" << std::endl; +} + void SWIDataModel::eval(const std::string& expr) { URL localPLFile = URL::toLocalFile(expr, ".pl"); PlCall("user", "load_files", PlTermv(localPLFile.asLocalFile(".pl").c_str())) || LOG(ERROR) << "Could not execute prolog from file"; diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h index a278db8..19dc712 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -33,6 +33,11 @@ public: virtual bool validate(const std::string& location, const std::string& schema); virtual uint32_t getLength(const std::string& expr); + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration); + virtual void pushContext(); virtual void popContext(); diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index 179fded..39616f8 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -59,7 +59,11 @@ boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpr dm->_datamodel.appendChild(ioProcElem); NodeSet ioProcNodeSet; - ioProcNodeSet.push_back(ioProcElem); + Node node = ioProcElem.getFirstChild(); + while(node) { + ioProcNodeSet.push_back(node); + node = node.getNextSibling(); + } dm->_varResolver.setVariable("_ioprocessors", ioProcNodeSet); Element sessIdElem = dm->_doc.createElement("data"); @@ -69,7 +73,7 @@ boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpr dm->_datamodel.appendChild(sessIdElem); NodeSet sessIdNodeSet; - sessIdNodeSet.push_back(sessIdElem); + sessIdNodeSet.push_back(sessIdText); dm->_varResolver.setVariable("_sessionid", sessIdNodeSet); @@ -80,7 +84,7 @@ boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpr dm->_datamodel.appendChild(nameElem); NodeSet nameNodeSet; - nameNodeSet.push_back(nameElem); + nameNodeSet.push_back(nameText); dm->_varResolver.setVariable("_name", nameNodeSet); return dm; @@ -129,6 +133,13 @@ void XPathDataModel::setEvent(const Event& event) { namelistIter++; } } + if (event.raw.size() > 0) { + Element eventRawElem = _doc.createElement("raw"); + Text textNode = _doc.createTextNode(event.raw.c_str()); + eventRawElem.appendChild(textNode); + eventDataElem.appendChild(eventRawElem); + } + if (event.content.size() > 0) { Text textNode = _doc.createTextNode(Interpreter::spaceNormalize(event.content).c_str()); eventDataElem.appendChild(textNode); @@ -139,7 +150,7 @@ void XPathDataModel::setEvent(const Event& event) { } eventElem.appendChild(eventDataElem); - eventNodeSet.push_back(eventElem); + eventNodeSet.push_back(eventDataElem); // do we need to replace an existing event? Node oldEventElem = _datamodel.getFirstChild(); @@ -169,28 +180,103 @@ bool XPathDataModel::validate(const std::string& location, const std::string& sc } uint32_t XPathDataModel::getLength(const std::string& expr) { - std::cout << _datamodel << std::endl; +// std::cout << _datamodel << std::endl; XPathValue result = _xpath.evaluate_expr(expr, _doc); switch(result.type()) { - case NUMBER: - return result.asNumber(); - break; - case NODE_SET: - return result.asNodeSet().size(); - break; - default: - throw Event("error.execution", Event::PLATFORM); + case NUMBER: + return result.asNumber(); + break; + case NODE_SET: + return result.asNodeSet().size(); + break; + default: + Event exceptionEvent("error.execution", Event::PLATFORM); + exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM); + throw(exceptionEvent); } return 0; } +void XPathDataModel::setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) { + + XPathValue arrayResult = _xpath.evaluate_expr(array, _doc); + assert(arrayResult.type() == NODE_SET); + +#if 0 + std::cout << "Array Size: " << arrayResult.asNodeSet().size() << std::endl; + for (int i = 0; i < arrayResult.asNodeSet().size(); i++) { + std::cout << arrayResult.asNodeSet()[i] << std::endl; + } +#endif + + assert(arrayResult.asNodeSet().size() >= iteration); + + + NodeSet arrayNodeSet; + arrayNodeSet.push_back(arrayResult.asNodeSet()[iteration]); + + if (!isDeclared(item)) { + if (!isValidIdentifier(item)) + throw Event("error.execution", Event::PLATFORM); + Element container = _doc.createElement("data"); + container.setAttribute("id", item); + container.appendChild(arrayResult.asNodeSet()[iteration].cloneNode(true)); + _datamodel.appendChild(container); + _varResolver.setVariable(item, arrayNodeSet); + } + XPathValue itemResult = _varResolver.resolveVariable("", item); + assign(itemResult, arrayNodeSet, Element()); + + if (index.length() > 0) { + NodeSet indexNodeSet; + Text indexElem = _doc.createTextNode(toStr(iteration)); + indexNodeSet.push_back(indexElem); + + if (!isDeclared(index)) { + Element container = _doc.createElement("data"); + container.setAttribute("id", index); + container.appendChild(indexElem); + _datamodel.appendChild(container); + + NodeSet indexVarNodeSet; + indexVarNodeSet.push_back(container); + _varResolver.setVariable(index, indexVarNodeSet); + } + XPathValue indexResult = _varResolver.resolveVariable("", index); + assign(indexResult, indexNodeSet, Element()); + } + + +#if 0 + std::cout << _datamodel << std::endl << std::endl; + std::cout << "Index: " << indexResult.asNodeSet().size() << std::endl; + for (int i = 0; i < indexResult.asNodeSet().size(); i++) { + std::cout << indexResult.asNodeSet()[i] << std::endl; + } + std::cout << std::endl; +#endif + + +} + +bool XPathDataModel::isValidIdentifier(const std::string& identifier) { + if(boost::starts_with(identifier, ".")) + return false; + + return true; +} + + void XPathDataModel::eval(const std::string& expr) { XPathValue result = _xpath.evaluate_expr(expr, _doc); } bool XPathDataModel::isDeclared(const std::string& expr) { try { - return evalAsBool(expr); + return _varResolver.isDeclared(expr) || evalAsBool(expr); } catch(...) { return false; } @@ -247,7 +333,22 @@ void XPathDataModel::assign(const Element& assignElem, XPathValue key = _xpath.evaluate_expr(location, _doc); NodeSet nodeSet; if (doc) { - nodeSet.push_back(doc.getDocumentElement()); + if (doc.getDocumentElement()) { + Node data = doc.getDocumentElement().getFirstChild(); + while (data) { + // do not add empty text as a node + if (data.getNodeType() == Node_base::TEXT_NODE) { + std::string trimmed = data.getNodeValue(); + boost::trim(trimmed); + if (trimmed.length() == 0) { + data = data.getNextSibling(); + continue; + } + } + nodeSet.push_back(data); + data = data.getNextSibling(); + } + } assign(key, nodeSet, assignElem); } else if (content.length() > 0) { Text textNode = _doc.createTextNode(Interpreter::spaceNormalize(content)); @@ -292,11 +393,26 @@ void XPathDataModel::init(const Element& dataElem, Text textNode = _doc.createTextNode(Interpreter::spaceNormalize(content)); container.appendChild(textNode); } else if (HAS_ATTR(dataElem, "expr")) { - XPathValue expr = _xpath.evaluate_expr(ATTR(dataElem, "expr"), _doc); - XPathValue key = _xpath.evaluate_expr(location, _doc); - assign(key, expr, dataElem); - for (int i = 0; expr.asNodeSet().size(); i++) - container.appendChild(expr.asNodeSet()[i]); + try { + XPathValue expr = _xpath.evaluate_expr(ATTR(dataElem, "expr"), _doc); + switch (expr.type()) { + case NODE_SET: + for (int i = 0; expr.asNodeSet().size(); i++) + container.appendChild(expr.asNodeSet()[i]); + break; + case STRING: + container.appendChild(_doc.createTextNode(expr.asString())); + break; + case NUMBER: + container.appendChild(_doc.createTextNode(toStr(expr.asNumber()))); + break; + case BOOL: + case ANY: + throw Event("error.execution", Event::PLATFORM); + } + } catch (SyntaxException e) { + throw Event("error.execution", Event::PLATFORM); + } } else { LOG(ERROR) << "data element has no content"; } @@ -307,7 +423,7 @@ void XPathDataModel::init(const Element& dataElem, nodeSet.push_back(container); _varResolver.setVariable(location, nodeSet); - std::cout << _datamodel << std::endl; +// std::cout << _datamodel << std::endl; } void XPathDataModel::init(const std::string& location, const Data& data) { @@ -320,46 +436,49 @@ void XPathDataModel::assign(const XPathValue& key, const XPathValue& value, const Element& assignElem) { switch (key.type()) { - case NODE_SET: { - switch (value.type()) { - case STRING: - assign(key.asNodeSet(), value.asString(), assignElem); - break; - case BOOL: - assign(key.asNodeSet(), value.asBool(), assignElem); - break; - case NUMBER: - assign(key.asNodeSet(), value.asNumber(), assignElem); - break; - case NODE_SET: - assign(key.asNodeSet(), value.asNodeSet(), assignElem); - break; - case ANY: - throw Event("error.execution", Event::PLATFORM); - } - break; + case NODE_SET: { + if (key.asNodeSet().size() == 0) { + throw Event("error.execution", Event::PLATFORM); } + switch (value.type()) { case STRING: + assign(key.asNodeSet(), value.asString(), assignElem); + break; case BOOL: + assign(key.asNodeSet(), value.asBool(), assignElem); + break; case NUMBER: + assign(key.asNodeSet(), value.asNumber(), assignElem); + break; + case NODE_SET: + assign(key.asNodeSet(), value.asNodeSet(), assignElem); + break; case ANY: throw Event("error.execution", Event::PLATFORM); + } + break; + } + case STRING: + case BOOL: + case NUMBER: + case ANY: + throw Event("error.execution", Event::PLATFORM); } } void XPathDataModel::assign(const XPathValue& key, - const NodeSet& value, - const Element& assignElem) { + const NodeSet& value, + const Element& assignElem) { switch (key.type()) { - case NODE_SET: { - assign(key.asNodeSet(), value, assignElem); - break; - } - case STRING: - case BOOL: - case NUMBER: - case ANY: - throw Event("error.execution", Event::PLATFORM); + case NODE_SET: { + assign(key.asNodeSet(), value, assignElem); + break; + } + case STRING: + case BOOL: + case NUMBER: + case ANY: + throw Event("error.execution", Event::PLATFORM); } } @@ -404,7 +523,7 @@ void XPathDataModel::assign(const NodeSet& key, } } } - + void XPathDataModel::assign(const NodeSet& key, const double value, const Element& assignElem) { @@ -429,6 +548,7 @@ void XPathDataModel::assign(const NodeSet& key, break; } default: +// std::cout << key[i].getNodeType() << std::endl; throw Event("error.execution", Event::PLATFORM); break; } @@ -436,23 +556,23 @@ void XPathDataModel::assign(const NodeSet& key, } void XPathDataModel::assign(const Element& key, - const NodeSet& value, - const Element& assignElem) { + const NodeSet& value, + const Element& assignElem) { Element element(key); if (false) { - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "firstchild")) { + } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "firstchild")) { // firstchild: Insert the value specified by 'expr' before all of the children at 'location'. for (int i = value.size(); i; i--) { Node importedNode = _doc.importNode(value[i-1], true); element.insertBefore(importedNode, element.getFirstChild()); } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "lastchild")) { + } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "lastchild")) { // lastchild: Insert the value specified by 'expr' after all of the children at 'location'. for (int i = 0; i < value.size(); i++) { Node importedNode = _doc.importNode(value[i], true); element.appendChild(importedNode); } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "previoussibling")) { + } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "previoussibling")) { // previoussibling: Insert the value specified by 'expr' before the // node specified by 'location', keeping the same parent. Node parent = element.getParentNode(); @@ -462,7 +582,7 @@ void XPathDataModel::assign(const Element& key, Node importedNode = _doc.importNode(value[i], true); parent.insertBefore(importedNode, element); } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "nextsibling")) { + } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "nextsibling")) { // nextsibling: Insert the value specified by 'expr' after the node // specified by 'location', keeping the same parent. Node parent = element.getParentNode(); @@ -477,7 +597,7 @@ void XPathDataModel::assign(const Element& key, parent.appendChild(importedNode); } } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "replace")) { + } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "replace")) { // replace: Replace the node specified by 'location' by the value specified by 'expr'. Node parent = element.getParentNode(); if (!parent) @@ -486,7 +606,7 @@ void XPathDataModel::assign(const Element& key, throw Event("error.execution", Event::PLATFORM); Node importedNode = _doc.importNode(value[0], true); parent.replaceChild(importedNode, element); - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "delete")) { + } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "delete")) { // delete: Delete the node specified by 'location'. ('expr' is ignored.). Node parent = element.getParentNode(); if (!parent) @@ -510,6 +630,13 @@ NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, if(n == _variables.end()) { throw Event("error.execution"); } +#if 0 + std::cout << std::endl << name << ":" << std::endl; + for (int i = 0; i < n->second.size(); i++) { + std::cout << n->second[i].getNodeType() << " | " << n->second[i] << std::endl; + } + std::cout << std::endl; +#endif return XPathValue(new NodeSetValue(n->second)); } diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h index 391af0b..7140b2f 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h @@ -58,7 +58,7 @@ public: bool isDeclared(const std::string& name) { return _variables.find(name) != _variables.end(); } - + private: std::map > _variables; friend class XPathDataModel; @@ -82,6 +82,11 @@ public: virtual bool validate(const std::string& location, const std::string& schema); virtual uint32_t getLength(const std::string& expr); + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration); + virtual void pushContext(); virtual void popContext(); @@ -109,6 +114,8 @@ protected: Arabica::DOM::Element _datamodel; Arabica::DOM::Document _doc; + bool isValidIdentifier(const std::string& identifier); + // resolve value to its type void assign(const Arabica::XPath::XPathValue& key, const Arabica::XPath::XPathValue& value, @@ -116,7 +123,7 @@ protected: void assign(const Arabica::XPath::XPathValue& key, const Arabica::XPath::NodeSet& value, const Arabica::DOM::Element& assignElem); - + // assign value to a nodeset key void assign(const Arabica::XPath::NodeSet& key, const std::string& value, @@ -130,12 +137,19 @@ protected: void assign(const Arabica::XPath::NodeSet& key, const Arabica::XPath::NodeSet& value, const Arabica::DOM::Element& assignElem); - + // assign value to an element key (from nodeset) void assign(const Arabica::DOM::Element& key, const Arabica::XPath::NodeSet& value, const Arabica::DOM::Element& assignElem); + + // assign value to a text node key (from nodeset) + void assign(const Arabica::DOM::Text& key, + const Arabica::XPath::NodeSet& value, + const Arabica::DOM::Element& assignElem); + + NodeSetVariableResolver _varResolver; XPathFunctionResolver _funcResolver; diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp index 09195bf..1d6394e 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp @@ -73,15 +73,32 @@ void BasicHTTPIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { reqEvent.type = Event::EXTERNAL; bool scxmlStructFound = false; - if (reqEvent.data.compound["header"].compound.find("_scxmleventstruct") != reqEvent.data.compound["header"].compound.end()) { - // TODO: this looses all other information - reqEvent = Event::fromXML(evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventstruct"].atom.c_str())); - scxmlStructFound = true; - } - if (reqEvent.data.compound["header"].compound.find("_scxmleventname") != reqEvent.data.compound["header"].compound.end()) { - reqEvent.name = evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventname"].atom.c_str()); + if (reqEvent.data.compound["header"].compound.find("Content-Type") != reqEvent.data.compound["header"].compound.end() && + boost::iequals(reqEvent.data.compound["header"].compound["Content-Type"].atom, "application/x-www-form-urlencoded")) { + std::stringstream ss(reqEvent.data.compound["content"].atom); + std::string term; + while(std::getline(ss, term, '&')) { + size_t split = term.find_first_of("="); + if (split != std::string::npos) { + std::string key = evhttp_decode_uri(term.substr(0, split).c_str()); + std::string value = evhttp_decode_uri(term.substr(split + 1).c_str()); + if (boost::iequals(key, "_scxmleventname")) { + reqEvent.name = value; + } else { + reqEvent.data.compound[key] = value; + } + } + } + } else { + if (reqEvent.data.compound["header"].compound.find("_scxmleventstruct") != reqEvent.data.compound["header"].compound.end()) { + // TODO: this looses all other information + reqEvent = Event::fromXML(evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventstruct"].atom.c_str())); + scxmlStructFound = true; + } + if (reqEvent.data.compound["header"].compound.find("_scxmleventname") != reqEvent.data.compound["header"].compound.end()) { + reqEvent.name = evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventname"].atom.c_str()); + } } - std::map::iterator headerIter = reqEvent.data.compound["header"].compound.begin(); while(headerIter != reqEvent.data.compound["header"].compound.end()) { reqEvent.data.compound[headerIter->first] = Data(evhttp_decode_uri(headerIter->second.atom.c_str()), Data::VERBATIM); @@ -118,12 +135,12 @@ void BasicHTTPIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { } void BasicHTTPIOProcessor::send(const SendRequest& req) { - + if (req.target.length() == 0) { _interpreter->receiveInternal(Event("error.communication", Event::PLATFORM)); return; } - + bool isLocal = false; std::string target; if (!boost::equals(req.target, _url)) { @@ -133,17 +150,23 @@ void BasicHTTPIOProcessor::send(const SendRequest& req) { target = _url; } URL targetURL(target); + std::stringstream kvps; + std::string kvpSeperator; // event name if (req.name.size() > 0) { - targetURL.addOutHeader("_scxmleventname", evhttp_encode_uri(req.name.c_str())); + kvps << kvpSeperator << evhttp_encode_uri("_scxmleventname") << "=" << evhttp_encode_uri(req.name.c_str()); + kvpSeperator = "&"; +// targetURL.addOutHeader("_scxmleventname", evhttp_encode_uri(req.name.c_str())); } // event namelist if (req.namelist.size() > 0) { std::map::const_iterator namelistIter = req.namelist.begin(); while (namelistIter != req.namelist.end()) { - targetURL.addOutHeader(namelistIter->first, namelistIter->second); + kvps << kvpSeperator << evhttp_encode_uri(namelistIter->first.c_str()) << "=" << evhttp_encode_uri(namelistIter->second.c_str()); + kvpSeperator = "&"; +// targetURL.addOutHeader(namelistIter->first, namelistIter->second); namelistIter++; } } @@ -152,15 +175,19 @@ void BasicHTTPIOProcessor::send(const SendRequest& req) { if (req.params.size() > 0) { std::multimap::const_iterator paramIter = req.params.begin(); while (paramIter != req.params.end()) { - targetURL.addOutHeader(paramIter->first, paramIter->second); + kvps << kvpSeperator << evhttp_encode_uri(paramIter->first.c_str()) << "=" << evhttp_encode_uri(paramIter->second.c_str()); + kvpSeperator = "&"; +// targetURL.addOutHeader(paramIter->first, paramIter->second); paramIter++; } } // content - if (req.content.size() > 0) + if (kvps.str().size() > 0) { + targetURL.setOutContent(kvps.str()); + } else if (req.content.size() > 0) { targetURL.setOutContent(req.content); - + } targetURL.setRequestType("post"); targetURL.addMonitor(this); diff --git a/src/uscxml/plugins/ioprocessor/modality/MMIComponent.h b/src/uscxml/plugins/ioprocessor/modality/MMIComponent.h index bee568b..ba3f2c8 100644 --- a/src/uscxml/plugins/ioprocessor/modality/MMIComponent.h +++ b/src/uscxml/plugins/ioprocessor/modality/MMIComponent.h @@ -19,7 +19,7 @@ public: virtual std::set getNames() { return std::set(); }; - + virtual Data getDataModelVariables(); virtual void send(const SendRequest& req); @@ -37,7 +37,7 @@ public: virtual NewContextResponse newContext(const NewContextRequest&); virtual DoneNotification done(const DoneNotification&); // virtual ExtensionNotification extension(const ExtensionNotification&); - + }; diff --git a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp index ed92fac..717e174 100644 --- a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp +++ b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp @@ -24,14 +24,14 @@ Arabica::DOM::Document MMIMessage::toXML() { if (data.size() > 0) { Element dataElem = doc.createElementNS(nameSpace, "data"); - + // try to parse content std::stringstream* ss = new std::stringstream(); (*ss) << data; std::auto_ptr ssPtr(ss); Arabica::SAX::InputSource inputSource; inputSource.setByteStream(ssPtr); - + Arabica::SAX2DOM::Parser parser; if(parser.parse(inputSource)) { Node importedNode = doc.importNode(parser.getDocument().getDocumentElement(), true); @@ -40,9 +40,9 @@ Arabica::DOM::Document MMIMessage::toXML() { Text textElem = doc.createTextNode(data); dataElem.appendChild(textElem); } - msgElem.appendChild(dataElem); + msgElem.appendChild(dataElem); } - + mmiElem.appendChild(msgElem); doc.appendChild(mmiElem); std::cout << doc; @@ -67,7 +67,7 @@ Arabica::DOM::Document ContentRequest::toXML() { contentURLElem.setAttributeNS(nameSpace, "max-age", contentURL.maxAge); msgElem.appendChild(contentURLElem); } - + if (content.size() > 0) { Element contentElem = doc.createElementNS(nameSpace, "content"); @@ -77,7 +77,7 @@ Arabica::DOM::Document ContentRequest::toXML() { std::auto_ptr ssPtr(ss); Arabica::SAX::InputSource inputSource; inputSource.setByteStream(ssPtr); - + Arabica::SAX2DOM::Parser parser; if(parser.parse(inputSource)) { Node importedNode = doc.importNode(parser.getDocument().getDocumentElement(), true); @@ -117,12 +117,12 @@ Arabica::DOM::Document StatusResponse::toXML() { Arabica::DOM::Document StatusInfoResponse::toXML() { Document doc = StatusResponse::toXML(); Element msgElem = Element(doc.getDocumentElement().getFirstChild()); - + Element statusInfoElem = doc.createElementNS(nameSpace, "StatusInfo"); Text statusInfoText = doc.createTextNode(statusInfo); statusInfoElem.appendChild(statusInfoText); msgElem.appendChild(statusInfoElem); - + return doc; } @@ -135,7 +135,7 @@ Arabica::DOM::Document StatusRequest::toXML() { } else { msgElem.setAttributeNS(nameSpace, "RequestAutomaticUpdate", "false"); } - + return doc; } @@ -153,14 +153,14 @@ MMIMessage MMIMessage::fromXML(const Arabica::DOM::Document& doc) { // msg.data = msgElem.getAttributeNS("http://www.w3.org/2008/04/mmi-arch", "Data"); msg.requestId = msgElem.getAttributeNS("http://www.w3.org/2008/04/mmi-arch", "RequestID"); msg.tagName = msgElem.getLocalName(); - + Element dataElem; node = msgElem.getFirstChild(); while (node) { if (node.getNodeType() == Node_base::ELEMENT_NODE) dataElem = Element(node); - if (dataElem && boost::iequals(dataElem.getLocalName(), "data")) - break; + if (dataElem && boost::iequals(dataElem.getLocalName(), "data")) + break; node = node.getNextSibling(); } @@ -176,7 +176,7 @@ MMIMessage MMIMessage::fromXML(const Arabica::DOM::Document& doc) { } msg.data = ss.str(); } - + return msg; } @@ -203,13 +203,13 @@ ContentRequest ContentRequest::fromXML(const Arabica::DOM::Document } Element msgElem(node); Element contentElem; - + node = msgElem.getFirstChild(); while (node) { if (node.getNodeType() == Node_base::ELEMENT_NODE) { contentElem = Element(node); if (boost::iequals(contentElem.getLocalName(), "content") || - boost::iequals(contentElem.getLocalName(), "contentURL")) + boost::iequals(contentElem.getLocalName(), "contentURL")) break; } node = node.getNextSibling(); @@ -233,7 +233,7 @@ ContentRequest ContentRequest::fromXML(const Arabica::DOM::Document msg.contentURL.fetchTimeout = contentElem.getAttributeNS("http://www.w3.org/2008/04/mmi-arch", "fetchtimeout"); } } - + //msg.content = msgElem.getAttributeNS("http://www.w3.org/2008/04/mmi-arch", "Context"); return msg; } @@ -294,7 +294,7 @@ StatusInfoResponse StatusInfoResponse::fromXML(const Arabica::DOM::Document& doc) { StatusRequest msg(ContextualizedRequest::fromXML(doc)); Node node = doc.getDocumentElement().getFirstChild(); @@ -320,7 +320,7 @@ StatusRequest StatusRequest::fromXML(const Arabica::DOM::Document& } Element msgElem(node); std::string autoUpdate = msgElem.getAttributeNS("http://www.w3.org/2008/04/mmi-arch", "RequestAutomaticUpdate"); - + if (boost::iequals(autoUpdate, "true")) { msg.automaticUpdate = true; } else if(boost::iequals(autoUpdate, "on")) { diff --git a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h index af31efe..a5328ac 100644 --- a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h +++ b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h @@ -18,11 +18,11 @@ public: std::string tagName; static std::string nameSpace; - + protected: MMIMessage() {} }; - + class NewContextRequest : public MMIMessage { public: NewContextRequest() { @@ -56,7 +56,7 @@ public: return ContextualizedRequest::fromXML(doc); } }; -class ResumeRequest : public ContextualizedRequest { +class ResumeRequest : public ContextualizedRequest { public: ResumeRequest() { tagName = "ResumeRequest"; @@ -67,7 +67,7 @@ public: } }; -class CancelRequest : public ContextualizedRequest { +class CancelRequest : public ContextualizedRequest { public: CancelRequest() { tagName = "CancelRequest"; @@ -78,7 +78,7 @@ public: } }; -class ClearContextRequest : public ContextualizedRequest { +class ClearContextRequest : public ContextualizedRequest { public: ClearContextRequest() { tagName = "ClearContextRequest"; @@ -89,7 +89,7 @@ public: } }; -class StatusRequest : public ContextualizedRequest { +class StatusRequest : public ContextualizedRequest { public: StatusRequest() { tagName = "StatusRequest"; @@ -109,7 +109,7 @@ public: std::string maxAge; std::string fetchTimeout; }; - + virtual Arabica::DOM::Document toXML(); static ContentRequest fromXML(const Arabica::DOM::Document& doc); std::string content; @@ -119,7 +119,7 @@ protected: ContentRequest(const ContextualizedRequest& father) : ContextualizedRequest(father) {} }; -class PrepareRequest : public ContentRequest { +class PrepareRequest : public ContentRequest { public: PrepareRequest() { tagName = "PrepareRequest"; @@ -130,7 +130,7 @@ public: } }; -class StartRequest : public ContentRequest { +class StartRequest : public ContentRequest { public: StartRequest() { tagName = "StartRequest"; @@ -159,10 +159,10 @@ protected: class StatusResponse : public ContextualizedRequest { public: enum Status { - ALIVE = 0, - DEAD = 1, - SUCCESS = 2, - FAILURE = 3 + ALIVE = 0, + DEAD = 1, + SUCCESS = 2, + FAILURE = 3 }; StatusResponse() { @@ -196,7 +196,7 @@ public: return StatusInfoResponse::fromXML(doc); } }; - + class StartResponse : public StatusInfoResponse { public: StartResponse() { @@ -207,7 +207,7 @@ public: return StatusInfoResponse::fromXML(doc); } }; - + class CancelResponse : public StatusInfoResponse { public: CancelResponse() { @@ -218,7 +218,7 @@ public: return StatusInfoResponse::fromXML(doc); } }; - + class PauseResponse : public StatusInfoResponse { public: PauseResponse() { @@ -229,7 +229,7 @@ public: return StatusInfoResponse::fromXML(doc); } }; - + class ResumeResponse : public StatusInfoResponse { public: ResumeResponse() { @@ -240,7 +240,7 @@ public: return StatusInfoResponse::fromXML(doc); } }; - + class ClearContextResponse : public StatusInfoResponse { public: ClearContextResponse() { @@ -251,7 +251,7 @@ public: return StatusInfoResponse::fromXML(doc); } }; - + class NewContextResponse : public StatusInfoResponse { public: NewContextResponse() { @@ -263,7 +263,7 @@ public: } }; - + class DoneNotification : public StatusInfoResponse { public: DoneNotification() { diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp index 0d5feee..70b272f 100644 --- a/src/uscxml/server/HTTPServer.cpp +++ b/src/uscxml/server/HTTPServer.cpp @@ -114,10 +114,14 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD // evhttp_send_error(req, 404, NULL); // return; + std::stringstream raw; + evhttp_request_own(req); Request request; request.curlReq = req; + + switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: request.data.compound["type"] = Data("get", Data::VERBATIM); @@ -150,6 +154,18 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD request.data.compound["type"] = Data("unknown", Data::VERBATIM); break; } + raw << boost::to_upper_copy(request.data.compound["type"].atom); + + request.data.compound["remoteHost"] = Data(req->remote_host, Data::VERBATIM); + request.data.compound["remotePort"] = Data(toStr(req->remote_port), Data::VERBATIM); + request.data.compound["httpMajor"] = Data(toStr((unsigned short)req->major), Data::VERBATIM); + request.data.compound["httpMinor"] = Data(toStr((unsigned short)req->minor), Data::VERBATIM); + request.data.compound["uri"] = Data(HTTPServer::getBaseURL() + req->uri, Data::VERBATIM); + request.data.compound["path"] = Data(evhttp_uri_get_path(evhttp_request_get_evhttp_uri(req)), Data::VERBATIM); + + raw << " " << request.data.compound["path"].atom; + raw << " HTTP/" << request.data.compound["httpMajor"].atom << "." << request.data.compound["httpMinor"].atom; + raw << std::endl; struct evkeyvalq *headers; struct evkeyval *header; @@ -159,14 +175,9 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; header = header->next.tqe_next) { request.data.compound["header"].compound[header->key] = Data(header->value, Data::VERBATIM); + raw << header->key << ": " << header->value << std::endl; } - - request.data.compound["remoteHost"] = Data(req->remote_host, Data::VERBATIM); - request.data.compound["remotePort"] = Data(toStr(req->remote_port), Data::VERBATIM); - request.data.compound["httpMajor"] = Data(toStr((unsigned short)req->major), Data::VERBATIM); - request.data.compound["httpMinor"] = Data(toStr((unsigned short)req->minor), Data::VERBATIM); - request.data.compound["uri"] = Data(HTTPServer::getBaseURL() + req->uri, Data::VERBATIM); - request.data.compound["path"] = Data(evhttp_uri_get_path(evhttp_request_get_evhttp_uri(req)), Data::VERBATIM); + raw << std::endl; // This was used for debugging // if (boost::ends_with(request.data.compound["path"].atom, ".png")) { @@ -207,6 +218,8 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD } } + raw << request.data.compound["content"].atom; + // decode content if (request.data.compound.find("content") != request.data.compound.end() && request.data.compound["header"].compound.find("Content-Type") != request.data.compound["header"].compound.end()) { @@ -219,6 +232,8 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD } } + request.raw = raw.str(); + if (callbackData == NULL) { HTTPServer::getInstance()->processByMatchingServlet(request); } else { diff --git a/test/src/test-mmi.cpp b/test/src/test-mmi.cpp index 1b5702b..2b34a82 100644 --- a/test/src/test-mmi.cpp +++ b/test/src/test-mmi.cpp @@ -24,7 +24,8 @@ Arabica::DOM::Document xmlToDoc(const std::string& xml) { } int main(int argc, char** argv) { - { // --- NewContextRequest + { + // --- NewContextRequest std::stringstream ss; ss << ""; NewContextRequest msg = NewContextRequest::fromXML(xmlToDoc(ss.str())); @@ -33,7 +34,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.target, "someOtherURI")); assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.data, "")); - + NewContextRequest msg2 = NewContextRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "NewContextRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -41,8 +42,9 @@ int main(int argc, char** argv) { assert(boost::iequals(msg2.requestId, "request-1")); assert(boost::iequals(msg2.data, "")); } - - { // --- NewContextResponse + + { + // --- NewContextResponse std::stringstream ss; ss << " "; NewContextResponse msg = NewContextResponse::fromXML(xmlToDoc(ss.str())); @@ -67,7 +69,8 @@ int main(int argc, char** argv) { } - { // --- PrepareRequest + { + // --- PrepareRequest std::stringstream ss; ss << " "; PrepareRequest msg = PrepareRequest::fromXML(xmlToDoc(ss.str())); @@ -81,7 +84,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.contentURL.href, "someContentURI")); assert(boost::iequals(msg.contentURL.maxAge, "")); assert(boost::iequals(msg.contentURL.fetchTimeout, "1s")); - + PrepareRequest msg2 = PrepareRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "PrepareRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -96,7 +99,8 @@ int main(int argc, char** argv) { } - { // --- PrepareRequest + { + // --- PrepareRequest std::stringstream ss; ss << " Hello World! "; PrepareRequest msg = PrepareRequest::fromXML(xmlToDoc(ss.str())); @@ -106,7 +110,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "URI-1")); assert(msg.content.size() > 0); - + PrepareRequest msg2 = PrepareRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "PrepareRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -117,7 +121,8 @@ int main(int argc, char** argv) { } - { // --- PrepareResponse + { + // --- PrepareResponse std::stringstream ss; ss << " "; PrepareResponse msg = PrepareResponse::fromXML(xmlToDoc(ss.str())); @@ -127,7 +132,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); assert(msg.status == StatusResponse::SUCCESS); - + PrepareResponse msg2 = PrepareResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "PrepareResponse")); assert(boost::iequals(msg2.source, "someURI")); @@ -138,7 +143,8 @@ int main(int argc, char** argv) { } - { // --- PrepareResponse + { + // --- PrepareResponse std::stringstream ss; ss << " NotAuthorized "; PrepareResponse msg = PrepareResponse::fromXML(xmlToDoc(ss.str())); @@ -161,7 +167,8 @@ int main(int argc, char** argv) { } - { // --- StartRequest + { + // --- StartRequest std::stringstream ss; ss << " "; StartRequest msg = StartRequest::fromXML(xmlToDoc(ss.str())); @@ -170,7 +177,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.target, "someOtherURI")); assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "URI-1")); - + StartRequest msg2 = StartRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "StartRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -180,7 +187,8 @@ int main(int argc, char** argv) { } - { // --- StartResponse + { + // --- StartResponse std::stringstream ss; ss << " NotAuthorized "; StartResponse msg = StartResponse::fromXML(xmlToDoc(ss.str())); @@ -191,7 +199,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.context, "someURI")); assert(boost::iequals(msg.statusInfo, " NotAuthorized ")); assert(msg.status == StatusResponse::FAILURE); - + StartResponse msg2 = StartResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "StartResponse")); assert(boost::iequals(msg2.source, "someURI")); @@ -203,7 +211,8 @@ int main(int argc, char** argv) { } - { // --- DoneNotification + { + // --- DoneNotification std::stringstream ss; ss << " Boston Denver "; DoneNotification msg = DoneNotification::fromXML(xmlToDoc(ss.str())); @@ -214,7 +223,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.context, "someURI")); assert(msg.data.size() > 0); assert(msg.status == StatusResponse::SUCCESS); - + DoneNotification msg2 = DoneNotification::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "DoneNotification")); assert(boost::iequals(msg2.source, "someURI")); @@ -226,7 +235,8 @@ int main(int argc, char** argv) { } - { // --- DoneNotification + { + // --- DoneNotification std::stringstream ss; ss << " "; DoneNotification msg = DoneNotification::fromXML(xmlToDoc(ss.str())); @@ -249,7 +259,8 @@ int main(int argc, char** argv) { } - { // --- CancelRequest + { + // --- CancelRequest std::stringstream ss; ss << " "; CancelRequest msg = CancelRequest::fromXML(xmlToDoc(ss.str())); @@ -268,7 +279,8 @@ int main(int argc, char** argv) { } - { // --- CancelResponse + { + // --- CancelResponse std::stringstream ss; ss << " "; CancelResponse msg = CancelResponse::fromXML(xmlToDoc(ss.str())); @@ -278,7 +290,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); assert(msg.status == StatusResponse::SUCCESS); - + CancelResponse msg2 = CancelResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "CancelResponse")); assert(boost::iequals(msg2.source, "someURI")); @@ -289,7 +301,8 @@ int main(int argc, char** argv) { } - { // --- PauseRequest + { + // --- PauseRequest std::stringstream ss; ss << " "; PauseRequest msg = PauseRequest::fromXML(xmlToDoc(ss.str())); @@ -298,7 +311,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.target, "someOtherURI")); assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); - + PauseRequest msg2 = PauseRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "PauseRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -308,7 +321,8 @@ int main(int argc, char** argv) { } - { // --- PauseResponse + { + // --- PauseResponse std::stringstream ss; ss << " "; PauseResponse msg = PauseResponse::fromXML(xmlToDoc(ss.str())); @@ -318,7 +332,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); assert(msg.status == StatusResponse::SUCCESS); - + PauseResponse msg2 = PauseResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "PauseResponse")); assert(boost::iequals(msg2.source, "someURI")); @@ -329,7 +343,8 @@ int main(int argc, char** argv) { } - { // --- ResumeRequest + { + // --- ResumeRequest std::stringstream ss; ss << " "; ResumeRequest msg = ResumeRequest::fromXML(xmlToDoc(ss.str())); @@ -338,7 +353,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.target, "someOtherURI")); assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); - + ResumeRequest msg2 = ResumeRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "ResumeRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -348,7 +363,8 @@ int main(int argc, char** argv) { } - { // --- ResumeResponse + { + // --- ResumeResponse std::stringstream ss; ss << " "; ResumeResponse msg = ResumeResponse::fromXML(xmlToDoc(ss.str())); @@ -358,7 +374,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); assert(msg.status == StatusResponse::SUCCESS); - + ResumeResponse msg2 = ResumeResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "ResumeResponse")); assert(boost::iequals(msg2.source, "someURI")); @@ -369,7 +385,8 @@ int main(int argc, char** argv) { } - { // --- ExtensionNotification + { + // --- ExtensionNotification std::stringstream ss; ss << " "; ExtensionNotification msg = ExtensionNotification::fromXML(xmlToDoc(ss.str())); @@ -379,7 +396,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-1")); assert(boost::iequals(msg.context, "someURI")); assert(boost::iequals(msg.name, "appEvent")); - + ExtensionNotification msg2 = ExtensionNotification::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "ExtensionNotification")); assert(boost::iequals(msg2.source, "someURI")); @@ -390,7 +407,8 @@ int main(int argc, char** argv) { } - { // --- ClearContextRequest + { + // --- ClearContextRequest std::stringstream ss; ss << " "; ClearContextRequest msg = ClearContextRequest::fromXML(xmlToDoc(ss.str())); @@ -399,7 +417,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.target, "someOtherURI")); assert(boost::iequals(msg.requestId, "request-2")); assert(boost::iequals(msg.context, "someURI")); - + ClearContextRequest msg2 = ClearContextRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "ClearContextRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -409,7 +427,8 @@ int main(int argc, char** argv) { } - { // --- ClearContextResponse + { + // --- ClearContextResponse std::stringstream ss; ss << " "; ClearContextResponse msg = ClearContextResponse::fromXML(xmlToDoc(ss.str())); @@ -419,7 +438,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-2")); assert(boost::iequals(msg.context, "someURI")); assert(msg.status == StatusResponse::SUCCESS); - + ClearContextResponse msg2 = ClearContextResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "ClearContextResponse")); assert(boost::iequals(msg2.source, "someURI")); @@ -430,7 +449,8 @@ int main(int argc, char** argv) { } - { // --- StatusRequest + { + // --- StatusRequest std::stringstream ss; ss << " "; StatusRequest msg = StatusRequest::fromXML(xmlToDoc(ss.str())); @@ -440,7 +460,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-3")); assert(boost::iequals(msg.context, "aToken")); assert(msg.automaticUpdate); - + StatusRequest msg2 = StatusRequest::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "StatusRequest")); assert(boost::iequals(msg2.source, "someURI")); @@ -451,7 +471,8 @@ int main(int argc, char** argv) { } - { // --- StatusResponse + { + // --- StatusResponse std::stringstream ss; ss << " "; StatusResponse msg = StatusResponse::fromXML(xmlToDoc(ss.str())); @@ -461,7 +482,7 @@ int main(int argc, char** argv) { assert(boost::iequals(msg.requestId, "request-3")); assert(boost::iequals(msg.context, "aToken")); assert(msg.status == StatusResponse::ALIVE); - + StatusResponse msg2 = StatusResponse::fromXML(msg.toXML()); assert(boost::iequals(msg2.tagName, "StatusResponse")); assert(boost::iequals(msg2.source, "someURI")); diff --git a/test/src/test-url.cpp b/test/src/test-url.cpp index cd11ac5..19257d6 100644 --- a/test/src/test-url.cpp +++ b/test/src/test-url.cpp @@ -44,7 +44,7 @@ int main(int argc, char** argv) { std::string exeName = argv[0]; exeName = exeName.substr(exeName.find_last_of("\\/") + 1); - + { Interpreter interpreter = Interpreter::fromURI("/Users/sradomski/Desktop/application_small.scxml"); assert(interpreter); @@ -58,7 +58,7 @@ int main(int argc, char** argv) { URL url(argv[0]); assert(canResolve(argv[0])); assert(canResolve(url.asString())); - + URL baseUrl = URL::asBaseURL(url); URL exeUrl(exeName); exeUrl.toAbsolute(baseUrl); -- cgit v0.12
Test#StatusDescriptionComment