mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-08 16:11:18 +00:00
Using core.h and modified API
This commit is contained in:
1 parent
6c8a0aa768
commit
8a65611a8c
2 files changed
+281
-93
No files matched your search
+192
-93
@@ -69,6 +69,7 @@ typedef CRITICAL_SECTION mutex_t;
|
|||||||
#define mutex_lock(x) EnterCriticalSection(x)
|
#define mutex_lock(x) EnterCriticalSection(x)
|
||||||
#define mutex_unlock(x) LeaveCriticalSection(x)
|
#define mutex_unlock(x) LeaveCriticalSection(x)
|
||||||
#define S_ISDIR(x) ((x) & _S_IFDIR)
|
#define S_ISDIR(x) ((x) & _S_IFDIR)
|
||||||
|
#define sleep(x) Sleep((x) * 1000)
|
||||||
#ifndef va_copy
|
#ifndef va_copy
|
||||||
#define va_copy(x,y) x = y
|
#define va_copy(x,y) x = y
|
||||||
#endif // MINGW #defines va_copy
|
#endif // MINGW #defines va_copy
|
||||||
@@ -93,7 +94,8 @@ typedef pthread_mutex_t mutex_t;
|
|||||||
#define INT64_FMT PRId64
|
#define INT64_FMT PRId64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mongoose.h"
|
//#include "mongoose.h"
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
struct linked_list_link { struct linked_list_link *prev, *next; };
|
struct linked_list_link { struct linked_list_link *prev, *next; };
|
||||||
#define LINKED_LIST_INIT(N) ((N)->next = (N)->prev = (N))
|
#define LINKED_LIST_INIT(N) ((N)->next = (N)->prev = (N))
|
||||||
@@ -139,6 +141,12 @@ struct vec {
|
|||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct uri_handler {
|
||||||
|
struct linked_list_link link;
|
||||||
|
char *uri;
|
||||||
|
mg_uri_handler_t handler;
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE(lsm): this enum shoulds be in sync with the config_options.
|
// NOTE(lsm): this enum shoulds be in sync with the config_options.
|
||||||
enum {
|
enum {
|
||||||
ACCESS_CONTROL_LIST, ACCESS_LOG_FILE, AUTH_DOMAIN, CGI_INTERPRETER,
|
ACCESS_CONTROL_LIST, ACCESS_LOG_FILE, AUTH_DOMAIN, CGI_INTERPRETER,
|
||||||
@@ -152,9 +160,9 @@ struct mg_server {
|
|||||||
sock_t listening_sock;
|
sock_t listening_sock;
|
||||||
union socket_address lsa; // Listening socket address
|
union socket_address lsa; // Listening socket address
|
||||||
struct linked_list_link active_connections;
|
struct linked_list_link active_connections;
|
||||||
|
struct linked_list_link uri_handlers;
|
||||||
char *config_options[NUM_OPTIONS];
|
char *config_options[NUM_OPTIONS];
|
||||||
mg_event_handler_t event_handler;
|
void *server_data;
|
||||||
void *user_data;
|
|
||||||
sock_t ctl[2]; // Control socketpair. Used to wake up from select() call
|
sock_t ctl[2]; // Control socketpair. Used to wake up from select() call
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,13 +178,13 @@ union endpoint {
|
|||||||
void *ssl; // SSL descriptor
|
void *ssl; // SSL descriptor
|
||||||
};
|
};
|
||||||
|
|
||||||
enum endpoint_type { EP_NONE, EP_FILE, EP_DIR, EP_CGI, EP_SSL };
|
enum endpoint_type { EP_NONE, EP_FILE, EP_DIR, EP_CGI, EP_SSL, EP_USER };
|
||||||
enum connection_flags { CONN_CLOSE = 1, CONN_SPOOL_DONE = 2 };
|
enum connection_flags { CONN_CLOSE = 1, CONN_SPOOL_DONE = 2 };
|
||||||
|
|
||||||
struct mg_connection {
|
struct connection {
|
||||||
|
struct mg_connection mg_conn; // XXX: Must be first
|
||||||
struct linked_list_link link; // Linkage to server->active_connections
|
struct linked_list_link link; // Linkage to server->active_connections
|
||||||
struct mg_server *server;
|
struct mg_server *server;
|
||||||
struct mg_event event; // NOTE(lsm): this has conn_data attribute
|
|
||||||
sock_t client_sock; // Connected client
|
sock_t client_sock; // Connected client
|
||||||
union socket_address csa; // Client's socket address
|
union socket_address csa; // Client's socket address
|
||||||
struct iobuf local_iobuf;
|
struct iobuf local_iobuf;
|
||||||
@@ -184,7 +192,6 @@ struct mg_connection {
|
|||||||
union endpoint endpoint;
|
union endpoint endpoint;
|
||||||
enum endpoint_type endpoint_type;
|
enum endpoint_type endpoint_type;
|
||||||
time_t expire_time;
|
time_t expire_time;
|
||||||
struct mg_request_info request_info;
|
|
||||||
char *path_info;
|
char *path_info;
|
||||||
int request_len;
|
int request_len;
|
||||||
int flags;
|
int flags;
|
||||||
@@ -206,7 +213,7 @@ static const char *static_config_options[] = {
|
|||||||
"hide_files_patterns", NULL,
|
"hide_files_patterns", NULL,
|
||||||
"idle_timeout_ms", "30000",
|
"idle_timeout_ms", "30000",
|
||||||
"index_files","index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
|
"index_files","index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
|
||||||
"listening_port", "8080",
|
"listening_port", NULL,
|
||||||
"num_threads", "50",
|
"num_threads", "50",
|
||||||
"put_delete_auth_file", NULL,
|
"put_delete_auth_file", NULL,
|
||||||
"run_as_user", NULL,
|
"run_as_user", NULL,
|
||||||
@@ -287,13 +294,13 @@ static int get_option_index(const char *name) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mg_get_option2(const struct mg_server *srv, const char *name) {
|
const char *mg_get_option(const struct mg_server *srv, const char *name) {
|
||||||
int i = get_option_index(name);
|
int i = get_option_index(name);
|
||||||
return i == -1 ? NULL : srv->config_options[i] == NULL ? "" :
|
return i == -1 ? NULL : srv->config_options[i] == NULL ? "" :
|
||||||
srv->config_options[i];
|
srv->config_options[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_start_thread(mg_thread_func_t f, void *p) {
|
int mg_start_thread(void *(*f)(void *), void *p) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
|
return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
|
||||||
#else
|
#else
|
||||||
@@ -316,6 +323,7 @@ int mg_start_thread(mg_thread_func_t f, void *p) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static int call_user(int event_type, struct mg_connection *conn, void *p) {
|
static int call_user(int event_type, struct mg_connection *conn, void *p) {
|
||||||
if (conn != NULL && conn->server != NULL) {
|
if (conn != NULL && conn->server != NULL) {
|
||||||
conn->event.user_data = conn->server->user_data;
|
conn->event.user_data = conn->server->user_data;
|
||||||
@@ -327,6 +335,7 @@ static int call_user(int event_type, struct mg_connection *conn, void *p) {
|
|||||||
return !conn || !conn->server || !conn->server->event_handler ? 0 :
|
return !conn || !conn->server || !conn->server->event_handler ? 0 :
|
||||||
conn->server->event_handler(&conn->event);
|
conn->server->event_handler(&conn->event);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void set_close_on_exec(int fd) {
|
static void set_close_on_exec(int fd) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -547,11 +556,11 @@ static int check_acl(const char *acl, uint32_t remote_ip) {
|
|||||||
return allowed == '+';
|
return allowed == '+';
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mg_connection *accept_new_connection(struct mg_server *server) {
|
static struct connection *accept_new_connection(struct mg_server *server) {
|
||||||
union socket_address sa;
|
union socket_address sa;
|
||||||
socklen_t len = sizeof(sa);
|
socklen_t len = sizeof(sa);
|
||||||
sock_t sock = INVALID_SOCKET;
|
sock_t sock = INVALID_SOCKET;
|
||||||
struct mg_connection *conn = NULL;
|
struct connection *conn = NULL;
|
||||||
|
|
||||||
if ((sock = accept(server->listening_sock, &sa.sa, &len)) == INVALID_SOCKET) {
|
if ((sock = accept(server->listening_sock, &sa.sa, &len)) == INVALID_SOCKET) {
|
||||||
#if 0
|
#if 0
|
||||||
@@ -562,7 +571,7 @@ static struct mg_connection *accept_new_connection(struct mg_server *server) {
|
|||||||
} else if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
|
} else if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
|
||||||
ntohl(* (uint32_t *) &sa.sin.sin_addr))) {
|
ntohl(* (uint32_t *) &sa.sin.sin_addr))) {
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
} else if ((conn = (struct mg_connection *)
|
} else if ((conn = (struct connection *)
|
||||||
calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
|
calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
} else {
|
} else {
|
||||||
@@ -584,7 +593,7 @@ static struct mg_connection *accept_new_connection(struct mg_server *server) {
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_conn(struct mg_connection *conn) {
|
static void close_conn(struct connection *conn) {
|
||||||
DBG(("closing %p", conn));
|
DBG(("closing %p", conn));
|
||||||
LINKED_LIST_REMOVE(&conn->link);
|
LINKED_LIST_REMOVE(&conn->link);
|
||||||
closesocket(conn->client_sock);
|
closesocket(conn->client_sock);
|
||||||
@@ -638,7 +647,7 @@ static char *skip(char **buf, const char *delimiters) {
|
|||||||
|
|
||||||
// Parse HTTP headers from the given buffer, advance buffer to the point
|
// Parse HTTP headers from the given buffer, advance buffer to the point
|
||||||
// where parsing stopped.
|
// where parsing stopped.
|
||||||
static void parse_http_headers(char **buf, struct mg_request_info *ri) {
|
static void parse_http_headers(char **buf, struct mg_connection *ri) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
|
for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
|
||||||
@@ -658,16 +667,15 @@ static int is_valid_http_method(const char *method) {
|
|||||||
|| !strcmp(method, "MKCOL");
|
|| !strcmp(method, "MKCOL");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse HTTP request, fill in mg_request_info structure.
|
// Parse HTTP request, fill in mg_request structure.
|
||||||
// This function modifies the buffer by NUL-terminating
|
// This function modifies the buffer by NUL-terminating
|
||||||
// HTTP request components, header names and header values.
|
// HTTP request components, header names and header values.
|
||||||
static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
|
static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
|
||||||
int is_request, request_len = get_request_len((unsigned char *) buf, len);
|
int is_request, request_len = get_request_len((unsigned char *) buf, len);
|
||||||
if (request_len > 0) {
|
if (request_len > 0) {
|
||||||
// Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
|
// Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
|
||||||
ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
|
ri->request_method = ri->uri = ri->http_version = NULL;
|
||||||
ri->num_headers = 0;
|
ri->num_headers = 0;
|
||||||
|
|
||||||
buf[request_len - 1] = '\0';
|
buf[request_len - 1] = '\0';
|
||||||
|
|
||||||
// RFC says that all initial whitespaces should be ingored
|
// RFC says that all initial whitespaces should be ingored
|
||||||
@@ -804,7 +812,7 @@ int mg_url_decode(const char *src, int src_len, char *dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return HTTP header value, or NULL if not found.
|
// Return HTTP header value, or NULL if not found.
|
||||||
static const char *get_header(const struct mg_request_info *ri, const char *s) {
|
const char *mg_get_header(const struct mg_connection *ri, const char *s) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ri->num_headers; i++)
|
for (i = 0; i < ri->num_headers; i++)
|
||||||
@@ -814,18 +822,14 @@ static const char *get_header(const struct mg_request_info *ri, const char *s) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mg_get_header(const struct mg_connection *conn, const char *name) {
|
|
||||||
return get_header(&conn->request_info, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return 1 if real file has been found, 0 otherwise
|
// Return 1 if real file has been found, 0 otherwise
|
||||||
static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
|
static int convert_uri_to_file_name(struct connection *conn, char *buf,
|
||||||
size_t buf_len, struct stat *st) {
|
size_t buf_len, struct stat *st) {
|
||||||
struct vec a, b;
|
struct vec a, b;
|
||||||
const char *rewrites = conn->server->config_options[URL_REWRITES],
|
const char *rewrites = conn->server->config_options[URL_REWRITES],
|
||||||
*root = conn->server->config_options[DOCUMENT_ROOT],
|
*root = conn->server->config_options[DOCUMENT_ROOT],
|
||||||
*cgi_pat = conn->server->config_options[CGI_PATTERN],
|
*cgi_pat = conn->server->config_options[CGI_PATTERN],
|
||||||
*uri = conn->request_info.uri;
|
*uri = conn->mg_conn.uri;
|
||||||
char *p;
|
char *p;
|
||||||
int match_len;
|
int match_len;
|
||||||
|
|
||||||
@@ -896,7 +900,8 @@ static int vspool(struct iobuf *io, const char *fmt, va_list ap) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
|
int mg_printf(struct mg_connection *c, const char *fmt, ...) {
|
||||||
|
struct connection *conn = (struct connection *) c;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int ret;
|
int ret;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
@@ -908,7 +913,8 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_write(struct mg_connection *conn, const void *buf, int len) {
|
int mg_write(struct mg_connection *c, const void *buf, int len) {
|
||||||
|
struct connection *conn = (struct connection *) c;
|
||||||
int ret;
|
int ret;
|
||||||
mutex_lock(&conn->mutex);
|
mutex_lock(&conn->mutex);
|
||||||
ret = spool(&conn->remote_iobuf, buf, len);
|
ret = spool(&conn->remote_iobuf, buf, len);
|
||||||
@@ -921,7 +927,7 @@ static int is_error(int n) {
|
|||||||
return n == 0 || (n < 0 && errno != EINTR && errno != EAGAIN);
|
return n == 0 || (n < 0 && errno != EINTR && errno != EAGAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_to_client(struct mg_connection *conn) {
|
static void write_to_client(struct connection *conn) {
|
||||||
struct iobuf *io = &conn->remote_iobuf;
|
struct iobuf *io = &conn->remote_iobuf;
|
||||||
int n = send(conn->client_sock, io->buf, io->len, 0);
|
int n = send(conn->client_sock, io->buf, io->len, 0);
|
||||||
|
|
||||||
@@ -938,7 +944,7 @@ static void write_to_client(struct mg_connection *conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mg_get_builtin_mime_type(const char *path) {
|
const char *mg_get_mime_type(const char *path) {
|
||||||
const char *ext;
|
const char *ext;
|
||||||
size_t i, path_len;
|
size_t i, path_len;
|
||||||
|
|
||||||
@@ -977,7 +983,7 @@ static void get_mime_type(const struct mg_server *server, const char *path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec->ptr = mg_get_builtin_mime_type(path);
|
vec->ptr = mg_get_mime_type(path);
|
||||||
vec->len = strlen(vec->ptr);
|
vec->len = strlen(vec->ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -994,7 +1000,7 @@ static void construct_etag(char *buf, size_t buf_len, const struct stat *st) {
|
|||||||
(unsigned long) st->st_mtime, (int64_t) st->st_size);
|
(unsigned long) st->st_mtime, (int64_t) st->st_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void open_file_endpoint(struct mg_connection *conn, const char *path,
|
static void open_file_endpoint(struct connection *conn, const char *path,
|
||||||
struct stat *st) {
|
struct stat *st) {
|
||||||
char date[64], lm[64], etag[64], range[64];
|
char date[64], lm[64], etag[64], range[64];
|
||||||
const char *msg = "OK", *hdr;
|
const char *msg = "OK", *hdr;
|
||||||
@@ -1013,7 +1019,7 @@ static void open_file_endpoint(struct mg_connection *conn, const char *path,
|
|||||||
|
|
||||||
// If Range: header specified, act accordingly
|
// If Range: header specified, act accordingly
|
||||||
r1 = r2 = 0;
|
r1 = r2 = 0;
|
||||||
hdr = mg_get_header(conn, "Range");
|
hdr = mg_get_header(&conn->mg_conn, "Range");
|
||||||
if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
|
if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
|
||||||
r1 >= 0 && r2 >= 0) {
|
r1 >= 0 && r2 >= 0) {
|
||||||
conn->status_code = 206;
|
conn->status_code = 206;
|
||||||
@@ -1031,7 +1037,7 @@ static void open_file_endpoint(struct mg_connection *conn, const char *path,
|
|||||||
gmt_time_string(lm, sizeof(lm), &st->st_mtime);
|
gmt_time_string(lm, sizeof(lm), &st->st_mtime);
|
||||||
construct_etag(etag, sizeof(etag), st);
|
construct_etag(etag, sizeof(etag), st);
|
||||||
|
|
||||||
mg_printf(conn,
|
mg_printf(&conn->mg_conn,
|
||||||
"HTTP/1.1 %d %s\r\n"
|
"HTTP/1.1 %d %s\r\n"
|
||||||
"Date: %s\r\n"
|
"Date: %s\r\n"
|
||||||
"Last-Modified: %s\r\n"
|
"Last-Modified: %s\r\n"
|
||||||
@@ -1044,46 +1050,67 @@ static void open_file_endpoint(struct mg_connection *conn, const char *path,
|
|||||||
conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
|
conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
|
||||||
mime_vec.ptr, cl, "keep-alive", range, EXTRA_HTTP_HEADERS);
|
mime_vec.ptr, cl, "keep-alive", range, EXTRA_HTTP_HEADERS);
|
||||||
|
|
||||||
if (!strcmp(conn->request_info.request_method, "HEAD")) {
|
if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
|
||||||
lseek(conn->endpoint.fd, 0, SEEK_END);
|
lseek(conn->endpoint.fd, 0, SEEK_END);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void open_local_endpoint(struct mg_connection *conn) {
|
static struct uri_handler *find_uri_handler(struct mg_server *server,
|
||||||
struct mg_request_info *ri = &conn->request_info;
|
const char *uri) {
|
||||||
|
struct linked_list_link *lp, *tmp;
|
||||||
|
struct uri_handler *uh;
|
||||||
|
|
||||||
|
LINKED_LIST_FOREACH(&server->uri_handlers, lp, tmp) {
|
||||||
|
uh = LINKED_LIST_ENTRY(lp, struct uri_handler, link);
|
||||||
|
if (!strcmp(uh->uri, uri)) return uh;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void open_local_endpoint(struct connection *conn) {
|
||||||
char path[MAX_PATH_SIZE] = {'\0'};
|
char path[MAX_PATH_SIZE] = {'\0'};
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int uri_len, exists = 0, is_directory = 0;
|
int uri_len, exists = 0, is_directory = 0;
|
||||||
|
struct uri_handler *uh;
|
||||||
|
|
||||||
if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
|
if ((conn->mg_conn.query_string = strchr(conn->mg_conn.uri, '?')) != NULL) {
|
||||||
* ((char *) conn->request_info.query_string++) = '\0';
|
* ((char *) conn->mg_conn.query_string++) = '\0';
|
||||||
}
|
}
|
||||||
uri_len = (int) strlen(ri->uri);
|
uri_len = (int) strlen(conn->mg_conn.uri);
|
||||||
mg_url_decode(ri->uri, uri_len, (char *) ri->uri, uri_len + 1, 0);
|
mg_url_decode(conn->mg_conn.uri, uri_len, (char *) conn->mg_conn.uri,
|
||||||
remove_double_dots_and_double_slashes((char *) ri->uri);
|
uri_len + 1, 0);
|
||||||
|
remove_double_dots_and_double_slashes((char *) conn->mg_conn.uri);
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (call_user(MG_REQUEST_BEGIN, conn, NULL) != 0) {
|
if (call_user(MG_REQUEST_BEGIN, conn, NULL) != 0) {
|
||||||
conn->flags |= CONN_SPOOL_DONE;
|
conn->flags |= CONN_SPOOL_DONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((uh = find_uri_handler(conn->server, conn->mg_conn.uri)) != NULL) {
|
||||||
|
conn->endpoint_type = EP_USER;
|
||||||
|
}
|
||||||
|
|
||||||
exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
|
exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
|
||||||
is_directory = S_ISDIR(st.st_mode);
|
is_directory = S_ISDIR(st.st_mode);
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
mg_printf(conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n");
|
mg_printf(&conn->mg_conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n");
|
||||||
conn->flags |= CONN_SPOOL_DONE;
|
conn->flags |= CONN_SPOOL_DONE;
|
||||||
} else if (is_directory && ri->uri[uri_len - 1] != '/') {
|
} else if (is_directory && conn->mg_conn.uri[uri_len - 1] != '/') {
|
||||||
mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"
|
mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
|
||||||
"Location: %s/\r\n\r\n", ri->uri);
|
"Location: %s/\r\n\r\n", conn->mg_conn.uri);
|
||||||
conn->flags |= CONN_SPOOL_DONE;
|
conn->flags |= CONN_SPOOL_DONE;
|
||||||
} else if (is_directory) {
|
} else if (is_directory) {
|
||||||
mg_printf(conn, "%s", "HTTP/1.0 403 Directory Listing Denied\r\n\r\n");
|
mg_printf(&conn->mg_conn, "%s",
|
||||||
|
"HTTP/1.0 403 Directory Listing Denied\r\n\r\n");
|
||||||
conn->flags |= CONN_SPOOL_DONE;
|
conn->flags |= CONN_SPOOL_DONE;
|
||||||
} else if ((conn->endpoint.fd = open(path, O_RDONLY)) != -1) {
|
} else if ((conn->endpoint.fd = open(path, O_RDONLY)) != -1) {
|
||||||
open_file_endpoint(conn, path, &st);
|
open_file_endpoint(conn, path, &st);
|
||||||
} else {
|
} else {
|
||||||
mg_printf(conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n");
|
mg_printf(&conn->mg_conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n");
|
||||||
conn->flags |= CONN_SPOOL_DONE;
|
conn->flags |= CONN_SPOOL_DONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1092,13 +1119,12 @@ static int io_space(const struct iobuf *io) {
|
|||||||
return io->size - io->len;
|
return io->size - io->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_request(struct mg_connection *conn) {
|
static void process_request(struct connection *conn) {
|
||||||
struct iobuf *io = &conn->local_iobuf;
|
struct iobuf *io = &conn->local_iobuf;
|
||||||
|
|
||||||
//DBG(("parse_http_message(%d [%.*s])", io->len, io->len, io->buf));
|
//DBG(("parse_http_message(%d [%.*s])", io->len, io->len, io->buf));
|
||||||
if (conn->request_len == 0) {
|
if (conn->request_len == 0) {
|
||||||
conn->request_len = parse_http_message(io->buf, io->len,
|
conn->request_len = parse_http_message(io->buf, io->len, &conn->mg_conn);
|
||||||
&conn->request_info);
|
|
||||||
}
|
}
|
||||||
DBG(("parse_http_message() -> %d", conn->request_len));
|
DBG(("parse_http_message() -> %d", conn->request_len));
|
||||||
|
|
||||||
@@ -1111,7 +1137,7 @@ static void process_request(struct mg_connection *conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_from_client(struct mg_connection *conn) {
|
static void read_from_client(struct connection *conn) {
|
||||||
struct iobuf *io = &conn->local_iobuf;
|
struct iobuf *io = &conn->local_iobuf;
|
||||||
int n = recv(conn->client_sock, io->buf + io->len, io->size - io->len, 0);
|
int n = recv(conn->client_sock, io->buf + io->len, io->size - io->len, 0);
|
||||||
|
|
||||||
@@ -1127,21 +1153,19 @@ static void read_from_client(struct mg_connection *conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int should_keep_alive(const struct mg_connection *conn) {
|
static int should_keep_alive(const struct connection *conn) {
|
||||||
const char *method = conn->request_info.request_method;
|
const char *method = conn->mg_conn.request_method;
|
||||||
const char *http_version = conn->request_info.http_version;
|
const char *http_version = conn->mg_conn.http_version;
|
||||||
const char *header = mg_get_header(conn, "Connection");
|
const char *header = mg_get_header(&conn->mg_conn, "Connection");
|
||||||
return method != NULL && !strcmp(method, "GET") &&
|
return method != NULL && !strcmp(method, "GET") &&
|
||||||
((header != NULL && !strcmp(header, "keep-alive")) ||
|
((header != NULL && !strcmp(header, "keep-alive")) ||
|
||||||
(header == NULL && http_version && !strcmp(http_version, "1.1")));
|
(header == NULL && http_version && !strcmp(http_version, "1.1")));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_local_endpoint(struct mg_connection *conn) {
|
static void close_local_endpoint(struct connection *conn) {
|
||||||
struct iobuf *io = &conn->local_iobuf;
|
struct iobuf *io = &conn->local_iobuf;
|
||||||
int keep_alive = should_keep_alive(conn); // Must be done before memmove
|
int keep_alive = should_keep_alive(conn); // Must be done before memmove
|
||||||
|
|
||||||
call_user(MG_REQUEST_END, conn, (void *) (long) conn->status_code);
|
|
||||||
|
|
||||||
// Close file descriptor
|
// Close file descriptor
|
||||||
switch (conn->endpoint_type) {
|
switch (conn->endpoint_type) {
|
||||||
case EP_FILE: close(conn->endpoint.fd); break;
|
case EP_FILE: close(conn->endpoint.fd); break;
|
||||||
@@ -1162,7 +1186,7 @@ static void close_local_endpoint(struct mg_connection *conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void transfer_file_data(struct mg_connection *conn) {
|
static void transfer_file_data(struct connection *conn) {
|
||||||
struct iobuf *io = &conn->remote_iobuf;
|
struct iobuf *io = &conn->remote_iobuf;
|
||||||
int n, rem_space = io_space(io);
|
int n, rem_space = io_space(io);
|
||||||
|
|
||||||
@@ -1183,22 +1207,24 @@ void add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_poll_server(struct mg_server *server, unsigned int milliseconds) {
|
void mg_poll_server(struct mg_server *server, int milliseconds) {
|
||||||
struct linked_list_link *lp, *tmp;
|
struct linked_list_link *lp, *tmp;
|
||||||
struct mg_connection *conn;
|
struct connection *conn;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
fd_set read_set, write_set;
|
fd_set read_set, write_set;
|
||||||
sock_t max_fd = -1;
|
sock_t max_fd = -1;
|
||||||
time_t current_time = time(NULL), expire_time = current_time +
|
time_t current_time = time(NULL), expire_time = current_time +
|
||||||
atoi(server->config_options[IDLE_TIMEOUT_MS]) / 1000;
|
atoi(server->config_options[IDLE_TIMEOUT_MS]) / 1000;
|
||||||
|
|
||||||
|
if (server->listening_sock == INVALID_SOCKET) return;
|
||||||
|
|
||||||
FD_ZERO(&read_set);
|
FD_ZERO(&read_set);
|
||||||
FD_ZERO(&write_set);
|
FD_ZERO(&write_set);
|
||||||
add_to_set(server->listening_sock, &read_set, &max_fd);
|
add_to_set(server->listening_sock, &read_set, &max_fd);
|
||||||
add_to_set(server->ctl[0], &read_set, &max_fd);
|
add_to_set(server->ctl[0], &read_set, &max_fd);
|
||||||
|
|
||||||
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
||||||
conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link);
|
conn = LINKED_LIST_ENTRY(lp, struct connection, link);
|
||||||
add_to_set(conn->client_sock, &read_set, &max_fd);
|
add_to_set(conn->client_sock, &read_set, &max_fd);
|
||||||
if (conn->endpoint_type == EP_FILE) {
|
if (conn->endpoint_type == EP_FILE) {
|
||||||
transfer_file_data(conn);
|
transfer_file_data(conn);
|
||||||
@@ -1230,7 +1256,7 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) {
|
|||||||
|
|
||||||
// Read/write from clients
|
// Read/write from clients
|
||||||
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
||||||
conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link);
|
conn = LINKED_LIST_ENTRY(lp, struct connection, link);
|
||||||
if (FD_ISSET(conn->client_sock, &read_set)) {
|
if (FD_ISSET(conn->client_sock, &read_set)) {
|
||||||
conn->expire_time = expire_time;
|
conn->expire_time = expire_time;
|
||||||
read_from_client(conn);
|
read_from_client(conn);
|
||||||
@@ -1244,7 +1270,7 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) {
|
|||||||
|
|
||||||
// Close expired connections and those that need to be closed
|
// Close expired connections and those that need to be closed
|
||||||
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
||||||
conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link);
|
conn = LINKED_LIST_ENTRY(lp, struct connection, link);
|
||||||
if (conn->flags & CONN_CLOSE || current_time > conn->expire_time) {
|
if (conn->flags & CONN_CLOSE || current_time > conn->expire_time) {
|
||||||
close_conn(conn);
|
close_conn(conn);
|
||||||
}
|
}
|
||||||
@@ -1253,27 +1279,85 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) {
|
|||||||
|
|
||||||
void mg_destroy_server(struct mg_server **server) {
|
void mg_destroy_server(struct mg_server **server) {
|
||||||
struct linked_list_link *lp, *tmp;
|
struct linked_list_link *lp, *tmp;
|
||||||
struct mg_connection *conn;
|
|
||||||
|
|
||||||
if (server != NULL && *server != NULL) {
|
if (server != NULL && *server != NULL) {
|
||||||
closesocket((*server)->listening_sock);
|
closesocket((*server)->listening_sock);
|
||||||
closesocket((*server)->ctl[0]);
|
closesocket((*server)->ctl[0]);
|
||||||
closesocket((*server)->ctl[1]);
|
closesocket((*server)->ctl[1]);
|
||||||
LINKED_LIST_FOREACH(&(*server)->active_connections, lp, tmp) {
|
LINKED_LIST_FOREACH(&(*server)->active_connections, lp, tmp) {
|
||||||
conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link);
|
free(LINKED_LIST_ENTRY(lp, struct connection, link));
|
||||||
LINKED_LIST_REMOVE(&conn->link);
|
}
|
||||||
free(conn);
|
LINKED_LIST_FOREACH(&(*server)->uri_handlers, lp, tmp) {
|
||||||
|
free(LINKED_LIST_ENTRY(lp, struct uri_handler, link));
|
||||||
}
|
}
|
||||||
free(*server);
|
free(*server);
|
||||||
*server = NULL;
|
*server = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mg_server *mg_create_server(const char *opts[], mg_event_handler_t func,
|
// Apply function to all active connections. Return number of active
|
||||||
void *user_data) {
|
// connections. Function could be NULL.
|
||||||
|
static int mg_iterate_over_connections(struct mg_server *server,
|
||||||
|
void (*func)(struct mg_connection *, void *),
|
||||||
|
void *param) {
|
||||||
|
struct linked_list_link *lp, *tmp;
|
||||||
|
struct connection *conn;
|
||||||
|
int num_connections = 0;
|
||||||
|
|
||||||
|
LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) {
|
||||||
|
num_connections++;
|
||||||
|
conn = LINKED_LIST_ENTRY(lp, struct connection, link);
|
||||||
|
if (conn->endpoint_type == EP_USER && func != NULL) {
|
||||||
|
func((struct mg_connection *) conn, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_add_uri_handler(struct mg_server *server, const char *uri,
|
||||||
|
mg_uri_handler_t handler) {
|
||||||
|
struct uri_handler *p = (struct uri_handler *) malloc(sizeof(*p));
|
||||||
|
if (p != NULL) {
|
||||||
|
LINKED_LIST_ADD_TO_FRONT(&server->uri_handlers, &p->link);
|
||||||
|
p->uri = mg_strdup(uri);
|
||||||
|
p->handler = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *mg_set_option(struct mg_server *server, const char *name,
|
||||||
|
const char *value) {
|
||||||
|
int ind = get_option_index(name);
|
||||||
|
const char *error_msg = NULL;
|
||||||
|
|
||||||
|
if (ind < 0) {
|
||||||
|
error_msg = "No such option";
|
||||||
|
} else {
|
||||||
|
if (server->config_options[ind] != NULL) {
|
||||||
|
free(server->config_options[ind]);
|
||||||
|
}
|
||||||
|
server->config_options[ind] = mg_strdup(value);
|
||||||
|
|
||||||
|
if (ind == LISTENING_PORT) {
|
||||||
|
if (server->listening_sock != INVALID_SOCKET) {
|
||||||
|
closesocket(server->listening_sock);
|
||||||
|
}
|
||||||
|
parse_port_string(server->config_options[LISTENING_PORT], &server->lsa);
|
||||||
|
server->listening_sock = open_listening_socket(&server->lsa);
|
||||||
|
if (server->listening_sock == INVALID_SOCKET) {
|
||||||
|
error_msg = "Cannot bind to port";
|
||||||
|
} else {
|
||||||
|
set_non_blocking_mode(server->listening_sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_server *mg_create_server(void *server_data) {
|
||||||
struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
|
struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
|
||||||
const char *name, *value;
|
const char *value;
|
||||||
char error_msg[100] = {'\0'};
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -1281,11 +1365,13 @@ struct mg_server *mg_create_server(const char *opts[], mg_event_handler_t func,
|
|||||||
WSAStartup(MAKEWORD(2, 2), &data);
|
WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
server->event_handler = func;
|
|
||||||
server->user_data = user_data;
|
|
||||||
LINKED_LIST_INIT(&server->active_connections);
|
LINKED_LIST_INIT(&server->active_connections);
|
||||||
|
LINKED_LIST_INIT(&server->uri_handlers);
|
||||||
mg_socketpair(server->ctl);
|
mg_socketpair(server->ctl);
|
||||||
|
server->server_data = server_data;
|
||||||
|
server->listening_sock = INVALID_SOCKET;
|
||||||
|
|
||||||
|
#if 0
|
||||||
while (opts != NULL && (name = *opts++) != NULL) {
|
while (opts != NULL && (name = *opts++) != NULL) {
|
||||||
if ((i = get_option_index(name)) == -1) {
|
if ((i = get_option_index(name)) == -1) {
|
||||||
snprintf(error_msg, sizeof(error_msg), "Invalid option: [%s]", name);
|
snprintf(error_msg, sizeof(error_msg), "Invalid option: [%s]", name);
|
||||||
@@ -1299,43 +1385,56 @@ struct mg_server *mg_create_server(const char *opts[], mg_event_handler_t func,
|
|||||||
DBG(("[%s] -> [%s]", name, value));
|
DBG(("[%s] -> [%s]", name, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set default values
|
// Set default options values
|
||||||
for (i = 0; static_config_options[i * 2] != NULL; i++) {
|
for (i = 0; static_config_options[i * 2] != NULL; i++) {
|
||||||
value = static_config_options[i * 2 + 1];
|
value = static_config_options[i * 2 + 1];
|
||||||
if (server->config_options[i] == NULL && value != NULL) {
|
if (server->config_options[i] == NULL && value != NULL) {
|
||||||
server->config_options[i] = mg_strdup(value);
|
server->config_options[i] = mg_strdup(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parse_port_string(server->config_options[LISTENING_PORT], &server->lsa);
|
|
||||||
server->listening_sock = open_listening_socket(&server->lsa);
|
|
||||||
set_non_blocking_mode(server->listening_sock);
|
|
||||||
|
|
||||||
if (error_msg[0] != '\0') {
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
}
|
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of library, start of the application code
|
// End of library, start of the application code
|
||||||
|
|
||||||
static int event_handler(struct mg_event *ev) {
|
static void iterate_callback(struct mg_connection *c, void *param) {
|
||||||
if (ev->type == MG_REQUEST_BEGIN &&
|
mg_write(c, "%d", * (int *) param);
|
||||||
!strcmp(ev->request_info->uri, "/x")) {
|
|
||||||
mg_printf(ev->conn, "%s", "HTTP/1.0 200 OK\r\n\r\n:-)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
static void *timer_thread(void *param) {
|
||||||
const char *options[] = {"document_root", ".", "listening_port", "8080", 0};
|
struct mg_server *server = (struct mg_server *) param;
|
||||||
struct mg_server *server = mg_create_server(options, event_handler, NULL);
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
sleep(1);
|
||||||
|
mg_iterate_over_connections(server, iterate_callback, &i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int websocket_handler(struct mg_connection *conn) {
|
||||||
|
mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n:-)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server = mg_create_server(NULL);
|
||||||
|
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
mg_set_option(server, "document_root", ".");
|
||||||
|
mg_add_uri_handler(server, "/ws", websocket_handler);
|
||||||
|
mg_start_thread(timer_thread, server);
|
||||||
|
|
||||||
|
printf("Started on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
mg_poll_server(server, 1000);
|
mg_poll_server(server, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
||||||
|
// Copyright (c) 2013 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// This library is dual-licensed: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2 as
|
||||||
|
// published by the Free Software Foundation. For the terms of this
|
||||||
|
// license, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// You are free to use this library under the terms of the GNU General
|
||||||
|
// Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// Alternatively, you can license this library under a commercial
|
||||||
|
// license, as set out in <http://cesanta.com/products.html>.
|
||||||
|
//
|
||||||
|
// NOTE: Detailed API documentation is at http://cesanta.com/docs.html
|
||||||
|
|
||||||
|
#ifndef MONGOOSE_HEADER_INCLUDED
|
||||||
|
#define MONGOOSE_HEADER_INCLUDED
|
||||||
|
|
||||||
|
#include <stdio.h> // required for FILE
|
||||||
|
#include <stddef.h> // required for size_t
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// This structure contains information about HTTP request.
|
||||||
|
struct mg_connection {
|
||||||
|
const char *request_method; // "GET", "POST", etc
|
||||||
|
const char *uri; // URL-decoded URI
|
||||||
|
const char *http_version; // E.g. "1.0", "1.1"
|
||||||
|
const char *query_string; // URL part after '?', not including '?', or NULL
|
||||||
|
long remote_ip; // Client's IP address
|
||||||
|
int remote_port; // Client's port
|
||||||
|
int is_ssl; // 1 if SSL-ed, 0 if not
|
||||||
|
int num_headers; // Number of HTTP headers
|
||||||
|
struct mg_header {
|
||||||
|
const char *name; // HTTP header name
|
||||||
|
const char *value; // HTTP header value
|
||||||
|
} http_headers[64]; // Maximum 64 headers
|
||||||
|
|
||||||
|
void *server_param; // Parameter passed to mg_add_uri_handler()
|
||||||
|
void *connection_param; // Placeholder for connection-specific data
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_server; // Opaque structure describing server instance
|
||||||
|
typedef int (*mg_uri_handler_t)(struct mg_connection *);
|
||||||
|
typedef int (*mg_error_handler_t)(struct mg_connection *, int http_error_code);
|
||||||
|
|
||||||
|
// Server management functions
|
||||||
|
struct mg_server *mg_create_server(void *server_param);
|
||||||
|
void mg_destroy_server(struct mg_server **);
|
||||||
|
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
|
||||||
|
void mg_poll_server(struct mg_server *, int milliseconds);
|
||||||
|
void mg_add_uri_handler(struct mg_server *, const char *uri, mg_uri_handler_t);
|
||||||
|
void mg_set_error_handler(struct mg_server *, mg_error_handler_t);
|
||||||
|
void mg_set_log_handler(struct mg_server*, int (*)(struct mg_connection*, int));
|
||||||
|
const char **mg_get_valid_option_names(void);
|
||||||
|
const char *mg_get_option(const struct mg_server *server, const char *name);
|
||||||
|
|
||||||
|
// Websocket functions
|
||||||
|
void mg_websocket_handshake(struct mg_connection *);
|
||||||
|
int mg_websocket_read(struct mg_connection *, int *bits, char **data);
|
||||||
|
int mg_websocket_write(struct mg_connection* conn, int opcode,
|
||||||
|
const char *data, size_t data_len);
|
||||||
|
|
||||||
|
// Connection management functions
|
||||||
|
int mg_write(struct mg_connection *, const void *buf, int len);
|
||||||
|
int mg_printf(struct mg_connection *, const char *fmt, ...);
|
||||||
|
void mg_send_file(struct mg_connection *, const char *path);
|
||||||
|
int mg_read(struct mg_connection *, void *buf, int len);
|
||||||
|
const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||||
|
int mg_get_var(const char *data, size_t data_len,
|
||||||
|
const char *var_name, char *dst, size_t dst_len);
|
||||||
|
int mg_get_cookie(const char *cookie, const char *var_name,
|
||||||
|
char *buf, size_t buf_len);
|
||||||
|
const char *mg_get_mime_type(const char *file_name);
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
int mg_start_thread(void *(*func)(void *), void *param);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // MONGOOSE_HEADER_INCLUDED
|
||||||
Reference in new issue
Block a user