/*----------------------------------------------------------------------------*/ void XmlServer :: methodRegister(XmlRequest& request, XmlResponse& response) { if(database->isKsefError() || database->ksefDatabase() == NULL) { response.setStatus(XmlResponse::InternalError, database->ksefMessage()); return; } User user = database->userStorage()->user(request.userName(), request.password()); if(!user.ksef.write) { response.setStatus(XmlResponse::accessDenied, QString("Access denied for user '%1'").arg(user.name)); return; } KsefDocument doc; QDomElement data = request.data(); QDomElement e = data.firstChildElement("RQ"); e = e.firstChildElement("DAT"); if(e.isNull() || !doc.assign(e)) { response.setStatus(XmlResponse::InvalidQuery, "Invalid query"); return; } if(!database->ksefDatabase()->cashRegister(doc, response)) response.setStatus(XmlResponse::InternalError, database->ksefDatabase()->message()); }
/*----------------------------------------------------------------------------*/ void XmlServer :: methodUpdate(XmlRequest& request, XmlResponse& response) { if(database->isStoreError() || database->storeDatabase() == NULL) { response.setStatus(XmlResponse::InternalError, database->storeMessage()); return; } User user = database->userStorage()->user(request.userName(), request.password()); if(!user.store.write) { response.setStatus(XmlResponse::accessDenied, QString("Access denied for user '%1'").arg(user.name)); return; } if(!database->storeDatabase()->update(request, response)) response.setStatus(XmlResponse::InternalError, database->storeDatabase()->message()); }
/*----------------------------------------------------------------------------*/ void XmlServer :: methodKsefGet(XmlRequest& request, XmlResponse& response) { if(database->isKsefError() || database->ksefDatabase() == NULL) { response.setStatus(XmlResponse::InternalError, database->ksefMessage()); return; } User user = database->userStorage()->user(request.userName(), request.password()); if(!user.ksef.read) { response.setStatus(XmlResponse::accessDenied, QString("Access denied for user '%1'").arg(user.name)); return; } if(!database->ksefDatabase()->query(request, response)) response.setStatus(XmlResponse::InternalError, database->ksefDatabase()->message()); }
/* **************************************************************************** * * invalidEntityIdAttribute_xml - * * FIXME P5: invalid attributes in EntityId are found but not reported */ TEST(SubscribeContextRequest, invalidEntityIdAttribute_xml) { ParseData parseData; ConnectionInfo ci("", "POST", "1.1"); const char* infile = "ngsi10.subscribeContextRequest.entityIdAttribute.invalid.xml"; const char* expected = "OK"; XmlRequest* reqP; utInit(); EXPECT_EQ("OK", testDataFromFile(testBuf, sizeof(testBuf), infile)) << "Error getting test data from '" << infile << "'"; std::string result = xmlTreat(testBuf, &ci, &parseData, SubscribeContext, "subscribeContextRequest", &reqP); reqP->release(&parseData); EXPECT_STREQ(expected, result.c_str()); utExit(); }
/* **************************************************************************** * * invalidDuration_xml - */ TEST(SubscribeContextRequest, invalidDuration_xml) { ParseData parseData; ConnectionInfo ci("", "POST", "1.1"); const char* infile = "ngsi10.subscribeContextRequest.duration.invalid.xml"; const char* outfile = "ngsi10.subscribeContextResponse.invalidDuration.valid.xml"; XmlRequest* reqP; utInit(); EXPECT_EQ("OK", testDataFromFile(testBuf, sizeof(testBuf), infile)) << "Error getting test data from '" << infile << "'"; EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), outfile)) << "Error getting test data from '" << outfile << "'"; lmTraceLevelSet(LmtDump, true); std::string out = xmlTreat(testBuf, &ci, &parseData, SubscribeContext, "subscribeContextRequest", &reqP); lmTraceLevelSet(LmtDump, false); reqP->release(&parseData); EXPECT_STREQ(expectedBuf, out.c_str()); utExit(); }
/*----------------------------------------------------------------------------*/ void XmlServer :: service(XmlRequest& request, XmlResponse& response) { if(request.method() == "register") { methodRegister(request, response); } else if(request.method() == "upload") { methodUpload(request, response); } else if(request.method() == "download") { methodDownload(request, response); } else if(request.method() == "sync") { methodUpload(request, response); if(response.isOk()) methodDownload(request, response); } else if(request.method() == "update") { methodUpdate(request, response); } else if(request.method() == "ksef_get") { methodKsefGet(request, response); } else { response.setStatus(XmlResponse::InvalidMethod, QString("Invalid method '%1'").arg(request.method()) ); } }
/* **************************************************************************** * * xmlTreat - */ std::string xmlTreat ( const char* content, ConnectionInfo* ciP, ParseData* parseDataP, RequestType request, std::string payloadWord, XmlRequest** reqPP, std::string* errorMsgP ) { xml_document<> doc; char* xmlPayload = (char*) content; // // If the payload is empty, the XML parsing library does an assert // and the broker dies. // Therefore, this check here is important, to avoid death. // // 'OK' is returned as there is no error to send a request without payload. // if ((content == NULL) || (*content == 0)) { return "OK"; } try { doc.parse<0>(xmlPayload); } catch (parse_error& e) { std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error"); LM_W(("Bad Input ('%s', '%s')", content, e.what())); if (errorMsgP) { *errorMsgP = std::string("XML parse error exception: ") + e.what(); } return errorReply; } catch (...) { std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error"); LM_W(("Bad Input (%s)", content)); if (errorMsgP) { *errorMsgP = std::string("XML parse generic exception"); } return errorReply; } xml_node<>* father = doc.first_node(); XmlRequest* reqP = xmlRequestGet(request, ciP->method); ciP->parseDataP = parseDataP; if (father == NULL) { std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error"); LM_W(("Bad Input (XML parse error)")); if (errorMsgP) { *errorMsgP = std::string("XML parse error: invalid XML input"); } return errorReply; } if (reqP == NULL) { std::string errorReply = restErrorReplyGet( ciP, ciP->outFormat, "", requestType(request), SccBadRequest, std::string("Sorry, no request treating object found for RequestType /") + requestType(request) + "/, method /" + ciP->method + "/"); LM_W(("Bad Input (no request treating object found for RequestType %d (%s), method %s)", request, requestType(request), ciP->method.c_str())); LM_W(("Bad Input (no request treating object found for RequestType %d (%s), method %s)", request, requestType(request), ciP->method.c_str())); if (errorMsgP) { *errorMsgP = std::string("Unable to treat ") + requestType(request) + " requests"; } return errorReply; } if (reqPP != NULL) { *reqPP = reqP; } // // Checking that the payload matches the URL // if (((ciP->verb == POST) || (ciP->verb == PUT)) && (payloadWord.length() != 0)) { std::string errorReply; char* payloadStart = (char*) content; // Skip '<?xml version="1.0" encoding="UTF-8"?> ' ? if (strncmp(payloadStart, "<?xml", 5) == 0) { ++payloadStart; payloadStart = strstr(payloadStart, "<"); } // Skip '<' if (*payloadStart == '<') { ++payloadStart; } if (strncasecmp(payloadWord.c_str(), payloadStart, payloadWord.length()) != 0) { errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", reqP->keyword, SccBadRequest, std::string("Expected /") + payloadWord + "/ payload, got /" + payloadStart + "/"); LM_W(("Bad Input (invalid payload: wanted: '%s', got '%s')", payloadWord.c_str(), payloadStart)); if (errorMsgP) { *errorMsgP = std::string("Bad Input (invalid payload, expecting '") + payloadWord + "', got '" + payloadStart + "')"; } return errorReply; } } if (reqP->init == NULL) // No payload treating function { return "OK"; } reqP->init(parseDataP); ciP->httpStatusCode = SccOk; xmlParse(ciP, NULL, father, "", "", reqP->parseVector, parseDataP, errorMsgP); if (ciP->httpStatusCode != SccOk) { LM_W(("Bad Input (XML parse error)")); return restErrorReplyGet(ciP, ciP->outFormat, "", payloadWord, ciP->httpStatusCode, ciP->answer); } LM_T(LmtParseCheck, ("Calling check for XML parsed tree (%s)", ciP->payloadWord)); std::string check = reqP->check(parseDataP, ciP); if (check != "OK") { LM_W(("Bad Input (%s: %s)", reqP->keyword.c_str(), check.c_str())); if (errorMsgP) { *errorMsgP = std::string("Bad Input: ") + check; } } reqP->present(parseDataP); if (check != "OK") { if (errorMsgP) { *errorMsgP = std::string("Bad Input: ") + check; } } return check; }
/* **************************************************************************** * * restService - */ std::string restService(ConnectionInfo* ciP, RestService* serviceV) { std::vector<std::string> compV; int components; XmlRequest* reqP = NULL; JsonRequest* jsonReqP = NULL; ParseData parseData; if ((ciP->url.length() == 0) || ((ciP->url.length() == 1) && (ciP->url.c_str()[0] == '/'))) { OrionError error(SccBadRequest, "The Orion Context Broker is a REST service, not a 'web page'"); std::string response = error.render(ciP->outFormat, ""); LM_W(("Bad Input (The Orion Context Broker is a REST service, not a 'web page')")); restReply(ciP, response); return std::string("Empty URL"); } ciP->httpStatusCode = SccOk; components = stringSplit(ciP->url, '/', compV); for (unsigned int ix = 0; serviceV[ix].treat != NULL; ++ix) { if ((serviceV[ix].components != 0) && (serviceV[ix].components != components)) { continue; } if ((ciP->method != serviceV[ix].verb) && (serviceV[ix].verb != "*")) { continue; } strncpy(ciP->payloadWord, serviceV[ix].payloadWord.c_str(), sizeof(ciP->payloadWord)); bool match = true; for (int compNo = 0; compNo < components; ++compNo) { if (serviceV[ix].compV[compNo] == "*") { continue; } if (strcasecmp(serviceV[ix].compV[compNo].c_str(), compV[compNo].c_str()) != 0) { match = false; break; } } if (match == false) { continue; } if ((ciP->payload != NULL) && (ciP->payloadSize != 0) && (ciP->payload[0] != 0) && (serviceV[ix].verb != "*")) { std::string response; LM_T(LmtParsedPayload, ("Parsing payload for URL '%s', method '%s', service vector index: %d", ciP->url.c_str(), ciP->method.c_str(), ix)); ciP->parseDataP = &parseData; response = payloadParse(ciP, &parseData, &serviceV[ix], &reqP, &jsonReqP); LM_T(LmtParsedPayload, ("payloadParse returns '%s'", response.c_str())); if (response != "OK") { restReply(ciP, response); if (reqP != NULL) { reqP->release(&parseData); } if (jsonReqP != NULL) { jsonReqP->release(&parseData); } compV.clear(); return response; } } LM_T(LmtService, ("Treating service %s %s", serviceV[ix].verb.c_str(), ciP->url.c_str())); // Sacred - used in 'heavyTest' statisticsUpdate(serviceV[ix].request, ciP->inFormat); // Tenant to connectionInfo ciP->tenant = ciP->tenantFromHttpHeader; // // A tenant string must not be longer than 50 characters and may only contain // underscores and alphanumeric characters. // std::string result; if ((ciP->tenant != "") && ((result = tenantCheck(ciP->tenant)) != "OK")) { OrionError error(SccBadRequest, "tenant name not accepted - a tenant string must not be longer than " MAX_TENANT_NAME_LEN_STRING " characters" " and may only contain underscores and alphanumeric characters"); std::string response = error.render(ciP->outFormat, ""); LM_W(("Bad Input (%s)", error.details.c_str())); restReply(ciP, response); if (reqP != NULL) { reqP->release(&parseData); } if (jsonReqP != NULL) { jsonReqP->release(&parseData); } compV.clear(); return response; } LM_T(LmtTenant, ("tenant: '%s'", ciP->tenant.c_str())); commonFilters(ciP, &parseData, &serviceV[ix]); scopeFilter(ciP, &parseData, &serviceV[ix]); std::string response = serviceV[ix].treat(ciP, components, compV, &parseData); filterRelease(&parseData, serviceV[ix].request); if (reqP != NULL) { reqP->release(&parseData); } if (jsonReqP != NULL) { jsonReqP->release(&parseData); } compV.clear(); if (response == "DIE") { orionExitFunction(0, "Received a 'DIE' request on REST interface"); } restReply(ciP, response); return response; } LM_W(("Bad Input (service '%s' not recognized)", ciP->url.c_str())); ciP->httpStatusCode = SccBadRequest; std::string answer = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->payloadWord, SccBadRequest, std::string("unrecognized request")); restReply(ciP, answer); compV.clear(); return answer; }