--- src/ne_basic.c	2020-05-15 13:07:40.646410787 +0200
+++ src/ne_basic.c.new	2020-05-19 09:56:17.761164071 +0200
@@ -107,7 +107,7 @@
     ne_lock_using_parent(req, uri);
 #endif
 
-    ne_set_request_body_fd(req, fd, 0, st.st_size);
+    ne_set_request_body_fd(req, fd, 0, st.st_size, NULL);
 	
     ret = ne_request_dispatch(req);
     
--- src/ne_request.c	2020-05-15 13:07:40.646410787 +0200
+++ src/ne_request.c.new	2020-05-19 10:19:41.612890009 +0200
@@ -42,6 +42,10 @@
 #include <unistd.h>
 #endif
 
+#include <sys/stat.h> //AVM
+#include <sys/time.h>
+#include <time.h>
+
 #include "ne_internal.h"
 
 #include "ne_alloc.h"
@@ -101,6 +105,7 @@
             int fd;
             ne_off_t offset, length;
             ne_off_t remain; /* remaining bytes to send. */
+            char* path;
         } file;
 	struct {
             /* length bytes @ buffer = whole body.
@@ -185,7 +190,7 @@
     ne_session *sess = req->session;
     int ret = NE_ERROR;
 
-    NE_DEBUG(NE_DBG_HTTP, "Aborted request (%" NE_FMT_SSIZE_T "): %s\n",
+    NE_DEBUG(NE_DBG_AVM, "Aborted request (%" NE_FMT_SSIZE_T "): %s",
 	     code, doing);
 
     switch(code) {
@@ -199,7 +204,7 @@
 	}
 	break;
     case NE_SOCK_TIMEOUT:
-	ne_set_error(sess, _("%s: connection timed out"), doing);
+	ne_set_error(sess, _("%s: connection timed out (aborted)"), doing);
 	ret = NE_TIMEOUT;
 	break;
     case NE_SOCK_ERROR:
@@ -216,11 +221,12 @@
     return ret;
 }
 
-static void notify_status(ne_session *sess, ne_session_status status)
+static int notify_status(ne_session *sess, ne_session_status status)
 {
     if (sess->notify_cb) {
-	sess->notify_cb(sess->notify_ud, status, &sess->status);
+	   return sess->notify_cb(sess->notify_ud, status, &sess->status);
     }
+    return 0;
 }
 
 static void *get_private(const struct hook *hk, const char *id)
@@ -394,16 +400,24 @@
     }
 
     req->session->status.sr.progress = 0;
-    notify_status(sess, ne_status_sending);
+    req->session->status.sr.duration = 0;
+    req->session->status.sr.current = 0;
+
+    if(notify_status(sess, ne_status_sending)){
+        NE_DEBUG(NE_DBG_AVM, "Send request body: notify abort");
+        ne_close_connection(sess);
+        return NE_ERROR;
+    }
     
     /* tell the source to start again from the beginning. */
     if (req->body_cb(req->body_ud, NULL, 0) != 0) {
+        NE_DEBUG(NE_DBG_AVM, "Send request body: must start again");
         ne_close_connection(sess);
         return NE_ERROR;
     }
     
     while ((bytes = req->body_cb(req->body_ud, start, buflen)) > 0) {
-        req->session->status.sr.progress += bytes;
+        req->session->status.sr.current = bytes;
         if (chunked) {
             /* Overwrite the buffer prefix with the appropriate chunk
              * size; since ne_snprintf always NUL-terminates, the \n
@@ -417,9 +431,13 @@
             buffer[CHUNK_OFFSET - 1] = '\n';
             bytes += CHUNK_OFFSET;
         }
+        //AVM
+        struct timeval start_time;
+        gettimeofday(&start_time, NULL);
         ret = ne_sock_fullwrite(sess->socket, buffer, bytes);
 
         if (ret < 0) {
+            NE_DEBUG(NE_DBG_AVM, "Sending request body failed");
             int aret = aborted(req, _("Could not send request body"), ret);
             return RETRY_RET(retry, ret, aret);
         }
@@ -429,11 +447,34 @@
 		 bytes, (int)bytes, buffer);
 
         /* invoke progress callback */
-        notify_status(sess, ne_status_sending);
+        struct timeval end_time;
+        gettimeofday(&end_time, NULL);
+        req->session->status.sr.duration = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_usec - start_time.tv_usec);
+        if(notify_status(sess, ne_status_sending)){
+            NE_DEBUG(NE_DBG_AVM, "Send request body: notify abort");
+            ne_close_connection(sess);
+            return NE_ERROR;
+        }
+        //-AVM
+#ifdef NE_LFS
+#define ne_stat stat64
+typedef struct stat64 struct_stat;
+#else
+#define ne_stat stat
+typedef struct stat struct_stat;
+#endif
+        struct_stat st;
+        if (req->body.file.fd>0 && req->body.file.path && ne_stat(req->body.file.path, &st)) {
+            /* Abort upload, if file is removed in the meantime */
+            NE_DEBUG(NE_DBG_AVM, "Send request body: upload aborted, input file is lost");
+            ne_close_connection(sess);
+            return NE_ERROR;
+        }
+        //AVM-
     }
 
     if (bytes) {
-        NE_DEBUG(NE_DBG_HTTP, "Request body provider failed with "
+        NE_DEBUG(NE_DBG_AVM, "Request body provider failed with "
                  "%" NE_FMT_SSIZE_T "\n", bytes);
         ne_close_connection(sess);
         return NE_ERROR;
@@ -452,7 +493,7 @@
             return RETRY_RET(retry, ret, aret);
         }
     }
-    
+    NE_DEBUG(NE_DBG_HTTP, "Request body completely sended");
     return NE_OK;
 }
 
@@ -539,6 +580,7 @@
 	    fn(req, hk->userdata, req->method, req->uri);
 	}
     }
+    req->body.file.path = NULL;
 
     return req;
 }
@@ -574,10 +616,11 @@
 }
 
 void ne_set_request_body_fd(ne_request *req, int fd,
-                            ne_off_t offset, ne_off_t length)
+                            ne_off_t offset, ne_off_t length, const char* path)
 {
     req->body.file.fd = fd;
     req->body.file.offset = offset;
+    req->body.file.path = path ? ne_strdup(path) : NULL;
     req->body.file.length = length;
     req->body_cb = body_fd_send;
     req->body_ud = req;
@@ -751,6 +794,9 @@
     if (req->status.reason_phrase)
 	ne_free(req->status.reason_phrase);
 
+    if (req->body.file.path)
+        ne_free(req->body.file.path);
+
     NE_DEBUG(NE_DBG_HTTP, "Request ends.\n");
     ne_free(req);
 }
@@ -860,16 +906,27 @@
     size_t readlen = buflen;
     struct ne_response *const resp = &req->resp;
 
+   //AVM
+    req->session->status.sr.duration = 0;
+    req->session->status.sr.current = 0;
+    struct timeval start_time;
+    gettimeofday(&start_time, NULL);
+
     if (read_response_block(req, resp, buffer, &readlen))
 	return -1;
 
     if (readlen) {
+        struct timeval end_time;
+        gettimeofday(&end_time, NULL);
+        req->session->status.sr.duration = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_usec - start_time.tv_usec);
+        req->session->status.sr.current = readlen;
         req->session->status.sr.progress += readlen;
         notify_status(req->session, ne_status_recving);
     }
 
     for (rdr = req->body_readers; rdr!=NULL; rdr=rdr->next) {
 	if (rdr->use && rdr->handler(rdr->userdata, buffer, readlen) != 0) {
+            NE_DEBUG(NE_DBG_AVM, "req: Closing connection for non-idempotent request.\n");
             ne_close_connection(req->session);
             return -1;
         }
@@ -1244,7 +1301,7 @@
      * do that. */
     if (!req->flags[NE_REQFLAG_IDEMPOTENT] && req->session->persisted
         && !req->session->flags[NE_SESSFLAG_CONNAUTH]) {
-        NE_DEBUG(NE_DBG_HTTP, "req: Closing connection for non-idempotent "
+        NE_DEBUG(NE_DBG_AVM, "req: Closing connection for non-idempotent "
                  "request.\n");
         ne_close_connection(req->session);
     }
@@ -1255,7 +1312,7 @@
     ret = send_request(req, data);
     /* Retry this once after a persistent connection timeout. */
     if (ret == NE_RETRY) {
-	NE_DEBUG(NE_DBG_HTTP, "Persistent connection timed out, retrying.\n");
+	NE_DEBUG(NE_DBG_AVM, "Persistent connection timed out, retrying.\n");
 	ret = send_request(req, data);
     }
     ne_buffer_destroy(data);
@@ -1382,6 +1439,8 @@
     }
 
     req->session->status.sr.progress = 0;
+    req->session->status.sr.duration = 0;
+    req->session->status.sr.current = 0;
     req->session->status.sr.total = 
         req->resp.mode == R_CLENGTH ? req->resp.body.clen.total : -1;
     notify_status(req->session, ne_status_recving);
@@ -1411,8 +1470,10 @@
     
     /* Close the connection if persistent connections are disabled or
      * not supported by the server. */
-    if (!req->session->flags[NE_SESSFLAG_PERSIST] || !req->can_persist)
-	ne_close_connection(req->session);
+    if (!req->session->flags[NE_SESSFLAG_PERSIST] || !req->can_persist) {
+	   NE_DEBUG(NE_DBG_AVM, "End Request: close connection");
+       ne_close_connection(req->session);
+    }
     else
 	req->session->persisted = 1;
     
@@ -1566,9 +1627,9 @@
         sess->status.ci.address = host->current;
 	notify_status(sess, ne_status_connecting);
 #ifdef NE_DEBUGGING
-	if (ne_debug_mask & NE_DBG_HTTP) {
+	if (ne_debug_mask & NE_DBG_AVM) {
 	    char buf[150];
-	    NE_DEBUG(NE_DBG_HTTP, "req: Connecting to %s:%u\n",
+	    NE_DEBUG(NE_DBG_AVM, "req: Connecting to %s:%u\n",
 		     ne_iaddr_print(host->current, buf, sizeof buf),
                      host->port);
 	}
@@ -1578,6 +1639,7 @@
 	     (host->current = resolve_next(host)) != NULL);
 
     if (ret) {
+        NE_DEBUG(NE_DBG_AVM, "Connecting failed: %s\n", ne_sock_error(sess->socket));
         const char *msg;
 
         if (host->proxy == PROXY_NONE)
@@ -1595,6 +1657,7 @@
 
     notify_status(sess, ne_status_connected);
     sess->nexthop = host;
+    NE_DEBUG(NE_DBG_AVM, "Connected");
 
     sess->connected = 1;
     /* clear persistent connection flag. */
@@ -1714,8 +1777,10 @@
         
         if (ret == NE_OK) {
             ret = ne__negotiate_ssl(sess);
-            if (ret != NE_OK)
+            if (ret != NE_OK) {
+                NE_DEBUG(NE_DBG_AVM, "Opening Connection: Negotiate SSL failed");
                 ne_close_connection(sess);
+            }
         }
     }
 #endif
--- src/ne_request.h	2020-05-15 13:07:40.646410787 +0200
+++ src/ne_request.h.new	2020-05-19 10:20:23.356883863 +0200
@@ -59,8 +59,7 @@
 /* The request body will be taken from 'length' bytes read from the
  * file descriptor 'fd', starting from file offset 'offset'. */
 void ne_set_request_body_fd(ne_request *req, int fd,
-                            ne_off_t offset, ne_off_t length)
-    ne_attribute((nonnull));
+                            ne_off_t offset, ne_off_t length, const char* path);
 
 /* "Pull"-based request body provider: a callback which is invoked to
  * provide blocks of request body on demand.