Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
8a65611a
Commit
8a65611a
authored
Dec 02, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Using core.h and modified API
parent
6c8a0aa7
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
279 additions
and
91 deletions
+279
-91
core.c
build/src/core.c
+190
-91
core.h
build/src/core.h
+89
-0
No files found.
build/src/core.c
View file @
8a65611a
...
...
@@ -69,6 +69,7 @@ typedef CRITICAL_SECTION mutex_t;
#define mutex_lock(x) EnterCriticalSection(x)
#define mutex_unlock(x) LeaveCriticalSection(x)
#define S_ISDIR(x) ((x) & _S_IFDIR)
#define sleep(x) Sleep((x) * 1000)
#ifndef va_copy
#define va_copy(x,y) x = y
#endif // MINGW #defines va_copy
...
...
@@ -93,7 +94,8 @@ typedef pthread_mutex_t mutex_t;
#define INT64_FMT PRId64
#endif
#include "mongoose.h"
//#include "mongoose.h"
#include "core.h"
struct
linked_list_link
{
struct
linked_list_link
*
prev
,
*
next
;
};
#define LINKED_LIST_INIT(N) ((N)->next = (N)->prev = (N))
...
...
@@ -139,6 +141,12 @@ struct vec {
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.
enum
{
ACCESS_CONTROL_LIST
,
ACCESS_LOG_FILE
,
AUTH_DOMAIN
,
CGI_INTERPRETER
,
...
...
@@ -152,9 +160,9 @@ struct mg_server {
sock_t
listening_sock
;
union
socket_address
lsa
;
// Listening socket address
struct
linked_list_link
active_connections
;
struct
linked_list_link
uri_handlers
;
char
*
config_options
[
NUM_OPTIONS
];
mg_event_handler_t
event_handler
;
void
*
user_data
;
void
*
server_data
;
sock_t
ctl
[
2
];
// Control socketpair. Used to wake up from select() call
};
...
...
@@ -170,13 +178,13 @@ union endpoint {
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
};
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
mg_server
*
server
;
struct
mg_event
event
;
// NOTE(lsm): this has conn_data attribute
sock_t
client_sock
;
// Connected client
union
socket_address
csa
;
// Client's socket address
struct
iobuf
local_iobuf
;
...
...
@@ -184,7 +192,6 @@ struct mg_connection {
union
endpoint
endpoint
;
enum
endpoint_type
endpoint_type
;
time_t
expire_time
;
struct
mg_request_info
request_info
;
char
*
path_info
;
int
request_len
;
int
flags
;
...
...
@@ -206,7 +213,7 @@ static const char *static_config_options[] = {
"hide_files_patterns"
,
NULL
,
"idle_timeout_ms"
,
"30000"
,
"index_files"
,
"index.html,index.htm,index.cgi,index.shtml,index.php,index.lp"
,
"listening_port"
,
"8080"
,
"listening_port"
,
NULL
,
"num_threads"
,
"50"
,
"put_delete_auth_file"
,
NULL
,
"run_as_user"
,
NULL
,
...
...
@@ -287,13 +294,13 @@ static int get_option_index(const char *name) {
return
-
1
;
}
const
char
*
mg_get_option
2
(
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
);
return
i
==
-
1
?
NULL
:
srv
->
config_options
[
i
]
==
NULL
?
""
:
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
return
(
long
)
_beginthread
((
void
(
__cdecl
*
)(
void
*
))
f
,
0
,
p
)
==
-
1L
?
-
1
:
0
;
#else
...
...
@@ -316,6 +323,7 @@ int mg_start_thread(mg_thread_func_t f, void *p) {
#endif
}
#if 0
static int call_user(int event_type, struct mg_connection *conn, void *p) {
if (conn != NULL && conn->server != NULL) {
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 :
conn->server->event_handler(&conn->event);
}
#endif
static
void
set_close_on_exec
(
int
fd
)
{
#ifdef _WIN32
...
...
@@ -547,11 +556,11 @@ static int check_acl(const char *acl, uint32_t remote_ip) {
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
;
socklen_t
len
=
sizeof
(
sa
);
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 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
],
ntohl
(
*
(
uint32_t
*
)
&
sa
.
sin
.
sin_addr
)))
{
closesocket
(
sock
);
}
else
if
((
conn
=
(
struct
mg_
connection
*
)
}
else
if
((
conn
=
(
struct
connection
*
)
calloc
(
1
,
sizeof
(
*
conn
)
+
MAX_REQUEST_SIZE
))
==
NULL
)
{
closesocket
(
sock
);
}
else
{
...
...
@@ -584,7 +593,7 @@ static struct mg_connection *accept_new_connection(struct mg_server *server) {
return
conn
;
}
static
void
close_conn
(
struct
mg_
connection
*
conn
)
{
static
void
close_conn
(
struct
connection
*
conn
)
{
DBG
((
"closing %p"
,
conn
));
LINKED_LIST_REMOVE
(
&
conn
->
link
);
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
// 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
;
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"
);
}
// 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
// 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
);
if
(
request_len
>
0
)
{
// Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
ri
->
re
mote_user
=
ri
->
re
quest_method
=
ri
->
uri
=
ri
->
http_version
=
NULL
;
ri
->
request_method
=
ri
->
uri
=
ri
->
http_version
=
NULL
;
ri
->
num_headers
=
0
;
buf
[
request_len
-
1
]
=
'\0'
;
// 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.
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
;
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
;
}
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
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
)
{
struct
vec
a
,
b
;
const
char
*
rewrites
=
conn
->
server
->
config_options
[
URL_REWRITES
],
*
root
=
conn
->
server
->
config_options
[
DOCUMENT_ROOT
],
*
cgi_pat
=
conn
->
server
->
config_options
[
CGI_PATTERN
],
*
uri
=
conn
->
request_info
.
uri
;
*
uri
=
conn
->
mg_conn
.
uri
;
char
*
p
;
int
match_len
;
...
...
@@ -896,7 +900,8 @@ static int vspool(struct iobuf *io, const char *fmt, va_list ap) {
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
;
int
ret
;
va_start
(
ap
,
fmt
);
...
...
@@ -908,7 +913,8 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
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
;
mutex_lock
(
&
conn
->
mutex
);
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
);
}
static
void
write_to_client
(
struct
mg_
connection
*
conn
)
{
static
void
write_to_client
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
remote_iobuf
;
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
;
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
);
}
...
...
@@ -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
);
}
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
)
{
char
date
[
64
],
lm
[
64
],
etag
[
64
],
range
[
64
];
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
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
&&
r1
>=
0
&&
r2
>=
0
)
{
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
);
construct_etag
(
etag
,
sizeof
(
etag
),
st
);
mg_printf
(
conn
,
mg_printf
(
&
conn
->
mg_
conn
,
"HTTP/1.1 %d %s
\r\n
"
"Date: %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
,
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
);
}
}
static
void
open_local_endpoint
(
struct
mg_connection
*
conn
)
{
struct
mg_request_info
*
ri
=
&
conn
->
request_info
;
static
struct
uri_handler
*
find_uri_handler
(
struct
mg_server
*
server
,
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'
};
struct
stat
st
;
int
uri_len
,
exists
=
0
,
is_directory
=
0
;
struct
uri_handler
*
uh
;
if
((
conn
->
request_info
.
query_string
=
strchr
(
ri
->
uri
,
'?'
))
!=
NULL
)
{
*
((
char
*
)
conn
->
request_info
.
query_string
++
)
=
'\0'
;
if
((
conn
->
mg_conn
.
query_string
=
strchr
(
conn
->
mg_conn
.
uri
,
'?'
))
!=
NULL
)
{
*
((
char
*
)
conn
->
mg_conn
.
query_string
++
)
=
'\0'
;
}
uri_len
=
(
int
)
strlen
(
ri
->
uri
);
mg_url_decode
(
ri
->
uri
,
uri_len
,
(
char
*
)
ri
->
uri
,
uri_len
+
1
,
0
);
remove_double_dots_and_double_slashes
((
char
*
)
ri
->
uri
);
uri_len
=
(
int
)
strlen
(
conn
->
mg_conn
.
uri
);
mg_url_decode
(
conn
->
mg_conn
.
uri
,
uri_len
,
(
char
*
)
conn
->
mg_conn
.
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) {
conn->flags |= CONN_SPOOL_DONE;
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
);
is_directory
=
S_ISDIR
(
st
.
st_mode
);
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
;
}
else
if
(
is_directory
&&
ri
->
uri
[
uri_len
-
1
]
!=
'/'
)
{
mg_printf
(
conn
,
"HTTP/1.1 301 Moved Permanently
\r\n
"
"Location: %s/
\r\n\r\n
"
,
ri
->
uri
);
}
else
if
(
is_directory
&&
conn
->
mg_conn
.
uri
[
uri_len
-
1
]
!=
'/'
)
{
mg_printf
(
&
conn
->
mg_
conn
,
"HTTP/1.1 301 Moved Permanently
\r\n
"
"Location: %s/
\r\n\r\n
"
,
conn
->
mg_conn
.
uri
);
conn
->
flags
|=
CONN_SPOOL_DONE
;
}
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
;
}
else
if
((
conn
->
endpoint
.
fd
=
open
(
path
,
O_RDONLY
))
!=
-
1
)
{
open_file_endpoint
(
conn
,
path
,
&
st
);
}
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
;
}
}
...
...
@@ -1092,13 +1119,12 @@ static int io_space(const struct iobuf *io) {
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
;
//DBG(("parse_http_message(%d [%.*s])", io->len, io->len, io->buf));
if
(
conn
->
request_len
==
0
)
{
conn
->
request_len
=
parse_http_message
(
io
->
buf
,
io
->
len
,
&
conn
->
request_info
);
conn
->
request_len
=
parse_http_message
(
io
->
buf
,
io
->
len
,
&
conn
->
mg_conn
);
}
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
;
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
)
{
const
char
*
method
=
conn
->
request_info
.
request_method
;
const
char
*
http_version
=
conn
->
request_info
.
http_version
;
const
char
*
header
=
mg_get_header
(
conn
,
"Connection"
);
static
int
should_keep_alive
(
const
struct
connection
*
conn
)
{
const
char
*
method
=
conn
->
mg_conn
.
request_method
;
const
char
*
http_version
=
conn
->
mg_conn
.
http_version
;
const
char
*
header
=
mg_get_header
(
&
conn
->
mg_
conn
,
"Connection"
);
return
method
!=
NULL
&&
!
strcmp
(
method
,
"GET"
)
&&
((
header
!=
NULL
&&
!
strcmp
(
header
,
"keep-alive"
))
||
(
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
;
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
switch
(
conn
->
endpoint_type
)
{
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
;
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
mg_
connection
*
conn
;
struct
connection
*
conn
;
struct
timeval
tv
;
fd_set
read_set
,
write_set
;
sock_t
max_fd
=
-
1
;
time_t
current_time
=
time
(
NULL
),
expire_time
=
current_time
+
atoi
(
server
->
config_options
[
IDLE_TIMEOUT_MS
])
/
1000
;
if
(
server
->
listening_sock
==
INVALID_SOCKET
)
return
;
FD_ZERO
(
&
read_set
);
FD_ZERO
(
&
write_set
);
add_to_set
(
server
->
listening_sock
,
&
read_set
,
&
max_fd
);
add_to_set
(
server
->
ctl
[
0
],
&
read_set
,
&
max_fd
);
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
);
if
(
conn
->
endpoint_type
==
EP_FILE
)
{
transfer_file_data
(
conn
);
...
...
@@ -1230,7 +1256,7 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) {
// Read/write from clients
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
))
{
conn
->
expire_time
=
expire_time
;
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
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
)
{
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
)
{
struct
linked_list_link
*
lp
,
*
tmp
;
struct
mg_connection
*
conn
;
if
(
server
!=
NULL
&&
*
server
!=
NULL
)
{
closesocket
((
*
server
)
->
listening_sock
);
closesocket
((
*
server
)
->
ctl
[
0
]);
closesocket
((
*
server
)
->
ctl
[
1
]);
LINKED_LIST_FOREACH
(
&
(
*
server
)
->
active_connections
,
lp
,
tmp
)
{
conn
=
LINKED_LIST_ENTRY
(
lp
,
struct
mg_connection
,
link
);
LINKED_LIST_REMOVE
(
&
conn
->
link
);
free
(
conn
);
free
(
LINKED_LIST_ENTRY
(
lp
,
struct
connection
,
link
));
}
LINKED_LIST_FOREACH
(
&
(
*
server
)
->
uri_handlers
,
lp
,
tmp
)
{
free
(
LINKED_LIST_ENTRY
(
lp
,
struct
uri_handler
,
link
));
}
free
(
*
server
);
*
server
=
NULL
;
}
}
struct
mg_server
*
mg_create_server
(
const
char
*
opts
[],
mg_event_handler_t
func
,
void
*
user_data
)
{
// Apply function to all active connections. Return number of active
// 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
));
const
char
*
name
,
*
value
;
char
error_msg
[
100
]
=
{
'\0'
};
const
char
*
value
;
int
i
;
#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
);
#endif
server
->
event_handler
=
func
;
server
->
user_data
=
user_data
;
LINKED_LIST_INIT
(
&
server
->
active_connections
);
LINKED_LIST_INIT
(
&
server
->
uri_handlers
);
mg_socketpair
(
server
->
ctl
);
server
->
server_data
=
server_data
;
server
->
listening_sock
=
INVALID_SOCKET
;
#if 0
while (opts != NULL && (name = *opts++) != NULL) {
if ((i = get_option_index(name)) == -1) {
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));
}
}
#endif
// Set default values
// Set default
options
values
for
(
i
=
0
;
static_config_options
[
i
*
2
]
!=
NULL
;
i
++
)
{
value
=
static_config_options
[
i
*
2
+
1
];
if
(
server
->
config_options
[
i
]
==
NULL
&&
value
!=
NULL
)
{
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
;
}
// End of library, start of the application code
static
int
event_handler
(
struct
mg_event
*
ev
)
{
if
(
ev
->
type
==
MG_REQUEST_BEGIN
&&
!
strcmp
(
ev
->
request_info
->
uri
,
"/x"
))
{
mg_printf
(
ev
->
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n\r\n
:-)
\n
"
);
return
1
;
static
void
iterate_callback
(
struct
mg_connection
*
c
,
void
*
param
)
{
mg_write
(
c
,
"%d"
,
*
(
int
*
)
param
);
}
static
void
*
timer_thread
(
void
*
param
)
{
struct
mg_server
*
server
=
(
struct
mg_server
*
)
param
;
int
i
;
for
(
i
=
0
;
i
<
1000
;
i
++
)
{
sleep
(
1
);
mg_iterate_over_connections
(
server
,
iterate_callback
,
&
i
);
}
return
0
;
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
)
{
const
char
*
options
[]
=
{
"document_root"
,
"."
,
"listening_port"
,
"8080"
,
0
};
struct
mg_server
*
server
=
mg_create_server
(
options
,
event_handler
,
NULL
);
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
(;;)
{
mg_poll_server
(
server
,
1000
);
}
mg_destroy_server
(
&
server
);
return
0
;
}
build/src/core.h
0 → 100644
View file @
8a65611a
// 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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment