Commit e0b61092 authored by Sergey Lyubka's avatar Sergey Lyubka

Added -DNO_FILESYSTEM

parent d29f8496
......@@ -120,7 +120,9 @@ static void show_usage_and_exit(void) {
fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n",
MONGOOSE_VERSION, __DATE__);
fprintf(stderr, "Usage:\n");
#ifndef NO_AUTH
fprintf(stderr, " mongoose -A <htpasswd_file> <realm> <user> <passwd>\n");
#endif
fprintf(stderr, " mongoose [config_file]\n");
fprintf(stderr, " mongoose [-option value ...]\n");
fprintf(stderr, "\nOPTIONS:\n");
......@@ -142,7 +144,7 @@ static const char *config_file_top_comment =
"# To make a change, remove leading '#', modify option's value,\n"
"# save this file and then restart Mongoose.\n\n";
static const char *get_url_to_first_open_port(const struct mg_server *server) {
static const char *get_url_to_me(const struct mg_server *server) {
static char url[100];
const char *s = mg_get_option(server, "listening_port");
const char *cert = mg_get_option(server, "ssl_certificate");
......@@ -335,6 +337,7 @@ static void set_absolute_path(char *options[], const char *option_name,
}
}
#ifndef NO_AUTH
int modify_passwords_file(const char *fname, const char *domain,
const char *user, const char *pass) {
int found;
......@@ -397,6 +400,7 @@ int modify_passwords_file(const char *fname, const char *domain,
return 1;
}
#endif
static void start_mongoose(int argc, char *argv[]) {
char *options[MAX_OPTIONS];
......@@ -406,6 +410,7 @@ static void start_mongoose(int argc, char *argv[]) {
die("%s", "Failed to start Mongoose.");
}
#ifndef NO_AUTH
// Edit passwords file if -A option is specified
if (argc > 1 && !strcmp(argv[1], "-A")) {
if (argc != 6) {
......@@ -414,6 +419,7 @@ static void start_mongoose(int argc, char *argv[]) {
exit(modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ?
EXIT_SUCCESS : EXIT_FAILURE);
}
#endif
// Show usage if -h or --help options are specified
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
......@@ -882,8 +888,8 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
manage_service(LOWORD(wParam));
break;
case ID_CONNECT:
printf("[%s]\n", get_url_to_first_open_port(server));
ShellExecute(NULL, "open", get_url_to_first_open_port(server),
printf("[%s]\n", get_url_to_me(server));
ShellExecute(NULL, "open", get_url_to_me(server),
NULL, NULL, SW_SHOW);
break;
}
......@@ -980,7 +986,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
- (void) openBrowser {
[[NSWorkspace sharedWorkspace]
openURL:[NSURL URLWithString:
[NSString stringWithUTF8String:get_url_to_first_open_port(server)]]];
[NSString stringWithUTF8String:get_url_to_me(server)]]];
}
- (void) editConfig {
create_config_file(config_file);
......
......@@ -189,6 +189,14 @@ struct ll { struct ll *prev, *next; };
#define DBG(x)
#endif
#ifdef NO_FILESYSTEM
#define NO_AUTH
#define NO_CGI
#define NO_DAV
#define NO_DIRECTORY_LISTING
#define NO_LOGGING
#endif
union socket_address {
struct sockaddr sa;
struct sockaddr_in sin;
......@@ -217,10 +225,21 @@ struct dir_entry {
// NOTE(lsm): this enum shoulds be in sync with the config_options.
enum {
ACCESS_CONTROL_LIST, ACCESS_LOG_FILE, AUTH_DOMAIN, CGI_INTERPRETER,
ACCESS_CONTROL_LIST,
#ifndef NO_FILESYSTEM
ACCESS_LOG_FILE, AUTH_DOMAIN, CGI_INTERPRETER,
CGI_PATTERN, DAV_AUTH_FILE, DOCUMENT_ROOT, ENABLE_DIRECTORY_LISTING,
EXTRA_MIME_TYPES, GLOBAL_AUTH_FILE, HIDE_FILES_PATTERN,
IDLE_TIMEOUT_MS, INDEX_FILES, LISTENING_PORT,
#endif
EXTRA_MIME_TYPES,
#ifndef NO_FILESYSTEM
GLOBAL_AUTH_FILE,
#endif
HIDE_FILES_PATTERN,
IDLE_TIMEOUT_MS,
#ifndef NO_FILESYSTEM
INDEX_FILES,
#endif
LISTENING_PORT,
#ifndef _WIN32
RUN_AS_USER,
#endif
......@@ -230,6 +249,37 @@ enum {
URL_REWRITES, NUM_OPTIONS
};
static const char *static_config_options[] = {
"access_control_list", NULL,
#ifndef NO_FILESYSTEM
"access_log_file", NULL,
"auth_domain", "mydomain.com",
"cgi_interpreter", NULL,
"cgi_pattern", "**.cgi$|**.pl$|**.php$",
"dav_auth_file", NULL,
"document_root", NULL,
"enable_directory_listing", "yes",
#endif
"extra_mime_types", NULL,
#ifndef NO_FILESYSTEM
"global_auth_file", NULL,
#endif
"hide_files_patterns", NULL,
"idle_timeout_ms", "30000",
#ifndef NO_FILESYSTEM
"index_files","index.html,index.htm,index.cgi,index.php,index.lp",
#endif
"listening_port", NULL,
#ifndef _WIN32
"run_as_user", NULL,
#endif
#ifdef USE_SSL
"ssl_certificate", NULL,
#endif
"url_rewrites", NULL,
NULL
};
struct mg_server {
sock_t listening_sock;
union socket_address lsa; // Listening socket address
......@@ -339,36 +389,6 @@ static const struct {
{NULL, 0, NULL}
};
static const char *static_config_options[] = {
"access_control_list", NULL,
"access_log_file", NULL,
"auth_domain", "mydomain.com",
"cgi_interpreter", NULL,
"cgi_pattern", "**.cgi$|**.pl$|**.php$",
"dav_auth_file", NULL,
"document_root", NULL,
"enable_directory_listing", "yes",
"extra_mime_types", NULL,
"global_auth_file", NULL,
"hide_files_patterns", NULL,
"idle_timeout_ms", "30000",
"index_files","index.html,index.htm,index.cgi,index.php,index.lp",
"listening_port", NULL,
#ifndef _WIN32
"run_as_user", NULL,
#endif
#ifdef USE_SSL
"ssl_certificate", NULL,
#endif
"url_rewrites", NULL,
NULL
};
static const char *static_month_names[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
void *mg_start_thread(void *(*f)(void *), void *p) {
#ifdef _WIN32
return (void *) _beginthread((void (__cdecl *)(void *)) f, 0, p);
......@@ -1413,6 +1433,18 @@ static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
return diff;
}
// Return HTTP header value, or NULL if not found.
const char *mg_get_header(const struct mg_connection *ri, const char *s) {
int i;
for (i = 0; i < ri->num_headers; i++)
if (!mg_strcasecmp(s, ri->http_headers[i].name))
return ri->http_headers[i].value;
return NULL;
}
#ifndef NO_FILESYSTEM
// Perform case-insensitive match of string against pattern
static int match_prefix(const char *pattern, int pattern_len, const char *str) {
const char *or_str;
......@@ -1453,17 +1485,6 @@ static int match_prefix(const char *pattern, int pattern_len, const char *str) {
return j;
}
// Return HTTP header value, or NULL if not found.
const char *mg_get_header(const struct mg_connection *ri, const char *s) {
int i;
for (i = 0; i < ri->num_headers; i++)
if (!mg_strcasecmp(s, ri->http_headers[i].name))
return ri->http_headers[i].value;
return NULL;
}
// Return 1 if real file has been found, 0 otherwise
static int convert_uri_to_file_name(struct connection *conn, char *buf,
size_t buf_len, file_stat_t *st) {
......@@ -1508,6 +1529,7 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf,
return 0;
}
#endif // NO_FILESYSTEM
static int should_keep_alive(const struct mg_connection *conn) {
const char *method = conn->request_method;
......@@ -1518,17 +1540,6 @@ static int should_keep_alive(const struct mg_connection *conn) {
(header == NULL && http_version && !strcmp(http_version, "1.1")));
}
static const char *suggest_connection_header(const struct mg_connection *conn) {
return should_keep_alive(conn) ? "keep-alive" : "close";
}
static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
for (; *src != '\0' && n > 1; n--) {
*dst++ = *src++;
}
*dst = '\0';
}
int mg_write(struct mg_connection *c, const void *buf, int len) {
return spool(&((struct connection *) c)->remote_iobuf, buf, len);
}
......@@ -1903,111 +1914,30 @@ const char *mg_get_mime_type(const char *path) {
return "text/plain";
}
// Look at the "path" extension and figure what mime type it has.
// Store mime type in the vector.
static void get_mime_type(const struct mg_server *server, const char *path,
struct vec *vec) {
struct vec ext_vec, mime_vec;
const char *list, *ext;
size_t path_len;
path_len = strlen(path);
// Scan user-defined mime types first, in case user wants to
// override default mime types.
list = server->config_options[EXTRA_MIME_TYPES];
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
// ext now points to the path suffix
ext = path + path_len - ext_vec.len;
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
*vec = mime_vec;
return;
}
}
vec->ptr = mg_get_mime_type(path);
vec->len = strlen(vec->ptr);
}
static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
}
static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
}
static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
(unsigned long) st->st_mtime, (int64_t) st->st_size);
}
static void open_file_endpoint(struct connection *conn, const char *path,
file_stat_t *st) {
char date[64], lm[64], etag[64], range[64], headers[500];
const char *msg = "OK", *hdr;
time_t curtime = time(NULL);
int64_t r1, r2;
struct vec mime_vec;
int n;
conn->endpoint_type = EP_FILE;
set_close_on_exec(conn->endpoint.fd);
conn->mg_conn.status_code = 200;
get_mime_type(conn->server, path, &mime_vec);
conn->cl = st->st_size;
range[0] = '\0';
static struct uri_handler *find_uri_handler(struct mg_server *server,
const char *uri) {
struct ll *lp, *tmp;
struct uri_handler *uh;
// If Range: header specified, act accordingly
r1 = r2 = 0;
hdr = mg_get_header(&conn->mg_conn, "Range");
if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
r1 >= 0 && r2 >= 0) {
conn->mg_conn.status_code = 206;
conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1;
mg_snprintf(range, sizeof(range), "Content-Range: bytes "
"%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
r1, r1 + conn->cl - 1, (int64_t) st->st_size);
msg = "Partial Content";
lseek(conn->endpoint.fd, r1, SEEK_SET);
LINKED_LIST_FOREACH(&server->uri_handlers, lp, tmp) {
uh = LINKED_LIST_ENTRY(lp, struct uri_handler, link);
if (!strncmp(uh->uri, uri, strlen(uh->uri))) return uh;
}
// Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
gmt_time_string(date, sizeof(date), &curtime);
gmt_time_string(lm, sizeof(lm), &st->st_mtime);
construct_etag(etag, sizeof(etag), st);
n = mg_snprintf(headers, sizeof(headers),
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"Etag: %s\r\n"
"Content-Type: %.*s\r\n"
"Content-Length: %" INT64_FMT "\r\n"
"Connection: %s\r\n"
"Accept-Ranges: bytes\r\n"
"%s%s\r\n",
conn->mg_conn.status_code, msg, date, lm, etag,
(int) mime_vec.len, mime_vec.ptr, conn->cl,
suggest_connection_header(&conn->mg_conn),
range, USE_EXTRA_HTTP_HEADERS);
spool(&conn->remote_iobuf, headers, n);
if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
conn->flags |= CONN_SPOOL_DONE;
close(conn->endpoint.fd);
conn->endpoint_type = EP_NONE;
}
return NULL;
}
#ifndef NO_FILESYSTEM
// Convert month to the month number. Return -1 on error, or month number
static int get_month_index(const char *s) {
static const char *month_names[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
int i;
for (i = 0; i < (int) ARRAY_SIZE(static_month_names); i++)
if (!strcmp(s, static_month_names[i]))
for (i = 0; i < (int) ARRAY_SIZE(month_names); i++)
if (!strcmp(s, month_names[i]))
return i;
return -1;
......@@ -2045,6 +1975,41 @@ static time_t parse_date_string(const char *datetime) {
return result;
}
// Look at the "path" extension and figure what mime type it has.
// Store mime type in the vector.
static void get_mime_type(const struct mg_server *server, const char *path,
struct vec *vec) {
struct vec ext_vec, mime_vec;
const char *list, *ext;
size_t path_len;
path_len = strlen(path);
// Scan user-defined mime types first, in case user wants to
// override default mime types.
list = server->config_options[EXTRA_MIME_TYPES];
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
// ext now points to the path suffix
ext = path + path_len - ext_vec.len;
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
*vec = mime_vec;
return;
}
}
vec->ptr = mg_get_mime_type(path);
vec->len = strlen(vec->ptr);
}
static const char *suggest_connection_header(const struct mg_connection *conn) {
return should_keep_alive(conn) ? "keep-alive" : "close";
}
static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
(unsigned long) st->st_mtime, (int64_t) st->st_size);
}
// Return True if we should reply 304 Not Modified.
static int is_not_modified(const struct connection *conn,
const file_stat_t *stp) {
......@@ -2056,19 +2021,6 @@ static int is_not_modified(const struct connection *conn,
(ims != NULL && stp->st_mtime <= parse_date_string(ims));
}
static struct uri_handler *find_uri_handler(struct mg_server *server,
const char *uri) {
struct ll *lp, *tmp;
struct uri_handler *uh;
LINKED_LIST_FOREACH(&server->uri_handlers, lp, tmp) {
uh = LINKED_LIST_ENTRY(lp, struct uri_handler, link);
if (!strncmp(uh->uri, uri, strlen(uh->uri))) return uh;
}
return NULL;
}
// For given directory path, substitute it to valid index file.
// Return 0 if index file has been found, -1 if not found.
// If the file is found, it's stats is returned in stp.
......@@ -2096,7 +2048,8 @@ static int find_index_file(struct connection *conn, char *path,
continue;
// Prepare full path to the index file
mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
strncpy(path + n + 1, filename_vec.ptr, filename_vec.len);
path[n + 1 + filename_vec.len] = '\0';
//DBG(("[%s]", path));
......@@ -2117,6 +2070,76 @@ static int find_index_file(struct connection *conn, char *path,
return found;
}
static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
}
static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
}
static void open_file_endpoint(struct connection *conn, const char *path,
file_stat_t *st) {
char date[64], lm[64], etag[64], range[64], headers[500];
const char *msg = "OK", *hdr;
time_t curtime = time(NULL);
int64_t r1, r2;
struct vec mime_vec;
int n;
conn->endpoint_type = EP_FILE;
set_close_on_exec(conn->endpoint.fd);
conn->mg_conn.status_code = 200;
get_mime_type(conn->server, path, &mime_vec);
conn->cl = st->st_size;
range[0] = '\0';
// If Range: header specified, act accordingly
r1 = r2 = 0;
hdr = mg_get_header(&conn->mg_conn, "Range");
if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
r1 >= 0 && r2 >= 0) {
conn->mg_conn.status_code = 206;
conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1;
mg_snprintf(range, sizeof(range), "Content-Range: bytes "
"%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
r1, r1 + conn->cl - 1, (int64_t) st->st_size);
msg = "Partial Content";
lseek(conn->endpoint.fd, r1, SEEK_SET);
}
// Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
gmt_time_string(date, sizeof(date), &curtime);
gmt_time_string(lm, sizeof(lm), &st->st_mtime);
construct_etag(etag, sizeof(etag), st);
n = mg_snprintf(headers, sizeof(headers),
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"Etag: %s\r\n"
"Content-Type: %.*s\r\n"
"Content-Length: %" INT64_FMT "\r\n"
"Connection: %s\r\n"
"Accept-Ranges: bytes\r\n"
"%s%s\r\n",
conn->mg_conn.status_code, msg, date, lm, etag,
(int) mime_vec.len, mime_vec.ptr, conn->cl,
suggest_connection_header(&conn->mg_conn),
range, USE_EXTRA_HTTP_HEADERS);
spool(&conn->remote_iobuf, headers, n);
if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
conn->flags |= CONN_SPOOL_DONE;
close(conn->endpoint.fd);
conn->endpoint_type = EP_NONE;
}
}
#endif // NO_FILESYSTEM
static void write_terminating_chunk(struct connection *conn) {
mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
}
......@@ -2584,7 +2607,6 @@ static void forward_put_data(struct connection *conn) {
}
}
}
#endif // NO_DAV
static void send_options(struct connection *conn) {
static const char reply[] = "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, "
......@@ -2592,6 +2614,7 @@ static void send_options(struct connection *conn) {
spool(&conn->remote_iobuf, reply, sizeof(reply) - 1);
conn->flags |= CONN_SPOOL_DONE;
}
#endif // NO_DAV
#ifndef NO_AUTH
static void send_authorization_request(struct connection *conn) {
......@@ -2630,7 +2653,7 @@ static FILE *open_auth_file(struct connection *conn, const char *path) {
return fp;
}
#ifndef HAVE_MD5
#if !defined(HAVE_MD5) && !defined(NO_AUTH)
typedef struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
......@@ -3234,13 +3257,15 @@ static void handle_lsp_request(struct connection *conn, const char *path,
#endif // USE_LUA
static void open_local_endpoint(struct connection *conn) {
const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
#ifndef NO_FILESYSTEM
static const char lua_pat[] = LUA_SCRIPT_PATTERN;
char path[MAX_PATH_SIZE];
file_stat_t st;
char path[MAX_PATH_SIZE];
int exists = 0, is_directory = 0;
const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
const char *dir_lst = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
#endif
conn->mg_conn.content_len = cl_hdr == NULL ? 0 : (int) to64(cl_hdr);
......@@ -3262,6 +3287,9 @@ static void open_local_endpoint(struct connection *conn) {
return;
}
#ifdef NO_FILESYSTEM
send_http_error(conn, 404, NULL);
#else
exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
is_directory = S_ISDIR(st.st_mode);
......@@ -3329,6 +3357,7 @@ static void open_local_endpoint(struct connection *conn) {
} else {
send_http_error(conn, 404, NULL);
}
#endif // NO_FILESYSTEM
}
static void send_continue_if_expected(struct connection *conn) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment