mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-15 10:29:47 +00:00
Get rid of fs->realpath
This commit is contained in:
1 parent
f3eb466af3
commit
894a168833
13 files changed
+195
-205
No files matched your search
+64
-80
@@ -431,13 +431,6 @@ const char *mg_unlist(size_t no) {
|
||||
}
|
||||
#endif
|
||||
|
||||
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++;
|
||||
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 && path[n] == '/';
|
||||
//(n == 0 || path[n] == MG_DIRSEP);
|
||||
@@ -515,9 +508,9 @@ static size_t packed_seek(void *fd, size_t offset) {
|
||||
return fp->pos;
|
||||
}
|
||||
|
||||
struct mg_fs mg_fs_packed = {packed_realpath, packed_stat, packed_list,
|
||||
packed_open, packed_close, packed_read,
|
||||
packed_write, packed_seek};
|
||||
struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open,
|
||||
packed_close, packed_read, packed_write,
|
||||
packed_seek};
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
#line 1 "src/fs_posix.c"
|
||||
@@ -525,19 +518,6 @@ struct mg_fs mg_fs_packed = {packed_realpath, packed_stat, packed_list,
|
||||
|
||||
|
||||
#if defined(FOPEN_MAX)
|
||||
static char *posix_realpath(const char *path, char *resolved_path) {
|
||||
#ifdef _WIN32
|
||||
return _fullpath(resolved_path, path, _MAX_PATH);
|
||||
#elif MG_ARCH == MG_ARCH_ESP32 || MG_ARCH == MG_ARCH_ESP8266 || \
|
||||
MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP
|
||||
if (resolved_path == NULL) resolved_path = malloc(strlen(path) + 1);
|
||||
strcpy(resolved_path, path);
|
||||
return resolved_path;
|
||||
#else
|
||||
return realpath(path, resolved_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int posix_stat(const char *path, size_t *size, time_t *mtime) {
|
||||
#ifdef _WIN32
|
||||
struct _stati64 st;
|
||||
@@ -762,9 +742,8 @@ static size_t posix_seek(void *fd, size_t offset) {
|
||||
}
|
||||
#endif
|
||||
|
||||
struct mg_fs mg_fs_posix = {posix_realpath, posix_stat, posix_list,
|
||||
posix_open, posix_close, posix_read,
|
||||
posix_write, posix_seek};
|
||||
struct mg_fs mg_fs_posix = {posix_stat, posix_list, posix_open, posix_close,
|
||||
posix_read, posix_write, posix_seek};
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
#line 1 "src/http.c"
|
||||
@@ -1458,49 +1437,50 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
memcpy(c->send.buf + off - 10, tmp, n); // Set content length
|
||||
}
|
||||
|
||||
static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts, char *root_dir,
|
||||
size_t rlen, char *path, size_t plen) {
|
||||
struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
|
||||
int flags = 0, tmp;
|
||||
if (fs->realpath(opts->root_dir, root_dir) == NULL) {
|
||||
LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno));
|
||||
mg_http_reply(c, 400, "", "Bad web root [%s]\n", opts->root_dir);
|
||||
} else if (!(fs->stat(root_dir, NULL, NULL) & MG_FS_DIR)) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%s]\n", root_dir);
|
||||
} else {
|
||||
// NOTE(lsm): Xilinx snprintf does not 0-terminate the destination for
|
||||
// the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0
|
||||
size_t n1 = strlen(root_dir), n2;
|
||||
// Temporarily append URI to the root_dir: that is the unresolved path
|
||||
mg_url_decode(hm->uri.ptr, hm->uri.len, root_dir + n1, rlen - n1, 0);
|
||||
root_dir[rlen - 1] = '\0';
|
||||
n2 = strlen(root_dir);
|
||||
while (n2 > 0 && root_dir[n2 - 1] == '/') root_dir[--n2] = 0;
|
||||
// Try to resolve it...
|
||||
if (fs->realpath(root_dir, path) == NULL ||
|
||||
(flags = fs->stat(path, NULL, NULL)) == 0) {
|
||||
mg_http_reply(c, 404, "", "Not found\n");
|
||||
} else {
|
||||
// Path is resolved successfully. It it is a directory, try to
|
||||
// serve index.html in it
|
||||
root_dir[n1] = '\0'; // Restore root_dir - remove appended URI
|
||||
n2 = strlen(path); // Memorise path length
|
||||
if ((flags & MG_FS_DIR) &&
|
||||
((snprintf(path + n2, plen - n2, "/index.html") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0) ||
|
||||
(snprintf(path + n2, plen - n2, "/index.shtml") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0))) {
|
||||
flags = tmp;
|
||||
} else {
|
||||
path[n2] = '\0'; // Remove appended index file name
|
||||
static void remove_double_dots(char *s) {
|
||||
char *p = s;
|
||||
while (*s != '\0') {
|
||||
*p++ = *s++;
|
||||
if (s[-1] == '/' || s[-1] == '\\') {
|
||||
while (s[0] != '\0') {
|
||||
if (s[0] == '/' || s[0] == '\\') {
|
||||
s++;
|
||||
} else if (s[0] == '.' && s[1] == '.') {
|
||||
s += 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check that the resolved file is located inside root directory
|
||||
if (strlen(path) < n1 || memcmp(root_dir, path, n1) != 0) {
|
||||
mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len,
|
||||
hm->uri.ptr);
|
||||
flags = 0;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
// Resolve requested file into `path` and return its fs->stat() result
|
||||
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
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
@@ -1508,19 +1488,22 @@ static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
|
||||
|
||||
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts) {
|
||||
char root[MG_PATH_MAX] = "", path[sizeof(root)] = "";
|
||||
int flags = uri_to_path(c, hm, opts, root, sizeof(root), path, sizeof(path));
|
||||
|
||||
if (flags == 0) return;
|
||||
// LOG(LL_DEBUG, ("root [%s], path [%s] %d", root, path, flags));
|
||||
if (flags & MG_FS_DIR) {
|
||||
listdir(c, hm, opts, path);
|
||||
} else if (opts->ssi_pattern != NULL &&
|
||||
mg_globmatch(opts->ssi_pattern, strlen(opts->ssi_pattern), path,
|
||||
strlen(path))) {
|
||||
mg_http_serve_ssi(c, root, path);
|
||||
char path[MG_PATH_MAX] = "";
|
||||
const char *sp = opts->ssi_pattern;
|
||||
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 {
|
||||
mg_http_serve_file(c, hm, path, opts);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4213,9 +4196,10 @@ bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
|
||||
i++, j++;
|
||||
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
|
||||
ni = i, nj = j + 1, i++;
|
||||
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
|
||||
} else if (nj > 0 && nj <= n2 && (s1[ni] == '#' || s2[j] != '/')) {
|
||||
i = ni, j = nj;
|
||||
} else {
|
||||
// printf(">>: [%s] [%s] %d %d %d %d\n", s1, s2, i, j, ni, nj);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+30
-17
@@ -214,13 +214,14 @@ struct timeval {
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
#if LWIP_SOCKET != 1
|
||||
// Sockets support disabled in LWIP by default
|
||||
// Sockets support disabled in LWIP by default
|
||||
#error Set LWIP_SOCKET variable to 1 (in lwipopts.h)
|
||||
#endif
|
||||
|
||||
#if LWIP_POSIX_SOCKETS_IO_NAMES != 0
|
||||
// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS enviroment
|
||||
// (freertos mimics to one) otherwise names like `read` and `write` conflict
|
||||
// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS
|
||||
// enviroment (freertos mimics to one) otherwise names like `read` and `write`
|
||||
// conflict
|
||||
#error LWIP_POSIX_SOCKETS_IO_NAMES must be set to 0 (in lwipopts.h) for FreeRTOS
|
||||
#endif
|
||||
|
||||
@@ -467,8 +468,8 @@ static __inline struct tm *localtime_r(time_t *t, struct tm *tm) {
|
||||
#include <string.h>
|
||||
|
||||
struct mg_str {
|
||||
const char *ptr;
|
||||
size_t len;
|
||||
const char *ptr; // Pointer to string data
|
||||
size_t len; // String len
|
||||
};
|
||||
|
||||
#define MG_NULL_STR \
|
||||
@@ -596,13 +597,25 @@ enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 };
|
||||
|
||||
// Filesystem API functions
|
||||
struct mg_fs {
|
||||
char *(*realpath)(const char *path, char *resolved_path);
|
||||
// Return MG_FS_* flags, and populate file size and modification time
|
||||
int (*stat)(const char *path, size_t *size, time_t *mtime);
|
||||
|
||||
// Enumerates objects in directory
|
||||
void (*list)(const char *path, void (*fn)(const char *, void *), void *);
|
||||
|
||||
// Open file
|
||||
struct mg_fd *(*open)(const char *path, int flags);
|
||||
|
||||
// Close file
|
||||
void (*close)(struct mg_fd *fd);
|
||||
|
||||
// Read file
|
||||
size_t (*read)(void *fd, void *buf, size_t len);
|
||||
|
||||
// Write file
|
||||
size_t (*write)(void *fd, const void *buf, size_t len);
|
||||
|
||||
// Seek file
|
||||
size_t (*seek)(void *fd, size_t offset);
|
||||
};
|
||||
|
||||
@@ -786,8 +799,8 @@ void mg_mgr_wakeup(struct mg_connection *pipe);
|
||||
|
||||
|
||||
struct mg_http_header {
|
||||
struct mg_str name;
|
||||
struct mg_str value;
|
||||
struct mg_str name; // Header name
|
||||
struct mg_str value; // Header value
|
||||
};
|
||||
|
||||
struct mg_http_message {
|
||||
@@ -873,8 +886,8 @@ void mg_tls_handshake(struct mg_connection *);
|
||||
|
||||
|
||||
struct mg_ws_message {
|
||||
struct mg_str data;
|
||||
uint8_t flags; // Websocket message flags
|
||||
struct mg_str data; // Websocket message data
|
||||
uint8_t flags; // Websocket message flags
|
||||
};
|
||||
|
||||
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
|
||||
@@ -917,13 +930,13 @@ int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv);
|
||||
#define MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1)
|
||||
|
||||
struct mg_mqtt_opts {
|
||||
struct mg_str client_id;
|
||||
struct mg_str will_topic;
|
||||
struct mg_str will_message;
|
||||
uint8_t qos; // Quality of service
|
||||
bool will_retain; // Retain last will
|
||||
bool clean; // Use clean session, 0 or 1
|
||||
uint16_t keepalive; // Keep-alive timer in seconds
|
||||
struct mg_str client_id; // Client ID
|
||||
struct mg_str will_topic; // Will topic
|
||||
struct mg_str will_message; // Will message
|
||||
uint8_t qos; // Quality of service
|
||||
bool will_retain; // Retain last will
|
||||
bool clean; // Use clean session, 0 or 1
|
||||
uint16_t keepalive; // Keep-alive timer in seconds
|
||||
};
|
||||
|
||||
struct mg_mqtt_message {
|
||||
|
||||
@@ -24,13 +24,14 @@ struct timeval {
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
#if LWIP_SOCKET != 1
|
||||
// Sockets support disabled in LWIP by default
|
||||
// Sockets support disabled in LWIP by default
|
||||
#error Set LWIP_SOCKET variable to 1 (in lwipopts.h)
|
||||
#endif
|
||||
|
||||
#if LWIP_POSIX_SOCKETS_IO_NAMES != 0
|
||||
// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS enviroment
|
||||
// (freertos mimics to one) otherwise names like `read` and `write` conflict
|
||||
// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS
|
||||
// enviroment (freertos mimics to one) otherwise names like `read` and `write`
|
||||
// conflict
|
||||
#error LWIP_POSIX_SOCKETS_IO_NAMES must be set to 0 (in lwipopts.h) for FreeRTOS
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 };
|
||||
|
||||
// Filesystem API functions
|
||||
// stat() returns MG_FS_* flags and populates file size and modification time
|
||||
// list() calls fn() for every directory entry, allowing to list a directory
|
||||
struct mg_fs {
|
||||
char *(*realpath)(const char *path, char *resolved_path);
|
||||
int (*stat)(const char *path, size_t *size, time_t *mtime);
|
||||
void (*list)(const char *path, void (*fn)(const char *, void *), void *);
|
||||
struct mg_fd *(*open)(const char *path, int flags);
|
||||
void (*close)(struct mg_fd *fd);
|
||||
size_t (*read)(void *fd, void *buf, size_t len);
|
||||
size_t (*write)(void *fd, const void *buf, size_t len);
|
||||
size_t (*seek)(void *fd, size_t offset);
|
||||
struct mg_fd *(*open)(const char *path, int flags); // Open file
|
||||
void (*close)(struct mg_fd *fd); // Close file
|
||||
size_t (*read)(void *fd, void *buf, size_t len); // Read file
|
||||
size_t (*write)(void *fd, const void *buf, size_t len); // Write file
|
||||
size_t (*seek)(void *fd, size_t offset); // Set file position
|
||||
};
|
||||
|
||||
// File descriptor
|
||||
|
||||
+3
-10
@@ -20,13 +20,6 @@ const char *mg_unlist(size_t no) {
|
||||
}
|
||||
#endif
|
||||
|
||||
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++;
|
||||
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 && path[n] == '/';
|
||||
//(n == 0 || path[n] == MG_DIRSEP);
|
||||
@@ -104,6 +97,6 @@ static size_t packed_seek(void *fd, size_t offset) {
|
||||
return fp->pos;
|
||||
}
|
||||
|
||||
struct mg_fs mg_fs_packed = {packed_realpath, packed_stat, packed_list,
|
||||
packed_open, packed_close, packed_read,
|
||||
packed_write, packed_seek};
|
||||
struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open,
|
||||
packed_close, packed_read, packed_write,
|
||||
packed_seek};
|
||||
+2
-16
@@ -1,19 +1,6 @@
|
||||
#include "fs.h"
|
||||
|
||||
#if defined(FOPEN_MAX)
|
||||
static char *posix_realpath(const char *path, char *resolved_path) {
|
||||
#ifdef _WIN32
|
||||
return _fullpath(resolved_path, path, _MAX_PATH);
|
||||
#elif MG_ARCH == MG_ARCH_ESP32 || MG_ARCH == MG_ARCH_ESP8266 || \
|
||||
MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP
|
||||
if (resolved_path == NULL) resolved_path = malloc(strlen(path) + 1);
|
||||
strcpy(resolved_path, path);
|
||||
return resolved_path;
|
||||
#else
|
||||
return realpath(path, resolved_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int posix_stat(const char *path, size_t *size, time_t *mtime) {
|
||||
#ifdef _WIN32
|
||||
struct _stati64 st;
|
||||
@@ -238,6 +225,5 @@ static size_t posix_seek(void *fd, size_t offset) {
|
||||
}
|
||||
#endif
|
||||
|
||||
struct mg_fs mg_fs_posix = {posix_realpath, posix_stat, posix_list,
|
||||
posix_open, posix_close, posix_read,
|
||||
posix_write, posix_seek};
|
||||
struct mg_fs mg_fs_posix = {posix_stat, posix_list, posix_open, posix_close,
|
||||
posix_read, posix_write, posix_seek};
|
||||
+57
-53
@@ -687,49 +687,50 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
memcpy(c->send.buf + off - 10, tmp, n); // Set content length
|
||||
}
|
||||
|
||||
static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts, char *root_dir,
|
||||
size_t rlen, char *path, size_t plen) {
|
||||
struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
|
||||
int flags = 0, tmp;
|
||||
if (fs->realpath(opts->root_dir, root_dir) == NULL) {
|
||||
LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno));
|
||||
mg_http_reply(c, 400, "", "Bad web root [%s]\n", opts->root_dir);
|
||||
} else if (!(fs->stat(root_dir, NULL, NULL) & MG_FS_DIR)) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%s]\n", root_dir);
|
||||
} else {
|
||||
// NOTE(lsm): Xilinx snprintf does not 0-terminate the destination for
|
||||
// the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0
|
||||
size_t n1 = strlen(root_dir), n2;
|
||||
// Temporarily append URI to the root_dir: that is the unresolved path
|
||||
mg_url_decode(hm->uri.ptr, hm->uri.len, root_dir + n1, rlen - n1, 0);
|
||||
root_dir[rlen - 1] = '\0';
|
||||
n2 = strlen(root_dir);
|
||||
while (n2 > 0 && root_dir[n2 - 1] == '/') root_dir[--n2] = 0;
|
||||
// Try to resolve it...
|
||||
if (fs->realpath(root_dir, path) == NULL ||
|
||||
(flags = fs->stat(path, NULL, NULL)) == 0) {
|
||||
mg_http_reply(c, 404, "", "Not found\n");
|
||||
} else {
|
||||
// Path is resolved successfully. It it is a directory, try to
|
||||
// serve index.html in it
|
||||
root_dir[n1] = '\0'; // Restore root_dir - remove appended URI
|
||||
n2 = strlen(path); // Memorise path length
|
||||
if ((flags & MG_FS_DIR) &&
|
||||
((snprintf(path + n2, plen - n2, "/index.html") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0) ||
|
||||
(snprintf(path + n2, plen - n2, "/index.shtml") > 0 &&
|
||||
(tmp = fs->stat(path, NULL, NULL)) != 0))) {
|
||||
flags = tmp;
|
||||
} else {
|
||||
path[n2] = '\0'; // Remove appended index file name
|
||||
static void remove_double_dots(char *s) {
|
||||
char *p = s;
|
||||
while (*s != '\0') {
|
||||
*p++ = *s++;
|
||||
if (s[-1] == '/' || s[-1] == '\\') {
|
||||
while (s[0] != '\0') {
|
||||
if (s[0] == '/' || s[0] == '\\') {
|
||||
s++;
|
||||
} else if (s[0] == '.' && s[1] == '.') {
|
||||
s += 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check that the resolved file is located inside root directory
|
||||
if (strlen(path) < n1 || memcmp(root_dir, path, n1) != 0) {
|
||||
mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len,
|
||||
hm->uri.ptr);
|
||||
flags = 0;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
// Resolve requested file into `path` and return its fs->stat() result
|
||||
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
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
@@ -737,19 +738,22 @@ static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
|
||||
|
||||
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts) {
|
||||
char root[MG_PATH_MAX] = "", path[sizeof(root)] = "";
|
||||
int flags = uri_to_path(c, hm, opts, root, sizeof(root), path, sizeof(path));
|
||||
|
||||
if (flags == 0) return;
|
||||
// LOG(LL_DEBUG, ("root [%s], path [%s] %d", root, path, flags));
|
||||
if (flags & MG_FS_DIR) {
|
||||
listdir(c, hm, opts, path);
|
||||
} else if (opts->ssi_pattern != NULL &&
|
||||
mg_globmatch(opts->ssi_pattern, strlen(opts->ssi_pattern), path,
|
||||
strlen(path))) {
|
||||
mg_http_serve_ssi(c, root, path);
|
||||
char path[MG_PATH_MAX] = "";
|
||||
const char *sp = opts->ssi_pattern;
|
||||
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 {
|
||||
mg_http_serve_file(c, hm, path, opts);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
#include "str.h"
|
||||
|
||||
struct mg_http_header {
|
||||
struct mg_str name;
|
||||
struct mg_str value;
|
||||
struct mg_str name; // Header name
|
||||
struct mg_str value; // Header value
|
||||
};
|
||||
|
||||
struct mg_http_message {
|
||||
|
||||
+7
-7
@@ -23,13 +23,13 @@
|
||||
#define MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1)
|
||||
|
||||
struct mg_mqtt_opts {
|
||||
struct mg_str client_id;
|
||||
struct mg_str will_topic;
|
||||
struct mg_str will_message;
|
||||
uint8_t qos; // Quality of service
|
||||
bool will_retain; // Retain last will
|
||||
bool clean; // Use clean session, 0 or 1
|
||||
uint16_t keepalive; // Keep-alive timer in seconds
|
||||
struct mg_str client_id; // Client ID
|
||||
struct mg_str will_topic; // Will topic
|
||||
struct mg_str will_message; // Will message
|
||||
uint8_t qos; // Quality of service
|
||||
bool will_retain; // Retain last will
|
||||
bool clean; // Use clean session, 0 or 1
|
||||
uint16_t keepalive; // Keep-alive timer in seconds
|
||||
};
|
||||
|
||||
struct mg_mqtt_message {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <string.h>
|
||||
|
||||
struct mg_str {
|
||||
const char *ptr;
|
||||
size_t len;
|
||||
const char *ptr; // Pointer to string data
|
||||
size_t len; // String len
|
||||
};
|
||||
|
||||
#define MG_NULL_STR \
|
||||
|
||||
+2
-1
@@ -86,9 +86,10 @@ bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
|
||||
i++, j++;
|
||||
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
|
||||
ni = i, nj = j + 1, i++;
|
||||
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
|
||||
} else if (nj > 0 && nj <= n2 && (s1[ni] == '#' || s2[j] != '/')) {
|
||||
i = ni, j = nj;
|
||||
} else {
|
||||
// printf(">>: [%s] [%s] %d %d %d %d\n", s1, s2, i, j, ni, nj);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "http.h"
|
||||
|
||||
struct mg_ws_message {
|
||||
struct mg_str data;
|
||||
uint8_t flags; // Websocket message flags
|
||||
struct mg_str data; // Websocket message data
|
||||
uint8_t flags; // Websocket message flags
|
||||
};
|
||||
|
||||
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
|
||||
|
||||
+13
-6
@@ -36,6 +36,18 @@ static void test_globmatch(void) {
|
||||
ASSERT(mg_globmatch("/api/*", 6, "/api/foo", 8) == 1);
|
||||
ASSERT(mg_globmatch("/api/*", 6, "/api/log/static", 15) == 0);
|
||||
ASSERT(mg_globmatch("/api/#", 6, "/api/log/static", 15) == 1);
|
||||
ASSERT(mg_globmatch("#.shtml", 7, "/ssi/index.shtml", 16) == 1);
|
||||
ASSERT(mg_globmatch("#.c", 3, ".c", 2) == 1);
|
||||
ASSERT(mg_globmatch("abc", 3, "ab", 2) == 0);
|
||||
ASSERT(mg_globmatch("#.c", 3, "a.c", 3) == 1);
|
||||
ASSERT(mg_globmatch("#.c", 3, "..c", 3) == 1);
|
||||
ASSERT(mg_globmatch("#.c", 3, "/.c", 3) == 1);
|
||||
ASSERT(mg_globmatch("#.c", 3, "//a.c", 5) == 1);
|
||||
ASSERT(mg_globmatch("#.c", 3, "x/a.c", 5) == 1);
|
||||
ASSERT(mg_globmatch("#.c", 3, "./a.c", 5) == 1);
|
||||
ASSERT(mg_globmatch("#.shtml", 7, "./ssi/index.shtml", 17) == 1);
|
||||
ASSERT(mg_globmatch("#aa#bb#", 7, "caabba", 6) == 1);
|
||||
ASSERT(mg_globmatch("#aa#bb#", 7, "caabxa", 6) == 0);
|
||||
}
|
||||
|
||||
static void test_commalist(void) {
|
||||
@@ -575,12 +587,7 @@ static void test_http_server(void) {
|
||||
}
|
||||
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /badroot HTTP/1.0\r\n\n") == 400);
|
||||
#if MG_ARCH == MG_ARCH_WIN32
|
||||
ASSERT(cmpbody(buf, "Invalid web root [Z:\\BAAADDD!]\n") == 0);
|
||||
#else
|
||||
// LOG(LL_INFO, ("--> [%s]", buf));
|
||||
ASSERT(cmpbody(buf, "Bad web root [/BAAADDD!]\n") == 0);
|
||||
#endif
|
||||
ASSERT(cmpbody(buf, "Invalid web root [/BAAADDD!]\n") == 0);
|
||||
|
||||
{
|
||||
char *data = mg_file_read("./test/data/ca.pem", NULL);
|
||||
|
||||
Reference in new issue
Block a user