Multiple revisions 420089-420090,420097
[asterisk/asterisk.git] / res / res_ari_endpoints.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 Endpoint 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_stasis</depend>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include "asterisk/app.h"
45 #include "asterisk/module.h"
46 #include "asterisk/stasis_app.h"
47 #include "ari/resource_endpoints.h"
48 #if defined(AST_DEVMODE)
49 #include "ari/ari_model_validators.h"
50 #endif
51
52 #define MAX_VALS 128
53
54 /*!
55  * \brief Parameter parsing callback for /endpoints.
56  * \param get_params GET parameters in the HTTP request.
57  * \param path_vars Path variables extracted from the request.
58  * \param headers HTTP headers.
59  * \param[out] response Response to the HTTP request.
60  */
61 static void ast_ari_endpoints_list_cb(
62         struct ast_tcptls_session_instance *ser,
63         struct ast_variable *get_params, struct ast_variable *path_vars,
64         struct ast_variable *headers, struct ast_ari_response *response)
65 {
66         struct ast_ari_endpoints_list_args args = {};
67         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
68 #if defined(AST_DEVMODE)
69         int is_valid;
70         int code;
71 #endif /* AST_DEVMODE */
72
73         ast_ari_endpoints_list(headers, &args, response);
74 #if defined(AST_DEVMODE)
75         code = response->response_code;
76
77         switch (code) {
78         case 0: /* Implementation is still a stub, or the code wasn't set */
79                 is_valid = response->message == NULL;
80                 break;
81         case 500: /* Internal Server Error */
82         case 501: /* Not Implemented */
83                 is_valid = 1;
84                 break;
85         default:
86                 if (200 <= code && code <= 299) {
87                         is_valid = ast_ari_validate_list(response->message,
88                                 ast_ari_validate_endpoint_fn());
89                 } else {
90                         ast_log(LOG_ERROR, "Invalid error response %d for /endpoints\n", code);
91                         is_valid = 0;
92                 }
93         }
94
95         if (!is_valid) {
96                 ast_log(LOG_ERROR, "Response validation failed for /endpoints\n");
97                 ast_ari_response_error(response, 500,
98                         "Internal Server Error", "Response validation failed");
99         }
100 #endif /* AST_DEVMODE */
101
102 fin: __attribute__((unused))
103         return;
104 }
105 int ast_ari_endpoints_send_message_parse_body(
106         struct ast_json *body,
107         struct ast_ari_endpoints_send_message_args *args)
108 {
109         struct ast_json *field;
110         /* Parse query parameters out of it */
111         field = ast_json_object_get(body, "to");
112         if (field) {
113                 args->to = ast_json_string_get(field);
114         }
115         field = ast_json_object_get(body, "from");
116         if (field) {
117                 args->from = ast_json_string_get(field);
118         }
119         field = ast_json_object_get(body, "body");
120         if (field) {
121                 args->body = ast_json_string_get(field);
122         }
123         return 0;
124 }
125
126 /*!
127  * \brief Parameter parsing callback for /endpoints/sendMessage.
128  * \param get_params GET parameters in the HTTP request.
129  * \param path_vars Path variables extracted from the request.
130  * \param headers HTTP headers.
131  * \param[out] response Response to the HTTP request.
132  */
133 static void ast_ari_endpoints_send_message_cb(
134         struct ast_tcptls_session_instance *ser,
135         struct ast_variable *get_params, struct ast_variable *path_vars,
136         struct ast_variable *headers, struct ast_ari_response *response)
137 {
138         struct ast_ari_endpoints_send_message_args args = {};
139         struct ast_variable *i;
140         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
141 #if defined(AST_DEVMODE)
142         int is_valid;
143         int code;
144 #endif /* AST_DEVMODE */
145
146         for (i = get_params; i; i = i->next) {
147                 if (strcmp(i->name, "to") == 0) {
148                         args.to = (i->value);
149                 } else
150                 if (strcmp(i->name, "from") == 0) {
151                         args.from = (i->value);
152                 } else
153                 if (strcmp(i->name, "body") == 0) {
154                         args.body = (i->value);
155                 } else
156                 {}
157         }
158         /* Look for a JSON request entity */
159         body = ast_http_get_json(ser, headers);
160         if (!body) {
161                 switch (errno) {
162                 case EFBIG:
163                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
164                         goto fin;
165                 case ENOMEM:
166                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
167                         goto fin;
168                 case EIO:
169                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
170                         goto fin;
171                 }
172         }
173         args.variables = ast_json_ref(body);
174         ast_ari_endpoints_send_message(headers, &args, response);
175 #if defined(AST_DEVMODE)
176         code = response->response_code;
177
178         switch (code) {
179         case 0: /* Implementation is still a stub, or the code wasn't set */
180                 is_valid = response->message == NULL;
181                 break;
182         case 500: /* Internal Server Error */
183         case 501: /* Not Implemented */
184         case 404: /* Endpoint not found */
185                 is_valid = 1;
186                 break;
187         default:
188                 if (200 <= code && code <= 299) {
189                         is_valid = ast_ari_validate_void(
190                                 response->message);
191                 } else {
192                         ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/sendMessage\n", code);
193                         is_valid = 0;
194                 }
195         }
196
197         if (!is_valid) {
198                 ast_log(LOG_ERROR, "Response validation failed for /endpoints/sendMessage\n");
199                 ast_ari_response_error(response, 500,
200                         "Internal Server Error", "Response validation failed");
201         }
202 #endif /* AST_DEVMODE */
203
204 fin: __attribute__((unused))
205         return;
206 }
207 /*!
208  * \brief Parameter parsing callback for /endpoints/{tech}.
209  * \param get_params GET parameters in the HTTP request.
210  * \param path_vars Path variables extracted from the request.
211  * \param headers HTTP headers.
212  * \param[out] response Response to the HTTP request.
213  */
214 static void ast_ari_endpoints_list_by_tech_cb(
215         struct ast_tcptls_session_instance *ser,
216         struct ast_variable *get_params, struct ast_variable *path_vars,
217         struct ast_variable *headers, struct ast_ari_response *response)
218 {
219         struct ast_ari_endpoints_list_by_tech_args args = {};
220         struct ast_variable *i;
221         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
222 #if defined(AST_DEVMODE)
223         int is_valid;
224         int code;
225 #endif /* AST_DEVMODE */
226
227         for (i = path_vars; i; i = i->next) {
228                 if (strcmp(i->name, "tech") == 0) {
229                         args.tech = (i->value);
230                 } else
231                 {}
232         }
233         ast_ari_endpoints_list_by_tech(headers, &args, response);
234 #if defined(AST_DEVMODE)
235         code = response->response_code;
236
237         switch (code) {
238         case 0: /* Implementation is still a stub, or the code wasn't set */
239                 is_valid = response->message == NULL;
240                 break;
241         case 500: /* Internal Server Error */
242         case 501: /* Not Implemented */
243         case 404: /* Endpoints not found */
244                 is_valid = 1;
245                 break;
246         default:
247                 if (200 <= code && code <= 299) {
248                         is_valid = ast_ari_validate_list(response->message,
249                                 ast_ari_validate_endpoint_fn());
250                 } else {
251                         ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}\n", code);
252                         is_valid = 0;
253                 }
254         }
255
256         if (!is_valid) {
257                 ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}\n");
258                 ast_ari_response_error(response, 500,
259                         "Internal Server Error", "Response validation failed");
260         }
261 #endif /* AST_DEVMODE */
262
263 fin: __attribute__((unused))
264         return;
265 }
266 /*!
267  * \brief Parameter parsing callback for /endpoints/{tech}/{resource}.
268  * \param get_params GET parameters in the HTTP request.
269  * \param path_vars Path variables extracted from the request.
270  * \param headers HTTP headers.
271  * \param[out] response Response to the HTTP request.
272  */
273 static void ast_ari_endpoints_get_cb(
274         struct ast_tcptls_session_instance *ser,
275         struct ast_variable *get_params, struct ast_variable *path_vars,
276         struct ast_variable *headers, struct ast_ari_response *response)
277 {
278         struct ast_ari_endpoints_get_args args = {};
279         struct ast_variable *i;
280         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
281 #if defined(AST_DEVMODE)
282         int is_valid;
283         int code;
284 #endif /* AST_DEVMODE */
285
286         for (i = path_vars; i; i = i->next) {
287                 if (strcmp(i->name, "tech") == 0) {
288                         args.tech = (i->value);
289                 } else
290                 if (strcmp(i->name, "resource") == 0) {
291                         args.resource = (i->value);
292                 } else
293                 {}
294         }
295         ast_ari_endpoints_get(headers, &args, response);
296 #if defined(AST_DEVMODE)
297         code = response->response_code;
298
299         switch (code) {
300         case 0: /* Implementation is still a stub, or the code wasn't set */
301                 is_valid = response->message == NULL;
302                 break;
303         case 500: /* Internal Server Error */
304         case 501: /* Not Implemented */
305         case 400: /* Invalid parameters for sending a message. */
306         case 404: /* Endpoints not found */
307                 is_valid = 1;
308                 break;
309         default:
310                 if (200 <= code && code <= 299) {
311                         is_valid = ast_ari_validate_endpoint(
312                                 response->message);
313                 } else {
314                         ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}/{resource}\n", code);
315                         is_valid = 0;
316                 }
317         }
318
319         if (!is_valid) {
320                 ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}/{resource}\n");
321                 ast_ari_response_error(response, 500,
322                         "Internal Server Error", "Response validation failed");
323         }
324 #endif /* AST_DEVMODE */
325
326 fin: __attribute__((unused))
327         return;
328 }
329 int ast_ari_endpoints_send_message_to_endpoint_parse_body(
330         struct ast_json *body,
331         struct ast_ari_endpoints_send_message_to_endpoint_args *args)
332 {
333         struct ast_json *field;
334         /* Parse query parameters out of it */
335         field = ast_json_object_get(body, "from");
336         if (field) {
337                 args->from = ast_json_string_get(field);
338         }
339         field = ast_json_object_get(body, "body");
340         if (field) {
341                 args->body = ast_json_string_get(field);
342         }
343         return 0;
344 }
345
346 /*!
347  * \brief Parameter parsing callback for /endpoints/{tech}/{resource}/sendMessage.
348  * \param get_params GET parameters in the HTTP request.
349  * \param path_vars Path variables extracted from the request.
350  * \param headers HTTP headers.
351  * \param[out] response Response to the HTTP request.
352  */
353 static void ast_ari_endpoints_send_message_to_endpoint_cb(
354         struct ast_tcptls_session_instance *ser,
355         struct ast_variable *get_params, struct ast_variable *path_vars,
356         struct ast_variable *headers, struct ast_ari_response *response)
357 {
358         struct ast_ari_endpoints_send_message_to_endpoint_args args = {};
359         struct ast_variable *i;
360         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
361 #if defined(AST_DEVMODE)
362         int is_valid;
363         int code;
364 #endif /* AST_DEVMODE */
365
366         for (i = get_params; i; i = i->next) {
367                 if (strcmp(i->name, "from") == 0) {
368                         args.from = (i->value);
369                 } else
370                 if (strcmp(i->name, "body") == 0) {
371                         args.body = (i->value);
372                 } else
373                 {}
374         }
375         for (i = path_vars; i; i = i->next) {
376                 if (strcmp(i->name, "tech") == 0) {
377                         args.tech = (i->value);
378                 } else
379                 if (strcmp(i->name, "resource") == 0) {
380                         args.resource = (i->value);
381                 } else
382                 {}
383         }
384         /* Look for a JSON request entity */
385         body = ast_http_get_json(ser, headers);
386         if (!body) {
387                 switch (errno) {
388                 case EFBIG:
389                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
390                         goto fin;
391                 case ENOMEM:
392                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
393                         goto fin;
394                 case EIO:
395                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
396                         goto fin;
397                 }
398         }
399         args.variables = ast_json_ref(body);
400         ast_ari_endpoints_send_message_to_endpoint(headers, &args, response);
401 #if defined(AST_DEVMODE)
402         code = response->response_code;
403
404         switch (code) {
405         case 0: /* Implementation is still a stub, or the code wasn't set */
406                 is_valid = response->message == NULL;
407                 break;
408         case 500: /* Internal Server Error */
409         case 501: /* Not Implemented */
410         case 400: /* Invalid parameters for sending a message. */
411         case 404: /* Endpoint not found */
412                 is_valid = 1;
413                 break;
414         default:
415                 if (200 <= code && code <= 299) {
416                         is_valid = ast_ari_validate_void(
417                                 response->message);
418                 } else {
419                         ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}/{resource}/sendMessage\n", code);
420                         is_valid = 0;
421                 }
422         }
423
424         if (!is_valid) {
425                 ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}/{resource}/sendMessage\n");
426                 ast_ari_response_error(response, 500,
427                         "Internal Server Error", "Response validation failed");
428         }
429 #endif /* AST_DEVMODE */
430
431 fin: __attribute__((unused))
432         return;
433 }
434
435 /*! \brief REST handler for /api-docs/endpoints.{format} */
436 static struct stasis_rest_handlers endpoints_sendMessage = {
437         .path_segment = "sendMessage",
438         .callbacks = {
439                 [AST_HTTP_PUT] = ast_ari_endpoints_send_message_cb,
440         },
441         .num_children = 0,
442         .children = {  }
443 };
444 /*! \brief REST handler for /api-docs/endpoints.{format} */
445 static struct stasis_rest_handlers endpoints_tech_resource_sendMessage = {
446         .path_segment = "sendMessage",
447         .callbacks = {
448                 [AST_HTTP_PUT] = ast_ari_endpoints_send_message_to_endpoint_cb,
449         },
450         .num_children = 0,
451         .children = {  }
452 };
453 /*! \brief REST handler for /api-docs/endpoints.{format} */
454 static struct stasis_rest_handlers endpoints_tech_resource = {
455         .path_segment = "resource",
456         .is_wildcard = 1,
457         .callbacks = {
458                 [AST_HTTP_GET] = ast_ari_endpoints_get_cb,
459         },
460         .num_children = 1,
461         .children = { &endpoints_tech_resource_sendMessage, }
462 };
463 /*! \brief REST handler for /api-docs/endpoints.{format} */
464 static struct stasis_rest_handlers endpoints_tech = {
465         .path_segment = "tech",
466         .is_wildcard = 1,
467         .callbacks = {
468                 [AST_HTTP_GET] = ast_ari_endpoints_list_by_tech_cb,
469         },
470         .num_children = 1,
471         .children = { &endpoints_tech_resource, }
472 };
473 /*! \brief REST handler for /api-docs/endpoints.{format} */
474 static struct stasis_rest_handlers endpoints = {
475         .path_segment = "endpoints",
476         .callbacks = {
477                 [AST_HTTP_GET] = ast_ari_endpoints_list_cb,
478         },
479         .num_children = 2,
480         .children = { &endpoints_sendMessage,&endpoints_tech, }
481 };
482
483 static int load_module(void)
484 {
485         int res = 0;
486         stasis_app_ref();
487         res |= ast_ari_add_handler(&endpoints);
488         return res;
489 }
490
491 static int unload_module(void)
492 {
493         ast_ari_remove_handler(&endpoints);
494         stasis_app_unref();
495         return 0;
496 }
497
498 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Endpoint resources",
499         .support_level = AST_MODULE_SUPPORT_CORE,
500         .load = load_module,
501         .unload = unload_module,
502         .nonoptreq = "res_ari,res_stasis",
503         );