ARI: Rotate log channels.
[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 /*!
56  * \brief Parameter parsing callback for /asterisk/config/dynamic/{configClass}/{objectType}/{id}.
57  * \param get_params GET parameters in the HTTP request.
58  * \param path_vars Path variables extracted from the request.
59  * \param headers HTTP headers.
60  * \param[out] response Response to the HTTP request.
61  */
62 static void ast_ari_asterisk_get_object_cb(
63         struct ast_tcptls_session_instance *ser,
64         struct ast_variable *get_params, struct ast_variable *path_vars,
65         struct ast_variable *headers, struct ast_ari_response *response)
66 {
67         struct ast_ari_asterisk_get_object_args args = {};
68         struct ast_variable *i;
69         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
70 #if defined(AST_DEVMODE)
71         int is_valid;
72         int code;
73 #endif /* AST_DEVMODE */
74
75         for (i = path_vars; i; i = i->next) {
76                 if (strcmp(i->name, "configClass") == 0) {
77                         args.config_class = (i->value);
78                 } else
79                 if (strcmp(i->name, "objectType") == 0) {
80                         args.object_type = (i->value);
81                 } else
82                 if (strcmp(i->name, "id") == 0) {
83                         args.id = (i->value);
84                 } else
85                 {}
86         }
87         ast_ari_asterisk_get_object(headers, &args, response);
88 #if defined(AST_DEVMODE)
89         code = response->response_code;
90
91         switch (code) {
92         case 0: /* Implementation is still a stub, or the code wasn't set */
93                 is_valid = response->message == NULL;
94                 break;
95         case 500: /* Internal Server Error */
96         case 501: /* Not Implemented */
97         case 404: /* {configClass|objectType|id} not found */
98                 is_valid = 1;
99                 break;
100         default:
101                 if (200 <= code && code <= 299) {
102                         is_valid = ast_ari_validate_list(response->message,
103                                 ast_ari_validate_config_tuple_fn());
104                 } else {
105                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n", code);
106                         is_valid = 0;
107                 }
108         }
109
110         if (!is_valid) {
111                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n");
112                 ast_ari_response_error(response, 500,
113                         "Internal Server Error", "Response validation failed");
114         }
115 #endif /* AST_DEVMODE */
116
117 fin: __attribute__((unused))
118         return;
119 }
120 int ast_ari_asterisk_update_object_parse_body(
121         struct ast_json *body,
122         struct ast_ari_asterisk_update_object_args *args)
123 {
124         /* Parse query parameters out of it */
125         return 0;
126 }
127
128 /*!
129  * \brief Parameter parsing callback for /asterisk/config/dynamic/{configClass}/{objectType}/{id}.
130  * \param get_params GET parameters in the HTTP request.
131  * \param path_vars Path variables extracted from the request.
132  * \param headers HTTP headers.
133  * \param[out] response Response to the HTTP request.
134  */
135 static void ast_ari_asterisk_update_object_cb(
136         struct ast_tcptls_session_instance *ser,
137         struct ast_variable *get_params, struct ast_variable *path_vars,
138         struct ast_variable *headers, struct ast_ari_response *response)
139 {
140         struct ast_ari_asterisk_update_object_args args = {};
141         struct ast_variable *i;
142         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
143 #if defined(AST_DEVMODE)
144         int is_valid;
145         int code;
146 #endif /* AST_DEVMODE */
147
148         for (i = path_vars; i; i = i->next) {
149                 if (strcmp(i->name, "configClass") == 0) {
150                         args.config_class = (i->value);
151                 } else
152                 if (strcmp(i->name, "objectType") == 0) {
153                         args.object_type = (i->value);
154                 } else
155                 if (strcmp(i->name, "id") == 0) {
156                         args.id = (i->value);
157                 } else
158                 {}
159         }
160         /* Look for a JSON request entity */
161         body = ast_http_get_json(ser, headers);
162         if (!body) {
163                 switch (errno) {
164                 case EFBIG:
165                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
166                         goto fin;
167                 case ENOMEM:
168                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
169                         goto fin;
170                 case EIO:
171                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
172                         goto fin;
173                 }
174         }
175         args.fields = body;
176         ast_ari_asterisk_update_object(headers, &args, response);
177 #if defined(AST_DEVMODE)
178         code = response->response_code;
179
180         switch (code) {
181         case 0: /* Implementation is still a stub, or the code wasn't set */
182                 is_valid = response->message == NULL;
183                 break;
184         case 500: /* Internal Server Error */
185         case 501: /* Not Implemented */
186         case 400: /* Bad request body */
187         case 403: /* Could not create or update object */
188         case 404: /* {configClass|objectType} not found */
189                 is_valid = 1;
190                 break;
191         default:
192                 if (200 <= code && code <= 299) {
193                         is_valid = ast_ari_validate_list(response->message,
194                                 ast_ari_validate_config_tuple_fn());
195                 } else {
196                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n", code);
197                         is_valid = 0;
198                 }
199         }
200
201         if (!is_valid) {
202                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n");
203                 ast_ari_response_error(response, 500,
204                         "Internal Server Error", "Response validation failed");
205         }
206 #endif /* AST_DEVMODE */
207
208 fin: __attribute__((unused))
209         return;
210 }
211 /*!
212  * \brief Parameter parsing callback for /asterisk/config/dynamic/{configClass}/{objectType}/{id}.
213  * \param get_params GET parameters in the HTTP request.
214  * \param path_vars Path variables extracted from the request.
215  * \param headers HTTP headers.
216  * \param[out] response Response to the HTTP request.
217  */
218 static void ast_ari_asterisk_delete_object_cb(
219         struct ast_tcptls_session_instance *ser,
220         struct ast_variable *get_params, struct ast_variable *path_vars,
221         struct ast_variable *headers, struct ast_ari_response *response)
222 {
223         struct ast_ari_asterisk_delete_object_args args = {};
224         struct ast_variable *i;
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         for (i = path_vars; i; i = i->next) {
232                 if (strcmp(i->name, "configClass") == 0) {
233                         args.config_class = (i->value);
234                 } else
235                 if (strcmp(i->name, "objectType") == 0) {
236                         args.object_type = (i->value);
237                 } else
238                 if (strcmp(i->name, "id") == 0) {
239                         args.id = (i->value);
240                 } else
241                 {}
242         }
243         ast_ari_asterisk_delete_object(headers, &args, response);
244 #if defined(AST_DEVMODE)
245         code = response->response_code;
246
247         switch (code) {
248         case 0: /* Implementation is still a stub, or the code wasn't set */
249                 is_valid = response->message == NULL;
250                 break;
251         case 500: /* Internal Server Error */
252         case 501: /* Not Implemented */
253         case 403: /* Could not delete object */
254         case 404: /* {configClass|objectType|id} not found */
255                 is_valid = 1;
256                 break;
257         default:
258                 if (200 <= code && code <= 299) {
259                         is_valid = ast_ari_validate_void(
260                                 response->message);
261                 } else {
262                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n", code);
263                         is_valid = 0;
264                 }
265         }
266
267         if (!is_valid) {
268                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n");
269                 ast_ari_response_error(response, 500,
270                         "Internal Server Error", "Response validation failed");
271         }
272 #endif /* AST_DEVMODE */
273
274 fin: __attribute__((unused))
275         return;
276 }
277 int ast_ari_asterisk_get_info_parse_body(
278         struct ast_json *body,
279         struct ast_ari_asterisk_get_info_args *args)
280 {
281         struct ast_json *field;
282         /* Parse query parameters out of it */
283         field = ast_json_object_get(body, "only");
284         if (field) {
285                 /* If they were silly enough to both pass in a query param and a
286                  * JSON body, free up the query value.
287                  */
288                 ast_free(args->only);
289                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
290                         /* Multiple param passed as array */
291                         size_t i;
292                         args->only_count = ast_json_array_size(field);
293                         args->only = ast_malloc(sizeof(*args->only) * args->only_count);
294
295                         if (!args->only) {
296                                 return -1;
297                         }
298
299                         for (i = 0; i < args->only_count; ++i) {
300                                 args->only[i] = ast_json_string_get(ast_json_array_get(field, i));
301                         }
302                 } else {
303                         /* Multiple param passed as single value */
304                         args->only_count = 1;
305                         args->only = ast_malloc(sizeof(*args->only) * args->only_count);
306                         if (!args->only) {
307                                 return -1;
308                         }
309                         args->only[0] = ast_json_string_get(field);
310                 }
311         }
312         return 0;
313 }
314
315 /*!
316  * \brief Parameter parsing callback for /asterisk/info.
317  * \param get_params GET parameters in the HTTP request.
318  * \param path_vars Path variables extracted from the request.
319  * \param headers HTTP headers.
320  * \param[out] response Response to the HTTP request.
321  */
322 static void ast_ari_asterisk_get_info_cb(
323         struct ast_tcptls_session_instance *ser,
324         struct ast_variable *get_params, struct ast_variable *path_vars,
325         struct ast_variable *headers, struct ast_ari_response *response)
326 {
327         struct ast_ari_asterisk_get_info_args args = {};
328         struct ast_variable *i;
329         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
330 #if defined(AST_DEVMODE)
331         int is_valid;
332         int code;
333 #endif /* AST_DEVMODE */
334
335         for (i = get_params; i; i = i->next) {
336                 if (strcmp(i->name, "only") == 0) {
337                         /* Parse comma separated list */
338                         char *vals[MAX_VALS];
339                         size_t j;
340
341                         args.only_parse = ast_strdup(i->value);
342                         if (!args.only_parse) {
343                                 ast_ari_response_alloc_failed(response);
344                                 goto fin;
345                         }
346
347                         if (strlen(args.only_parse) == 0) {
348                                 /* ast_app_separate_args can't handle "" */
349                                 args.only_count = 1;
350                                 vals[0] = args.only_parse;
351                         } else {
352                                 args.only_count = ast_app_separate_args(
353                                         args.only_parse, ',', vals,
354                                         ARRAY_LEN(vals));
355                         }
356
357                         if (args.only_count == 0) {
358                                 ast_ari_response_alloc_failed(response);
359                                 goto fin;
360                         }
361
362                         if (args.only_count >= MAX_VALS) {
363                                 ast_ari_response_error(response, 400,
364                                         "Bad Request",
365                                         "Too many values for only");
366                                 goto fin;
367                         }
368
369                         args.only = ast_malloc(sizeof(*args.only) * args.only_count);
370                         if (!args.only) {
371                                 ast_ari_response_alloc_failed(response);
372                                 goto fin;
373                         }
374
375                         for (j = 0; j < args.only_count; ++j) {
376                                 args.only[j] = (vals[j]);
377                         }
378                 } else
379                 {}
380         }
381         /* Look for a JSON request entity */
382         body = ast_http_get_json(ser, headers);
383         if (!body) {
384                 switch (errno) {
385                 case EFBIG:
386                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
387                         goto fin;
388                 case ENOMEM:
389                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
390                         goto fin;
391                 case EIO:
392                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
393                         goto fin;
394                 }
395         }
396         if (ast_ari_asterisk_get_info_parse_body(body, &args)) {
397                 ast_ari_response_alloc_failed(response);
398                 goto fin;
399         }
400         ast_ari_asterisk_get_info(headers, &args, response);
401 #if defined(AST_DEVMODE)
402         code = response->response_code;
403
404         switch (code) {
405         case 0: /* Implementation is still a stub, or the code wasn't set */
406                 is_valid = response->message == NULL;
407                 break;
408         case 500: /* Internal Server Error */
409         case 501: /* Not Implemented */
410                 is_valid = 1;
411                 break;
412         default:
413                 if (200 <= code && code <= 299) {
414                         is_valid = ast_ari_validate_asterisk_info(
415                                 response->message);
416                 } else {
417                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/info\n", code);
418                         is_valid = 0;
419                 }
420         }
421
422         if (!is_valid) {
423                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/info\n");
424                 ast_ari_response_error(response, 500,
425                         "Internal Server Error", "Response validation failed");
426         }
427 #endif /* AST_DEVMODE */
428
429 fin: __attribute__((unused))
430         ast_free(args.only_parse);
431         ast_free(args.only);
432         return;
433 }
434 /*!
435  * \brief Parameter parsing callback for /asterisk/modules.
436  * \param get_params GET parameters in the HTTP request.
437  * \param path_vars Path variables extracted from the request.
438  * \param headers HTTP headers.
439  * \param[out] response Response to the HTTP request.
440  */
441 static void ast_ari_asterisk_list_modules_cb(
442         struct ast_tcptls_session_instance *ser,
443         struct ast_variable *get_params, struct ast_variable *path_vars,
444         struct ast_variable *headers, struct ast_ari_response *response)
445 {
446         struct ast_ari_asterisk_list_modules_args args = {};
447         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
448 #if defined(AST_DEVMODE)
449         int is_valid;
450         int code;
451 #endif /* AST_DEVMODE */
452
453         ast_ari_asterisk_list_modules(headers, &args, response);
454 #if defined(AST_DEVMODE)
455         code = response->response_code;
456
457         switch (code) {
458         case 0: /* Implementation is still a stub, or the code wasn't set */
459                 is_valid = response->message == NULL;
460                 break;
461         case 500: /* Internal Server Error */
462         case 501: /* Not Implemented */
463                 is_valid = 1;
464                 break;
465         default:
466                 if (200 <= code && code <= 299) {
467                         is_valid = ast_ari_validate_list(response->message,
468                                 ast_ari_validate_module_fn());
469                 } else {
470                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules\n", code);
471                         is_valid = 0;
472                 }
473         }
474
475         if (!is_valid) {
476                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules\n");
477                 ast_ari_response_error(response, 500,
478                         "Internal Server Error", "Response validation failed");
479         }
480 #endif /* AST_DEVMODE */
481
482 fin: __attribute__((unused))
483         return;
484 }
485 /*!
486  * \brief Parameter parsing callback for /asterisk/modules/{moduleName}.
487  * \param get_params GET parameters in the HTTP request.
488  * \param path_vars Path variables extracted from the request.
489  * \param headers HTTP headers.
490  * \param[out] response Response to the HTTP request.
491  */
492 static void ast_ari_asterisk_get_module_cb(
493         struct ast_tcptls_session_instance *ser,
494         struct ast_variable *get_params, struct ast_variable *path_vars,
495         struct ast_variable *headers, struct ast_ari_response *response)
496 {
497         struct ast_ari_asterisk_get_module_args args = {};
498         struct ast_variable *i;
499         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
500 #if defined(AST_DEVMODE)
501         int is_valid;
502         int code;
503 #endif /* AST_DEVMODE */
504
505         for (i = path_vars; i; i = i->next) {
506                 if (strcmp(i->name, "moduleName") == 0) {
507                         args.module_name = (i->value);
508                 } else
509                 {}
510         }
511         ast_ari_asterisk_get_module(headers, &args, response);
512 #if defined(AST_DEVMODE)
513         code = response->response_code;
514
515         switch (code) {
516         case 0: /* Implementation is still a stub, or the code wasn't set */
517                 is_valid = response->message == NULL;
518                 break;
519         case 500: /* Internal Server Error */
520         case 501: /* Not Implemented */
521         case 404: /* Module could not be found in running modules. */
522         case 409: /* Module information could not be retrieved. */
523                 is_valid = 1;
524                 break;
525         default:
526                 if (200 <= code && code <= 299) {
527                         is_valid = ast_ari_validate_module(
528                                 response->message);
529                 } else {
530                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code);
531                         is_valid = 0;
532                 }
533         }
534
535         if (!is_valid) {
536                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n");
537                 ast_ari_response_error(response, 500,
538                         "Internal Server Error", "Response validation failed");
539         }
540 #endif /* AST_DEVMODE */
541
542 fin: __attribute__((unused))
543         return;
544 }
545 /*!
546  * \brief Parameter parsing callback for /asterisk/modules/{moduleName}.
547  * \param get_params GET parameters in the HTTP request.
548  * \param path_vars Path variables extracted from the request.
549  * \param headers HTTP headers.
550  * \param[out] response Response to the HTTP request.
551  */
552 static void ast_ari_asterisk_load_module_cb(
553         struct ast_tcptls_session_instance *ser,
554         struct ast_variable *get_params, struct ast_variable *path_vars,
555         struct ast_variable *headers, struct ast_ari_response *response)
556 {
557         struct ast_ari_asterisk_load_module_args args = {};
558         struct ast_variable *i;
559         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
560 #if defined(AST_DEVMODE)
561         int is_valid;
562         int code;
563 #endif /* AST_DEVMODE */
564
565         for (i = path_vars; i; i = i->next) {
566                 if (strcmp(i->name, "moduleName") == 0) {
567                         args.module_name = (i->value);
568                 } else
569                 {}
570         }
571         ast_ari_asterisk_load_module(headers, &args, response);
572 #if defined(AST_DEVMODE)
573         code = response->response_code;
574
575         switch (code) {
576         case 0: /* Implementation is still a stub, or the code wasn't set */
577                 is_valid = response->message == NULL;
578                 break;
579         case 500: /* Internal Server Error */
580         case 501: /* Not Implemented */
581         case 409: /* Module could not be loaded. */
582                 is_valid = 1;
583                 break;
584         default:
585                 if (200 <= code && code <= 299) {
586                         is_valid = ast_ari_validate_void(
587                                 response->message);
588                 } else {
589                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code);
590                         is_valid = 0;
591                 }
592         }
593
594         if (!is_valid) {
595                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n");
596                 ast_ari_response_error(response, 500,
597                         "Internal Server Error", "Response validation failed");
598         }
599 #endif /* AST_DEVMODE */
600
601 fin: __attribute__((unused))
602         return;
603 }
604 /*!
605  * \brief Parameter parsing callback for /asterisk/modules/{moduleName}.
606  * \param get_params GET parameters in the HTTP request.
607  * \param path_vars Path variables extracted from the request.
608  * \param headers HTTP headers.
609  * \param[out] response Response to the HTTP request.
610  */
611 static void ast_ari_asterisk_unload_module_cb(
612         struct ast_tcptls_session_instance *ser,
613         struct ast_variable *get_params, struct ast_variable *path_vars,
614         struct ast_variable *headers, struct ast_ari_response *response)
615 {
616         struct ast_ari_asterisk_unload_module_args args = {};
617         struct ast_variable *i;
618         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
619 #if defined(AST_DEVMODE)
620         int is_valid;
621         int code;
622 #endif /* AST_DEVMODE */
623
624         for (i = path_vars; i; i = i->next) {
625                 if (strcmp(i->name, "moduleName") == 0) {
626                         args.module_name = (i->value);
627                 } else
628                 {}
629         }
630         ast_ari_asterisk_unload_module(headers, &args, response);
631 #if defined(AST_DEVMODE)
632         code = response->response_code;
633
634         switch (code) {
635         case 0: /* Implementation is still a stub, or the code wasn't set */
636                 is_valid = response->message == NULL;
637                 break;
638         case 500: /* Internal Server Error */
639         case 501: /* Not Implemented */
640         case 404: /* Module not found in running modules. */
641         case 409: /* Module could not be unloaded. */
642                 is_valid = 1;
643                 break;
644         default:
645                 if (200 <= code && code <= 299) {
646                         is_valid = ast_ari_validate_void(
647                                 response->message);
648                 } else {
649                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code);
650                         is_valid = 0;
651                 }
652         }
653
654         if (!is_valid) {
655                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n");
656                 ast_ari_response_error(response, 500,
657                         "Internal Server Error", "Response validation failed");
658         }
659 #endif /* AST_DEVMODE */
660
661 fin: __attribute__((unused))
662         return;
663 }
664 /*!
665  * \brief Parameter parsing callback for /asterisk/modules/{moduleName}.
666  * \param get_params GET parameters in the HTTP request.
667  * \param path_vars Path variables extracted from the request.
668  * \param headers HTTP headers.
669  * \param[out] response Response to the HTTP request.
670  */
671 static void ast_ari_asterisk_reload_module_cb(
672         struct ast_tcptls_session_instance *ser,
673         struct ast_variable *get_params, struct ast_variable *path_vars,
674         struct ast_variable *headers, struct ast_ari_response *response)
675 {
676         struct ast_ari_asterisk_reload_module_args args = {};
677         struct ast_variable *i;
678         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
679 #if defined(AST_DEVMODE)
680         int is_valid;
681         int code;
682 #endif /* AST_DEVMODE */
683
684         for (i = path_vars; i; i = i->next) {
685                 if (strcmp(i->name, "moduleName") == 0) {
686                         args.module_name = (i->value);
687                 } else
688                 {}
689         }
690         ast_ari_asterisk_reload_module(headers, &args, response);
691 #if defined(AST_DEVMODE)
692         code = response->response_code;
693
694         switch (code) {
695         case 0: /* Implementation is still a stub, or the code wasn't set */
696                 is_valid = response->message == NULL;
697                 break;
698         case 500: /* Internal Server Error */
699         case 501: /* Not Implemented */
700         case 404: /* Module not found in running modules. */
701         case 409: /* Module could not be reloaded. */
702                 is_valid = 1;
703                 break;
704         default:
705                 if (200 <= code && code <= 299) {
706                         is_valid = ast_ari_validate_void(
707                                 response->message);
708                 } else {
709                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code);
710                         is_valid = 0;
711                 }
712         }
713
714         if (!is_valid) {
715                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n");
716                 ast_ari_response_error(response, 500,
717                         "Internal Server Error", "Response validation failed");
718         }
719 #endif /* AST_DEVMODE */
720
721 fin: __attribute__((unused))
722         return;
723 }
724 /*!
725  * \brief Parameter parsing callback for /asterisk/logging/{logChannelName}/rotate.
726  * \param get_params GET parameters in the HTTP request.
727  * \param path_vars Path variables extracted from the request.
728  * \param headers HTTP headers.
729  * \param[out] response Response to the HTTP request.
730  */
731 static void ast_ari_asterisk_rotate_log_cb(
732         struct ast_tcptls_session_instance *ser,
733         struct ast_variable *get_params, struct ast_variable *path_vars,
734         struct ast_variable *headers, struct ast_ari_response *response)
735 {
736         struct ast_ari_asterisk_rotate_log_args args = {};
737         struct ast_variable *i;
738         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
739 #if defined(AST_DEVMODE)
740         int is_valid;
741         int code;
742 #endif /* AST_DEVMODE */
743
744         for (i = path_vars; i; i = i->next) {
745                 if (strcmp(i->name, "logChannelName") == 0) {
746                         args.log_channel_name = (i->value);
747                 } else
748                 {}
749         }
750         ast_ari_asterisk_rotate_log(headers, &args, response);
751 #if defined(AST_DEVMODE)
752         code = response->response_code;
753
754         switch (code) {
755         case 0: /* Implementation is still a stub, or the code wasn't set */
756                 is_valid = response->message == NULL;
757                 break;
758         case 500: /* Internal Server Error */
759         case 501: /* Not Implemented */
760         case 404: /* Log channel does not exist. */
761                 is_valid = 1;
762                 break;
763         default:
764                 if (200 <= code && code <= 299) {
765                         is_valid = ast_ari_validate_void(
766                                 response->message);
767                 } else {
768                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/logging/{logChannelName}/rotate\n", code);
769                         is_valid = 0;
770                 }
771         }
772
773         if (!is_valid) {
774                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/logging/{logChannelName}/rotate\n");
775                 ast_ari_response_error(response, 500,
776                         "Internal Server Error", "Response validation failed");
777         }
778 #endif /* AST_DEVMODE */
779
780 fin: __attribute__((unused))
781         return;
782 }
783 int ast_ari_asterisk_get_global_var_parse_body(
784         struct ast_json *body,
785         struct ast_ari_asterisk_get_global_var_args *args)
786 {
787         struct ast_json *field;
788         /* Parse query parameters out of it */
789         field = ast_json_object_get(body, "variable");
790         if (field) {
791                 args->variable = ast_json_string_get(field);
792         }
793         return 0;
794 }
795
796 /*!
797  * \brief Parameter parsing callback for /asterisk/variable.
798  * \param get_params GET parameters in the HTTP request.
799  * \param path_vars Path variables extracted from the request.
800  * \param headers HTTP headers.
801  * \param[out] response Response to the HTTP request.
802  */
803 static void ast_ari_asterisk_get_global_var_cb(
804         struct ast_tcptls_session_instance *ser,
805         struct ast_variable *get_params, struct ast_variable *path_vars,
806         struct ast_variable *headers, struct ast_ari_response *response)
807 {
808         struct ast_ari_asterisk_get_global_var_args args = {};
809         struct ast_variable *i;
810         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
811 #if defined(AST_DEVMODE)
812         int is_valid;
813         int code;
814 #endif /* AST_DEVMODE */
815
816         for (i = get_params; i; i = i->next) {
817                 if (strcmp(i->name, "variable") == 0) {
818                         args.variable = (i->value);
819                 } else
820                 {}
821         }
822         /* Look for a JSON request entity */
823         body = ast_http_get_json(ser, headers);
824         if (!body) {
825                 switch (errno) {
826                 case EFBIG:
827                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
828                         goto fin;
829                 case ENOMEM:
830                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
831                         goto fin;
832                 case EIO:
833                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
834                         goto fin;
835                 }
836         }
837         if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
838                 ast_ari_response_alloc_failed(response);
839                 goto fin;
840         }
841         ast_ari_asterisk_get_global_var(headers, &args, response);
842 #if defined(AST_DEVMODE)
843         code = response->response_code;
844
845         switch (code) {
846         case 0: /* Implementation is still a stub, or the code wasn't set */
847                 is_valid = response->message == NULL;
848                 break;
849         case 500: /* Internal Server Error */
850         case 501: /* Not Implemented */
851         case 400: /* Missing variable parameter. */
852                 is_valid = 1;
853                 break;
854         default:
855                 if (200 <= code && code <= 299) {
856                         is_valid = ast_ari_validate_variable(
857                                 response->message);
858                 } else {
859                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
860                         is_valid = 0;
861                 }
862         }
863
864         if (!is_valid) {
865                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
866                 ast_ari_response_error(response, 500,
867                         "Internal Server Error", "Response validation failed");
868         }
869 #endif /* AST_DEVMODE */
870
871 fin: __attribute__((unused))
872         return;
873 }
874 int ast_ari_asterisk_set_global_var_parse_body(
875         struct ast_json *body,
876         struct ast_ari_asterisk_set_global_var_args *args)
877 {
878         struct ast_json *field;
879         /* Parse query parameters out of it */
880         field = ast_json_object_get(body, "variable");
881         if (field) {
882                 args->variable = ast_json_string_get(field);
883         }
884         field = ast_json_object_get(body, "value");
885         if (field) {
886                 args->value = ast_json_string_get(field);
887         }
888         return 0;
889 }
890
891 /*!
892  * \brief Parameter parsing callback for /asterisk/variable.
893  * \param get_params GET parameters in the HTTP request.
894  * \param path_vars Path variables extracted from the request.
895  * \param headers HTTP headers.
896  * \param[out] response Response to the HTTP request.
897  */
898 static void ast_ari_asterisk_set_global_var_cb(
899         struct ast_tcptls_session_instance *ser,
900         struct ast_variable *get_params, struct ast_variable *path_vars,
901         struct ast_variable *headers, struct ast_ari_response *response)
902 {
903         struct ast_ari_asterisk_set_global_var_args args = {};
904         struct ast_variable *i;
905         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
906 #if defined(AST_DEVMODE)
907         int is_valid;
908         int code;
909 #endif /* AST_DEVMODE */
910
911         for (i = get_params; i; i = i->next) {
912                 if (strcmp(i->name, "variable") == 0) {
913                         args.variable = (i->value);
914                 } else
915                 if (strcmp(i->name, "value") == 0) {
916                         args.value = (i->value);
917                 } else
918                 {}
919         }
920         /* Look for a JSON request entity */
921         body = ast_http_get_json(ser, headers);
922         if (!body) {
923                 switch (errno) {
924                 case EFBIG:
925                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
926                         goto fin;
927                 case ENOMEM:
928                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
929                         goto fin;
930                 case EIO:
931                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
932                         goto fin;
933                 }
934         }
935         if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
936                 ast_ari_response_alloc_failed(response);
937                 goto fin;
938         }
939         ast_ari_asterisk_set_global_var(headers, &args, response);
940 #if defined(AST_DEVMODE)
941         code = response->response_code;
942
943         switch (code) {
944         case 0: /* Implementation is still a stub, or the code wasn't set */
945                 is_valid = response->message == NULL;
946                 break;
947         case 500: /* Internal Server Error */
948         case 501: /* Not Implemented */
949         case 400: /* Missing variable parameter. */
950                 is_valid = 1;
951                 break;
952         default:
953                 if (200 <= code && code <= 299) {
954                         is_valid = ast_ari_validate_void(
955                                 response->message);
956                 } else {
957                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
958                         is_valid = 0;
959                 }
960         }
961
962         if (!is_valid) {
963                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
964                 ast_ari_response_error(response, 500,
965                         "Internal Server Error", "Response validation failed");
966         }
967 #endif /* AST_DEVMODE */
968
969 fin: __attribute__((unused))
970         return;
971 }
972
973 /*! \brief REST handler for /api-docs/asterisk.{format} */
974 static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType_id = {
975         .path_segment = "id",
976         .is_wildcard = 1,
977         .callbacks = {
978                 [AST_HTTP_GET] = ast_ari_asterisk_get_object_cb,
979                 [AST_HTTP_PUT] = ast_ari_asterisk_update_object_cb,
980                 [AST_HTTP_DELETE] = ast_ari_asterisk_delete_object_cb,
981         },
982         .num_children = 0,
983         .children = {  }
984 };
985 /*! \brief REST handler for /api-docs/asterisk.{format} */
986 static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType = {
987         .path_segment = "objectType",
988         .is_wildcard = 1,
989         .callbacks = {
990         },
991         .num_children = 1,
992         .children = { &asterisk_config_dynamic_configClass_objectType_id, }
993 };
994 /*! \brief REST handler for /api-docs/asterisk.{format} */
995 static struct stasis_rest_handlers asterisk_config_dynamic_configClass = {
996         .path_segment = "configClass",
997         .is_wildcard = 1,
998         .callbacks = {
999         },
1000         .num_children = 1,
1001         .children = { &asterisk_config_dynamic_configClass_objectType, }
1002 };
1003 /*! \brief REST handler for /api-docs/asterisk.{format} */
1004 static struct stasis_rest_handlers asterisk_config_dynamic = {
1005         .path_segment = "dynamic",
1006         .callbacks = {
1007         },
1008         .num_children = 1,
1009         .children = { &asterisk_config_dynamic_configClass, }
1010 };
1011 /*! \brief REST handler for /api-docs/asterisk.{format} */
1012 static struct stasis_rest_handlers asterisk_config = {
1013         .path_segment = "config",
1014         .callbacks = {
1015         },
1016         .num_children = 1,
1017         .children = { &asterisk_config_dynamic, }
1018 };
1019 /*! \brief REST handler for /api-docs/asterisk.{format} */
1020 static struct stasis_rest_handlers asterisk_info = {
1021         .path_segment = "info",
1022         .callbacks = {
1023                 [AST_HTTP_GET] = ast_ari_asterisk_get_info_cb,
1024         },
1025         .num_children = 0,
1026         .children = {  }
1027 };
1028 /*! \brief REST handler for /api-docs/asterisk.{format} */
1029 static struct stasis_rest_handlers asterisk_modules_moduleName = {
1030         .path_segment = "moduleName",
1031         .is_wildcard = 1,
1032         .callbacks = {
1033                 [AST_HTTP_GET] = ast_ari_asterisk_get_module_cb,
1034                 [AST_HTTP_POST] = ast_ari_asterisk_load_module_cb,
1035                 [AST_HTTP_DELETE] = ast_ari_asterisk_unload_module_cb,
1036                 [AST_HTTP_PUT] = ast_ari_asterisk_reload_module_cb,
1037         },
1038         .num_children = 0,
1039         .children = {  }
1040 };
1041 /*! \brief REST handler for /api-docs/asterisk.{format} */
1042 static struct stasis_rest_handlers asterisk_modules = {
1043         .path_segment = "modules",
1044         .callbacks = {
1045                 [AST_HTTP_GET] = ast_ari_asterisk_list_modules_cb,
1046         },
1047         .num_children = 1,
1048         .children = { &asterisk_modules_moduleName, }
1049 };
1050 /*! \brief REST handler for /api-docs/asterisk.{format} */
1051 static struct stasis_rest_handlers asterisk_logging_logChannelName_rotate = {
1052         .path_segment = "rotate",
1053         .callbacks = {
1054                 [AST_HTTP_PUT] = ast_ari_asterisk_rotate_log_cb,
1055         },
1056         .num_children = 0,
1057         .children = {  }
1058 };
1059 /*! \brief REST handler for /api-docs/asterisk.{format} */
1060 static struct stasis_rest_handlers asterisk_logging_logChannelName = {
1061         .path_segment = "logChannelName",
1062         .is_wildcard = 1,
1063         .callbacks = {
1064         },
1065         .num_children = 1,
1066         .children = { &asterisk_logging_logChannelName_rotate, }
1067 };
1068 /*! \brief REST handler for /api-docs/asterisk.{format} */
1069 static struct stasis_rest_handlers asterisk_logging = {
1070         .path_segment = "logging",
1071         .callbacks = {
1072         },
1073         .num_children = 1,
1074         .children = { &asterisk_logging_logChannelName, }
1075 };
1076 /*! \brief REST handler for /api-docs/asterisk.{format} */
1077 static struct stasis_rest_handlers asterisk_variable = {
1078         .path_segment = "variable",
1079         .callbacks = {
1080                 [AST_HTTP_GET] = ast_ari_asterisk_get_global_var_cb,
1081                 [AST_HTTP_POST] = ast_ari_asterisk_set_global_var_cb,
1082         },
1083         .num_children = 0,
1084         .children = {  }
1085 };
1086 /*! \brief REST handler for /api-docs/asterisk.{format} */
1087 static struct stasis_rest_handlers asterisk = {
1088         .path_segment = "asterisk",
1089         .callbacks = {
1090         },
1091         .num_children = 5,
1092         .children = { &asterisk_config,&asterisk_info,&asterisk_modules,&asterisk_logging,&asterisk_variable, }
1093 };
1094
1095 static int load_module(void)
1096 {
1097         int res = 0;
1098         stasis_app_ref();
1099         res |= ast_ari_add_handler(&asterisk);
1100         return res;
1101 }
1102
1103 static int unload_module(void)
1104 {
1105         ast_ari_remove_handler(&asterisk);
1106         stasis_app_unref();
1107         return 0;
1108 }
1109
1110 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Asterisk resources",
1111         .support_level = AST_MODULE_SUPPORT_CORE,
1112         .load = load_module,
1113         .unload = unload_module,
1114         .nonoptreq = "res_ari,res_stasis",
1115 );