diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index 0204d9dab5..51b82a9f79 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -162,7 +162,16 @@ struct http_file_context { switch_file_t *lock_fd; switch_memory_pool_t *pool; int del_on_close; - + struct { + char *dest_url; + char *params; + char *file_name; + char *profile_name; + char *file; + char *method; + char *name; + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + } write; }; typedef struct http_file_context http_file_context_t; @@ -900,7 +909,6 @@ static switch_status_t parse_record(const char *tag_name, client_t *client, swit if (!zstr(tmp_record_path) && switch_file_exists(tmp_record_path, client->pool) == SWITCH_STATUS_SUCCESS) { char *key = switch_core_sprintf(client->pool, "attach_file:%s:%s.%s", name, fname, ext); switch_event_add_header_string(client->one_time_params, SWITCH_STACK_BOTTOM, key, tmp_record_path); - status = SWITCH_STATUS_TERM; } end: @@ -1117,8 +1125,10 @@ static client_t *client_create(switch_core_session_t *session, const char *profi switch_event_create(&client->headers, SWITCH_EVENT_CLONE); - client->session = session; - client->channel = switch_core_session_get_channel(session); + if (session) { + client->session = session; + client->channel = switch_core_session_get_channel(session); + } client->profile = profile; @@ -1151,12 +1161,18 @@ static void cleanup_attachments(client_t *client) for (hp = client->params->headers; hp; hp = hp->next) { if (!strncasecmp(hp->name, "attach_file:", 12)) { if (switch_file_exists(hp->value, client->pool)) { + printf("DELETE %s\n", hp->value); unlink(hp->value); } } } } +size_t put_file_read( void *ptr, size_t size, size_t nmemb, void *userdata) +{ + return fread(ptr, size, nmemb, (FILE *) userdata); +} + static switch_status_t httapi_sync(client_t *client) { @@ -1171,7 +1187,9 @@ static switch_status_t httapi_sync(client_t *client) char *method = NULL; struct curl_httppost *formpost=NULL; switch_event_t *save_params = NULL; - + const char *put_file; + FILE *fd = NULL; + if (client->one_time_params && client->one_time_params->headers) { save_params = client->params; switch_event_dup(&client->params, save_params); @@ -1182,7 +1200,7 @@ static switch_status_t httapi_sync(client_t *client) } if (!(session_id = switch_event_get_header(client->params, "HTTAPI_SESSION_ID"))) { - if (!(session_id = switch_channel_get_variable(client->channel, "HTTAPI_SESSION_ID"))) { + if (client->channel && !(session_id = switch_channel_get_variable(client->channel, "HTTAPI_SESSION_ID"))) { session_id = switch_core_session_get_uuid(client->session); } } @@ -1207,7 +1225,17 @@ static switch_status_t httapi_sync(client_t *client) dynamic_url = switch_event_expand_headers(client->params, url); - switch_curl_process_form_post_params(client->params, curl_handle, &formpost); + if ((put_file = switch_event_get_header(client->params, "put_file"))) { + if (!(fd = fopen(put_file, "rb"))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Can't open [%s]\n", put_file); + put_file = NULL; + } + } + + if (!put_file) { + switch_curl_process_form_post_params(client->params, curl_handle, &formpost); + get_style_method = 1; + } if (formpost) { get_style_method = 1; @@ -1259,7 +1287,12 @@ static switch_status_t httapi_sync(client_t *client) switch_curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, method); } - if (formpost) { + if (put_file) { + curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curl_handle, CURLOPT_READDATA, fd); + curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, put_file_read); + + } else if (formpost) { curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost); } else { switch_curl_easy_setopt(curl_handle, CURLOPT_POST, !get_style_method); @@ -1351,6 +1384,9 @@ static switch_status_t httapi_sync(client_t *client) save_params = NULL; } + if (fd) { + fclose(fd); + } return status; } @@ -2165,30 +2201,78 @@ static switch_status_t http_file_file_open(switch_file_handle_t *handle, const c char *file_dup; switch_status_t status; - if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n"); - return SWITCH_STATUS_FALSE; - } - context = switch_core_alloc(handle->memory_pool, sizeof(*context)); context->pool = handle->memory_pool; + + if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + char *ext; + + + context->fh.channels = handle->channels; + context->fh.native_rate = handle->native_rate; + context->fh.samples = handle->samples; + context->fh.samplerate = handle->samplerate; + context->fh.prefix = handle->prefix; + + context->write.dest_url = switch_core_sprintf(context->pool, "http://%s", path); + + if ((context->write.params = strchr(context->write.dest_url, ';'))) { + *context->write.params++ = '\0'; + context->write.file_name = switch_find_parameter(context->write.params, "file", context->pool); + context->write.profile_name = switch_find_parameter(context->write.params, "profile", context->pool); + context->write.method = switch_find_parameter(context->write.params, "method", context->pool); + context->write.name = switch_find_parameter(context->write.params, "name", context->pool); + } + + if (!context->write.file_name) { + char *p; + if ((p = strrchr(context->write.dest_url, '/'))) { + p++; + context->write.file_name = switch_core_strdup(context->pool, p); + } + } + + if ((ext = strrchr(context->write.file_name, '.'))) { + ext++; + } else { + ext = "wav"; + } + + if (!context->write.profile_name) context->write.profile_name = "default"; + if (!context->write.method) context->write.method = !strcasecmp(ext, "cgi") ? "post" : "put"; + if (!context->write.name) context->write.name = "recorded_file"; + + switch_uuid_str(context->write.uuid_str, sizeof(context->write.uuid_str)); + + context->write.file = switch_core_sprintf(context->pool, "%s%s%s_%s", + SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, context->write.uuid_str, context->write.file_name); + + + if (switch_core_file_open(&context->fh, context->write.file, handle->channels, handle->samplerate, handle->flags, NULL) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_GENERR; + } + + } else { + - file_dup = switch_core_sprintf(handle->memory_pool, "http://%s", path); + file_dup = switch_core_sprintf(handle->memory_pool, "http://%s", path); + + if ((status = locate_url_file(context, file_dup)) != SWITCH_STATUS_SUCCESS) { + return status; + } + + - if ((status = locate_url_file(context, file_dup)) != SWITCH_STATUS_SUCCESS) { - return status; + if ((status = switch_core_file_open(&context->fh, + context->cache_file, + handle->channels, + handle->samplerate, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL)) != SWITCH_STATUS_SUCCESS) { + return status; + } } handle->private_info = context; - - if ((status = switch_core_file_open(&context->fh, - context->cache_file, - handle->channels, - handle->samplerate, - SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL)) != SWITCH_STATUS_SUCCESS) { - return status; - } - handle->samples = context->fh.samples; handle->format = context->fh.format; handle->sections = context->fh.sections; @@ -2212,6 +2296,38 @@ static switch_status_t http_file_file_close(switch_file_handle_t *handle) if (switch_test_flag((&context->fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&context->fh); } + + if (context->write.file) { + client_t *client; + switch_event_t *params; + char *key; + + switch_event_create(¶ms, SWITCH_EVENT_CLONE); + params->flags |= EF_UNIQ_HEADERS; + + if (!strcasecmp(context->write.method, "put")) { + switch_event_add_header(params, SWITCH_STACK_BOTTOM, "put_file", context->write.file); + } else { + key = switch_core_sprintf(context->pool, "attach_file:%s:%s", context->write.name, context->write.file_name); + switch_event_add_header(params, SWITCH_STACK_BOTTOM, key, context->write.file); + } + + switch_event_add_header(params, SWITCH_STACK_BOTTOM, "url", context->write.dest_url); + switch_event_add_header(params, SWITCH_STACK_BOTTOM, "file_driver", "true"); + switch_event_add_header(params, SWITCH_STACK_BOTTOM, "HTTAPI_SESSION_ID", context->write.uuid_str); + + if ((client = client_create(NULL, context->write.profile_name, ¶ms))) { + httapi_sync(client); + client_destroy(&client); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find suitable profile\n"); + switch_event_destroy(¶ms); + } + + unlink(context->write.file); + return SWITCH_STATUS_SUCCESS; + } + if (context->del_on_close) { if (context->cache_file) { @@ -2224,6 +2340,14 @@ static switch_status_t http_file_file_close(switch_file_handle_t *handle) return SWITCH_STATUS_SUCCESS; } + +static switch_status_t http_file_write(switch_file_handle_t *handle, void *data, size_t *len) +{ + http_file_context_t *context = handle->private_info; + + return switch_core_file_write(&context->fh, data, len); +} + static switch_status_t http_file_file_read(switch_file_handle_t *handle, void *data, size_t *len) { http_file_context_t *context = handle->private_info; @@ -2276,6 +2400,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_httapi_load) file_interface->file_open = http_file_file_open; file_interface->file_close = http_file_file_close; file_interface->file_read = http_file_file_read; + file_interface->file_write = http_file_write; file_interface->file_seek = http_file_file_seek; switch_snprintf(globals.cache_path, sizeof(globals.cache_path), "%s%shttp_file_cache", SWITCH_GLOBAL_dirs.storage_dir, SWITCH_PATH_SEPARATOR);