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
03e73782
Commit
03e73782
authored
Dec 05, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Made URI handler work
parent
95d88814
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
207 additions
and
233 deletions
+207
-233
core.c
build/src/core.c
+197
-227
core.h
build/src/core.h
+10
-6
No files found.
build/src/core.c
View file @
03e73782
...
@@ -66,6 +66,7 @@ typedef struct _stati64 file_stat_t;
...
@@ -66,6 +66,7 @@ typedef struct _stati64 file_stat_t;
#define S_ISDIR(x) ((x) & _S_IFDIR)
#define S_ISDIR(x) ((x) & _S_IFDIR)
#define sleep(x) Sleep((x) * 1000)
#define sleep(x) Sleep((x) * 1000)
#define stat(x, y) _stati64((x), (y))
#define stat(x, y) _stati64((x), (y))
#define to64(x) _atoi64(x)
#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
...
@@ -89,6 +90,7 @@ typedef struct stat file_stat_t;
...
@@ -89,6 +90,7 @@ typedef struct stat file_stat_t;
#define mutex_unlock(x) pthread_mutex_unlock(x)
#define mutex_unlock(x) pthread_mutex_unlock(x)
#define INVALID_SOCKET ((sock_t) -1)
#define INVALID_SOCKET ((sock_t) -1)
#define INT64_FMT PRId64
#define INT64_FMT PRId64
#define to64(x) strtoll(x, NULL, 10)
#endif
#endif
//#include "mongoose.h"
//#include "mongoose.h"
...
@@ -120,7 +122,7 @@ struct linked_list_link { struct linked_list_link *prev, *next; };
...
@@ -120,7 +122,7 @@ struct linked_list_link { struct linked_list_link *prev, *next; };
#endif
#endif
#ifdef ENABLE_DBG
#ifdef ENABLE_DBG
#define DBG(x) do { printf("%s::%s
()
", __FILE__, __func__); \
#define DBG(x) do { printf("%s::%s ", __FILE__, __func__); \
printf x; putchar('\n'); fflush(stdout); } while(0)
printf x; putchar('\n'); fflush(stdout); } while(0)
#else
#else
#define DBG(x)
#define DBG(x)
...
@@ -197,6 +199,7 @@ struct iobuf {
...
@@ -197,6 +199,7 @@ struct iobuf {
union
endpoint
{
union
endpoint
{
int
fd
;
// Opened regular local file
int
fd
;
// Opened regular local file
void
*
ssl
;
// SSL descriptor
void
*
ssl
;
// SSL descriptor
struct
uri_handler
*
uh
;
// URI handler user function
};
};
enum
endpoint_type
{
EP_NONE
,
EP_FILE
,
EP_USER
};
enum
endpoint_type
{
EP_NONE
,
EP_FILE
,
EP_USER
};
...
@@ -207,16 +210,15 @@ struct connection {
...
@@ -207,16 +210,15 @@ struct connection {
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
;
sock_t
client_sock
;
// Connected client
sock_t
client_sock
;
// Connected client
union
socket_address
csa
;
// Client's socket address
struct
iobuf
local_iobuf
;
struct
iobuf
local_iobuf
;
struct
iobuf
remote_iobuf
;
struct
iobuf
remote_iobuf
;
union
endpoint
endpoint
;
union
endpoint
endpoint
;
enum
endpoint_type
endpoint_type
;
enum
endpoint_type
endpoint_type
;
time_t
expire_time
;
time_t
expire_time
;
char
*
path_info
;
char
*
path_info
;
int
request_len
;
char
*
request
;
int
flags
;
int
request_len
;
// Request length, including last \r\n after last header
int
status_code
;
int
flags
;
// CONN_* flags: CONN_CLOSE, CONN_SPOOL_DONE, etc
mutex_t
mutex
;
// Guards concurrent mg_write() calls
mutex_t
mutex
;
// Guards concurrent mg_write() calls
};
};
...
@@ -326,20 +328,6 @@ int mg_start_thread(void *(*f)(void *), void *p) {
...
@@ -326,20 +328,6 @@ int mg_start_thread(void *(*f)(void *), void *p) {
#endif
#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;
conn->event.type = event_type;
conn->event.event_param = p;
conn->event.request_info = &conn->request_info;
conn->event.conn = conn;
}
return !conn || !conn->server || !conn->server->event_handler ? 0 :
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
(
void
)
SetHandleInformation
((
HANDLE
)
fd
,
HANDLE_FLAG_INHERIT
,
0
);
(
void
)
SetHandleInformation
((
HANDLE
)
fd
,
HANDLE_FLAG_INHERIT
,
0
);
...
@@ -565,29 +553,19 @@ static struct connection *accept_new_connection(struct mg_server *server) {
...
@@ -565,29 +553,19 @@ static struct connection *accept_new_connection(struct mg_server *server) {
sock_t
sock
=
INVALID_SOCKET
;
sock_t
sock
=
INVALID_SOCKET
;
struct
connection
*
conn
=
NULL
;
struct
connection
*
conn
=
NULL
;
// NOTE(lsm): on Windows, sock is always > FD_SETSIZE
if
((
sock
=
accept
(
server
->
listening_sock
,
&
sa
.
sa
,
&
len
))
==
INVALID_SOCKET
)
{
if
((
sock
=
accept
(
server
->
listening_sock
,
&
sa
.
sa
,
&
len
))
==
INVALID_SOCKET
)
{
#if 0
} else if (sock >= FD_SETSIZE) {
DBG((">fd_setsize"));
closesocket(sock);
#endif
}
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
)))
{
// NOTE(lsm): check_acl doesn't work for IPv6
closesocket
(
sock
);
closesocket
(
sock
);
}
else
if
((
conn
=
(
struct
connection
*
)
}
else
if
((
conn
=
(
struct
connection
*
)
calloc
(
1
,
sizeof
(
*
conn
)))
==
NULL
)
{
calloc
(
1
,
sizeof
(
*
conn
)
+
MAX_REQUEST_SIZE
))
==
NULL
)
{
closesocket
(
sock
);
closesocket
(
sock
);
}
else
{
}
else
{
// Put so socket structure into the queue
set_close_on_exec
(
sock
);
set_close_on_exec
(
sock
);
set_non_blocking_mode
(
sock
);
set_non_blocking_mode
(
sock
);
conn
->
server
=
server
;
conn
->
server
=
server
;
conn
->
client_sock
=
sock
;
conn
->
client_sock
=
sock
;
conn
->
csa
=
sa
;
conn
->
local_iobuf
.
buf
=
(
char
*
)
conn
+
sizeof
(
*
conn
);
conn
->
local_iobuf
.
size
=
MAX_REQUEST_SIZE
;
conn
->
remote_iobuf
.
buf
=
(
char
*
)
calloc
(
1
,
IOBUF_SIZE
);
conn
->
remote_iobuf
.
size
=
IOBUF_SIZE
;
mutex_init
(
&
conn
->
mutex
);
mutex_init
(
&
conn
->
mutex
);
LINKED_LIST_ADD_TO_FRONT
(
&
server
->
active_connections
,
&
conn
->
link
);
LINKED_LIST_ADD_TO_FRONT
(
&
server
->
active_connections
,
&
conn
->
link
);
DBG
((
"added conn %p"
,
conn
));
DBG
((
"added conn %p"
,
conn
));
...
@@ -600,7 +578,9 @@ static void close_conn(struct connection *conn) {
...
@@ -600,7 +578,9 @@ 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
);
free
(
conn
->
remote_iobuf
.
buf
);
free
(
conn
->
request
);
// It's OK to free(NULL)
free
(
conn
->
remote_iobuf
.
buf
);
// It's OK to free(NULL)
free
(
conn
->
local_iobuf
.
buf
);
// It's OK to free(NULL)
mutex_destroy
(
&
conn
->
mutex
);
mutex_destroy
(
&
conn
->
mutex
);
free
(
conn
);
free
(
conn
);
}
}
...
@@ -648,6 +628,50 @@ static char *skip(char **buf, const char *delimiters) {
...
@@ -648,6 +628,50 @@ static char *skip(char **buf, const char *delimiters) {
return
begin_word
;
return
begin_word
;
}
}
// Protect against directory disclosure attack by removing '..',
// excessive '/' and '\' characters
static
void
remove_double_dots_and_double_slashes
(
char
*
s
)
{
char
*
p
=
s
;
while
(
*
s
!=
'\0'
)
{
*
p
++
=
*
s
++
;
if
(
s
[
-
1
]
==
'/'
||
s
[
-
1
]
==
'\\'
)
{
// Skip all following slashes, backslashes and double-dots
while
(
s
[
0
]
!=
'\0'
)
{
if
(
s
[
0
]
==
'/'
||
s
[
0
]
==
'\\'
)
{
s
++
;
}
else
if
(
s
[
0
]
==
'.'
&&
s
[
1
]
==
'.'
)
{
s
+=
2
;
}
else
{
break
;
}
}
}
}
*
p
=
'\0'
;
}
int
mg_url_decode
(
const
char
*
src
,
int
src_len
,
char
*
dst
,
int
dst_len
,
int
is_form_url_encoded
)
{
int
i
,
j
,
a
,
b
;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
for
(
i
=
j
=
0
;
i
<
src_len
&&
j
<
dst_len
-
1
;
i
++
,
j
++
)
{
if
(
src
[
i
]
==
'%'
&&
i
<
src_len
-
2
&&
isxdigit
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
1
))
&&
isxdigit
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
2
)))
{
a
=
tolower
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
1
));
b
=
tolower
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
2
));
dst
[
j
]
=
(
char
)
((
HEXTOI
(
a
)
<<
4
)
|
HEXTOI
(
b
));
i
+=
2
;
}
else
if
(
is_form_url_encoded
&&
src
[
i
]
==
'+'
)
{
dst
[
j
]
=
' '
;
}
else
{
dst
[
j
]
=
src
[
i
];
}
}
dst
[
j
]
=
'\0'
;
// Null-terminate the destination
return
i
>=
src_len
?
j
:
-
1
;
}
// 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_connection
*
ri
)
{
static
void
parse_http_headers
(
char
**
buf
,
struct
mg_connection
*
ri
)
{
...
@@ -674,12 +698,12 @@ static int is_valid_http_method(const char *method) {
...
@@ -674,12 +698,12 @@ static int is_valid_http_method(const char *method) {
// 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_connection
*
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
,
n
;
if
(
request_len
>
0
)
{
// Reset attributes. DO NOT TOUCH is_ssl,
remote_ip, remote_port
// Reset attributes. DO NOT TOUCH
remote_ip, remote_port
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
[
len
-
1
]
=
'\0'
;
// RFC says that all initial whitespaces should be ingored
// RFC says that all initial whitespaces should be ingored
while
(
*
buf
!=
'\0'
&&
isspace
(
*
(
unsigned
char
*
)
buf
))
{
while
(
*
buf
!=
'\0'
&&
isspace
(
*
(
unsigned
char
*
)
buf
))
{
...
@@ -694,15 +718,22 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
...
@@ -694,15 +718,22 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
is_request
=
is_valid_http_method
(
ri
->
request_method
);
is_request
=
is_valid_http_method
(
ri
->
request_method
);
if
((
is_request
&&
memcmp
(
ri
->
http_version
,
"HTTP/"
,
5
)
!=
0
)
||
if
((
is_request
&&
memcmp
(
ri
->
http_version
,
"HTTP/"
,
5
)
!=
0
)
||
(
!
is_request
&&
memcmp
(
ri
->
request_method
,
"HTTP/"
,
5
)
!=
0
))
{
(
!
is_request
&&
memcmp
(
ri
->
request_method
,
"HTTP/"
,
5
)
!=
0
))
{
request_
len
=
-
1
;
len
=
-
1
;
}
else
{
}
else
{
if
(
is_request
)
{
if
(
is_request
)
{
ri
->
http_version
+=
5
;
ri
->
http_version
+=
5
;
}
}
parse_http_headers
(
&
buf
,
ri
);
parse_http_headers
(
&
buf
,
ri
);
if
((
ri
->
query_string
=
strchr
(
ri
->
uri
,
'?'
))
!=
NULL
)
{
*
(
char
*
)
ri
->
query_string
++
=
'\0'
;
}
}
n
=
(
int
)
strlen
(
ri
->
uri
);
mg_url_decode
(
ri
->
uri
,
n
,
(
char
*
)
ri
->
uri
,
n
+
1
,
0
);
remove_double_dots_and_double_slashes
((
char
*
)
ri
->
uri
);
}
}
return
request_len
;
return
len
;
}
}
static
int
lowercase
(
const
char
*
s
)
{
static
int
lowercase
(
const
char
*
s
)
{
...
@@ -770,50 +801,6 @@ static int match_prefix(const char *pattern, int pattern_len, const char *str) {
...
@@ -770,50 +801,6 @@ static int match_prefix(const char *pattern, int pattern_len, const char *str) {
return
j
;
return
j
;
}
}
// Protect against directory disclosure attack by removing '..',
// excessive '/' and '\' characters
static
void
remove_double_dots_and_double_slashes
(
char
*
s
)
{
char
*
p
=
s
;
while
(
*
s
!=
'\0'
)
{
*
p
++
=
*
s
++
;
if
(
s
[
-
1
]
==
'/'
||
s
[
-
1
]
==
'\\'
)
{
// Skip all following slashes, backslashes and double-dots
while
(
s
[
0
]
!=
'\0'
)
{
if
(
s
[
0
]
==
'/'
||
s
[
0
]
==
'\\'
)
{
s
++
;
}
else
if
(
s
[
0
]
==
'.'
&&
s
[
1
]
==
'.'
)
{
s
+=
2
;
}
else
{
break
;
}
}
}
}
*
p
=
'\0'
;
}
int
mg_url_decode
(
const
char
*
src
,
int
src_len
,
char
*
dst
,
int
dst_len
,
int
is_form_url_encoded
)
{
int
i
,
j
,
a
,
b
;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
for
(
i
=
j
=
0
;
i
<
src_len
&&
j
<
dst_len
-
1
;
i
++
,
j
++
)
{
if
(
src
[
i
]
==
'%'
&&
i
<
src_len
-
2
&&
isxdigit
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
1
))
&&
isxdigit
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
2
)))
{
a
=
tolower
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
1
));
b
=
tolower
(
*
(
const
unsigned
char
*
)
(
src
+
i
+
2
));
dst
[
j
]
=
(
char
)
((
HEXTOI
(
a
)
<<
4
)
|
HEXTOI
(
b
));
i
+=
2
;
}
else
if
(
is_form_url_encoded
&&
src
[
i
]
==
'+'
)
{
dst
[
j
]
=
' '
;
}
else
{
dst
[
j
]
=
src
[
i
];
}
}
dst
[
j
]
=
'\0'
;
// Null-terminate the destination
return
i
>=
src_len
?
j
:
-
1
;
}
// Return HTTP header value, or NULL if not found.
// Return HTTP header value, or NULL if not found.
const
char
*
mg_get_header
(
const
struct
mg_connection
*
ri
,
const
char
*
s
)
{
const
char
*
mg_get_header
(
const
struct
mg_connection
*
ri
,
const
char
*
s
)
{
int
i
;
int
i
;
...
@@ -867,67 +854,40 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf,
...
@@ -867,67 +854,40 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf,
}
}
static
int
spool
(
struct
iobuf
*
io
,
const
void
*
buf
,
int
len
)
{
static
int
spool
(
struct
iobuf
*
io
,
const
void
*
buf
,
int
len
)
{
static
const
float
mult
=
1
.
2
;
char
*
p
=
NULL
;
char
*
p
=
NULL
;
int
new_len
=
io
->
len
+
len
;
int
new_len
=
0
;
DBG
((
"%d %d %d"
,
len
,
io
->
len
,
io
->
size
));
assert
(
io
->
len
>=
0
);
assert
(
io
->
len
<=
io
->
size
);
//DBG(("1. %d %d %d", len, io->len, io->size));
if
(
len
<=
0
)
{
if
(
len
<=
0
)
{
}
else
if
(
new_len
<
io
->
size
)
{
}
else
if
(
(
new_len
=
io
->
len
+
len
)
<
io
->
size
)
{
memcpy
(
io
->
buf
+
io
->
len
,
buf
,
len
);
memcpy
(
io
->
buf
+
io
->
len
,
buf
,
len
);
io
->
len
+=
len
;
io
->
len
=
new_
len
;
}
else
if
((
p
=
(
char
*
)
realloc
(
io
->
buf
,
new_len
*
2
))
!=
NULL
)
{
}
else
if
((
p
=
(
char
*
)
realloc
(
io
->
buf
,
new_len
*
mult
))
!=
NULL
)
{
io
->
buf
=
p
;
io
->
buf
=
p
;
memcpy
(
io
->
buf
+
io
->
len
,
buf
,
len
);
memcpy
(
io
->
buf
+
io
->
len
,
buf
,
len
);
io
->
len
=
new_len
;
io
->
len
=
new_len
;
io
->
size
=
new_len
*
2
;
io
->
size
=
new_len
*
mult
;
}
else
{
len
=
0
;
}
return
len
;
}
static
int
vspool
(
struct
iobuf
*
io
,
const
char
*
fmt
,
va_list
ap
)
{
char
*
ptr
=
io
->
buf
;
va_list
ap_copy
;
int
len
;
va_copy
(
ap_copy
,
ap
);
len
=
vsnprintf
(
NULL
,
0
,
fmt
,
ap_copy
);
if
(
len
<=
0
)
{
}
else
if
(
len
<
io
->
size
-
io
->
len
||
(
ptr
=
(
char
*
)
realloc
(
io
->
buf
,
io
->
len
+
len
+
1
-
io
->
size
))
!=
NULL
)
{
io
->
buf
=
ptr
;
vsnprintf
(
io
->
buf
+
io
->
len
,
len
+
1
,
fmt
,
ap
);
io
->
len
+=
len
;
}
else
{
}
else
{
len
=
0
;
len
=
0
;
}
}
DBG
((
"%d %d %d"
,
len
,
io
->
len
,
io
->
size
));
return
len
;
return
len
;
}
}
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
);
mutex_lock
(
&
conn
->
mutex
);
ret
=
vspool
(
&
conn
->
remote_iobuf
,
fmt
,
ap
);
mutex_unlock
(
&
conn
->
mutex
);
va_end
(
ap
);
send
(
conn
->
server
->
ctl
[
1
],
"."
,
1
,
0
);
// Wake up select call
return
ret
;
}
int
mg_write
(
struct
mg_connection
*
c
,
const
void
*
buf
,
int
len
)
{
int
mg_write
(
struct
mg_connection
*
c
,
const
void
*
buf
,
int
len
)
{
struct
connection
*
conn
=
(
struct
connection
*
)
c
;
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
);
mutex_unlock
(
&
conn
->
mutex
);
mutex_unlock
(
&
conn
->
mutex
);
send
(
conn
->
server
->
ctl
[
1
],
"."
,
1
,
0
);
// Wake up select call
send
(
conn
->
server
->
ctl
[
1
],
"."
,
1
,
0
);
// Wake up select call
return
ret
;
return
ret
;
}
}
...
@@ -1010,16 +970,15 @@ static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
...
@@ -1010,16 +970,15 @@ static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
static
void
open_file_endpoint
(
struct
connection
*
conn
,
const
char
*
path
,
static
void
open_file_endpoint
(
struct
connection
*
conn
,
const
char
*
path
,
file_stat_t
*
st
)
{
file_stat_t
*
st
)
{
char
date
[
64
],
lm
[
64
],
etag
[
64
],
range
[
64
];
char
date
[
64
],
lm
[
64
],
etag
[
64
],
range
[
64
]
,
headers
[
500
]
;
const
char
*
msg
=
"OK"
,
*
hdr
;
const
char
*
msg
=
"OK"
,
*
hdr
;
time_t
curtime
=
time
(
NULL
);
time_t
curtime
=
time
(
NULL
);
int64_t
cl
,
r1
,
r2
;
int64_t
cl
,
r1
,
r2
;
struct
vec
mime_vec
;
struct
vec
mime_vec
;
int
n
;
int
n
,
status_code
=
200
;
conn
->
endpoint_type
=
EP_FILE
;
conn
->
endpoint_type
=
EP_FILE
;
set_close_on_exec
(
conn
->
endpoint
.
fd
);
set_close_on_exec
(
conn
->
endpoint
.
fd
);
conn
->
status_code
=
200
;
get_mime_type
(
conn
->
server
,
path
,
&
mime_vec
);
get_mime_type
(
conn
->
server
,
path
,
&
mime_vec
);
cl
=
st
->
st_size
;
cl
=
st
->
st_size
;
...
@@ -1030,7 +989,7 @@ static void open_file_endpoint(struct connection *conn, const char *path,
...
@@ -1030,7 +989,7 @@ static void open_file_endpoint(struct connection *conn, const char *path,
hdr
=
mg_get_header
(
&
conn
->
mg_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
;
status_code
=
206
;
cl
=
n
==
2
?
(
r2
>
cl
?
cl
:
r2
)
-
r1
+
1
:
cl
-
r1
;
cl
=
n
==
2
?
(
r2
>
cl
?
cl
:
r2
)
-
r1
+
1
:
cl
-
r1
;
snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes "
snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes "
"%"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
"%"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
...
@@ -1045,7 +1004,7 @@ static void open_file_endpoint(struct connection *conn, const char *path,
...
@@ -1045,7 +1004,7 @@ static void open_file_endpoint(struct 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_conn
,
n
=
snprintf
(
headers
,
sizeof
(
headers
)
,
"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
"
...
@@ -1055,8 +1014,9 @@ static void open_file_endpoint(struct connection *conn, const char *path,
...
@@ -1055,8 +1014,9 @@ static void open_file_endpoint(struct connection *conn, const char *path,
"Connection: %s
\r\n
"
"Connection: %s
\r\n
"
"Accept-Ranges: bytes
\r\n
"
"Accept-Ranges: bytes
\r\n
"
"%s%s
\r\n
"
,
"%s%s
\r\n
"
,
conn
->
status_code
,
msg
,
date
,
lm
,
etag
,
(
int
)
mime_vec
.
len
,
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
);
spool
(
&
conn
->
remote_iobuf
,
headers
,
n
);
if
(
!
strcmp
(
conn
->
mg_conn
.
request_method
,
"HEAD"
))
{
if
(
!
strcmp
(
conn
->
mg_conn
.
request_method
,
"HEAD"
))
{
conn
->
flags
|=
CONN_SPOOL_DONE
;
conn
->
flags
|=
CONN_SPOOL_DONE
;
...
@@ -1135,7 +1095,7 @@ static struct uri_handler *find_uri_handler(struct mg_server *server,
...
@@ -1135,7 +1095,7 @@ static struct uri_handler *find_uri_handler(struct mg_server *server,
// For given directory path, substitute it to valid index file.
// For given directory path, substitute it to valid index file.
// Return 0 if index file has been found, -1 if not found.
// Return 0 if index file has been found, -1 if not found.
// If the file is found, it's stats is returned in stp.
// If the file is found, it's stats is returned in stp.
static
int
substitute
_index_file
(
struct
connection
*
conn
,
char
*
path
,
static
int
find
_index_file
(
struct
connection
*
conn
,
char
*
path
,
size_t
path_len
,
file_stat_t
*
stp
)
{
size_t
path_len
,
file_stat_t
*
stp
)
{
const
char
*
list
=
conn
->
server
->
config_options
[
INDEX_FILES
];
const
char
*
list
=
conn
->
server
->
config_options
[
INDEX_FILES
];
file_stat_t
st
;
file_stat_t
st
;
...
@@ -1179,33 +1139,40 @@ static int substitute_index_file(struct connection *conn, char *path,
...
@@ -1179,33 +1139,40 @@ static int substitute_index_file(struct connection *conn, char *path,
}
}
static
void
send_http_error
(
struct
connection
*
conn
,
const
char
*
fmt
,
...)
{
static
void
send_http_error
(
struct
connection
*
conn
,
const
char
*
fmt
,
...)
{
char
buf
[
500
];
int
len
;
va_list
ap
;
va_list
ap
;
va_start
(
ap
,
fmt
);
va_start
(
ap
,
fmt
);
vspool
(
&
conn
->
remote_iobuf
,
fmt
,
ap
);
len
=
vsnprintf
(
buf
,
sizeof
(
buf
)
,
fmt
,
ap
);
va_end
(
ap
);
va_end
(
ap
);
spool
(
&
conn
->
remote_iobuf
,
buf
,
len
);
conn
->
flags
|=
CONN_SPOOL_DONE
;
conn
->
flags
|=
CONN_SPOOL_DONE
;
}
}
static
void
exec_lua_script
(
struct
connection
*
conn
,
const
char
*
path
)
{
static
void
call_uri_handler_if_data_is_buffered
(
struct
connection
*
conn
)
{
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 501 Not Implemented
\r\n\r\n
"
);
if
(
conn
->
local_iobuf
.
len
>=
conn
->
mg_conn
.
content_len
)
{
conn
->
endpoint
.
uh
->
handler
(
&
conn
->
mg_conn
);
close_local_endpoint
(
conn
);
}
}
}
static
void
open_local_endpoint
(
struct
connection
*
conn
)
{
static
void
open_local_endpoint
(
struct
connection
*
conn
)
{
char
path
[
MAX_PATH_SIZE
]
=
{
'\0'
};
char
path
[
MAX_PATH_SIZE
]
=
{
'\0'
};
file_stat_t
st
;
file_stat_t
st
;
int
uri_len
,
exists
=
0
,
is_directory
=
0
;
int
exists
=
0
,
is_directory
=
0
;
struct
uri_handler
*
uh
;
const
char
*
cl_hdr
=
mg_get_header
(
&
conn
->
mg_conn
,
"Content-Length"
)
;
if
((
conn
->
mg_conn
.
query_string
=
strchr
(
conn
->
mg_conn
.
uri
,
'?'
))
!=
NULL
)
{
conn
->
mg_conn
.
content_len
=
cl_hdr
==
NULL
?
0
:
to64
(
cl_hdr
);
*
((
char
*
)
conn
->
mg_conn
.
query_string
++
)
=
'\0'
;
}
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
((
uh
=
find_uri_handler
(
conn
->
server
,
conn
->
mg_conn
.
uri
))
!=
NULL
)
{
// Call URI handler if one is registered for this URI
conn
->
endpoint
.
uh
=
find_uri_handler
(
conn
->
server
,
conn
->
mg_conn
.
uri
);
if
(
conn
->
endpoint
.
uh
!=
NULL
)
{
conn
->
endpoint_type
=
EP_USER
;
conn
->
endpoint_type
=
EP_USER
;
conn
->
mg_conn
.
content
=
conn
->
local_iobuf
.
buf
;
call_uri_handler_if_data_is_buffered
(
conn
);
return
;
}
}
exists
=
convert_uri_to_file_name
(
conn
,
path
,
sizeof
(
path
),
&
st
);
exists
=
convert_uri_to_file_name
(
conn
,
path
,
sizeof
(
path
),
&
st
);
...
@@ -1213,14 +1180,10 @@ static void open_local_endpoint(struct connection *conn) {
...
@@ -1213,14 +1180,10 @@ static void open_local_endpoint(struct connection *conn) {
if
(
!
exists
)
{
if
(
!
exists
)
{
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 404 Not Found
\r\n\r\n
"
);
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 404 Not Found
\r\n\r\n
"
);
}
else
if
(
is_directory
&&
conn
->
mg_conn
.
uri
[
uri_len
-
1
]
!=
'/'
)
{
}
else
if
(
is_directory
&&
!
find_index_file
(
conn
,
path
,
sizeof
(
path
),
&
st
))
{
send_http_error
(
conn
,
"HTTP/1.1 301 Moved Permanently
\r\n
"
"Location: %s/
\r\n\r\n
"
,
conn
->
mg_conn
.
uri
);
}
else
if
(
is_directory
&&
!
substitute_index_file
(
conn
,
path
,
sizeof
(
path
),
&
st
))
{
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 403 Listing Denied
\r\n\r\n
"
);
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 403 Listing Denied
\r\n\r\n
"
);
}
else
if
(
match_prefix
(
LUA_SCRIPT_PATTERN
,
6
,
path
)
>
0
)
{
}
else
if
(
match_prefix
(
LUA_SCRIPT_PATTERN
,
6
,
path
)
>
0
)
{
exec_lua_script
(
conn
,
path
);
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 501 Not Implemented
\r\n\r\n
"
);
conn
->
flags
|=
CONN_SPOOL_DONE
;
conn
->
flags
|=
CONN_SPOOL_DONE
;
}
else
if
(
is_not_modified
(
conn
,
&
st
))
{
}
else
if
(
is_not_modified
(
conn
,
&
st
))
{
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 304 Not Modified
\r\n\r\n
"
);
send_http_error
(
conn
,
"%s"
,
"HTTP/1.1 304 Not Modified
\r\n\r\n
"
);
...
@@ -1231,40 +1194,54 @@ static void open_local_endpoint(struct connection *conn) {
...
@@ -1231,40 +1194,54 @@ static void open_local_endpoint(struct connection *conn) {
}
}
}
}
static
int
io_space
(
const
struct
iobuf
*
io
)
{
static
void
send_continue_if_expected
(
struct
connection
*
conn
)
{
return
io
->
size
-
io
->
len
;
static
const
char
expect_response
[]
=
"HTTP/1.1 100 Continue
\r\n\r\n
"
;
const
char
*
expect_hdr
=
mg_get_header
(
&
conn
->
mg_conn
,
"Expect"
);
if
(
expect_hdr
!=
NULL
)
{
spool
(
&
conn
->
remote_iobuf
,
expect_response
,
sizeof
(
expect_response
)
-
1
);
}
}
}
static
void
process_request
(
struct
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
->
mg_conn
);
(
conn
->
request_len
=
get_request_len
((
unsigned
char
*
)
io
->
buf
,
io
->
len
))
>
0
)
{
// If request is buffered in, remove it from the iobuf. This is because
// iobuf could be reallocated, and pointers in parsed request could
// become ivalid.
conn
->
request
=
(
char
*
)
malloc
(
conn
->
request_len
);
memcpy
(
conn
->
request
,
io
->
buf
,
conn
->
request_len
);
memmove
(
io
->
buf
,
io
->
buf
+
conn
->
request_len
,
io
->
len
-
conn
->
request_len
);
io
->
len
-=
conn
->
request_len
;
conn
->
request_len
=
parse_http_message
(
conn
->
request
,
conn
->
request_len
,
&
conn
->
mg_conn
);
DBG
((
"request_len = %d"
,
conn
->
request_len
));
}
}
DBG
((
"parse_http_message() -> %d"
,
conn
->
request_len
));
if
(
conn
->
request_len
<
0
||
if
(
conn
->
request_len
<
0
||
(
conn
->
request_len
==
0
&&
io
_space
(
io
)
<=
0
))
{
(
conn
->
request_len
==
0
&&
io
->
len
>
MAX_REQUEST_SIZE
))
{
// Invalid request, or request is too big: close the connection
// Invalid request, or request is too big: close the connection
conn
->
flags
|=
CONN_CLOSE
;
conn
->
flags
|=
CONN_CLOSE
;
}
else
if
(
conn
->
request_len
>
0
&&
conn
->
endpoint_type
==
EP_NONE
)
{
}
else
if
(
conn
->
request_len
>
0
&&
conn
->
endpoint_type
==
EP_NONE
)
{
send_continue_if_expected
(
conn
);
open_local_endpoint
(
conn
);
open_local_endpoint
(
conn
);
}
else
if
(
conn
->
endpoint_type
==
EP_USER
)
{
call_uri_handler_if_data_is_buffered
(
conn
);
}
}
}
}
static
void
read_from_client
(
struct
connection
*
conn
)
{
static
void
read_from_client
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
char
buf
[
IOBUF_SIZE
];
int
n
=
recv
(
conn
->
client_sock
,
io
->
buf
+
io
->
len
,
io
->
size
-
io
->
len
,
0
);
int
n
=
recv
(
conn
->
client_sock
,
buf
,
sizeof
(
buf
),
0
);
//DBG(("Read: %d [%.*s]", n, n, io->buf + io->len));
assert
(
io
->
len
>=
0
);
assert
(
io
->
len
<=
io
->
size
);
if
(
is_error
(
n
))
{
if
(
is_error
(
n
))
{
conn
->
flags
|=
CONN_CLOSE
;
conn
->
flags
|=
CONN_CLOSE
;
}
else
if
(
n
>
0
)
{
}
else
if
(
n
>
0
)
{
io
->
len
+=
n
;
spool
(
&
conn
->
local_iobuf
,
buf
,
n
)
;
process_request
(
conn
);
process_request
(
conn
);
}
}
}
}
...
@@ -1279,22 +1256,22 @@ static int should_keep_alive(const struct connection *conn) {
...
@@ -1279,22 +1256,22 @@ static int should_keep_alive(const struct connection *conn) {
}
}
static
void
close_local_endpoint
(
struct
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 free()
int
keep_alive
=
should_keep_alive
(
conn
);
// Must be done before memmove
//DBG(("Closing for conn %p", conn));
// 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
;
case
EP_USER
:
break
;
case
EP_NONE
:
break
;
case
EP_NONE
:
break
;
default:
assert
(
0
);
break
;
default:
assert
(
0
);
break
;
}
}
// Get rid of that request from the buffer. NOTE: order is important here
assert
(
conn
->
request_len
<=
io
->
len
);
memmove
(
io
->
buf
,
io
->
buf
+
conn
->
request_len
,
io
->
len
-
conn
->
request_len
);
io
->
len
-=
conn
->
request_len
;
conn
->
endpoint_type
=
EP_NONE
;
conn
->
endpoint_type
=
EP_NONE
;
conn
->
request_len
=
0
;
conn
->
request_len
=
0
;
free
(
conn
->
request
);
conn
->
request
=
NULL
;
if
(
keep_alive
)
{
if
(
keep_alive
)
{
process_request
(
conn
);
// Can call us recursively if pipelining is used
process_request
(
conn
);
// Can call us recursively if pipelining is used
...
@@ -1304,16 +1281,13 @@ static void close_local_endpoint(struct connection *conn) {
...
@@ -1304,16 +1281,13 @@ static void close_local_endpoint(struct connection *conn) {
}
}
static
void
transfer_file_data
(
struct
connection
*
conn
)
{
static
void
transfer_file_data
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
remote_iobuf
;
char
buf
[
IOBUF_SIZE
];
int
n
,
rem_space
=
io_space
(
io
);
int
n
=
read
(
conn
->
endpoint
.
fd
,
buf
,
sizeof
(
buf
));
if
(
rem_space
<=
0
)
return
;
n
=
read
(
conn
->
endpoint
.
fd
,
io
->
buf
+
io
->
len
,
rem_space
);
if
(
is_error
(
n
))
{
if
(
is_error
(
n
))
{
close_local_endpoint
(
conn
);
close_local_endpoint
(
conn
);
}
else
if
(
n
>
0
)
{
}
else
if
(
n
>
0
)
{
io
->
len
+=
n
;
spool
(
&
conn
->
remote_iobuf
,
buf
,
n
)
;
}
}
}
}
...
@@ -1488,22 +1462,6 @@ struct mg_server *mg_create_server(void *server_data) {
...
@@ -1488,22 +1462,6 @@ struct mg_server *mg_create_server(void *server_data) {
server
->
server_data
=
server_data
;
server
->
server_data
=
server_data
;
server
->
listening_sock
=
INVALID_SOCKET
;
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);
} else if ((value = *opts++) == NULL) {
snprintf(error_msg, sizeof(error_msg), "[%s] cannot be NULL", name);
} else {
if (server->config_options[i] != NULL) {
free(server->config_options[i]);
}
server->config_options[i] = mg_strdup(value);
DBG(("[%s] -> [%s]", name, value));
}
}
#endif
// Set default options 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
];
...
@@ -1518,7 +1476,9 @@ struct mg_server *mg_create_server(void *server_data) {
...
@@ -1518,7 +1476,9 @@ struct mg_server *mg_create_server(void *server_data) {
// End of library, start of the application code
// End of library, start of the application code
static
void
iterate_callback
(
struct
mg_connection
*
c
,
void
*
param
)
{
static
void
iterate_callback
(
struct
mg_connection
*
c
,
void
*
param
)
{
if
(
c
->
connection_param
!=
NULL
)
{
mg_write
(
c
,
"%d"
,
*
(
int
*
)
param
);
mg_write
(
c
,
"%d"
,
*
(
int
*
)
param
);
}
}
}
static
void
*
timer_thread
(
void
*
param
)
{
static
void
*
timer_thread
(
void
*
param
)
{
...
@@ -1534,7 +1494,17 @@ static void *timer_thread(void *param) {
...
@@ -1534,7 +1494,17 @@ static void *timer_thread(void *param) {
}
}
static
int
websocket_handler
(
struct
mg_connection
*
conn
)
{
static
int
websocket_handler
(
struct
mg_connection
*
conn
)
{
mg_printf
(
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n\r\n
:-)
\n
"
);
char
headers
[
500
],
content
[
500
];
int
headers_len
,
content_len
;
content_len
=
snprintf
(
content
,
sizeof
(
content
),
"%s %s, POST len %d
\n
"
,
conn
->
request_method
,
conn
->
uri
,
conn
->
content_len
);
headers_len
=
snprintf
(
headers
,
sizeof
(
headers
),
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n\r\n
"
,
content_len
);
mg_write
(
conn
,
headers
,
headers_len
);
mg_write
(
conn
,
content
,
content_len
);
return
1
;
return
1
;
}
}
...
@@ -1549,7 +1519,7 @@ int main(void) {
...
@@ -1549,7 +1519,7 @@ int main(void) {
printf
(
"Started on port %s
\n
"
,
mg_get_option
(
server
,
"listening_port"
));
printf
(
"Started on port %s
\n
"
,
mg_get_option
(
server
,
"listening_port"
));
for
(;;)
{
for
(;;)
{
mg_poll_server
(
server
,
1
000
);
mg_poll_server
(
server
,
3
000
);
}
}
mg_destroy_server
(
&
server
);
mg_destroy_server
(
&
server
);
...
...
build/src/core.h
View file @
03e73782
...
@@ -33,15 +33,19 @@ struct mg_connection {
...
@@ -33,15 +33,19 @@ struct mg_connection {
const
char
*
uri
;
// URL-decoded URI
const
char
*
uri
;
// URL-decoded URI
const
char
*
http_version
;
// E.g. "1.0", "1.1"
const
char
*
http_version
;
// E.g. "1.0", "1.1"
const
char
*
query_string
;
// URL part after '?', not including '?', or NULL
const
char
*
query_string
;
// URL part after '?', not including '?', or NULL
long
remote_ip
;
// Client's IP address
long
remote_ip
;
// Client's IP address
int
remote_port
;
// Client's port
int
remote_port
;
// Client's port
int
is_ssl
;
// 1 if SSL-ed, 0 if not
int
num_headers
;
// Number of HTTP headers
int
num_headers
;
// Number of HTTP headers
struct
mg_header
{
struct
mg_header
{
const
char
*
name
;
// HTTP header name
const
char
*
name
;
// HTTP header name
const
char
*
value
;
// HTTP header value
const
char
*
value
;
// HTTP header value
}
http_headers
[
64
];
// Maximum 64 headers
}
http_headers
[
64
];
// Maximum 64 headers
char
*
content
;
// POST (or websocket message) data, or NULL
int
content_len
;
// content length
void
*
server_param
;
// Parameter passed to mg_add_uri_handler()
void
*
server_param
;
// Parameter passed to mg_add_uri_handler()
void
*
connection_param
;
// Placeholder for connection-specific data
void
*
connection_param
;
// Placeholder for connection-specific data
};
};
...
@@ -64,16 +68,16 @@ const char **mg_get_valid_option_names(void);
...
@@ -64,16 +68,16 @@ const char **mg_get_valid_option_names(void);
const
char
*
mg_get_option
(
const
struct
mg_server
*
server
,
const
char
*
name
);
const
char
*
mg_get_option
(
const
struct
mg_server
*
server
,
const
char
*
name
);
// Websocket functions
// Websocket functions
void
mg_websocket_handshake
(
struct
mg_connection
*
);
//
void mg_websocket_handshake(struct mg_connection *);
int
mg_websocket_read
(
struct
mg_connection
*
,
int
*
bits
,
char
**
data
);
//
int mg_websocket_read(struct mg_connection *, int *bits, char **data);
int
mg_websocket_write
(
struct
mg_connection
*
conn
,
int
opcode
,
//
int mg_websocket_write(struct mg_connection* conn, int opcode,
const
char
*
data
,
size_t
data_len
);
//
const char *data, size_t data_len);
// Connection management functions
// Connection management functions
int
mg_write
(
struct
mg_connection
*
,
const
void
*
buf
,
int
len
);
int
mg_write
(
struct
mg_connection
*
,
const
void
*
buf
,
int
len
);
int
mg_printf
(
struct
mg_connection
*
,
const
char
*
fmt
,
...);
#if 0
#if 0
int mg_printf(struct mg_connection *, const char *fmt, ...);
void mg_send_file(struct mg_connection *, const char *path);
void mg_send_file(struct mg_connection *, const char *path);
int mg_read(struct mg_connection *, void *buf, int len);
int mg_read(struct mg_connection *, void *buf, int len);
const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_header(const struct mg_connection *, const char *name);
...
...
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