res_pjsip_session.c: Fix build when TEST_FRAMEWORK is not defined
[asterisk/asterisk.git] / res / res_ari_bridges.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 Bridge 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 #include "asterisk/app.h"
44 #include "asterisk/module.h"
45 #include "asterisk/stasis_app.h"
46 #include "ari/resource_bridges.h"
47 #if defined(AST_DEVMODE)
48 #include "ari/ari_model_validators.h"
49 #endif
50
51 #define MAX_VALS 128
52
53 /*!
54  * \brief Parameter parsing callback for /bridges.
55  * \param get_params GET parameters in the HTTP request.
56  * \param path_vars Path variables extracted from the request.
57  * \param headers HTTP headers.
58  * \param[out] response Response to the HTTP request.
59  */
60 static void ast_ari_bridges_list_cb(
61         struct ast_tcptls_session_instance *ser,
62         struct ast_variable *get_params, struct ast_variable *path_vars,
63         struct ast_variable *headers, struct ast_ari_response *response)
64 {
65         struct ast_ari_bridges_list_args args = {};
66         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
67 #if defined(AST_DEVMODE)
68         int is_valid;
69         int code;
70 #endif /* AST_DEVMODE */
71
72         ast_ari_bridges_list(headers, &args, response);
73 #if defined(AST_DEVMODE)
74         code = response->response_code;
75
76         switch (code) {
77         case 0: /* Implementation is still a stub, or the code wasn't set */
78                 is_valid = response->message == NULL;
79                 break;
80         case 500: /* Internal Server Error */
81         case 501: /* Not Implemented */
82                 is_valid = 1;
83                 break;
84         default:
85                 if (200 <= code && code <= 299) {
86                         is_valid = ast_ari_validate_list(response->message,
87                                 ast_ari_validate_bridge_fn());
88                 } else {
89                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
90                         is_valid = 0;
91                 }
92         }
93
94         if (!is_valid) {
95                 ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
96                 ast_ari_response_error(response, 500,
97                         "Internal Server Error", "Response validation failed");
98         }
99 #endif /* AST_DEVMODE */
100
101 fin: __attribute__((unused))
102         return;
103 }
104 int ast_ari_bridges_create_parse_body(
105         struct ast_json *body,
106         struct ast_ari_bridges_create_args *args)
107 {
108         struct ast_json *field;
109         /* Parse query parameters out of it */
110         field = ast_json_object_get(body, "type");
111         if (field) {
112                 args->type = ast_json_string_get(field);
113         }
114         field = ast_json_object_get(body, "bridgeId");
115         if (field) {
116                 args->bridge_id = ast_json_string_get(field);
117         }
118         field = ast_json_object_get(body, "name");
119         if (field) {
120                 args->name = ast_json_string_get(field);
121         }
122         return 0;
123 }
124
125 /*!
126  * \brief Parameter parsing callback for /bridges.
127  * \param get_params GET parameters in the HTTP request.
128  * \param path_vars Path variables extracted from the request.
129  * \param headers HTTP headers.
130  * \param[out] response Response to the HTTP request.
131  */
132 static void ast_ari_bridges_create_cb(
133         struct ast_tcptls_session_instance *ser,
134         struct ast_variable *get_params, struct ast_variable *path_vars,
135         struct ast_variable *headers, struct ast_ari_response *response)
136 {
137         struct ast_ari_bridges_create_args args = {};
138         struct ast_variable *i;
139         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
140 #if defined(AST_DEVMODE)
141         int is_valid;
142         int code;
143 #endif /* AST_DEVMODE */
144
145         for (i = get_params; i; i = i->next) {
146                 if (strcmp(i->name, "type") == 0) {
147                         args.type = (i->value);
148                 } else
149                 if (strcmp(i->name, "bridgeId") == 0) {
150                         args.bridge_id = (i->value);
151                 } else
152                 if (strcmp(i->name, "name") == 0) {
153                         args.name = (i->value);
154                 } else
155                 {}
156         }
157         /* Look for a JSON request entity */
158         body = ast_http_get_json(ser, headers);
159         if (!body) {
160                 switch (errno) {
161                 case EFBIG:
162                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
163                         goto fin;
164                 case ENOMEM:
165                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
166                         goto fin;
167                 case EIO:
168                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
169                         goto fin;
170                 }
171         }
172         if (ast_ari_bridges_create_parse_body(body, &args)) {
173                 ast_ari_response_alloc_failed(response);
174                 goto fin;
175         }
176         ast_ari_bridges_create(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                 is_valid = 1;
187                 break;
188         default:
189                 if (200 <= code && code <= 299) {
190                         is_valid = ast_ari_validate_bridge(
191                                 response->message);
192                 } else {
193                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
194                         is_valid = 0;
195                 }
196         }
197
198         if (!is_valid) {
199                 ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
200                 ast_ari_response_error(response, 500,
201                         "Internal Server Error", "Response validation failed");
202         }
203 #endif /* AST_DEVMODE */
204
205 fin: __attribute__((unused))
206         return;
207 }
208 int ast_ari_bridges_create_with_id_parse_body(
209         struct ast_json *body,
210         struct ast_ari_bridges_create_with_id_args *args)
211 {
212         struct ast_json *field;
213         /* Parse query parameters out of it */
214         field = ast_json_object_get(body, "type");
215         if (field) {
216                 args->type = ast_json_string_get(field);
217         }
218         field = ast_json_object_get(body, "name");
219         if (field) {
220                 args->name = ast_json_string_get(field);
221         }
222         return 0;
223 }
224
225 /*!
226  * \brief Parameter parsing callback for /bridges/{bridgeId}.
227  * \param get_params GET parameters in the HTTP request.
228  * \param path_vars Path variables extracted from the request.
229  * \param headers HTTP headers.
230  * \param[out] response Response to the HTTP request.
231  */
232 static void ast_ari_bridges_create_with_id_cb(
233         struct ast_tcptls_session_instance *ser,
234         struct ast_variable *get_params, struct ast_variable *path_vars,
235         struct ast_variable *headers, struct ast_ari_response *response)
236 {
237         struct ast_ari_bridges_create_with_id_args args = {};
238         struct ast_variable *i;
239         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
240 #if defined(AST_DEVMODE)
241         int is_valid;
242         int code;
243 #endif /* AST_DEVMODE */
244
245         for (i = get_params; i; i = i->next) {
246                 if (strcmp(i->name, "type") == 0) {
247                         args.type = (i->value);
248                 } else
249                 if (strcmp(i->name, "name") == 0) {
250                         args.name = (i->value);
251                 } else
252                 {}
253         }
254         for (i = path_vars; i; i = i->next) {
255                 if (strcmp(i->name, "bridgeId") == 0) {
256                         args.bridge_id = (i->value);
257                 } else
258                 {}
259         }
260         /* Look for a JSON request entity */
261         body = ast_http_get_json(ser, headers);
262         if (!body) {
263                 switch (errno) {
264                 case EFBIG:
265                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
266                         goto fin;
267                 case ENOMEM:
268                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
269                         goto fin;
270                 case EIO:
271                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
272                         goto fin;
273                 }
274         }
275         if (ast_ari_bridges_create_with_id_parse_body(body, &args)) {
276                 ast_ari_response_alloc_failed(response);
277                 goto fin;
278         }
279         ast_ari_bridges_create_with_id(headers, &args, response);
280 #if defined(AST_DEVMODE)
281         code = response->response_code;
282
283         switch (code) {
284         case 0: /* Implementation is still a stub, or the code wasn't set */
285                 is_valid = response->message == NULL;
286                 break;
287         case 500: /* Internal Server Error */
288         case 501: /* Not Implemented */
289                 is_valid = 1;
290                 break;
291         default:
292                 if (200 <= code && code <= 299) {
293                         is_valid = ast_ari_validate_bridge(
294                                 response->message);
295                 } else {
296                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
297                         is_valid = 0;
298                 }
299         }
300
301         if (!is_valid) {
302                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
303                 ast_ari_response_error(response, 500,
304                         "Internal Server Error", "Response validation failed");
305         }
306 #endif /* AST_DEVMODE */
307
308 fin: __attribute__((unused))
309         return;
310 }
311 /*!
312  * \brief Parameter parsing callback for /bridges/{bridgeId}.
313  * \param get_params GET parameters in the HTTP request.
314  * \param path_vars Path variables extracted from the request.
315  * \param headers HTTP headers.
316  * \param[out] response Response to the HTTP request.
317  */
318 static void ast_ari_bridges_get_cb(
319         struct ast_tcptls_session_instance *ser,
320         struct ast_variable *get_params, struct ast_variable *path_vars,
321         struct ast_variable *headers, struct ast_ari_response *response)
322 {
323         struct ast_ari_bridges_get_args args = {};
324         struct ast_variable *i;
325         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
326 #if defined(AST_DEVMODE)
327         int is_valid;
328         int code;
329 #endif /* AST_DEVMODE */
330
331         for (i = path_vars; i; i = i->next) {
332                 if (strcmp(i->name, "bridgeId") == 0) {
333                         args.bridge_id = (i->value);
334                 } else
335                 {}
336         }
337         ast_ari_bridges_get(headers, &args, response);
338 #if defined(AST_DEVMODE)
339         code = response->response_code;
340
341         switch (code) {
342         case 0: /* Implementation is still a stub, or the code wasn't set */
343                 is_valid = response->message == NULL;
344                 break;
345         case 500: /* Internal Server Error */
346         case 501: /* Not Implemented */
347         case 404: /* Bridge not found */
348                 is_valid = 1;
349                 break;
350         default:
351                 if (200 <= code && code <= 299) {
352                         is_valid = ast_ari_validate_bridge(
353                                 response->message);
354                 } else {
355                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
356                         is_valid = 0;
357                 }
358         }
359
360         if (!is_valid) {
361                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
362                 ast_ari_response_error(response, 500,
363                         "Internal Server Error", "Response validation failed");
364         }
365 #endif /* AST_DEVMODE */
366
367 fin: __attribute__((unused))
368         return;
369 }
370 /*!
371  * \brief Parameter parsing callback for /bridges/{bridgeId}.
372  * \param get_params GET parameters in the HTTP request.
373  * \param path_vars Path variables extracted from the request.
374  * \param headers HTTP headers.
375  * \param[out] response Response to the HTTP request.
376  */
377 static void ast_ari_bridges_destroy_cb(
378         struct ast_tcptls_session_instance *ser,
379         struct ast_variable *get_params, struct ast_variable *path_vars,
380         struct ast_variable *headers, struct ast_ari_response *response)
381 {
382         struct ast_ari_bridges_destroy_args args = {};
383         struct ast_variable *i;
384         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
385 #if defined(AST_DEVMODE)
386         int is_valid;
387         int code;
388 #endif /* AST_DEVMODE */
389
390         for (i = path_vars; i; i = i->next) {
391                 if (strcmp(i->name, "bridgeId") == 0) {
392                         args.bridge_id = (i->value);
393                 } else
394                 {}
395         }
396         ast_ari_bridges_destroy(headers, &args, response);
397 #if defined(AST_DEVMODE)
398         code = response->response_code;
399
400         switch (code) {
401         case 0: /* Implementation is still a stub, or the code wasn't set */
402                 is_valid = response->message == NULL;
403                 break;
404         case 500: /* Internal Server Error */
405         case 501: /* Not Implemented */
406         case 404: /* Bridge not found */
407                 is_valid = 1;
408                 break;
409         default:
410                 if (200 <= code && code <= 299) {
411                         is_valid = ast_ari_validate_void(
412                                 response->message);
413                 } else {
414                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
415                         is_valid = 0;
416                 }
417         }
418
419         if (!is_valid) {
420                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
421                 ast_ari_response_error(response, 500,
422                         "Internal Server Error", "Response validation failed");
423         }
424 #endif /* AST_DEVMODE */
425
426 fin: __attribute__((unused))
427         return;
428 }
429 int ast_ari_bridges_add_channel_parse_body(
430         struct ast_json *body,
431         struct ast_ari_bridges_add_channel_args *args)
432 {
433         struct ast_json *field;
434         /* Parse query parameters out of it */
435         field = ast_json_object_get(body, "channel");
436         if (field) {
437                 /* If they were silly enough to both pass in a query param and a
438                  * JSON body, free up the query value.
439                  */
440                 ast_free(args->channel);
441                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
442                         /* Multiple param passed as array */
443                         size_t i;
444                         args->channel_count = ast_json_array_size(field);
445                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
446
447                         if (!args->channel) {
448                                 return -1;
449                         }
450
451                         for (i = 0; i < args->channel_count; ++i) {
452                                 args->channel[i] = ast_json_string_get(ast_json_array_get(field, i));
453                         }
454                 } else {
455                         /* Multiple param passed as single value */
456                         args->channel_count = 1;
457                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
458                         if (!args->channel) {
459                                 return -1;
460                         }
461                         args->channel[0] = ast_json_string_get(field);
462                 }
463         }
464         field = ast_json_object_get(body, "role");
465         if (field) {
466                 args->role = ast_json_string_get(field);
467         }
468         return 0;
469 }
470
471 /*!
472  * \brief Parameter parsing callback for /bridges/{bridgeId}/addChannel.
473  * \param get_params GET parameters in the HTTP request.
474  * \param path_vars Path variables extracted from the request.
475  * \param headers HTTP headers.
476  * \param[out] response Response to the HTTP request.
477  */
478 static void ast_ari_bridges_add_channel_cb(
479         struct ast_tcptls_session_instance *ser,
480         struct ast_variable *get_params, struct ast_variable *path_vars,
481         struct ast_variable *headers, struct ast_ari_response *response)
482 {
483         struct ast_ari_bridges_add_channel_args args = {};
484         struct ast_variable *i;
485         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
486 #if defined(AST_DEVMODE)
487         int is_valid;
488         int code;
489 #endif /* AST_DEVMODE */
490
491         for (i = get_params; i; i = i->next) {
492                 if (strcmp(i->name, "channel") == 0) {
493                         /* Parse comma separated list */
494                         char *vals[MAX_VALS];
495                         size_t j;
496
497                         args.channel_parse = ast_strdup(i->value);
498                         if (!args.channel_parse) {
499                                 ast_ari_response_alloc_failed(response);
500                                 goto fin;
501                         }
502
503                         if (strlen(args.channel_parse) == 0) {
504                                 /* ast_app_separate_args can't handle "" */
505                                 args.channel_count = 1;
506                                 vals[0] = args.channel_parse;
507                         } else {
508                                 args.channel_count = ast_app_separate_args(
509                                         args.channel_parse, ',', vals,
510                                         ARRAY_LEN(vals));
511                         }
512
513                         if (args.channel_count == 0) {
514                                 ast_ari_response_alloc_failed(response);
515                                 goto fin;
516                         }
517
518                         if (args.channel_count >= MAX_VALS) {
519                                 ast_ari_response_error(response, 400,
520                                         "Bad Request",
521                                         "Too many values for channel");
522                                 goto fin;
523                         }
524
525                         args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
526                         if (!args.channel) {
527                                 ast_ari_response_alloc_failed(response);
528                                 goto fin;
529                         }
530
531                         for (j = 0; j < args.channel_count; ++j) {
532                                 args.channel[j] = (vals[j]);
533                         }
534                 } else
535                 if (strcmp(i->name, "role") == 0) {
536                         args.role = (i->value);
537                 } else
538                 {}
539         }
540         for (i = path_vars; i; i = i->next) {
541                 if (strcmp(i->name, "bridgeId") == 0) {
542                         args.bridge_id = (i->value);
543                 } else
544                 {}
545         }
546         /* Look for a JSON request entity */
547         body = ast_http_get_json(ser, headers);
548         if (!body) {
549                 switch (errno) {
550                 case EFBIG:
551                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
552                         goto fin;
553                 case ENOMEM:
554                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
555                         goto fin;
556                 case EIO:
557                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
558                         goto fin;
559                 }
560         }
561         if (ast_ari_bridges_add_channel_parse_body(body, &args)) {
562                 ast_ari_response_alloc_failed(response);
563                 goto fin;
564         }
565         ast_ari_bridges_add_channel(headers, &args, response);
566 #if defined(AST_DEVMODE)
567         code = response->response_code;
568
569         switch (code) {
570         case 0: /* Implementation is still a stub, or the code wasn't set */
571                 is_valid = response->message == NULL;
572                 break;
573         case 500: /* Internal Server Error */
574         case 501: /* Not Implemented */
575         case 400: /* Channel not found */
576         case 404: /* Bridge not found */
577         case 409: /* Bridge not in Stasis application; Channel currently recording */
578         case 422: /* Channel not in Stasis application */
579                 is_valid = 1;
580                 break;
581         default:
582                 if (200 <= code && code <= 299) {
583                         is_valid = ast_ari_validate_void(
584                                 response->message);
585                 } else {
586                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/addChannel\n", code);
587                         is_valid = 0;
588                 }
589         }
590
591         if (!is_valid) {
592                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/addChannel\n");
593                 ast_ari_response_error(response, 500,
594                         "Internal Server Error", "Response validation failed");
595         }
596 #endif /* AST_DEVMODE */
597
598 fin: __attribute__((unused))
599         ast_free(args.channel_parse);
600         ast_free(args.channel);
601         return;
602 }
603 int ast_ari_bridges_remove_channel_parse_body(
604         struct ast_json *body,
605         struct ast_ari_bridges_remove_channel_args *args)
606 {
607         struct ast_json *field;
608         /* Parse query parameters out of it */
609         field = ast_json_object_get(body, "channel");
610         if (field) {
611                 /* If they were silly enough to both pass in a query param and a
612                  * JSON body, free up the query value.
613                  */
614                 ast_free(args->channel);
615                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
616                         /* Multiple param passed as array */
617                         size_t i;
618                         args->channel_count = ast_json_array_size(field);
619                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
620
621                         if (!args->channel) {
622                                 return -1;
623                         }
624
625                         for (i = 0; i < args->channel_count; ++i) {
626                                 args->channel[i] = ast_json_string_get(ast_json_array_get(field, i));
627                         }
628                 } else {
629                         /* Multiple param passed as single value */
630                         args->channel_count = 1;
631                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
632                         if (!args->channel) {
633                                 return -1;
634                         }
635                         args->channel[0] = ast_json_string_get(field);
636                 }
637         }
638         return 0;
639 }
640
641 /*!
642  * \brief Parameter parsing callback for /bridges/{bridgeId}/removeChannel.
643  * \param get_params GET parameters in the HTTP request.
644  * \param path_vars Path variables extracted from the request.
645  * \param headers HTTP headers.
646  * \param[out] response Response to the HTTP request.
647  */
648 static void ast_ari_bridges_remove_channel_cb(
649         struct ast_tcptls_session_instance *ser,
650         struct ast_variable *get_params, struct ast_variable *path_vars,
651         struct ast_variable *headers, struct ast_ari_response *response)
652 {
653         struct ast_ari_bridges_remove_channel_args args = {};
654         struct ast_variable *i;
655         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
656 #if defined(AST_DEVMODE)
657         int is_valid;
658         int code;
659 #endif /* AST_DEVMODE */
660
661         for (i = get_params; i; i = i->next) {
662                 if (strcmp(i->name, "channel") == 0) {
663                         /* Parse comma separated list */
664                         char *vals[MAX_VALS];
665                         size_t j;
666
667                         args.channel_parse = ast_strdup(i->value);
668                         if (!args.channel_parse) {
669                                 ast_ari_response_alloc_failed(response);
670                                 goto fin;
671                         }
672
673                         if (strlen(args.channel_parse) == 0) {
674                                 /* ast_app_separate_args can't handle "" */
675                                 args.channel_count = 1;
676                                 vals[0] = args.channel_parse;
677                         } else {
678                                 args.channel_count = ast_app_separate_args(
679                                         args.channel_parse, ',', vals,
680                                         ARRAY_LEN(vals));
681                         }
682
683                         if (args.channel_count == 0) {
684                                 ast_ari_response_alloc_failed(response);
685                                 goto fin;
686                         }
687
688                         if (args.channel_count >= MAX_VALS) {
689                                 ast_ari_response_error(response, 400,
690                                         "Bad Request",
691                                         "Too many values for channel");
692                                 goto fin;
693                         }
694
695                         args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
696                         if (!args.channel) {
697                                 ast_ari_response_alloc_failed(response);
698                                 goto fin;
699                         }
700
701                         for (j = 0; j < args.channel_count; ++j) {
702                                 args.channel[j] = (vals[j]);
703                         }
704                 } else
705                 {}
706         }
707         for (i = path_vars; i; i = i->next) {
708                 if (strcmp(i->name, "bridgeId") == 0) {
709                         args.bridge_id = (i->value);
710                 } else
711                 {}
712         }
713         /* Look for a JSON request entity */
714         body = ast_http_get_json(ser, headers);
715         if (!body) {
716                 switch (errno) {
717                 case EFBIG:
718                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
719                         goto fin;
720                 case ENOMEM:
721                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
722                         goto fin;
723                 case EIO:
724                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
725                         goto fin;
726                 }
727         }
728         if (ast_ari_bridges_remove_channel_parse_body(body, &args)) {
729                 ast_ari_response_alloc_failed(response);
730                 goto fin;
731         }
732         ast_ari_bridges_remove_channel(headers, &args, response);
733 #if defined(AST_DEVMODE)
734         code = response->response_code;
735
736         switch (code) {
737         case 0: /* Implementation is still a stub, or the code wasn't set */
738                 is_valid = response->message == NULL;
739                 break;
740         case 500: /* Internal Server Error */
741         case 501: /* Not Implemented */
742         case 400: /* Channel not found */
743         case 404: /* Bridge not found */
744         case 409: /* Bridge not in Stasis application */
745         case 422: /* Channel not in this bridge */
746                 is_valid = 1;
747                 break;
748         default:
749                 if (200 <= code && code <= 299) {
750                         is_valid = ast_ari_validate_void(
751                                 response->message);
752                 } else {
753                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/removeChannel\n", code);
754                         is_valid = 0;
755                 }
756         }
757
758         if (!is_valid) {
759                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/removeChannel\n");
760                 ast_ari_response_error(response, 500,
761                         "Internal Server Error", "Response validation failed");
762         }
763 #endif /* AST_DEVMODE */
764
765 fin: __attribute__((unused))
766         ast_free(args.channel_parse);
767         ast_free(args.channel);
768         return;
769 }
770 int ast_ari_bridges_start_moh_parse_body(
771         struct ast_json *body,
772         struct ast_ari_bridges_start_moh_args *args)
773 {
774         struct ast_json *field;
775         /* Parse query parameters out of it */
776         field = ast_json_object_get(body, "mohClass");
777         if (field) {
778                 args->moh_class = ast_json_string_get(field);
779         }
780         return 0;
781 }
782
783 /*!
784  * \brief Parameter parsing callback for /bridges/{bridgeId}/moh.
785  * \param get_params GET parameters in the HTTP request.
786  * \param path_vars Path variables extracted from the request.
787  * \param headers HTTP headers.
788  * \param[out] response Response to the HTTP request.
789  */
790 static void ast_ari_bridges_start_moh_cb(
791         struct ast_tcptls_session_instance *ser,
792         struct ast_variable *get_params, struct ast_variable *path_vars,
793         struct ast_variable *headers, struct ast_ari_response *response)
794 {
795         struct ast_ari_bridges_start_moh_args args = {};
796         struct ast_variable *i;
797         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
798 #if defined(AST_DEVMODE)
799         int is_valid;
800         int code;
801 #endif /* AST_DEVMODE */
802
803         for (i = get_params; i; i = i->next) {
804                 if (strcmp(i->name, "mohClass") == 0) {
805                         args.moh_class = (i->value);
806                 } else
807                 {}
808         }
809         for (i = path_vars; i; i = i->next) {
810                 if (strcmp(i->name, "bridgeId") == 0) {
811                         args.bridge_id = (i->value);
812                 } else
813                 {}
814         }
815         /* Look for a JSON request entity */
816         body = ast_http_get_json(ser, headers);
817         if (!body) {
818                 switch (errno) {
819                 case EFBIG:
820                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
821                         goto fin;
822                 case ENOMEM:
823                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
824                         goto fin;
825                 case EIO:
826                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
827                         goto fin;
828                 }
829         }
830         if (ast_ari_bridges_start_moh_parse_body(body, &args)) {
831                 ast_ari_response_alloc_failed(response);
832                 goto fin;
833         }
834         ast_ari_bridges_start_moh(headers, &args, response);
835 #if defined(AST_DEVMODE)
836         code = response->response_code;
837
838         switch (code) {
839         case 0: /* Implementation is still a stub, or the code wasn't set */
840                 is_valid = response->message == NULL;
841                 break;
842         case 500: /* Internal Server Error */
843         case 501: /* Not Implemented */
844         case 404: /* Bridge not found */
845         case 409: /* Bridge not in Stasis application */
846                 is_valid = 1;
847                 break;
848         default:
849                 if (200 <= code && code <= 299) {
850                         is_valid = ast_ari_validate_void(
851                                 response->message);
852                 } else {
853                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/moh\n", code);
854                         is_valid = 0;
855                 }
856         }
857
858         if (!is_valid) {
859                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/moh\n");
860                 ast_ari_response_error(response, 500,
861                         "Internal Server Error", "Response validation failed");
862         }
863 #endif /* AST_DEVMODE */
864
865 fin: __attribute__((unused))
866         return;
867 }
868 /*!
869  * \brief Parameter parsing callback for /bridges/{bridgeId}/moh.
870  * \param get_params GET parameters in the HTTP request.
871  * \param path_vars Path variables extracted from the request.
872  * \param headers HTTP headers.
873  * \param[out] response Response to the HTTP request.
874  */
875 static void ast_ari_bridges_stop_moh_cb(
876         struct ast_tcptls_session_instance *ser,
877         struct ast_variable *get_params, struct ast_variable *path_vars,
878         struct ast_variable *headers, struct ast_ari_response *response)
879 {
880         struct ast_ari_bridges_stop_moh_args args = {};
881         struct ast_variable *i;
882         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
883 #if defined(AST_DEVMODE)
884         int is_valid;
885         int code;
886 #endif /* AST_DEVMODE */
887
888         for (i = path_vars; i; i = i->next) {
889                 if (strcmp(i->name, "bridgeId") == 0) {
890                         args.bridge_id = (i->value);
891                 } else
892                 {}
893         }
894         ast_ari_bridges_stop_moh(headers, &args, response);
895 #if defined(AST_DEVMODE)
896         code = response->response_code;
897
898         switch (code) {
899         case 0: /* Implementation is still a stub, or the code wasn't set */
900                 is_valid = response->message == NULL;
901                 break;
902         case 500: /* Internal Server Error */
903         case 501: /* Not Implemented */
904         case 404: /* Bridge not found */
905         case 409: /* Bridge not in Stasis application */
906                 is_valid = 1;
907                 break;
908         default:
909                 if (200 <= code && code <= 299) {
910                         is_valid = ast_ari_validate_void(
911                                 response->message);
912                 } else {
913                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/moh\n", code);
914                         is_valid = 0;
915                 }
916         }
917
918         if (!is_valid) {
919                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/moh\n");
920                 ast_ari_response_error(response, 500,
921                         "Internal Server Error", "Response validation failed");
922         }
923 #endif /* AST_DEVMODE */
924
925 fin: __attribute__((unused))
926         return;
927 }
928 int ast_ari_bridges_play_parse_body(
929         struct ast_json *body,
930         struct ast_ari_bridges_play_args *args)
931 {
932         struct ast_json *field;
933         /* Parse query parameters out of it */
934         field = ast_json_object_get(body, "media");
935         if (field) {
936                 /* If they were silly enough to both pass in a query param and a
937                  * JSON body, free up the query value.
938                  */
939                 ast_free(args->media);
940                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
941                         /* Multiple param passed as array */
942                         size_t i;
943                         args->media_count = ast_json_array_size(field);
944                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
945
946                         if (!args->media) {
947                                 return -1;
948                         }
949
950                         for (i = 0; i < args->media_count; ++i) {
951                                 args->media[i] = ast_json_string_get(ast_json_array_get(field, i));
952                         }
953                 } else {
954                         /* Multiple param passed as single value */
955                         args->media_count = 1;
956                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
957                         if (!args->media) {
958                                 return -1;
959                         }
960                         args->media[0] = ast_json_string_get(field);
961                 }
962         }
963         field = ast_json_object_get(body, "lang");
964         if (field) {
965                 args->lang = ast_json_string_get(field);
966         }
967         field = ast_json_object_get(body, "offsetms");
968         if (field) {
969                 args->offsetms = ast_json_integer_get(field);
970         }
971         field = ast_json_object_get(body, "skipms");
972         if (field) {
973                 args->skipms = ast_json_integer_get(field);
974         }
975         field = ast_json_object_get(body, "playbackId");
976         if (field) {
977                 args->playback_id = ast_json_string_get(field);
978         }
979         return 0;
980 }
981
982 /*!
983  * \brief Parameter parsing callback for /bridges/{bridgeId}/play.
984  * \param get_params GET parameters in the HTTP request.
985  * \param path_vars Path variables extracted from the request.
986  * \param headers HTTP headers.
987  * \param[out] response Response to the HTTP request.
988  */
989 static void ast_ari_bridges_play_cb(
990         struct ast_tcptls_session_instance *ser,
991         struct ast_variable *get_params, struct ast_variable *path_vars,
992         struct ast_variable *headers, struct ast_ari_response *response)
993 {
994         struct ast_ari_bridges_play_args args = {};
995         struct ast_variable *i;
996         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
997 #if defined(AST_DEVMODE)
998         int is_valid;
999         int code;
1000 #endif /* AST_DEVMODE */
1001
1002         for (i = get_params; i; i = i->next) {
1003                 if (strcmp(i->name, "media") == 0) {
1004                         /* Parse comma separated list */
1005                         char *vals[MAX_VALS];
1006                         size_t j;
1007
1008                         args.media_parse = ast_strdup(i->value);
1009                         if (!args.media_parse) {
1010                                 ast_ari_response_alloc_failed(response);
1011                                 goto fin;
1012                         }
1013
1014                         if (strlen(args.media_parse) == 0) {
1015                                 /* ast_app_separate_args can't handle "" */
1016                                 args.media_count = 1;
1017                                 vals[0] = args.media_parse;
1018                         } else {
1019                                 args.media_count = ast_app_separate_args(
1020                                         args.media_parse, ',', vals,
1021                                         ARRAY_LEN(vals));
1022                         }
1023
1024                         if (args.media_count == 0) {
1025                                 ast_ari_response_alloc_failed(response);
1026                                 goto fin;
1027                         }
1028
1029                         if (args.media_count >= MAX_VALS) {
1030                                 ast_ari_response_error(response, 400,
1031                                         "Bad Request",
1032                                         "Too many values for media");
1033                                 goto fin;
1034                         }
1035
1036                         args.media = ast_malloc(sizeof(*args.media) * args.media_count);
1037                         if (!args.media) {
1038                                 ast_ari_response_alloc_failed(response);
1039                                 goto fin;
1040                         }
1041
1042                         for (j = 0; j < args.media_count; ++j) {
1043                                 args.media[j] = (vals[j]);
1044                         }
1045                 } else
1046                 if (strcmp(i->name, "lang") == 0) {
1047                         args.lang = (i->value);
1048                 } else
1049                 if (strcmp(i->name, "offsetms") == 0) {
1050                         args.offsetms = atoi(i->value);
1051                 } else
1052                 if (strcmp(i->name, "skipms") == 0) {
1053                         args.skipms = atoi(i->value);
1054                 } else
1055                 if (strcmp(i->name, "playbackId") == 0) {
1056                         args.playback_id = (i->value);
1057                 } else
1058                 {}
1059         }
1060         for (i = path_vars; i; i = i->next) {
1061                 if (strcmp(i->name, "bridgeId") == 0) {
1062                         args.bridge_id = (i->value);
1063                 } else
1064                 {}
1065         }
1066         /* Look for a JSON request entity */
1067         body = ast_http_get_json(ser, headers);
1068         if (!body) {
1069                 switch (errno) {
1070                 case EFBIG:
1071                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1072                         goto fin;
1073                 case ENOMEM:
1074                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1075                         goto fin;
1076                 case EIO:
1077                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1078                         goto fin;
1079                 }
1080         }
1081         if (ast_ari_bridges_play_parse_body(body, &args)) {
1082                 ast_ari_response_alloc_failed(response);
1083                 goto fin;
1084         }
1085         ast_ari_bridges_play(headers, &args, response);
1086 #if defined(AST_DEVMODE)
1087         code = response->response_code;
1088
1089         switch (code) {
1090         case 0: /* Implementation is still a stub, or the code wasn't set */
1091                 is_valid = response->message == NULL;
1092                 break;
1093         case 500: /* Internal Server Error */
1094         case 501: /* Not Implemented */
1095         case 404: /* Bridge not found */
1096         case 409: /* Bridge not in a Stasis application */
1097                 is_valid = 1;
1098                 break;
1099         default:
1100                 if (200 <= code && code <= 299) {
1101                         is_valid = ast_ari_validate_playback(
1102                                 response->message);
1103                 } else {
1104                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/play\n", code);
1105                         is_valid = 0;
1106                 }
1107         }
1108
1109         if (!is_valid) {
1110                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/play\n");
1111                 ast_ari_response_error(response, 500,
1112                         "Internal Server Error", "Response validation failed");
1113         }
1114 #endif /* AST_DEVMODE */
1115
1116 fin: __attribute__((unused))
1117         ast_free(args.media_parse);
1118         ast_free(args.media);
1119         return;
1120 }
1121 int ast_ari_bridges_play_with_id_parse_body(
1122         struct ast_json *body,
1123         struct ast_ari_bridges_play_with_id_args *args)
1124 {
1125         struct ast_json *field;
1126         /* Parse query parameters out of it */
1127         field = ast_json_object_get(body, "media");
1128         if (field) {
1129                 /* If they were silly enough to both pass in a query param and a
1130                  * JSON body, free up the query value.
1131                  */
1132                 ast_free(args->media);
1133                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
1134                         /* Multiple param passed as array */
1135                         size_t i;
1136                         args->media_count = ast_json_array_size(field);
1137                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
1138
1139                         if (!args->media) {
1140                                 return -1;
1141                         }
1142
1143                         for (i = 0; i < args->media_count; ++i) {
1144                                 args->media[i] = ast_json_string_get(ast_json_array_get(field, i));
1145                         }
1146                 } else {
1147                         /* Multiple param passed as single value */
1148                         args->media_count = 1;
1149                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
1150                         if (!args->media) {
1151                                 return -1;
1152                         }
1153                         args->media[0] = ast_json_string_get(field);
1154                 }
1155         }
1156         field = ast_json_object_get(body, "lang");
1157         if (field) {
1158                 args->lang = ast_json_string_get(field);
1159         }
1160         field = ast_json_object_get(body, "offsetms");
1161         if (field) {
1162                 args->offsetms = ast_json_integer_get(field);
1163         }
1164         field = ast_json_object_get(body, "skipms");
1165         if (field) {
1166                 args->skipms = ast_json_integer_get(field);
1167         }
1168         return 0;
1169 }
1170
1171 /*!
1172  * \brief Parameter parsing callback for /bridges/{bridgeId}/play/{playbackId}.
1173  * \param get_params GET parameters in the HTTP request.
1174  * \param path_vars Path variables extracted from the request.
1175  * \param headers HTTP headers.
1176  * \param[out] response Response to the HTTP request.
1177  */
1178 static void ast_ari_bridges_play_with_id_cb(
1179         struct ast_tcptls_session_instance *ser,
1180         struct ast_variable *get_params, struct ast_variable *path_vars,
1181         struct ast_variable *headers, struct ast_ari_response *response)
1182 {
1183         struct ast_ari_bridges_play_with_id_args args = {};
1184         struct ast_variable *i;
1185         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1186 #if defined(AST_DEVMODE)
1187         int is_valid;
1188         int code;
1189 #endif /* AST_DEVMODE */
1190
1191         for (i = get_params; i; i = i->next) {
1192                 if (strcmp(i->name, "media") == 0) {
1193                         /* Parse comma separated list */
1194                         char *vals[MAX_VALS];
1195                         size_t j;
1196
1197                         args.media_parse = ast_strdup(i->value);
1198                         if (!args.media_parse) {
1199                                 ast_ari_response_alloc_failed(response);
1200                                 goto fin;
1201                         }
1202
1203                         if (strlen(args.media_parse) == 0) {
1204                                 /* ast_app_separate_args can't handle "" */
1205                                 args.media_count = 1;
1206                                 vals[0] = args.media_parse;
1207                         } else {
1208                                 args.media_count = ast_app_separate_args(
1209                                         args.media_parse, ',', vals,
1210                                         ARRAY_LEN(vals));
1211                         }
1212
1213                         if (args.media_count == 0) {
1214                                 ast_ari_response_alloc_failed(response);
1215                                 goto fin;
1216                         }
1217
1218                         if (args.media_count >= MAX_VALS) {
1219                                 ast_ari_response_error(response, 400,
1220                                         "Bad Request",
1221                                         "Too many values for media");
1222                                 goto fin;
1223                         }
1224
1225                         args.media = ast_malloc(sizeof(*args.media) * args.media_count);
1226                         if (!args.media) {
1227                                 ast_ari_response_alloc_failed(response);
1228                                 goto fin;
1229                         }
1230
1231                         for (j = 0; j < args.media_count; ++j) {
1232                                 args.media[j] = (vals[j]);
1233                         }
1234                 } else
1235                 if (strcmp(i->name, "lang") == 0) {
1236                         args.lang = (i->value);
1237                 } else
1238                 if (strcmp(i->name, "offsetms") == 0) {
1239                         args.offsetms = atoi(i->value);
1240                 } else
1241                 if (strcmp(i->name, "skipms") == 0) {
1242                         args.skipms = atoi(i->value);
1243                 } else
1244                 {}
1245         }
1246         for (i = path_vars; i; i = i->next) {
1247                 if (strcmp(i->name, "bridgeId") == 0) {
1248                         args.bridge_id = (i->value);
1249                 } else
1250                 if (strcmp(i->name, "playbackId") == 0) {
1251                         args.playback_id = (i->value);
1252                 } else
1253                 {}
1254         }
1255         /* Look for a JSON request entity */
1256         body = ast_http_get_json(ser, headers);
1257         if (!body) {
1258                 switch (errno) {
1259                 case EFBIG:
1260                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1261                         goto fin;
1262                 case ENOMEM:
1263                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1264                         goto fin;
1265                 case EIO:
1266                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1267                         goto fin;
1268                 }
1269         }
1270         if (ast_ari_bridges_play_with_id_parse_body(body, &args)) {
1271                 ast_ari_response_alloc_failed(response);
1272                 goto fin;
1273         }
1274         ast_ari_bridges_play_with_id(headers, &args, response);
1275 #if defined(AST_DEVMODE)
1276         code = response->response_code;
1277
1278         switch (code) {
1279         case 0: /* Implementation is still a stub, or the code wasn't set */
1280                 is_valid = response->message == NULL;
1281                 break;
1282         case 500: /* Internal Server Error */
1283         case 501: /* Not Implemented */
1284         case 404: /* Bridge not found */
1285         case 409: /* Bridge not in a Stasis application */
1286                 is_valid = 1;
1287                 break;
1288         default:
1289                 if (200 <= code && code <= 299) {
1290                         is_valid = ast_ari_validate_playback(
1291                                 response->message);
1292                 } else {
1293                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/play/{playbackId}\n", code);
1294                         is_valid = 0;
1295                 }
1296         }
1297
1298         if (!is_valid) {
1299                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/play/{playbackId}\n");
1300                 ast_ari_response_error(response, 500,
1301                         "Internal Server Error", "Response validation failed");
1302         }
1303 #endif /* AST_DEVMODE */
1304
1305 fin: __attribute__((unused))
1306         ast_free(args.media_parse);
1307         ast_free(args.media);
1308         return;
1309 }
1310 int ast_ari_bridges_record_parse_body(
1311         struct ast_json *body,
1312         struct ast_ari_bridges_record_args *args)
1313 {
1314         struct ast_json *field;
1315         /* Parse query parameters out of it */
1316         field = ast_json_object_get(body, "name");
1317         if (field) {
1318                 args->name = ast_json_string_get(field);
1319         }
1320         field = ast_json_object_get(body, "format");
1321         if (field) {
1322                 args->format = ast_json_string_get(field);
1323         }
1324         field = ast_json_object_get(body, "maxDurationSeconds");
1325         if (field) {
1326                 args->max_duration_seconds = ast_json_integer_get(field);
1327         }
1328         field = ast_json_object_get(body, "maxSilenceSeconds");
1329         if (field) {
1330                 args->max_silence_seconds = ast_json_integer_get(field);
1331         }
1332         field = ast_json_object_get(body, "ifExists");
1333         if (field) {
1334                 args->if_exists = ast_json_string_get(field);
1335         }
1336         field = ast_json_object_get(body, "beep");
1337         if (field) {
1338                 args->beep = ast_json_is_true(field);
1339         }
1340         field = ast_json_object_get(body, "terminateOn");
1341         if (field) {
1342                 args->terminate_on = ast_json_string_get(field);
1343         }
1344         return 0;
1345 }
1346
1347 /*!
1348  * \brief Parameter parsing callback for /bridges/{bridgeId}/record.
1349  * \param get_params GET parameters in the HTTP request.
1350  * \param path_vars Path variables extracted from the request.
1351  * \param headers HTTP headers.
1352  * \param[out] response Response to the HTTP request.
1353  */
1354 static void ast_ari_bridges_record_cb(
1355         struct ast_tcptls_session_instance *ser,
1356         struct ast_variable *get_params, struct ast_variable *path_vars,
1357         struct ast_variable *headers, struct ast_ari_response *response)
1358 {
1359         struct ast_ari_bridges_record_args args = {};
1360         struct ast_variable *i;
1361         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1362 #if defined(AST_DEVMODE)
1363         int is_valid;
1364         int code;
1365 #endif /* AST_DEVMODE */
1366
1367         for (i = get_params; i; i = i->next) {
1368                 if (strcmp(i->name, "name") == 0) {
1369                         args.name = (i->value);
1370                 } else
1371                 if (strcmp(i->name, "format") == 0) {
1372                         args.format = (i->value);
1373                 } else
1374                 if (strcmp(i->name, "maxDurationSeconds") == 0) {
1375                         args.max_duration_seconds = atoi(i->value);
1376                 } else
1377                 if (strcmp(i->name, "maxSilenceSeconds") == 0) {
1378                         args.max_silence_seconds = atoi(i->value);
1379                 } else
1380                 if (strcmp(i->name, "ifExists") == 0) {
1381                         args.if_exists = (i->value);
1382                 } else
1383                 if (strcmp(i->name, "beep") == 0) {
1384                         args.beep = ast_true(i->value);
1385                 } else
1386                 if (strcmp(i->name, "terminateOn") == 0) {
1387                         args.terminate_on = (i->value);
1388                 } else
1389                 {}
1390         }
1391         for (i = path_vars; i; i = i->next) {
1392                 if (strcmp(i->name, "bridgeId") == 0) {
1393                         args.bridge_id = (i->value);
1394                 } else
1395                 {}
1396         }
1397         /* Look for a JSON request entity */
1398         body = ast_http_get_json(ser, headers);
1399         if (!body) {
1400                 switch (errno) {
1401                 case EFBIG:
1402                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1403                         goto fin;
1404                 case ENOMEM:
1405                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1406                         goto fin;
1407                 case EIO:
1408                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1409                         goto fin;
1410                 }
1411         }
1412         if (ast_ari_bridges_record_parse_body(body, &args)) {
1413                 ast_ari_response_alloc_failed(response);
1414                 goto fin;
1415         }
1416         ast_ari_bridges_record(headers, &args, response);
1417 #if defined(AST_DEVMODE)
1418         code = response->response_code;
1419
1420         switch (code) {
1421         case 0: /* Implementation is still a stub, or the code wasn't set */
1422                 is_valid = response->message == NULL;
1423                 break;
1424         case 500: /* Internal Server Error */
1425         case 501: /* Not Implemented */
1426         case 400: /* Invalid parameters */
1427         case 404: /* Bridge not found */
1428         case 409: /* Bridge is not in a Stasis application; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail */
1429         case 422: /* The format specified is unknown on this system */
1430                 is_valid = 1;
1431                 break;
1432         default:
1433                 if (200 <= code && code <= 299) {
1434                         is_valid = ast_ari_validate_live_recording(
1435                                 response->message);
1436                 } else {
1437                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/record\n", code);
1438                         is_valid = 0;
1439                 }
1440         }
1441
1442         if (!is_valid) {
1443                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/record\n");
1444                 ast_ari_response_error(response, 500,
1445                         "Internal Server Error", "Response validation failed");
1446         }
1447 #endif /* AST_DEVMODE */
1448
1449 fin: __attribute__((unused))
1450         return;
1451 }
1452
1453 /*! \brief REST handler for /api-docs/bridges.json */
1454 static struct stasis_rest_handlers bridges_bridgeId_addChannel = {
1455         .path_segment = "addChannel",
1456         .callbacks = {
1457                 [AST_HTTP_POST] = ast_ari_bridges_add_channel_cb,
1458         },
1459         .num_children = 0,
1460         .children = {  }
1461 };
1462 /*! \brief REST handler for /api-docs/bridges.json */
1463 static struct stasis_rest_handlers bridges_bridgeId_removeChannel = {
1464         .path_segment = "removeChannel",
1465         .callbacks = {
1466                 [AST_HTTP_POST] = ast_ari_bridges_remove_channel_cb,
1467         },
1468         .num_children = 0,
1469         .children = {  }
1470 };
1471 /*! \brief REST handler for /api-docs/bridges.json */
1472 static struct stasis_rest_handlers bridges_bridgeId_moh = {
1473         .path_segment = "moh",
1474         .callbacks = {
1475                 [AST_HTTP_POST] = ast_ari_bridges_start_moh_cb,
1476                 [AST_HTTP_DELETE] = ast_ari_bridges_stop_moh_cb,
1477         },
1478         .num_children = 0,
1479         .children = {  }
1480 };
1481 /*! \brief REST handler for /api-docs/bridges.json */
1482 static struct stasis_rest_handlers bridges_bridgeId_play_playbackId = {
1483         .path_segment = "playbackId",
1484         .is_wildcard = 1,
1485         .callbacks = {
1486                 [AST_HTTP_POST] = ast_ari_bridges_play_with_id_cb,
1487         },
1488         .num_children = 0,
1489         .children = {  }
1490 };
1491 /*! \brief REST handler for /api-docs/bridges.json */
1492 static struct stasis_rest_handlers bridges_bridgeId_play = {
1493         .path_segment = "play",
1494         .callbacks = {
1495                 [AST_HTTP_POST] = ast_ari_bridges_play_cb,
1496         },
1497         .num_children = 1,
1498         .children = { &bridges_bridgeId_play_playbackId, }
1499 };
1500 /*! \brief REST handler for /api-docs/bridges.json */
1501 static struct stasis_rest_handlers bridges_bridgeId_record = {
1502         .path_segment = "record",
1503         .callbacks = {
1504                 [AST_HTTP_POST] = ast_ari_bridges_record_cb,
1505         },
1506         .num_children = 0,
1507         .children = {  }
1508 };
1509 /*! \brief REST handler for /api-docs/bridges.json */
1510 static struct stasis_rest_handlers bridges_bridgeId = {
1511         .path_segment = "bridgeId",
1512         .is_wildcard = 1,
1513         .callbacks = {
1514                 [AST_HTTP_POST] = ast_ari_bridges_create_with_id_cb,
1515                 [AST_HTTP_GET] = ast_ari_bridges_get_cb,
1516                 [AST_HTTP_DELETE] = ast_ari_bridges_destroy_cb,
1517         },
1518         .num_children = 5,
1519         .children = { &bridges_bridgeId_addChannel,&bridges_bridgeId_removeChannel,&bridges_bridgeId_moh,&bridges_bridgeId_play,&bridges_bridgeId_record, }
1520 };
1521 /*! \brief REST handler for /api-docs/bridges.json */
1522 static struct stasis_rest_handlers bridges = {
1523         .path_segment = "bridges",
1524         .callbacks = {
1525                 [AST_HTTP_GET] = ast_ari_bridges_list_cb,
1526                 [AST_HTTP_POST] = ast_ari_bridges_create_cb,
1527         },
1528         .num_children = 1,
1529         .children = { &bridges_bridgeId, }
1530 };
1531
1532 static int load_module(void)
1533 {
1534         int res = 0;
1535         stasis_app_ref();
1536         res |= ast_ari_add_handler(&bridges);
1537         return res;
1538 }
1539
1540 static int unload_module(void)
1541 {
1542         ast_ari_remove_handler(&bridges);
1543         stasis_app_unref();
1544         return 0;
1545 }
1546
1547 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Bridge resources",
1548         .support_level = AST_MODULE_SUPPORT_CORE,
1549         .load = load_module,
1550         .unload = unload_module,
1551         .nonoptreq = "res_ari,res_stasis",
1552 );