Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
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
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
mongoose
Commits
7a129c17
Commit
7a129c17
authored
Jan 19, 2014
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added http client with unit tests
parent
400084ea
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
226 additions
and
143 deletions
+226
-143
mongoose.c
mongoose.c
+135
-70
mongoose.h
mongoose.h
+10
-2
unit_test.c
unit_test.c
+81
-71
No files found.
mongoose.c
View file @
7a129c17
...
...
@@ -318,7 +318,7 @@ enum connection_flags {
CONN_HEADERS_SENT
=
8
,
// User callback has sent HTTP headers
CONN_BUFFER
=
16
,
// CGI only. Holds data send until CGI prints
// all HTTP headers
CONN_CONNECT
ED
=
32
,
// HTTP client has connected
CONN_CONNECT
ING
=
32
,
// HTTP client is doing non-blocking connect()
CONN_LONG_RUNNING
=
64
// Long-running URI handlers
};
...
...
@@ -1154,6 +1154,7 @@ static void open_cgi_endpoint(struct connection *conn, const char *prog) {
conn
->
endpoint_type
=
EP_CGI
;
conn
->
endpoint
.
cgi_sock
=
fds
[
0
];
spool
(
&
conn
->
remote_iobuf
,
cgi_status
,
sizeof
(
cgi_status
)
-
1
);
conn
->
mg_conn
.
status_code
=
200
;
conn
->
flags
|=
CONN_BUFFER
;
}
else
{
closesocket
(
fds
[
0
]);
...
...
@@ -1193,19 +1194,24 @@ static void read_from_cgi(struct connection *conn) {
}
}
memcpy
(
io
->
buf
+
9
,
status
,
3
);
conn
->
mg_conn
.
status_code
=
atoi
(
status
);
conn
->
flags
&=
~
CONN_BUFFER
;
}
}
}
static
void
forward_post_data
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
int
n
=
send
(
conn
->
endpoint
.
cgi_sock
,
io
->
buf
,
io
->
len
,
0
);
if
(
n
>
0
)
{
static
void
discard_leading_iobuf_bytes
(
struct
iobuf
*
io
,
int
n
)
{
if
(
n
>=
0
&&
n
<=
io
->
len
)
{
memmove
(
io
->
buf
,
io
->
buf
+
n
,
io
->
len
-
n
);
io
->
len
-=
n
;
}
}
static
void
forward_post_data
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
int
n
=
send
(
conn
->
endpoint
.
cgi_sock
,
io
->
buf
,
io
->
len
,
0
);
discard_leading_iobuf_bytes
(
io
,
n
);
}
#endif // !NO_CGI
// 'sa' must be an initialized address to bind to
...
...
@@ -1331,9 +1337,10 @@ static struct connection *accept_new_connection(struct mg_server *server) {
}
static
void
close_conn
(
struct
connection
*
conn
)
{
DBG
((
"%p %d %d"
,
conn
,
conn
->
flags
,
conn
->
endpoint_type
));
LINKED_LIST_REMOVE
(
&
conn
->
link
);
closesocket
(
conn
->
client_sock
);
close_local_endpoint
(
conn
);
DBG
((
"%p %d %d"
,
conn
,
conn
->
flags
,
conn
->
endpoint_type
));
free
(
conn
->
request
);
// It's OK to free(NULL), ditto below
free
(
conn
->
path_info
);
free
(
conn
->
remote_iobuf
.
buf
);
...
...
@@ -1840,8 +1847,7 @@ static int deliver_websocket_frame(struct connection *conn) {
if
(
conn
->
endpoint
.
uh
->
handler
(
&
conn
->
mg_conn
))
{
conn
->
flags
|=
CONN_SPOOL_DONE
;
}
memmove
(
buf
,
buf
+
frame_len
,
buf_len
-
frame_len
);
conn
->
local_iobuf
.
len
-=
frame_len
;
discard_leading_iobuf_bytes
(
&
conn
->
local_iobuf
,
frame_len
);
}
return
buffered
;
...
...
@@ -1938,8 +1944,7 @@ static void write_to_socket(struct connection *conn) {
if
(
is_error
(
n
))
{
conn
->
flags
|=
CONN_CLOSE
;
}
else
if
(
n
>
0
)
{
memmove
(
io
->
buf
,
io
->
buf
+
n
,
io
->
len
-
n
);
io
->
len
-=
n
;
discard_leading_iobuf_bytes
(
io
,
n
);
conn
->
num_bytes_sent
+=
n
;
}
...
...
@@ -2641,8 +2646,7 @@ static void forward_put_data(struct connection *conn) {
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
int
n
=
write
(
conn
->
endpoint
.
fd
,
io
->
buf
,
io
->
len
);
if
(
n
>
0
)
{
memmove
(
io
->
buf
,
io
->
buf
+
n
,
io
->
len
-
n
);
io
->
len
-=
n
;
discard_leading_iobuf_bytes
(
io
,
n
);
conn
->
cl
-=
n
;
if
(
conn
->
cl
<=
0
)
{
close_local_endpoint
(
conn
);
...
...
@@ -3312,7 +3316,6 @@ static void handle_lsp_request(struct connection *conn, const char *path,
#endif // USE_LUA
static
void
open_local_endpoint
(
struct
connection
*
conn
)
{
const
char
*
cl_hdr
=
mg_get_header
(
&
conn
->
mg_conn
,
"Content-Length"
);
#ifndef NO_FILESYSTEM
static
const
char
lua_pat
[]
=
LUA_SCRIPT_PATTERN
;
file_stat_t
st
;
...
...
@@ -3322,8 +3325,6 @@ static void open_local_endpoint(struct connection *conn) {
const
char
*
dir_lst
=
conn
->
server
->
config_options
[
ENABLE_DIRECTORY_LISTING
];
#endif
conn
->
mg_conn
.
content_len
=
cl_hdr
==
NULL
?
0
:
(
int
)
to64
(
cl_hdr
);
// 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
)
{
...
...
@@ -3425,7 +3426,7 @@ static int is_valid_uri(const char *uri) {
return
uri
[
0
]
==
'/'
||
(
uri
[
0
]
==
'*'
&&
uri
[
1
]
==
'\0'
);
}
static
void
process_request
(
struct
connection
*
conn
)
{
static
void
try_http_parse_and_set_content_length
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
if
(
conn
->
request_len
==
0
&&
...
...
@@ -3435,14 +3436,24 @@ static void process_request(struct connection *conn) {
// become invalid.
conn
->
request
=
(
char
*
)
malloc
(
conn
->
request_len
);
memcpy
(
conn
->
request
,
io
->
buf
,
conn
->
request_len
);
DBG
((
"%p ==> [%.*s]"
,
conn
,
conn
->
request_len
,
conn
->
request
));
memmove
(
io
->
buf
,
io
->
buf
+
conn
->
request_len
,
io
->
len
-
conn
->
request_len
);
io
->
len
-=
conn
->
request_len
;
DBG
((
"%p [%.*s]"
,
conn
,
conn
->
request_len
,
conn
->
request
));
discard_leading_iobuf_bytes
(
io
,
conn
->
request_len
);
conn
->
request_len
=
parse_http_message
(
conn
->
request
,
conn
->
request_len
,
&
conn
->
mg_conn
);
if
(
conn
->
request_len
>
0
)
{
const
char
*
cl_hdr
=
mg_get_header
(
&
conn
->
mg_conn
,
"Content-Length"
);
conn
->
cl
=
cl_hdr
==
NULL
?
0
:
to64
(
cl_hdr
);
conn
->
mg_conn
.
content_len
=
(
long
int
)
conn
->
cl
;
}
}
}
DBG
((
"%p %d %d [%.*s]"
,
conn
,
conn
->
request_len
,
io
->
len
,
io
->
len
,
io
->
buf
));
static
void
process_request
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
try_http_parse_and_set_content_length
(
conn
);
DBG
((
"%p %d %d %d [%.*s]"
,
conn
,
conn
->
request_len
,
io
->
len
,
conn
->
flags
,
io
->
len
,
io
->
buf
));
if
(
conn
->
request_len
<
0
||
(
conn
->
request_len
>
0
&&
!
is_valid_uri
(
conn
->
mg_conn
.
uri
)))
{
send_http_error
(
conn
,
400
,
NULL
);
...
...
@@ -3475,48 +3486,96 @@ static void process_request(struct connection *conn) {
#endif
}
static
void
call_http_client_handler
(
struct
connection
*
conn
,
int
code
)
{
conn
->
mg_conn
.
status_code
=
code
;
// For responses without Content-Lengh, use the whole buffer
if
(
conn
->
cl
==
0
&&
code
==
MG_DOWNLOAD_SUCCESS
)
{
conn
->
mg_conn
.
content_len
=
conn
->
local_iobuf
.
len
;
}
conn
->
mg_conn
.
content
=
conn
->
local_iobuf
.
buf
;
if
(
conn
->
handler
(
&
conn
->
mg_conn
)
||
code
==
MG_CONNECT_FAILURE
||
code
==
MG_DOWNLOAD_FAILURE
)
{
conn
->
flags
|=
CONN_CLOSE
;
}
discard_leading_iobuf_bytes
(
&
conn
->
local_iobuf
,
conn
->
mg_conn
.
content_len
);
conn
->
flags
=
conn
->
mg_conn
.
status_code
=
0
;
conn
->
cl
=
conn
->
num_bytes_sent
=
conn
->
request_len
=
0
;
free
(
conn
->
request
);
conn
->
request
=
NULL
;
}
static
void
process_response
(
struct
connection
*
conn
)
{
struct
iobuf
*
io
=
&
conn
->
local_iobuf
;
try_http_parse_and_set_content_length
(
conn
);
DBG
((
"%p %d %d [%.*s]"
,
conn
,
conn
->
request_len
,
io
->
len
,
io
->
len
>
40
?
40
:
io
->
len
,
io
->
buf
));
if
(
conn
->
request_len
<
0
||
(
conn
->
request_len
==
0
&&
io
->
len
>
MAX_REQUEST_SIZE
))
{
call_http_client_handler
(
conn
,
MG_DOWNLOAD_FAILURE
);
}
if
(
io
->
len
>=
conn
->
cl
)
{
call_http_client_handler
(
conn
,
MG_DOWNLOAD_SUCCESS
);
}
}
static
void
callback_http_client_on_connect
(
struct
connection
*
conn
)
{
int
ok
;
socklen_t
len
=
sizeof
(
ok
);
if
(
getsockopt
(
conn
->
client_sock
,
SOL_SOCKET
,
SO_ERROR
,
(
char
*
)
&
ok
,
&
len
)
==
0
&&
ok
==
0
)
{
conn
->
mg_conn
.
status_code
=
MG_CONNECT_SUCCESS
;
}
conn
->
flags
&=
~
CONN_CONNECTING
;
if
(
conn
->
handler
(
&
conn
->
mg_conn
)
||
ok
!=
0
)
{
conn
->
flags
|=
CONN_CLOSE
;
}
}
static
void
read_from_socket
(
struct
connection
*
conn
)
{
char
buf
[
IOBUF_SIZE
];
int
ok
,
n
=
0
;
socklen_t
len
=
sizeof
(
ok
);
int
n
=
0
;
if
(
conn
->
endpoint_type
==
EP_CLIENT
)
{
conn
->
mg_conn
.
wsbits
=
1
;
if
(
!
(
conn
->
flags
&
CONN_CONNECTED
)
&&
getsockopt
(
conn
->
client_sock
,
SOL_SOCKET
,
SO_ERROR
,
(
char
*
)
&
ok
,
&
len
)
<
0
)
{
conn
->
mg_conn
.
wsbits
=
0
;
}
conn
->
handler
(
&
conn
->
mg_conn
);
conn
->
flags
|=
CONN_CLOSE
|
CONN_CONNECTED
;
}
else
{
if
(
conn
->
ssl
!=
NULL
)
{
if
(
conn
->
endpoint_type
==
EP_CLIENT
&&
conn
->
flags
&
CONN_CONNECTING
)
{
callback_http_client_on_connect
(
conn
);
return
;
}
if
(
conn
->
ssl
!=
NULL
)
{
#ifdef USE_SSL
if
(
conn
->
flags
&
CONN_SSL_HANDS_SHAKEN
)
{
n
=
SSL_read
(
conn
->
ssl
,
buf
,
sizeof
(
buf
));
}
else
{
if
(
SSL_accept
(
conn
->
ssl
)
==
1
)
{
conn
->
flags
|=
CONN_SSL_HANDS_SHAKEN
;
}
return
;
}
#endif
if
(
conn
->
flags
&
CONN_SSL_HANDS_SHAKEN
)
{
n
=
SSL_read
(
conn
->
ssl
,
buf
,
sizeof
(
buf
));
}
else
{
n
=
recv
(
conn
->
client_sock
,
buf
,
sizeof
(
buf
),
0
);
if
(
SSL_accept
(
conn
->
ssl
)
==
1
)
{
conn
->
flags
|=
CONN_SSL_HANDS_SHAKEN
;
}
return
;
}
#endif
}
else
{
n
=
recv
(
conn
->
client_sock
,
buf
,
sizeof
(
buf
),
0
);
}
DBG
((
"%p %d"
,
conn
,
n
));
if
(
is_error
(
n
))
{
conn
->
flags
|=
CONN_CLOSE
;
}
else
if
(
n
>
0
)
{
spool
(
&
conn
->
local_iobuf
,
buf
,
n
);
DBG
((
"%p %d %d (1)"
,
conn
,
n
,
conn
->
flags
));
if
(
is_error
(
n
))
{
if
(
conn
->
endpoint_type
==
EP_CLIENT
&&
conn
->
local_iobuf
.
len
>
0
)
{
call_http_client_handler
(
conn
,
MG_DOWNLOAD_SUCCESS
);
}
conn
->
flags
|=
CONN_CLOSE
;
}
else
if
(
n
>
0
)
{
spool
(
&
conn
->
local_iobuf
,
buf
,
n
);
if
(
conn
->
endpoint_type
==
EP_CLIENT
)
{
process_response
(
conn
);
}
else
{
process_request
(
conn
);
}
}
DBG
((
"%p %d %d (2)"
,
conn
,
n
,
conn
->
flags
));
}
int
mg_connect
(
struct
mg_server
*
server
,
const
char
*
host
,
int
port
,
mg_handler_t
handler
,
void
*
param
)
{
int
mg_connect
(
struct
mg_server
*
server
,
const
char
*
host
,
int
port
,
mg_handler_t
handler
,
void
*
param
)
{
sock_t
sock
=
INVALID_SOCKET
;
struct
sockaddr_in
sin
;
struct
hostent
*
he
=
NULL
;
...
...
@@ -3544,10 +3603,16 @@ int mg_connect(struct mg_server *server, const char *host,
conn
->
handler
=
handler
;
conn
->
mg_conn
.
server_param
=
server
->
server_data
;
conn
->
mg_conn
.
connection_param
=
param
;
conn
->
birth_time
=
conn
->
last_activity_time
=
time
(
NULL
);
conn
->
flags
=
CONN_CONNECTING
;
conn
->
mg_conn
.
status_code
=
MG_CONNECT_FAILURE
;
LINKED_LIST_ADD_TO_FRONT
(
&
server
->
active_connections
,
&
conn
->
link
);
DBG
((
"%p %s:%d"
,
conn
,
host
,
port
));
if
(
connect_ret_val
==
0
)
{
conn
->
flags
=
CONN_CONNECTED
;
conn
->
mg_conn
.
status_code
=
MG_CONNECT_SUCCESS
;
conn
->
flags
&=
~
CONN_CONNECTING
;
conn
->
mg_conn
.
content
=
conn
->
local_iobuf
.
buf
;
handler
(
&
conn
->
mg_conn
);
}
...
...
@@ -3593,17 +3658,11 @@ static void log_access(const struct connection *conn, const char *path) {
}
#endif
static
void
gobble_prior_post_data
(
struct
iobuf
*
io
,
int
len
)
{
if
(
len
>
0
&&
len
<=
io
->
len
)
{
memmove
(
io
->
buf
,
io
->
buf
+
len
,
io
->
len
-
len
);
io
->
len
-=
len
;
}
}
static
void
close_local_endpoint
(
struct
connection
*
conn
)
{
// Must be done before free()
int
keep_alive
=
should_keep_alive
(
&
conn
->
mg_conn
)
&&
(
conn
->
endpoint_type
==
EP_FILE
||
conn
->
endpoint_type
==
EP_USER
);
DBG
((
"%p %d %d %d"
,
conn
,
conn
->
endpoint_type
,
keep_alive
,
conn
->
flags
));
switch
(
conn
->
endpoint_type
)
{
case
EP_PUT
:
close
(
conn
->
endpoint
.
fd
);
break
;
...
...
@@ -3613,17 +3672,16 @@ static void close_local_endpoint(struct connection *conn) {
}
#ifndef NO_LOGGING
if
(
conn
->
mg_conn
.
status_code
!=
400
)
{
if
(
conn
->
mg_conn
.
status_code
>
0
&&
conn
->
endpoint_type
!=
EP_CLIENT
&&
conn
->
mg_conn
.
status_code
!=
400
)
{
log_access
(
conn
,
conn
->
server
->
config_options
[
ACCESS_LOG_FILE
]);
}
#endif
if
(
conn
->
endpoint_type
==
EP_USER
)
{
gobble_prior_post_data
(
&
conn
->
local_iobuf
,
conn
->
mg_conn
.
content_len
);
}
// Gobble possible POST data sent to the URI handler
discard_leading_iobuf_bytes
(
&
conn
->
local_iobuf
,
conn
->
mg_conn
.
content_len
);
conn
->
endpoint_type
=
EP_NONE
;
conn
->
flags
=
0
;
conn
->
flags
=
conn
->
mg_conn
.
status_code
=
0
;
conn
->
cl
=
conn
->
num_bytes_sent
=
conn
->
request_len
=
0
;
free
(
conn
->
request
);
conn
->
request
=
NULL
;
...
...
@@ -3690,6 +3748,9 @@ unsigned int mg_poll_server(struct mg_server *server, int milliseconds) {
LINKED_LIST_FOREACH
(
&
server
->
active_connections
,
lp
,
tmp
)
{
conn
=
LINKED_LIST_ENTRY
(
lp
,
struct
connection
,
link
);
add_to_set
(
conn
->
client_sock
,
&
read_set
,
&
max_fd
);
if
(
conn
->
endpoint_type
==
EP_CLIENT
&&
(
conn
->
flags
&
CONN_CONNECTING
))
{
add_to_set
(
conn
->
client_sock
,
&
write_set
,
&
max_fd
);
}
if
(
conn
->
endpoint_type
==
EP_FILE
)
{
transfer_file_data
(
conn
);
}
else
if
(
conn
->
endpoint_type
==
EP_CGI
)
{
...
...
@@ -3730,10 +3791,14 @@ unsigned int mg_poll_server(struct mg_server *server, int milliseconds) {
read_from_cgi
(
conn
);
}
#endif
if
(
FD_ISSET
(
conn
->
client_sock
,
&
write_set
)
&&
!
(
conn
->
flags
&
CONN_BUFFER
))
{
conn
->
last_activity_time
=
current_time
;
write_to_socket
(
conn
);
if
(
FD_ISSET
(
conn
->
client_sock
,
&
write_set
))
{
if
(
conn
->
endpoint_type
==
EP_CLIENT
&&
(
conn
->
flags
&
CONN_CONNECTING
))
{
read_from_socket
(
conn
);
}
else
if
(
!
(
conn
->
flags
&
CONN_BUFFER
))
{
conn
->
last_activity_time
=
current_time
;
write_to_socket
(
conn
);
}
}
}
}
...
...
@@ -3767,7 +3832,7 @@ void mg_destroy_server(struct mg_server **server) {
closesocket
((
*
server
)
->
ctl
[
0
]);
closesocket
((
*
server
)
->
ctl
[
1
]);
LINKED_LIST_FOREACH
(
&
(
*
server
)
->
active_connections
,
lp
,
tmp
)
{
free
(
LINKED_LIST_ENTRY
(
lp
,
struct
connection
,
link
));
close_conn
(
LINKED_LIST_ENTRY
(
lp
,
struct
connection
,
link
));
}
LINKED_LIST_FOREACH
(
&
(
*
server
)
->
uri_handlers
,
lp
,
tmp
)
{
free
(
LINKED_LIST_ENTRY
(
lp
,
struct
uri_handler
,
link
)
->
uri
);
...
...
@@ -3980,7 +4045,7 @@ const char *mg_set_option(struct mg_server *server, const char *name,
free
(
server
->
config_options
[
ind
]);
}
server
->
config_options
[
ind
]
=
mg_strdup
(
value
);
DBG
((
"%s
=> %s
"
,
name
,
value
));
DBG
((
"%s
[%s]
"
,
name
,
value
));
if
(
ind
==
LISTENING_PORT
)
{
if
(
server
->
listening_sock
!=
INVALID_SOCKET
)
{
...
...
mongoose.h
View file @
7a129c17
...
...
@@ -46,11 +46,11 @@ struct mg_connection {
}
http_headers
[
30
];
char
*
content
;
// POST (or websocket message) data, or NULL
int
content_len
;
// content length
long
int
content_len
;
// content length
int
is_websocket
;
// Connection is a websocket connection
int
status_code
;
// HTTP status code for HTTP error handler
unsigned
char
wsbits
;
// First byte of the websocket frame
int
wsbits
;
// First byte of the websocket frame
void
*
server_param
;
// Parameter passed to mg_add_uri_handler()
void
*
connection_param
;
// Placeholder for connection-specific data
};
...
...
@@ -101,6 +101,14 @@ char *mg_md5(char buf[33], ...);
int
mg_authorize_digest
(
struct
mg_connection
*
c
,
FILE
*
fp
);
void
mg_send_digest_auth_request
(
struct
mg_connection
*
conn
);
// HTTP client interface
enum
{
MG_CONNECT_SUCCESS
,
MG_CONNECT_FAILURE
,
MG_DOWNLOAD_SUCCESS
,
MG_DOWNLOAD_FAILURE
};
int
mg_connect
(
struct
mg_server
*
server
,
const
char
*
host
,
int
port
,
mg_handler_t
handler
,
void
*
param
);
#ifdef __cplusplus
}
#endif // __cplusplus
...
...
unit_test.c
View file @
7a129c17
// Unit test for the mongoose web server.
// g++ -W -Wall -pedantic
unit_test.c -o t && ./
t
// g++ -W -Wall -pedantic
-g unit_test.c && ./a.ou
t
#define USE_WEBSOCKET
...
...
@@ -28,6 +28,7 @@
static
int
static_num_tests
=
0
;
#if 0
// Connects to host:port, and sends formatted request to it. Returns
// malloc-ed reply and reply length, or NULL on error. Reply contains
// everything including headers, not just the message body.
...
...
@@ -73,6 +74,7 @@ static char *wget(const char *host, int port, int *len, const char *fmt, ...) {
return reply;
}
#endif
static
char
*
read_file
(
const
char
*
path
,
int
*
size
)
{
FILE
*
fp
;
...
...
@@ -361,78 +363,42 @@ static const char *test_next_option(void) {
static
int
cb1
(
struct
mg_connection
*
conn
)
{
// We're not sending HTTP headers here, to make testing easier
//mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s",
mg_printf
(
conn
,
"%s %s %s"
,
conn
->
server_param
==
NULL
?
"?"
:
(
char
*
)
conn
->
server_param
,
conn
->
connection_param
==
NULL
?
"?"
:
"!"
,
conn
->
remote_ip
);
return
1
;
}
static
const
char
*
test_regular_file
(
void
)
{
static
const
char
*
fname
=
"mongoose.c"
;
int
reply_len
,
file_len
;
char
*
reply
,
*
file_data
;
file_stat_t
st
;
ASSERT
(
stat
(
fname
,
&
st
)
==
0
);
ASSERT
(
st
.
st_size
>
0
);
ASSERT
((
file_data
=
read_file
(
fname
,
&
file_len
))
!=
NULL
);
ASSERT
(
file_len
==
st
.
st_size
);
reply
=
wget
(
"127.0.0.1"
,
atoi
(
HTTP_PORT
),
&
reply_len
,
"GET /%s.c HTTP/1.0
\r\n\r\n
"
,
fname
);
ASSERT
(
reply
!=
NULL
);
ASSERT
(
reply_len
>
0
);
// TODO(lsm): test headers and content
free
(
reply
);
free
(
file_data
);
return
NULL
;
}
static
const
char
*
test_server_param
(
void
)
{
int
reply_len
;
char
*
reply
;
reply
=
wget
(
"127.0.0.1"
,
atoi
(
HTTP_PORT
),
&
reply_len
,
"%s"
,
"GET /cb1 HTTP/1.0
\r\n\r\n
"
);
ASSERT
(
reply
!=
NULL
);
ASSERT
(
reply_len
==
15
);
// cb1() does not send HTTP headers
ASSERT
(
memcmp
(
reply
,
"foo ? 127.0.0.1"
,
5
)
==
0
);
//printf("%d [%.*s]\n", reply_len, reply_len, reply);
free
(
reply
);
return
NULL
;
}
static
int
error_handler
(
struct
mg_connection
*
conn
)
{
mg_printf
(
conn
,
"
error
: %d"
,
conn
->
status_code
);
mg_printf
(
conn
,
"
HTTP/1.0 404 NF
\r\n\r\n
ERR
: %d"
,
conn
->
status_code
);
return
1
;
}
static
const
char
*
test_error_handler
(
void
)
{
int
reply_len
;
char
*
reply
;
reply
=
wget
(
"127.0.0.1"
,
atoi
(
HTTP_PORT
),
&
reply_len
,
"%s"
,
"GET /non_exist HTTP/1.0
\r\n\r\n
"
);
ASSERT
(
reply
!=
NULL
);
ASSERT
(
reply_len
==
10
);
ASSERT
(
memcmp
(
reply
,
"error: 404"
,
10
)
==
0
);
free
(
reply
);
return
NULL
;
static
int
ts1
(
struct
mg_connection
*
conn
)
{
if
(
conn
->
status_code
==
MG_CONNECT_SUCCESS
)
{
mg_printf
(
conn
,
"%s"
,
"GET /cb1 HTTP/1.0
\r\n\r\n
"
);
return
0
;
}
else
if
(
conn
->
status_code
==
MG_DOWNLOAD_SUCCESS
)
{
sprintf
((
char
*
)
conn
->
connection_param
,
"%.*s"
,
(
int
)
conn
->
content_len
,
conn
->
content
);
}
return
1
;
}
static
void
*
server_thread
(
void
*
param
)
{
int
i
;
for
(
i
=
0
;
i
<
10
;
i
++
)
mg_poll_server
((
struct
mg_server
*
)
param
,
1
);
return
NULL
;
static
int
ts2
(
struct
mg_connection
*
conn
)
{
if
(
conn
->
status_code
==
MG_CONNECT_SUCCESS
)
{
mg_printf
(
conn
,
"%s"
,
"GET /non_exist HTTP/1.0
\r\n\r\n
"
);
return
0
;
}
else
if
(
conn
->
status_code
==
MG_DOWNLOAD_SUCCESS
)
{
sprintf
((
char
*
)
conn
->
connection_param
,
"%s %.*s"
,
conn
->
uri
,
(
int
)
conn
->
content_len
,
conn
->
content
);
}
return
1
;
}
static
const
char
*
test_server
(
void
)
{
char
buf1
[
100
]
=
""
,
buf2
[
100
]
=
""
;
struct
mg_server
*
server
=
mg_create_server
((
void
*
)
"foo"
);
ASSERT
(
server
!=
NULL
);
...
...
@@ -440,34 +406,78 @@ static const char *test_server(void) {
ASSERT
(
mg_set_option
(
server
,
"document_root"
,
"."
)
==
NULL
);
mg_add_uri_handler
(
server
,
"/cb1"
,
cb1
);
mg_set_http_error_handler
(
server
,
error_handler
);
mg_start_thread
(
server_thread
,
server
);
RUN_TEST
(
test_regular_file
);
RUN_TEST
(
test_server_param
);
RUN_TEST
(
test_error_handler
);
// TODO(lsm): come up with a better way of thread sync
sleep
(
1
);
ASSERT
(
mg_connect
(
server
,
"127.0.0.1"
,
atoi
(
HTTP_PORT
),
ts1
,
buf1
)
==
1
);
ASSERT
(
mg_connect
(
server
,
"127.0.0.1"
,
atoi
(
HTTP_PORT
),
ts2
,
buf2
)
==
1
);
ASSERT
(
strcmp
(
static_config_options
[
URL_REWRITES
*
2
],
"url_rewrites"
)
==
0
);
{
int
i
;
for
(
i
=
0
;
i
<
50
;
i
++
)
mg_poll_server
(
server
,
0
);
}
ASSERT
(
strcmp
(
buf1
,
"foo ? 127.0.0.1"
)
==
0
);
ASSERT
(
strcmp
(
buf2
,
"404 ERR: 404"
)
==
0
);
ASSERT
(
strcmp
(
static_config_options
[
URL_REWRITES
*
2
],
"url_rewrites"
)
==
0
);
mg_destroy_server
(
&
server
);
ASSERT
(
server
==
NULL
);
return
NULL
;
}
// This http client sends two requests using one connection
static
int
cb2
(
struct
mg_connection
*
conn
)
{
(
void
)
conn
;
return
0
;
const
char
*
file1
=
"mongoose.h"
,
*
file2
=
"mongoose.c"
,
*
file_name
=
file2
;
char
*
buf
=
(
char
*
)
conn
->
connection_param
,
*
file_data
;
int
file_len
,
ret_val
=
1
;
switch
(
conn
->
status_code
)
{
case
MG_CONNECT_SUCCESS
:
mg_printf
(
conn
,
"GET /%s HTTP/1.1
\r\n\r\n
"
,
file1
);
strcat
(
buf
,
"a"
);
ret_val
=
0
;
break
;
case
MG_CONNECT_FAILURE
:
strcat
(
buf
,
"b"
);
break
;
case
MG_DOWNLOAD_FAILURE
:
strcat
(
buf
,
"c"
);
break
;
case
MG_DOWNLOAD_SUCCESS
:
if
(
!
strcmp
(
buf
,
"a"
))
{
// Send second request
mg_printf
(
conn
,
"GET /%s HTTP/1.1
\r\n\r\n
"
,
file2
);
file_name
=
file1
;
}
if
((
file_data
=
read_file
(
file_name
,
&
file_len
))
!=
NULL
)
{
if
(
file_len
==
conn
->
content_len
&&
memcmp
(
file_data
,
conn
->
content
,
file_len
)
==
0
)
{
strcat
(
buf
,
"d"
);
}
else
{
strcat
(
buf
,
"f"
);
}
free
(
file_data
);
}
ret_val
=
!
strcmp
(
buf
,
"ad"
)
?
0
:
1
;
break
;
default:
strcat
(
buf
,
"e"
);
break
;
}
return
ret_val
;
}
static
int
cb3
(
struct
mg_connection
*
conn
)
{
sprintf
((
char
*
)
conn
->
connection_param
,
"%d"
,
conn
->
status_code
);
return
1
;
}
static
const
char
*
test_mg_connect
(
void
)
{
char
buf
[
1000
]
;
struct
mg_server
*
server
=
mg_create_server
(
buf
);
//mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), cb2);
char
buf
2
[
40
]
=
""
,
buf3
[
40
]
=
""
;
struct
mg_server
*
server
=
mg_create_server
(
NULL
);
ASSERT
(
mg_set_option
(
server
,
"listening_port"
,
LISTENING_ADDR
)
==
NULL
);
ASSERT
(
mg_set_option
(
server
,
"document_root"
,
"."
)
==
NULL
);
mg_add_uri_handler
(
server
,
"/cb1"
,
cb2
);
ASSERT
(
mg_connect
(
server
,
""
,
0
,
NULL
,
NULL
)
==
0
);
ASSERT
(
mg_connect
(
server
,
"127.0.0.1"
,
atoi
(
HTTP_PORT
),
cb2
,
buf2
)
==
1
);
ASSERT
(
mg_connect
(
server
,
"127.0.0.1"
,
1
,
cb3
,
buf3
)
==
1
);
{
int
i
;
for
(
i
=
0
;
i
<
50
;
i
++
)
mg_poll_server
(
server
,
0
);
}
ASSERT
(
strcmp
(
buf2
,
"add"
)
==
0
);
ASSERT
(
strcmp
(
buf3
,
"1"
)
==
0
);
mg_destroy_server
(
&
server
);
return
NULL
;
}
...
...
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