add basic http virtual host support and fix some leaks

This commit is contained in:
Seven Du 2014-09-06 12:06:24 +08:00
parent 76b093a098
commit 7f8cc54cfb
2 changed files with 177 additions and 23 deletions

View File

@ -24,6 +24,7 @@
* Contributor(s): * Contributor(s):
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Seven Du <dujinfang@gmail.com>
* *
* mod_verto.c -- HTML5 Verto interface * mod_verto.c -- HTML5 Verto interface
* *
@ -1330,7 +1331,7 @@ static switch_status_t http_stream_write(switch_stream_handle_t *handle, const c
return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
} }
static void http_static_handler(switch_http_request_t *request) static void http_static_handler(switch_http_request_t *request, verto_vhost_t *vhost)
{ {
jsock_t *jsock = request->user_data; jsock_t *jsock = request->user_data;
char path[512]; char path[512];
@ -1339,17 +1340,12 @@ static void http_static_handler(switch_http_request_t *request)
uint8_t chunk[4096]; uint8_t chunk[4096];
const char *mime_type = "text/html", *new_type; const char *mime_type = "text/html", *new_type;
switch_snprintf(path, sizeof(path), "%s%s", jsock->profile->htdocs, request->uri); switch_snprintf(path, sizeof(path), "%s%s", vhost->root, request->uri);
// printf("local path: %s\n", path); if (switch_directory_exists(path, NULL) == SWITCH_STATUS_SUCCESS) {
switch_snprintf(path, sizeof(path), "%s%s%s%s",
if (end_of(path) == '/') { vhost->root, request->uri, end_of(path) == '/' ? "" : SWITCH_PATH_SEPARATOR, vhost->index);
char *data = "HTTP/1.1 500 Internal Error\r\n" // printf("local path: %s\n", path);
"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, '.'))) { if ((ext = strrchr(path, '.'))) {
@ -1359,7 +1355,8 @@ static void http_static_handler(switch_http_request_t *request)
} }
} }
if (switch_file_open(&fd, path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, jsock->pool) == SWITCH_STATUS_SUCCESS) { if (switch_file_exists(path, NULL) == SWITCH_STATUS_SUCCESS &&
switch_file_open(&fd, path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD, jsock->pool) == SWITCH_STATUS_SUCCESS) {
switch_size_t flen = switch_file_get_size(fd); switch_size_t flen = switch_file_get_size(fd);
switch_snprintf((char *)chunk, sizeof(chunk), switch_snprintf((char *)chunk, sizeof(chunk),
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
@ -1400,6 +1397,8 @@ static void http_run(jsock_t *jsock)
switch_http_request_t request = { 0 }; switch_http_request_t request = { 0 };
switch_stream_handle_t stream = { 0 }; switch_stream_handle_t stream = { 0 };
char *data; char *data;
char *ext;
verto_vhost_t *vhost;
request.user_data = jsock; request.user_data = jsock;
@ -1423,12 +1422,50 @@ static void http_run(jsock_t *jsock)
stream.raw_write_function = http_stream_raw_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, "Request-Method", request.method);
switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-Request-URI", request.uri);
if (!jsock->profile->vhosts) goto err;
/* only one vhost supported for now */
vhost = jsock->profile->vhosts;
if (vhost->rewrites) {
switch_event_header_t *rule = vhost->rewrites->headers;
switch_regex_t *re = NULL;
int ovector[30];
int proceed;
while(rule) {
char *expression = rule->name;
if ((proceed = switch_regex_perform(request.uri, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"%d request [%s] matched expr [%s]\n", proceed, request.uri, expression);
request.uri = rule->value;
break;
}
rule = rule->next;
}
}
switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-URI", request.uri); switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-URI", request.uri);
if (!strncmp(request.uri, "/rest/", 6)) { if ((ext = strrchr(request.uri, '.'))) {
switch_api_execute("lua", "__rest_init__.lua", NULL, &stream); char path[1024];
if (!strncmp(ext, ".lua", 4)) {
switch_snprintf(path, sizeof(path), "%s%s", vhost->script_root, request.uri);
switch_api_execute("lua", path, NULL, &stream);
} else if (!strncmp(ext, ".js", 3)) {
switch_snprintf(path, sizeof(path), "%s%s", vhost->script_root, request.uri);
switch_api_execute("jsrun", path, NULL, &stream);
} else {
http_static_handler(&request, vhost);
}
} else { } else {
http_static_handler(&request); http_static_handler(&request, vhost);
} }
switch_http_free_request(&request); switch_http_free_request(&request);
@ -1448,8 +1485,8 @@ static void client_run(jsock_t *jsock)
jsock->local_addr.sin_port = 0; 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, !!jsock->profile->htdocs) < 0) { if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) {
if (jsock->profile->htdocs) { if (jsock->profile->vhosts) {
http_run(jsock); http_run(jsock);
ws_close(&jsock->ws, WS_NONE); ws_close(&jsock->ws, WS_NONE);
goto error; goto error;
@ -3603,6 +3640,7 @@ static int runtime(verto_profile_t *profile)
static void kill_profile(verto_profile_t *profile) static void kill_profile(verto_profile_t *profile)
{ {
jsock_t *p; jsock_t *p;
verto_vhost_t *h;
int i; int i;
profile->running = 0; profile->running = 0;
@ -3619,6 +3657,16 @@ static void kill_profile(verto_profile_t *profile)
for(p = profile->jsock_head; p; p = p->next) { for(p = profile->jsock_head; p; p = p->next) {
close_socket(&p->client_socket); close_socket(&p->client_socket);
} }
h = profile->vhosts;
while(h) {
if (h->rewrites) {
switch_event_destroy(&h->rewrites);
}
h = h->next;
}
switch_mutex_unlock(profile->mutex); switch_mutex_unlock(profile->mutex);
@ -3768,6 +3816,7 @@ static switch_status_t parse_config(const char *cf)
{ {
switch_xml_t cfg, xml, settings, param, xprofile, xprofiles; switch_xml_t cfg, xml, settings, param, xprofile, xprofiles;
switch_xml_t xvhosts, xvhost, rewrites, rule;
switch_status_t status = SWITCH_STATUS_SUCCESS; switch_status_t status = SWITCH_STATUS_SUCCESS;
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
@ -3821,8 +3870,6 @@ static switch_status_t parse_config(const char *cf)
} else { } else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max Bindings Reached!\n"); 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")) { } else if (!strcasecmp(var, "secure-combined")) {
set_string(profile->cert, val); set_string(profile->cert, val);
set_string(profile->key, val); set_string(profile->key, val);
@ -3918,8 +3965,89 @@ static switch_status_t parse_config(const char *cf)
profile->name, profile->ip[i].local_ip, profile->ip[i].local_port); profile->name, profile->ip[i].local_ip, profile->ip[i].local_port);
} }
} }
}
} /* parse vhosts */
/* WARNNING: Experimental feature, DO NOT use until we remove this warnning!! */
if ((xvhosts = switch_xml_child(xprofile, "vhosts"))) {
verto_vhost_t *vhost_tail = NULL;
for (xvhost = switch_xml_child(xvhosts, "vhost"); xvhost; xvhost = xvhost->next) {
verto_vhost_t *vhost;
const char *domain = switch_xml_attr(xvhost, "domain");
if (zstr(domain)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Required field domain missing\n");
continue;
}
vhost = switch_core_alloc(profile->pool, sizeof(*vhost));
memset(vhost, 0, sizeof(*vhost));
vhost->pool = profile->pool;
vhost->domain = switch_core_strdup(profile->pool, domain);
if (!vhost_tail) {
profile->vhosts = vhost;
} else {
vhost_tail->next = vhost;
}
vhost_tail = vhost;
for (param = switch_xml_child(xvhost, "param"); param; param = param->next) {
char *var = NULL;
char *val = NULL;
var = (char *) switch_xml_attr_soft(param, "name");
val = (char *) switch_xml_attr_soft(param, "value");
if (!strcasecmp(var, "alias")) {
vhost->alias = switch_core_strdup(vhost->pool, val);
} else if (!strcasecmp(var, "root")) {
vhost->root = switch_core_strdup(vhost->pool, val);
} else if (!strcasecmp(var, "script_root")) {
vhost->script_root = switch_core_strdup(vhost->pool, val);
} else if (!strcasecmp(var, "index")) {
vhost->index = switch_core_strdup(vhost->pool, val);
} else if (!strcasecmp(var, "auth-realm")) {
vhost->auth_realm = switch_core_strdup(vhost->pool, val);
} else if (!strcasecmp(var, "auth-user")) {
vhost->auth_user = switch_core_strdup(vhost->pool, val);
} else if (!strcasecmp(var, "auth-pass")) {
vhost->auth_pass = switch_core_strdup(vhost->pool, val);
}
}
if (zstr(vhost->root)) {
vhost->root = SWITCH_GLOBAL_dirs.htdocs_dir;
}
if (zstr(vhost->script_root)) {
vhost->root = SWITCH_GLOBAL_dirs.script_dir;
}
if (zstr(vhost->index)) {
vhost->index = "index.html";
}
if ((rewrites = switch_xml_child(xvhost, "rewrites"))) {
if (switch_event_create(&vhost->rewrites, SWITCH_EVENT_CLONE) == SWITCH_STATUS_SUCCESS) {
for (rule = switch_xml_child(rewrites, "rule"); rule; rule = rule->next) {
char *expr = NULL;
char *val = NULL;
expr = (char *) switch_xml_attr_soft(rule, "expression");
val = (char *) switch_xml_attr_soft(rule, "value");
if (zstr(expr)) continue;
switch_event_add_header_string(vhost->rewrites, SWITCH_STACK_BOTTOM, expr, val);
}
}
} // rewrites
} // xvhost
} // xvhosts
} // xprofile
} // xprofiles
if ((settings = switch_xml_child(cfg, "settings"))) { if ((settings = switch_xml_child(cfg, "settings"))) {
for (param = switch_xml_child(settings, "param"); param; param = param->next) { for (param = switch_xml_child(settings, "param"); param; param = param->next) {
@ -3995,6 +4123,7 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
{ {
verto_profile_t *profile = NULL; verto_profile_t *profile = NULL;
jsock_t *jsock; jsock_t *jsock;
verto_vhost_t *vhost;
int cp = 0; int cp = 0;
int cc = 0; int cc = 0;
const char *line = "================================================================================================="; const char *line = "=================================================================================================";
@ -4007,14 +4136,22 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
for (int i = 0; i < profile->i; i++) { for (int i = 0; i < profile->i; i++) {
char *tmpurl = switch_mprintf("%s:%s:%d",(profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port); char *tmpurl = switch_mprintf("%s:%s:%d",(profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port);
stream->write_function(stream, "%25s\t%s\t %40s\t%s\n", profile->name, "profile", tmpurl, (profile->running) ? "RUNNING" : "DOWN"); stream->write_function(stream, "%25s\t%s\t %40s\t%s\n", profile->name, "profile", tmpurl, (profile->running) ? "RUNNING" : "DOWN");
switch_safe_free(tmpurl);
} }
cp++; cp++;
switch_mutex_lock(profile->mutex); switch_mutex_lock(profile->mutex);
for(jsock = profile->jsock_head; jsock; jsock = jsock->next) { for (vhost = profile->vhosts; vhost; vhost = vhost->next) {
char *tmpname = switch_mprintf("%s::%s", profile->name, vhost->domain);
stream->write_function(stream, "%25s\t%s\t %40s\t%s (%s)\n", tmpname, "vhost", vhost->root, vhost->auth_user ? "AUTH" : "NOAUTH", vhost->auth_user ? vhost->auth_user : "");
switch_safe_free(tmpname);
}
for (jsock = profile->jsock_head; jsock; jsock = jsock->next) {
char *tmpname = switch_mprintf("%s::%s@%s", profile->name, jsock->id, jsock->domain); char *tmpname = switch_mprintf("%s::%s@%s", profile->name, jsock->id, jsock->domain);
stream->write_function(stream, "%25s\t%s\t %40s\t%s (%s)\n", tmpname, "client", jsock->name, (!zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS"); stream->write_function(stream, "%25s\t%s\t %40s\t%s (%s)\n", tmpname, "client", jsock->name, (!zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS");
cc++; cc++;
switch_safe_free(tmpname);
} }
switch_mutex_unlock(profile->mutex); switch_mutex_unlock(profile->mutex);
} }
@ -4041,6 +4178,7 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
for (int i = 0; i < profile->i; i++) { for (int i = 0; i < profile->i; i++) {
char *tmpurl = switch_mprintf("%s:%s:%d",(profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port); char *tmpurl = switch_mprintf("%s:%s:%d",(profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port);
stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</profile>\n", profile->name, "profile", tmpurl, (profile->running) ? "RUNNING" : "DOWN"); stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</profile>\n", profile->name, "profile", tmpurl, (profile->running) ? "RUNNING" : "DOWN");
switch_safe_free(tmpurl);
} }
cp++; cp++;
@ -4050,6 +4188,7 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
stream->write_function(stream, "<client>\n<profile>%s</profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%s)</state>\n</client>\n", profile->name, tmpname, "client", jsock->name, stream->write_function(stream, "<client>\n<profile>%s</profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%s)</state>\n</client>\n", profile->name, tmpname, "client", jsock->name,
(!zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS"); (!zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS");
cc++; cc++;
switch_safe_free(tmpname);
} }
switch_mutex_unlock(profile->mutex); switch_mutex_unlock(profile->mutex);
} }

View File

@ -24,6 +24,7 @@
* Contributor(s): * Contributor(s):
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Seven Du <dujinfang@gmail.com>
* *
* mod_html.h -- HTML 5 interface * mod_html.h -- HTML 5 interface
* *
@ -166,6 +167,20 @@ typedef struct verto_pvt_s {
struct verto_pvt_s *next; struct verto_pvt_s *next;
} verto_pvt_t; } verto_pvt_t;
typedef struct verto_vhost_s {
char *domain;
char *alias;
char *root;
char *script_root;
char *index;
char *auth_realm;
char *auth_user;
char *auth_pass;
switch_event_t *rewrites;
switch_memory_pool_t *pool;
struct verto_vhost_s *next;
} verto_vhost_t;
struct verto_profile_s { struct verto_profile_s {
char *name; char *name;
switch_mutex_t *mutex; switch_mutex_t *mutex;
@ -220,7 +235,7 @@ struct verto_profile_s {
char *timer_name; char *timer_name;
char *local_network; char *local_network;
char *htdocs; verto_vhost_t *vhosts;
struct verto_profile_s *next; struct verto_profile_s *next;
}; };