/* **************************************************************************** * * xmlParse - * * This function is called once (actually it is not that simple) for each node in * the tree that the XML parser has built for us. * * * In the node '<contextValue>', isCompoundValuePath returns TRUE. * Under "<contextValue>", we have either a simple string or a Compound Value Tree. * In the case of a "simple string" the value of the current node is NON EMPTY, * and as the node is treated already in the previous call to 'treat()', no further action is needed. * * If a node is NOT TREATED and it is NOT a compound, a parse error is issued */ void xmlParse ( ConnectionInfo* ciP, xml_node<>* father, xml_node<>* node, const std::string& indentation, const std::string& fatherPath, XmlNode* parseVector, ParseData* parseDataP ) { std::string value = wsStrip(node->value()); std::string name = wsStrip(node->name()); std::string path = fatherPath + "/" + name; bool treated = treat(node, path, parseVector, parseDataP); if (isCompoundValuePath(path.c_str()) && (value == "") && (node->first_node() != NULL)) { // // Count children (to avoid false compounds because of just en empty sttribute value) // xml_node<>* child = node->first_node(); int children = 0; while (child != NULL) { if (child->name()[0] != 0) ++children; child = child->next_sibling(); } if (children == 0) // NOT a compound value return; eatCompound(ciP, NULL, node, ""); compoundValueEnd(ciP, parseDataP); return; } else if (treated == false) { ciP->httpStatusCode = SccBadRequest; if (ciP->answer == "") ciP->answer = std::string("Unknown XML field: '") + name.c_str() + "'"; LM_W(("ERROR: '%s', PATH: '%s' ", ciP->answer.c_str(), fatherPath.c_str())); return; } // Recursive calls for all children of this node xml_node<>* child = node->first_node(); while (child != NULL) { if ((child != NULL) && (child->name() != NULL) && (onlyWs(child->name()) == false)) xmlParse(ciP, node, child, indentation + " ", path, parseVector, parseDataP); child = child->next_sibling(); } }
/* **************************************************************************** * * eatCompound - consume the compound tree * * Three types of tree nodes here (4 actually); * - toplevel node * - leaf * - object node * - vector node */ void eatCompound(ConnectionInfo* ciP, orion::CompoundValueNode* containerP, xml_node<>* node, std::string indent) { if (containerP == NULL) // toplevel) { std::string xmlAttribute = xmlTypeAttributeGet(node); if (xmlAttribute == "vector") containerP = new CompoundValueNode(orion::CompoundValueNode::Vector); else if (xmlAttribute =="") containerP = new CompoundValueNode(orion::CompoundValueNode::Struct); else { ciP->httpStatusCode = SccBadRequest; ciP->answer = std::string("Bad value for XML attribute 'type' for '") + node->name() + "': '" + xmlAttribute + "'"; LM_W(("ERROR: '%s'", ciP->answer.c_str())); return; } ciP->compoundValueRoot = containerP; } else { std::string value = wsStrip(node->value()); std::string name = wsStrip(node->name()); if (value == "") // Object OR Vector { std::string xmlAttribute = xmlTypeAttributeGet(node); if (xmlAttribute == "vector") containerP = containerP->add(orion::CompoundValueNode::Vector, name); else if (xmlAttribute == "") containerP = containerP->add(orion::CompoundValueNode::Struct, name); else { ciP->httpStatusCode = SccBadRequest; ciP->answer = std::string("Bad value for XML attribute 'type' for '") + name + "': '" + xmlAttribute + "'"; LM_W(("ERROR: '%s'", ciP->answer.c_str())); return; } } else // String containerP->add(orion::CompoundValueNode::Leaf, name, value); } xml_node<>* child = node->first_node(); while (child != NULL) { if (child->name()[0] != 0) eatCompound(ciP, containerP, child, indent + " "); child = child->next_sibling(); } }
/* **************************************************************************** * * string2coords - */ bool string2coords(std::string s, double& latitude, double& longitude) { char* initial = strdup(s.c_str()); char* cP = initial; char* comma; char* number1; char* number2; cP = wsStrip(cP); comma = strchr(cP, ','); if (comma == NULL) { free(initial); return false; } *comma = 0; ++comma; number1 = cP; number2 = comma; number1 = wsStrip(number1); number2 = wsStrip(number2); std::string err; double oldLatitude = latitude; double oldLongitude = longitude; latitude = atoF(number1, err); if (err.length() > 0) { latitude = oldLatitude; free(initial); return false; } else { longitude = atoF(number2, err); if (err.length() > 0) { /* Rollback latitude */ latitude = oldLatitude; longitude = oldLongitude; free(initial); return false; } } free(initial); return true; }
/* **************************************************************************** * * servicePathSplit - */ int servicePathSplit(ConnectionInfo* ciP) { int servicePaths = stringSplit(ciP->servicePath, ',', ciP->servicePathV); if (servicePaths == 0) { /* In this case the result is a 0 length vector */ return 0; } if (servicePaths > 10) { OrionError e(SccBadRequest, "too many service paths - a maximum of ten service paths is allowed"); ciP->answer = e.render(ciP->outFormat, ""); return -1; } for (int ix = 0; ix < servicePaths; ++ix) { ciP->servicePathV[ix] = std::string(wsStrip((char*) ciP->servicePathV[ix].c_str())); ciP->servicePathV[ix] = removeTrailingSlash(ciP->servicePathV[ix]); LM_T(LmtServicePath, ("Service Path %d: '%s'", ix, ciP->servicePathV[ix].c_str())); } for (int ix = 0; ix < servicePaths; ++ix) { int s; if ((s = servicePathCheck(ciP, ciP->servicePathV[ix].c_str())) != 0) return s; } return 0; }
/* **************************************************************************** * * servicePathSplit - */ int servicePathSplit(ConnectionInfo* ciP) { #if 0 // // Special case: empty service-path // // FIXME P4: We're not sure what this 'fix' really fixes. // Must implement a functest to reproduce this situation. // And, if that is not possible, just remove the whole thing // if ((ciP->httpHeaders.servicePathReceived == true) && (ciP->servicePath == "")) { OrionError e(SccBadRequest, "empty service path"); ciP->answer = e.render(ciP, ""); alarmMgr.badInput(clientIp, "empty service path"); return -1; } #endif int servicePaths = stringSplit(ciP->servicePath, ',', ciP->servicePathV); if (servicePaths == 0) { /* In this case the result is a vector with an empty string */ ciP->servicePathV.push_back(""); return 0; } if (servicePaths > SERVICE_PATH_MAX_COMPONENTS) { OrionError e(SccBadRequest, "too many service paths - a maximum of ten service paths is allowed"); ciP->answer = e.render(ciP, ""); return -1; } for (int ix = 0; ix < servicePaths; ++ix) { std::string stripped = std::string(wsStrip((char*) ciP->servicePathV[ix].c_str())); ciP->servicePathV[ix] = removeTrailingSlash(stripped); // This was previously a LM_T trace, but we have "promoted" it to INFO due to it is needed to check logs in a .test case (case 0392 service_path_http_header.test) LM_I(("Service Path %d: '%s'", ix, ciP->servicePathV[ix].c_str())); } for (int ix = 0; ix < servicePaths; ++ix) { int s; if ((s = servicePathCheck(ciP, ciP->servicePathV[ix].c_str())) != 0) { return s; } } return 0; }
/* **************************************************************************** * * reference - */ static int reference(xml_node<>* node, ParseData* reqDataP) { std::string ref = node->value(); char* stripped = wsStrip((char*) ref.c_str()); LM_T(LmtParse, ("Got a reference: '%s'", stripped)); reqDataP->scar.res.reference.set(stripped); return 0; }
/* **************************************************************************** * * servicePathSplit - */ int servicePathSplit(ConnectionInfo* ciP) { #if 0 // // Special case: empty service-path // // FIXME P4: We're not sure what this 'fix' really fixes. // Must implement a functest to reproduce this situation. // And, if that is not possible, just remove the whole thing // if ((ciP->httpHeaders.servicePathReceived == true) && (ciP->servicePath == "")) { OrionError e(SccBadRequest, "empty service path"); ciP->answer = e.render(ciP->outFormat, ""); LM_W(("Bad Input (empty service path)")); return -1; } #endif int servicePaths = stringSplit(ciP->servicePath, ',', ciP->servicePathV); if (servicePaths == 0) { /* In this case the result is a 0 length vector */ return 0; } if (servicePaths > 10) { OrionError e(SccBadRequest, "too many service paths - a maximum of ten service paths is allowed"); ciP->answer = e.render(ciP->outFormat, ""); return -1; } for (int ix = 0; ix < servicePaths; ++ix) { ciP->servicePathV[ix] = std::string(wsStrip((char*) ciP->servicePathV[ix].c_str())); ciP->servicePathV[ix] = removeTrailingSlash(ciP->servicePathV[ix]); LM_T(LmtServicePath, ("Service Path %d: '%s'", ix, ciP->servicePathV[ix].c_str())); } for (int ix = 0; ix < servicePaths; ++ix) { int s; if ((s = servicePathCheck(ciP, ciP->servicePathV[ix].c_str())) != 0) return s; } return 0; }
/* **************************************************************************** * * wantedOutputSupported - */ static Format wantedOutputSupported(const std::string& acceptList, std::string* charsetP) { std::vector<std::string> vec; char* copy; if (acceptList.length() == 0) { /* HTTP RFC states that a missing Accept header must be interpreted as if the client is * accepting any type */ copy = strdup("*/*"); } else { copy = strdup((char*) acceptList.c_str()); } char* cP = copy; do { char* comma; comma = strstr(cP, ","); if (comma != NULL) { *comma = 0; cP = wsStrip(cP); vec.push_back(cP); cP = comma; ++cP; } else { cP = wsStrip(cP); if (*cP != 0) { vec.push_back(cP); } *cP = 0; } } while (*cP != 0); free(copy); bool xml = false; bool json = false; for (unsigned int ix = 0; ix < vec.size(); ++ix) { char* s; // // charset embedded in 'Accept' header? // We read it but we don't do anything with it ... // if ((s = strstr((char*) vec[ix].c_str(), ";")) != NULL) { *s = 0; ++s; s = wsStrip(s); if (strncmp(s, "charset=", 8) == 0) { s = &s[8]; s = wsStrip(s); if (charsetP != NULL) *charsetP = s; } } std::string format = vec[ix].c_str(); if (format == "*/*") xml = true; if (format == "*/xml") xml = true; if (format == "application/*") xml = true; if (format == "application/xml") xml = true; if (format == "application/json") json = true; if (format == "*/json") json = true; if ((acceptTextXml == true) && (format == "text/xml")) xml = true; // // Resetting charset // if (charsetP != NULL) *charsetP = ""; } if (xml == true) return XML; else if (json == true) return JSON; LM_W(("Bad Input (no valid 'Accept-format' found)")); return NOFORMAT; }
/* **************************************************************************** * * wantedOutputSupported - */ static MimeType wantedOutputSupported(const std::string& apiVersion, const std::string& acceptList, std::string* charsetP) { std::vector<std::string> vec; char* copy; if (acceptList.length() == 0) { /* HTTP RFC states that a missing Accept header must be interpreted as if the client is accepting any type */ copy = strdup("*/*"); } else { copy = strdup((char*) acceptList.c_str()); } char* cP = copy; do { char* comma; comma = strstr(cP, ","); if (comma != NULL) { *comma = 0; cP = wsStrip(cP); vec.push_back(cP); cP = comma; ++cP; } else { cP = wsStrip(cP); if (*cP != 0) { vec.push_back(cP); } *cP = 0; } } while (*cP != 0); free(copy); bool json = false; bool text = true; for (unsigned int ix = 0; ix < vec.size(); ++ix) { char* s; // // charset embedded in 'Accept' header? // We read it but we don't do anything with it ... // if ((s = strstr((char*) vec[ix].c_str(), ";")) != NULL) { *s = 0; ++s; s = wsStrip(s); if (strncmp(s, "charset=", 8) == 0) { s = &s[8]; s = wsStrip(s); if (charsetP != NULL) *charsetP = s; } } std::string mimeType = vec[ix].c_str(); if (mimeType == "*/*") { json = true; text=true;} if (mimeType == "application/*") { json = true; } if (mimeType == "application/json") { json = true; } if (mimeType == "*/json") { json = true; } if (mimeType == "text/plain") { text = true; } // // Resetting charset // if (charsetP != NULL) { *charsetP = ""; } } if (apiVersion == "v2") { if (json == true) { return JSON; } else if (text) { return TEXT; } } else { if (json == true) { return JSON; } } alarmMgr.badInput(clientIp, "no valid 'Accept-format' found"); return NOMIMETYPE; }
/* **************************************************************************** * * eatCompound - consume the compound tree * * Three types of tree nodes here (4 actually); * - toplevel node * - string * - object node * - vector node */ void eatCompound(ConnectionInfo* ciP, orion::CompoundValueNode* containerP, xml_node<>* node, const std::string& indent) { if (containerP == NULL) // toplevel { std::string xmlAttribute = xmlTypeAttributeGet(node); if (xmlAttribute == "vector") { containerP = new CompoundValueNode(orion::CompoundValueNode::Vector); } else if (xmlAttribute =="") { containerP = new CompoundValueNode(orion::CompoundValueNode::Object); } else { ciP->httpStatusCode = SccBadRequest; ciP->answer = std::string("Bad value for XML attribute /type/ for /") + node->name() + "/: " + xmlAttribute; LM_W(("Bad Input (%s)", ciP->answer.c_str())); return; } ciP->compoundValueRoot = containerP; } else { std::string value = wsStrip(node->value()); std::string name = wsStrip(node->name()); if (value == "") // Object OR Vector { std::string xmlAttribute = xmlTypeAttributeGet(node); if (xmlAttribute == "vector") { containerP = containerP->add(orion::CompoundValueNode::Vector, name); } else if (xmlAttribute == "") { containerP = containerP->add(orion::CompoundValueNode::Object, name); } else { ciP->httpStatusCode = SccBadRequest; ciP->answer = std::string("Bad value for XML attribute /type/ for /") + name + "/: " + xmlAttribute; LM_W(("Bad Input (%s)", ciP->answer.c_str())); return; } } else // String { if (forbiddenChars(value.c_str()) == true) { LM_E(("Found a forbidden value in '%s'", value.c_str())); ciP->httpStatusCode = SccBadRequest; ciP->answer = std::string("Illegal value for XML attribute"); return; } containerP->add(orion::CompoundValueNode::String, name, value); } } xml_node<>* child = node->first_node(); while (child != NULL) { if (child->name()[0] != 0) { eatCompound(ciP, containerP, child, indent + " "); } child = child->next_sibling(); } }
/* **************************************************************************** * * versionParse - */ bool versionParse(const std::string& version, int& mayor, int& minor, std::string& bugFix) { char* copy = strdup(version.c_str()); char* s = wsStrip(copy); char* dotP; // // mayor number // dotP = strchr(s, '.'); if (dotP == NULL) { free(copy); return false; } *dotP = 0; ++dotP; s = wsStrip(s); mayor = atoi(s); if (strspn(s, "0123456789") != strlen(s)) { free(copy); return false; } s = dotP; // // minor number // If no dot is found, no bugFix 'version' is present. // Just zero the 'bugFix' and keep the remaining string in minor. // bool bugFixEmpty = false; dotP = strchr(s, '.'); if (dotP != NULL) { *dotP = 0; ++dotP; } else { bugFix = ""; bugFixEmpty = true; } s = wsStrip(s); minor = atoi(s); if (strspn(s, "0123456789") != strlen(s)) { free(copy); return false; } if (bugFixEmpty == true) { free(copy); return true; } s = dotP; // // bugfix // s = wsStrip(s); bugFix = s; free(copy); return true; }
/* **************************************************************************** * * string2coords - */ bool string2coords(const std::string& s, double& latitude, double& longitude) { char* initial = strdup(s.c_str()); char* cP = initial; char* comma; char* number1; char* number2; bool ret = true; cP = wsStrip(cP); comma = strchr(cP, ','); if (comma == NULL) { free(initial); return false; } *comma = 0; ++comma; number1 = cP; number2 = comma; number1 = wsStrip(number1); number2 = wsStrip(number2); std::string err; double oldLatitude = latitude; double oldLongitude = longitude; latitude = atoF(number1, &err); if (err.length() > 0) { latitude = oldLatitude; LM_W(("Bad Input (bad latitude value in coordinate string '%s')", initial)); ret = false; } else { longitude = atoF(number2, &err); if (err.length() > 0) { /* Rollback latitude */ latitude = oldLatitude; longitude = oldLongitude; LM_W(("Bad Input (bad longitude value in coordinate string '%s')", initial)); ret = false; } } if ((latitude > 90) || (latitude < -90)) { LM_W(("Bad Input (bad value for latitude '%s')", initial)); ret = false; } else if ((longitude > 180) || (longitude < -180)) { LM_W(("Bad Input (bad value for longitude '%s')", initial)); ret = false; } free(initial); return ret; }