diff --git a/mongoose.c b/mongoose.c index bfd023af..e56401d6 100644 --- a/mongoose.c +++ b/mongoose.c @@ -433,14 +433,14 @@ const char *mg_unlist(size_t no) { static char *packed_realpath(const char *path, char *resolved_path) { if (resolved_path == NULL) resolved_path = (char *) malloc(strlen(path) + 1); - while (*path == '.' || *path == '/') path++; + // while (*path == '.' || *path == '/') path++; strcpy(resolved_path, path); return resolved_path; } static int is_dir_prefix(const char *prefix, size_t n, const char *path) { - return n < strlen(path) && memcmp(prefix, path, n) == 0 && - (n == 0 || path[n] == MG_DIRSEP); + return n < strlen(path) && memcmp(prefix, path, n) == 0 && path[n] == '/'; + //(n == 0 || path[n] == MG_DIRSEP); } static int packed_stat(const char *path, size_t *size, time_t *mtime) { @@ -454,12 +454,24 @@ static int packed_stat(const char *path, size_t *size, time_t *mtime) { return 0; } -static void packed_list(const char *path, void (*fn)(const char *, void *), +static void packed_list(const char *dir, void (*fn)(const char *, void *), void *userdata) { - const char *p; - size_t i, n = strlen(path); - for (i = 0; (p = mg_unlist(i)) != NULL; i++) { - if (is_dir_prefix(path, n, p)) fn(&p[n], userdata); + char buf[256], tmp[sizeof(buf)]; + const char *path, *begin, *end; + size_t i, n = strlen(dir); + tmp[0] = '\0'; // Previously listed entry + for (i = 0; (path = mg_unlist(i)) != NULL; i++) { + if (!is_dir_prefix(dir, n, path)) continue; + begin = &path[n + 1]; + end = strchr(begin, '/'); + if (end == NULL) end = begin + strlen(begin); + snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); + buf[sizeof(buf) - 1] = '\0'; + // If this entry has been already listed, skip + // NOTE: we're assuming that file list is sorted alphabetically + if (strcmp(buf, tmp) == 0) continue; + fn(buf, userdata); // Not yet listed, call user function + strcpy(tmp, buf); // And save this entry as listed } } @@ -1355,6 +1367,7 @@ static void printdirentry(const char *name, void *userdata) { char path[MG_PATH_MAX], sz[64], mod[64]; int flags, n = 0; + // LOG(LL_DEBUG, ("[%s] [%s]", d->dir, name)); if (snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) < 0) { LOG(LL_ERROR, ("%s truncated", name)); } else if ((flags = fs->stat(path, &size, &mtime)) == 0) { diff --git a/src/fs_packed.c b/src/fs_packed.c index 9d4c8d79..90531245 100644 --- a/src/fs_packed.c +++ b/src/fs_packed.c @@ -22,14 +22,14 @@ const char *mg_unlist(size_t no) { static char *packed_realpath(const char *path, char *resolved_path) { if (resolved_path == NULL) resolved_path = (char *) malloc(strlen(path) + 1); - while (*path == '.' || *path == '/') path++; + // while (*path == '.' || *path == '/') path++; strcpy(resolved_path, path); return resolved_path; } static int is_dir_prefix(const char *prefix, size_t n, const char *path) { - return n < strlen(path) && memcmp(prefix, path, n) == 0 && - (n == 0 || path[n] == MG_DIRSEP); + return n < strlen(path) && memcmp(prefix, path, n) == 0 && path[n] == '/'; + //(n == 0 || path[n] == MG_DIRSEP); } static int packed_stat(const char *path, size_t *size, time_t *mtime) { @@ -43,12 +43,24 @@ static int packed_stat(const char *path, size_t *size, time_t *mtime) { return 0; } -static void packed_list(const char *path, void (*fn)(const char *, void *), +static void packed_list(const char *dir, void (*fn)(const char *, void *), void *userdata) { - const char *p; - size_t i, n = strlen(path); - for (i = 0; (p = mg_unlist(i)) != NULL; i++) { - if (is_dir_prefix(path, n, p)) fn(&p[n], userdata); + char buf[256], tmp[sizeof(buf)]; + const char *path, *begin, *end; + size_t i, n = strlen(dir); + tmp[0] = '\0'; // Previously listed entry + for (i = 0; (path = mg_unlist(i)) != NULL; i++) { + if (!is_dir_prefix(dir, n, path)) continue; + begin = &path[n + 1]; + end = strchr(begin, '/'); + if (end == NULL) end = begin + strlen(begin); + snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); + buf[sizeof(buf) - 1] = '\0'; + // If this entry has been already listed, skip + // NOTE: we're assuming that file list is sorted alphabetically + if (strcmp(buf, tmp) == 0) continue; + fn(buf, userdata); // Not yet listed, call user function + strcpy(tmp, buf); // And save this entry as listed } } diff --git a/src/http.c b/src/http.c index a2b732dd..b7558180 100644 --- a/src/http.c +++ b/src/http.c @@ -596,6 +596,7 @@ static void printdirentry(const char *name, void *userdata) { char path[MG_PATH_MAX], sz[64], mod[64]; int flags, n = 0; + // LOG(LL_DEBUG, ("[%s] [%s]", d->dir, name)); if (snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) < 0) { LOG(LL_ERROR, ("%s truncated", name)); } else if ((flags = fs->stat(path, &size, &mtime)) == 0) { diff --git a/test/pack.c b/test/pack.c index 1a6216de..183de982 100644 --- a/test/pack.c +++ b/test/pack.c @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) { for (i = 1; i < argc; i++) { struct stat st; stat(argv[i], &st); - printf(" {\"%s\", v%d, sizeof(v%d), %lu},\n", argv[i], i, i, st.st_mtime); + printf(" {\"/%s\", v%d, sizeof(v%d), %lu},\n", argv[i], i, i, st.st_mtime); } printf("%s", " {NULL, NULL, 0, 0}\n"); printf("%s", "};\n\n"); diff --git a/test/unit_test.c b/test/unit_test.c index 1cdb821d..bb45b655 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -582,7 +582,6 @@ static void test_http_server(void) { // Directory listing fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n"); ASSERT(fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n") == 200); - printf("-------\n%s\n", buf); ASSERT(mg_strstr(mg_str(buf), mg_str(">Index of /test/<")) != NULL); ASSERT(mg_strstr(mg_str(buf), mg_str(">fuzz.c<")) != NULL); @@ -1358,7 +1357,7 @@ static void eh7(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 sopts; memset(&sopts, 0, sizeof(sopts)); - sopts.root_dir = "."; + sopts.root_dir = ""; sopts.fs = &mg_fs_packed; mg_http_serve_dir(c, hm, &sopts); } @@ -1371,12 +1370,26 @@ static void test_packed(void) { char buf[FETCH_BUF_SIZE] = "", *data = mg_file_read("Makefile", NULL); mg_mgr_init(&mgr); mg_http_listen(&mgr, url, eh7, NULL); + + // Load top level file directly ASSERT(fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n") == 200); ASSERT(cmpbody(buf, data) == 0); free(data); + + // Load file deeper in the FS tree directly + data = mg_file_read("src/ssi.h", NULL); + ASSERT(fetch(&mgr, buf, url, "GET /src/ssi.h HTTP/1.0\n\n") == 200); + ASSERT(cmpbody(buf, data) == 0); + free(data); + + // List root dir ASSERT(fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n") == 200); // printf("--------\n%s\n", buf); - // exit(0); + + // List nested dir + ASSERT(fetch(&mgr, buf, url, "GET /test HTTP/1.0\n\n") == 200); + // printf("--------\n%s\n", buf); + mg_mgr_free(&mgr); ASSERT(mgr.conns == NULL); }