214bb2fea19f4e2b6ebbc95e4111abf58fc55297
[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 int ast_ari_asterisk_get_global_var_parse_body(
324         struct ast_json *body,
325         struct ast_ari_asterisk_get_global_var_args *args)
326 {
327         struct ast_json *field;
328         /* Parse query parameters out of it */
329         field = ast_json_object_get(body, "variable");
330         if (field) {
331                 args->variable = ast_json_string_get(field);
332         }
333         return 0;
334 }
335
336 /*!
337  * \brief Parameter parsing callback for /asterisk/variable.
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_asterisk_get_global_var_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_asterisk_get_global_var_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
356         for (i = get_params; i; i = i->next) {
357                 if (strcmp(i->name, "variable") == 0) {
358                         args.variable = (i->value);
359                 } else
360                 {}
361         }
362         /* Look for a JSON request entity */
363         body = ast_http_get_json(ser, headers);
364         if (!body) {
365                 switch (errno) {
366                 case EFBIG:
367                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
368                         goto fin;
369                 case ENOMEM:
370                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
371                         goto fin;
372                 case EIO:
373                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
374                         goto fin;
375                 }
376         }
377         if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
378                 ast_ari_response_alloc_failed(response);
379                 goto fin;
380         }
381         ast_ari_asterisk_get_global_var(headers, &args, response);
382 #if defined(AST_DEVMODE)
383         code = response->response_code;
384
385         switch (code) {
386         case 0: /* Implementation is still a stub, or the code wasn't set */
387                 is_valid = response->message == NULL;
388                 break;
389         case 500: /* Internal Server Error */
390         case 501: /* Not Implemented */
391         case 400: /* Missing variable parameter. */
392                 is_valid = 1;
393                 break;
394         default:
395                 if (200 <= code && code <= 299) {
396                         is_valid = ast_ari_validate_variable(
397                                 response->message);
398                 } else {
399                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
400                         is_valid = 0;
401                 }
402         }
403
404         if (!is_valid) {
405                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
406                 ast_ari_response_error(response, 500,
407                         "Internal Server Error", "Response validation failed");
408         }
409 #endif /* AST_DEVMODE */
410
411 fin: __attribute__((unused))
412         return;
413 }
414 int ast_ari_asterisk_set_global_var_parse_body(
415         struct ast_json *body,
416         struct ast_ari_asterisk_set_global_var_args *args)
417 {
418         struct ast_json *field;
419         /* Parse query parameters out of it */
420         field = ast_json_object_get(body, "variable");
421         if (field) {
422                 args->variable = ast_json_string_get(field);
423         }
424         field = ast_json_object_get(body, "value");
425         if (field) {
426                 args->value = ast_json_string_get(field);
427         }
428         return 0;
429 }
430
431 /*!
432  * \brief Parameter parsing callback for /asterisk/variable.
433  * \param get_params GET parameters in the HTTP request.
434  * \param path_vars Path variables extracted from the request.
435  * \param headers HTTP headers.
436  * \param[out] response Response to the HTTP request.
437  */
438 static void ast_ari_asterisk_set_global_var_cb(
439         struct ast_tcptls_session_instance *ser,
440         struct ast_variable *get_params, struct ast_variable *path_vars,
441         struct ast_variable *headers, struct ast_ari_response *response)
442 {
443         struct ast_ari_asterisk_set_global_var_args args = {};
444         struct ast_variable *i;
445         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
446 #if defined(AST_DEVMODE)
447         int is_valid;
448         int code;
449 #endif /* AST_DEVMODE */
450
451         for (i = get_params; i; i = i->next) {
452                 if (strcmp(i->name, "variable") == 0) {
453                         args.variable = (i->value);
454                 } else
455                 if (strcmp(i->name, "value") == 0) {
456                         args.value = (i->value);
457                 } else
458                 {}
459         }
460         /* Look for a JSON request entity */
461         body = ast_http_get_json(ser, headers);
462         if (!body) {
463                 switch (errno) {
464                 case EFBIG:
465                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
466                         goto fin;
467                 case ENOMEM:
468                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
469                         goto fin;
470                 case EIO:
471                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
472                         goto fin;
473                 }
474         }
475         if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
476                 ast_ari_response_alloc_failed(response);
477                 goto fin;
478         }
479         ast_ari_asterisk_set_global_var(headers, &args, response);
480 #if defined(AST_DEVMODE)
481         code = response->response_code;
482
483         switch (code) {
484         case 0: /* Implementation is still a stub, or the code wasn't set */
485                 is_valid = response->message == NULL;
486                 break;
487         case 500: /* Internal Server Error */
488         case 501: /* Not Implemented */
489         case 400: /* Missing variable parameter. */
490                 is_valid = 1;
491                 break;
492         default:
493                 if (200 <= code && code <= 299) {
494                         is_valid = ast_ari_validate_void(
495                                 response->message);
496                 } else {
497                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
498                         is_valid = 0;
499                 }
500         }
501
502         if (!is_valid) {
503                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
504                 ast_ari_response_error(response, 500,
505                         "Internal Server Error", "Response validation failed");
506         }
507 #endif /* AST_DEVMODE */
508
509 fin: __attribute__((unused))
510         return;
511 }
512
513 /*! \brief REST handler for /api-docs/asterisk.{format} */
514 static struct stasis_rest_handlers asterisk_info = {
515         .path_segment = "info",
516         .callbacks = {
517                 [AST_HTTP_GET] = ast_ari_asterisk_get_info_cb,
518         },
519         .num_children = 0,
520         .children = {  }
521 };
522 /*! \brief REST handler for /api-docs/asterisk.{format} */
523 static struct stasis_rest_handlers asterisk_modules_moduleName = {
524         .path_segment = "moduleName",
525         .is_wildcard = 1,
526         .callbacks = {
527                 [AST_HTTP_GET] = ast_ari_asterisk_get_module_cb,
528         },
529         .num_children = 0,
530         .children = {  }
531 };
532 /*! \brief REST handler for /api-docs/asterisk.{format} */
533 static struct stasis_rest_handlers asterisk_modules = {
534         .path_segment = "modules",
535         .callbacks = {
536                 [AST_HTTP_GET] = ast_ari_asterisk_list_modules_cb,
537         },
538         .num_children = 1,
539         .children = { &asterisk_modules_moduleName, }
540 };
541 /*! \brief REST handler for /api-docs/asterisk.{format} */
542 static struct stasis_rest_handlers asterisk_variable = {
543         .path_segment = "variable",
544         .callbacks = {
545                 [AST_HTTP_GET] = ast_ari_asterisk_get_global_var_cb,
546                 [AST_HTTP_POST] = ast_ari_asterisk_set_global_var_cb,
547         },
548         .num_children = 0,
549         .children = {  }
550 };
551 /*! \brief REST handler for /api-docs/asterisk.{format} */
552 static struct stasis_rest_handlers asterisk = {
553         .path_segment = "asterisk",
554         .callbacks = {
555         },
556         .num_children = 3,
557         .children = { &asterisk_info,&asterisk_modules,&asterisk_variable, }
558 };
559
560 static int load_module(void)
561 {
562         int res = 0;
563         stasis_app_ref();
564         res |= ast_ari_add_handler(&asterisk);
565         return res;
566 }
567
568 static int unload_module(void)
569 {
570         ast_ari_remove_handler(&asterisk);
571         stasis_app_unref();
572         return 0;
573 }
574
575 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Asterisk resources",
576         .support_level = AST_MODULE_SUPPORT_CORE,
577         .load = load_module,
578         .unload = unload_module,
579         .nonoptreq = "res_ari,res_stasis",
580 );