1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
16 #include <anna/http/Request.hpp>
17 #include <anna/core/functions.hpp>
20 #include <MyHandler.hpp>
21 #include <Launcher.hpp>
22 #include <EventOperation.hpp>
24 void MyHandler::splitURI(const std::string &uri, std::string & operation, std::string & param1, std::string & param2) const {
26 std::string::size_type slash_pos = uri.find("/", 1u);
27 if (slash_pos == std::string::npos) {
28 operation = uri.substr(0);
31 operation = uri.substr(0, slash_pos);
32 param1 = uri.substr(slash_pos + 1);
34 std::string::size_type slash2_pos = uri.find("/", slash_pos + 1);
35 if (slash2_pos != std::string::npos) {
36 param1 = uri.substr(slash_pos + 1, slash2_pos - slash_pos - 1);
37 param2 = uri.substr(slash2_pos + 1);
42 void MyHandler::sendResponse(anna::comm::ClientSocket& clientSocket, anna::http::Response *response)
45 clientSocket.send(*response);
46 } catch(Exception& ex) {
51 void MyHandler::evRequest(anna::comm::ClientSocket& clientSocket, const anna::http::Request& request)
52 throw(anna::RuntimeException) {
54 const anna::DataBlock& body = request.getBody();
55 anna::http::Method::Type::_v method = request.getMethod();
56 std::string uri = request.getURI();
57 bool isGET = (method == anna::http::Method::Type::Get);
58 bool isPOST = (method == anna::http::Method::Type::Post);
59 std::string body_content;
60 nlohmann::json json_body;
63 anna::http::Response* response = allocateResponse();
64 response->setStatusCode(200);
67 if(body.getSize() != 0)
68 response->setStatusCode(400); // bad request
71 if(body.getSize() != 0) {
72 body_content.assign(body.getData(), body.getSize()); // assign body content:
75 json_body = nlohmann::json::parse(body_content);
77 std::string msg("Json body received:\n\n");
78 msg += json_body.dump(4); // pretty print json body
79 anna::Logger::information(msg, ANNA_FILE_LOCATION);
82 catch (nlohmann::json::parse_error& e)
84 ss << "Json body parse error: " << e.what() << '\n'
85 << "exception id: " << e.id << '\n'
86 << "byte position of error: " << e.byte << std::endl;
87 anna::Logger::error(ss.str(), ANNA_FILE_LOCATION);
92 response->setStatusCode(405); // method not allowed
95 //////////////////////
96 // Prepare response //
97 //////////////////////
100 http::Header* contentType =response->find(http::Header::Type::ContentType);
101 if(contentType == NULL)
102 contentType = response->createHeader(http::Header::Type::ContentType);
103 contentType->setValue("application/json");
106 std::string response_content = "Internal error (check ADML traces): ";
107 bool success = false;
109 success = doGET(uri, response_content);
113 success = doPOST(uri, json_body, response_content);
115 catch(anna::RuntimeException &ex) {
117 LOGINFORMATION(anna::Logger::information("doPOST exception: TODO control in inner method. Check traces", ANNA_FILE_LOCATION));
121 ss << R"({ "success":")" << (success ? "true":"false")
122 << R"(", "response": )" << std::quoted(response_content);
125 anna::DataBlock db_content(true);
126 db_content = ss.str();
127 response->setBody(db_content);
129 sendResponse(clientSocket, response);
132 bool MyHandler::doGET(const std::string &uri, std::string &response) {
136 EventOperation eop(true /* is HTTP */);
139 if (uri == "/show-oam") {
140 result = eop.show_oam(response);
142 else if (uri == "/show-stats") {
143 result = eop.show_stats(response);
149 bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::string &response) {
153 EventOperation eop(true /* is HTTP */);
155 std::string opType{}, param1{}, param2{};
156 splitURI(uri, opType, param1, param2);
159 if (opType == "/node") {
160 auto it = j.find("name");
161 if (it != j.end() && it->is_string())
162 result = eop.node(response, *it);
164 response += "missing 'name' string field";
166 else if (opType == "/node-auto") {
167 result = eop.node_auto(response);
170 // Parsing operations
171 else if (opType == "/code") {
172 auto it = j.find("diameterJson");
173 if (it != j.end() && it->is_object())
174 result = eop.code(response, it->dump(4)); // get the object as string (always indentation = 4)
176 response += "missing 'diameterJson' object field";
178 else if (opType == "/decode") {
179 auto it = j.find("diameterHex");
180 if (it != j.end() && it->is_string())
181 result = eop.decode(response, *it);
183 response += "missing 'diameterHex' string field";
185 else if (opType == "/loadmsg") {
186 auto it = j.find("diameterJson");
187 if (it != j.end() && it->is_object())
188 result = eop.loadmsg(response, it->dump(4)); // get the object as string (always indentation = 4)
190 response += "missing 'diameterJson' object field";
194 else if (opType == "/services") {
195 auto it = j.find("servicesJson");
196 if (it != j.end() && it->is_object()) {
197 result = eop.services(response, it->dump(4)); // get the object as string (always indentation = 4)
200 response += "missing 'servicesJson' object field";
202 else if (opType == "/diameterServerSessions") {
203 auto it = j.find("sessions");
204 if (it != j.end() && it->is_number_integer())
205 result = eop.diameterServerSessions(response, it->get<int>());
207 response += "missing 'session' integer field";
209 else if (opType == "/change-dir") {
210 auto it = j.find("directory");
211 std::string directory = (it != j.end() && it->is_string()) ? *it : ""; // default is: restore initial directory
212 result = eop.change_dir(response, directory);
215 // Client sessions visibility
216 else if (opType == "/visibility") {
217 auto it = j.find("action");
218 if (it != j.end() && it->is_string()) {
219 std::string action = *it;
221 it = j.find("addressPort");
222 std::string addressPort = (it != j.end() && it->is_string()) ? *it : "";
224 it = j.find("socket");
225 int socket = (it != j.end() && it->is_number_integer()) ? it->get<int>() : -1;
227 result = eop.visibility(response, action, addressPort, socket);
230 response += "missing 'action' string field";
234 else if (opType == "/collect") {
235 result = eop.collect(response);
237 else if (opType == "/context") {
238 auto it = j.find("targetFile");
239 std::string targetFile = (it != j.end() && it->is_string()) ? *it : "";
240 result = eop.context(response, targetFile);
242 else if (opType == "/forceCountersRecord") {
243 result = eop.forceCountersRecord(response);
245 else if (opType == "/log-statistics-samples") {
246 auto it = j.find("list");
247 std::string list = (it != j.end() && it->is_string()) ? *it : "list";
248 result = eop.log_statistics_samples(response, list);
252 else if ((opType == "/sendmsg2e")||(opType == "/sendmsg2c")) {
253 auto itJ = j.find("diameterJson");
254 if (itJ != j.end() && itJ->is_object()) {
255 if (opType == "/sendmsg2e")
256 result = eop.sendmsg_hex_2e(response, itJ->dump(4), true); // get the object as string (always indentation = 4)
258 result = eop.sendmsg_hex_2c(response, itJ->dump(4), true); // get the object as string (always indentation = 4)
261 response += "missing 'diameterJson' object field";
263 else if ((opType == "/sendhex2e")||(opType == "/sendhex2c")) {
264 auto itH = j.find("diameterHex");
265 if (itH != j.end() && itH->is_string())
266 if (opType == "/sendhex2e")
267 result = eop.sendmsg_hex_2e(response, *itH, false);
269 result = eop.sendmsg_hex_2c(response, *itH, false);
271 response += "missing 'diameterHex' string field";
273 else if ((opType == "/answermsg2e")||(opType == "/answermsg2c")) {
274 auto itJ = j.find("diameterJson");
275 auto itA = j.find("action");
276 bool hasJ = (itJ != j.end() && itJ->is_object());
277 bool hasA = (itA != j.end() && itA->is_string());
279 if (hasJ != hasA) { // XOR
283 if (action == "") action = "list"; // default if missing
286 if (opType == "/answermsg2e")
287 result = eop.answermsg_action_2e(response, (hasJ ? itJ->dump(4) : action), hasJ); // itJ: get the object as string (always indentation = 4)
289 result = eop.answermsg_action_2c(response, (hasJ ? itJ->dump(4) : action), hasJ); // itJ: get the object as string (always indentation = 4)
292 response += "missing 'diameterJson' object or 'action' string field (only one accepted)";
296 // test_id__<command>
297 else if (opType == "/testid-description") {
298 auto it = j.find("description");
299 if (it != j.end() && it->is_string())
300 result = eop.test_id__description(response, atoi(param1.c_str()), *it);
302 response += "missing 'description' string field";
304 else if (opType == "/testid-ip-limit") {
305 auto it = j.find("amount");
306 int amount = (it != j.end() && it->is_number_integer()) ? it->get<int>() : 1;
307 result = eop.test_id__ip_limit(response, atoi(param1.c_str()), amount);
309 else if (opType == "/testid-timeout") {
310 auto it = j.find("msecs");
311 if (it != j.end() && it->is_number_integer())
312 result = eop.test_id__timeout(response, atoi(param1.c_str()), it->get<int>());
314 response += "missing 'msecs' integer field";
316 else if ((opType == "/testid-sendmsg2e")||(opType == "/testid-sendmsg2c")) {
317 auto it = j.find("diameterJson");
318 if (it != j.end() && it->is_object()) {
320 auto itS = j.find("stepNumber");
321 int stepNumber = (itS != j.end() && itS->is_number_integer()) ? itS->get<int>() : -1;
323 result = eop.test_id__sendmsg2e_2c(response, atoi(param1.c_str()),
324 (opType == "/testid-sendmsg2e"), it->dump(4), stepNumber); // get the object as string (always indentation = 4)
327 response += "missing 'diameterJson' object field";
329 else if (opType == "/testid-delay") {
330 auto it = j.find("msecs");
331 if (it != j.end() && it->is_number_integer())
332 result = eop.test_id__delay(response, atoi(param1.c_str()), it->get<int>());
334 response += "missing 'msecs' integer field";
336 else if (opType == "/testid-sh-command") {
337 auto it = j.find("script");
338 if (it != j.end() && it->is_string())
339 result = eop.test_id__sh_command(response, atoi(param1.c_str()), *it);
341 response += "missing 'script' string field";
343 else if ((opType == "/testid-waitfe-hex")||(opType == "/testid-waitfc-hex")) {
344 auto it = j.find("hex");
345 if (it != j.end() && it->is_string()) {
347 auto itS = j.find("strict");
348 bool strict = (itS != j.end() && itS->is_string()) ? (*itS == "true") : false;
350 result = eop.test_id__waitfefc_hex(response, atoi(param1.c_str()), (opType == "/testid-waitfe-hex"), *it, strict);
353 response += "missing 'hex' string field";
355 else if ((opType == "/testid-waitfe-msg")||(opType == "/testid-waitfc-msg")) {
356 auto it = j.find("diameterJson");
357 if (it != j.end() && it->is_object()) {
359 auto itS = j.find("strict");
360 bool strict = (itS != j.end() && itS->is_string()) ? (*itS == "true") : false;
362 result = eop.test_id__waitfefc_msg(response, atoi(param1.c_str()), (opType == "/testid-waitfe-msg"), it->dump(4), strict); // get the object as string (always indentation = 4)
365 response += "missing 'diameterJson' object field";
367 else if ((opType == "/testid-waitfe")||(opType == "/testid-waitfc")) {
368 auto it = j.find("condition");
369 if (it != j.end() && it->is_object()) {
372 auto j2 = it->get<nlohmann::json::object_t>();
374 // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
375 auto it_code = j2.find("code");
376 auto it_bitR = j2.find("bitR");
377 auto it_hopByHop = j2.find("hopByHop");
378 auto it_applicationId = j2.find("applicationId");
379 auto it_sessionId = j2.find("sessionId");
380 auto it_resultCode = j2.find("resultCode");
381 auto it_msisdn = j2.find("msisdn");
382 auto it_imsi = j2.find("imsi");
383 auto it_serviceContextId = j2.find("serviceContextId");
385 std::string p1 = (it_code != j2.end() && it_code->is_string()) ? *it_code : "";
386 std::string p2 = (it_bitR != j2.end() && it_bitR->is_string()) ? *it_bitR : "";
387 std::string p3 = (it_hopByHop != it->end() && it_hopByHop->is_string()) ? *it_hopByHop : "";
388 std::string p4 = (it_applicationId != it->end() && it_applicationId->is_string()) ? *it_applicationId : "";
389 std::string p5 = (it_sessionId != it->end() && it_sessionId->is_string()) ? *it_sessionId : "";
390 std::string p6 = (it_resultCode != it->end() && it_resultCode->is_string()) ? *it_resultCode : "";
391 std::string p7 = (it_msisdn != it->end() && it_msisdn->is_string()) ? *it_msisdn : "";
392 std::string p8 = (it_imsi != it->end() && it_imsi->is_string()) ? *it_imsi : "";
393 std::string p9 = (it_serviceContextId != it->end() && it_serviceContextId->is_string()) ? *it_serviceContextId : "";
396 // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
397 auto it_code = it->find("code");
398 auto it_bitR = it->find("bitR");
399 auto it_hopByHop = it->find("hopByHop");
400 auto it_applicationId = it->find("applicationId");
401 auto it_sessionId = it->find("sessionId");
402 auto it_resultCode = it->find("resultCode");
403 auto it_msisdn = it->find("msisdn");
404 auto it_imsi = it->find("imsi");
405 auto it_serviceContextId = it->find("serviceContextId");
407 std::string p1 = (it_code != it->end() && it_code->is_string()) ? *it_code : "";
408 std::string p2 = (it_bitR != it->end() && it_bitR->is_string()) ? *it_bitR : "";
409 std::string p3 = (it_hopByHop != it->end() && it_hopByHop->is_string()) ? *it_hopByHop : "";
410 std::string p4 = (it_applicationId != it->end() && it_applicationId->is_string()) ? *it_applicationId : "";
411 std::string p5 = (it_sessionId != it->end() && it_sessionId->is_string()) ? *it_sessionId : "";
412 std::string p6 = (it_resultCode != it->end() && it_resultCode->is_string()) ? *it_resultCode : "";
413 std::string p7 = (it_msisdn != it->end() && it_msisdn->is_string()) ? *it_msisdn : "";
414 std::string p8 = (it_imsi != it->end() && it_imsi->is_string()) ? *it_imsi : "";
415 std::string p9 = (it_serviceContextId != it->end() && it_serviceContextId->is_string()) ? *it_serviceContextId : "";
417 result = eop.test_id__waitfefc(response, atoi(param1.c_str()), (opType == "/testid-waitfe"), p1, p2, p3, p4, p5, p6, p7, p8, p9);
420 response += "missing 'condition' object field";
423 // Testcases execution
425 else if (opType == "/test-ttps") {
426 auto it = j.find("amount");
427 if (it != j.end() && it->is_number_integer())
428 result = eop.test__ttps(response, it->get<int>());
430 response += "missing 'amount' integer field";
432 else if (opType == "/test-next") {
433 auto it = j.find("syncAmount");
434 int syncAmount = (it != j.end() && it->is_number_integer()) ? it->get<int>() : 1;
435 result = eop.test__next(response, syncAmount);
437 else if (opType == "/test-ip-limit") {
438 auto it = j.find("amount");
439 int amount = (it != j.end() && it->is_number_integer()) ? it->get<int>() : -2; // default is: show current ip-limit and in-progress test cases amount
440 result = eop.test__ip_limit(response, amount);
442 else if (opType == "/test-goto") {
443 auto it = j.find("id");
444 if (it != j.end() && it->is_number_integer())
445 result = eop.test__goto(response, it->get<int>());
447 response += "missing 'id' integer field";
449 else if (opType == "/test-run") {
450 auto it = j.find("id");
451 if (it != j.end() && it->is_number_integer())
452 result = eop.test__run(response, it->get<int>());
454 response += "missing 'id' integer field";
456 else if (opType == "/test-look") {
457 auto it = j.find("id");
458 int id = (it != j.end() && it->is_number_integer()) ? it->get<int>() : -1; // default is: current
459 result = eop.test__look(response, id);
461 else if (opType == "/test-state") {
462 auto it = j.find("id");
463 int id = (it != j.end() && it->is_number_integer()) ? it->get<int>() : -1; // default is: current
464 result = eop.test__state(response, id);
466 else if (opType == "/test-interact") {
467 auto it = j.find("amount");
468 if (it != j.end() && it->is_number_integer()) {
470 auto itI = j.find("id");
471 int id = (itI != j.end() && itI->is_number_integer()) ? itI->get<int>() : -1; // default is: current
473 result = eop.test__interact(response, it->get<int>(), id);
476 response += "missing 'amount' integer field";
478 else if (opType == "/test-reset") {
479 auto it = j.find("type");
480 if (it != j.end() && it->is_string()) {
482 auto itI = j.find("id");
483 int id = (itI != j.end() && itI->is_number_integer()) ? itI->get<int>() : -2; // default is: apply to all the tests
485 if ((*it == "soft") || (*it == "hard")) {
486 result = eop.test__reset(response, (*it == "soft"), id);
489 response += "invalid 'type' string field (allowed: soft|hard)";
492 response += "missing 'type' string field";
494 else if (opType == "/test-repeats") {
495 auto it = j.find("amount");
496 if (it != j.end() && it->is_number_integer())
497 result = eop.test__repeats(response, it->get<int>());
499 response += "missing 'amount' integer field";
501 else if (opType == "/test-auto-reset") {
502 auto it = j.find("type");
503 if (it != j.end() && it->is_string()) {
505 if ((*it == "soft") || (*it == "hard")) {
506 result = eop.test__auto_reset(response, (*it == "soft"));
509 response += "invalid 'type' string field (allowed: soft|hard)";
512 response += "missing 'type' string field";
514 else if (opType == "/test-initialized") {
515 result = eop.test__initialized(response);
517 else if (opType == "/test-finished") {
518 result = eop.test__finished(response);
520 else if (opType == "/test-clear") {
521 result = eop.test__clear(response);
523 else if (opType == "/test-junit") {
524 auto it = j.find("targetFile");
525 if (it != j.end() && it->is_string())
526 result = eop.test__junit(response, *it);
528 response += "missing 'targetFile' string field";
530 else if (opType == "/test-summary-counts") {
531 result = eop.test__summary_counts(response);
533 else if (opType == "/test-summary-states") {
534 result = eop.test__summary_states(response);
536 else if (opType == "/test-summary") {
537 result = eop.test__summary(response);
539 else if (opType == "/test-report") {
540 auto it = j.find("state");
541 std::string state = (it != j.end() && it->is_string()) ? *it : "all"; // initialized|in-progress|failed|success|[all]|none
543 auto itA = j.find("action");
544 std::string action = (itA != j.end() && itA->is_string()) ? *itA : "enable"; // default is: enable
546 if ((action == "enable") || (action == "disable")) {
547 result = eop.test__report(response, state, (action == "enable"));
550 response += "invalid 'action' string field (allowed: enable|disable)";
552 else if ((opType == "/test-report-hex")||(opType == "/test-dump_stdout")) {
554 auto itA = j.find("action");
555 std::string action = (itA != j.end() && itA->is_string()) ? *itA : "enable"; // default is: enable
557 if ((action == "enable") || (action == "disable")) {
558 bool enable = (action == "enable");
560 if (opType == "/test-report-hex")
561 result = eop.test__report_hex(response, enable);
563 result = eop.test__dump_stdout(response, enable);
566 response += "invalid 'action' string field (allowed: enable|disable)";