initial support of http handing in mod_verto

This commit is contained in:
Seven Du 2014-09-04 10:24:19 +08:00
parent 602e82d483
commit b2554848a1
2 changed files with 172 additions and 3 deletions

View File

@ -1279,6 +1279,167 @@ static void jsock_check_event_queue(jsock_t *jsock)
switch_mutex_unlock(jsock->write_mutex);
}
/* DO NOT use this unless you know what you are doing, you are WARNNED!!! */
static uint8_t *http_stream_read(switch_stream_handle_t *handle, int *len)
{
switch_http_request_t *r = (switch_http_request_t *) handle->data;
jsock_t *jsock = r->user_data;
wsh_t *wsh = &jsock->ws;
*len = r->_unparsed_len;
if (*len) { // we already read part of the body
r->_unparsed_len = 0; // reset for the next read
return (uint8_t *)r->_unparsed_data;
}
if ((*len = ws_raw_read(wsh, wsh->buffer, 4096, wsh->block)) < 0) {
return NULL;
}
return (uint8_t *)wsh->buffer;
}
static switch_status_t http_stream_raw_write(switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen)
{
switch_http_request_t *r = (switch_http_request_t *) handle->data;
jsock_t *jsock = r->user_data;
return ws_raw_write(&jsock->ws, data, (uint32_t)datalen) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
static switch_status_t http_stream_write(switch_stream_handle_t *handle, const char *fmt, ...)
{
switch_http_request_t *r = (switch_http_request_t *) handle->data;
jsock_t *jsock = r->user_data;
int ret = 1;
char *data;
va_list ap;
va_start(ap, fmt);
ret = switch_vasprintf(&data, fmt, ap);
va_end(ap);
if (data) {
if (ret) {
ret = ws_raw_write(&jsock->ws, data, (uint32_t)strlen(data));
}
switch_safe_free(data);
}
return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
static void http_static_handler(switch_http_request_t *request)
{
jsock_t *jsock = request->user_data;
char path[512];
switch_file_t *fd;
char *ext;
uint8_t chunk[4096];
const char *mime_type = "text/html", *new_type;
switch_snprintf(path, sizeof(path), "%s%s", jsock->profile->htdocs, request->uri);
printf("local path: %s\n", path);
if (end_of(path) == '/') {
char *data = "HTTP/1.1 500 Internal Error\r\n"
"Connection: close\r\n"
"Content-Type: text/plain\r\n\r\n"
"Directory indexing is UNSUPPORTED!\r\n";
ws_raw_write(&jsock->ws, data, strlen(data));
return;
}
if ((ext = strrchr(path, '.'))) {
ext++;
if ((new_type = switch_core_mime_ext2type(ext))) {
mime_type = new_type;
}
}
if (switch_file_open(&fd, path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, jsock->pool) == SWITCH_STATUS_SUCCESS) {
switch_size_t flen = switch_file_get_size(fd);
switch_snprintf((char *)chunk, sizeof(chunk),
"HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"Date: %s\r\n"
"Server: FreeSWITCH-%s-mod_verto\r\n"
"Content-Type: %s\r\n"
"Content-Length: %" SWITCH_SIZE_T_FMT "\r\n\r\n",
switch_event_get_header(request->headers, "Event-Date-GMT"),
switch_version_full(),
mime_type,
flen);
ws_raw_write(&jsock->ws, chunk, strlen((char *)chunk));
for (;;) {
switch_status_t status;
flen = sizeof(chunk);
status = switch_file_read(fd, chunk, &flen);
if (status != SWITCH_STATUS_SUCCESS || flen == 0) {
break;
}
ws_raw_write(&jsock->ws, chunk, flen);
}
switch_file_close(fd);
} else {
char *data = "HTTP/1.1 404 Not Found\r\n"
"Connection: close\r\n\r\n";
ws_raw_write(&jsock->ws, data, strlen(data));
}
}
static void http_run(jsock_t *jsock)
{
switch_http_request_t request = { 0 };
switch_stream_handle_t stream = { 0 };
char *data;
request.user_data = jsock;
if (switch_event_create(&stream.param_event, SWITCH_EVENT_CHANNEL_DATA) != SWITCH_STATUS_SUCCESS) {
goto err;
}
request.headers = stream.param_event;
if (switch_http_parse_header(jsock->ws.buffer, jsock->ws.datalen, &request) != SWITCH_STATUS_SUCCESS) {
switch_event_destroy(&stream.param_event);
goto err;
}
switch_http_dump_request(&request);
/* TODO: parse virtual hosts here */
stream.data = &request;
stream.read_function = http_stream_read;
stream.write_function = http_stream_write;
stream.raw_write_function = http_stream_raw_write;
switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "Request-Method", request.method);
switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-URI", request.uri);
if (!strncmp(request.uri, "/rest/", 6)) {
switch_api_execute("lua", "__rest_init__.lua", NULL, &stream);
} else {
http_static_handler(&request);
}
switch_http_free_request(&request);
return;
err:
data = "HTTP/1.1 500 Internal Server Error\r\n"
"Connection: close\r\n\r\n";
ws_raw_write(&jsock->ws, data, strlen(data));
}
static void client_run(jsock_t *jsock)
{
@ -1287,8 +1448,14 @@ static void client_run(jsock_t *jsock)
jsock->local_addr.sin_port = 0;
if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1) < 0) {
die("%s WS SETUP FAILED", jsock->name);
if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->htdocs) < 0) {
if (jsock->profile->htdocs) {
http_run(jsock);
ws_close(&jsock->ws, WS_NONE);
goto error;
} else {
die("%s WS SETUP FAILED [%s]", jsock->name, jsock->ws.buffer);
}
}
while(jsock->profile->running) {
@ -3654,6 +3821,8 @@ static switch_status_t parse_config(const char *cf)
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max Bindings Reached!\n");
}
} else if (!strcasecmp(var, "htdocs-directory")) {
profile->htdocs = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "secure-combined")) {
set_string(profile->cert, val);
set_string(profile->key, val);

View File

@ -220,7 +220,7 @@ struct verto_profile_s {
char *timer_name;
char *local_network;
char *htdocs;
struct verto_profile_s *next;
};