Skip to content
Snippets Groups Projects
Commit d1058df1 authored by Luigi Rizzo's avatar Luigi Rizzo
Browse files

various code simplifications to reduce nesting depth,

minor optimizations to avoid extra calls of strlen(),
and some variable localization.

One feature worth backporting is the move of ast_variables_destroy()
to a different place in handle_uri() to avoid leaking memory
in case a uri is not found.



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@45463 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent bb8926d5
No related branches found
No related tags found
No related merge requests found
...@@ -285,23 +285,21 @@ void ast_http_uri_unlink(struct ast_http_uri *urih) ...@@ -285,23 +285,21 @@ void ast_http_uri_unlink(struct ast_http_uri *urih)
static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies) static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies)
{ {
char *c; char *c;
char *params; char *params = uri;
struct ast_http_uri *urih=NULL; struct ast_http_uri *urih=NULL;
int prefix_len; int l;
struct ast_variable *vars=NULL, *v, *prev = NULL; struct ast_variable *vars=NULL, *v, *prev = NULL;
strsep(&params, "?");
/* Extract arguments from the request and store them in variables. */ /* Extract arguments from the request and store them in variables. */
params = strchr(uri, '?');
if (params) { if (params) {
char *var, *val; char *var, *val;
*params++ = '\0'; while ((val = strsep(&params, "&"))) {
while ((var = strsep(&params, "&"))) { var = strsep(&val, "=");
val = strchr(var, '='); if (val)
if (val) {
*val++ = '\0';
ast_uri_decode(val); ast_uri_decode(val);
} else else
val = ""; val = "";
ast_uri_decode(var); ast_uri_decode(var);
if ((v = ast_variable_new(var, val))) { if ((v = ast_variable_new(var, val))) {
...@@ -316,7 +314,7 @@ static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char ** ...@@ -316,7 +314,7 @@ static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **
/* /*
* Append the cookies to the variables (the only reason to have them * Append the cookies to the variables (the only reason to have them
* at the end is to avoid another pass of the cookies list to find * at the end is to avoid another pass of the cookies list to find
* the tail. * the tail).
*/ */
if (prev) if (prev)
prev->next = *cookies; prev->next = *cookies;
...@@ -326,38 +324,40 @@ static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char ** ...@@ -326,38 +324,40 @@ static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **
ast_uri_decode(uri); ast_uri_decode(uri);
/* We want requests to start with the prefix and '/' */ /* We want requests to start with the prefix and '/' */
prefix_len = strlen(prefix); l = strlen(prefix);
if (prefix_len && !strncasecmp(uri, prefix, prefix_len) && uri[prefix_len] == '/') { if (l && !strncasecmp(uri, prefix, l) && uri[l] == '/') {
uri += prefix_len + 1; uri += l + 1;
/* scan registered uris to see if we match one. */ /* scan registered uris to see if we match one. */
for (urih = uris; urih; urih = urih->next) { for (urih = uris; urih; urih = urih->next) {
int len = strlen(urih->uri); l = strlen(urih->uri);
if (!strncasecmp(urih->uri, uri, len)) { c = uri + l; /* candidate */
if (!uri[len] || uri[len] == '/') { if (strncasecmp(urih->uri, uri, l) /* no match */
char *turi = uri + len; /* possible candidate */ || (*c && *c != '/')) /* substring */
if (*turi == '/') continue;
turi++; if (*c == '/')
if (!*turi || urih->has_subtree) { c++;
uri = turi; if (!*c || urih->has_subtree) {
break; uri = c;
} break;
}
} }
} }
} }
if (urih) { if (urih) {
c = urih->callback(sin, uri, vars, status, title, contentlength); c = urih->callback(sin, uri, vars, status, title, contentlength);
ast_variables_destroy(vars);
} else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) { } else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) {
/* Special case: If no prefix, and no URI, send to /static/index.html */ /* Special case: no prefix, no URI, send to /static/index.html */
c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "This is not the page you are looking for..."); c = ast_http_error(302, "Moved Temporarily",
"Location: /static/index.html\r\n",
"This is not the page you are looking for...");
*status = 302; *status = 302;
*title = strdup("Moved Temporarily"); *title = strdup("Moved Temporarily");
} else { } else {
c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server."); c = ast_http_error(404, "Not Found", NULL,
"The requested URL was not found on this server.");
*status = 404; *status = 404;
*title = strdup("Not Found"); *title = strdup("Not Found");
} }
ast_variables_destroy(vars);
return c; return c;
} }
...@@ -365,121 +365,120 @@ static void *ast_httpd_helper_thread(void *data) ...@@ -365,121 +365,120 @@ static void *ast_httpd_helper_thread(void *data)
{ {
char buf[4096]; char buf[4096];
char cookie[4096]; char cookie[4096];
char timebuf[256];
struct ast_http_server_instance *ser = data; struct ast_http_server_instance *ser = data;
struct ast_variable *var, *prev=NULL, *vars=NULL; struct ast_variable *var, *prev=NULL, *vars=NULL;
char *uri, *c, *title=NULL; char *uri, *c, *title=NULL;
char *vname, *vval;
int status = 200, contentlength = 0; int status = 200, contentlength = 0;
time_t t;
if (fgets(buf, sizeof(buf), ser->f)) { if (!fgets(buf, sizeof(buf), ser->f))
uri = ast_skip_nonblanks(buf); /* Skip method */ goto done;
if (*uri)
*uri++ = '\0';
uri = ast_skip_blanks(uri); /* Skip white space */ uri = ast_skip_nonblanks(buf); /* Skip method */
if (*uri)
*uri++ = '\0';
if (*uri) { /* terminate at the first blank */ uri = ast_skip_blanks(uri); /* Skip white space */
c = ast_skip_nonblanks(uri);
if (*c)
*c = '\0';
}
/* process "Cookie: " lines */ if (*uri) { /* terminate at the first blank */
while (fgets(cookie, sizeof(cookie), ser->f)) { c = ast_skip_nonblanks(uri);
/* Trim trailing characters */ if (*c)
ast_trim_blanks(cookie); *c = '\0';
if (ast_strlen_zero(cookie)) }
break;
if (strncasecmp(cookie, "Cookie: ", 8)) /* process "Cookie: " lines */
continue; while (fgets(cookie, sizeof(cookie), ser->f)) {
char *vname, *vval;
int l;
/* XXX fix indentation */ /* Trim trailing characters */
ast_trim_blanks(cookie);
if (ast_strlen_zero(cookie))
break;
if (strncasecmp(cookie, "Cookie: ", 8))
continue;
/* TODO - The cookie parsing code below seems to work /* TODO - The cookie parsing code below seems to work
in IE6 and FireFox 1.5. However, it is not entirely in IE6 and FireFox 1.5. However, it is not entirely
correct, and therefore may not work in all correct, and therefore may not work in all
circumstances. circumstances.
For more details see RFC 2109 and RFC 2965 */ For more details see RFC 2109 and RFC 2965 */
/* FireFox cookie strings look like:
Cookie: mansession_id="********"
InternetExplorer's look like:
Cookie: $Version="1"; mansession_id="********" */
/* FireFox cookie strings look like: /* If we got a FireFox cookie string, the name's right
Cookie: mansession_id="********" after "Cookie: " */
InternetExplorer's look like: vname = ast_skip_blanks(cookie + 8);
Cookie: $Version="1"; mansession_id="********" */
/* If we got a FireFox cookie string, the name's right /* If we got an IE cookie string, we need to skip to
after "Cookie: " */ past the version to get to the name */
vname = cookie + 8; if (*vname == '$') {
strsep(&vname, ";");
/* If we got an IE cookie string, we need to skip to if (!vname) /* no name ? */
past the version to get to the name */ continue;
if (*vname == '$') { vname = ast_skip_blanks(vname);
vname = strchr(vname, ';');
if (vname) {
vname++;
if (*vname == ' ')
vname++;
}
}
if (vname) {
vval = strchr(vname, '=');
if (vval) {
/* Ditch the = and the quotes */
*vval++ = '\0';
if (*vval)
vval++;
if (strlen(vval))
vval[strlen(vval) - 1] = '\0';
var = ast_variable_new(vname, vval);
if (var) {
if (prev)
prev->next = var;
else
vars = var;
prev = var;
}
}
}
} }
vval = strchr(vname, '=');
if (*uri) { if (!vval)
if (!strcasecmp(buf, "get")) continue;
c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars); /* Ditch the = and the quotes */
else *vval++ = '\0';
c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\ if (*vval)
} else vval++;
c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); if ( (l = strlen(vval)) )
vval[l - 1] = '\0'; /* trim trailing quote */
/* If they aren't mopped up already, clean up the cookies */ var = ast_variable_new(vname, vval);
if (vars) if (var) {
ast_variables_destroy(vars); if (prev)
prev->next = var;
if (!c) else
c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); vars = var;
if (c) { prev = var;
time(&t);
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK");
ast_cli(ser->fd, "Server: Asterisk\r\n");
ast_cli(ser->fd, "Date: %s\r\n", timebuf);
ast_cli(ser->fd, "Connection: close\r\n");
if (contentlength) {
char *tmp;
tmp = strstr(c, "\r\n\r\n");
if (tmp) {
ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
write(ser->fd, c, (tmp + 4 - c));
write(ser->fd, tmp + 4, contentlength);
}
} else
ast_cli(ser->fd, "%s", c);
free(c);
} }
if (title)
free(title);
} }
if (!*uri)
c = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
else if (strcasecmp(buf, "get"))
c = ast_http_error(501, "Not Implemented", NULL,
"Attempt to use unimplemented / unsupported method");
else /* try to serve it */
c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars);
/* If they aren't mopped up already, clean up the cookies */
if (vars)
ast_variables_destroy(vars);
if (!c)
c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
if (c) {
time_t t = time(NULL);
char timebuf[256];
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK");
ast_cli(ser->fd, "Server: Asterisk\r\n");
ast_cli(ser->fd, "Date: %s\r\n", timebuf);
ast_cli(ser->fd, "Connection: close\r\n");
if (contentlength) {
char *tmp = strstr(c, "\r\n\r\n");
if (tmp) {
ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
/* first write the header, then the body */
write(ser->fd, c, (tmp + 4 - c));
write(ser->fd, tmp + 4, contentlength);
}
} else
ast_cli(ser->fd, "%s", c);
free(c);
}
if (title)
free(title);
done:
fclose(ser->f); fclose(ser->f);
free(ser); free(ser);
return NULL; return NULL;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment