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
ee55d38b
Commit
ee55d38b
authored
Feb 01, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
API CHANGE: using struct mg_callbacks
parent
62162ff3
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
284 additions
and
386 deletions
+284
-386
chat.c
examples/chat.c
+20
-26
hello.c
examples/hello.c
+35
-21
post.c
examples/post.c
+30
-35
upload.c
examples/upload.c
+29
-27
websocket.c
examples/websocket.c
+46
-45
main.c
main.c
+8
-9
mongoose.c
mongoose.c
+54
-59
mongoose.h
mongoose.h
+13
-115
test.pl
test/test.pl
+1
-1
unit_test.c
test/unit_test.c
+48
-48
No files found.
examples/chat.c
View file @
ee55d38b
...
...
@@ -325,34 +325,25 @@ static void redirect_to_ssl(struct mg_connection *conn,
}
}
static
void
*
event_handler
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
void
*
processed
=
"yes"
;
if
(
event
==
MG_NEW_REQUEST
)
{
if
(
!
request_info
->
is_ssl
)
{
redirect_to_ssl
(
conn
,
request_info
);
}
else
if
(
!
is_authorized
(
conn
,
request_info
))
{
redirect_to_login
(
conn
,
request_info
);
}
else
if
(
strcmp
(
request_info
->
uri
,
authorize_url
)
==
0
)
{
authorize
(
conn
,
request_info
);
}
else
if
(
strcmp
(
request_info
->
uri
,
"/ajax/get_messages"
)
==
0
)
{
ajax_get_messages
(
conn
,
request_info
);
}
else
if
(
strcmp
(
request_info
->
uri
,
"/ajax/send_message"
)
==
0
)
{
ajax_send_message
(
conn
,
request_info
);
}
else
{
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
processed
=
NULL
;
}
}
else
if
(
event
==
MG_EVENT_LOG
)
{
printf
(
"%s
\n
"
,
(
const
char
*
)
mg_get_request_info
(
conn
)
->
ev_data
);
processed
=
NULL
;
int
processed
=
1
;
if
(
!
request_info
->
is_ssl
)
{
redirect_to_ssl
(
conn
,
request_info
);
}
else
if
(
!
is_authorized
(
conn
,
request_info
))
{
redirect_to_login
(
conn
,
request_info
);
}
else
if
(
strcmp
(
request_info
->
uri
,
authorize_url
)
==
0
)
{
authorize
(
conn
,
request_info
);
}
else
if
(
strcmp
(
request_info
->
uri
,
"/ajax/get_messages"
)
==
0
)
{
ajax_get_messages
(
conn
,
request_info
);
}
else
if
(
strcmp
(
request_info
->
uri
,
"/ajax/send_message"
)
==
0
)
{
ajax_send_message
(
conn
,
request_info
);
}
else
{
processed
=
NULL
;
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
processed
=
0
;
}
return
processed
;
}
...
...
@@ -365,6 +356,7 @@ static const char *options[] = {
};
int
main
(
void
)
{
struct
mg_callbacks
callbacks
;
struct
mg_context
*
ctx
;
// Initialize random number generator. It will be used later on for
...
...
@@ -372,7 +364,9 @@ int main(void) {
srand
((
unsigned
)
time
(
0
));
// Setup and start Mongoose
if
((
ctx
=
mg_start
(
&
event_handler
,
NULL
,
options
))
==
NULL
)
{
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
if
((
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
))
==
NULL
)
{
printf
(
"%s
\n
"
,
"Cannot start chat server, fatal exit"
);
exit
(
EXIT_FAILURE
);
}
...
...
examples/hello.c
View file @
ee55d38b
...
...
@@ -2,35 +2,49 @@
#include <string.h>
#include "mongoose.h"
static
void
*
callback
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
// This function will be called by mongoose on every new request.
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
char
content
[
100
];
if
(
event
==
MG_NEW_REQUEST
)
{
char
content
[
1024
];
int
content_length
=
snprintf
(
content
,
sizeof
(
content
)
,
"Hello from mongoose! Remote port: %d"
,
request_info
->
remote_port
);
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Type: text/plain
\r\n
"
"Content-Length: %d
\r\n
"
// Always set Content-Length
"
\r\n
"
"%s"
,
content_length
,
content
);
// Mark as processed
return
""
;
}
else
{
return
NULL
;
}
// Prepare the message we're going to send
int
content_length
=
snprintf
(
content
,
sizeof
(
content
),
"Hello from mongoose! Remote port: %d"
,
request_info
->
remote_port
);
// Send HTTP reply to the client
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Type: text/plain
\r\n
"
"Content-Length: %d
\r\n
"
// Always set Content-Length
"
\r\n
"
"%s"
,
content_length
,
content
);
// Returning non-zero tells mongoose that our function has replied to
// the client, and mongoose should not send client any more data.
return
1
;
}
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_callbacks
callbacks
;
// List of options. Last element must be NULL.
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
ctx
=
mg_start
(
&
callback
,
NULL
,
options
);
getchar
();
// Wait until user hits "enter"
// Prepare callbacks structure. We have only one callback, the rest are NULL.
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
// Start the web server.
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
// Wait until user hits "enter". Server is running in separate thread.
// Navigating to http://localhost:8080 will invoke begin_request_handler().
getchar
();
// Stop the server.
mg_stop
(
ctx
);
return
0
;
...
...
examples/post.c
View file @
ee55d38b
...
...
@@ -10,50 +10,45 @@ static const char *html_form =
"<input type=
\"
submit
\"
/>"
"</form></body></html>"
;
static
void
*
callback
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
if
(
event
==
MG_NEW_REQUEST
)
{
if
(
!
strcmp
(
ri
->
uri
,
"/handle_post_request"
))
{
// User has submitted a form, show submitted data and a variable value
char
post_data
[
1024
],
input1
[
sizeof
(
post_data
)],
input2
[
sizeof
(
post_data
)];
int
post_data_len
;
// Read POST data
post_data_len
=
mg_read
(
conn
,
post_data
,
sizeof
(
post_data
));
// Parse form data. input1 and input2 are guaranteed to be NUL-terminated
mg_get_var
(
post_data
,
post_data_len
,
"input_1"
,
input1
,
sizeof
(
input1
));
mg_get_var
(
post_data
,
post_data_len
,
"input_2"
,
input2
,
sizeof
(
input2
));
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"Submitted data: [%.*s]
\n
"
"Submitted data length: %d bytes
\n
"
"input_1: [%s]
\n
"
"input_2: [%s]
\n
"
,
post_data_len
,
post_data
,
post_data_len
,
input1
,
input2
);
}
else
{
// Show HTML form.
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/html
\r\n\r\n
%s"
,
(
int
)
strlen
(
html_form
),
html_form
);
}
// Mark as processed
return
""
;
char
post_data
[
1024
],
input1
[
sizeof
(
post_data
)],
input2
[
sizeof
(
post_data
)];
int
post_data_len
;
if
(
!
strcmp
(
ri
->
uri
,
"/handle_post_request"
))
{
// User has submitted a form, show submitted data and a variable value
post_data_len
=
mg_read
(
conn
,
post_data
,
sizeof
(
post_data
));
// Parse form data. input1 and input2 are guaranteed to be NUL-terminated
mg_get_var
(
post_data
,
post_data_len
,
"input_1"
,
input1
,
sizeof
(
input1
));
mg_get_var
(
post_data
,
post_data_len
,
"input_2"
,
input2
,
sizeof
(
input2
));
// Send reply to the client, showing submitted form values.
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"Submitted data: [%.*s]
\n
"
"Submitted data length: %d bytes
\n
"
"input_1: [%s]
\n
"
"input_2: [%s]
\n
"
,
post_data_len
,
post_data
,
post_data_len
,
input1
,
input2
);
}
else
{
return
NULL
;
// Show HTML form.
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/html
\r\n\r\n
%s"
,
(
int
)
strlen
(
html_form
),
html_form
);
}
return
1
;
// Mark request as processed
}
int
main
(
void
)
{
struct
mg_context
*
ctx
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
struct
mg_callbacks
callbacks
;
ctx
=
mg_start
(
&
callback
,
NULL
,
options
);
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
...
...
examples/upload.c
View file @
ee55d38b
...
...
@@ -17,42 +17,44 @@ typedef __int64 int64_t;
#include "mongoose.h"
static
void
*
callback
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
if
(
event
==
MG_NEW_REQUEST
)
{
if
(
!
strcmp
(
mg_get_request_info
(
conn
)
->
uri
,
"/handle_post_request"
))
{
mg_printf
(
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n\r\n
"
);
mg_upload
(
conn
,
"/tmp"
);
}
else
{
// Show HTML form. Make sure it has enctype="multipart/form-data" attr.
static
const
char
*
html_form
=
"<html><body>Upload example."
"<form method=
\"
POST
\"
action=
\"
/handle_post_request
\"
"
" enctype=
\"
multipart/form-data
\"
>"
"<input type=
\"
file
\"
name=
\"
file
\"
/> <br/>"
"<input type=
\"
submit
\"
value=
\"
Upload
\"
/>"
"</form></body></html>"
;
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/html
\r\n\r\n
%s"
,
(
int
)
strlen
(
html_form
),
html_form
);
}
// Mark as processed
return
""
;
}
else
if
(
event
==
MG_UPLOAD
)
{
mg_printf
(
conn
,
"Saved [%s]"
,
mg_get_request_info
(
conn
)
->
ev_data
);
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
if
(
!
strcmp
(
mg_get_request_info
(
conn
)
->
uri
,
"/handle_post_request"
))
{
mg_printf
(
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n\r\n
"
);
mg_upload
(
conn
,
"/tmp"
);
}
else
{
// Show HTML form. Make sure it has enctype="multipart/form-data" attr.
static
const
char
*
html_form
=
"<html><body>Upload example."
"<form method=
\"
POST
\"
action=
\"
/handle_post_request
\"
"
" enctype=
\"
multipart/form-data
\"
>"
"<input type=
\"
file
\"
name=
\"
file
\"
/> <br/>"
"<input type=
\"
submit
\"
value=
\"
Upload
\"
/>"
"</form></body></html>"
;
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/html
\r\n\r\n
%s"
,
(
int
)
strlen
(
html_form
),
html_form
);
}
return
NULL
;
// Mark request as processed
return
1
;
}
static
void
upload_handler
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
mg_printf
(
conn
,
"Saved [%s]"
,
path
);
}
int
main
(
void
)
{
struct
mg_context
*
ctx
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
struct
mg_callbacks
callbacks
;
ctx
=
mg_start
(
&
callback
,
NULL
,
options
);
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
callbacks
.
upload
=
upload_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
getchar
();
// Wait until user hits "enter"
pause
();
mg_stop
(
ctx
);
return
0
;
...
...
examples/websocket.c
View file @
ee55d38b
...
...
@@ -5,69 +5,70 @@
#include <string.h>
#include "mongoose.h"
static
void
*
callback
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
if
(
event
==
MG_WEBSOCKET_READY
)
{
unsigned
char
buf
[
40
]
;
buf
[
0
]
=
0x81
;
buf
[
1
]
=
snprintf
((
char
*
)
buf
+
2
,
sizeof
(
buf
)
-
2
,
"%s"
,
"server ready"
);
mg_write
(
conn
,
buf
,
2
+
buf
[
1
]);
return
""
;
// MG_WEBSOCKET_READY return value is ignored
}
else
if
(
event
==
MG_WEBSOCKET_MESSAGE
)
{
unsigned
char
buf
[
200
],
reply
[
200
];
int
n
,
i
,
mask_len
,
xor
,
msg_len
,
len
;
static
void
websocket_ready_handler
(
struct
mg_connection
*
conn
)
{
unsigned
char
buf
[
40
];
buf
[
0
]
=
0x81
;
buf
[
1
]
=
snprintf
((
char
*
)
buf
+
2
,
sizeof
(
buf
)
-
2
,
"%s"
,
"server ready"
)
;
mg_write
(
conn
,
buf
,
2
+
buf
[
1
]
);
}
static
int
websocket_data_handler
(
struct
mg_connection
*
conn
)
{
unsigned
char
buf
[
200
],
reply
[
200
];
int
n
,
i
,
mask_len
,
xor
,
msg_len
,
len
;
// Read message from the client.
// Accept only small (<126 bytes) messages.
len
=
0
;
msg_len
=
mask_len
=
0
;
for
(;;)
{
if
((
n
=
mg_read
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
))
<=
0
)
{
return
""
;
// Read error, close websocket
// Read message from the client.
// Accept only small (<126 bytes) messages.
len
=
0
;
msg_len
=
mask_len
=
0
;
for
(;;)
{
if
((
n
=
mg_read
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
))
<=
0
)
{
return
0
;
// Read error, close websocket
}
len
+=
n
;
if
(
len
>=
2
)
{
msg_len
=
buf
[
1
]
&
127
;
mask_len
=
(
buf
[
1
]
&
128
)
?
4
:
0
;
if
(
msg_len
>
125
)
{
return
0
;
// Message is too long, close websocket
}
len
+=
n
;
if
(
len
>=
2
)
{
msg_len
=
buf
[
1
]
&
127
;
mask_len
=
(
buf
[
1
]
&
128
)
?
4
:
0
;
if
(
msg_len
>
125
)
{
return
""
;
// Message is too long, close websocket
}
// If we've buffered the whole message, exit the loop
if
(
len
>=
2
+
mask_len
+
msg_len
)
{
break
;
}
// If we've buffered the whole message, exit the loop
if
(
len
>=
2
+
mask_len
+
msg_len
)
{
break
;
}
}
}
// Prepare frame
reply
[
0
]
=
0x81
;
// text, FIN set
reply
[
1
]
=
msg_len
;
// Prepare frame
reply
[
0
]
=
0x81
;
// text, FIN set
reply
[
1
]
=
msg_len
;
// Copy message from request to reply, applying the mask if required.
for
(
i
=
0
;
i
<
msg_len
;
i
++
)
{
xor
=
mask_len
==
0
?
0
:
buf
[
2
+
(
i
%
4
)];
reply
[
i
+
2
]
=
buf
[
i
+
2
+
mask_len
]
^
xor
;
}
// Copy message from request to reply, applying the mask if required.
for
(
i
=
0
;
i
<
msg_len
;
i
++
)
{
xor
=
mask_len
==
0
?
0
:
buf
[
2
+
(
i
%
4
)];
reply
[
i
+
2
]
=
buf
[
i
+
2
+
mask_len
]
^
xor
;
}
// Echo the message back to the client
mg_write
(
conn
,
reply
,
2
+
msg_len
);
// Echo the message back to the client
mg_write
(
conn
,
reply
,
2
+
msg_len
);
// Return non-NULL means stoping websocket conversation.
// Close the conversation if client has sent us "exit" string.
return
memcmp
(
reply
+
2
,
"exit"
,
4
)
==
0
?
""
:
NULL
;
}
else
{
return
NULL
;
}
// Returnint zero means stoping websocket conversation.
// Close the conversation if client has sent us "exit" string.
return
memcmp
(
reply
+
2
,
"exit"
,
4
);
}
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_callbacks
callbacks
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
"document_root"
,
"websocket_html_root"
,
NULL
};
ctx
=
mg_start
(
&
callback
,
NULL
,
options
);
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
websocket_ready
=
websocket_ready_handler
;
callbacks
.
websocket_data
=
websocket_data_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
...
...
main.c
View file @
ee55d38b
...
...
@@ -266,17 +266,14 @@ static void init_server_name(void) {
mg_version
());
}
static
void
*
mongoose_callback
(
enum
mg_event
ev
,
struct
mg_connection
*
conn
)
{
if
(
ev
==
MG_EVENT_LOG
)
{
printf
(
"%s
\n
"
,
(
const
char
*
)
mg_get_request_info
(
conn
)
->
ev_data
);
}
// Returning NULL marks request as not handled, signalling mongoose to
// proceed with handling it.
return
NULL
;
static
int
log_message
(
const
struct
mg_connection
*
conn
,
const
char
*
message
)
{
(
void
)
conn
;
printf
(
"%s
\n
"
,
message
);
return
0
;
}
static
void
start_mongoose
(
int
argc
,
char
*
argv
[])
{
struct
mg_callbacks
callbacks
;
char
*
options
[
MAX_OPTIONS
];
int
i
;
...
...
@@ -302,7 +299,9 @@ static void start_mongoose(int argc, char *argv[]) {
signal
(
SIGINT
,
signal_handler
);
/* Start Mongoose */
ctx
=
mg_start
(
&
mongoose_callback
,
NULL
,
(
const
char
**
)
options
);
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
log_message
=
&
log_message
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
(
const
char
**
)
options
);
for
(
i
=
0
;
options
[
i
]
!=
NULL
;
i
++
)
{
free
(
options
[
i
]);
}
...
...
mongoose.c
View file @
ee55d38b
...
...
@@ -466,11 +466,11 @@ static const char *config_options[] = {
#define ENTRIES_PER_CONFIG_OPTION 3
struct
mg_context
{
volatile
int
stop_flag
;
// Should we stop event loop
SSL_CTX
*
ssl_ctx
;
// SSL context
char
*
config
[
NUM_OPTIONS
];
// Mongoose configuration parameters
mg_callback_t
user_callback
;
// User-defined callback function
void
*
user_data
;
// User-defined data
volatile
int
stop_flag
;
// Should we stop event loop
SSL_CTX
*
ssl_ctx
;
// SSL context
char
*
config
[
NUM_OPTIONS
];
// Mongoose configuration parameters
struct
mg_callbacks
callbacks
;
// User-defined callback function
void
*
user_data
;
// User-defined data
struct
socket
*
listening_sockets
;
int
num_listening_sockets
;
...
...
@@ -512,20 +512,12 @@ const char **mg_get_valid_option_names(void) {
return
config_options
;
}
static
void
*
call_user
(
struct
mg_connection
*
conn
,
enum
mg_event
event
)
{
if
(
conn
!=
NULL
&&
conn
->
ctx
!=
NULL
)
{
conn
->
request_info
.
user_data
=
conn
->
ctx
->
user_data
;
}
return
conn
==
NULL
||
conn
->
ctx
==
NULL
||
conn
->
ctx
->
user_callback
==
NULL
?
NULL
:
conn
->
ctx
->
user_callback
(
event
,
conn
);
}
static
int
is_file_in_memory
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
conn
->
request_info
.
ev_data
=
(
void
*
)
path
;
if
((
filep
->
membuf
=
call_user
(
conn
,
MG_OPEN_FILE
))
!=
NULL
)
{
filep
->
size
=
(
long
)
conn
->
request_info
.
ev_data
;
}
size_t
size
=
0
;
filep
->
membuf
=
conn
->
ctx
->
callbacks
.
open_file
==
NULL
?
NULL
:
conn
->
ctx
->
callbacks
.
open_file
(
conn
,
path
,
&
size
)
;
filep
->
size
=
size
;
return
filep
->
membuf
!=
NULL
;
}
...
...
@@ -610,8 +602,8 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
// Do not lock when getting the callback value, here and below.
// I suppose this is fine, since function cannot disappear in the
// same way string option can.
conn
->
request_info
.
ev_data
=
buf
;
if
(
call_user
(
conn
,
MG_EVENT_LOG
)
==
NULL
)
{
if
(
conn
->
ctx
->
callbacks
.
log_message
==
NULL
||
conn
->
ctx
->
callbacks
.
log_message
(
conn
,
buf
)
==
0
)
{
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
...
...
@@ -634,7 +626,6 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
fclose
(
fp
);
}
}
conn
->
request_info
.
ev_data
=
NULL
;
}
// Return fake connection structure. Used for logging, if connection
...
...
@@ -917,31 +908,27 @@ static void send_http_error(struct mg_connection *conn, int status,
const
char
*
reason
,
const
char
*
fmt
,
...)
{
char
buf
[
MG_BUF_LEN
];
va_list
ap
;
int
len
;
int
len
=
0
;
conn
->
status_code
=
status
;
conn
->
request_info
.
ev_data
=
(
void
*
)
(
long
)
status
;
if
(
call_user
(
conn
,
MG_HTTP_ERROR
)
==
NULL
)
{
buf
[
0
]
=
'\0'
;
len
=
0
;
// Errors 1xx, 204 and 304 MUST NOT send a body
if
(
status
>
199
&&
status
!=
204
&&
status
!=
304
)
{
len
=
mg_snprintf
(
conn
,
buf
,
sizeof
(
buf
),
"Error %d: %s"
,
status
,
reason
);
buf
[
len
++
]
=
'\n'
;
va_start
(
ap
,
fmt
);
len
+=
mg_vsnprintf
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
,
fmt
,
ap
);
va_end
(
ap
);
}
DEBUG_TRACE
((
"[%s]"
,
buf
));
buf
[
0
]
=
'\0'
;
mg_printf
(
conn
,
"HTTP/1.1 %d %s
\r\n
"
"Content-Length: %d
\r\n
"
"Connection: %s
\r\n\r\n
"
,
status
,
reason
,
len
,
suggest_connection_header
(
conn
));
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"%s"
,
buf
);
// Errors 1xx, 204 and 304 MUST NOT send a body
if
(
status
>
199
&&
status
!=
204
&&
status
!=
304
)
{
len
=
mg_snprintf
(
conn
,
buf
,
sizeof
(
buf
),
"Error %d: %s"
,
status
,
reason
);
buf
[
len
++
]
=
'\n'
;
va_start
(
ap
,
fmt
);
len
+=
mg_vsnprintf
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
,
fmt
,
ap
);
va_end
(
ap
);
}
DEBUG_TRACE
((
"[%s]"
,
buf
));
mg_printf
(
conn
,
"HTTP/1.1 %d %s
\r\n
"
"Content-Length: %d
\r\n
"
"Connection: %s
\r\n\r\n
"
,
status
,
reason
,
len
,
suggest_connection_header
(
conn
));
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"%s"
,
buf
);
}
#if defined(_WIN32) && !defined(__SYMBIAN32__)
...
...
@@ -2609,7 +2596,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
// print_dir_entry(). memset is required only if mg_stat()
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
// mg_stat will memset the whole struct file with zeroes.
memset
(
&
de
.
file
,
0
,
sizeof
(
de
.
file
));
mg_stat
(
conn
,
path
,
&
de
.
file
);
de
.
file_name
=
dp
->
d_name
;
...
...
@@ -3797,7 +3784,8 @@ static void read_websocket(struct mg_connection *conn) {
}
if
(
conn
->
content_len
>
0
)
{
if
(
call_user
(
conn
,
MG_WEBSOCKET_MESSAGE
)
!=
NULL
)
{
if
(
conn
->
ctx
->
callbacks
.
websocket_data
!=
NULL
&&
conn
->
ctx
->
callbacks
.
websocket_data
(
conn
)
==
0
)
{
break
;
// Callback signalled to exit
}
discard_len
=
conn
->
content_len
>
body_len
?
...
...
@@ -3819,13 +3807,15 @@ static void read_websocket(struct mg_connection *conn) {
static
void
handle_websocket_request
(
struct
mg_connection
*
conn
)
{
if
(
strcmp
(
mg_get_header
(
conn
,
"Sec-WebSocket-Version"
),
"13"
)
!=
0
)
{
send_http_error
(
conn
,
426
,
"Upgrade Required"
,
"%s"
,
"Upgrade Required"
);
}
else
if
(
call_user
(
conn
,
MG_WEBSOCKET_CONNECT
)
!=
NULL
)
{
// Callback has returned non-NULL, do not proceed with handshake
}
else
if
(
conn
->
ctx
->
callbacks
.
websocket_connect
!=
NULL
&&
conn
->
ctx
->
callbacks
.
websocket_connect
(
conn
)
!=
0
)
{
// Callback has returned non-zero, do not proceed with handshake
}
else
{
send_websocket_handshake
(
conn
);
call_user
(
conn
,
MG_WEBSOCKET_READY
);
if
(
conn
->
ctx
->
callbacks
.
websocket_ready
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
websocket_ready
(
conn
);
}
read_websocket
(
conn
);
call_user
(
conn
,
MG_WEBSOCKET_CLOSE
);
}
}
...
...
@@ -4035,8 +4025,9 @@ static void handle_lsp_request(struct mg_connection *conn, const char *path,
}
else
{
// We're not sending HTTP headers here, Lua page must do it.
prepare_lua_environment
(
conn
,
L
);
conn
->
request_info
.
ev_data
=
L
;
call_user
(
conn
,
MG_INIT_LUA
);
if
(
conn
->
ctx
->
callbacks
.
init_lua
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
init_lua
(
conn
,
L
);
}
lsp
(
conn
,
filep
->
membuf
==
NULL
?
p
:
filep
->
membuf
,
filep
->
size
,
L
);
}
...
...
@@ -4135,8 +4126,9 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
fwrite
(
buf
,
1
,
i
,
fp
);
fflush
(
fp
);
num_uploaded_files
++
;
conn
->
request_info
.
ev_data
=
(
void
*
)
path
;
call_user
(
conn
,
MG_UPLOAD
);
if
(
conn
->
ctx
->
callbacks
.
upload
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
upload
(
conn
,
path
);
}
memmove
(
buf
,
&
buf
[
i
+
bl
],
len
-
(
i
+
bl
));
len
-=
i
+
bl
;
break
;
...
...
@@ -4203,7 +4195,8 @@ static void handle_request(struct mg_connection *conn) {
get_remote_ip
(
conn
),
ri
->
uri
);
DEBUG_TRACE
((
"%s"
,
ri
->
uri
));
if
(
call_user
(
conn
,
MG_NEW_REQUEST
)
!=
NULL
)
{
if
(
conn
->
ctx
->
callbacks
.
begin_request
!=
NULL
&&
conn
->
ctx
->
callbacks
.
begin_request
(
conn
))
{
// Do nothing, callback has served the request
}
else
if
(
!
conn
->
client
.
is_ssl
&&
conn
->
client
.
ssl_redir
&&
(
ssl_index
=
get_first_ssl_listener_index
(
conn
->
ctx
))
>
-
1
)
{
...
...
@@ -4550,8 +4543,8 @@ static int set_ssl_option(struct mg_context *ctx) {
// If user callback returned non-NULL, that means that user callback has
// set up certificate itself. In this case, skip sertificate setting.
fc
(
ctx
)
->
request_info
.
ev_data
=
ctx
->
ssl_ctx
;
if
(
call_user
(
fc
(
ctx
),
MG_INIT_SSL
)
==
NULL
&&
if
((
ctx
->
callbacks
.
init_ssl
==
NULL
||
!
ctx
->
callbacks
.
init_ssl
(
ctx
->
ssl_ctx
))
&&
(
SSL_CTX_use_certificate_file
(
ctx
->
ssl_ctx
,
pem
,
1
)
==
0
||
SSL_CTX_use_PrivateKey_file
(
ctx
->
ssl_ctx
,
pem
,
1
)
==
0
))
{
cry
(
fc
(
ctx
),
"%s: cannot open %s: %s"
,
__func__
,
pem
,
ssl_error
());
...
...
@@ -4608,7 +4601,7 @@ static int set_acl_option(struct mg_context *ctx) {
}
static
void
reset_per_request_attributes
(
struct
mg_connection
*
conn
)
{
conn
->
path_info
=
conn
->
request_info
.
ev_data
=
NULL
;
conn
->
path_info
=
NULL
;
conn
->
num_bytes_sent
=
conn
->
consumed_content
=
0
;
conn
->
status_code
=
-
1
;
conn
->
must_close
=
conn
->
request_len
=
conn
->
throttle
=
0
;
...
...
@@ -4811,8 +4804,9 @@ static void process_new_connection(struct mg_connection *conn) {
if
(
ebuf
[
0
]
==
'\0'
)
{
handle_request
(
conn
);
conn
->
request_info
.
ev_data
=
(
void
*
)
(
long
)
conn
->
status_code
;
call_user
(
conn
,
MG_REQUEST_COMPLETE
);
if
(
conn
->
ctx
->
callbacks
.
end_request
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
end_request
(
conn
,
conn
->
status_code
);
}
log_access
(
conn
);
}
if
(
ri
->
remote_user
!=
NULL
)
{
...
...
@@ -5087,7 +5081,8 @@ void mg_stop(struct mg_context *ctx) {
#endif // _WIN32
}
struct
mg_context
*
mg_start
(
mg_callback_t
user_callback
,
void
*
user_data
,
struct
mg_context
*
mg_start
(
const
struct
mg_callbacks
*
callbacks
,
void
*
user_data
,
const
char
**
options
)
{
struct
mg_context
*
ctx
;
const
char
*
name
,
*
value
,
*
default_value
;
...
...
@@ -5104,7 +5099,7 @@ struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,
if
((
ctx
=
(
struct
mg_context
*
)
calloc
(
1
,
sizeof
(
*
ctx
)))
==
NULL
)
{
return
NULL
;
}
ctx
->
user_callback
=
user_callback
;
ctx
->
callbacks
=
*
callbacks
;
ctx
->
user_data
=
user_data
;
while
(
options
&&
(
name
=
*
options
++
)
!=
NULL
)
{
...
...
mongoose.h
View file @
ee55d38b
...
...
@@ -42,13 +42,13 @@ struct mg_request_info {
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 headers
void
*
user_data
;
// User data pointer passed to mg_start()
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
*
user_data
;
// User data pointer passed to mg_start()
void
*
ev_data
;
// Event-specific data pointer
};
...
...
@@ -56,126 +56,23 @@ struct mg_request_info {
// which callbacks to invoke. For detailed description, see
// https://github.com/valenok/mongoose/blob/master/UserManual.md
struct
mg_callbacks
{
int
(
*
request_star
t
)(
struct
mg_connection
*
);
void
(
*
request_done
)(
struct
mg_connection
*
,
int
reply_status_code
);
int
(
*
log_message
)(
struct
mg_connection
*
,
const
char
*
message
);
int
(
*
begin_reques
t
)(
struct
mg_connection
*
);
void
(
*
end_request
)(
const
struct
mg_connection
*
,
int
reply_status_code
);
int
(
*
log_message
)(
const
struct
mg_connection
*
,
const
char
*
message
);
int
(
*
init_ssl
)(
void
*
ssl_context
);
void
(
*
websocket_connect
)(
struct
mg_connection
*
);
int
(
*
websocket_connect
)(
const
struct
mg_connection
*
);
void
(
*
websocket_ready
)(
struct
mg_connection
*
);
int
(
*
websocket_data
)(
struct
mg_connection
*
);
void
(
*
websocket_close
)(
struct
mg_connection
*
);
void
(
*
open_file
)(
struct
mg_connection
*
,
char
**
data
,
size_t
*
data_len
);
const
char
*
(
*
open_file
)(
const
struct
mg_connection
*
,
const
char
*
path
,
size_t
*
data_len
);
void
(
*
init_lua
)(
struct
mg_connection
*
,
void
*
lua_context
);
void
(
*
upload
)(
struct
mg_connection
*
,
const
char
*
file_name
);
};
// Various events on which user-defined callback function is called by Mongoose.
enum
mg_event
{
// New HTTP request has arrived from the client.
// If callback returns non-NULL, Mongoose stops handling current request.
// ev_data contains NULL.
MG_NEW_REQUEST
,
// Mongoose has finished handling the request.
// Callback return value is ignored.
// ev_data contains integer HTTP status code:
// int http_reply_status_code = (long) request_info->ev_data;
MG_REQUEST_COMPLETE
,
// HTTP error must be returned to the client.
// If callback returns non-NULL, Mongoose stops handling error.
// ev_data contains HTTP error code:
// int http_reply_status_code = (long) request_info->ev_data;
MG_HTTP_ERROR
,
// Mongoose logs a message.
// If callback returns non-NULL, Mongoose stops handling that event.
// ev_data contains a message to be logged:
// const char *log_message = request_info->ev_data;
MG_EVENT_LOG
,
// SSL initialization, sent before certificate setup.
// If callback returns non-NULL, Mongoose does not set up certificates.
// ev_data contains server's OpenSSL context:
// SSL_CTX *ssl_context = request_info->ev_data;
MG_INIT_SSL
,
// Sent on HTTP connect, before websocket handshake.
// If user callback returns NULL, then mongoose proceeds
// with handshake, otherwise it closes the connection.
// ev_data contains NULL.
MG_WEBSOCKET_CONNECT
,
// Handshake has been successfully completed.
// Callback's return value is ignored.
// ev_data contains NULL.
MG_WEBSOCKET_READY
,
// Incoming message from the client, data could be read with mg_read().
// If user callback returns non-NULL, mongoose closes the websocket.
// ev_data contains NULL.
MG_WEBSOCKET_MESSAGE
,
// Client has closed the connection.
// Callback's return value is ignored.
// ev_data contains NULL.
MG_WEBSOCKET_CLOSE
,
// Mongoose tries to open file.
// If callback returns non-NULL, Mongoose will not try to open it, but
// will use the returned value as a pointer to the file data. This allows
// for example to serve files from memory.
// ev_data contains file path, including document root path.
// Upon return, ev_data should return file size, which should be a long int.
//
// const char *file_name = request_info->ev_data;
// if (strcmp(file_name, "foo.txt") == 0) {
// request_info->ev_data = (void *) (long) 4;
// return "data";
// }
// return NULL;
//
// Note that this even is sent multiple times during one request. Each
// time mongoose tries to open or stat the file, this event is sent, e.g.
// for opening .htpasswd file, stat-ting requested file, opening requested
// file, etc.
MG_OPEN_FILE
,
// Mongoose initializes Lua server page. Sent only if Lua support is enabled.
// Callback's return value is ignored.
// ev_data contains lua_State pointer.
MG_INIT_LUA
,
// Mongoose has uploaded file to a temporary directory.
// Callback's return value is ignored.
// ev_data contains NUL-terminated file name.
MG_UPLOAD
,
};
// Prototype for the user-defined function. Mongoose calls this function
// on every MG_* event.
//
// Parameters:
// event: which event has been triggered.
// conn: opaque connection handler. Could be used to read, write data to the
// client, etc. See functions below that have "mg_connection *" arg.
//
// Return:
// If handler returns non-NULL, that means that handler has processed the
// request by sending appropriate HTTP reply to the client. Mongoose treats
// the request as served.
// If handler returns NULL, that means that handler has not processed
// the request. Handler must not send any data to the client in this case.
// Mongoose proceeds with request handling as if nothing happened.
typedef
void
*
(
*
mg_callback_t
)(
enum
mg_event
event
,
struct
mg_connection
*
conn
);
// Start web server.
//
// Parameters:
// callback
: user defined event handling function or NULL
.
// callback
s: mg_callbacks structure with user-defined callbacks
.
// options: NULL terminated list of option_name, option_value pairs that
// specify Mongoose configuration parameters.
//
...
...
@@ -197,8 +94,9 @@ typedef void *(*mg_callback_t)(enum mg_event event, struct mg_connection *conn);
//
// Return:
// web server context, or NULL on error.
struct
mg_context
*
mg_start
(
mg_callback_t
callback
,
void
*
user_data
,
const
char
**
options
);
struct
mg_context
*
mg_start
(
const
struct
mg_callbacks
*
callbacks
,
void
*
user_data
,
const
char
**
configuration_options
);
// Stop the web server.
...
...
test/test.pl
View file @
ee55d38b
...
...
@@ -426,7 +426,7 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
do_PUT_test
();
kill_spawned_child
();
do_unit_test
();
do_embedded_test
();
#
do_embedded_test();
}
sub
do_PUT_test
{
...
...
test/unit_test.c
View file @
ee55d38b
...
...
@@ -189,44 +189,61 @@ static const char *inmemory_file_data = "hi there";
static
const
char
*
upload_filename
=
"upload_test.txt"
;
static
const
char
*
upload_ok_message
=
"upload successful"
;
static
void
*
event_handler
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
static
const
char
*
open_file_cb
(
const
struct
mg_connection
*
conn
,
const
char
*
path
,
size_t
*
size
)
{
(
void
)
conn
;
if
(
!
strcmp
(
path
,
"./blah"
))
{
*
size
=
strlen
(
inmemory_file_data
);
return
inmemory_file_data
;
}
return
NULL
;
}
static
void
upload_cb
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
char
*
p1
,
*
p2
;
int
len1
,
len2
;
ASSERT
(
!
strcmp
(
path
,
"./upload_test.txt"
));
ASSERT
((
p1
=
read_file
(
"mongoose.c"
,
&
len1
))
!=
NULL
);
ASSERT
((
p2
=
read_file
(
path
,
&
len2
))
!=
NULL
);
ASSERT
(
len1
==
len2
);
ASSERT
(
memcmp
(
p1
,
p2
,
len1
)
==
0
);
free
(
p1
),
free
(
p2
);
remove
(
upload_filename
);
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
Content-Length: %d
\r\n\r\n
%s"
,
(
int
)
strlen
(
upload_ok_message
),
upload_ok_message
);
}
static
int
begin_request_handler_cb
(
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
if
(
event
==
MG_NEW_REQUEST
&&
!
strcmp
(
request_info
->
uri
,
"/data"
))
{
if
(
!
strcmp
(
ri
->
uri
,
"/data"
))
{
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"%s"
,
(
int
)
strlen
(
fetch_data
),
fetch_data
);
return
""
;
}
else
if
(
event
==
MG_NEW_REQUEST
&&
!
strcmp
(
request_info
->
uri
,
"/upload"
))
{
return
1
;
}
if
(
!
strcmp
(
ri
->
uri
,
"/upload"
))
{
ASSERT
(
mg_upload
(
conn
,
"."
)
==
1
);
}
else
if
(
event
==
MG_OPEN_FILE
)
{
const
char
*
path
=
request_info
->
ev_data
;
if
(
strcmp
(
path
,
"./blah"
)
==
0
)
{
mg_get_request_info
(
conn
)
->
ev_data
=
(
void
*
)
(
long
)
strlen
(
inmemory_file_data
);
return
(
void
*
)
inmemory_file_data
;
}
}
else
if
(
event
==
MG_EVENT_LOG
)
{
}
else
if
(
event
==
MG_UPLOAD
)
{
char
*
p1
,
*
p2
;
int
len1
,
len2
;
ASSERT
(
!
strcmp
((
char
*
)
request_info
->
ev_data
,
"./upload_test.txt"
));
ASSERT
((
p1
=
read_file
(
"mongoose.c"
,
&
len1
))
!=
NULL
);
ASSERT
((
p2
=
read_file
(
upload_filename
,
&
len2
))
!=
NULL
);
ASSERT
(
len1
==
len2
);
ASSERT
(
memcmp
(
p1
,
p2
,
len1
)
==
0
);
free
(
p1
),
free
(
p2
);
remove
(
upload_filename
);
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
Content-Length: %d
\r\n\r\n
%s"
,
(
int
)
strlen
(
upload_ok_message
),
upload_ok_message
);
}
return
NULL
;
return
0
;
}
static
int
log_message_cb
(
const
struct
mg_connection
*
conn
,
const
char
*
msg
)
{
(
void
)
conn
;
printf
(
"%s
\n
"
,
msg
);
return
0
;
}
static
const
struct
mg_callbacks
CALLBACKS
=
{
&
begin_request_handler_cb
,
NULL
,
&
log_message_cb
,
NULL
,
NULL
,
NULL
,
NULL
,
&
open_file_cb
,
NULL
,
&
upload_cb
};
static
const
char
*
OPTIONS
[]
=
{
"document_root"
,
"."
,
"listening_ports"
,
LISTENING_ADDR
,
...
...
@@ -252,7 +269,7 @@ static void test_mg_download(void) {
struct
mg_connection
*
conn
;
struct
mg_context
*
ctx
;
ASSERT
((
ctx
=
mg_start
(
event_handler
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
&
CALLBACKS
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
(
mg_download
(
NULL
,
port
,
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
""
)
==
NULL
);
ASSERT
(
mg_download
(
"localhost"
,
0
,
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
""
)
==
NULL
);
...
...
@@ -323,7 +340,7 @@ static void test_mg_upload(void) {
char
ebuf
[
100
],
buf
[
20
],
*
file_data
,
*
post_data
=
NULL
;
int
file_len
,
post_data_len
;
ASSERT
((
ctx
=
mg_start
(
event_handler
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
&
CALLBACKS
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
file_data
=
read_file
(
"mongoose.c"
,
&
file_len
))
!=
NULL
);
post_data_len
=
alloc_printf
(
&
post_data
,
0
,
"--%s
\r\n
"
...
...
@@ -462,22 +479,6 @@ static void test_lua(void) {
}
#endif
static
void
*
user_data_tester
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
ASSERT
(
ri
->
user_data
==
(
void
*
)
123
);
ASSERT
(
event
==
MG_NEW_REQUEST
||
event
==
MG_INIT_SSL
);
return
NULL
;
}
static
void
test_user_data
(
void
)
{
struct
mg_context
*
ctx
;
ASSERT
((
ctx
=
mg_start
(
user_data_tester
,
(
void
*
)
123
,
OPTIONS
))
!=
NULL
);
ASSERT
(
ctx
->
user_data
==
(
void
*
)
123
);
call_user
(
fc
(
ctx
),
MG_NEW_REQUEST
);
mg_stop
(
ctx
);
}
static
void
test_mg_stat
(
void
)
{
static
struct
mg_context
ctx
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
...
...
@@ -529,7 +530,7 @@ static void test_request_replies(void) {
{
NULL
,
NULL
},
};
ASSERT
((
ctx
=
mg_start
(
event_handler
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
&
CALLBACKS
,
NULL
,
OPTIONS
))
!=
NULL
);
for
(
i
=
0
;
tests
[
i
].
request
!=
NULL
;
i
++
)
{
ASSERT
((
conn
=
mg_download
(
"localhost"
,
port
,
1
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
tests
[
i
].
request
))
!=
NULL
);
...
...
@@ -549,7 +550,6 @@ int __cdecl main(void) {
test_mg_get_var
();
test_set_throttle
();
test_next_option
();
test_user_data
();
test_mg_stat
();
test_skip_quoted
();
test_mg_upload
();
...
...
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