From 01decbf434ea323c155fec5e863f5e51e55bad97 Mon Sep 17 00:00:00 2001 From: Luis Azedo Date: Mon, 5 Dec 2016 08:09:35 +0000 Subject: [PATCH] FS-9813 [mod_kazoo] add kz_http_put --- .../event_handlers/mod_kazoo/kazoo_commands.c | 172 ++++++++++++++++++ src/mod/event_handlers/mod_kazoo/kazoo_node.c | 2 +- .../event_handlers/mod_kazoo/kazoo_utils.c | 7 +- src/mod/event_handlers/mod_kazoo/mod_kazoo.h | 3 +- 4 files changed, 181 insertions(+), 3 deletions(-) diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_commands.c b/src/mod/event_handlers/mod_kazoo/kazoo_commands.c index 4de71398f4..736d14fc18 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_commands.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_commands.c @@ -31,6 +31,7 @@ * */ #include "mod_kazoo.h" +#include #define UUID_SET_DESC "Set a variable" #define UUID_SET_SYNTAX " [value]" @@ -38,6 +39,9 @@ #define UUID_MULTISET_DESC "Set multiple variables" #define UUID_MULTISET_SYNTAX " =;=..." +#define KZ_HTTP_PUT_DESC "upload a local freeswitch file to a url" +#define KZ_HTTP_PUT_SYNTAX "localfile url" + SWITCH_STANDARD_API(uuid_setvar_function) { switch_core_session_t *psession = NULL; char *mycmd = NULL, *argv[3] = { 0 }; @@ -144,9 +148,177 @@ SWITCH_STANDARD_API(uuid_setvar_multi_function) { return SWITCH_STATUS_SUCCESS; } +static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) +{ + switch_event_t* event = (switch_event_t*)userdata; + int len = strlen(buffer); + char buf[1024]; + if(len > 2 && len < 1024) { + strncpy(buf, buffer, len-2); + buf[len-2] = '\0'; + switch_event_add_header_string(event, SWITCH_STACK_PUSH | SWITCH_STACK_BOTTOM, "Reply-Headers", buf); + } + return nitems * size; +} + +SWITCH_STANDARD_API(kz_http_put) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_memory_pool_t *lpool = NULL; + switch_memory_pool_t *pool = NULL; + char *args = NULL; + char *argv[10] = { 0 }; + int argc = 0; + switch_event_t *params = NULL; + char *url = NULL; + char *filename = NULL; + + switch_curl_slist_t *headers = NULL; /* optional linked-list of HTTP headers */ + char *ext; /* file extension, used for MIME type identification */ + const char *mime_type = "application/octet-stream"; + char *buf = NULL; + char *error = NULL; + + CURL *curl_handle = NULL; + long httpRes = 0; + struct stat file_info = {0}; + FILE *file_to_put = NULL; + int fd; + + if (session) { + pool = switch_core_session_get_pool(session); + } else { + switch_core_new_memory_pool(&lpool); + pool = lpool; + } + + if (zstr(cmd)) { + stream->write_function(stream, "USAGE: %s\n", KZ_HTTP_PUT_SYNTAX); + status = SWITCH_STATUS_SUCCESS; + goto done; + } + + args = strdup(cmd); + argc = switch_separate_string(args, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (argc != 2) { + stream->write_function(stream, "USAGE: %s\n", KZ_HTTP_PUT_SYNTAX); + status = SWITCH_STATUS_SUCCESS; + goto done; + } + + /* parse params and get profile */ + url = switch_core_strdup(pool, argv[0]); + if (*url == '{') { + switch_event_create_brackets(url, '{', '}', ',', ¶ms, &url, SWITCH_FALSE); + } + + filename = switch_core_strdup(pool, argv[1]); + + /* guess what type of mime content this is going to be */ + if ((ext = strrchr(filename, '.'))) { + ext++; + if (!(mime_type = switch_core_mime_ext2type(ext))) { + mime_type = "application/octet-stream"; + } + } + + buf = switch_mprintf("Content-Type: %s", mime_type); + + headers = switch_curl_slist_append(headers, buf); + + /* open file and get the file size */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "opening %s for upload to %s\n", filename, url); + fd = open(filename, O_RDONLY); + if (fd == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open() error: %s\n", strerror(errno)); + status = SWITCH_STATUS_FALSE; + stream->write_function(stream, "-ERR error opening file\n"); + goto done; + } + if (fstat(fd, &file_info) == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "fstat() error: %s\n", strerror(errno)); + stream->write_function(stream, "-ERR fstat error\n"); + goto done; + } + close(fd); + + /* libcurl requires FILE* */ + file_to_put = fopen(filename, "rb"); + if (!file_to_put) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "fopen() error: %s\n", strerror(errno)); + status = SWITCH_STATUS_FALSE; + goto done; + } + + curl_handle = switch_curl_easy_init(); + if (!curl_handle) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_curl_easy_init() failure\n"); + status = SWITCH_STATUS_FALSE; + stream->write_function(stream, "-ERR switch_curl_easy init failure\n"); + goto done; + } + switch_curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_PUT, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); + switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url); + switch_curl_easy_setopt(curl_handle, CURLOPT_READDATA, file_to_put); + switch_curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); + switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); + switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-http-cache/1.0"); + switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, stream->param_event); + switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + switch_curl_easy_perform(curl_handle); + switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); + switch_curl_easy_cleanup(curl_handle); + + if (httpRes == 200 || httpRes == 201 || httpRes == 202 || httpRes == 204) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s saved to %s\n", filename, url); + switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-Output", "%s saved to %s\n", filename, url); + stream->write_function(stream, "+OK\n"); + } else { + error = switch_mprintf("Received HTTP error %ld trying to save %s to %s", httpRes, filename, url); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", error); + switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-Error", "%s", error); + switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-HTTP-Error", "%ld", httpRes); + stream->write_function(stream, "-ERR "); + stream->write_function(stream, error); + stream->write_function(stream, "\n"); + status = SWITCH_STATUS_GENERR; + } + +done: + if (file_to_put) { + fclose(file_to_put); + } + + if (headers) { + switch_curl_slist_free_all(headers); + } + + switch_safe_free(buf); + switch_safe_free(error); + + switch_safe_free(args); + + if (lpool) { + switch_core_destroy_memory_pool(&lpool); + } + + if (params) { + switch_event_destroy(¶ms); + } + + return status; +} + void add_kz_commands(switch_loadable_module_interface_t **module_interface, switch_api_interface_t *api_interface) { SWITCH_ADD_API(api_interface, "kz_uuid_setvar_multi", UUID_SET_DESC, uuid_setvar_multi_function, UUID_MULTISET_SYNTAX); switch_console_set_complete("add kz_uuid_setvar_multi ::console::list_uuid"); SWITCH_ADD_API(api_interface, "kz_uuid_setvar", UUID_MULTISET_DESC, uuid_setvar_function, UUID_SET_SYNTAX); switch_console_set_complete("add kz_uuid_setvar ::console::list_uuid"); + SWITCH_ADD_API(api_interface, "kz_http_put", KZ_HTTP_PUT_DESC, kz_http_put, KZ_HTTP_PUT_SYNTAX); } + diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_node.c b/src/mod/event_handlers/mod_kazoo/kazoo_node.c index ac3a42ee3a..cf7f044346 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_node.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_node.c @@ -377,7 +377,7 @@ static void *SWITCH_THREAD_FUNC bgapi4_exec(switch_thread_t *thread, void *obj) _ei_x_encode_string(&send_msg->buf, reply); if (stream.param_event) { - ei_encode_switch_event_headers(&send_msg->buf, stream.param_event); + ei_encode_switch_event_headers_2(&send_msg->buf, stream.param_event, 0); } if (switch_queue_trypush(ei_node->send_msgs, send_msg) != SWITCH_STATUS_SUCCESS) { diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_utils.c b/src/mod/event_handlers/mod_kazoo/kazoo_utils.c index 5f6e4bf78c..d7ed341048 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_utils.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_utils.c @@ -84,6 +84,10 @@ static void ei_x_print_msg(ei_x_buff *buf, erlang_pid *pid, int send) { #endif void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event) { + ei_encode_switch_event_headers_2(ebuf, event, 1); +} + +void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int encode) { switch_event_header_t *hp; char *uuid = switch_event_get_header(event, "unique-id"); int i; @@ -105,7 +109,8 @@ void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event) { for (hp = event->headers; hp; hp = hp->next) { ei_x_encode_tuple_header(ebuf, 2); ei_x_encode_binary(ebuf, hp->name, strlen(hp->name)); - switch_url_decode(hp->value); + if(encode) + switch_url_decode(hp->value); ei_x_encode_binary(ebuf, hp->value, strlen(hp->value)); } diff --git a/src/mod/event_handlers/mod_kazoo/mod_kazoo.h b/src/mod/event_handlers/mod_kazoo/mod_kazoo.h index e2a23134ba..8c41dc6402 100644 --- a/src/mod/event_handlers/mod_kazoo/mod_kazoo.h +++ b/src/mod/event_handlers/mod_kazoo/mod_kazoo.h @@ -11,7 +11,7 @@ #define MAX_QUEUE_LEN 25000 #define MAX_MISSED 500 #define MAX_PID_CHARS 255 -#define VERSION "mod_kazoo v1.3.0-1" +#define VERSION "mod_kazoo v1.4.0-1" #define API_COMMAND_DISCONNECT 0 #define API_COMMAND_REMOTE_IP 1 @@ -153,6 +153,7 @@ switch_socket_t *create_socket(switch_memory_pool_t *pool); switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode); switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2); void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event); +void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int decode); void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to); void ei_encode_switch_event(ei_x_buff * ebuf, switch_event_t *event); int ei_helper_send(ei_node_t *ei_node, erlang_pid* to, ei_x_buff *buf);