ARI: Added new functionality to load a single module.
[asterisk/asterisk.git] / res / res_ari_asterisk.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 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  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21  * !!!!!                               DO NOT EDIT                        !!!!!
22  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23  * This file is generated by a mustache template. Please see the original
24  * template in rest-api-templates/res_ari_resource.c.mustache
25  */
26
27 /*! \file
28  *
29  * \brief Asterisk resources
30  *
31  * \author David M. Lee, II <dlee@digium.com>
32  */
33
34 /*** MODULEINFO
35         <depend type="module">res_ari</depend>
36         <depend type="module">res_ari_model</depend>
37         <depend type="module">res_stasis</depend>
38         <support_level>core</support_level>
39  ***/
40
41 #include "asterisk.h"
42
43 ASTERISK_REGISTER_FILE()
44
45 #include "asterisk/app.h"
46 #include "asterisk/module.h"
47 #include "asterisk/stasis_app.h"
48 #include "ari/resource_asterisk.h"
49 #if defined(AST_DEVMODE)
50 #include "ari/ari_model_validators.h"
51 #endif
52
53 #define MAX_VALS 128
54
55 int ast_ari_asterisk_get_info_parse_body(
56         struct ast_json *body,
57         struct ast_ari_asterisk_get_info_args *args)
58 {
59         struct ast_json *field;
60         /* Parse query parameters out of it */
61         field = ast_json_object_get(body, "only");
62         if (field) {
63                 /* If they were silly enough to both pass in a query param and a
64                  * JSON body, free up the query value.
65                  */
66                 ast_free(args->only);
67                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
68                         /* Multiple param passed as array */
69                         size_t i;
70                         args->only_count = ast_json_array_size(field);
71                         args->only = ast_malloc(sizeof(*args->only) * args->only_count);
72
73                         if (!args->only) {
74                                 return -1;
75                         }
76
77                         for (i = 0; i < args->only_count; ++i) {
78                                 args->only[i] = ast_json_string_get(ast_json_array_get(field, i));
79                         }
80                 } else {
81                         /* Multiple param passed as single value */
82                         args->only_count = 1;
83                         args->only = ast_malloc(sizeof(*args->only) * args->only_count);
84                         if (!args->only) {
85                                 return -1;
86                         }
87                         args->only[0] = ast_json_string_get(field);
88                 }
89         }
90         return 0;
91 }
92
93 /*!
94  * \brief Parameter parsing callback for /asterisk/info.
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_asterisk_get_info_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_asterisk_get_info_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
113         for (i = get_params; i; i = i->next) {
114                 if (strcmp(i->name, "only") == 0) {
115                         /* Parse comma separated list */
116                         char *vals[MAX_VALS];
117                         size_t j;
118
119                         args.only_parse = ast_strdup(i->value);
120                         if (!args.only_parse) {
121                                 ast_ari_response_alloc_failed(response);
122                                 goto fin;
123                         }
124
125                         if (strlen(args.only_parse) == 0) {
126                                 /* ast_app_separate_args can't handle "" */
127                                 args.only_count = 1;
128                                 vals[0] = args.only_parse;
129                         } else {
130                                 args.only_count = ast_app_separate_args(
131                                         args.only_parse, ',', vals,
132                                         ARRAY_LEN(vals));
133                         }
134
135                         if (args.only_count == 0) {
136                                 ast_ari_response_alloc_failed(response);
137                                 goto fin;
138                         }
139
140                         if (args.only_count >= MAX_VALS) {
141                                 ast_ari_response_error(response, 400,
142                                         "Bad Request",
143                                         "Too many values for only");
144                                 goto fin;
145                         }
146
147                         args.only = ast_malloc(sizeof(*args.only) * args.only_count);
148                         if (!args.only) {
149                                 ast_ari_response_alloc_failed(response);
150                                 goto fin;
151                         }
152
153                         for (j = 0; j < args.only_count; ++j) {
154                                 args.only[j] = (vals[j]);
155                         }
156                 } else
157                 {}
158         }
159         /* Look for a JSON request entity */
160         body = ast_http_get_json(ser, headers);
161         if (!body) {
162                 switch (errno) {
163                 case EFBIG:
164                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
165                         goto fin;
166                 case ENOMEM:
167                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
168                         goto fin;
169                 case EIO:
170                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
171                         goto fin;
172                 }
173         }
174         if (ast_ari_asterisk_get_info_parse_body(body, &args)) {
175                 ast_ari_response_alloc_failed(response);
176                 goto fin;
177         }
178         ast_ari_asterisk_get_info(headers, &args, response);
179 #if defined(AST_DEVMODE)
180         code = response->response_code;
181
182         switch (code) {
183         case 0: /* Implementation is still a stub, or the code wasn't set */
184                 is_valid = response->message == NULL;
185                 break;
186         case 500: /* Internal Server Error */
187         case 501: /* Not Implemented */
188                 is_valid = 1;
189                 break;
190         default:
191                 if (200 <= code && code <= 299) {
192                         is_valid = ast_ari_validate_asterisk_info(
193                                 response->message);
194                 } else {
195                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/info\n", code);
196                         is_valid = 0;
197                 }
198         }
199
200         if (!is_valid) {
201                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/info\n");
202                 ast_ari_response_error(response, 500,
203                         "Internal Server Error", "Response validation failed");
204         }
205 #endif /* AST_DEVMODE */
206
207 fin: __attribute__((unused))
208         ast_free(args.only_parse);
209         ast_free(args.only);
210         return;
211 }
212 /*!
213  * \brief Parameter parsing callback for /asterisk/modules.
214  * \param get_params GET parameters in the HTTP request.
215  * \param path_vars Path variables extracted from the request.
216  * \param headers HTTP headers.
217  * \param[out] response Response to the HTTP request.
218  */
219 static void ast_ari_asterisk_list_modules_cb(
220         struct ast_tcptls_session_instance *ser,
221         struct ast_variable *get_params, struct ast_variable *path_vars,
222         struct ast_variable *headers, struct ast_ari_response *response)
223 {
224         struct ast_ari_asterisk_list_modules_args args = {};
225         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
226 #if defined(AST_DEVMODE)
227         int is_valid;
228         int code;
229 #endif /* AST_DEVMODE */
230
231         ast_ari_asterisk_list_modules(headers, &args, response);
232 #if defined(AST_DEVMODE)
233         code = response->response_code;
234
235         switch (code) {
236         case 0: /* Implementation is still a stub, or the code wasn't set */
237                 is_valid = response->message == NULL;
238                 break;
239         case 500: /* Internal Server Error */
240         case 501: /* Not Implemented */
241                 is_valid = 1;
242                 break;
243         default:
244                 if (200 <= code && code <= 299) {
245                         is_valid = ast_ari_validate_list(response->message,
246                                 ast_ari_validate_module_fn());
247                 } else {
248                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules\n", code);
249                         is_valid = 0;
250                 }
251         }
252
253         if (!is_valid) {
254                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules\n");
255                 ast_ari_response_error(response, 500,
256                         "Internal Server Error", "Response validation failed");
257         }
258 #endif /* AST_DEVMODE */
259
260 fin: __attribute__((unused))
261         return;
262 }
263 /*!
264  * \brief Parameter parsing callback for /asterisk/modules/{moduleName}.
265  * \param get_params GET parameters in the HTTP request.
266  * \param path_vars Path variables extracted from the request.
267  * \param headers HTTP headers.
268  * \param[out] response Response to the HTTP request.
269  */
270 static void ast_ari_asterisk_get_module_cb(
271         struct ast_tcptls_session_instance *ser,
272         struct ast_variable *get_params, struct ast_variable *path_vars,
273         struct ast_variable *headers, struct ast_ari_response *response)
274 {
275         struct ast_ari_asterisk_get_module_args args = {};
276         struct ast_variable *i;
277         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
278 #if defined(AST_DEVMODE)
279         int is_valid;
280         int code;
281 #endif /* AST_DEVMODE */
282
283         for (i = path_vars; i; i = i->next) {
284                 if (strcmp(i->name, "moduleName") == 0) {
285                         args.module_name = (i->value);
286                 } else
287                 {}
288         }
289         ast_ari_asterisk_get_module(headers, &args, response);
290 #if defined(AST_DEVMODE)
291         code = response->response_code;
292
293         switch (code) {
294         case 0: /* Implementation is still a stub, or the code wasn't set */
295                 is_valid = response->message == NULL;
296                 break;
297         case 500: /* Internal Server Error */
298         case 501: /* Not Implemented */
299         case 404: /* Module could not be found in running modules. */
300         case 409: /* Module information could not be retrieved. */
301                 is_valid = 1;
302                 break;
303         default:
304                 if (200 <= code && code <= 299) {
305                         is_valid = ast_ari_validate_module(
306                                 response->message);
307                 } else {
308                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code);
309                         is_valid = 0;
310                 }
311         }
312
313         if (!is_valid) {
314                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n");
315                 ast_ari_response_error(response, 500,
316                         "Internal Server Error", "Response validation failed");
317         }
318 #endif /* AST_DEVMODE */
319
320 fin: __attribute__((unused))
321         return;
322 }
323 /*!
324  * \brief Parameter parsing callback for /asterisk/modules/{moduleName}.
325  * \param get_params GET parameters in the HTTP request.
326  * \param path_vars Path variables extracted from the request.
327  * \param headers HTTP headers.
328  * \param[out] response Response to the HTTP request.
329  */
330 static void ast_ari_asterisk_load_module_cb(
331         struct ast_tcptls_session_instance *ser,
332         struct ast_variable *get_params, struct ast_variable *path_vars,
333         struct ast_variable *headers, struct ast_ari_response *response)
334 {
335         struct ast_ari_asterisk_load_module_args args = {};
336         struct ast_variable *i;
337         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
338 #if defined(AST_DEVMODE)
339         int is_valid;
340         int code;
341 #endif /* AST_DEVMODE */
342
343         for (i = path_vars; i; i = i->next) {
344                 if (strcmp(i->name, "moduleName") == 0) {
345                         args.module_name = (i->value);
346                 } else
347                 {}
348         }
349         ast_ari_asterisk_load_module(headers, &args, response);
350 #if defined(AST_DEVMODE)
351         code = response->response_code;
352
353         switch (code) {
354         case 0: /* Implementation is still a stub, or the code wasn't set */
355                 is_valid = response->message == NULL;
356                 break;
357         case 500: /* Internal Server Error */
358         case 501: /* Not Implemented */
359         case 409: /* Module could not be loaded. */
360                 is_valid = 1;
361                 break;
362         default:
363                 if (200 <= code && code <= 299) {
364                         is_valid = ast_ari_validate_void(
365                                 response->message);
366                 } else {
367                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code);
368                         is_valid = 0;
369                 }
370         }
371
372         if (!is_valid) {
373                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n");
374                 ast_ari_response_error(response, 500,
375                         "Internal Server Error", "Response validation failed");
376         }
377 #endif /* AST_DEVMODE */
378
379 fin: __attribute__((unused))
380         return;
381 }
382 int ast_ari_asterisk_get_global_var_parse_body(
383         struct ast_json *body,
384         struct ast_ari_asterisk_get_global_var_args *args)
385 {
386         struct ast_json *field;
387         /* Parse query parameters out of it */
388         field = ast_json_object_get(body, "variable");
389         if (field) {
390                 args->variable = ast_json_string_get(field);
391         }
392         return 0;
393 }
394
395 /*!
396  * \brief Parameter parsing callback for /asterisk/variable.
397  * \param get_params GET parameters in the HTTP request.
398  * \param path_vars Path variables extracted from the request.
399  * \param headers HTTP headers.
400  * \param[out] response Response to the HTTP request.
401  */
402 static void ast_ari_asterisk_get_global_var_cb(
403         struct ast_tcptls_session_instance *ser,
404         struct ast_variable *get_params, struct ast_variable *path_vars,
405         struct ast_variable *headers, struct ast_ari_response *response)
406 {
407         struct ast_ari_asterisk_get_global_var_args args = {};
408         struct ast_variable *i;
409         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
410 #if defined(AST_DEVMODE)
411         int is_valid;
412         int code;
413 #endif /* AST_DEVMODE */
414
415         for (i = get_params; i; i = i->next) {
416                 if (strcmp(i->name, "variable") == 0) {
417                         args.variable = (i->value);
418                 } else
419                 {}
420         }
421         /* Look for a JSON request entity */
422         body = ast_http_get_json(ser, headers);
423         if (!body) {
424                 switch (errno) {
425                 case EFBIG:
426                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
427                         goto fin;
428                 case ENOMEM:
429                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
430                         goto fin;
431                 case EIO:
432                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
433                         goto fin;
434                 }
435         }
436         if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
437                 ast_ari_response_alloc_failed(response);
438                 goto fin;
439         }
440         ast_ari_asterisk_get_global_var(headers, &args, response);
441 #if defined(AST_DEVMODE)
442         code = response->response_code;
443
444         switch (code) {
445         case 0: /* Implementation is still a stub, or the code wasn't set */
446                 is_valid = response->message == NULL;
447                 break;
448         case 500: /* Internal Server Error */
449         case 501: /* Not Implemented */
450         case 400: /* Missing variable parameter. */
451                 is_valid = 1;
452                 break;
453         default:
454                 if (200 <= code && code <= 299) {
455                         is_valid = ast_ari_validate_variable(
456                                 response->message);
457                 } else {
458                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
459                         is_valid = 0;
460                 }
461         }
462
463         if (!is_valid) {
464                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
465                 ast_ari_response_error(response, 500,
466                         "Internal Server Error", "Response validation failed");
467         }
468 #endif /* AST_DEVMODE */
469
470 fin: __attribute__((unused))
471         return;
472 }
473 int ast_ari_asterisk_set_global_var_parse_body(
474         struct ast_json *body,
475         struct ast_ari_asterisk_set_global_var_args *args)
476 {
477         struct ast_json *field;
478         /* Parse query parameters out of it */
479         field = ast_json_object_get(body, "variable");
480         if (field) {
481                 args->variable = ast_json_string_get(field);
482         }
483         field = ast_json_object_get(body, "value");
484         if (field) {
485                 args->value = ast_json_string_get(field);
486         }
487         return 0;
488 }
489
490 /*!
491  * \brief Parameter parsing callback for /asterisk/variable.
492  * \param get_params GET parameters in the HTTP request.
493  * \param path_vars Path variables extracted from the request.
494  * \param headers HTTP headers.
495  * \param[out] response Response to the HTTP request.
496  */
497 static void ast_ari_asterisk_set_global_var_cb(
498         struct ast_tcptls_session_instance *ser,
499         struct ast_variable *get_params, struct ast_variable *path_vars,
500         struct ast_variable *headers, struct ast_ari_response *response)
501 {
502         struct ast_ari_asterisk_set_global_var_args args = {};
503         struct ast_variable *i;
504         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
505 #if defined(AST_DEVMODE)
506         int is_valid;
507         int code;
508 #endif /* AST_DEVMODE */
509
510         for (i = get_params; i; i = i->next) {
511                 if (strcmp(i->name, "variable") == 0) {
512                         args.variable = (i->value);
513                 } else
514                 if (strcmp(i->name, "value") == 0) {
515                         args.value = (i->value);
516                 } else
517                 {}
518         }
519         /* Look for a JSON request entity */
520         body = ast_http_get_json(ser, headers);
521         if (!body) {
522                 switch (errno) {
523                 case EFBIG:
524                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
525                         goto fin;
526                 case ENOMEM:
527                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
528                         goto fin;
529                 case EIO:
530                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
531                         goto fin;
532                 }
533         }
534         if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
535                 ast_ari_response_alloc_failed(response);
536                 goto fin;
537         }
538         ast_ari_asterisk_set_global_var(headers, &args, response);
539 #if defined(AST_DEVMODE)
540         code = response->response_code;
541
542         switch (code) {
543         case 0: /* Implementation is still a stub, or the code wasn't set */
544                 is_valid = response->message == NULL;
545                 break;
546         case 500: /* Internal Server Error */
547         case 501: /* Not Implemented */
548         case 400: /* Missing variable parameter. */
549                 is_valid = 1;
550                 break;
551         default:
552                 if (200 <= code && code <= 299) {
553                         is_valid = ast_ari_validate_void(
554                                 response->message);
555                 } else {
556                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
557                         is_valid = 0;
558                 }
559         }
560
561         if (!is_valid) {
562                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
563                 ast_ari_response_error(response, 500,
564                         "Internal Server Error", "Response validation failed");
565         }
566 #endif /* AST_DEVMODE */
567
568 fin: __attribute__((unused))
569         return;
570 }
571
572 /*! \brief REST handler for /api-docs/asterisk.{format} */
573 static struct stasis_rest_handlers asterisk_info = {
574         .path_segment = "info",
575         .callbacks = {
576                 [AST_HTTP_GET] = ast_ari_asterisk_get_info_cb,
577         },
578         .num_children = 0,
579         .children = {  }
580 };
581 /*! \brief REST handler for /api-docs/asterisk.{format} */
582 static struct stasis_rest_handlers asterisk_modules_moduleName = {
583         .path_segment = "moduleName",
584         .is_wildcard = 1,
585         .callbacks = {
586                 [AST_HTTP_GET] = ast_ari_asterisk_get_module_cb,
587                 [AST_HTTP_POST] = ast_ari_asterisk_load_module_cb,
588         },
589         .num_children = 0,
590         .children = {  }
591 };
592 /*! \brief REST handler for /api-docs/asterisk.{format} */
593 static struct stasis_rest_handlers asterisk_modules = {
594         .path_segment = "modules",
595         .callbacks = {
596                 [AST_HTTP_GET] = ast_ari_asterisk_list_modules_cb,
597         },
598         .num_children = 1,
599         .children = { &asterisk_modules_moduleName, }
600 };
601 /*! \brief REST handler for /api-docs/asterisk.{format} */
602 static struct stasis_rest_handlers asterisk_variable = {
603         .path_segment = "variable",
604         .callbacks = {
605                 [AST_HTTP_GET] = ast_ari_asterisk_get_global_var_cb,
606                 [AST_HTTP_POST] = ast_ari_asterisk_set_global_var_cb,
607         },
608         .num_children = 0,
609         .children = {  }
610 };
611 /*! \brief REST handler for /api-docs/asterisk.{format} */
612 static struct stasis_rest_handlers asterisk = {
613         .path_segment = "asterisk",
614         .callbacks = {
615         },
616         .num_children = 3,
617         .children = { &asterisk_info,&asterisk_modules,&asterisk_variable, }
618 };
619
620 static int load_module(void)
621 {
622         int res = 0;
623         stasis_app_ref();
624         res |= ast_ari_add_handler(&asterisk);
625         return res;
626 }
627
628 static int unload_module(void)
629 {
630         ast_ari_remove_handler(&asterisk);
631         stasis_app_unref();
632         return 0;
633 }
634
635 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Asterisk resources",
636         .support_level = AST_MODULE_SUPPORT_CORE,
637         .load = load_module,
638         .unload = unload_module,
639         .nonoptreq = "res_ari,res_stasis",
640 );