mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-24 02:59:01 +08:00
Support multiple web roots
This commit is contained in:
parent
2b48e8b03a
commit
2139fbc4b7
@ -915,7 +915,8 @@ enable SSI, set a `-DMG_ENABLE_SSI=1` build flag.
|
||||
Parameters:
|
||||
- `c` - connection to use
|
||||
- `hm` - http message, that should be served
|
||||
- `opts` - serve options
|
||||
- `opts` - serve options. Note that `opts.root_dir` can optionally accept
|
||||
extra comma-separated `uri=path` pairs, see example below
|
||||
|
||||
Return value: none
|
||||
|
||||
@ -928,7 +929,7 @@ void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
struct mg_http_serve_opts opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.root_dir = "/my_root";
|
||||
opts.root_dir = "/var/www,/conf=/etc"; // Serve /var/www. URIs starting with /conf are served from /etc
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
}
|
||||
|
90
mongoose.c
90
mongoose.c
@ -1457,54 +1457,80 @@ static void remove_double_dots(char *s) {
|
||||
}
|
||||
|
||||
// Resolve requested file into `path` and return its fs->stat() result
|
||||
static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_fs *fs, struct mg_str url, struct mg_str dir,
|
||||
char *path, size_t path_size) {
|
||||
int flags = 0, tmp;
|
||||
// Append URI to the root_dir, and sanitize it
|
||||
size_t n = (size_t) snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr);
|
||||
if (n > path_size) n = path_size;
|
||||
path[path_size - 1] = '\0';
|
||||
if ((fs->stat(path, NULL, NULL) & MG_FS_DIR) == 0) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%.*s]\n", (int) dir.len,
|
||||
dir.ptr);
|
||||
} else {
|
||||
if (n + 2 < path_size) path[n++] = '/', path[n] = '\0';
|
||||
mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n,
|
||||
path_size - n, 0);
|
||||
path[path_size - 1] = '\0'; // Double-check
|
||||
remove_double_dots(path);
|
||||
n = strlen(path);
|
||||
LOG(LL_DEBUG, ("--> %s", path));
|
||||
while (n > 0 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
|
||||
flags = fs->stat(path, NULL, NULL); // Does it exist?
|
||||
if (flags == 0) {
|
||||
mg_http_reply(c, 404, "", "Not found\n"); // Does not exist, doh
|
||||
} else if (flags & MG_FS_DIR) {
|
||||
if (((snprintf(path + n, path_size - n, "/index.html") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0) ||
|
||||
(snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0))) {
|
||||
flags = tmp;
|
||||
} else {
|
||||
path[n] = '\0'; // Remove appended index file name
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts, char *path,
|
||||
size_t path_size) {
|
||||
struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
|
||||
int flags = 0, tmp;
|
||||
// Append URI to the root_dir, and sanitize it
|
||||
size_t n = (size_t) snprintf(path, path_size, "%s", opts->root_dir);
|
||||
if (n > path_size) n = path_size;
|
||||
mg_url_decode(hm->uri.ptr, hm->uri.len, path + n, path_size - n, 0);
|
||||
path[path_size - 1] = '\0'; // Double-check
|
||||
remove_double_dots(path);
|
||||
n = strlen(path);
|
||||
while (n > 0 && path[n - 1] == '/') path[--n] = 0; // Strip trailing slashes
|
||||
flags = fs->stat(path, NULL, NULL); // Does it exist?
|
||||
if (flags == 0) {
|
||||
mg_http_reply(c, 404, "", "Not found\n"); // Does not exist, doh
|
||||
} else if (flags & MG_FS_DIR) {
|
||||
if (((snprintf(path + n, path_size - n, "/index.html") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0) ||
|
||||
(snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0))) {
|
||||
flags = tmp;
|
||||
} else {
|
||||
path[n] = '\0'; // Remove appended index file name
|
||||
}
|
||||
struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0};
|
||||
while (mg_commalist(&s, &k, &v)) {
|
||||
if (v.len == 0) v = k, k = mg_str("/");
|
||||
if (hm->uri.len < k.len) continue;
|
||||
if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue;
|
||||
u = k, p = v;
|
||||
}
|
||||
return flags;
|
||||
return uri_to_path2(c, hm, fs, u, p, path, path_size);
|
||||
}
|
||||
|
||||
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts) {
|
||||
char path[MG_PATH_MAX] = "";
|
||||
const char *sp = opts->ssi_pattern;
|
||||
#if 0
|
||||
struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
|
||||
if ((fs->stat(opts->root_dir, NULL, NULL) & MG_FS_DIR) == 0) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%s]\n", opts->root_dir);
|
||||
} else {
|
||||
int flags = uri_to_path(c, hm, opts, path, sizeof(path));
|
||||
if (flags == 0) return;
|
||||
LOG(LL_DEBUG, ("%.*s %s %d", (int) hm->uri.len, hm->uri.ptr, path, flags));
|
||||
if (flags & MG_FS_DIR) {
|
||||
listdir(c, hm, opts, path);
|
||||
} else if (sp != NULL && mg_globmatch(sp, strlen(sp), path, strlen(path))) {
|
||||
mg_http_serve_ssi(c, opts->root_dir, path);
|
||||
} else {
|
||||
mg_http_serve_file(c, hm, path, opts);
|
||||
}
|
||||
#endif
|
||||
int flags = uri_to_path(c, hm, opts, path, sizeof(path));
|
||||
if (flags == 0) return;
|
||||
LOG(LL_DEBUG, ("%.*s %s %d", (int) hm->uri.len, hm->uri.ptr, path, flags));
|
||||
if (flags & MG_FS_DIR) {
|
||||
listdir(c, hm, opts, path);
|
||||
} else if (sp != NULL && mg_globmatch(sp, strlen(sp), path, strlen(path))) {
|
||||
mg_http_serve_ssi(c, opts->root_dir, path);
|
||||
} else {
|
||||
mg_http_serve_file(c, hm, path, opts);
|
||||
}
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool mg_is_url_safe(int c) {
|
||||
|
90
src/http.c
90
src/http.c
@ -707,54 +707,80 @@ static void remove_double_dots(char *s) {
|
||||
}
|
||||
|
||||
// Resolve requested file into `path` and return its fs->stat() result
|
||||
static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_fs *fs, struct mg_str url, struct mg_str dir,
|
||||
char *path, size_t path_size) {
|
||||
int flags = 0, tmp;
|
||||
// Append URI to the root_dir, and sanitize it
|
||||
size_t n = (size_t) snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr);
|
||||
if (n > path_size) n = path_size;
|
||||
path[path_size - 1] = '\0';
|
||||
if ((fs->stat(path, NULL, NULL) & MG_FS_DIR) == 0) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%.*s]\n", (int) dir.len,
|
||||
dir.ptr);
|
||||
} else {
|
||||
if (n + 2 < path_size) path[n++] = '/', path[n] = '\0';
|
||||
mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n,
|
||||
path_size - n, 0);
|
||||
path[path_size - 1] = '\0'; // Double-check
|
||||
remove_double_dots(path);
|
||||
n = strlen(path);
|
||||
LOG(LL_DEBUG, ("--> %s", path));
|
||||
while (n > 0 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
|
||||
flags = fs->stat(path, NULL, NULL); // Does it exist?
|
||||
if (flags == 0) {
|
||||
mg_http_reply(c, 404, "", "Not found\n"); // Does not exist, doh
|
||||
} else if (flags & MG_FS_DIR) {
|
||||
if (((snprintf(path + n, path_size - n, "/index.html") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0) ||
|
||||
(snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0))) {
|
||||
flags = tmp;
|
||||
} else {
|
||||
path[n] = '\0'; // Remove appended index file name
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts, char *path,
|
||||
size_t path_size) {
|
||||
struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
|
||||
int flags = 0, tmp;
|
||||
// Append URI to the root_dir, and sanitize it
|
||||
size_t n = (size_t) snprintf(path, path_size, "%s", opts->root_dir);
|
||||
if (n > path_size) n = path_size;
|
||||
mg_url_decode(hm->uri.ptr, hm->uri.len, path + n, path_size - n, 0);
|
||||
path[path_size - 1] = '\0'; // Double-check
|
||||
remove_double_dots(path);
|
||||
n = strlen(path);
|
||||
while (n > 0 && path[n - 1] == '/') path[--n] = 0; // Strip trailing slashes
|
||||
flags = fs->stat(path, NULL, NULL); // Does it exist?
|
||||
if (flags == 0) {
|
||||
mg_http_reply(c, 404, "", "Not found\n"); // Does not exist, doh
|
||||
} else if (flags & MG_FS_DIR) {
|
||||
if (((snprintf(path + n, path_size - n, "/index.html") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0) ||
|
||||
(snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0))) {
|
||||
flags = tmp;
|
||||
} else {
|
||||
path[n] = '\0'; // Remove appended index file name
|
||||
}
|
||||
struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0};
|
||||
while (mg_commalist(&s, &k, &v)) {
|
||||
if (v.len == 0) v = k, k = mg_str("/");
|
||||
if (hm->uri.len < k.len) continue;
|
||||
if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue;
|
||||
u = k, p = v;
|
||||
}
|
||||
return flags;
|
||||
return uri_to_path2(c, hm, fs, u, p, path, path_size);
|
||||
}
|
||||
|
||||
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts) {
|
||||
char path[MG_PATH_MAX] = "";
|
||||
const char *sp = opts->ssi_pattern;
|
||||
#if 0
|
||||
struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
|
||||
if ((fs->stat(opts->root_dir, NULL, NULL) & MG_FS_DIR) == 0) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%s]\n", opts->root_dir);
|
||||
} else {
|
||||
int flags = uri_to_path(c, hm, opts, path, sizeof(path));
|
||||
if (flags == 0) return;
|
||||
LOG(LL_DEBUG, ("%.*s %s %d", (int) hm->uri.len, hm->uri.ptr, path, flags));
|
||||
if (flags & MG_FS_DIR) {
|
||||
listdir(c, hm, opts, path);
|
||||
} else if (sp != NULL && mg_globmatch(sp, strlen(sp), path, strlen(path))) {
|
||||
mg_http_serve_ssi(c, opts->root_dir, path);
|
||||
} else {
|
||||
mg_http_serve_file(c, hm, path, opts);
|
||||
}
|
||||
#endif
|
||||
int flags = uri_to_path(c, hm, opts, path, sizeof(path));
|
||||
if (flags == 0) return;
|
||||
LOG(LL_DEBUG, ("%.*s %s %d", (int) hm->uri.len, hm->uri.ptr, path, flags));
|
||||
if (flags & MG_FS_DIR) {
|
||||
listdir(c, hm, opts, path);
|
||||
} else if (sp != NULL && mg_globmatch(sp, strlen(sp), path, strlen(path))) {
|
||||
mg_http_serve_ssi(c, opts->root_dir, path);
|
||||
} else {
|
||||
mg_http_serve_file(c, hm, path, opts);
|
||||
}
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool mg_is_url_safe(int c) {
|
||||
|
@ -1555,8 +1555,38 @@ static void test_ws_fragmentation(void) {
|
||||
ASSERT(mgr.conns == NULL);
|
||||
}
|
||||
|
||||
static void h7(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;
|
||||
struct mg_http_serve_opts opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.root_dir = "./test/data,/foo=./src";
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
static void test_rewrites(void) {
|
||||
char buf[FETCH_BUF_SIZE];
|
||||
const char *url = "http://LOCALHOST:12358";
|
||||
const char *expected = "#define MG_VERSION \"" MG_VERSION "\"\n";
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
ASSERT(mg_http_listen(&mgr, url, h7, NULL) != NULL);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, "hello\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /foo/version.h HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, expected) == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /foo HTTP/1.0\n\n") == 200);
|
||||
// printf("-->[%s]\n", buf);
|
||||
// exit(0);
|
||||
mg_mgr_free(&mgr);
|
||||
ASSERT(mgr.conns == NULL);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
mg_log_set("3");
|
||||
test_rewrites();
|
||||
test_check_ip_acl();
|
||||
test_udp();
|
||||
test_pipe();
|
||||
|
Loading…
Reference in New Issue
Block a user