diff --git a/configure b/configure index 5e36bac66adfb646e6ed8cf8ef365b69ddb50865..c440f1898686a4b60499e30ec6b4077192b575f0 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 4c4a48c7ad07e9faa8b112f55171d96fe544e818..9e8279d0711a06c784b579db7e15431639e27a54 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 85618b9e35eb878a1ebb4ba3f86c1c67bfe2dcd4..3f175ddf06c7f7cd3309ec8a87e64969426066bc 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 9d92ef5a76b546beb65b91b03aea6160da0f92cf..b0215221e69b87bd60a1734eccd2762521c9f406 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 d6c4e25f3481742461112f26f65ea6238582f1cb..f71ae0dfb18d0d60302daf251ca3d823c18ca9ec 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 2c66f5fb404b748bc43d9aa1bdc414cda6f476fe..a905bc19959314b0f33bf878454d1126a7020352 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 = {