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