]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merge changes from team/russell/http_filetxfer
authorRussell Bryant <russell@russellbryant.com>
Fri, 29 Jun 2007 20:35:09 +0000 (20:35 +0000)
committerRussell Bryant <russell@russellbryant.com>
Fri, 29 Jun 2007 20:35:09 +0000 (20:35 +0000)
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

configure
configure.ac
include/asterisk/autoconfig.h.in
include/asterisk/http.h
main/http.c
main/manager.c

index 5e36bac66adfb646e6ed8cf8ef365b69ddb50865..c440f1898686a4b60499e30ec6b4077192b575f0 100755 (executable)
--- 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
 
 
index 4c4a48c7ad07e9faa8b112f55171d96fe544e818..9e8279d0711a06c784b579db7e15431639e27a54 100644 (file)
@@ -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])
index 85618b9e35eb878a1ebb4ba3f86c1c67bfe2dcd4..3f175ddf06c7f7cd3309ec8a87e64969426066bc 100644 (file)
 /* 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
 
index 9d92ef5a76b546beb65b91b03aea6160da0f92cf..b0215221e69b87bd60a1734eccd2762521c9f406 100644 (file)
@@ -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 {
index d6c4e25f3481742461112f26f65ea6238582f1cb..f71ae0dfb18d0d60302daf251ca3d823c18ca9ec 100644 (file)
@@ -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];
index 2c66f5fb404b748bc43d9aa1bdc414cda6f476fe..a905bc19959314b0f33bf878454d1126a7020352 100644 (file)
@@ -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 = {