Merge "dns_core: Allow zero-length DNS responses."
[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 int ast_ari_asterisk_get_global_var_parse_body(
725         struct ast_json *body,
726         struct ast_ari_asterisk_get_global_var_args *args)
727 {
728         struct ast_json *field;
729         /* Parse query parameters out of it */
730         field = ast_json_object_get(body, "variable");
731         if (field) {
732                 args->variable = ast_json_string_get(field);
733         }
734         return 0;
735 }
736
737 /*!
738  * \brief Parameter parsing callback for /asterisk/variable.
739  * \param get_params GET parameters in the HTTP request.
740  * \param path_vars Path variables extracted from the request.
741  * \param headers HTTP headers.
742  * \param[out] response Response to the HTTP request.
743  */
744 static void ast_ari_asterisk_get_global_var_cb(
745         struct ast_tcptls_session_instance *ser,
746         struct ast_variable *get_params, struct ast_variable *path_vars,
747         struct ast_variable *headers, struct ast_ari_response *response)
748 {
749         struct ast_ari_asterisk_get_global_var_args args = {};
750         struct ast_variable *i;
751         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
752 #if defined(AST_DEVMODE)
753         int is_valid;
754         int code;
755 #endif /* AST_DEVMODE */
756
757         for (i = get_params; i; i = i->next) {
758                 if (strcmp(i->name, "variable") == 0) {
759                         args.variable = (i->value);
760                 } else
761                 {}
762         }
763         /* Look for a JSON request entity */
764         body = ast_http_get_json(ser, headers);
765         if (!body) {
766                 switch (errno) {
767                 case EFBIG:
768                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
769                         goto fin;
770                 case ENOMEM:
771                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
772                         goto fin;
773                 case EIO:
774                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
775                         goto fin;
776                 }
777         }
778         if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
779                 ast_ari_response_alloc_failed(response);
780                 goto fin;
781         }
782         ast_ari_asterisk_get_global_var(headers, &args, response);
783 #if defined(AST_DEVMODE)
784         code = response->response_code;
785
786         switch (code) {
787         case 0: /* Implementation is still a stub, or the code wasn't set */
788                 is_valid = response->message == NULL;
789                 break;
790         case 500: /* Internal Server Error */
791         case 501: /* Not Implemented */
792         case 400: /* Missing variable parameter. */
793                 is_valid = 1;
794                 break;
795         default:
796                 if (200 <= code && code <= 299) {
797                         is_valid = ast_ari_validate_variable(
798                                 response->message);
799                 } else {
800                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
801                         is_valid = 0;
802                 }
803         }
804
805         if (!is_valid) {
806                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
807                 ast_ari_response_error(response, 500,
808                         "Internal Server Error", "Response validation failed");
809         }
810 #endif /* AST_DEVMODE */
811
812 fin: __attribute__((unused))
813         return;
814 }
815 int ast_ari_asterisk_set_global_var_parse_body(
816         struct ast_json *body,
817         struct ast_ari_asterisk_set_global_var_args *args)
818 {
819         struct ast_json *field;
820         /* Parse query parameters out of it */
821         field = ast_json_object_get(body, "variable");
822         if (field) {
823                 args->variable = ast_json_string_get(field);
824         }
825         field = ast_json_object_get(body, "value");
826         if (field) {
827                 args->value = ast_json_string_get(field);
828         }
829         return 0;
830 }
831
832 /*!
833  * \brief Parameter parsing callback for /asterisk/variable.
834  * \param get_params GET parameters in the HTTP request.
835  * \param path_vars Path variables extracted from the request.
836  * \param headers HTTP headers.
837  * \param[out] response Response to the HTTP request.
838  */
839 static void ast_ari_asterisk_set_global_var_cb(
840         struct ast_tcptls_session_instance *ser,
841         struct ast_variable *get_params, struct ast_variable *path_vars,
842         struct ast_variable *headers, struct ast_ari_response *response)
843 {
844         struct ast_ari_asterisk_set_global_var_args args = {};
845         struct ast_variable *i;
846         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
847 #if defined(AST_DEVMODE)
848         int is_valid;
849         int code;
850 #endif /* AST_DEVMODE */
851
852         for (i = get_params; i; i = i->next) {
853                 if (strcmp(i->name, "variable") == 0) {
854                         args.variable = (i->value);
855                 } else
856                 if (strcmp(i->name, "value") == 0) {
857                         args.value = (i->value);
858                 } else
859                 {}
860         }
861         /* Look for a JSON request entity */
862         body = ast_http_get_json(ser, headers);
863         if (!body) {
864                 switch (errno) {
865                 case EFBIG:
866                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
867                         goto fin;
868                 case ENOMEM:
869                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
870                         goto fin;
871                 case EIO:
872                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
873                         goto fin;
874                 }
875         }
876         if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
877                 ast_ari_response_alloc_failed(response);
878                 goto fin;
879         }
880         ast_ari_asterisk_set_global_var(headers, &args, response);
881 #if defined(AST_DEVMODE)
882         code = response->response_code;
883
884         switch (code) {
885         case 0: /* Implementation is still a stub, or the code wasn't set */
886                 is_valid = response->message == NULL;
887                 break;
888         case 500: /* Internal Server Error */
889         case 501: /* Not Implemented */
890         case 400: /* Missing variable parameter. */
891                 is_valid = 1;
892                 break;
893         default:
894                 if (200 <= code && code <= 299) {
895                         is_valid = ast_ari_validate_void(
896                                 response->message);
897                 } else {
898                         ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
899                         is_valid = 0;
900                 }
901         }
902
903         if (!is_valid) {
904                 ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
905                 ast_ari_response_error(response, 500,
906                         "Internal Server Error", "Response validation failed");
907         }
908 #endif /* AST_DEVMODE */
909
910 fin: __attribute__((unused))
911         return;
912 }
913
914 /*! \brief REST handler for /api-docs/asterisk.{format} */
915 static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType_id = {
916         .path_segment = "id",
917         .is_wildcard = 1,
918         .callbacks = {
919                 [AST_HTTP_GET] = ast_ari_asterisk_get_object_cb,
920                 [AST_HTTP_PUT] = ast_ari_asterisk_update_object_cb,
921                 [AST_HTTP_DELETE] = ast_ari_asterisk_delete_object_cb,
922         },
923         .num_children = 0,
924         .children = {  }
925 };
926 /*! \brief REST handler for /api-docs/asterisk.{format} */
927 static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType = {
928         .path_segment = "objectType",
929         .is_wildcard = 1,
930         .callbacks = {
931         },
932         .num_children = 1,
933         .children = { &asterisk_config_dynamic_configClass_objectType_id, }
934 };
935 /*! \brief REST handler for /api-docs/asterisk.{format} */
936 static struct stasis_rest_handlers asterisk_config_dynamic_configClass = {
937         .path_segment = "configClass",
938         .is_wildcard = 1,
939         .callbacks = {
940         },
941         .num_children = 1,
942         .children = { &asterisk_config_dynamic_configClass_objectType, }
943 };
944 /*! \brief REST handler for /api-docs/asterisk.{format} */
945 static struct stasis_rest_handlers asterisk_config_dynamic = {
946         .path_segment = "dynamic",
947         .callbacks = {
948         },
949         .num_children = 1,
950         .children = { &asterisk_config_dynamic_configClass, }
951 };
952 /*! \brief REST handler for /api-docs/asterisk.{format} */
953 static struct stasis_rest_handlers asterisk_config = {
954         .path_segment = "config",
955         .callbacks = {
956         },
957         .num_children = 1,
958         .children = { &asterisk_config_dynamic, }
959 };
960 /*! \brief REST handler for /api-docs/asterisk.{format} */
961 static struct stasis_rest_handlers asterisk_info = {
962         .path_segment = "info",
963         .callbacks = {
964                 [AST_HTTP_GET] = ast_ari_asterisk_get_info_cb,
965         },
966         .num_children = 0,
967         .children = {  }
968 };
969 /*! \brief REST handler for /api-docs/asterisk.{format} */
970 static struct stasis_rest_handlers asterisk_modules_moduleName = {
971         .path_segment = "moduleName",
972         .is_wildcard = 1,
973         .callbacks = {
974                 [AST_HTTP_GET] = ast_ari_asterisk_get_module_cb,
975                 [AST_HTTP_POST] = ast_ari_asterisk_load_module_cb,
976                 [AST_HTTP_DELETE] = ast_ari_asterisk_unload_module_cb,
977                 [AST_HTTP_PUT] = ast_ari_asterisk_reload_module_cb,
978         },
979         .num_children = 0,
980         .children = {  }
981 };
982 /*! \brief REST handler for /api-docs/asterisk.{format} */
983 static struct stasis_rest_handlers asterisk_modules = {
984         .path_segment = "modules",
985         .callbacks = {
986                 [AST_HTTP_GET] = ast_ari_asterisk_list_modules_cb,
987         },
988         .num_children = 1,
989         .children = { &asterisk_modules_moduleName, }
990 };
991 /*! \brief REST handler for /api-docs/asterisk.{format} */
992 static struct stasis_rest_handlers asterisk_variable = {
993         .path_segment = "variable",
994         .callbacks = {
995                 [AST_HTTP_GET] = ast_ari_asterisk_get_global_var_cb,
996                 [AST_HTTP_POST] = ast_ari_asterisk_set_global_var_cb,
997         },
998         .num_children = 0,
999         .children = {  }
1000 };
1001 /*! \brief REST handler for /api-docs/asterisk.{format} */
1002 static struct stasis_rest_handlers asterisk = {
1003         .path_segment = "asterisk",
1004         .callbacks = {
1005         },
1006         .num_children = 4,
1007         .children = { &asterisk_config,&asterisk_info,&asterisk_modules,&asterisk_variable, }
1008 };
1009
1010 static int load_module(void)
1011 {
1012         int res = 0;
1013         stasis_app_ref();
1014         res |= ast_ari_add_handler(&asterisk);
1015         return res;
1016 }
1017
1018 static int unload_module(void)
1019 {
1020         ast_ari_remove_handler(&asterisk);
1021         stasis_app_unref();
1022         return 0;
1023 }
1024
1025 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Asterisk resources",
1026         .support_level = AST_MODULE_SUPPORT_CORE,
1027         .load = load_module,
1028         .unload = unload_module,
1029         .nonoptreq = "res_ari,res_stasis",
1030 );