/* **************************************************************************** * * jsonTreat - */ std::string jsonTreat(const char* content, ConnectionInfo* ciP, ParseData* parseDataP, RequestType request, std::string payloadWord, JsonRequest** reqPP) { std::string res = "OK"; JsonRequest* reqP = jsonRequestGet(request, ciP->method); LM_T(LmtParse, ("Treating a JSON request: '%s'", content)); ciP->parseDataP = parseDataP; 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) + "'"); LM_RE(errorReply, ("Sorry, no request treating object found for RequestType %d (%s)", request, requestType(request))); } if (reqPP != NULL) *reqPP = reqP; LM_T(LmtParse, ("Treating '%s' request", reqP->keyword.c_str())); reqP->init(parseDataP); try { res = jsonParse(ciP, content, reqP->keyword, reqP->parseVector, parseDataP); if (ciP->inCompoundValue == true) orion::compoundValueEnd(ciP, parseDataP); if ((lmTraceIsSet(LmtCompoundValueShow)) && (ciP->compoundValueP != NULL)) ciP->compoundValueP->shortShow("after parse: "); } catch (std::exception &e) { std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", reqP->keyword, SccBadRequest, std::string("JSON Parse Error: ") + e.what()); LM_E(("JSON Parse Error: '%s'", e.what())); LM_RE(errorReply, (res.c_str())); } if (res != "OK") { LM_E(("JSON parse error: %s", res.c_str())); ciP->httpStatusCode = SccBadRequest; std::string answer = restErrorReplyGet(ciP, ciP->outFormat, "", payloadWord, ciP->httpStatusCode, res); return answer; } reqP->present(parseDataP); LM_T(LmtParseCheck, ("Calling check for JSON parsed tree (%s)", ciP->payloadWord)); res = reqP->check(parseDataP, ciP); reqP->present(parseDataP); return res; }
/* **************************************************************************** * * badIsPattern_json - */ TEST(UpdateContextRequest, badIsPattern_json) { ParseData parseData; ConnectionInfo ci("", "POST", "1.1"); const char* infile = "ngsi10.updateContextRequest.badIsPattern.invalid.json"; const char* outfile = "ngsi10.updateContextResponse.badIsPattern.invalid.json"; JsonRequest* reqP; utInit(); ci.inFormat = JSON; ci.outFormat = JSON; 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; std::string out = jsonTreat(testBuf, &ci, &parseData, UpdateContext, "updateContextRequest", &reqP); EXPECT_STREQ(expectedBuf, out.c_str()); reqP->release(&parseData); utExit(); }
/* **************************************************************************** * * json_ok - */ TEST(RegisterContextRequest, json_ok) { ParseData parseData; const char* inFile = "ngsi9.registerContextRequest.ok.valid.json"; const char* outFile = "ngsi9.registerContextRequestRendered.ok.valid.json"; RegisterContextRequest* rcrP = &parseData.rcr.res; ConnectionInfo ci("", "POST", "1.1"); JsonRequest* reqP; std::string out; ci.inFormat = JSON; ci.outFormat = JSON; 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 << "'"; std::string result = jsonTreat(testBuf, &ci, &parseData, RegisterContext, "registerContextRequest", &reqP); EXPECT_EQ("OK", result) << "this test should be OK"; out = rcrP->render(RegisterContext, JSON, ""); EXPECT_STREQ(expectedBuf, out.c_str()); reqP->release(&parseData); }
/* **************************************************************************** * * restService - */ std::string restService(ConnectionInfo* ciP, RestService* serviceV) { std::vector<std::string> compV; int components; JsonRequest* jsonReqP = NULL; ParseData parseData; JsonDelayedRelease jsonRelease; 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, ""); alarmMgr.badInput(clientIp, "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; LM_T(LmtPayload, ("Parsing payload '%s'", ciP->payload)); response = payloadParse(ciP, &parseData, &serviceV[ix], &jsonReqP, &jsonRelease, compV); LM_T(LmtParsedPayload, ("payloadParse returns '%s'", response.c_str())); if (response != "OK") { alarmMgr.badInput(clientIp, response); restReply(ciP, response); if (jsonReqP != NULL) { jsonReqP->release(&parseData); } if (ciP->apiVersion == "v2") { delayedRelease(&jsonRelease); } compV.clear(); return response; } } LM_T(LmtService, ("Treating service %s %s", serviceV[ix].verb.c_str(), ciP->url.c_str())); // Sacred - used in 'heavyTest' if (ciP->payloadSize == 0) { ciP->inFormat = NOFORMAT; } statisticsUpdate(serviceV[ix].request, ciP->inFormat); // Tenant to connectionInfo ciP->tenant = ciP->tenantFromHttpHeader; lmTransactionSetService(ciP->tenant.c_str()); // // 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, result); std::string response = error.render(ciP, ""); alarmMgr.badInput(clientIp, result); if (ciP->apiVersion != "v1") { ciP->httpStatusCode = SccBadRequest; // FIXME P9: OK for all versions? } restReply(ciP, response); if (jsonReqP != NULL) { jsonReqP->release(&parseData); } if (ciP->apiVersion == "v2") { delayedRelease(&jsonRelease); } compV.clear(); return response; } LM_T(LmtTenant, ("tenant: '%s'", ciP->tenant.c_str())); commonFilters(ciP, &parseData, &serviceV[ix]); scopeFilter(ciP, &parseData, &serviceV[ix]); // // If we have gotten this far the Input is OK. // Except for all the badVerb/badRequest, etc. // A common factor for all these 'services' is that the verb is '*' // // So, the 'Bad Input' alarm is cleared for this client. // if (serviceV[ix].verb != "*") { alarmMgr.badInputReset(clientIp); } std::string response = serviceV[ix].treat(ciP, components, compV, &parseData); filterRelease(&parseData, serviceV[ix].request); if (jsonReqP != NULL) { jsonReqP->release(&parseData); } if (ciP->apiVersion == "v2") { delayedRelease(&jsonRelease); } compV.clear(); if (response == "DIE") { orionExitFunction(0, "Received a 'DIE' request on REST interface"); } restReply(ciP, response); return response; } std::string details = std::string("service '") + ciP->url + "' not recognized"; alarmMgr.badInput(clientIp, details); ciP->httpStatusCode = SccBadRequest; std::string answer = restErrorReplyGet(ciP, "", ciP->payloadWord, SccBadRequest, std::string("unrecognized request")); restReply(ciP, answer); compV.clear(); return answer; }
void StreamServer::onMessageReceived(ControlSession* controlSession, const std::string& message) { JsonRequest request; try { request.parse(message); logO << "method: " << request.method << ", " << "id: " << request.id << "\n"; json response; ClientInfoPtr clientInfo = nullptr; msg::ServerSettings serverSettings; serverSettings.bufferMs = settings_.bufferMs; if (request.method.find("Client.Set") == 0) { clientInfo = Config::instance().getClientInfo(request.getParam("client").get<string>(), false); if (clientInfo == nullptr) throw JsonInternalErrorException("Client not found", request.id); } if (request.method == "Server.GetStatus") { json jClient = json::array(); if (request.hasParam("client")) { ClientInfoPtr client = Config::instance().getClientInfo(request.getParam("client").get<string>(), false); if (client) jClient += client->toJson(); } else jClient = Config::instance().getClientInfos(); Host host; //TODO: Set MAC and IP Snapserver snapserver("Snapserver", VERSION); response = { {"server", { {"host", host.toJson()},//getHostName()}, {"snapserver", snapserver.toJson()} }}, {"clients", jClient}, {"streams", streamManager_->toJson()} }; // cout << response.dump(4); } else if (request.method == "Server.DeleteClient") { clientInfo = Config::instance().getClientInfo(request.getParam("client").get<string>(), false); if (clientInfo == nullptr) throw JsonInternalErrorException("Client not found", request.id); response = clientInfo->host.mac; Config::instance().remove(clientInfo); Config::instance().save(); json notification = JsonNotification::getJson("Client.OnDelete", clientInfo->toJson()); controlServer_->send(notification.dump(), controlSession); clientInfo = nullptr; } else if (request.method == "Client.SetVolume") { clientInfo->config.volume.percent = request.getParam<uint16_t>("volume", 0, 100); response = clientInfo->config.volume.percent; } else if (request.method == "Client.SetMute") { clientInfo->config.volume.muted = request.getParam<bool>("mute", false, true); response = clientInfo->config.volume.muted; } else if (request.method == "Client.SetStream") { string streamId = request.getParam("id").get<string>(); PcmStreamPtr stream = streamManager_->getStream(streamId); if (stream == nullptr) throw JsonInternalErrorException("Stream not found", request.id); clientInfo->config.streamId = streamId; response = clientInfo->config.streamId; StreamSession* session = getStreamSession(request.getParam("client").get<string>()); if (session != NULL) { session->add(stream->getHeader()); session->setPcmStream(stream); } } else if (request.method == "Client.SetLatency") { clientInfo->config.latency = request.getParam<int>("latency", -10000, settings_.bufferMs); response = clientInfo->config.latency; } else if (request.method == "Client.SetName") { clientInfo->config.name = request.getParam("name").get<string>(); response = clientInfo->config.name; } else throw JsonMethodNotFoundException(request.id); if (clientInfo != nullptr) { serverSettings.volume = clientInfo->config.volume.percent; serverSettings.muted = clientInfo->config.volume.muted; serverSettings.latency = clientInfo->config.latency; StreamSession* session = getStreamSession(request.getParam("client").get<string>()); if (session != NULL) session->send(&serverSettings); Config::instance().save(); json notification = JsonNotification::getJson("Client.OnUpdate", clientInfo->toJson()); controlServer_->send(notification.dump(), controlSession); } controlSession->send(request.getResponse(response).dump()); } catch (const JsonRequestException& e) { controlSession->send(e.getResponse().dump()); } catch (const exception& e) { JsonInternalErrorException jsonException(e.what(), request.id); controlSession->send(jsonException.getResponse().dump()); } }
/* **************************************************************************** * * 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; }