@@ -9,6 +9,7 @@ static const char *s_root_dir = ".";
9
9
static const char * s_listening_address = "http://0.0.0.0:8000" ;
10
10
static const char * s_enable_hexdump = "no" ;
11
11
static const char * s_ssi_pattern = "#.html" ;
12
+ static const char * s_upload_dir = NULL ; // File uploads disabled by default
12
13
13
14
// Handle interrupts, like Ctrl-C
14
15
static int s_signo ;
@@ -20,18 +21,45 @@ static void signal_handler(int signo) {
20
21
// Simply serve static files from `s_root_dir`
21
22
static void cb (struct mg_connection * c , int ev , void * ev_data ) {
22
23
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 ));
35
63
}
36
64
}
37
65
@@ -43,6 +71,7 @@ static void usage(const char *prog) {
43
71
" -S PAT - SSI filename pattern, default: '%s'\n"
44
72
" -d DIR - directory to serve, default: '%s'\n"
45
73
" -l ADDR - listening address, default: '%s'\n"
74
+ " -u DIR - file upload directory, default: unset\n"
46
75
" -v LEVEL - debug level, from 0 to 4, default: %d\n" ,
47
76
MG_VERSION , prog , s_enable_hexdump , s_ssi_pattern , s_root_dir ,
48
77
s_listening_address , s_debug_level );
@@ -65,6 +94,8 @@ int main(int argc, char *argv[]) {
65
94
s_ssi_pattern = argv [++ i ];
66
95
} else if (strcmp (argv [i ], "-l" ) == 0 ) {
67
96
s_listening_address = argv [++ i ];
97
+ } else if (strcmp (argv [i ], "-u" ) == 0 ) {
98
+ s_upload_dir = argv [++ i ];
68
99
} else if (strcmp (argv [i ], "-v" ) == 0 ) {
69
100
s_debug_level = atoi (argv [++ i ]);
70
101
} else {
@@ -95,6 +126,7 @@ int main(int argc, char *argv[]) {
95
126
MG_INFO (("Mongoose version : v%s" , MG_VERSION ));
96
127
MG_INFO (("Listening on : %s" , s_listening_address ));
97
128
MG_INFO (("Web root : [%s]" , s_root_dir ));
129
+ MG_INFO (("Upload dir : [%s]" , s_upload_dir ? s_upload_dir : "unset" ));
98
130
while (s_signo == 0 ) mg_mgr_poll (& mgr , 1000 );
99
131
mg_mgr_free (& mgr );
100
132
MG_INFO (("Exiting on signal %d" , s_signo ));
0 commit comments