Skip to content

Commit f01807e

Browse files
committed
Add file upload functionality to the http-server example
1 parent a4ed740 commit f01807e

File tree

1 file changed

+44
-12
lines changed

1 file changed

+44
-12
lines changed

examples/http-server/main.c

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ static const char *s_root_dir = ".";
99
static const char *s_listening_address = "http://0.0.0.0:8000";
1010
static const char *s_enable_hexdump = "no";
1111
static const char *s_ssi_pattern = "#.html";
12+
static const char *s_upload_dir = NULL; // File uploads disabled by default
1213

1314
// Handle interrupts, like Ctrl-C
1415
static int s_signo;
@@ -20,18 +21,45 @@ static void signal_handler(int signo) {
2021
// Simply serve static files from `s_root_dir`
2122
static void cb(struct mg_connection *c, int ev, void *ev_data) {
2223
if (ev == MG_EV_HTTP_MSG) {
23-
struct mg_http_message *hm = ev_data, tmp = {0};
24-
struct mg_str unknown = mg_str_n("?", 1), *cl;
25-
struct mg_http_serve_opts opts = {0};
26-
opts.root_dir = s_root_dir;
27-
opts.ssi_pattern = s_ssi_pattern;
28-
mg_http_serve_dir(c, hm, &opts);
29-
mg_http_parse((char *) c->send.buf, c->send.len, &tmp);
30-
cl = mg_http_get_header(&tmp, "Content-Length");
31-
if (cl == NULL) cl = &unknown;
32-
MG_INFO(("%.*s %.*s %.*s %.*s", (int) hm->method.len, hm->method.ptr,
33-
(int) hm->uri.len, hm->uri.ptr, (int) tmp.uri.len, tmp.uri.ptr,
34-
(int) cl->len, cl->ptr));
24+
struct mg_http_message *hm = ev_data;
25+
26+
if (mg_match(hm->uri, mg_str("/upload"), NULL)) {
27+
// Serve file upload
28+
if (s_upload_dir == NULL) {
29+
mg_http_reply(c, 403, "", "Denied: file upload directory not set\n");
30+
} else {
31+
struct mg_http_part part;
32+
size_t pos = 0, total_bytes = 0, num_files = 0;
33+
while ((pos = mg_http_next_multipart(hm->body, pos, &part)) > 0) {
34+
char path[MG_PATH_MAX];
35+
MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
36+
part.name.len, part.name.ptr, part.filename.len,
37+
part.filename.ptr, part.body.len));
38+
mg_snprintf(path, sizeof(path), "%s/%.*s", s_upload_dir,
39+
part.filename.len, part.filename.ptr);
40+
if (mg_path_is_sane(path)) {
41+
mg_file_write(&mg_fs_posix, path, part.body.ptr, part.body.len);
42+
total_bytes += part.body.len;
43+
num_files++;
44+
} else {
45+
MG_ERROR(("Rejecting dangerous path %s", path));
46+
}
47+
}
48+
mg_http_reply(c, 200, "", "Uploaded %lu files, %lu bytes\n", num_files,
49+
total_bytes);
50+
}
51+
} else {
52+
// Serve web root directory
53+
struct mg_http_serve_opts opts = {0};
54+
opts.root_dir = s_root_dir;
55+
opts.ssi_pattern = s_ssi_pattern;
56+
mg_http_serve_dir(c, hm, &opts);
57+
}
58+
59+
// Log request
60+
MG_INFO(("%.*s %.*s %lu -> %.*s %lu", hm->method.len, hm->method.ptr,
61+
hm->uri.len, hm->uri.ptr, hm->body.len, 3, c->send.buf + 9,
62+
c->send.len));
3563
}
3664
}
3765

@@ -43,6 +71,7 @@ static void usage(const char *prog) {
4371
" -S PAT - SSI filename pattern, default: '%s'\n"
4472
" -d DIR - directory to serve, default: '%s'\n"
4573
" -l ADDR - listening address, default: '%s'\n"
74+
" -u DIR - file upload directory, default: unset\n"
4675
" -v LEVEL - debug level, from 0 to 4, default: %d\n",
4776
MG_VERSION, prog, s_enable_hexdump, s_ssi_pattern, s_root_dir,
4877
s_listening_address, s_debug_level);
@@ -65,6 +94,8 @@ int main(int argc, char *argv[]) {
6594
s_ssi_pattern = argv[++i];
6695
} else if (strcmp(argv[i], "-l") == 0) {
6796
s_listening_address = argv[++i];
97+
} else if (strcmp(argv[i], "-u") == 0) {
98+
s_upload_dir = argv[++i];
6899
} else if (strcmp(argv[i], "-v") == 0) {
69100
s_debug_level = atoi(argv[++i]);
70101
} else {
@@ -95,6 +126,7 @@ int main(int argc, char *argv[]) {
95126
MG_INFO(("Mongoose version : v%s", MG_VERSION));
96127
MG_INFO(("Listening on : %s", s_listening_address));
97128
MG_INFO(("Web root : [%s]", s_root_dir));
129+
MG_INFO(("Upload dir : [%s]", s_upload_dir ? s_upload_dir : "unset"));
98130
while (s_signo == 0) mg_mgr_poll(&mgr, 1000);
99131
mg_mgr_free(&mgr);
100132
MG_INFO(("Exiting on signal %d", s_signo));

0 commit comments

Comments
 (0)