diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2019-12-29 15:10:59 -0500 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2020-07-08 19:54:29 -0400 |
commit | 0d62b8657b57ab2eef5ee82a9694c6c0954e20ef (patch) | |
tree | 929640d67f14ecca97c2cf6f1b3b77590ee9c24e | |
parent | 3f7779d247262fc23984b87afea0d77299b2f8f6 (diff) | |
download | lighttpd-git-0d62b8657b57ab2eef5ee82a9694c6c0954e20ef.tar.gz |
[mod_webdav] use copy_file_range() if available
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/meson.build | 1 | ||||
-rw-r--r-- | src/mod_webdav.c | 26 |
5 files changed, 28 insertions, 2 deletions
@@ -386,6 +386,7 @@ if 1: 'arc4random_buf', 'chroot', 'clock_gettime', + 'copy_file_range', 'dup2', 'epoll_ctl', 'explicit_bzero', diff --git a/configure.ac b/configure.ac index b219c8b7..e9f0b60e 100644 --- a/configure.ac +++ b/configure.ac @@ -1216,6 +1216,7 @@ AC_CHECK_FUNCS([\ arc4random_buf \ chroot \ clock_gettime \ + copy_file_range \ epoll_ctl \ explicit_bzero \ explicit_memset \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb78de22..1386eeec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -150,6 +150,7 @@ check_type_size(off_t SIZEOF_OFF_T) check_function_exists(arc4random_buf HAVE_ARC4RANDOM_BUF) check_function_exists(chroot HAVE_CHROOT) +check_function_exists(copy_file_range HAVE_COPY_FILE_RANGE) check_function_exists(epoll_ctl HAVE_EPOLL_CTL) check_function_exists(fork HAVE_FORK) check_function_exists(getloadavg HAVE_GETLOADAVG) diff --git a/src/meson.build b/src/meson.build index 01aed93b..6de4a884 100644 --- a/src/meson.build +++ b/src/meson.build @@ -113,6 +113,7 @@ conf_data.set('SIZEOF_OFF_T', compiler.sizeof('off_t', args: defs)) conf_data.set('HAVE_ARC4RANDOM_BUF', compiler.has_function('arc4random_buf', args: defs)) conf_data.set('HAVE_CHROOT', compiler.has_function('chroot', args: defs)) +conf_data.set('HAVE_COPY_FILE_RANGE', compiler.has_function('copy_file_range', args: defs)) conf_data.set('HAVE_EPOLL_CTL', compiler.has_function('epoll_ctl', args: defs)) conf_data.set('HAVE_FORK', compiler.has_function('fork', args: defs)) conf_data.set('HAVE_GETLOADAVG', compiler.has_function('getloadavg', args: defs)) diff --git a/src/mod_webdav.c b/src/mod_webdav.c index c23dd356..29e48b06 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -4369,11 +4369,11 @@ mod_webdav_put_deprecated_unsafe_partial_put_compat (connection * const con, const char *num = h->ptr; off_t offset; char *err; - if (0 != strncmp(num, "bytes", sizeof("bytes")-1)) { + if (0 != strncmp(num, "bytes ", sizeof("bytes ")-1)) { http_status_set_error(con, 501); /* Not Implemented */ return HANDLER_FINISHED; } - num += 5; /* +5 for "bytes" */ + num += sizeof("bytes ")-1; /* +6 for "bytes " */ offset = strtoll(num, &err, 10); /*(strtoll() ignores leading whitespace)*/ if (num == err || *err != '-' || offset < 0) { http_status_set_error(con, 501); /* Not Implemented */ @@ -4387,6 +4387,27 @@ mod_webdav_put_deprecated_unsafe_partial_put_compat (connection * const con, return HANDLER_FINISHED; } + #ifdef HAVE_COPY_FILE_RANGE + /* use Linux copy_file_range() if available + * (Linux 4.5, but glibc 2.27 provides a user-space emulation) + * fd_in and fd_out must be on same mount (handled in mod_webdav_put_prep()) + * check that reqbody is contained in single tempfile and open fd (expected) + * (Note: copying might take some time, temporarily pausing server) + */ + chunkqueue * const cq = con->request_content_queue; + chunk *c = cq->first; + off_t cqlen = chunkqueue_length(cq); + if (c->type == FILE_CHUNK && NULL == c->next && c->file.fd >= 0) { + loff_t zoff = 0; + loff_t ooff = offset; + ssize_t wr; + do { + wr = copy_file_range(c->file.fd,&zoff,fd,&ooff,(size_t)cqlen, 0); + } while (wr >= 0 && (cqlen -= wr)); + } + if (0 != cqlen) /* fallback, retry if copy_file_range() did not finish */ + #endif + { if (-1 == lseek(fd, offset, SEEK_SET)) { close(fd); http_status_set_error(con, 500); /* Internal Server Error */ @@ -4398,6 +4419,7 @@ mod_webdav_put_deprecated_unsafe_partial_put_compat (connection * const con, * (Note: copying might take some time, temporarily pausing server) * (error status is set if error occurs) */ mod_webdav_write_cq(con, con->request_content_queue, fd); + } struct stat st; if (0 != con->conf.etag_flags && !http_status_is_set(con)) { |