summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2019-12-29 15:10:59 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2020-07-08 19:54:29 -0400
commit0d62b8657b57ab2eef5ee82a9694c6c0954e20ef (patch)
tree929640d67f14ecca97c2cf6f1b3b77590ee9c24e
parent3f7779d247262fc23984b87afea0d77299b2f8f6 (diff)
downloadlighttpd-git-0d62b8657b57ab2eef5ee82a9694c6c0954e20ef.tar.gz
[mod_webdav] use copy_file_range() if available
-rw-r--r--SConstruct1
-rw-r--r--configure.ac1
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/meson.build1
-rw-r--r--src/mod_webdav.c26
5 files changed, 28 insertions, 2 deletions
diff --git a/SConstruct b/SConstruct
index cea63d11..3d5a8708 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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)) {