diff --git a/examples/embedded_c/embedded_c.c b/examples/embedded_c/embedded_c.c
index 375eb381..13f094f6 100644
--- a/examples/embedded_c/embedded_c.c
+++ b/examples/embedded_c/embedded_c.c
@@ -63,9 +63,9 @@ ExampleHandler(struct mg_connection *conn, void *cbdata)
mg_printf(conn,
"
To see a page from the *.foo handler click xy.foo
");
- mg_printf(
- conn,
- "To see a page from the close handler click close
");
+ mg_printf(conn,
+ "To see a page from the close handler click close
");
mg_printf(conn,
"To see a page from the FileHandler handler click form (this is the form test page)
");
@@ -155,22 +155,23 @@ CloseHandler(struct mg_connection *conn, void *cbdata)
mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
mg_printf(conn, "");
- mg_printf(conn, "This handler will close the connection in a second
");
+ mg_printf(conn,
+ "This handler will close the connection in a second
");
#ifdef _WIN32
- Sleep(1000);
+ Sleep(1000);
#else
- sleep(1);
+ sleep(1);
#endif
mg_printf(conn, "bye");
- printf("CloseHandler: close connection\n");
- mg_close_connection(conn);
- printf("CloseHandler: wait 10 sec\n");
+ printf("CloseHandler: close connection\n");
+ mg_close_connection(conn);
+ printf("CloseHandler: wait 10 sec\n");
#ifdef _WIN32
- Sleep(10000);
+ Sleep(10000);
#else
- sleep(10);
+ sleep(10);
#endif
- printf("CloseHandler: return from function\n");
+ printf("CloseHandler: return from function\n");
return 1;
}
diff --git a/include/civetweb.h b/include/civetweb.h
index 4500b5ab..f0fadd73 100644
--- a/include/civetweb.h
+++ b/include/civetweb.h
@@ -589,6 +589,16 @@ CIVETWEB_API int mg_printf(struct mg_connection *,
CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path);
+/* Store body data into a file. */
+CIVETWEB_API long long mg_store_body(struct mg_connection *conn,
+ const char *path);
+/* Read entire request body and stor it in a file "path".
+ Return:
+ < 0 Error
+ >= 0 Number of bytes stored in file "path".
+*/
+
+
/* Read data from the remote end, return number of bytes read.
Return:
0 connection has been closed by peer. No more data could be read.
diff --git a/src/civetweb.c b/src/civetweb.c
index 104a6bb9..6b014361 100644
--- a/src/civetweb.c
+++ b/src/civetweb.c
@@ -1085,7 +1085,8 @@ enum {
#endif
ACCESS_CONTROL_ALLOW_ORIGIN,
ERROR_PAGES,
- CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the socket option typedef TCP_NODELAY */
+ CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the socket
+ option typedef TCP_NODELAY */
NUM_OPTIONS
};
@@ -2889,6 +2890,7 @@ mg_remove(const char *path)
to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
return DeleteFileW(wbuf) ? 0 : -1;
}
+#endif
static int
@@ -2905,7 +2907,7 @@ mg_mkdir(const char *path, int mode)
return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
}
-#endif
+
/* Create substitutes for POSIX functions in Win32. */
@@ -6446,6 +6448,98 @@ mg_send_file(struct mg_connection *conn, const char *path)
}
+/* For a given PUT path, create all intermediate subdirectories.
+ * Return 0 if the path itself is a directory.
+ * Return 1 if the path leads to a file.
+ * Return -1 for if the path is too long.
+ * Return -2 if path can not be created.
+*/
+static int
+put_dir(struct mg_connection *conn, const char *path)
+{
+ char buf[PATH_MAX];
+ const char *s, *p;
+ struct file file = STRUCT_FILE_INITIALIZER;
+ size_t len;
+ int res = 1;
+
+ for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
+ len = (size_t)(p - path);
+ if (len >= sizeof(buf)) {
+ /* path too long */
+ res = -1;
+ break;
+ }
+ memcpy(buf, path, len);
+ buf[len] = '\0';
+
+ /* Try to create intermediate directory */
+ DEBUG_TRACE("mkdir(%s)", buf);
+ if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
+ /* path does not exixt and can not be created */
+ res = -2;
+ break;
+ }
+
+ /* Is path itself a directory? */
+ if (p[1] == '\0') {
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+
+long long
+mg_store_body(struct mg_connection *conn, const char *path)
+{
+ char buf[MG_BUF_LEN];
+ long long len = 0;
+ int ret, n;
+ FILE *f;
+
+ if (conn->consumed_content != 0) {
+ mg_cry(conn, "%s: Contents already consumed", __func__);
+ return -11;
+ }
+
+ ret = put_dir(conn, path);
+ if (ret < 0) {
+ /* -1 for path too long,
+ * -2 for path can not be created. */
+ return ret;
+ }
+ if (ret != 1) {
+ /* Return 0 means, path itself is a directory. */
+ return 0;
+ }
+
+ f = fopen(path, "w");
+ if (!f) {
+ return -12;
+ }
+
+ ret = mg_read(conn, buf, sizeof(buf));
+ while (ret > 0) {
+ n = (int)fwrite(buf, 1, (size_t)ret, f);
+ if (n != ret) {
+ fclose(f);
+ remove(path);
+ return -13;
+ }
+ ret = mg_read(conn, buf, sizeof(buf));
+ }
+
+ if (fclose(f) != 0) {
+ remove(path);
+ return -14;
+ }
+
+ return len;
+}
+
+
/* Parse HTTP headers from the given buffer, advance buffer to the point
* where parsing stopped. */
static void
@@ -6788,7 +6882,7 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
}
if (conn->consumed_content == conn->content_len) {
- success = nread >= 0;
+ success = (nread >= 0);
}
/* Each error code path in this function must send an error */
@@ -7353,49 +7447,6 @@ done:
#if !defined(NO_FILES)
-/* For a given PUT path, create all intermediate subdirectories.
- * Return 0 if the path itself is a directory.
- * Return 1 if the path leads to a file.
- * Return -1 for if the path is too long.
- * Return -2 if path can not be created.
-*/
-static int
-put_dir(struct mg_connection *conn, const char *path)
-{
- char buf[PATH_MAX];
- const char *s, *p;
- struct file file = STRUCT_FILE_INITIALIZER;
- size_t len;
- int res = 1;
-
- for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
- len = (size_t)(p - path);
- if (len >= sizeof(buf)) {
- /* path too long */
- res = -1;
- break;
- }
- memcpy(buf, path, len);
- buf[len] = '\0';
-
- /* Try to create intermediate directory */
- DEBUG_TRACE("mkdir(%s)", buf);
- if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
- /* path does not exixt and can not be created */
- res = -2;
- break;
- }
-
- /* Is path itself a directory? */
- if (p[1] == '\0') {
- res = 0;
- }
- }
-
- return res;
-}
-
-
static void
mkcol(struct mg_connection *conn, const char *path)
{
@@ -7585,6 +7636,7 @@ put_file(struct mg_connection *conn, const char *path)
/* forward_body_data failed.
* The error code has already been sent to the client,
* and conn->status_code is already set. */
+ mg_fclose(&file);
return;
}
@@ -12003,25 +12055,25 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
}
- /* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
- * to effectively fill up the underlying IP packet payload and reduce
- * the overhead of sending lots of small buffers. However this hurts
- * the server's throughput (ie. operations per second) when HTTP 1.1
- * persistent connections are used and the responses are relatively
- * small (eg. less than 1400 bytes).
- */
- if (ctx && mg_strcasecmp(ctx->config[CONFIG_TCP_NODELAY], "yes") == 0) {
- if (setsockopt(so.sock,
- IPPROTO_TCP,
- TCP_NODELAY,
- (SOCK_OPT_TYPE)&on,
- sizeof(on)) != 0) {
- mg_cry(fc(ctx),
- "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
- __func__,
- strerror(ERRNO));
- }
- }
+ /* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
+ * to effectively fill up the underlying IP packet payload and reduce
+ * the overhead of sending lots of small buffers. However this hurts
+ * the server's throughput (ie. operations per second) when HTTP 1.1
+ * persistent connections are used and the responses are relatively
+ * small (eg. less than 1400 bytes).
+ */
+ if (ctx && mg_strcasecmp(ctx->config[CONFIG_TCP_NODELAY], "yes") == 0) {
+ if (setsockopt(so.sock,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (SOCK_OPT_TYPE)&on,
+ sizeof(on)) != 0) {
+ mg_cry(fc(ctx),
+ "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+ }
if (ctx && ctx->config[REQUEST_TIMEOUT]) {
timeout = atoi(ctx->config[REQUEST_TIMEOUT]);