Skip to content

Commit

Permalink
Make mg_http_upload() use predefined upload path
Browse files Browse the repository at this point in the history
  • Loading branch information
cpq committed Feb 4, 2024
1 parent e4bfb2b commit 89c1c9a
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 48 deletions.
12 changes: 11 additions & 1 deletion examples/file-upload-multiple-posts/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@ static void cb(struct mg_connection *c, int ev, void *ev_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")) {
mg_http_upload(c, hm, &mg_fs_posix, "/tmp", 99999);
const char *tempfile = "/tmp/upload.data";
long res = mg_http_upload(c, hm, &mg_fs_posix, tempfile, 99999);
if (res == 0) {
// Upload finished. Rename temprorary file into a target one
char path[80], file[64];
mg_http_get_var(&hm->query, "file", file, sizeof(file));
mg_snprintf(path, sizeof(path), "/tmp/%s", file);
if (mg_path_is_sane(path)) {
mg_fs_posix.mv(tempfile, path);
}
}
} else {
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
mg_http_serve_dir(c, ev_data, &opts);
Expand Down
20 changes: 6 additions & 14 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -3134,28 +3134,20 @@ bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
}

long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_fs *fs, const char *dir, size_t max_size) {
char buf[20] = "0", file[40], path[MG_PATH_MAX];
struct mg_fs *fs, const char *path, size_t max_size) {
char buf[20] = "0";
long res = 0, offset;
mg_http_get_var(&hm->query, "offset", buf, sizeof(buf));
mg_http_get_var(&hm->query, "file", file, sizeof(file));
offset = strtol(buf, NULL, 0);
mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, file);
if (hm->body.len == 0) {
mg_http_reply(c, 200, "", "%ld", res); // Nothing to write
} else if (file[0] == '\0') {
mg_http_reply(c, 400, "", "file required");
res = -1;
} else if (mg_path_is_sane(file) == false) {
mg_http_reply(c, 400, "", "%s: invalid file", file);
res = -2;
} else if (offset < 0) {
mg_http_reply(c, 400, "", "offset required");
res = -3;
res = -1;
} else if ((size_t) offset + hm->body.len > max_size) {
mg_http_reply(c, 400, "", "%s: over max size of %lu", path,
(unsigned long) max_size);
res = -4;
res = -2;
} else {
struct mg_fd *fd;
size_t current_size = 0;
Expand All @@ -3164,10 +3156,10 @@ long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
fs->st(path, &current_size, NULL);
if (offset > 0 && current_size != (size_t) offset) {
mg_http_reply(c, 400, "", "%s: offset mismatch", path);
res = -5;
res = -3;
} else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
mg_http_reply(c, 400, "", "open(%s): %d", path, errno);
res = -6;
res = -4;
} else {
res = offset + (long) fs->wr(fd->fd, hm->body.ptr, hm->body.len);
mg_fs_close(fd);
Expand Down
2 changes: 1 addition & 1 deletion mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,7 @@ size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_fs *fs, const char *dir, size_t max_size);
struct mg_fs *fs, const char *path, size_t max_size);
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
Expand Down
20 changes: 6 additions & 14 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -918,28 +918,20 @@ bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
}

long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_fs *fs, const char *dir, size_t max_size) {
char buf[20] = "0", file[40], path[MG_PATH_MAX];
struct mg_fs *fs, const char *path, size_t max_size) {
char buf[20] = "0";
long res = 0, offset;
mg_http_get_var(&hm->query, "offset", buf, sizeof(buf));
mg_http_get_var(&hm->query, "file", file, sizeof(file));
offset = strtol(buf, NULL, 0);
mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, file);
if (hm->body.len == 0) {
mg_http_reply(c, 200, "", "%ld", res); // Nothing to write
} else if (file[0] == '\0') {
mg_http_reply(c, 400, "", "file required");
res = -1;
} else if (mg_path_is_sane(file) == false) {
mg_http_reply(c, 400, "", "%s: invalid file", file);
res = -2;
} else if (offset < 0) {
mg_http_reply(c, 400, "", "offset required");
res = -3;
res = -1;
} else if ((size_t) offset + hm->body.len > max_size) {
mg_http_reply(c, 400, "", "%s: over max size of %lu", path,
(unsigned long) max_size);
res = -4;
res = -2;
} else {
struct mg_fd *fd;
size_t current_size = 0;
Expand All @@ -948,10 +940,10 @@ long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
fs->st(path, &current_size, NULL);
if (offset > 0 && current_size != (size_t) offset) {
mg_http_reply(c, 400, "", "%s: offset mismatch", path);
res = -5;
res = -3;
} else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
mg_http_reply(c, 400, "", "open(%s): %d", path, errno);
res = -6;
res = -4;
} else {
res = offset + (long) fs->wr(fd->fd, hm->body.ptr, hm->body.len);
mg_fs_close(fd);
Expand Down
2 changes: 1 addition & 1 deletion src/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_fs *fs, const char *dir, size_t max_size);
struct mg_fs *fs, const char *path, size_t max_size);
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
Expand Down
18 changes: 1 addition & 17 deletions test/unit_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ static void eh1(struct mg_connection *c, int ev, void *ev_data) {
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
mg_http_reply(c, 200, "", "[%s]:[%s]", user, pass);
} else if (mg_http_match_uri(hm, "/upload")) {
mg_http_upload(c, hm, &mg_fs_posix, ".", 99999);
mg_http_upload(c, hm, &mg_fs_posix, "./uploaded.txt", 99999);
c->is_hexdumping = 1;
} else if (mg_http_match_uri(hm, "/test/")) {
struct mg_http_serve_opts sopts;
Expand Down Expand Up @@ -1062,10 +1062,6 @@ static void test_http_server(void) {
char *p;
remove("uploaded.txt");
ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
ASSERT(fetch(&mgr, buf, url,
"POST /upload HTTP/1.0\n"
"Content-Length: 1\n\nx") == 400);

ASSERT(fetch(&mgr, buf, url,
"POST /upload?file=uploaded.txt HTTP/1.0\r\n"
"Content-Length: 5\r\n"
Expand All @@ -1080,18 +1076,6 @@ static void test_http_server(void) {
remove("uploaded.txt");
}

{
// Test upload directory traversal
char *p;
remove("uploaded.txt");
ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
ASSERT(fetch(&mgr, buf, url,
"POST /upload?file=../uploaded.txt HTTP/1.0\r\n"
"Content-Length: 5\r\n"
"\r\nhello") == 400);
ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
}

// HEAD request
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
ASSERT(fetch(&mgr, buf, url, "HEAD /a.txt HTTP/1.0\n\n") == 200);
Expand Down

0 comments on commit 89c1c9a

Please sign in to comment.