aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-06-29 20:35:09 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-06-29 20:35:09 +0000
commit20e9f5d47c81a1ab3fb3ec4840e6efa35d87e8d9 (patch)
tree9e01621c41fcbbbd3c12d161b63a79ad22099161
parent388ee3fa59e4762d9e1ef20978f3d4c55480c128 (diff)
Merge changes from team/russell/http_filetxfer
Handle transferring large files from the built-in http server. Previously, the code attempted to malloc a block as large as the file itself. Now it uses the sendfile() system call so that the file isn't copied into userspace at all if it is available. Otherwise, it just uses a read/write of small chunks at a time. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@72701 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xconfigure62
-rw-r--r--configure.ac17
-rw-r--r--include/asterisk/autoconfig.h.in3
-rw-r--r--include/asterisk/http.h2
-rw-r--r--main/http.c52
-rw-r--r--main/manager.c12
6 files changed, 119 insertions, 29 deletions
diff --git a/configure b/configure
index 5e36bac66..c440f1898 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 71732 .
+# From configure.ac Revision: 72539 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61.
#
@@ -16476,6 +16476,66 @@ _ACEOF
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+ #include <sys/sendfile.h>
+int
+main ()
+{
+sendfile(1, 0, NULL, 1);
+ ;
+ return 0;
+}
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ have_sendfile=yes
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ have_sendfile=no
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if test "${have_sendfile}" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SENDFILE 1
+_ACEOF
+
+fi
+
# do the package library checks now
diff --git a/configure.ac b/configure.ac
index 4c4a48c7a..9e8279d07 100644
--- a/configure.ac
+++ b/configure.ac
@@ -364,6 +364,23 @@ AC_CHECK_HEADER([libkern/OSAtomic.h],
AC_CHECK_SIZEOF(int)
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include <stdlib.h>
+ #include <sys/sendfile.h>],
+ [sendfile(1, 0, NULL, 1);])
+ ],[
+ AC_MSG_RESULT(yes)
+ have_sendfile=yes
+ ],[
+ AC_MSG_RESULT(no)
+ have_sendfile=no
+ ]
+)
+if test "${have_sendfile}" = "yes"; then
+ AC_DEFINE([HAVE_SENDFILE], 1, [Define if your system has the sendfile syscall.])
+fi
+
# do the package library checks now
AST_EXT_LIB_CHECK([ALSA], [asound], [snd_spcm_init], [alsa/asoundlib.h], [-lm -ldl])
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index 85618b9e3..3f175ddf0 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -394,6 +394,9 @@
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
+/* Define if your system has the sendfile syscall. */
+#undef HAVE_SENDFILE
+
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
diff --git a/include/asterisk/http.h b/include/asterisk/http.h
index 9d92ef5a7..b0215221e 100644
--- a/include/asterisk/http.h
+++ b/include/asterisk/http.h
@@ -147,7 +147,7 @@ int ssl_setup(struct tls_config *cfg);
content is specified)
\endverbatim
*/
-typedef struct ast_str *(*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 server_instance *ser, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength);
/*! \brief Definition of a URI reachable in the embedded HTTP server */
struct ast_http_uri {
diff --git a/main/http.c b/main/http.c
index d6c4e25f3..f71ae0dfb 100644
--- a/main/http.c
+++ b/main/http.c
@@ -48,6 +48,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <fcntl.h>
#include <pthread.h>
+#ifdef HAVE_SENDFILE
+#include <sys/sendfile.h>
+#endif
+
#include "minimime/mm.h"
#include "asterisk/cli.h"
@@ -145,9 +149,8 @@ static const char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
return wkspace;
}
-static struct ast_str *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 server_instance *ser, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
{
- struct ast_str *result;
char *path;
char *ftype;
const char *mtype;
@@ -155,6 +158,8 @@ static struct ast_str *static_callback(struct sockaddr_in *req, const char *uri,
struct stat st;
int len;
int fd;
+ time_t t;
+ char buf[256];
/* 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. */
@@ -185,21 +190,28 @@ static struct ast_str *static_callback(struct sockaddr_in *req, const char *uri,
if (fd < 0)
goto out403;
- len = st.st_size + strlen(mtype) + 40;
- result = ast_str_create(len);
- if (result == NULL) /* XXX not really but... */
- goto out403;
+ time(&t);
+ strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
+ fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
+ "Server: Asterisk/%s\r\n"
+ "Date: %s\r\n"
+ "Connection: close\r\n"
+ "Cache-Control: no-cache, no-store\r\n"
+ "Content-Length: %d\r\n"
+ "Content-type: %s\r\n\r\n",
+ ASTERISK_VERSION, buf, (int) st.st_size, mtype);
+
+ fflush(ser->f);
+
+#ifdef HAVE_SENDFILE
+ sendfile(ser->fd, fd, NULL, st.st_size);
+#else
+ while ((len = read(fd, buf, sizeof(buf))) > 0)
+ write(ser->fd, buf, len);
+#endif
- ast_str_append(&result, 0, "Content-type: %s\r\n\r\n", mtype);
- *contentlength = read(fd, result->str + result->used, st.st_size);
- if (*contentlength < 0) {
- close(fd);
- ast_free(result);
- goto out403;
- }
- result->used += *contentlength;
close(fd);
- return result;
+ return NULL;
out404:
*status = 404;
@@ -213,7 +225,7 @@ out403:
}
-static struct ast_str *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 server_instance *ser, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
{
struct ast_str *out = ast_str_create(512);
struct ast_variable *v;
@@ -541,7 +553,7 @@ static struct ast_str *handle_post(struct server_instance *ser, char *uri,
return ast_http_error(200, "OK", NULL, "File successfully uploaded.");
}
-static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *status,
+static struct ast_str *handle_uri(struct server_instance *ser, char *uri, int *status,
char **title, int *contentlength, struct ast_variable **cookies,
unsigned int *static_content)
{
@@ -627,7 +639,7 @@ static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *statu
if (urih) {
if (urih->static_content)
*static_content = 1;
- out = urih->callback(sin, uri, vars, status, title, contentlength);
+ out = urih->callback(ser, uri, vars, status, title, contentlength);
AST_RWLIST_UNLOCK(&uris);
} else {
out = ast_http_error(404, "Not Found", NULL,
@@ -834,14 +846,12 @@ static void *httpd_helper_thread(void *data)
out = ast_http_error(501, "Not Implemented", NULL,
"Attempt to use unimplemented / unsupported method");
else /* try to serve it */
- out = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content);
+ out = handle_uri(ser, uri, &status, &title, &contentlength, &vars, &static_content);
/* If they aren't mopped up already, clean up the cookies */
if (vars)
ast_variables_destroy(vars);
- if (out == NULL)
- out = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
if (out) {
time_t t = time(NULL);
char timebuf[256];
diff --git a/main/manager.c b/main/manager.c
index 2c66f5fb4..a905bc199 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -3182,19 +3182,19 @@ generic_callback_out:
return out;
}
-static struct ast_str *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 server_instance *ser, 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, &ser->requestor, uri, params, status, title, 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)
+static struct ast_str *mxml_http_callback(struct server_instance *ser, 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, &ser->requestor, uri, params, status, title, 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)
+static struct ast_str *rawman_http_callback(struct server_instance *ser, 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, &ser->requestor, uri, params, status, title, contentlength);
}
struct ast_http_uri rawmanuri = {