res_ari_applications.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * David M. Lee, II <dlee@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*
  19. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  20. * !!!!! DO NOT EDIT !!!!!
  21. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  22. * This file is generated by a mustache template. Please see the original
  23. * template in rest-api-templates/res_ari_resource.c.mustache
  24. */
  25. /*! \file
  26. *
  27. * \brief Stasis application resources
  28. *
  29. * \author David M. Lee, II <dlee@digium.com>
  30. */
  31. /*** MODULEINFO
  32. <depend type="module">res_ari</depend>
  33. <depend type="module">res_stasis</depend>
  34. <support_level>core</support_level>
  35. ***/
  36. #include "asterisk.h"
  37. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  38. #include "asterisk/app.h"
  39. #include "asterisk/module.h"
  40. #include "asterisk/stasis_app.h"
  41. #include "ari/resource_applications.h"
  42. #if defined(AST_DEVMODE)
  43. #include "ari/ari_model_validators.h"
  44. #endif
  45. #define MAX_VALS 128
  46. /*!
  47. * \brief Parameter parsing callback for /applications.
  48. * \param get_params GET parameters in the HTTP request.
  49. * \param path_vars Path variables extracted from the request.
  50. * \param headers HTTP headers.
  51. * \param[out] response Response to the HTTP request.
  52. */
  53. static void ast_ari_applications_list_cb(
  54. struct ast_tcptls_session_instance *ser,
  55. struct ast_variable *get_params, struct ast_variable *path_vars,
  56. struct ast_variable *headers, struct ast_ari_response *response)
  57. {
  58. struct ast_ari_applications_list_args args = {};
  59. RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
  60. #if defined(AST_DEVMODE)
  61. int is_valid;
  62. int code;
  63. #endif /* AST_DEVMODE */
  64. ast_ari_applications_list(headers, &args, response);
  65. #if defined(AST_DEVMODE)
  66. code = response->response_code;
  67. switch (code) {
  68. case 0: /* Implementation is still a stub, or the code wasn't set */
  69. is_valid = response->message == NULL;
  70. break;
  71. case 500: /* Internal Server Error */
  72. case 501: /* Not Implemented */
  73. is_valid = 1;
  74. break;
  75. default:
  76. if (200 <= code && code <= 299) {
  77. is_valid = ast_ari_validate_list(response->message,
  78. ast_ari_validate_application_fn());
  79. } else {
  80. ast_log(LOG_ERROR, "Invalid error response %d for /applications\n", code);
  81. is_valid = 0;
  82. }
  83. }
  84. if (!is_valid) {
  85. ast_log(LOG_ERROR, "Response validation failed for /applications\n");
  86. ast_ari_response_error(response, 500,
  87. "Internal Server Error", "Response validation failed");
  88. }
  89. #endif /* AST_DEVMODE */
  90. fin: __attribute__((unused))
  91. return;
  92. }
  93. /*!
  94. * \brief Parameter parsing callback for /applications/{applicationName}.
  95. * \param get_params GET parameters in the HTTP request.
  96. * \param path_vars Path variables extracted from the request.
  97. * \param headers HTTP headers.
  98. * \param[out] response Response to the HTTP request.
  99. */
  100. static void ast_ari_applications_get_cb(
  101. struct ast_tcptls_session_instance *ser,
  102. struct ast_variable *get_params, struct ast_variable *path_vars,
  103. struct ast_variable *headers, struct ast_ari_response *response)
  104. {
  105. struct ast_ari_applications_get_args args = {};
  106. struct ast_variable *i;
  107. RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
  108. #if defined(AST_DEVMODE)
  109. int is_valid;
  110. int code;
  111. #endif /* AST_DEVMODE */
  112. for (i = path_vars; i; i = i->next) {
  113. if (strcmp(i->name, "applicationName") == 0) {
  114. args.application_name = (i->value);
  115. } else
  116. {}
  117. }
  118. ast_ari_applications_get(headers, &args, response);
  119. #if defined(AST_DEVMODE)
  120. code = response->response_code;
  121. switch (code) {
  122. case 0: /* Implementation is still a stub, or the code wasn't set */
  123. is_valid = response->message == NULL;
  124. break;
  125. case 500: /* Internal Server Error */
  126. case 501: /* Not Implemented */
  127. case 404: /* Application does not exist. */
  128. is_valid = 1;
  129. break;
  130. default:
  131. if (200 <= code && code <= 299) {
  132. is_valid = ast_ari_validate_application(
  133. response->message);
  134. } else {
  135. ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}\n", code);
  136. is_valid = 0;
  137. }
  138. }
  139. if (!is_valid) {
  140. ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}\n");
  141. ast_ari_response_error(response, 500,
  142. "Internal Server Error", "Response validation failed");
  143. }
  144. #endif /* AST_DEVMODE */
  145. fin: __attribute__((unused))
  146. return;
  147. }
  148. int ast_ari_applications_subscribe_parse_body(
  149. struct ast_json *body,
  150. struct ast_ari_applications_subscribe_args *args)
  151. {
  152. struct ast_json *field;
  153. /* Parse query parameters out of it */
  154. field = ast_json_object_get(body, "eventSource");
  155. if (field) {
  156. /* If they were silly enough to both pass in a query param and a
  157. * JSON body, free up the query value.
  158. */
  159. ast_free(args->event_source);
  160. if (ast_json_typeof(field) == AST_JSON_ARRAY) {
  161. /* Multiple param passed as array */
  162. size_t i;
  163. args->event_source_count = ast_json_array_size(field);
  164. args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
  165. if (!args->event_source) {
  166. return -1;
  167. }
  168. for (i = 0; i < args->event_source_count; ++i) {
  169. args->event_source[i] = ast_json_string_get(ast_json_array_get(field, i));
  170. }
  171. } else {
  172. /* Multiple param passed as single value */
  173. args->event_source_count = 1;
  174. args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
  175. if (!args->event_source) {
  176. return -1;
  177. }
  178. args->event_source[0] = ast_json_string_get(field);
  179. }
  180. }
  181. return 0;
  182. }
  183. /*!
  184. * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
  185. * \param get_params GET parameters in the HTTP request.
  186. * \param path_vars Path variables extracted from the request.
  187. * \param headers HTTP headers.
  188. * \param[out] response Response to the HTTP request.
  189. */
  190. static void ast_ari_applications_subscribe_cb(
  191. struct ast_tcptls_session_instance *ser,
  192. struct ast_variable *get_params, struct ast_variable *path_vars,
  193. struct ast_variable *headers, struct ast_ari_response *response)
  194. {
  195. struct ast_ari_applications_subscribe_args args = {};
  196. struct ast_variable *i;
  197. RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
  198. #if defined(AST_DEVMODE)
  199. int is_valid;
  200. int code;
  201. #endif /* AST_DEVMODE */
  202. for (i = get_params; i; i = i->next) {
  203. if (strcmp(i->name, "eventSource") == 0) {
  204. /* Parse comma separated list */
  205. char *vals[MAX_VALS];
  206. size_t j;
  207. args.event_source_parse = ast_strdup(i->value);
  208. if (!args.event_source_parse) {
  209. ast_ari_response_alloc_failed(response);
  210. goto fin;
  211. }
  212. if (strlen(args.event_source_parse) == 0) {
  213. /* ast_app_separate_args can't handle "" */
  214. args.event_source_count = 1;
  215. vals[0] = args.event_source_parse;
  216. } else {
  217. args.event_source_count = ast_app_separate_args(
  218. args.event_source_parse, ',', vals,
  219. ARRAY_LEN(vals));
  220. }
  221. if (args.event_source_count == 0) {
  222. ast_ari_response_alloc_failed(response);
  223. goto fin;
  224. }
  225. if (args.event_source_count >= MAX_VALS) {
  226. ast_ari_response_error(response, 400,
  227. "Bad Request",
  228. "Too many values for event_source");
  229. goto fin;
  230. }
  231. args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
  232. if (!args.event_source) {
  233. ast_ari_response_alloc_failed(response);
  234. goto fin;
  235. }
  236. for (j = 0; j < args.event_source_count; ++j) {
  237. args.event_source[j] = (vals[j]);
  238. }
  239. } else
  240. {}
  241. }
  242. for (i = path_vars; i; i = i->next) {
  243. if (strcmp(i->name, "applicationName") == 0) {
  244. args.application_name = (i->value);
  245. } else
  246. {}
  247. }
  248. /* Look for a JSON request entity */
  249. body = ast_http_get_json(ser, headers);
  250. if (!body) {
  251. switch (errno) {
  252. case EFBIG:
  253. ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
  254. goto fin;
  255. case ENOMEM:
  256. ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
  257. goto fin;
  258. case EIO:
  259. ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
  260. goto fin;
  261. }
  262. }
  263. if (ast_ari_applications_subscribe_parse_body(body, &args)) {
  264. ast_ari_response_alloc_failed(response);
  265. goto fin;
  266. }
  267. ast_ari_applications_subscribe(headers, &args, response);
  268. #if defined(AST_DEVMODE)
  269. code = response->response_code;
  270. switch (code) {
  271. case 0: /* Implementation is still a stub, or the code wasn't set */
  272. is_valid = response->message == NULL;
  273. break;
  274. case 500: /* Internal Server Error */
  275. case 501: /* Not Implemented */
  276. case 400: /* Missing parameter. */
  277. case 404: /* Application does not exist. */
  278. case 422: /* Event source does not exist. */
  279. is_valid = 1;
  280. break;
  281. default:
  282. if (200 <= code && code <= 299) {
  283. is_valid = ast_ari_validate_application(
  284. response->message);
  285. } else {
  286. ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
  287. is_valid = 0;
  288. }
  289. }
  290. if (!is_valid) {
  291. ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
  292. ast_ari_response_error(response, 500,
  293. "Internal Server Error", "Response validation failed");
  294. }
  295. #endif /* AST_DEVMODE */
  296. fin: __attribute__((unused))
  297. ast_free(args.event_source_parse);
  298. ast_free(args.event_source);
  299. return;
  300. }
  301. int ast_ari_applications_unsubscribe_parse_body(
  302. struct ast_json *body,
  303. struct ast_ari_applications_unsubscribe_args *args)
  304. {
  305. struct ast_json *field;
  306. /* Parse query parameters out of it */
  307. field = ast_json_object_get(body, "eventSource");
  308. if (field) {
  309. /* If they were silly enough to both pass in a query param and a
  310. * JSON body, free up the query value.
  311. */
  312. ast_free(args->event_source);
  313. if (ast_json_typeof(field) == AST_JSON_ARRAY) {
  314. /* Multiple param passed as array */
  315. size_t i;
  316. args->event_source_count = ast_json_array_size(field);
  317. args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
  318. if (!args->event_source) {
  319. return -1;
  320. }
  321. for (i = 0; i < args->event_source_count; ++i) {
  322. args->event_source[i] = ast_json_string_get(ast_json_array_get(field, i));
  323. }
  324. } else {
  325. /* Multiple param passed as single value */
  326. args->event_source_count = 1;
  327. args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
  328. if (!args->event_source) {
  329. return -1;
  330. }
  331. args->event_source[0] = ast_json_string_get(field);
  332. }
  333. }
  334. return 0;
  335. }
  336. /*!
  337. * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
  338. * \param get_params GET parameters in the HTTP request.
  339. * \param path_vars Path variables extracted from the request.
  340. * \param headers HTTP headers.
  341. * \param[out] response Response to the HTTP request.
  342. */
  343. static void ast_ari_applications_unsubscribe_cb(
  344. struct ast_tcptls_session_instance *ser,
  345. struct ast_variable *get_params, struct ast_variable *path_vars,
  346. struct ast_variable *headers, struct ast_ari_response *response)
  347. {
  348. struct ast_ari_applications_unsubscribe_args args = {};
  349. struct ast_variable *i;
  350. RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
  351. #if defined(AST_DEVMODE)
  352. int is_valid;
  353. int code;
  354. #endif /* AST_DEVMODE */
  355. for (i = get_params; i; i = i->next) {
  356. if (strcmp(i->name, "eventSource") == 0) {
  357. /* Parse comma separated list */
  358. char *vals[MAX_VALS];
  359. size_t j;
  360. args.event_source_parse = ast_strdup(i->value);
  361. if (!args.event_source_parse) {
  362. ast_ari_response_alloc_failed(response);
  363. goto fin;
  364. }
  365. if (strlen(args.event_source_parse) == 0) {
  366. /* ast_app_separate_args can't handle "" */
  367. args.event_source_count = 1;
  368. vals[0] = args.event_source_parse;
  369. } else {
  370. args.event_source_count = ast_app_separate_args(
  371. args.event_source_parse, ',', vals,
  372. ARRAY_LEN(vals));
  373. }
  374. if (args.event_source_count == 0) {
  375. ast_ari_response_alloc_failed(response);
  376. goto fin;
  377. }
  378. if (args.event_source_count >= MAX_VALS) {
  379. ast_ari_response_error(response, 400,
  380. "Bad Request",
  381. "Too many values for event_source");
  382. goto fin;
  383. }
  384. args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
  385. if (!args.event_source) {
  386. ast_ari_response_alloc_failed(response);
  387. goto fin;
  388. }
  389. for (j = 0; j < args.event_source_count; ++j) {
  390. args.event_source[j] = (vals[j]);
  391. }
  392. } else
  393. {}
  394. }
  395. for (i = path_vars; i; i = i->next) {
  396. if (strcmp(i->name, "applicationName") == 0) {
  397. args.application_name = (i->value);
  398. } else
  399. {}
  400. }
  401. /* Look for a JSON request entity */
  402. body = ast_http_get_json(ser, headers);
  403. if (!body) {
  404. switch (errno) {
  405. case EFBIG:
  406. ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
  407. goto fin;
  408. case ENOMEM:
  409. ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
  410. goto fin;
  411. case EIO:
  412. ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
  413. goto fin;
  414. }
  415. }
  416. if (ast_ari_applications_unsubscribe_parse_body(body, &args)) {
  417. ast_ari_response_alloc_failed(response);
  418. goto fin;
  419. }
  420. ast_ari_applications_unsubscribe(headers, &args, response);
  421. #if defined(AST_DEVMODE)
  422. code = response->response_code;
  423. switch (code) {
  424. case 0: /* Implementation is still a stub, or the code wasn't set */
  425. is_valid = response->message == NULL;
  426. break;
  427. case 500: /* Internal Server Error */
  428. case 501: /* Not Implemented */
  429. case 400: /* Missing parameter; event source scheme not recognized. */
  430. case 404: /* Application does not exist. */
  431. case 409: /* Application not subscribed to event source. */
  432. case 422: /* Event source does not exist. */
  433. is_valid = 1;
  434. break;
  435. default:
  436. if (200 <= code && code <= 299) {
  437. is_valid = ast_ari_validate_application(
  438. response->message);
  439. } else {
  440. ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
  441. is_valid = 0;
  442. }
  443. }
  444. if (!is_valid) {
  445. ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
  446. ast_ari_response_error(response, 500,
  447. "Internal Server Error", "Response validation failed");
  448. }
  449. #endif /* AST_DEVMODE */
  450. fin: __attribute__((unused))
  451. ast_free(args.event_source_parse);
  452. ast_free(args.event_source);
  453. return;
  454. }
  455. /*! \brief REST handler for /api-docs/applications.{format} */
  456. static struct stasis_rest_handlers applications_applicationName_subscription = {
  457. .path_segment = "subscription",
  458. .callbacks = {
  459. [AST_HTTP_POST] = ast_ari_applications_subscribe_cb,
  460. [AST_HTTP_DELETE] = ast_ari_applications_unsubscribe_cb,
  461. },
  462. .num_children = 0,
  463. .children = { }
  464. };
  465. /*! \brief REST handler for /api-docs/applications.{format} */
  466. static struct stasis_rest_handlers applications_applicationName = {
  467. .path_segment = "applicationName",
  468. .is_wildcard = 1,
  469. .callbacks = {
  470. [AST_HTTP_GET] = ast_ari_applications_get_cb,
  471. },
  472. .num_children = 1,
  473. .children = { &applications_applicationName_subscription, }
  474. };
  475. /*! \brief REST handler for /api-docs/applications.{format} */
  476. static struct stasis_rest_handlers applications = {
  477. .path_segment = "applications",
  478. .callbacks = {
  479. [AST_HTTP_GET] = ast_ari_applications_list_cb,
  480. },
  481. .num_children = 1,
  482. .children = { &applications_applicationName, }
  483. };
  484. static int load_module(void)
  485. {
  486. int res = 0;
  487. stasis_app_ref();
  488. res |= ast_ari_add_handler(&applications);
  489. return res;
  490. }
  491. static int unload_module(void)
  492. {
  493. ast_ari_remove_handler(&applications);
  494. stasis_app_unref();
  495. return 0;
  496. }
  497. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Stasis application resources",
  498. .support_level = AST_MODULE_SUPPORT_CORE,
  499. .load = load_module,
  500. .unload = unload_module,
  501. .nonoptreq = "res_ari,res_stasis",
  502. );