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: https://origsvn.digium.com/svn/asterisk/trunk@72701 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.6.0
Russell Bryant 19 years ago
parent 3caa225108
commit 408dbc4304

62
configure vendored

@ -1,5 +1,5 @@
#! /bin/sh #! /bin/sh
# From configure.ac Revision: 71732 . # From configure.ac Revision: 72539 .
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61. # 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 # do the package library checks now

@ -364,6 +364,23 @@ AC_CHECK_HEADER([libkern/OSAtomic.h],
AC_CHECK_SIZEOF(int) 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 # do the package library checks now
AST_EXT_LIB_CHECK([ALSA], [asound], [snd_spcm_init], [alsa/asoundlib.h], [-lm -ldl]) AST_EXT_LIB_CHECK([ALSA], [asound], [snd_spcm_init], [alsa/asoundlib.h], [-lm -ldl])

@ -394,6 +394,9 @@
/* Define to 1 if you have the `select' function. */ /* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT #undef HAVE_SELECT
/* Define if your system has the sendfile syscall. */
#undef HAVE_SENDFILE
/* Define to 1 if you have the `setenv' function. */ /* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV #undef HAVE_SETENV

@ -147,7 +147,7 @@ int ssl_setup(struct tls_config *cfg);
content is specified) content is specified)
\endverbatim \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 */ /*! \brief Definition of a URI reachable in the embedded HTTP server */
struct ast_http_uri { struct ast_http_uri {

@ -48,6 +48,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
#ifdef HAVE_SENDFILE
#include <sys/sendfile.h>
#endif
#include "minimime/mm.h" #include "minimime/mm.h"
#include "asterisk/cli.h" #include "asterisk/cli.h"
@ -145,9 +149,8 @@ static const char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
return wkspace; 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 *path;
char *ftype; char *ftype;
const char *mtype; const char *mtype;
@ -155,6 +158,8 @@ static struct ast_str *static_callback(struct sockaddr_in *req, const char *uri,
struct stat st; struct stat st;
int len; int len;
int fd; 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 /* 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. */
@ -185,21 +190,28 @@ static struct ast_str *static_callback(struct sockaddr_in *req, const char *uri,
if (fd < 0) if (fd < 0)
goto out403; goto out403;
len = st.st_size + strlen(mtype) + 40; time(&t);
result = ast_str_create(len); strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
if (result == NULL) /* XXX not really but... */ fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
goto out403; "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); close(fd);
return result; return NULL;
out404: out404:
*status = 404; *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_str *out = ast_str_create(512);
struct ast_variable *v; 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."); 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, char **title, int *contentlength, struct ast_variable **cookies,
unsigned int *static_content) 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) {
if (urih->static_content) if (urih->static_content)
*static_content = 1; *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); AST_RWLIST_UNLOCK(&uris);
} else { } else {
out = ast_http_error(404, "Not Found", NULL, 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, 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 */
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 they aren't mopped up already, clean up the cookies */
if (vars) if (vars)
ast_variables_destroy(vars); ast_variables_destroy(vars);
if (out == NULL)
out = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
if (out) { if (out) {
time_t t = time(NULL); time_t t = time(NULL);
char timebuf[256]; char timebuf[256];

@ -3182,19 +3182,19 @@ generic_callback_out:
return 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 = { struct ast_http_uri rawmanuri = {

Loading…
Cancel
Save