replace ast_build_string() with ast_str_*() functions.

This makes the code easier to follow and saves some
copies to intermediate buffers.



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48515 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Luigi Rizzo
2006-12-16 09:33:31 +00:00
parent b2bd05ee83
commit 20b382cfff
4 changed files with 158 additions and 156 deletions

View File

@@ -144,7 +144,7 @@ int ssl_setup(struct tls_config *cfg);
The return value may include additional headers at the front and MUST include a blank The return value may include additional headers at the front and MUST include a blank
line with \r\n to provide separation between user headers and content (even if no line with \r\n to provide separation between user headers and content (even if no
content is specified) */ content is specified) */
typedef char *(*ast_http_callback)(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength); typedef struct ast_str *(*ast_http_callback)(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength);
struct ast_http_uri { struct ast_http_uri {
struct ast_http_uri *next; struct ast_http_uri *next;
@@ -157,14 +157,12 @@ struct ast_http_uri {
/*! \brief Link into the Asterisk HTTP server */ /*! \brief Link into the Asterisk HTTP server */
int ast_http_uri_link(struct ast_http_uri *urihandler); int ast_http_uri_link(struct ast_http_uri *urihandler);
/*! \brief Return a malloc()'d string containing an HTTP error message */ /*! \brief Return an ast_str malloc()'d string containing an HTTP error message */
char *ast_http_error(int status, const char *title, const char *extra_header, const char *text); struct ast_str *ast_http_error(int status, const char *title, const char *extra_header, const char *text);
/*! \brief Destroy an HTTP server */ /*! \brief Destroy an HTTP server */
void ast_http_uri_unlink(struct ast_http_uri *urihandler); void ast_http_uri_unlink(struct ast_http_uri *urihandler);
char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, size_t buflen);
int ast_http_init(void); int ast_http_init(void);
int ast_http_reload(void); int ast_http_reload(void);

View File

@@ -336,6 +336,27 @@ struct ast_str * attribute_malloc ast_str_create(size_t init_len),
} }
) )
/*!
* Make space in a new string (e.g. to read in data from a file)
*/
AST_INLINE_API(
int ast_str_make_space(struct ast_str **buf, size_t new_len),
{
if (new_len <= (*buf)->len)
return 0; /* success */
if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC)
return -1; /* cannot extend */
*buf = ast_realloc(*buf, new_len + sizeof(struct ast_str));
if (*buf == NULL) /* XXX watch out, we leak memory here */
return -1;
if ((*buf)->ts != DS_MALLOC)
pthread_setspecific((*buf)->ts->key, *buf);
(*buf)->len = new_len;
return 0;
}
)
#define ast_str_alloca(init_len) \ #define ast_str_alloca(init_len) \
({ \ ({ \
struct ast_str *buf; \ struct ast_str *buf; \

View File

@@ -148,17 +148,15 @@ static char *uri_decode(char *buf)
} }
return buf; return buf;
} }
static char *static_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength) static struct ast_str *static_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
{ {
char result[4096]; struct ast_str *result;
char *c=result;
char *path; char *path;
char *ftype, *mtype; char *ftype, *mtype;
char wkspace[80]; char wkspace[80];
struct stat st; struct stat st;
int len; int len;
int fd; int fd;
void *blob;
/* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */ substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */
@@ -188,23 +186,22 @@ static char *static_callback(struct sockaddr_in *req, const char *uri, struct as
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) if (fd < 0)
goto out403; goto out403;
len = st.st_size + strlen(mtype) + 40; len = st.st_size + strlen(mtype) + 40;
result = ast_str_create(len);
blob = malloc(len); if (result == NULL) /* XXX not really but... */
if (blob) { goto out403;
c = blob;
sprintf(c, "Content-type: %s\r\n\r\n", mtype); ast_str_append(&result, 0, "Content-type: %s\r\n\r\n", mtype);
c += strlen(c); *contentlength = read(fd, result->str + result->used, st.st_size);
*contentlength = read(fd, c, st.st_size); if (*contentlength < 0) {
if (*contentlength < 0) { close(fd);
close(fd); free(result);
free(blob); goto out403;
goto out403;
}
} }
result->used += *contentlength;
close(fd); close(fd);
return blob; return result;
out404: out404:
*status = 404; *status = 404;
@@ -218,44 +215,41 @@ out403:
} }
static char *httpstatus_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength) static struct ast_str *httpstatus_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
{ {
char result[4096]; struct ast_str *out = ast_str_create(512);
size_t reslen = sizeof(result);
char *c=result;
struct ast_variable *v; struct ast_variable *v;
ast_build_string(&c, &reslen, if (out == NULL)
return out;
ast_str_append(&out, 0,
"\r\n" "\r\n"
"<title>Asterisk HTTP Status</title>\r\n" "<title>Asterisk HTTP Status</title>\r\n"
"<body bgcolor=\"#ffffff\">\r\n" "<body bgcolor=\"#ffffff\">\r\n"
"<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n" "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
"<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n"); "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
ast_build_string(&c, &reslen, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix); ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
ast_build_string(&c, &reslen, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n", ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
ast_inet_ntoa(http_desc.oldsin.sin_addr)); ast_inet_ntoa(http_desc.oldsin.sin_addr));
ast_build_string(&c, &reslen, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n", ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
ntohs(http_desc.oldsin.sin_port)); ntohs(http_desc.oldsin.sin_port));
if (http_tls_cfg.enabled) if (http_tls_cfg.enabled)
ast_build_string(&c, &reslen, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n", ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
ntohs(https_desc.oldsin.sin_port)); ntohs(https_desc.oldsin.sin_port));
ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
v = vars; for (v = vars; v; v = v->next) {
while(v) {
if (strncasecmp(v->name, "cookie_", 7)) if (strncasecmp(v->name, "cookie_", 7))
ast_build_string(&c, &reslen, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); ast_str_append(&out, 0, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
v = v->next;
} }
ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
v = vars; for (v = vars; v; v = v->next) {
while(v) {
if (!strncasecmp(v->name, "cookie_", 7)) if (!strncasecmp(v->name, "cookie_", 7))
ast_build_string(&c, &reslen, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
v = v->next;
} }
ast_build_string(&c, &reslen, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n"); ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
return strdup(result); return out;
} }
static struct ast_http_uri statusuri = { static struct ast_http_uri statusuri = {
@@ -272,10 +266,12 @@ static struct ast_http_uri staticuri = {
.has_subtree = 1, .has_subtree = 1,
}; };
char *ast_http_error(int status, const char *title, const char *extra_header, const char *text) struct ast_str *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
{ {
char *c = NULL; struct ast_str *out = ast_str_create(512);
asprintf(&c, if (out == NULL)
return out;
ast_str_set(&out, 0,
"Content-type: text/html\r\n" "Content-type: text/html\r\n"
"%s" "%s"
"\r\n" "\r\n"
@@ -289,7 +285,7 @@ char *ast_http_error(int status, const char *title, const char *extra_header, co
"<address>Asterisk Server</address>\r\n" "<address>Asterisk Server</address>\r\n"
"</body></html>\r\n", "</body></html>\r\n",
(extra_header ? extra_header : ""), status, title, title, text); (extra_header ? extra_header : ""), status, title, title, text);
return c; return out;
} }
/*! \brief /*! \brief
@@ -334,9 +330,10 @@ 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 struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies)
{ {
char *c; char *c;
struct ast_str *out = NULL;
char *params = uri; char *params = uri;
struct ast_http_uri *urih=NULL; struct ast_http_uri *urih=NULL;
int l; int l;
@@ -395,22 +392,22 @@ static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **
} }
} }
if (urih) { if (urih) {
c = urih->callback(sin, uri, vars, status, title, contentlength); out = urih->callback(sin, uri, vars, status, title, contentlength);
} else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) { } else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) {
/* Special case: no prefix, 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", out = ast_http_error(302, "Moved Temporarily",
"Location: /static/index.html\r\n", "Location: /static/index.html\r\n",
"This is not the page you are looking for..."); "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, out = ast_http_error(404, "Not Found", NULL,
"The requested URL was not found on this server."); "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); ast_variables_destroy(vars);
return c; return out;
} }
#ifdef DO_SSL #ifdef DO_SSL
@@ -509,8 +506,9 @@ static void *httpd_helper_thread(void *data)
char cookie[4096]; char cookie[4096];
struct server_instance *ser = data; struct 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, *title=NULL;
int status = 200, contentlength = 0; int status = 200, contentlength = 0;
struct ast_str *out = NULL;
if (!fgets(buf, sizeof(buf), ser->f)) if (!fgets(buf, sizeof(buf), ser->f))
goto done; goto done;
@@ -522,7 +520,7 @@ static void *httpd_helper_thread(void *data)
uri = ast_skip_blanks(uri); /* Skip white space */ uri = ast_skip_blanks(uri); /* Skip white space */
if (*uri) { /* terminate at the first blank */ if (*uri) { /* terminate at the first blank */
c = ast_skip_nonblanks(uri); char *c = ast_skip_nonblanks(uri);
if (*c) if (*c)
*c = '\0'; *c = '\0';
} }
@@ -582,20 +580,20 @@ static void *httpd_helper_thread(void *data)
} }
if (!*uri) if (!*uri)
c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); out = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
else if (strcasecmp(buf, "get")) else if (strcasecmp(buf, "get"))
c = ast_http_error(501, "Not Implemented", NULL, out = ast_http_error(501, "Not Implemented", NULL,
"Attempt to use unimplemented / unsupported method"); "Attempt to use unimplemented / unsupported method");
else /* try to serve it */ else /* try to serve it */
c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars); out = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars);
/* If they aren't mopped up already, clean up the cookies */ /* If they aren't mopped up already, clean up the cookies */
if (vars) if (vars)
ast_variables_destroy(vars); ast_variables_destroy(vars);
if (!c) if (out == NULL)
c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); out = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
if (c) { if (out) {
time_t t = time(NULL); time_t t = time(NULL);
char timebuf[256]; char timebuf[256];
@@ -606,18 +604,18 @@ static void *httpd_helper_thread(void *data)
"Connection: close\r\n", "Connection: close\r\n",
status, title ? title : "OK", timebuf); status, title ? title : "OK", timebuf);
if (!contentlength) { /* opaque body ? just dump it hoping it is properly formatted */ if (!contentlength) { /* opaque body ? just dump it hoping it is properly formatted */
fprintf(ser->f, "%s", c); fprintf(ser->f, "%s", out->str);
} else { } else {
char *tmp = strstr(c, "\r\n\r\n"); char *tmp = strstr(out->str, "\r\n\r\n");
if (tmp) { if (tmp) {
fprintf(ser->f, "Content-length: %d\r\n", contentlength); fprintf(ser->f, "Content-length: %d\r\n", contentlength);
/* first write the header, then the body */ /* first write the header, then the body */
fwrite(c, 1, (tmp + 4 - c), ser->f); fwrite(out->str, 1, (tmp + 4 - out->str), ser->f);
fwrite(tmp + 4, 1, contentlength, ser->f); fwrite(tmp + 4, 1, contentlength, ser->f);
} }
} }
free(c); free(out);
} }
if (title) if (title)
free(title); free(title);
@@ -678,17 +676,6 @@ void *server_root(void *data)
return NULL; return NULL;
} }
char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, size_t buflen)
{
char *c;
c = buf;
ast_build_string(&c, &buflen, "Set-Cookie: %s=\"%s\"; Version=\"1\"", var, val);
if (expires)
ast_build_string(&c, &buflen, "; Max-Age=%d", expires);
ast_build_string(&c, &buflen, "\r\n");
return buf;
}
int ssl_setup(struct tls_config *cfg) int ssl_setup(struct tls_config *cfg)
{ {
#ifndef DO_SSL #ifndef DO_SSL

View File

@@ -2491,44 +2491,58 @@ static void vars2msg(struct message *m, struct ast_variable *vars)
* mode & 1 -> lowercase; * mode & 1 -> lowercase;
* mode & 2 -> replace non-alphanumeric chars with underscore * mode & 2 -> replace non-alphanumeric chars with underscore
*/ */
static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int mode) static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
{ {
for ( ; *src && *maxlen > 6; src++) { /* store in a local buffer to avoid calling ast_str_append too often */
char buf[256];
char *dst = buf;
int space = sizeof(buf);
/* repeat until done and nothing to flush */
for ( ; *src || dst != buf ; src++) {
if (*src == '\0' || space < 10) { /* flush */
*dst++ = '\0';
ast_str_append(out, 0, "%s", buf);
dst = buf;
space = sizeof(buf);
if (*src == '\0')
break;
}
if ( (mode & 2) && !isalnum(*src)) { if ( (mode & 2) && !isalnum(*src)) {
*(*dst)++ = '_'; *dst++ = '_';
(*maxlen)--; space--;
continue; continue;
} }
switch (*src) { switch (*src) {
case '<': case '<':
strcpy(*dst, "&lt;"); strcpy(dst, "&lt;");
(*dst) += 4; dst += 4;
*maxlen -= 4; space -= 4;
break; break;
case '>': case '>':
strcpy(*dst, "&gt;"); strcpy(dst, "&gt;");
(*dst) += 4; dst += 4;
*maxlen -= 4; space -= 4;
break; break;
case '\"': case '\"':
strcpy(*dst, "&quot;"); strcpy(dst, "&quot;");
(*dst) += 6; dst += 6;
*maxlen -= 6; space -= 6;
break; break;
case '\'': case '\'':
strcpy(*dst, "&apos;"); strcpy(dst, "&apos;");
(*dst) += 6; dst += 6;
*maxlen -= 6; space -= 6;
break; break;
case '&': case '&':
strcpy(*dst, "&amp;"); strcpy(dst, "&amp;");
(*dst) += 5; dst += 5;
*maxlen -= 5; space -= 5;
break; break;
default: default:
*(*dst)++ = mode ? tolower(*src) : *src; *dst++ = mode ? tolower(*src) : *src;
(*maxlen)--; space--;
} }
} }
} }
@@ -2558,19 +2572,14 @@ static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int mod
* Sections (blank lines in the input) are separated by a <HR> * Sections (blank lines in the input) are separated by a <HR>
* *
*/ */
static char *xml_translate(char *in, struct ast_variable *vars, enum output_format format) static void xml_translate(struct ast_str **out, char *in, struct ast_variable *vars, enum output_format format)
{ {
struct ast_variable *v; struct ast_variable *v;
char *dest = NULL; char *dest = NULL;
char *out, *tmp, *var, *val; char *var, *val;
char *objtype = NULL; char *objtype = NULL;
int colons = 0;
int breaks = 0;
size_t len;
int in_data = 0; /* parsing data */ int in_data = 0; /* parsing data */
int escaped = 0;
int inobj = 0; int inobj = 0;
int x;
int xml = (format == FORMAT_XML); int xml = (format == FORMAT_XML);
for (v = vars; v; v = v->next) { for (v = vars; v; v = v->next) {
@@ -2583,7 +2592,7 @@ static char *xml_translate(char *in, struct ast_variable *vars, enum output_form
dest = "unknown"; dest = "unknown";
if (!objtype) if (!objtype)
objtype = "generic"; objtype = "generic";
#if 0
/* determine how large is the response. /* determine how large is the response.
* This is a heuristic - counting colons (for headers), * This is a heuristic - counting colons (for headers),
* newlines (for extra arguments), and escaped chars. * newlines (for extra arguments), and escaped chars.
@@ -2604,6 +2613,7 @@ static char *xml_translate(char *in, struct ast_variable *vars, enum output_form
return NULL; return NULL;
tmp = out; tmp = out;
*tmp = '\0'; *tmp = '\0';
#endif
/* we want to stop when we find an empty line */ /* we want to stop when we find an empty line */
while (in && *in) { while (in && *in) {
val = strsep(&in, "\r\n"); /* mark start and end of line */ val = strsep(&in, "\r\n"); /* mark start and end of line */
@@ -2614,10 +2624,10 @@ static char *xml_translate(char *in, struct ast_variable *vars, enum output_form
ast_verbose("inobj %d in_data %d line <%s>\n", inobj, in_data, val); ast_verbose("inobj %d in_data %d line <%s>\n", inobj, in_data, val);
if (ast_strlen_zero(val)) { if (ast_strlen_zero(val)) {
if (in_data) { /* close data */ if (in_data) { /* close data */
ast_build_string(&tmp, &len, xml ? "'" : "</td></tr>\n"); ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
in_data = 0; in_data = 0;
} }
ast_build_string(&tmp, &len, xml ? " /></response>\n" : ast_str_append(out, 0, xml ? " /></response>\n" :
"<tr><td colspan=\"2\"><hr></td></tr>\r\n"); "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
inobj = 0; inobj = 0;
continue; continue;
@@ -2637,45 +2647,41 @@ static char *xml_translate(char *in, struct ast_variable *vars, enum output_form
} }
if (!inobj) { if (!inobj) {
if (xml) if (xml)
ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype); ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
else else
ast_build_string(&tmp, &len, "<body>\n"); ast_str_append(out, 0, "<body>\n");
inobj = 1; inobj = 1;
} }
if (!in_data) { /* build appropriate line start */ if (!in_data) { /* build appropriate line start */
ast_build_string(&tmp, &len, xml ? " " : "<tr><td>"); ast_str_append(out, 0, xml ? " " : "<tr><td>");
xml_copy_escape(&tmp, &len, var, xml ? 1 | 2 : 0); xml_copy_escape(out, var, xml ? 1 | 2 : 0);
ast_build_string(&tmp, &len, xml ? "='" : "</td><td>"); ast_str_append(out, 0, xml ? "='" : "</td><td>");
if (!strcmp(var, "Opaque-data")) if (!strcmp(var, "Opaque-data"))
in_data = 1; in_data = 1;
} }
xml_copy_escape(&tmp, &len, val, 0); /* data field */ xml_copy_escape(out, val, 0); /* data field */
if (!in_data) if (!in_data)
ast_build_string(&tmp, &len, xml ? "'" : "</td></tr>\n"); ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
else else
ast_build_string(&tmp, &len, xml ? "\n" : "<br>\n"); ast_str_append(out, 0, xml ? "\n" : "<br>\n");
} }
if (inobj) if (inobj)
ast_build_string(&tmp, &len, xml ? " /></response>\n" : ast_str_append(out, 0, xml ? " /></response>\n" :
"<tr><td colspan=\"2\"><hr></td></tr>\r\n"); "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
return out;
} }
static char *generic_http_callback(enum output_format format, static struct ast_str *generic_http_callback(enum output_format format,
struct sockaddr_in *requestor, const char *uri, struct sockaddr_in *requestor, const char *uri,
struct ast_variable *params, int *status, struct ast_variable *params, int *status,
char **title, int *contentlength) char **title, int *contentlength)
{ {
struct mansession *s = NULL; struct mansession *s = NULL;
unsigned long ident = 0; /* invalid, so find_session will fail if not set through the cookie */ unsigned long ident = 0; /* invalid, so find_session will fail if not set through the cookie */
char workspace[1024];
size_t len = sizeof(workspace);
int blastaway = 0; int blastaway = 0;
char *c = workspace;
char *retval = NULL;
struct message m; struct message m;
struct ast_variable *v; struct ast_variable *v;
char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
struct ast_str *out = NULL;
for (v = params; v; v = v->next) { for (v = params; v; v = v->next) {
if (!strcasecmp(v->name, "mansession_id")) { if (!strcasecmp(v->name, "mansession_id")) {
@@ -2708,23 +2714,27 @@ static char *generic_http_callback(enum output_format format,
} }
ast_mutex_unlock(&s->__lock); ast_mutex_unlock(&s->__lock);
memset(&m, 0, sizeof(m));
{
char tmp[80];
char cookie[128];
ast_build_string(&c, &len, "Content-type: text/%s\r\n", contenttype[format]); out = ast_str_create(1024);
ast_build_string(&c, &len, "Cache-Control: no-cache;\r\n"); if (out == NULL) {
sprintf(tmp, "%08lx", s->managerid); *status = 500;
ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie))); goto generic_callback_out;
} }
memset(&m, 0, sizeof(m));
ast_str_append(&out, 0,
"Content-type: text/%s\r\n"
"Cache-Control: no-cache;\r\n"
"Set-Cookie: mansession_id=\"%08lx\"; Version=\"1\"; Max-Age=%d\r\n"
"\r\n",
contenttype[format],
s->managerid, httptimeout);
if (format == FORMAT_HTML) if (format == FORMAT_HTML)
ast_build_string(&c, &len, "<title>Asterisk&trade; Manager Test Interface</title>"); ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Test Interface</title>");
vars2msg(&m, params); vars2msg(&m, params);
if (format == FORMAT_XML) { if (format == FORMAT_XML) {
ast_build_string(&c, &len, "<ajax-response>\n"); ast_str_append(&out, 0, "<ajax-response>\n");
} else if (format == FORMAT_HTML) { } else if (format == FORMAT_HTML) {
#define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n" #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
@@ -2733,9 +2743,9 @@ static char *generic_http_callback(enum output_format format,
user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br> \ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br> \
<input type=\"submit\"></form>" <input type=\"submit\"></form>"
ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n"); ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
ast_build_string(&c, &len, ROW_FMT, "<h1>Manager Tester</h1>"); ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
ast_build_string(&c, &len, ROW_FMT, TEST_STRING); ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
} }
s->fd = mkstemp(template); /* create a temporary file for command output */ s->fd = mkstemp(template); /* create a temporary file for command output */
@@ -2763,26 +2773,12 @@ static char *generic_http_callback(enum output_format format,
/* always return something even if len == 0 */ /* always return something even if len == 0 */
if ((buf = ast_calloc(1, l+1))) { if ((buf = ast_calloc(1, l+1))) {
char *tmp;
if (l > 0) { if (l > 0) {
fseek(s->f, 0, SEEK_SET); fseek(s->f, 0, SEEK_SET);
fread(buf, 1, l, s->f); fread(buf, 1, l, s->f);
} }
if (format == FORMAT_XML || format == FORMAT_HTML) if (format == FORMAT_XML || format == FORMAT_HTML)
tmp = xml_translate(buf, params, format); xml_translate(&out, buf, params, format);
else
tmp = buf;
if (tmp) {
retval = malloc(strlen(workspace) + strlen(tmp) + 128);
if (retval) {
strcpy(retval, workspace);
strcpy(retval + strlen(retval), tmp);
c = retval + strlen(retval);
len = 120;
}
}
if (tmp != buf)
free(tmp);
free(buf); free(buf);
} }
fclose(s->f); fclose(s->f);
@@ -2794,9 +2790,9 @@ static char *generic_http_callback(enum output_format format,
/* Still okay because c would safely be pointing to workspace even /* Still okay because c would safely be pointing to workspace even
if retval failed to allocate above */ if retval failed to allocate above */
if (format == FORMAT_XML) { if (format == FORMAT_XML) {
ast_build_string(&c, &len, "</ajax-response>\n"); ast_str_append(&out, 0, "</ajax-response>\n");
} else if (format == FORMAT_HTML) } else if (format == FORMAT_HTML)
ast_build_string(&c, &len, "</table></body>\r\n"); ast_str_append(&out, 0, "</table></body>\r\n");
ast_mutex_lock(&s->__lock); ast_mutex_lock(&s->__lock);
/* Reset HTTP timeout. If we're not authenticated, keep it extremely short */ /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
@@ -2825,20 +2821,20 @@ static char *generic_http_callback(enum output_format format,
generic_callback_out: generic_callback_out:
if (*status != 200) if (*status != 200)
return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n"); return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
return retval; return out;
} }
static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength) static struct ast_str *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
{ {
return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength); return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
} }
static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength) static struct ast_str *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
{ {
return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength); return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
} }
static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength) static struct ast_str *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
{ {
return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength); return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
} }