return false;
}
-bool Launcher::getContentFromFile(const std::string &pathfile, std::string &content) const throw(anna::RuntimeException) {
-
- std::ifstream inFile(pathfile.c_str(), std::ifstream::in);
- if(!inFile.good()) {
- throw RuntimeException(anna::functions::asString("Unable to open file '%s'", pathfile.c_str()), ANNA_FILE_LOCATION);
- }
-
- std::stringstream strStream;
- strStream << inFile.rdbuf(); //read the file
- content = strStream.str(); // holds the content of the file
- inFile.close();
-
- return true;
-}
-
void Launcher::resetStatistics() throw() {
if (a_workingNode) {
a_workingNode->getCommEngine()->resetStatistics();
throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
- // Get xml content from file:
- std::string regexp;
- if(!getContentFromFile(param3, regexp))
- throw anna::RuntimeException("Error reading xml content from file provided", ANNA_FILE_LOCATION);
+ codecMsg.loadXMLFile(param3);
+ std::string regexp = codecMsg.asXMLString(true /* normalization */);
+
+ // Now we must insert regular expressions in hop-by-hop, end-to-end and Origin-State-Id:
// optional 'full':
if(param4 != "strict") {
-
- // TODO: use this from gcc4.9.0: http://stackoverflow.com/questions/8060025/is-this-c11-regex-error-me-or-the-compiler
-/*
- std::string s_from = "hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\"";
- std::string s_to = s_from;
- std::string s_from2 = "avp name=\"Origin-State-Id\" data=\"[0-9]+\"";
- std::string s_to2 = s_from2;
-
- try {
- regexp = std::regex_replace (regexp, std::regex(s_from), s_to);
- regexp = std::regex_replace (regexp, std::regex(s_from2), s_to2);
- }
- catch (const std::regex_error& e) {
- throw anna::RuntimeException(e.what(), ANNA_FILE_LOCATION);
- }
-
-*/
std::string::size_type pos, pos_1, pos_2;
- pos = regexp.find("hop-by-hop-id=", 0u);
+ pos = regexp.find("end-to-end-id=", 0u);
pos = regexp.find("\"", pos);
pos_1 = pos;
pos = regexp.find("\"", pos+1);
pos_2 = pos;
regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
- pos = regexp.find("end-to-end-id=", 0u);
+ pos = regexp.find("hop-by-hop-id=", 0u);
pos = regexp.find("\"", pos);
pos_1 = pos;
pos = regexp.find("\"", pos+1);
pos_2 = pos;
regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
+ // For this representation: <avp name="Origin-State-Id" data="1428633668"/>
+ //pos = regexp.find("Origin-State-Id", 0u);
+ //pos = regexp.find("\"", pos);
+ //pos = regexp.find("\"", pos+1);
+ //pos_1 = pos;
+ //pos = regexp.find("\"", pos+1);
+ //pos_2 = pos;
+ //regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
+ // But we have this one: <avp data="1428633668" name="Origin-State-Id"/>
pos = regexp.find("Origin-State-Id", 0u);
- pos = regexp.find("\"", pos);
- pos = regexp.find("\"", pos+1);
+ pos = regexp.rfind("\"", pos);
+ pos = regexp.rfind("\"", pos-1);
+ pos = regexp.rfind("\"", pos-1);
pos_1 = pos;
pos = regexp.find("\"", pos+1);
pos_2 = pos;
// helpers
bool getDataBlockFromHexFile(const std::string &pathfile, anna::DataBlock &db) const throw(anna::RuntimeException);
- bool getContentFromFile(const std::string &pathfile, std::string &content) const throw(anna::RuntimeException);
friend class TestManager;
};
* @return Returns decoded representation
*/
static std::string decodeBase64(const std::string & encodedString);
+
+
+ /*
+ * Reads a file into passed string
+ *
+ * @param pathfile Path file to read
+ * @param content String where file content is dump
+ *
+ * @return success for read operation
+ */
+ static bool getContentFromFile(const std::string &pathfile, std::string &content) throw(anna::RuntimeException);
};
}
/**
Class xml string representation
- @param sortAttributes Optional normalization used to match xml representation with regexps
+ @param normalize Optional normalization which sorts attribute names and removes
+ newlines in the xml representation in order to ease regexp matching.
\return XML string representation with relevant information for this instance.
*/
- std::string asXMLString(bool sortAttributes = false) const throw();
+ std::string asXMLString(bool normalize = false) const throw();
/**
Comparison operator by mean serialization
/**
Class xml string representation
- @param sortAttributes Optional normalization used to match xml representation with regexps
+ @param normalize Optional normalization which sorts attribute names and removes
+ newlines in the xml representation in order to ease regexp matching.
\return XML string representation with relevant information for this instance.
*/
- std::string asXMLString(bool sortAttributes = false) const throw();
+ std::string asXMLString(bool normalize = false) const throw();
/**
Comparison operator by mean serialization
friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); }
/**
- Match a regular expression (string pattern) regarding xml string serialization for this message.
- Using a complex pattern (many avps, grouped ones) it could be necessary to fix the message before
- using the method in order to perform a more controlled comparison. In the same way, flags could be
- ignored to simplify message xml presentation.
- This powerful tool could be used to program traffic analysis and decide future behaviour (routing,
- traslation, etc.).
+ Matchs a regular expression (string pattern) regarding xml string serialization for this message.
+ The message xml representation is internally normalized (attribute names are sort and newlines
+ are removed) in order to ease regexp matching.
- <pre>
- Examples:
+ You could use simple regular expressions.
+ For example, the pattern '<avp data="(.)*32251@3gpp.org" name="Service-Context-Id"/>' detects
+ PS charging contexts because of data suffix specification '32251@3gpp.org' for that AVP.
+ The pattern '<message(.)* name="Capabilities-Exchange-Request"' detects a CER message. And so on.
- The pattern '<avp name="Service-Context-Id" data="(.)*32251@3gpp.org"/>' detects PS charging contexts
- because of data suffix specification '32251@3gpp.org' for that AVP.
+ It would seems strange or 'creative' to use regular expressions within an hex string representation,
+ but anyway you could also do such kind of things to check non-printable data parts within the message:
+ for example, the pattern '<avp hex-data="0a[A-Fa-f0-9]{2}0a0a" name="Framed-IP-Address"/>'
+ matchs IP addresses for '10.x.10.10' where x = [0..255].
- The pattern '<message version="1" name="Capabilities-Exchange-Request"' detects a CER message.
+ Normally only printable 'data' fields are used for matching issues.
- The pattern (string including carriage returns):
+ Now imagine 'message.xml' containing this avp:
- '<avp name="Subscription-Id">
- <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
- <avp name="Subscription-Id-Data" data="606000106"/>
+ <pre>
+ ...
+ <avp name="Subscription-Id">
+ <avp alias="END_USER_E164" data="0" name="Subscription-Id-Type"/>
+ <avp data="616[0-9]{6}" name="Subscription-Id-Data"/>
</avp>'
+ ...
+ </pre>
- detects MSISDN (not IMSI) equal to 606000106
+ You could also extract AVP xml normalized representation in this way:
- It would seems strange or 'creative' to use regular expressions within an hex string representation,
- but anyway you could also do such kind of things to check non-printable data parts within the message:
- for example, the pattern '<avp name="Framed-IP-Address" hex-data="0a[A-Fa-f0-9][A-Fa-f0-9]0a0a"/>'
- matchs IP addresses for '10.x.10.10' where x = [0..255].
+ <pre>
+ anna::diameter::codec::Message myMessage;
+ myMessage.loadXMLFile("message.xml");
+ std::string subscriptionId = myMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString(true);
+ // Former is '<avp data="616[0-9]{6}" name="Subscription-Id-Data"/>'
+ </pre>
+
+ And then use to match incoming messages:
- Note that string pattern could also be generated via #loadXMLFile/#loadXMLString and then #asXML, thus, you
- could get patterns through xml files which act as conditional triggers over message. In that case,
- it is not possible to specify regular expressions within xml 'hex-data' fields because parser will fail
- during hexadecimal read. Normally only printable 'data' fields are used for matching issues.
-
- For example, imagine a 'pattern.xml' file like:
- <message version="1" name="Credit-Control-Request" application-id="16777236" hop-by-hop-id="0" end-to-end-id="0">
- <avp name="Subscription-Id">
- <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
- <avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>
- </avp>
- </message>
-
- Then you could do:
-
- anna::diameter::codec::Message patternMessage;
- patternMessage.loadXMLFile("pattern.xml");
- std::string pattern = patternMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString();
- // Former is '<avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>'
- bool match = incomingMessage.isLike(pattern);
-
- Then, messages having MSISDN numbers starting with '616' will match the pattern.
- Note, that any other message codes (and not only Credit-Control-Request ones), could pass the test...
- You could also build that string manually:
-
- Example 1:
- std::string pattern = "<avp name=\"Subscription-Id\">\n";
- pattern += std::string(ANNA_XML_INDENTATION_SPACES, ' '); pattern += "<avp name=\"Subscription-Id-Type\" data=\"0\" alias=\"END_USER_E164\"/>\n"
- pattern += std::string(ANNA_XML_INDENTATION_SPACES, ' '); pattern += "<avp name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"/>"
-
- Example 2:
- std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
+ <pre>
+ bool match = incomingMessage.isLike(subscriptionId);
</pre>
+ Using a complex pattern (many avps, grouped ones) is possible, indeed testing ADML engine supports 'waitfe/fc-xml'
+ operations which load entire diameter messages to be used as a whole regular expression (hop-by-hop, end-to-end and
+ Origin-State-Id avp is automatically replaced by '[0-9]+' to make possible the comparison).
+
+ Those operations makes all the work, but if you use the API, you may take into account:
+
+ - Respect indentation for inner Message xml representation (normally 3 spaces).
+ - Sort alphabetically the attribute names in every xml node.
+ - Remove all the newlines in the xml representation as normalization stage.
+ - Ignore flags and set the fix mode for the message.
+
\return Returns the match result
*/
bool isLike(const std::string &pattern) const throw();
#include <anna/core/util/Tokenizer.hpp>
#include <algorithm>
+#include <fstream>
+#include <sstream>
using namespace anna;
return ret;
}
+bool functions::getContentFromFile(const std::string &pathfile, std::string &content) throw(anna::RuntimeException) {
+
+ std::ifstream inFile(pathfile.c_str(), std::ifstream::in);
+ if(!inFile.good()) {
+ throw RuntimeException(anna::functions::asString("Unable to open file '%s'", pathfile.c_str()), ANNA_FILE_LOCATION);
+ }
+
+ std::stringstream strStream;
+ strStream << inFile.rdbuf(); //read the file
+ content = strStream.str(); // holds the content of the file
+ inFile.close();
+
+ return true;
+}
+
//------------------------------------------------------------------------------
//----------------------------------------------------------- Avp::asXMLString()
//------------------------------------------------------------------------------
-std::string Avp::asXMLString(bool sortAttributes) const throw() {
+std::string Avp::asXMLString(bool normalize) const throw() {
anna::xml::Node root("root");
- anna::xml::Compiler::Mode::_v mode = sortAttributes ? anna::xml::Compiler::Mode::Sort : anna::xml::Compiler::Mode::Visual;
- return anna::xml::Compiler().apply(asXML(&root), mode);
+ anna::xml::Compiler::Mode::_v mode = normalize ? anna::xml::Compiler::Mode::Sort : anna::xml::Compiler::Mode::Visual;
+ std::string result = anna::xml::Compiler().apply(asXML(&root), mode);
+
+ if (normalize)
+ result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
+
+ return result;
}
//------------------------------------------------------------------------------
bool Avp::isLike(const std::string &pattern) const throw() {
anna::RegularExpression re(pattern);
- return re.isLike(asXMLString());
+ return re.isLike(asXMLString(true /* normalize by mean sorting attribute names and removing new lines */));
}
+
//------------------------------------------------------------------------------
//------------------------------------------------------- Message::asXMLString()
//------------------------------------------------------------------------------
-std::string Message::asXMLString(bool sortAttributes) const throw() {
+std::string Message::asXMLString(bool normalize) const throw() {
anna::xml::Node root("root");
- anna::xml::Compiler::Mode::_v mode = sortAttributes ? anna::xml::Compiler::Mode::Sort : anna::xml::Compiler::Mode::Visual;
- return anna::xml::Compiler().apply(asXML(&root), mode);
+ anna::xml::Compiler::Mode::_v mode = normalize ? anna::xml::Compiler::Mode::Sort : anna::xml::Compiler::Mode::Visual;
+ std::string result = anna::xml::Compiler().apply(asXML(&root), mode);
+
+ if (normalize)
+ result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
+
+ return result;
}
//------------------------------------------------------------------------------
bool Message::isLike(const std::string &pattern) const throw() {
anna::RegularExpression re(pattern);
- return re.isLike(asXMLString());
+ return re.isLike(asXMLString(true /* normalize by mean sorting attribute names and removing new lines */));
}
+
if (a_type == Type::RegexpXml) {
anna::diameter::codec::Message codecMsg;
try { codecMsg.decode(message); } catch (anna::RuntimeException &ex) { ex.trace(); }
-
- //return codecMsg.isLike(getRegexp());
- // We will remove LF from both sides to ease regexp management:
- std::string regexp = getRegexp();
- regexp.erase(std::remove(regexp.begin(), regexp.end(), '\n'), regexp.end());
- anna::RegularExpression re(regexp);
-
- std::string msgString = codecMsg.asXMLString();
- msgString.erase(std::remove(msgString.begin(), msgString.end(), '\n'), msgString.end());
-
- return re.isLike(msgString);
+ return codecMsg.isLike(getRegexp());
}
else if (a_type == Type::RegexpHex) {
anna::RegularExpression re(getRegexp());