mirror of
https://github.com/lammertb/libhttp.git
synced 2025-08-09 03:22:45 +03:00
Add funtion to store body data
This commit is contained in:
@@ -63,9 +63,9 @@ ExampleHandler(struct mg_connection *conn, void *cbdata)
|
|||||||
mg_printf(conn,
|
mg_printf(conn,
|
||||||
"<p>To see a page from the *.foo handler <a "
|
"<p>To see a page from the *.foo handler <a "
|
||||||
"href=\"xy.foo\">click xy.foo</a></p>");
|
"href=\"xy.foo\">click xy.foo</a></p>");
|
||||||
mg_printf(
|
mg_printf(conn,
|
||||||
conn,
|
"<p>To see a page from the close handler <a "
|
||||||
"<p>To see a page from the close handler <a href=\"close\">click close</a></p>");
|
"href=\"close\">click close</a></p>");
|
||||||
mg_printf(conn,
|
mg_printf(conn,
|
||||||
"<p>To see a page from the FileHandler handler <a "
|
"<p>To see a page from the FileHandler handler <a "
|
||||||
"href=\"form\">click form</a> (this is the form test page)</p>");
|
"href=\"form\">click form</a> (this is the form test page)</p>");
|
||||||
@@ -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, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
|
||||||
mg_printf(conn, "<html><body>");
|
mg_printf(conn, "<html><body>");
|
||||||
mg_printf(conn, "<h2>This handler will close the connection in a second</h2>");
|
mg_printf(conn,
|
||||||
|
"<h2>This handler will close the connection in a second</h2>");
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
#else
|
#else
|
||||||
sleep(1);
|
sleep(1);
|
||||||
#endif
|
#endif
|
||||||
mg_printf(conn, "bye");
|
mg_printf(conn, "bye");
|
||||||
printf("CloseHandler: close connection\n");
|
printf("CloseHandler: close connection\n");
|
||||||
mg_close_connection(conn);
|
mg_close_connection(conn);
|
||||||
printf("CloseHandler: wait 10 sec\n");
|
printf("CloseHandler: wait 10 sec\n");
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Sleep(10000);
|
Sleep(10000);
|
||||||
#else
|
#else
|
||||||
sleep(10);
|
sleep(10);
|
||||||
#endif
|
#endif
|
||||||
printf("CloseHandler: return from function\n");
|
printf("CloseHandler: return from function\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
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.
|
/* Read data from the remote end, return number of bytes read.
|
||||||
Return:
|
Return:
|
||||||
0 connection has been closed by peer. No more data could be read.
|
0 connection has been closed by peer. No more data could be read.
|
||||||
|
182
src/civetweb.c
182
src/civetweb.c
@@ -1085,7 +1085,8 @@ enum {
|
|||||||
#endif
|
#endif
|
||||||
ACCESS_CONTROL_ALLOW_ORIGIN,
|
ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||||
ERROR_PAGES,
|
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
|
NUM_OPTIONS
|
||||||
};
|
};
|
||||||
@@ -2889,6 +2890,7 @@ mg_remove(const char *path)
|
|||||||
to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
|
to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
|
||||||
return DeleteFileW(wbuf) ? 0 : -1;
|
return DeleteFileW(wbuf) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -2905,7 +2907,7 @@ mg_mkdir(const char *path, int mode)
|
|||||||
|
|
||||||
return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
|
return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Create substitutes for POSIX functions in Win32. */
|
/* 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
|
/* Parse HTTP headers from the given buffer, advance buffer to the point
|
||||||
* where parsing stopped. */
|
* where parsing stopped. */
|
||||||
static void
|
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) {
|
if (conn->consumed_content == conn->content_len) {
|
||||||
success = nread >= 0;
|
success = (nread >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Each error code path in this function must send an error */
|
/* Each error code path in this function must send an error */
|
||||||
@@ -7353,49 +7447,6 @@ done:
|
|||||||
|
|
||||||
|
|
||||||
#if !defined(NO_FILES)
|
#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
|
static void
|
||||||
mkcol(struct mg_connection *conn, const char *path)
|
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.
|
/* forward_body_data failed.
|
||||||
* The error code has already been sent to the client,
|
* The error code has already been sent to the client,
|
||||||
* and conn->status_code is already set. */
|
* and conn->status_code is already set. */
|
||||||
|
mg_fclose(&file);
|
||||||
return;
|
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
|
/* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
|
||||||
* to effectively fill up the underlying IP packet payload and reduce
|
* to effectively fill up the underlying IP packet payload and reduce
|
||||||
* the overhead of sending lots of small buffers. However this hurts
|
* the overhead of sending lots of small buffers. However this hurts
|
||||||
* the server's throughput (ie. operations per second) when HTTP 1.1
|
* the server's throughput (ie. operations per second) when HTTP 1.1
|
||||||
* persistent connections are used and the responses are relatively
|
* persistent connections are used and the responses are relatively
|
||||||
* small (eg. less than 1400 bytes).
|
* small (eg. less than 1400 bytes).
|
||||||
*/
|
*/
|
||||||
if (ctx && mg_strcasecmp(ctx->config[CONFIG_TCP_NODELAY], "yes") == 0) {
|
if (ctx && mg_strcasecmp(ctx->config[CONFIG_TCP_NODELAY], "yes") == 0) {
|
||||||
if (setsockopt(so.sock,
|
if (setsockopt(so.sock,
|
||||||
IPPROTO_TCP,
|
IPPROTO_TCP,
|
||||||
TCP_NODELAY,
|
TCP_NODELAY,
|
||||||
(SOCK_OPT_TYPE)&on,
|
(SOCK_OPT_TYPE)&on,
|
||||||
sizeof(on)) != 0) {
|
sizeof(on)) != 0) {
|
||||||
mg_cry(fc(ctx),
|
mg_cry(fc(ctx),
|
||||||
"%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
|
"%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
|
||||||
__func__,
|
__func__,
|
||||||
strerror(ERRNO));
|
strerror(ERRNO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx && ctx->config[REQUEST_TIMEOUT]) {
|
if (ctx && ctx->config[REQUEST_TIMEOUT]) {
|
||||||
timeout = atoi(ctx->config[REQUEST_TIMEOUT]);
|
timeout = atoi(ctx->config[REQUEST_TIMEOUT]);
|
||||||
|
Reference in New Issue
Block a user