diff --git a/mongoose.c b/mongoose.c
index c421938bde9c145cf9a46b6e8b50a4327d4676a0..bf88c32fcde97a7e99d33f706bf1dc87dcf58d9f 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -1602,16 +1602,15 @@ static void write_chunk(struct connection *conn, const char *buf, int len) {
   ns_send(conn->ns_conn, "\r\n", 2);
 }
 
-int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
+size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) {
   struct connection *c = MG_CONN_2_CONN(conn);
-  int len;
   va_list ap;
 
   va_start(ap, fmt);
-  len = ns_vprintf(c->ns_conn, fmt, ap);
+  ns_vprintf(c->ns_conn, fmt, ap);
   va_end(ap);
 
-  return len;
+  return c->ns_conn->send_iobuf.len;
 }
 
 static void ns_forward(struct ns_connection *from, struct ns_connection *to) {
@@ -2176,7 +2175,7 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
     n = (int) strlen(ri->uri);
     mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0);
     if (*ri->uri == '/' || *ri->uri == '.') {
-      remove_double_dots_and_double_slashes((char *) ri->uri);      
+      remove_double_dots_and_double_slashes((char *) ri->uri);
     }
   }
 
@@ -2376,9 +2375,10 @@ static int should_keep_alive(const struct mg_connection *conn) {
      (header == NULL && http_version && !strcmp(http_version, "1.1")));
 }
 
-int mg_write(struct mg_connection *c, const void *buf, int len) {
+size_t mg_write(struct mg_connection *c, const void *buf, int len) {
   struct connection *conn = MG_CONN_2_CONN(c);
-  return ns_send(conn->ns_conn, buf, len);
+  ns_send(conn->ns_conn, buf, len);
+  return conn->ns_conn->send_iobuf.len;
 }
 
 void mg_send_status(struct mg_connection *c, int status) {
@@ -2405,12 +2405,14 @@ static void terminate_headers(struct mg_connection *c) {
   }
 }
 
-void mg_send_data(struct mg_connection *c, const void *data, int data_len) {
+size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) {
+  struct connection *conn = MG_CONN_2_CONN(c);
   terminate_headers(c);
   write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len);
+  return conn->ns_conn->send_iobuf.len;
 }
 
-void mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
+size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
   struct connection *conn = MG_CONN_2_CONN(c);
   va_list ap;
   int len;
@@ -2428,6 +2430,7 @@ void mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
   if (buf != mem && buf != NULL) {
     free(buf);
   }
+  return conn->ns_conn->send_iobuf.len;
 }
 
 #if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH)
@@ -2660,15 +2663,14 @@ static int deliver_websocket_frame(struct connection *conn) {
   return buffered;
 }
 
-int mg_websocket_write(struct mg_connection* conn, int opcode,
+size_t mg_websocket_write(struct mg_connection* conn, int opcode,
                        const char *data, size_t data_len) {
     unsigned char mem[4192], *copy = mem;
     size_t copy_len = 0;
-    int retval = -1;
 
     if (data_len + 10 > sizeof(mem) &&
         (copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
-      return -1;
+      return 0;
     }
 
     copy[0] = 0x80 + (opcode & 0x0f);
@@ -2696,17 +2698,17 @@ int mg_websocket_write(struct mg_connection* conn, int opcode,
     }
 
     if (copy_len > 0) {
-      retval = mg_write(conn, copy, copy_len);
+      mg_write(conn, copy, copy_len);
     }
     if (copy != mem) {
       free(copy);
     }
 
-    return retval;
+    return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
 }
 
-int mg_websocket_printf(struct mg_connection* conn, int opcode,
-                        const char *fmt, ...) {
+size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
+                           const char *fmt, ...) {
   char mem[4192], *buf = mem;
   va_list ap;
   int len;
@@ -2721,7 +2723,7 @@ int mg_websocket_printf(struct mg_connection* conn, int opcode,
     free(buf);
   }
 
-  return len;
+  return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
 }
 
 static void send_websocket_handshake_if_requested(struct mg_connection *conn) {
@@ -4121,8 +4123,9 @@ static void proxify_connection(struct connection *conn) {
   }
 }
 
-static void open_local_endpoint(struct connection *conn, int skip_user) {
 #ifndef MONGOOSE_NO_FILESYSTEM
+void mg_send_file(struct mg_connection *c, const char *file_name) {
+  struct connection *conn = MG_CONN_2_CONN(c);
   file_stat_t st;
   char path[MAX_PATH_SIZE];
   int exists = 0, is_directory = 0;
@@ -4136,7 +4139,57 @@ static void open_local_endpoint(struct connection *conn, int skip_user) {
 #else
   const char *dir_lst = "yes";
 #endif
+
+  mg_snprintf(path, sizeof(path), "%s", file_name);
+  exists = stat(path, &st) == 0;
+  is_directory = S_ISDIR(st.st_mode);
+  
+  if (!exists || must_hide_file(conn, path)) {
+    send_http_error(conn, 404, NULL);
+  } else if (is_directory &&
+             conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') {
+    conn->mg_conn.status_code = 301;
+    mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
+              "Location: %s/\r\n\r\n", conn->mg_conn.uri);
+    close_local_endpoint(conn);
+  } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) {
+    if (!mg_strcasecmp(dir_lst, "yes")) {
+#ifndef MONGOOSE_NO_DIRECTORY_LISTING
+      send_directory_listing(conn, path);
+#else
+      send_http_error(conn, 501, NULL);
+#endif
+    } else {
+      send_http_error(conn, 403, NULL);
+    }
+  } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) {
+#if !defined(MONGOOSE_NO_CGI)
+    open_cgi_endpoint(conn, path);
+#else
+    send_http_error(conn, 501, NULL);
+#endif // !MONGOOSE_NO_CGI
+#ifndef MONGOOSE_NO_SSI
+  } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN],
+                             strlen(conn->server->config_options[SSI_PATTERN]),
+                             path) > 0) {
+    handle_ssi_request(conn, path);
 #endif
+  } else if (is_not_modified(conn, &st)) {
+    send_http_error(conn, 304, NULL);
+  } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) {
+    // O_BINARY is required for Windows, otherwise in default text mode
+    // two bytes \r\n will be read as one.
+    open_file_endpoint(conn, path, &st);
+  } else {
+    send_http_error(conn, 404, NULL);
+  }
+}
+#endif  // !MONGOOSE_NO_FILESYSTEM
+
+static void open_local_endpoint(struct connection *conn, int skip_user) {
+  char path[MAX_PATH_SIZE];
+  file_stat_t st;
+  int exists = 0;
 
   // If EP_USER was set in a prev call, reset it
   conn->endpoint_type = EP_NONE;
@@ -4170,16 +4223,16 @@ static void open_local_endpoint(struct connection *conn, int skip_user) {
     proxify_connection(conn);
     return;
   }
-
-#ifdef MONGOOSE_NO_FILESYSTEM
+  
   if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
     send_options(conn);
-  } else {
-    send_http_error(conn, 404, NULL);
+    return;
   }
+  
+#ifdef MONGOOSE_NO_FILESYSTEM
+  send_http_error(conn, 404, NULL);
 #else
   exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
-  is_directory = S_ISDIR(st.st_mode);
 
   if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
     send_options(conn);
@@ -4201,44 +4254,8 @@ static void open_local_endpoint(struct connection *conn, int skip_user) {
   } else if (!strcmp(conn->mg_conn.request_method, "PUT")) {
     handle_put(conn, path);
 #endif
-  } else if (!exists || must_hide_file(conn, path)) {
-    send_http_error(conn, 404, NULL);
-  } else if (is_directory &&
-             conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') {
-    conn->mg_conn.status_code = 301;
-    mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
-              "Location: %s/\r\n\r\n", conn->mg_conn.uri);
-    close_local_endpoint(conn);
-  } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) {
-    if (!mg_strcasecmp(dir_lst, "yes")) {
-#ifndef MONGOOSE_NO_DIRECTORY_LISTING
-      send_directory_listing(conn, path);
-#else
-      send_http_error(conn, 501, NULL);
-#endif
-    } else {
-      send_http_error(conn, 403, NULL);
-    }
-  } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) {
-#if !defined(MONGOOSE_NO_CGI)
-    open_cgi_endpoint(conn, path);
-#else
-    send_http_error(conn, 501, NULL);
-#endif // !MONGOOSE_NO_CGI
-#ifndef MONGOOSE_NO_SSI
-  } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN],
-                             strlen(conn->server->config_options[SSI_PATTERN]),
-                             path) > 0) {
-    handle_ssi_request(conn, path);
-#endif
-  } else if (is_not_modified(conn, &st)) {
-    send_http_error(conn, 304, NULL);
-  } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) {
-    // O_BINARY is required for Windows, otherwise in default text mode
-    // two bytes \r\n will be read as one.
-    open_file_endpoint(conn, path, &st);
   } else {
-    send_http_error(conn, 404, NULL);
+    mg_send_file(&conn->mg_conn, path);
   }
 #endif  // MONGOOSE_NO_FILESYSTEM
 }
diff --git a/mongoose.h b/mongoose.h
index 18afc2ff7adb03a9f82495f892f3f01e712bd74e..fc431886da4c283f71823d7a9b8664e7028604fd 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -99,17 +99,15 @@ struct mg_connection *mg_connect(struct mg_server *, const char *, int, int);
 // Connection management functions
 void mg_send_status(struct mg_connection *, int status_code);
 void mg_send_header(struct mg_connection *, const char *name, const char *val);
-void mg_send_data(struct mg_connection *, const void *data, int data_len);
-void mg_printf_data(struct mg_connection *, const char *format, ...);
+size_t mg_send_data(struct mg_connection *, const void *data, int data_len);
+size_t mg_printf_data(struct mg_connection *, const char *format, ...);
+size_t mg_write(struct mg_connection *, const void *buf, int len);
+size_t mg_printf(struct mg_connection *conn, const char *fmt, ...);
 
-int mg_websocket_write(struct mg_connection *, int opcode,
-                       const char *data, size_t data_len);
-int mg_websocket_printf(struct mg_connection* conn, int opcode,
-                        const char *fmt, ...);
-
-// Deprecated in favor of mg_send_* interface
-int mg_write(struct mg_connection *, const void *buf, int len);
-int mg_printf(struct mg_connection *conn, const char *fmt, ...);
+size_t mg_websocket_write(struct mg_connection *, int opcode,
+                          const char *data, size_t data_len);
+size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
+                           const char *fmt, ...);
 
 const char *mg_get_header(const struct mg_connection *, const char *name);
 const char *mg_get_mime_type(const char *name, const char *default_mime_type);
@@ -122,6 +120,7 @@ int mg_parse_multipart(const char *buf, int buf_len,
                        const char **data, int *data_len);
 
 // Utility functions
+void mg_send_file(struct mg_connection *, const char *path);
 void *mg_start_thread(void *(*func)(void *), void *param);
 char *mg_md5(char buf[33], ...);
 int mg_authorize_digest(struct mg_connection *c, FILE *fp);