mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-27 20:59:00 +08:00
Add form-upload example
This commit is contained in:
parent
41c1e0f08d
commit
4dbb2da78f
@ -846,28 +846,8 @@ Parse the multipart chunk in the `body` at a given `offset`. An initial
|
||||
`offset` should be 0. Fill up parameters in the provided `part`, which could be
|
||||
NULL. Return offset to the next chunk, or 0 if there are no more chunks.
|
||||
|
||||
Usage example:
|
||||
See `form-upload` example for a usage example.
|
||||
|
||||
```c
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_http_match_uri(hm, "/upload")) {
|
||||
struct mg_http_part part;
|
||||
size_t ofs = 0;
|
||||
while ((ofs = mg_http_next_multipart(ev->body, ofs, &part)) > 0) {
|
||||
LOG(LL_INFO, ("Name: [%.*s] Filename: [%.*s] Body: [%.*s]",
|
||||
(int) part.name.len, part.name.ptr,
|
||||
(int) part.filename.len, part.filename.ptr,
|
||||
(int) part.body.len, part.body.ptr));
|
||||
}
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
|
10
examples/form-upload/Makefile
Normal file
10
examples/form-upload/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
PROG ?= example
|
||||
|
||||
all: $(PROG)
|
||||
$(DEBUGGER) ./$(PROG)
|
||||
|
||||
$(PROG):
|
||||
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
42
examples/form-upload/main.c
Normal file
42
examples/form-upload/main.c
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// HTTP request handler function. It implements the following endpoints:
|
||||
// /upload - prints all submitted form elements
|
||||
// all other URI - serves web_root/ directory
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
LOG(LL_INFO, ("New request to: [%.*s]", (int) hm->uri.len, hm->uri.ptr));
|
||||
if (mg_http_match_uri(hm, "/upload")) {
|
||||
struct mg_http_part part;
|
||||
size_t ofs = 0;
|
||||
while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
|
||||
LOG(LL_INFO,
|
||||
("Name: [%.*s] Filename: [%.*s] Body: [%.*s]", (int) part.name.len,
|
||||
part.name.ptr, (int) part.filename.len, part.filename.ptr,
|
||||
(int) part.body.len, part.body.ptr));
|
||||
}
|
||||
mg_http_reply(c, 200, "", "Thank you!");
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
struct mg_timer t1;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_log_set("3");
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 50);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
40
examples/form-upload/web_root/index.html
Normal file
40
examples/form-upload/web_root/index.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>example</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#wrapper { margin-top: 1em; }
|
||||
form * { margin: 0.2em 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
Mongoose always buffers a full HTTP message before invoking
|
||||
MG_EV_HTTP_MSG event. Big POST request require of lot
|
||||
of RAM to buffer everything. Therefore, standard form uploads
|
||||
should be used only when Mongoose runs on a system with lots of RAM.
|
||||
Otherwise, please see <code>file-updload</code> example, how
|
||||
a big file could be uploaded to a device with little RAM.
|
||||
<br/><br/>
|
||||
In this example, a standard HTML form upload is used, which uses
|
||||
<code>multipart-form-data</code> encoding with
|
||||
several variables and file upload. On a server side, a
|
||||
<code>mg_http_next_multipart()</code> API is used to iterate over
|
||||
all submitted form elements and print their payload.
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="text" name="field1" value="type some text here" /> <br/>
|
||||
<input type="file" name="file1" /> </br>
|
||||
<button type="submit">submit form</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
13
mongoose.c
13
mongoose.c
@ -470,8 +470,8 @@ size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
|
||||
h1 = h2 = h2 + 2;
|
||||
}
|
||||
b1 = b2 = h2 + 2;
|
||||
while (b2 + 2 + (b - ofs) + 2 < max && s[b2] != '\r' && s[b2 + 1] != '\n' &&
|
||||
memcmp(&s[b2 + 2], s, b - ofs) != 0)
|
||||
while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
|
||||
memcmp(&s[b2 + 2], s, b - ofs) == 0))
|
||||
b2++;
|
||||
|
||||
if (b2 + 2 >= max) return 0;
|
||||
@ -1224,9 +1224,12 @@ struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
|
||||
size_t i;
|
||||
for (i = 0; i + v.len + 2 < s.len; i++) {
|
||||
if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
|
||||
const char *p2 = &s.ptr[i + v.len + 1], *p3 = p2;
|
||||
while (p2 < &s.ptr[s.len] && p2[0] != ';' && p2[0] != ' ') p2++;
|
||||
return stripquotes(mg_str_n(p3, p2 - p3));
|
||||
const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
|
||||
int q = p < x && *p == '"' ? 1 : 0;
|
||||
while (p < x && (q ? p == b || *p != '"' : *p != ';' && *p != ' ')) p++;
|
||||
// LOG(LL_INFO, ("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
|
||||
// v.ptr, (int) (p - b), b));
|
||||
return stripquotes(mg_str_n(b, p - b + q));
|
||||
}
|
||||
}
|
||||
return mg_str_n(NULL, 0);
|
||||
|
13
src/http.c
13
src/http.c
@ -51,8 +51,8 @@ size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
|
||||
h1 = h2 = h2 + 2;
|
||||
}
|
||||
b1 = b2 = h2 + 2;
|
||||
while (b2 + 2 + (b - ofs) + 2 < max && s[b2] != '\r' && s[b2 + 1] != '\n' &&
|
||||
memcmp(&s[b2 + 2], s, b - ofs) != 0)
|
||||
while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
|
||||
memcmp(&s[b2 + 2], s, b - ofs) == 0))
|
||||
b2++;
|
||||
|
||||
if (b2 + 2 >= max) return 0;
|
||||
@ -805,9 +805,12 @@ struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
|
||||
size_t i;
|
||||
for (i = 0; i + v.len + 2 < s.len; i++) {
|
||||
if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
|
||||
const char *p2 = &s.ptr[i + v.len + 1], *p3 = p2;
|
||||
while (p2 < &s.ptr[s.len] && p2[0] != ';' && p2[0] != ' ') p2++;
|
||||
return stripquotes(mg_str_n(p3, p2 - p3));
|
||||
const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
|
||||
int q = p < x && *p == '"' ? 1 : 0;
|
||||
while (p < x && (q ? p == b || *p != '"' : *p != ';' && *p != ' ')) p++;
|
||||
// LOG(LL_INFO, ("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
|
||||
// v.ptr, (int) (p - b), b));
|
||||
return stripquotes(mg_str_n(b, p - b + q));
|
||||
}
|
||||
}
|
||||
return mg_str_n(NULL, 0);
|
||||
|
@ -1265,9 +1265,9 @@ static void test_multipart(void) {
|
||||
"--xyz\r\n"
|
||||
"Content-Disposition: form-data; name=\"val\"\r\n"
|
||||
"\r\n"
|
||||
"abcdef\r\n"
|
||||
"abc\r\ndef\r\n"
|
||||
"--xyz\r\n"
|
||||
"Content-Disposition: form-data; name=\"foo\"; filename=\"a.txt\"\r\n"
|
||||
"Content-Disposition: form-data; name=\"foo\"; filename=\"a b.txt\"\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"\r\n"
|
||||
"hello world\r\n"
|
||||
@ -1276,12 +1276,14 @@ static void test_multipart(void) {
|
||||
ASSERT(mg_http_next_multipart(mg_str(""), 0, NULL) == 0);
|
||||
ASSERT((ofs = mg_http_next_multipart(mg_str(s), 0, &part)) > 0);
|
||||
ASSERT(mg_strcmp(part.name, mg_str("val")) == 0);
|
||||
ASSERT(mg_strcmp(part.body, mg_str("abcdef")) == 0);
|
||||
// LOG(LL_INFO, ("--> [%.*s]", (int) part.body.len, part.body.ptr));
|
||||
ASSERT(mg_strcmp(part.body, mg_str("abc\r\ndef")) == 0);
|
||||
ASSERT(part.filename.len == 0);
|
||||
ASSERT((ofs = mg_http_next_multipart(mg_str(s), ofs, &part)) > 0);
|
||||
ASSERT(mg_strcmp(part.name, mg_str("foo")) == 0);
|
||||
ASSERT(mg_strcmp(part.filename, mg_str("a.txt")) == 0);
|
||||
ASSERT(mg_strcmp(part.body, mg_str("hello world")) == 0);
|
||||
// LOG(LL_INFO, ("--> [%.*s]", (int) part.filename.len, part.filename.ptr));
|
||||
ASSERT(mg_strcmp(part.filename, mg_str("a b.txt")) == 0);
|
||||
ASSERT(mg_strcmp(part.body, mg_str("hello world\r\n")) == 0);
|
||||
ASSERT(mg_http_next_multipart(mg_str(s), ofs, &part) == 0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user