void ei_encode_switch_event_headers(ei_x_buff * ebuf, switch_event_t *event) { int i; char *uuid = switch_event_get_header(event, "unique-id"); switch_event_header_t *hp; for (i = 0, hp = event->headers; hp; hp = hp->next, i++); if (event->body) i++; ei_x_encode_list_header(ebuf, i + 1); if (uuid) { _ei_x_encode_string(ebuf, switch_event_get_header(event, "unique-id")); } else { ei_x_encode_atom(ebuf, "undefined"); } for (hp = event->headers; hp; hp = hp->next) { ei_x_encode_tuple_header(ebuf, 2); _ei_x_encode_string(ebuf, hp->name); switch_url_decode(hp->value); _ei_x_encode_string(ebuf, hp->value); } if (event->body) { ei_x_encode_tuple_header(ebuf, 2); _ei_x_encode_string(ebuf, "body"); _ei_x_encode_string(ebuf, event->body); } ei_x_encode_empty_list(ebuf); }
void xpass_encode_switch_event_headers(char *ebuf, int buf_len, switch_event_t *event) { switch_event_header_t *hp; char *uuid = switch_event_get_header(event, "unique-id"); int i; int left_buf_len = buf_len; char * tmp = ebuf; for (i = 0, hp = event->headers; hp; hp = hp->next, i++); if (event->body) i++; if (uuid) { char *unique_id = switch_event_get_header(event, "unique-id"); tmp = encode_data(tmp, unique_id, strlen(unique_id)); } else { tmp = encode_data(tmp, "undefined", 9); } tmp = encode_data(tmp, "\r\n", 2); for (hp = event->headers; hp; hp = hp->next) { tmp = encode_data(tmp, hp->name, strlen(hp->name)); tmp = encode_data(tmp, ":", 1); switch_url_decode(hp->value); tmp = encode_data(tmp, hp->value, strlen(hp->value)); tmp = encode_data(tmp, "\r\n", 2); } tmp = encode_data(tmp, "\r\n", 2); if (event->body) { tmp = encode_data(tmp, event->body, strlen(event->body)); } }
// This function and do_lookup_url functions could possibly be merged together. Or at least have do_lookup_url call this up as part of the initialization routine as it is a subset of the operations. static void http_sendfile_initialize_curl(http_sendfile_data_t *http_data) { uint8_t count; http_data->curl_handle = curl_easy_init(); if (!strncasecmp(http_data->url, "https", 5)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", http_data->url); curl_easy_setopt(http_data->curl_handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(http_data->curl_handle, CURLOPT_SSL_VERIFYHOST, 0); } /* From the docs: * Optionally, you can provide data to POST using the CURLOPT_READFUNCTION and CURLOPT_READDATA * options but then you must make sure to not set CURLOPT_POSTFIELDS to anything but NULL * curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(data)); * curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, (void *) data); */ // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Post data: %s\n", data); curl_easy_setopt(http_data->curl_handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(http_data->curl_handle, CURLOPT_MAXREDIRS, 15); curl_easy_setopt(http_data->curl_handle, CURLOPT_URL, http_data->url); curl_easy_setopt(http_data->curl_handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(http_data->curl_handle, CURLOPT_USERAGENT, "freeswitch-curl/1.0"); http_data->sendfile_response = switch_core_alloc(http_data->pool, sizeof(char) * HTTP_SENDFILE_RESPONSE_SIZE); memset(http_data->sendfile_response, 0, sizeof(char) * HTTP_SENDFILE_RESPONSE_SIZE); // Set the function where we will copy out the response body data to curl_easy_setopt(http_data->curl_handle, CURLOPT_WRITEFUNCTION, http_sendfile_response_callback); curl_easy_setopt(http_data->curl_handle, CURLOPT_WRITEDATA, (void *) http_data); /* Add the file to upload as a POST form field */ curl_formadd(&http_data->formpost, &http_data->lastptr, CURLFORM_COPYNAME, http_data->filename_element_name, CURLFORM_FILE, http_data->filename_element, CURLFORM_END); if(!zstr(http_data->extrapost_elements)) { // Now to parse out the individual post element/value pairs char *argv[64] = { 0 }; // Probably don't need 64 but eh does it really use that much memory? uint32_t argc = 0; char *temp_extrapost = switch_core_strdup(http_data->pool, http_data->extrapost_elements); argc = switch_separate_string(temp_extrapost, '&', argv, (sizeof(argv) / sizeof(argv[0]))); for(count = 0; count < argc; count++) { char *argv2[4] = { 0 }; uint32_t argc2 = switch_separate_string(argv[count], '=', argv2, (sizeof(argv2) / sizeof(argv2[0]))); if(argc2 == 2) { switch_url_decode(argv2[0]); switch_url_decode(argv2[1]); curl_formadd(&http_data->formpost, &http_data->lastptr, CURLFORM_COPYNAME, argv2[0], CURLFORM_COPYCONTENTS, argv2[1], CURLFORM_END); } } } /* Fill in the submit field too, even if this isn't really needed */ curl_formadd(&http_data->formpost, &http_data->lastptr, CURLFORM_COPYNAME, "submit", CURLFORM_COPYCONTENTS, "or_die", CURLFORM_END); /* what URL that receives this POST */ curl_easy_setopt(http_data->curl_handle, CURLOPT_HTTPPOST, http_data->formpost); // This part actually fires off the curl, captures the HTTP response code, and then frees up the handle. curl_easy_perform(http_data->curl_handle); curl_easy_getinfo(http_data->curl_handle, CURLINFO_RESPONSE_CODE, &http_data->http_response_code); curl_easy_cleanup(http_data->curl_handle); // Clean up the form data from POST curl_formfree(http_data->formpost); }
abyss_bool handler_hook(TSession * r) { switch_stream_handle_t stream = { 0 }; char *command; int i; char *fs_user = NULL, *fs_domain = NULL; char *path_info = NULL; abyss_bool ret = TRUE; int html = 0, text = 0, xml = 0, api = 0; const char *api_str; const char *uri = 0; TRequestInfo *info = 0; switch_event_t *evnt = 0; /* shortcut to stream.param_event */ if (!r || !(info = &r->requestInfo) || !(uri = info->uri)) { return FALSE; } stream.data = r; stream.write_function = http_stream_write; stream.raw_write_function = http_stream_raw_write; if ((command = strstr(uri, "/api/"))) { command += 5; api++; } else if ((command = strstr(uri, "/webapi/"))) { command += 8; html++; } else if ((command = strstr(uri, "/txtapi/"))) { command += 8; text++; } else if ((command = strstr(uri, "/xmlapi/"))) { command += 8; xml++; } else { return FALSE; /* 404 */ } if ((path_info = strchr(command, '/'))) { *path_info++ = '\0'; } for (i = 0; i < r->responseHeaderFields.size; i++) { TTableItem *ti = &r->responseHeaderFields.item[i]; if (!strcasecmp(ti->name, "freeswitch-user")) { fs_user = ti->value; } else if (!strcasecmp(ti->name, "freeswitch-domain")) { fs_domain = ti->value; } } if (!is_authorized(r, command)) { ret = TRUE; goto end; } /* auth: */ if (switch_event_create(&stream.param_event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) { const char *const content_length = RequestHeaderValue(r, "content-length"); evnt = stream.param_event; if (html) { switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/html"); } else if (text) { switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/plain"); } else if (xml) { switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/xml"); } if (api) { switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-API", "api"); } if (fs_user) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", fs_user); if (fs_domain) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", fs_domain); if (path_info) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", path_info); if (info->host) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-HOST", info->host); if (info->from) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-FROM", info->from); if (info->useragent) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-USER-AGENT", info->useragent); if (info->referer) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-REFERER", info->referer); if (info->requestline) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-REQUESTLINE", info->requestline); if (info->user) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-USER", info->user); if (info->port) switch_event_add_header(evnt, SWITCH_STACK_BOTTOM, "HTTP-PORT", "%u", info->port); { char *q, *qd; char *next; char *query = (char *) info->query; char *name, *val; char qbuf[8192] = ""; /* first finish reading from the socket if post method was used*/ if (info->method == m_post && content_length) { int len = atoi(content_length); int qlen = 0; if (len > 0) { int succeeded = TRUE; char *qp = qbuf; char *readError; do { int blen = r->connP->buffersize - r->connP->bufferpos; if ((qlen + blen) > len) { blen = len - qlen; } qlen += blen; if (qlen > sizeof(qbuf)) { break; } memcpy(qp, r->connP->buffer.b + r->connP->bufferpos, blen); qp += blen; if (qlen >= len) { break; } ConnRead(r->connP, 2000, NULL, NULL, &readError); if (readError) { succeeded = FALSE; free(readError); } } while (succeeded); query = qbuf; } } /* parse query and add kv-pairs as event headers */ /* a kv pair starts with '&', '+' or \0 mark the end */ if (query) { switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-QUERY", query); qd = strdup(query); } else { qd = strdup(uri); } switch_assert(qd != NULL); q = qd; next = q; do { char *p; if (next = strchr(next, '&')) { if (!query) { /* pass kv pairs from uri to query */ /* "?" is absent in url so parse uri */ *((char *)uri + (next - q - 1)) = '\0'; query = next; switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-QUERY", next); /* and strip uri */ /* the start of first kv pair marks the end of uri */ /* to prevent kv-pairs confusing fs api commands */ /* that have arguments separated by space */ } *next++ = '\0'; } for (p = q; p && *p; p++) { if (*p == '+') { *p = ' '; } } /* hmmm, get method requests are already decoded ... */ switch_url_decode(q); name = q; if ((val = strchr(name, '='))) { *val++ = '\0'; switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, name, val); } q = next; } while (q != NULL); free(qd); } } switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-URI", uri); /* We made it this far, always OK */ if (!HTTPWrite(r, "HTTP/1.1 200 OK\r\n", (uint32_t) strlen("HTTP/1.1 200 OK\r\n"))) { return TRUE; } ResponseAddField(r, "Connection", "close"); /* generation of the date field */ if (evnt) { ResponseAddField(r, "Date", switch_event_get_header(evnt, "Event-Date-GMT")); } else { const char *dateValue; DateToString(r->date, &dateValue); if (dateValue) { ResponseAddField(r, "Date", dateValue); free((void *)dateValue); } } /* Generation of the server field */ ResponseAddField(r, "Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc"); if (html) { ResponseAddField(r, "Content-Type", "text/html"); } else if (text) { ResponseAddField(r, "Content-Type", "text/plain"); } else if (xml) { ResponseAddField(r, "Content-Type", "text/xml"); } for (i = 0; i < r->responseHeaderFields.size; i++) { TTableItem *ti = &r->responseHeaderFields.item[i]; char *header = switch_mprintf("%s: %s\r\n", ti->name, ti->value); if (!ConnWrite(r->connP, header, (uint32_t) strlen(header))) { switch_safe_free(header); return TRUE; } switch_safe_free(header); } /* send end http header */ if (html||text||xml) { if (!ConnWrite(r->connP, CRLF, 2)) { return TRUE; } } else { /* content-type and end of http header will be streamed by fs api or http_stream_write */ } if (switch_stristr("unload", command) && switch_stristr("mod_xml_rpc", info->query)) { command = "bgapi"; api_str = "unload mod_xml_rpc"; } else if (switch_stristr("reload", command) && switch_stristr("mod_xml_rpc", info->query)) { command = "bgapi"; api_str = "reload mod_xml_rpc"; } else { api_str = info->query; } /* TODO (maybe): take "refresh=xxx" out of query as to not confuse fs api commands */ /* execute actual fs api command */ /* fs api command will write to stream, calling http_stream_write / http_stream_raw_write */ /* switch_api_execute will stream INVALID COMMAND before it fails */ switch_api_execute(command, api_str, NULL, &stream); r->responseStarted = TRUE; ResponseStatus(r, 200); /* we don't want an assertion failure */ r->requestInfo.keepalive = 0; end: return ret; }
abyss_bool handler_hook(TSession * r) { //char *mime = "text/html"; char buf[80] = "HTTP/1.1 200 OK\n"; switch_stream_handle_t stream = { 0 }; char *command; int i; TTableItem *ti; char *fs_user = NULL, *fs_domain = NULL; char *path_info = NULL; abyss_bool ret = TRUE; int html = 0, text = 0, xml = 0; const char *api_str; stream.data = r; stream.write_function = http_stream_write; stream.raw_write_function = http_stream_raw_write; if (!r || !r->requestInfo.uri) { return FALSE; } if ((command = strstr(r->requestInfo.uri, "/api/"))) { command += 5; } else if ((command = strstr(r->requestInfo.uri, "/webapi/"))) { command += 8; html++; } else if ((command = strstr(r->requestInfo.uri, "/txtapi/"))) { command += 8; text++; } else if ((command = strstr(r->requestInfo.uri, "/xmlapi/"))) { command += 8; xml++; } else { return FALSE; } if ((path_info = strchr(command, '/'))) { *path_info++ = '\0'; } for (i = 0; i < r->response_headers.size; i++) { ti = &r->response_headers.item[i]; if (!strcasecmp(ti->name, "freeswitch-user")) { fs_user = ti->value; } else if (!strcasecmp(ti->name, "freeswitch-domain")) { fs_domain = ti->value; } } if (is_authorized(r, command)) { goto auth; } ret = TRUE; goto end; auth: if (switch_event_create(&stream.param_event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) { const char *const content_length = RequestHeaderValue(r, "content-length"); if (html) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/html"); else if (text) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/plain"); else if (xml) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/xml"); if (fs_user) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", fs_user); if (fs_domain) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", fs_domain); if (path_info) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", path_info); switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-URI", r->requestInfo.uri); if (r->requestInfo.query) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-QUERY", r->requestInfo.query); if (r->requestInfo.host) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-HOST", r->requestInfo.host); if (r->requestInfo.from) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-FROM", r->requestInfo.from); if (r->requestInfo.useragent) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER-AGENT", r->requestInfo.useragent); if (r->requestInfo.referer) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-REFERER", r->requestInfo.referer); if (r->requestInfo.requestline) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-REQUESTLINE", r->requestInfo.requestline); if (r->requestInfo.user) switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER", r->requestInfo.user); if (r->requestInfo.port) switch_event_add_header(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-PORT", "%u", r->requestInfo.port); if (r->requestInfo.query || content_length) { char *q, *qd; char *next; char *query = (char *) r->requestInfo.query; char *name, *val; char qbuf[8192] = ""; if (r->requestInfo.method == m_post && content_length) { int len = atoi(content_length); int qlen = 0; if (len > 0) { int succeeded; char *qp = qbuf; do { int blen = r->conn->buffersize - r->conn->bufferpos; if ((qlen + blen) > len) { blen = len - qlen; } qlen += blen; if (qlen > sizeof(qbuf)) { break; } memcpy(qp, r->conn->buffer + r->conn->bufferpos, blen); qp += blen; if (qlen >= len) { break; } } while ((succeeded = ConnRead(r->conn, 2000))); query = qbuf; } } if (query) { switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-QUERY", query); qd = strdup(query); switch_assert(qd != NULL); q = qd; next = q; do { char *p; if ((next = strchr(next, '&'))) { *next++ = '\0'; } for (p = q; p && *p; p++) { if (*p == '+') { *p = ' '; } } switch_url_decode(q); name = q; if ((val = strchr(name, '='))) { *val++ = '\0'; switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, name, val); } q = next; } while (q != NULL); free(qd); } } } //ResponseChunked(r); //ResponseContentType(r, mime); //ResponseWrite(r); HTTPWrite(r, buf, (uint32_t) strlen(buf)); //HTTPWrite(r, "<pre>\n\n", 7); /* generation of the date field */ { const char *dateValue; DateToString(r->date, &dateValue); if (dateValue) { ResponseAddField(r, "Date", dateValue); } } /* Generation of the server field */ ResponseAddField(r, "Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc"); if (html) { ResponseAddField(r, "Content-Type", "text/html"); } else if (text) { ResponseAddField(r, "Content-Type", "text/plain"); } else if (xml) { ResponseAddField(r, "Content-Type", "text/xml"); } for (i = 0; i < r->response_headers.size; i++) { ti = &r->response_headers.item[i]; ConnWrite(r->conn, ti->name, (uint32_t) strlen(ti->name)); ConnWrite(r->conn, ": ", 2); ConnWrite(r->conn, ti->value, (uint32_t) strlen(ti->value)); ConnWrite(r->conn, CRLF, 2); } switch_snprintf(buf, sizeof(buf), "Connection: close\r\n"); ConnWrite(r->conn, buf, (uint32_t) strlen(buf)); if (html || text || xml) { ConnWrite(r->conn, "\r\n", 2); } if (switch_stristr("unload", command) && switch_stristr("mod_xml_rpc", r->requestInfo.query)) { command = "bgapi"; api_str = "unload mod_xml_rpc"; } else if (switch_stristr("reload", command) && switch_stristr("mod_xml_rpc", r->requestInfo.query)) { command = "bgapi"; api_str = "reload mod_xml_rpc"; } else { api_str = r->requestInfo.query; } if (switch_api_execute(command, api_str, NULL, &stream) == SWITCH_STATUS_SUCCESS) { ResponseStatus(r, 200); r->responseStarted = TRUE; //r->done = TRUE; } else { ResponseStatus(r, 404); ResponseError(r); } //SocketClose(&(r->conn->socket)); HTTPWriteEnd(r); //if (r->conn->channelP) //ConnKill(r->conn); //ChannelInterrupt(r->conn->channelP); //ConnClose(r->conn); //ChannelDestroy(r->conn->channelP); r->requestInfo.keepalive = 0; end: return ret; }