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
ecbf7913
Commit
ecbf7913
authored
Sep 28, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored API, returned back to event-based handlers. Upload and Websocket API simplified
parent
96eb4890
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
338 additions
and
418 deletions
+338
-418
main.c
build/main.c
+5
-7
chat.c
examples/chat.c
+10
-9
hello.c
examples/hello.c
+11
-11
post.c
examples/post.c
+13
-11
upload.c
examples/upload.c
+17
-26
websocket.c
examples/websocket.c
+35
-21
mongoose.c
mongoose.c
+148
-165
mongoose.h
mongoose.h
+33
-42
unit_test.c
test/unit_test.c
+66
-126
No files found.
build/main.c
View file @
ecbf7913
...
@@ -271,9 +271,10 @@ static void init_server_name(void) {
...
@@ -271,9 +271,10 @@ static void init_server_name(void) {
mg_version
());
mg_version
());
}
}
static
int
log_message
(
const
struct
mg_connection
*
conn
,
const
char
*
message
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
(
void
)
conn
;
if
(
event
->
type
==
MG_EVENT_LOG
)
{
printf
(
"%s
\n
"
,
message
);
printf
(
"%s
\n
"
,
(
const
char
*
)
event
->
event_param
);
}
return
0
;
return
0
;
}
}
...
@@ -341,7 +342,6 @@ static void set_absolute_path(char *options[], const char *option_name,
...
@@ -341,7 +342,6 @@ static void set_absolute_path(char *options[], const char *option_name,
}
}
static
void
start_mongoose
(
int
argc
,
char
*
argv
[])
{
static
void
start_mongoose
(
int
argc
,
char
*
argv
[])
{
struct
mg_callbacks
callbacks
;
char
*
options
[
MAX_OPTIONS
];
char
*
options
[
MAX_OPTIONS
];
int
i
;
int
i
;
...
@@ -385,9 +385,7 @@ static void start_mongoose(int argc, char *argv[]) {
...
@@ -385,9 +385,7 @@ static void start_mongoose(int argc, char *argv[]) {
signal
(
SIGINT
,
signal_handler
);
signal
(
SIGINT
,
signal_handler
);
// Start Mongoose
// Start Mongoose
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
ctx
=
mg_start
((
const
char
**
)
options
,
event_handler
,
NULL
);
callbacks
.
log_message
=
&
log_message
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
(
const
char
**
)
options
);
for
(
i
=
0
;
options
[
i
]
!=
NULL
;
i
++
)
{
for
(
i
=
0
;
options
[
i
]
!=
NULL
;
i
++
)
{
free
(
options
[
i
]);
free
(
options
[
i
]);
}
}
...
...
examples/chat.c
View file @
ecbf7913
...
@@ -326,9 +326,12 @@ static void redirect_to_ssl(struct mg_connection *conn,
...
@@ -326,9 +326,12 @@ static void redirect_to_ssl(struct mg_connection *conn,
}
}
}
}
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
struct
mg_request_info
*
request_info
=
event
->
request_info
;
int
processed
=
1
;
struct
mg_connection
*
conn
=
event
->
conn
;
int
result
=
1
;
if
(
event
->
type
!=
MG_REQUEST_BEGIN
)
return
0
;
if
(
!
request_info
->
is_ssl
)
{
if
(
!
request_info
->
is_ssl
)
{
redirect_to_ssl
(
conn
,
request_info
);
redirect_to_ssl
(
conn
,
request_info
);
...
@@ -343,9 +346,10 @@ static int begin_request_handler(struct mg_connection *conn) {
...
@@ -343,9 +346,10 @@ static int begin_request_handler(struct mg_connection *conn) {
}
else
{
}
else
{
// No suitable handler found, mark as not processed. Mongoose will
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
// try to serve the request.
processed
=
0
;
result
=
0
;
}
}
return
processed
;
return
result
;
}
}
static
const
char
*
options
[]
=
{
static
const
char
*
options
[]
=
{
...
@@ -357,7 +361,6 @@ static const char *options[] = {
...
@@ -357,7 +361,6 @@ static const char *options[] = {
};
};
int
main
(
void
)
{
int
main
(
void
)
{
struct
mg_callbacks
callbacks
;
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
// Initialize random number generator. It will be used later on for
// Initialize random number generator. It will be used later on for
...
@@ -365,9 +368,7 @@ int main(void) {
...
@@ -365,9 +368,7 @@ int main(void) {
srand
((
unsigned
)
time
(
0
));
srand
((
unsigned
)
time
(
0
));
// Setup and start Mongoose
// Setup and start Mongoose
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
if
((
ctx
=
mg_start
(
options
,
event_handler
,
NULL
))
==
NULL
)
{
callbacks
.
begin_request
=
begin_request_handler
;
if
((
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
))
==
NULL
)
{
printf
(
"%s
\n
"
,
"Cannot start chat server, fatal exit"
);
printf
(
"%s
\n
"
,
"Cannot start chat server, fatal exit"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
...
...
examples/hello.c
View file @
ecbf7913
...
@@ -3,17 +3,18 @@
...
@@ -3,17 +3,18 @@
#include "mongoose.h"
#include "mongoose.h"
// This function will be called by mongoose on every new request.
// This function will be called by mongoose on every new request.
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
char
content
[
100
];
char
content
[
100
];
// Prepare the message we're going to send
// Prepare the message we're going to send
int
content_length
=
snprintf
(
content
,
sizeof
(
content
),
int
content_length
=
snprintf
(
content
,
sizeof
(
content
),
"Hello from mongoose! Remote port: %d
"
,
"Hello from mongoose! Requested: [%s] [%s]
"
,
request_info
->
remote_port
);
event
->
request_info
->
request_method
,
event
->
request_info
->
uri
);
// Send HTTP reply to the client
// Send HTTP reply to the client
mg_printf
(
conn
,
mg_printf
(
event
->
conn
,
"HTTP/1.1 200 OK
\r\n
"
"HTTP/1.1 200 OK
\r\n
"
"Content-Type: text/plain
\r\n
"
"Content-Type: text/plain
\r\n
"
"Content-Length: %d
\r\n
"
// Always set Content-Length
"Content-Length: %d
\r\n
"
// Always set Content-Length
...
@@ -24,21 +25,20 @@ static int begin_request_handler(struct mg_connection *conn) {
...
@@ -24,21 +25,20 @@ static int begin_request_handler(struct mg_connection *conn) {
// Returning non-zero tells mongoose that our function has replied to
// Returning non-zero tells mongoose that our function has replied to
// the client, and mongoose should not send client any more data.
// the client, and mongoose should not send client any more data.
return
1
;
return
1
;
}
// We do not handle any other event
return
0
;
}
}
int
main
(
void
)
{
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
struct
mg_callbacks
callbacks
;
// List of options. Last element must be NULL.
// List of options. Last element must be NULL.
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
// 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.
// Start the web server.
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
ctx
=
mg_start
(
options
,
&
event_handler
,
NULL
);
// Wait until user hits "enter". Server is running in separate thread.
// Wait until user hits "enter". Server is running in separate thread.
// Navigating to http://localhost:8080 will invoke begin_request_handler().
// Navigating to http://localhost:8080 will invoke begin_request_handler().
...
...
examples/post.c
View file @
ecbf7913
...
@@ -10,21 +10,21 @@ static const char *html_form =
...
@@ -10,21 +10,21 @@ static const char *html_form =
"<input type=
\"
submit
\"
/>"
"<input type=
\"
submit
\"
/>"
"</form></body></html>"
;
"</form></body></html>"
;
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
char
post_data
[
1024
],
input1
[
sizeof
(
post_data
)],
input2
[
sizeof
(
post_data
)];
char
post_data
[
1024
],
input1
[
sizeof
(
post_data
)],
input2
[
sizeof
(
post_data
)];
int
post_data_len
;
int
post_data_len
;
if
(
!
strcmp
(
ri
->
uri
,
"/handle_post_request"
))
{
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
if
(
!
strcmp
(
event
->
request_info
->
uri
,
"/handle_post_request"
))
{
// User has submitted a form, show submitted data and a variable value
// User has submitted a form, show submitted data and a variable value
post_data_len
=
mg_read
(
conn
,
post_data
,
sizeof
(
post_data
));
post_data_len
=
mg_read
(
event
->
conn
,
post_data
,
sizeof
(
post_data
));
// Parse form data. input1 and input2 are guaranteed to be NUL-terminated
// 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_1"
,
input1
,
sizeof
(
input1
));
mg_get_var
(
post_data
,
post_data_len
,
"input_2"
,
input2
,
sizeof
(
input2
));
mg_get_var
(
post_data
,
post_data_len
,
"input_2"
,
input2
,
sizeof
(
input2
));
// Send reply to the client, showing submitted form values.
// Send reply to the client, showing submitted form values.
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
mg_printf
(
event
->
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"Submitted data: [%.*s]
\n
"
"Submitted data: [%.*s]
\n
"
"Submitted data length: %d bytes
\n
"
"Submitted data length: %d bytes
\n
"
...
@@ -33,22 +33,24 @@ static int begin_request_handler(struct mg_connection *conn) {
...
@@ -33,22 +33,24 @@ static int begin_request_handler(struct mg_connection *conn) {
post_data_len
,
post_data
,
post_data_len
,
input1
,
input2
);
post_data_len
,
post_data
,
post_data_len
,
input1
,
input2
);
}
else
{
}
else
{
// Show HTML form.
// Show HTML form.
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
mg_printf
(
event
->
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/html
\r\n\r\n
%s"
,
"Content-Type: text/html
\r\n\r\n
%s"
,
(
int
)
strlen
(
html_form
),
html_form
);
(
int
)
strlen
(
html_form
),
html_form
);
}
}
return
1
;
// Mark request as processed
return
1
;
// Mark event as processed
}
// All other events are left not processed
return
0
;
}
}
int
main
(
void
)
{
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
struct
mg_callbacks
callbacks
;
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
ctx
=
mg_start
(
options
,
&
event_handler
,
NULL
);
callbacks
.
begin_request
=
begin_request_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
getchar
();
// Wait until user hits "enter"
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
mg_stop
(
ctx
);
...
...
examples/upload.c
View file @
ecbf7913
...
@@ -3,24 +3,20 @@
...
@@ -3,24 +3,20 @@
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define strtoll strtol
typedef
__int64
int64_t
;
#else
#include <inttypes.h>
#include <unistd.h>
#endif // !_WIN32
#include "mongoose.h"
#include "mongoose.h"
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
if
(
!
strcmp
(
mg_get_request_info
(
conn
)
->
uri
,
"/handle_post_request"
))
{
mg_printf
(
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n\r\n
"
);
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
mg_upload
(
conn
,
"/tmp"
);
if
(
!
strcmp
(
event
->
request_info
->
uri
,
"/handle_post_request"
))
{
char
path
[
200
];
FILE
*
fp
=
mg_upload
(
event
->
conn
,
"/tmp"
,
path
,
sizeof
(
path
));
if
(
fp
!=
NULL
)
{
fclose
(
fp
);
mg_printf
(
event
->
conn
,
"HTTP/1.0 200 OK
\r\n\r\n
Saved: [%s]"
,
path
);
}
else
{
mg_printf
(
event
->
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n\r\n
No files sent"
);
}
}
else
{
}
else
{
// Show HTML form. Make sure it has enctype="multipart/form-data" attr.
// Show HTML form. Make sure it has enctype="multipart/form-data" attr.
static
const
char
*
html_form
=
static
const
char
*
html_form
=
...
@@ -31,7 +27,7 @@ static int begin_request_handler(struct mg_connection *conn) {
...
@@ -31,7 +27,7 @@ static int begin_request_handler(struct mg_connection *conn) {
"<input type=
\"
submit
\"
value=
\"
Upload
\"
/>"
"<input type=
\"
submit
\"
value=
\"
Upload
\"
/>"
"</form></body></html>"
;
"</form></body></html>"
;
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n
"
mg_printf
(
event
->
conn
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/html
\r\n\r\n
%s"
,
"Content-Type: text/html
\r\n\r\n
%s"
,
(
int
)
strlen
(
html_form
),
html_form
);
(
int
)
strlen
(
html_form
),
html_form
);
...
@@ -39,21 +35,16 @@ static int begin_request_handler(struct mg_connection *conn) {
...
@@ -39,21 +35,16 @@ static int begin_request_handler(struct mg_connection *conn) {
// Mark request as processed
// Mark request as processed
return
1
;
return
1
;
}
}
static
void
upload_handler
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
// All other events left unprocessed
mg_printf
(
conn
,
"Saved [%s]"
,
path
)
;
return
1
;
}
}
int
main
(
void
)
{
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
struct
mg_callbacks
callbacks
;
ctx
=
mg_start
(
options
,
event_handler
,
NULL
);
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"
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
mg_stop
(
ctx
);
...
...
examples/websocket.c
View file @
ecbf7913
...
@@ -5,38 +5,52 @@
...
@@ -5,38 +5,52 @@
#include <string.h>
#include <string.h>
#include "mongoose.h"
#include "mongoose.h"
static
void
websocket_ready_handler
(
struct
mg_connection
*
conn
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
static
const
char
*
message
=
"server ready"
;
mg_websocket_write
(
conn
,
WEBSOCKET_OPCODE_TEXT
,
message
,
strlen
(
message
));
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
}
const
char
*
version_header
=
mg_get_header
(
event
->
conn
,
"Sec-WebSocket-Version"
);
if
(
version_header
!=
NULL
)
{
// Websocket request, process it
if
(
strcmp
(
version_header
,
"13"
)
!=
0
)
{
mg_printf
(
event
->
conn
,
"%s"
,
"HTTP/1.1 426 Upgrade Required
\r\n\r\n
"
);
}
else
{
static
const
char
*
server_ready_message
=
"server ready"
;
char
*
data
;
int
bits
,
len
;
// Arguments:
// Handshake, and send initial server message
// flags: first byte of websocket frame, see websocket RFC,
mg_websocket_handshake
(
event
->
conn
);
// http://tools.ietf.org/html/rfc6455, section 5.2
mg_websocket_write
(
event
->
conn
,
WEBSOCKET_OPCODE_TEXT
,
// data, data_len: payload data. Mask, if any, is already applied.
server_ready_message
,
strlen
(
server_ready_message
));
static
int
websocket_data_handler
(
struct
mg_connection
*
conn
,
int
flags
,
char
*
data
,
size_t
data_len
)
{
while
((
len
=
mg_websocket_read
(
event
->
conn
,
&
bits
,
&
data
))
>
0
)
{
(
void
)
flags
;
// Unused
// Echo message back to the client
mg_websocket_write
(
conn
,
WEBSOCKET_OPCODE_TEXT
,
data
,
data_len
);
mg_websocket_write
(
event
->
conn
,
WEBSOCKET_OPCODE_TEXT
,
data
,
len
);
if
(
memcmp
(
data
,
"exit"
,
4
)
==
0
)
{
// Returning zero means stoping websocket conversation.
mg_websocket_write
(
event
->
conn
,
// Close the conversation if client has sent us "exit" string.
WEBSOCKET_OPCODE_CONNECTION_CLOSE
,
""
,
0
);
return
memcmp
(
data
,
"exit"
,
4
);
break
;
}
}
}
return
1
;
}
}
return
0
;
}
}
int
main
(
void
)
{
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
struct
mg_callbacks
callbacks
;
const
char
*
options
[]
=
{
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
"listening_ports"
,
"8080"
,
"document_root"
,
"websocket_html_root"
,
"document_root"
,
"websocket_html_root"
,
NULL
NULL
};
};
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
ctx
=
mg_start
(
options
,
&
event_handler
,
NULL
);
callbacks
.
websocket_ready
=
websocket_ready_handler
;
callbacks
.
websocket_data
=
websocket_data_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
getchar
();
// Wait until user hits "enter"
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
mg_stop
(
ctx
);
...
...
mongoose.c
View file @
ecbf7913
...
@@ -345,7 +345,7 @@ struct ssl_func {
...
@@ -345,7 +345,7 @@ struct ssl_func {
#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
const
char
*
,
int
))
ssl_sw
[
12
].
ptr
)
const
char
*
,
int
))
ssl_sw
[
12
].
ptr
)
#define SSL_CTX_set_default_passwd_cb \
#define SSL_CTX_set_default_passwd_cb \
(
*
(
void
(
*
)(
SSL_CTX
*
,
mg_
callback
_t
))
ssl_sw
[
13
].
ptr
)
(
*
(
void
(
*
)(
SSL_CTX
*
,
mg_
event_handler
_t
))
ssl_sw
[
13
].
ptr
)
#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
#define SSL_CTX_use_certificate_chain_file \
#define SSL_CTX_use_certificate_chain_file \
...
@@ -490,8 +490,7 @@ struct mg_context {
...
@@ -490,8 +490,7 @@ struct mg_context {
volatile
int
stop_flag
;
// Should we stop event loop
volatile
int
stop_flag
;
// Should we stop event loop
SSL_CTX
*
ssl_ctx
;
// SSL context
SSL_CTX
*
ssl_ctx
;
// SSL context
char
*
config
[
NUM_OPTIONS
];
// Mongoose configuration parameters
char
*
config
[
NUM_OPTIONS
];
// Mongoose configuration parameters
struct
mg_callbacks
callbacks
;
// User-defined callback function
mg_event_handler_t
event_handler
;
// User-defined callback function
mg_callback_t
user_callback
;
// User-defined callback function
void
*
user_data
;
// User-defined data
void
*
user_data
;
// User-defined data
struct
socket
*
listening_sockets
;
struct
socket
*
listening_sockets
;
...
@@ -510,6 +509,7 @@ struct mg_context {
...
@@ -510,6 +509,7 @@ struct mg_context {
struct
mg_connection
{
struct
mg_connection
{
struct
mg_request_info
request_info
;
struct
mg_request_info
request_info
;
struct
mg_event
event
;
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
SSL
*
ssl
;
// SSL descriptor
SSL
*
ssl
;
// SSL descriptor
SSL_CTX
*
client_ssl_ctx
;
// SSL context for client connections
SSL_CTX
*
client_ssl_ctx
;
// SSL context for client connections
...
@@ -517,7 +517,7 @@ struct mg_connection {
...
@@ -517,7 +517,7 @@ struct mg_connection {
time_t
birth_time
;
// Time when request was received
time_t
birth_time
;
// Time when request was received
int64_t
num_bytes_sent
;
// Total bytes sent to client
int64_t
num_bytes_sent
;
// Total bytes sent to client
int64_t
content_len
;
// Content-Length header value
int64_t
content_len
;
// Content-Length header value
int64_t
consumed_content
;
// How many bytes of content have been read
int64_t
num_bytes_read
;
// Bytes read from a remote socket
char
*
buf
;
// Buffer for received data
char
*
buf
;
// Buffer for received data
char
*
path_info
;
// PATH_INFO part of the URL
char
*
path_info
;
// PATH_INFO part of the URL
int
must_close
;
// 1 if connection must be closed
int
must_close
;
// 1 if connection must be closed
...
@@ -537,16 +537,25 @@ struct de {
...
@@ -537,16 +537,25 @@ struct de {
struct
file
file
;
struct
file
file
;
};
};
// Return number of bytes left to read for this connection
static
int64_t
left_to_read
(
const
struct
mg_connection
*
conn
)
{
return
conn
->
content_len
+
conn
->
request_len
-
conn
->
num_bytes_read
;
}
const
char
**
mg_get_valid_option_names
(
void
)
{
const
char
**
mg_get_valid_option_names
(
void
)
{
return
config_options
;
return
config_options
;
}
}
static
int
call_user
(
enum
mg_event
ev
,
struct
mg_connection
*
conn
,
void
*
p
)
{
static
int
call_user
(
int
type
,
struct
mg_connection
*
conn
,
void
*
p
)
{
if
(
conn
!=
NULL
&&
conn
->
ctx
!=
NULL
)
{
if
(
conn
!=
NULL
&&
conn
->
ctx
!=
NULL
)
{
conn
->
request_info
.
user_data
=
conn
->
ctx
->
user_data
;
conn
->
event
.
user_data
=
conn
->
ctx
->
user_data
;
conn
->
event
.
type
=
type
;
conn
->
event
.
event_param
=
p
;
conn
->
event
.
request_info
=
&
conn
->
request_info
;
conn
->
event
.
conn
=
conn
;
}
}
return
conn
==
NULL
||
conn
->
ctx
==
NULL
||
conn
->
ctx
->
user_callback
==
NULL
?
return
conn
==
NULL
||
conn
->
ctx
==
NULL
||
conn
->
ctx
->
event_handler
==
NULL
?
0
:
conn
->
ctx
->
user_callback
(
ev
,
conn
,
p
);
0
:
conn
->
ctx
->
event_handler
(
&
conn
->
event
);
}
}
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
)
{
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
)
{
...
@@ -614,8 +623,7 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
...
@@ -614,8 +623,7 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
// Do not lock when getting the callback value, here and below.
// Do not lock when getting the callback value, here and below.
// I suppose this is fine, since function cannot disappear in the
// I suppose this is fine, since function cannot disappear in the
// same way string option can.
// same way string option can.
if
(
conn
->
ctx
->
callbacks
.
log_message
==
NULL
||
if
(
call_user
(
MG_EVENT_LOG
,
conn
,
buf
)
==
0
)
{
conn
->
ctx
->
callbacks
.
log_message
(
conn
,
buf
)
==
0
)
{
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
...
@@ -646,7 +654,7 @@ static struct mg_connection *fc(struct mg_context *ctx) {
...
@@ -646,7 +654,7 @@ static struct mg_connection *fc(struct mg_context *ctx) {
static
struct
mg_connection
fake_connection
;
static
struct
mg_connection
fake_connection
;
fake_connection
.
ctx
=
ctx
;
fake_connection
.
ctx
=
ctx
;
// See https://github.com/cesanta/mongoose/issues/236
// See https://github.com/cesanta/mongoose/issues/236
fake_connection
.
request_info
.
user_data
=
ctx
->
user_data
;
fake_connection
.
event
.
user_data
=
ctx
->
user_data
;
return
&
fake_connection
;
return
&
fake_connection
;
}
}
...
@@ -1497,6 +1505,7 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
...
@@ -1497,6 +1505,7 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
static
int
pull
(
FILE
*
fp
,
struct
mg_connection
*
conn
,
char
*
buf
,
int
len
)
{
static
int
pull
(
FILE
*
fp
,
struct
mg_connection
*
conn
,
char
*
buf
,
int
len
)
{
int
nread
;
int
nread
;
if
(
len
<=
0
)
return
0
;
if
(
fp
!=
NULL
)
{
if
(
fp
!=
NULL
)
{
// Use read() instead of fread(), because if we're reading from the CGI
// Use read() instead of fread(), because if we're reading from the CGI
// pipe, fread() may block until IO buffer is filled up. We cannot afford
// pipe, fread() may block until IO buffer is filled up. We cannot afford
...
@@ -1509,6 +1518,9 @@ static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
...
@@ -1509,6 +1518,9 @@ static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
}
else
{
}
else
{
nread
=
recv
(
conn
->
client
.
sock
,
buf
,
(
size_t
)
len
,
0
);
nread
=
recv
(
conn
->
client
.
sock
,
buf
,
(
size_t
)
len
,
0
);
}
}
if
(
nread
>
0
)
{
conn
->
num_bytes_read
+=
nread
;
}
return
conn
->
ctx
->
stop_flag
?
-
1
:
nread
;
return
conn
->
ctx
->
stop_flag
?
-
1
:
nread
;
}
}
...
@@ -1524,7 +1536,6 @@ static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
...
@@ -1524,7 +1536,6 @@ static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
}
else
if
(
n
==
0
)
{
}
else
if
(
n
==
0
)
{
break
;
// No more data to read
break
;
// No more data to read
}
else
{
}
else
{
conn
->
consumed_content
+=
n
;
nread
+=
n
;
nread
+=
n
;
len
-=
n
;
len
-=
n
;
}
}
...
@@ -1533,46 +1544,48 @@ static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
...
@@ -1533,46 +1544,48 @@ static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
return
nread
;
return
nread
;
}
}
int
mg_read
(
struct
mg_connection
*
conn
,
void
*
buf
,
size_
t
len
)
{
int
mg_read
(
struct
mg_connection
*
conn
,
void
*
buf
,
in
t
len
)
{
int
n
,
buffered_len
,
nread
;
int
n
,
buffered_len
,
nread
=
0
;
const
char
*
body
;
int64_t
left
;
// If Content-Length is not set, read until socket is closed
// If Content-Length is not set, read until socket is closed
if
(
conn
->
con
sumed_content
==
0
&&
conn
->
content_len
=
=
0
)
{
if
(
conn
->
con
tent_len
<
=
0
)
{
conn
->
content_len
=
INT64_MAX
;
conn
->
content_len
=
INT64_MAX
;
conn
->
must_close
=
1
;
conn
->
must_close
=
1
;
}
}
nread
=
0
;
// conn->buf body
if
(
conn
->
consumed_content
<
conn
->
content_len
)
{
// |=================|==========|===============|
// Adjust number of bytes to read.
// |<--request_len-->| |
int64_t
to_read
=
conn
->
content_len
-
conn
->
consumed_content
;
// |<-----------data_len------->| conn->buf + conn->buf_size
if
(
to_read
<
(
int64_t
)
len
)
{
len
=
(
size_t
)
to_read
;
// First, check for data buffered in conn->buf by read_request().
}
if
(
len
>
0
&&
(
buffered_len
=
conn
->
data_len
-
conn
->
request_len
)
>
0
)
{
char
*
body
=
conn
->
buf
+
conn
->
request_len
;
if
(
buffered_len
>
len
)
buffered_len
=
len
;
if
(
buffered_len
>
conn
->
content_len
)
buffered_len
=
conn
->
content_len
;
// Return buffered data
body
=
conn
->
buf
+
conn
->
request_len
+
conn
->
consumed_content
;
buffered_len
=
&
conn
->
buf
[
conn
->
data_len
]
-
body
;
if
(
buffered_len
>
0
)
{
if
(
len
<
(
size_t
)
buffered_len
)
{
buffered_len
=
(
int
)
len
;
}
memcpy
(
buf
,
body
,
(
size_t
)
buffered_len
);
memcpy
(
buf
,
body
,
(
size_t
)
buffered_len
);
memmove
(
body
,
body
+
buffered_len
,
&
conn
->
buf
[
conn
->
data_len
]
-
&
body
[
buffered_len
]);
len
-=
buffered_len
;
len
-=
buffered_len
;
conn
->
consumed_content
+
=
buffered_len
;
conn
->
data_len
-
=
buffered_len
;
nread
+=
buffered_len
;
nread
+=
buffered_len
;
buf
=
(
char
*
)
buf
+
buffered_len
;
}
}
// We have returned all buffered data. Read new data from the remote socket.
// Read data from the socket.
n
=
pull_all
(
NULL
,
conn
,
(
char
*
)
buf
,
(
int
)
len
);
if
(
len
>
0
&&
(
left
=
left_to_read
(
conn
))
>
0
)
{
if
(
left
<
len
)
{
len
=
(
int
)
left
;
}
n
=
pull_all
(
NULL
,
conn
,
(
char
*
)
buf
+
nread
,
(
int
)
len
);
nread
=
n
>=
0
?
nread
+
n
:
n
;
nread
=
n
>=
0
?
nread
+
n
:
n
;
}
}
return
nread
;
return
nread
;
}
}
int
mg_write
(
struct
mg_connection
*
conn
,
const
void
*
buf
,
size_
t
len
)
{
int
mg_write
(
struct
mg_connection
*
conn
,
const
void
*
buf
,
in
t
len
)
{
time_t
now
;
time_t
now
;
int64_t
n
,
total
,
allowed
;
int64_t
n
,
total
,
allowed
;
...
@@ -1864,25 +1877,25 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
...
@@ -1864,25 +1877,25 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
// -1 if request is malformed
// -1 if request is malformed
// 0 if request is not yet fully buffered
// 0 if request is not yet fully buffered
// >0 actual request length, including last \r\n\r\n
// >0 actual request length, including last \r\n\r\n
static
int
get_request_len
(
const
char
*
buf
,
int
buflen
)
{
static
int
get_request_len
(
const
char
*
buf
,
int
buf_len
)
{
const
char
*
s
,
*
e
;
int
i
;
int
len
=
0
;
for
(
s
=
buf
,
e
=
s
+
buflen
-
1
;
len
<=
0
&&
s
<
e
;
s
++
)
for
(
i
=
0
;
i
<
buf_len
;
i
++
)
{
// Control characters are not allowed but >=128 is.
// Control characters are not allowed but >=128 is.
if
(
!
isprint
(
*
(
const
unsigned
char
*
)
s
)
&&
*
s
!=
'\r'
&&
// Abort scan as soon as one malformed character is found;
*
s
!=
'\n'
&&
*
(
const
unsigned
char
*
)
s
<
128
)
{
len
=
-
1
;
break
;
// [i_a] abort scan as soon as one malformed character is found;
// don't let subsequent \r\n\r\n win us over anyhow
// don't let subsequent \r\n\r\n win us over anyhow
}
else
if
(
s
[
0
]
==
'\n'
&&
s
[
1
]
==
'\n'
)
{
if
(
!
isprint
(
*
(
const
unsigned
char
*
)
&
buf
[
i
])
&&
buf
[
i
]
!=
'\r'
&&
len
=
(
int
)
(
s
-
buf
)
+
2
;
buf
[
i
]
!=
'\n'
&&
*
(
const
unsigned
char
*
)
&
buf
[
i
]
<
128
)
{
}
else
if
(
s
[
0
]
==
'\n'
&&
&
s
[
1
]
<
e
&&
return
-
1
;
s
[
1
]
==
'\r'
&&
s
[
2
]
==
'\n'
)
{
}
else
if
(
buf
[
i
]
==
'\n'
&&
i
+
1
<
buf_len
&&
buf
[
i
+
1
]
==
'\n'
)
{
len
=
(
int
)
(
s
-
buf
)
+
3
;
return
i
+
2
;
}
else
if
(
buf
[
i
]
==
'\n'
&&
i
+
2
<
buf_len
&&
buf
[
i
+
1
]
==
'\r'
&&
buf
[
i
+
2
]
==
'\n'
)
{
return
i
+
3
;
}
}
}
return
len
;
return
0
;
}
}
// Convert month to the month number. Return -1 on error, or month number
// Convert month to the month number. Return -1 on error, or month number
...
@@ -2840,7 +2853,7 @@ static void handle_directory_request(struct mg_connection *conn,
...
@@ -2840,7 +2853,7 @@ static void handle_directory_request(struct mg_connection *conn,
static
void
send_file_data
(
struct
mg_connection
*
conn
,
FILE
*
fp
,
static
void
send_file_data
(
struct
mg_connection
*
conn
,
FILE
*
fp
,
int64_t
offset
,
int64_t
len
)
{
int64_t
offset
,
int64_t
len
)
{
char
buf
[
MG_BUF_LEN
];
char
buf
[
MG_BUF_LEN
];
int
to_read
,
num_read
,
num_written
;
int
num_read
,
num_written
,
to_read
;
// If offset is beyond file boundaries, don't send anything
// If offset is beyond file boundaries, don't send anything
if
(
offset
>
0
&&
fseeko
(
fp
,
offset
,
SEEK_SET
)
!=
0
)
{
if
(
offset
>
0
&&
fseeko
(
fp
,
offset
,
SEEK_SET
)
!=
0
)
{
...
@@ -3054,7 +3067,8 @@ static int read_request(FILE *fp, struct mg_connection *conn,
...
@@ -3054,7 +3067,8 @@ static int read_request(FILE *fp, struct mg_connection *conn,
request_len
=
get_request_len
(
buf
,
*
nread
);
request_len
=
get_request_len
(
buf
,
*
nread
);
while
(
conn
->
ctx
->
stop_flag
==
0
&&
while
(
conn
->
ctx
->
stop_flag
==
0
&&
*
nread
<
bufsiz
&&
request_len
==
0
&&
*
nread
<
bufsiz
&&
request_len
==
0
&&
(
n
=
pull
(
fp
,
conn
,
buf
+
*
nread
,
bufsiz
-
*
nread
))
>
0
)
{
(
n
=
pull
(
fp
,
conn
,
buf
+
*
nread
,
bufsiz
-
*
nread
))
>
0
)
{
*
nread
+=
n
;
*
nread
+=
n
;
assert
(
*
nread
<=
bufsiz
);
assert
(
*
nread
<=
bufsiz
);
...
@@ -3126,7 +3140,8 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
...
@@ -3126,7 +3140,8 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
SOCKET
sock
,
SSL
*
ssl
)
{
SOCKET
sock
,
SSL
*
ssl
)
{
const
char
*
expect
,
*
body
;
const
char
*
expect
,
*
body
;
char
buf
[
MG_BUF_LEN
];
char
buf
[
MG_BUF_LEN
];
int
to_read
,
nread
,
buffered_len
,
success
=
0
;
int
nread
,
buffered_len
,
success
=
0
;
int64_t
left
;
expect
=
mg_get_header
(
conn
,
"Expect"
);
expect
=
mg_get_header
(
conn
,
"Expect"
);
assert
(
fp
!=
NULL
);
assert
(
fp
!=
NULL
);
...
@@ -3140,33 +3155,32 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
...
@@ -3140,33 +3155,32 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
(
void
)
mg_printf
(
conn
,
"%s"
,
"HTTP/1.1 100 Continue
\r\n\r\n
"
);
(
void
)
mg_printf
(
conn
,
"%s"
,
"HTTP/1.1 100 Continue
\r\n\r\n
"
);
}
}
b
ody
=
conn
->
buf
+
conn
->
request_len
+
conn
->
consumed_content
;
b
uffered_len
=
conn
->
data_len
-
conn
->
request_len
;
b
uffered_len
=
&
conn
->
buf
[
conn
->
data_len
]
-
body
;
b
ody
=
conn
->
buf
+
conn
->
request_len
;
assert
(
buffered_len
>=
0
);
assert
(
buffered_len
>=
0
);
assert
(
conn
->
consumed_content
==
0
);
if
(
buffered_len
>
0
)
{
if
(
buffered_len
>
0
)
{
if
((
int64_t
)
buffered_len
>
conn
->
content_len
)
{
if
((
int64_t
)
buffered_len
>
conn
->
content_len
)
{
buffered_len
=
(
int
)
conn
->
content_len
;
buffered_len
=
(
int
)
conn
->
content_len
;
}
}
push
(
fp
,
sock
,
ssl
,
body
,
(
int64_t
)
buffered_len
);
push
(
fp
,
sock
,
ssl
,
body
,
(
int64_t
)
buffered_len
);
conn
->
consumed_content
+=
buffered_len
;
memmove
((
char
*
)
body
,
body
+
buffered_len
,
buffered_len
);
conn
->
data_len
-=
buffered_len
;
}
}
nread
=
0
;
nread
=
0
;
while
(
conn
->
consumed_content
<
conn
->
conten
t_len
)
{
while
(
conn
->
num_bytes_read
<
conn
->
content_len
+
conn
->
reques
t_len
)
{
to_read
=
sizeof
(
buf
);
left
=
left_to_read
(
conn
);
if
(
(
int64_t
)
to_read
>
conn
->
content_len
-
conn
->
consumed_content
)
{
if
(
left
>
(
int64_t
)
sizeof
(
buf
)
)
{
to_read
=
(
int
)
(
conn
->
content_len
-
conn
->
consumed_content
);
left
=
sizeof
(
buf
);
}
}
nread
=
pull
(
NULL
,
conn
,
buf
,
to_read
);
nread
=
pull
(
NULL
,
conn
,
buf
,
left
);
if
(
nread
<=
0
||
push
(
fp
,
sock
,
ssl
,
buf
,
nread
)
!=
nread
)
{
if
(
nread
<=
0
||
push
(
fp
,
sock
,
ssl
,
buf
,
nread
)
!=
nread
)
{
break
;
break
;
}
}
conn
->
consumed_content
+=
nread
;
}
}
if
(
conn
->
consumed_content
==
conn
->
content_len
)
{
if
(
left_to_read
(
conn
)
==
0
)
{
success
=
nread
>=
0
;
success
=
nread
>=
0
;
}
}
...
@@ -3980,7 +3994,7 @@ static void base64_encode(const unsigned char *src, int src_len, char *dst) {
...
@@ -3980,7 +3994,7 @@ static void base64_encode(const unsigned char *src, int src_len, char *dst) {
dst
[
j
++
]
=
'\0'
;
dst
[
j
++
]
=
'\0'
;
}
}
static
void
send
_websocket_handshake
(
struct
mg_connection
*
conn
)
{
void
mg
_websocket_handshake
(
struct
mg_connection
*
conn
)
{
static
const
char
*
magic
=
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
;
static
const
char
*
magic
=
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
;
char
buf
[
100
],
sha
[
20
],
b64_sha
[
sizeof
(
sha
)
*
2
];
char
buf
[
100
],
sha
[
20
],
b64_sha
[
sizeof
(
sha
)
*
2
];
SHA1_CTX
sha_ctx
;
SHA1_CTX
sha_ctx
;
...
@@ -3998,17 +4012,14 @@ static void send_websocket_handshake(struct mg_connection *conn) {
...
@@ -3998,17 +4012,14 @@ static void send_websocket_handshake(struct mg_connection *conn) {
"Sec-WebSocket-Accept: "
,
b64_sha
,
"
\r\n\r\n
"
);
"Sec-WebSocket-Accept: "
,
b64_sha
,
"
\r\n\r\n
"
);
}
}
static
void
read_websocket
(
struct
mg_connection
*
conn
)
{
int
mg_websocket_read
(
struct
mg_connection
*
conn
,
int
*
bits
,
char
**
data
)
{
// Pointer to the beginning of the portion of the incoming websocket message
// Pointer to the beginning of the portion of the incoming websocket message
// queue. The original websocket upgrade request is never removed,
// queue. The original websocket upgrade request is never removed,
// so the queue begins after it.
// so the queue begins after it.
unsigned
char
*
buf
=
(
unsigned
char
*
)
conn
->
buf
+
conn
->
request_len
;
unsigned
char
*
buf
=
(
unsigned
char
*
)
conn
->
buf
+
conn
->
request_len
;
int
bits
,
n
,
stop
=
0
;
int
n
,
stop
=
0
;
size_t
i
,
len
,
mask_len
,
data_len
,
header_len
,
body_len
;
size_t
i
,
len
,
mask_len
,
data_len
,
header_len
,
body_len
;
// data points to the place where the message is stored when passed to the
char
mask
[
4
];
// websocket_data callback. This is either mem on the stack,
// or a dynamically allocated buffer if it is too large.
char
mem
[
4
*
1024
],
mask
[
4
],
*
data
;
assert
(
conn
->
content_len
==
0
);
assert
(
conn
->
content_len
==
0
);
...
@@ -4046,28 +4057,28 @@ static void read_websocket(struct mg_connection *conn) {
...
@@ -4046,28 +4057,28 @@ static void read_websocket(struct mg_connection *conn) {
if
(
header_len
>
0
)
{
if
(
header_len
>
0
)
{
// Allocate space to hold websocket payload
// Allocate space to hold websocket payload
data
=
mem
;
if
((
*
data
=
malloc
(
data_len
))
==
NULL
)
{
if
(
data_len
>
sizeof
(
mem
)
&&
(
data
=
malloc
(
data_len
))
==
NULL
)
{
// Allocation failed, exit the loop and then close the connection
// Allocation failed, exit the loop and then close the connection
// TODO: notify user about the failure
// TODO: notify user about the failure
data_len
=
0
;
break
;
break
;
}
}
// Save mask and bits, otherwise it may be clobbered by memmove below
// Save mask and bits, otherwise it may be clobbered by memmove below
bits
=
buf
[
0
];
*
bits
=
buf
[
0
];
memcpy
(
mask
,
buf
+
header_len
-
mask_len
,
mask_len
);
memcpy
(
mask
,
buf
+
header_len
-
mask_len
,
mask_len
);
// Read frame payload into the allocated buffer.
// Read frame payload into the allocated buffer.
assert
(
body_len
>=
header_len
);
assert
(
body_len
>=
header_len
);
if
(
data_len
+
header_len
>
body_len
)
{
if
(
data_len
+
header_len
>
body_len
)
{
len
=
body_len
-
header_len
;
len
=
body_len
-
header_len
;
memcpy
(
data
,
buf
+
header_len
,
len
);
memcpy
(
*
data
,
buf
+
header_len
,
len
);
// TODO: handle pull error
// TODO: handle pull error
pull_all
(
NULL
,
conn
,
data
+
len
,
data_len
-
len
);
pull_all
(
NULL
,
conn
,
*
data
+
len
,
data_len
-
len
);
conn
->
data_len
=
conn
->
request_len
;
conn
->
data_len
=
conn
->
request_len
;
}
else
{
}
else
{
len
=
data_len
+
header_len
;
len
=
data_len
+
header_len
;
memcpy
(
data
,
buf
+
header_len
,
data_len
);
memcpy
(
*
data
,
buf
+
header_len
,
data_len
);
memmove
(
buf
,
buf
+
len
,
body_len
-
len
);
memmove
(
buf
,
buf
+
len
,
body_len
-
len
);
conn
->
data_len
-=
len
;
conn
->
data_len
-=
len
;
}
}
...
@@ -4075,21 +4086,17 @@ static void read_websocket(struct mg_connection *conn) {
...
@@ -4075,21 +4086,17 @@ static void read_websocket(struct mg_connection *conn) {
// Apply mask if necessary
// Apply mask if necessary
if
(
mask_len
>
0
)
{
if
(
mask_len
>
0
)
{
for
(
i
=
0
;
i
<
data_len
;
i
++
)
{
for
(
i
=
0
;
i
<
data_len
;
i
++
)
{
data
[
i
]
^=
mask
[
i
%
4
];
(
*
data
)
[
i
]
^=
mask
[
i
%
4
];
}
}
}
}
// Exit the loop if callback signalled to exit,
// Exit the loop if callback signalled to exit,
// or "connection close" opcode received.
// or "connection close" opcode received.
if
(((
bits
&
0x0f
)
==
WEBSOCKET_OPCODE_CONNECTION_CLOSE
)
||
if
((
*
bits
&
0x0f
)
==
WEBSOCKET_OPCODE_CONNECTION_CLOSE
)
{
(
conn
->
ctx
->
callbacks
.
websocket_data
!=
NULL
&&
return
data_len
;
!
conn
->
ctx
->
callbacks
.
websocket_data
(
conn
,
bits
,
data
,
data_len
)))
{
stop
=
1
;
stop
=
1
;
}
}
if
(
data
!=
mem
)
{
free
(
data
);
}
// Not breaking the loop, process next websocket frame.
// Not breaking the loop, process next websocket frame.
}
else
{
}
else
{
// Buffering websocket request
// Buffering websocket request
...
@@ -4100,6 +4107,8 @@ static void read_websocket(struct mg_connection *conn) {
...
@@ -4100,6 +4107,8 @@ static void read_websocket(struct mg_connection *conn) {
conn
->
data_len
+=
n
;
conn
->
data_len
+=
n
;
}
}
}
}
return
0
;
}
}
int
mg_websocket_write
(
struct
mg_connection
*
conn
,
int
opcode
,
int
mg_websocket_write
(
struct
mg_connection
*
conn
,
int
opcode
,
...
@@ -4143,37 +4152,6 @@ int mg_websocket_write(struct mg_connection* conn, int opcode,
...
@@ -4143,37 +4152,6 @@ int mg_websocket_write(struct mg_connection* conn, int opcode,
return
retval
;
return
retval
;
}
}
static
void
handle_websocket_request
(
struct
mg_connection
*
conn
)
{
const
char
*
version
=
mg_get_header
(
conn
,
"Sec-WebSocket-Version"
);
if
(
version
==
NULL
||
strcmp
(
version
,
"13"
)
!=
0
)
{
send_http_error
(
conn
,
426
,
"Upgrade Required"
,
"%s"
,
"Upgrade Required"
);
}
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
);
if
(
conn
->
ctx
->
callbacks
.
websocket_ready
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
websocket_ready
(
conn
);
}
read_websocket
(
conn
);
}
}
static
int
is_websocket_request
(
const
struct
mg_connection
*
conn
)
{
const
char
*
host
,
*
upgrade
,
*
connection
,
*
version
,
*
key
;
host
=
mg_get_header
(
conn
,
"Host"
);
upgrade
=
mg_get_header
(
conn
,
"Upgrade"
);
connection
=
mg_get_header
(
conn
,
"Connection"
);
key
=
mg_get_header
(
conn
,
"Sec-WebSocket-Key"
);
version
=
mg_get_header
(
conn
,
"Sec-WebSocket-Version"
);
return
host
!=
NULL
&&
upgrade
!=
NULL
&&
connection
!=
NULL
&&
key
!=
NULL
&&
version
!=
NULL
&&
mg_strcasestr
(
upgrade
,
"websocket"
)
!=
NULL
&&
mg_strcasestr
(
connection
,
"Upgrade"
)
!=
NULL
;
}
#endif // !USE_WEBSOCKET
#endif // !USE_WEBSOCKET
static
int
isbyte
(
int
n
)
{
static
int
isbyte
(
int
n
)
{
...
@@ -4231,12 +4209,12 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) {
...
@@ -4231,12 +4209,12 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) {
#include "build/mod_lua.c"
#include "build/mod_lua.c"
#endif // USE_LUA
#endif // USE_LUA
int
mg_upload
(
struct
mg_connection
*
conn
,
const
char
*
destination_dir
)
{
FILE
*
mg_upload
(
struct
mg_connection
*
conn
,
const
char
*
destination_dir
,
char
*
path
,
int
path_len
)
{
const
char
*
content_type_header
,
*
boundary_start
;
const
char
*
content_type_header
,
*
boundary_start
;
char
buf
[
MG_BUF_LEN
],
path
[
PATH_MAX
],
fname
[
1024
],
boundary
[
100
],
*
s
;
char
*
buf
,
fname
[
1024
],
boundary
[
100
],
*
s
;
int
bl
,
n
,
i
,
j
,
headers_len
,
boundary_len
,
eof
,
buf_len
,
to_read
,
len
=
0
;
FILE
*
fp
;
FILE
*
fp
;
int
bl
,
n
,
i
,
j
,
headers_len
,
boundary_len
,
eof
,
len
=
0
,
num_uploaded_files
=
0
;
// Request looks like this:
// Request looks like this:
//
//
...
@@ -4260,15 +4238,31 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
...
@@ -4260,15 +4238,31 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
(
sscanf
(
boundary_start
,
"boundary=
\"
%99[^
\"
]
\"
"
,
boundary
)
==
0
&&
(
sscanf
(
boundary_start
,
"boundary=
\"
%99[^
\"
]
\"
"
,
boundary
)
==
0
&&
sscanf
(
boundary_start
,
"boundary=%99s"
,
boundary
)
==
0
)
||
sscanf
(
boundary_start
,
"boundary=%99s"
,
boundary
)
==
0
)
||
boundary
[
0
]
==
'\0'
)
{
boundary
[
0
]
==
'\0'
)
{
return
num_uploaded_files
;
return
NULL
;
}
}
boundary_len
=
strlen
(
boundary
);
boundary_len
=
strlen
(
boundary
);
bl
=
boundary_len
+
4
;
// \r\n--<boundary>
bl
=
boundary_len
+
4
;
// \r\n--<boundary>
// buf
// conn->buf |<--------- buf_len ------>|
// |=================|==========|===============|
// |<--request_len-->|<--len--->| |
// |<-----------data_len------->| conn->buf + conn->buf_size
buf
=
conn
->
buf
+
conn
->
request_len
;
buf_len
=
conn
->
buf_size
-
conn
->
request_len
;
len
=
conn
->
data_len
-
conn
->
request_len
;
for
(;;)
{
for
(;;)
{
// Pull in headers
// Pull in headers
assert
(
len
>=
0
&&
len
<=
(
int
)
sizeof
(
buf
));
assert
(
len
>=
0
&&
len
<=
buf_len
);
while
((
n
=
mg_read
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
))
>
0
)
{
to_read
=
buf_len
-
len
;
if
(
to_read
>
left_to_read
(
conn
))
{
to_read
=
left_to_read
(
conn
);
}
while
(
len
<
buf_len
&&
(
n
=
pull
(
NULL
,
conn
,
buf
+
len
,
to_read
))
>
0
)
{
len
+=
n
;
len
+=
n
;
}
}
if
((
headers_len
=
get_request_len
(
buf
,
len
))
<=
0
)
{
if
((
headers_len
=
get_request_len
(
buf
,
len
))
<=
0
)
{
...
@@ -4297,10 +4291,12 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
...
@@ -4297,10 +4291,12 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
assert
(
len
>=
headers_len
);
assert
(
len
>=
headers_len
);
memmove
(
buf
,
&
buf
[
headers_len
],
len
-
headers_len
);
memmove
(
buf
,
&
buf
[
headers_len
],
len
-
headers_len
);
len
-=
headers_len
;
len
-=
headers_len
;
conn
->
data_len
=
conn
->
request_len
+
len
;
// We open the file with exclusive lock held. This guarantee us
// We open the file with exclusive lock held. This guarantee us
// there is no other thread can save into the same file simultaneously.
// there is no other thread can save into the same file simultaneously.
fp
=
NULL
;
fp
=
NULL
;
// Construct destination file name. Do not allow paths to have slashes.
// Construct destination file name. Do not allow paths to have slashes.
if
((
s
=
strrchr
(
fname
,
'/'
))
==
NULL
&&
if
((
s
=
strrchr
(
fname
,
'/'
))
==
NULL
&&
(
s
=
strrchr
(
fname
,
'\\'
))
==
NULL
)
{
(
s
=
strrchr
(
fname
,
'\\'
))
==
NULL
)
{
...
@@ -4308,7 +4304,7 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
...
@@ -4308,7 +4304,7 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
}
}
// Open file in binary mode. TODO: set an exclusive lock.
// Open file in binary mode. TODO: set an exclusive lock.
snprintf
(
path
,
sizeof
(
path
)
,
"%s/%s"
,
destination_dir
,
s
);
snprintf
(
path
,
path_len
,
"%s/%s"
,
destination_dir
,
s
);
if
((
fp
=
fopen
(
path
,
"wb"
))
==
NULL
)
{
if
((
fp
=
fopen
(
path
,
"wb"
))
==
NULL
)
{
break
;
break
;
}
}
...
@@ -4333,17 +4329,22 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
...
@@ -4333,17 +4329,22 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
memmove
(
buf
,
&
buf
[
len
-
bl
],
bl
);
memmove
(
buf
,
&
buf
[
len
-
bl
],
bl
);
len
=
bl
;
len
=
bl
;
}
}
}
while
(
!
eof
&&
(
n
=
mg_read
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
))
>
0
);
to_read
=
buf_len
-
len
;
fclose
(
fp
);
if
(
to_read
>
left_to_read
(
conn
))
{
if
(
eof
)
{
to_read
=
left_to_read
(
conn
);
num_uploaded_files
++
;
if
(
conn
->
ctx
->
callbacks
.
upload
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
upload
(
conn
,
path
);
}
}
}
while
(
!
eof
&&
(
n
=
pull
(
NULL
,
conn
,
buf
+
len
,
to_read
))
>
0
);
conn
->
data_len
=
conn
->
request_len
+
len
;
if
(
eof
)
{
rewind
(
fp
);
return
fp
;
}
else
{
fclose
(
fp
);
}
}
}
}
return
num_uploaded_files
;
return
NULL
;
}
}
static
int
is_put_or_delete_request
(
const
struct
mg_connection
*
conn
)
{
static
int
is_put_or_delete_request
(
const
struct
mg_connection
*
conn
)
{
...
@@ -4417,7 +4418,6 @@ static void handle_request(struct mg_connection *conn) {
...
@@ -4417,7 +4418,6 @@ static void handle_request(struct mg_connection *conn) {
path
[
0
]
=
'\0'
;
path
[
0
]
=
'\0'
;
convert_uri_to_file_name
(
conn
,
path
,
sizeof
(
path
),
&
file
);
convert_uri_to_file_name
(
conn
,
path
,
sizeof
(
path
),
&
file
);
DEBUG_TRACE
((
"%s"
,
ri
->
uri
));
// Perform redirect and auth checks before calling begin_request() handler.
// Perform redirect and auth checks before calling begin_request() handler.
// Otherwise, begin_request() would need to perform auth checks and redirects.
// Otherwise, begin_request() would need to perform auth checks and redirects.
if
(
!
conn
->
client
.
is_ssl
&&
conn
->
client
.
ssl_redir
&&
if
(
!
conn
->
client
.
is_ssl
&&
conn
->
client
.
ssl_redir
&&
...
@@ -4426,13 +4426,8 @@ static void handle_request(struct mg_connection *conn) {
...
@@ -4426,13 +4426,8 @@ static void handle_request(struct mg_connection *conn) {
}
else
if
(
!
is_put_or_delete_request
(
conn
)
&&
}
else
if
(
!
is_put_or_delete_request
(
conn
)
&&
!
check_authorization
(
conn
,
path
))
{
!
check_authorization
(
conn
,
path
))
{
send_authorization_request
(
conn
);
send_authorization_request
(
conn
);
}
else
if
(
conn
->
ctx
->
callbacks
.
begin_request
!=
NULL
&&
}
else
if
(
call_user
(
MG_REQUEST_BEGIN
,
conn
,
(
void
*
)
ri
->
uri
)
==
1
)
{
conn
->
ctx
->
callbacks
.
begin_request
(
conn
))
{
// Do nothing, callback has served the request
// Do nothing, callback has served the request
#if defined(USE_WEBSOCKET)
}
else
if
(
is_websocket_request
(
conn
))
{
handle_websocket_request
(
conn
);
#endif
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"OPTIONS"
))
{
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"OPTIONS"
))
{
handle_options_request
(
conn
);
handle_options_request
(
conn
);
}
else
if
(
conn
->
ctx
->
config
[
DOCUMENT_ROOT
]
==
NULL
)
{
}
else
if
(
conn
->
ctx
->
config
[
DOCUMENT_ROOT
]
==
NULL
)
{
...
@@ -4767,8 +4762,9 @@ static int set_ssl_option(struct mg_context *ctx) {
...
@@ -4767,8 +4762,9 @@ static int set_ssl_option(struct mg_context *ctx) {
// If PEM file is not specified and the init_ssl callback
// If PEM file is not specified and the init_ssl callback
// is not specified, skip SSL initialization.
// is not specified, skip SSL initialization.
if
((
pem
=
ctx
->
config
[
SSL_CERTIFICATE
])
==
NULL
&&
if
((
pem
=
ctx
->
config
[
SSL_CERTIFICATE
])
==
NULL
)
{
ctx
->
callbacks
.
init_ssl
==
NULL
)
{
// MG_INIT_SSL
// ctx->callbacks.init_ssl == NULL) {
return
1
;
return
1
;
}
}
...
@@ -4790,10 +4786,9 @@ static int set_ssl_option(struct mg_context *ctx) {
...
@@ -4790,10 +4786,9 @@ static int set_ssl_option(struct mg_context *ctx) {
// If user callback returned non-NULL, that means that user callback has
// If user callback returned non-NULL, that means that user callback has
// set up certificate itself. In this case, skip sertificate setting.
// set up certificate itself. In this case, skip sertificate setting.
if
((
ctx
->
callbacks
.
init_ssl
==
NULL
||
// MG_INIT_SSL
!
ctx
->
callbacks
.
init_ssl
(
ctx
->
ssl_ctx
,
ctx
->
user_data
))
&&
if
(
SSL_CTX_use_certificate_file
(
ctx
->
ssl_ctx
,
pem
,
1
)
==
0
||
(
SSL_CTX_use_certificate_file
(
ctx
->
ssl_ctx
,
pem
,
1
)
==
0
||
SSL_CTX_use_PrivateKey_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
());
cry
(
fc
(
ctx
),
"%s: cannot open %s: %s"
,
__func__
,
pem
,
ssl_error
());
return
0
;
return
0
;
}
}
...
@@ -4849,7 +4844,7 @@ static int set_acl_option(struct mg_context *ctx) {
...
@@ -4849,7 +4844,7 @@ static int set_acl_option(struct mg_context *ctx) {
static
void
reset_per_request_attributes
(
struct
mg_connection
*
conn
)
{
static
void
reset_per_request_attributes
(
struct
mg_connection
*
conn
)
{
conn
->
path_info
=
NULL
;
conn
->
path_info
=
NULL
;
conn
->
num_bytes_sent
=
conn
->
consumed_content
=
0
;
conn
->
num_bytes_sent
=
conn
->
num_bytes_read
=
0
;
conn
->
status_code
=
-
1
;
conn
->
status_code
=
-
1
;
conn
->
must_close
=
conn
->
request_len
=
conn
->
throttle
=
0
;
conn
->
must_close
=
conn
->
request_len
=
conn
->
throttle
=
0
;
}
}
...
@@ -5039,9 +5034,7 @@ static void process_new_connection(struct mg_connection *conn) {
...
@@ -5039,9 +5034,7 @@ static void process_new_connection(struct mg_connection *conn) {
if
(
ebuf
[
0
]
==
'\0'
)
{
if
(
ebuf
[
0
]
==
'\0'
)
{
handle_request
(
conn
);
handle_request
(
conn
);
if
(
conn
->
ctx
->
callbacks
.
end_request
!=
NULL
)
{
call_user
(
MG_REQUEST_END
,
conn
,
(
void
*
)
conn
->
status_code
);
conn
->
ctx
->
callbacks
.
end_request
(
conn
,
conn
->
status_code
);
}
log_access
(
conn
);
log_access
(
conn
);
}
}
if
(
ri
->
remote_user
!=
NULL
)
{
if
(
ri
->
remote_user
!=
NULL
)
{
...
@@ -5111,12 +5104,9 @@ static void *worker_thread(void *thread_func_param) {
...
@@ -5111,12 +5104,9 @@ static void *worker_thread(void *thread_func_param) {
conn
->
buf_size
=
MAX_REQUEST_SIZE
;
conn
->
buf_size
=
MAX_REQUEST_SIZE
;
conn
->
buf
=
(
char
*
)
(
conn
+
1
);
conn
->
buf
=
(
char
*
)
(
conn
+
1
);
conn
->
ctx
=
ctx
;
conn
->
ctx
=
ctx
;
conn
->
request_info
.
user_data
=
ctx
->
user_data
;
conn
->
event
.
user_data
=
ctx
->
user_data
;
if
(
ctx
->
callbacks
.
thread_start
!=
NULL
)
{
call_user
(
MG_THREAD_BEGIN
,
conn
,
NULL
);
ctx
->
callbacks
.
thread_start
(
&
conn
->
request_info
.
user_data
,
&
conn
->
request_info
.
conn_data
);
}
// Call consume_socket() even when ctx->stop_flag > 0, to let it signal
// Call consume_socket() even when ctx->stop_flag > 0, to let it signal
// sq_empty condvar to wake up the master waiting in produce_socket()
// sq_empty condvar to wake up the master waiting in produce_socket()
...
@@ -5143,10 +5133,7 @@ static void *worker_thread(void *thread_func_param) {
...
@@ -5143,10 +5133,7 @@ static void *worker_thread(void *thread_func_param) {
close_connection
(
conn
);
close_connection
(
conn
);
}
}
if
(
ctx
->
callbacks
.
thread_stop
!=
NULL
)
{
call_user
(
MG_THREAD_END
,
conn
,
NULL
);
ctx
->
callbacks
.
thread_stop
(
&
conn
->
request_info
.
user_data
,
&
conn
->
request_info
.
conn_data
);
}
free
(
conn
);
free
(
conn
);
}
}
...
@@ -5241,9 +5228,7 @@ static void *master_thread(void *thread_func_param) {
...
@@ -5241,9 +5228,7 @@ static void *master_thread(void *thread_func_param) {
pthread_setschedparam
(
pthread_self
(),
SCHED_RR
,
&
sched_param
);
pthread_setschedparam
(
pthread_self
(),
SCHED_RR
,
&
sched_param
);
#endif
#endif
if
(
ctx
->
callbacks
.
thread_start
!=
NULL
)
{
call_user
(
MG_THREAD_BEGIN
,
fc
(
ctx
),
NULL
);
ctx
->
callbacks
.
thread_start
(
&
ctx
->
user_data
,
NULL
);
}
pfd
=
(
struct
pollfd
*
)
calloc
(
ctx
->
num_listening_sockets
,
sizeof
(
pfd
[
0
]));
pfd
=
(
struct
pollfd
*
)
calloc
(
ctx
->
num_listening_sockets
,
sizeof
(
pfd
[
0
]));
while
(
pfd
!=
NULL
&&
ctx
->
stop_flag
==
0
)
{
while
(
pfd
!=
NULL
&&
ctx
->
stop_flag
==
0
)
{
...
@@ -5291,9 +5276,7 @@ static void *master_thread(void *thread_func_param) {
...
@@ -5291,9 +5276,7 @@ static void *master_thread(void *thread_func_param) {
#endif
#endif
DEBUG_TRACE
((
"exiting"
));
DEBUG_TRACE
((
"exiting"
));
if
(
ctx
->
callbacks
.
thread_stop
!=
NULL
)
{
call_user
(
MG_THREAD_END
,
fc
(
ctx
),
NULL
);
ctx
->
callbacks
.
thread_stop
(
&
ctx
->
user_data
,
NULL
);
}
// Signal mg_stop() that we're done.
// Signal mg_stop() that we're done.
// WARNING: This must be the very last thing this
// WARNING: This must be the very last thing this
...
@@ -5340,9 +5323,9 @@ void mg_stop(struct mg_context *ctx) {
...
@@ -5340,9 +5323,9 @@ void mg_stop(struct mg_context *ctx) {
#endif // _WIN32
#endif // _WIN32
}
}
struct
mg_context
*
mg_start
(
const
struct
mg_callbacks
*
callback
s
,
struct
mg_context
*
mg_start
(
const
char
**
option
s
,
void
*
user_data
,
mg_event_handler_t
func
,
const
char
**
options
)
{
void
*
user_data
)
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
const
char
*
name
,
*
value
,
*
default_value
;
const
char
*
name
,
*
value
,
*
default_value
;
int
i
;
int
i
;
...
@@ -5357,7 +5340,7 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
...
@@ -5357,7 +5340,7 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
if
((
ctx
=
(
struct
mg_context
*
)
calloc
(
1
,
sizeof
(
*
ctx
)))
==
NULL
)
{
if
((
ctx
=
(
struct
mg_context
*
)
calloc
(
1
,
sizeof
(
*
ctx
)))
==
NULL
)
{
return
NULL
;
return
NULL
;
}
}
ctx
->
callbacks
=
*
callbacks
;
ctx
->
event_handler
=
func
;
ctx
->
user_data
=
user_data
;
ctx
->
user_data
=
user_data
;
while
(
options
&&
(
name
=
*
options
++
)
!=
NULL
)
{
while
(
options
&&
(
name
=
*
options
++
)
!=
NULL
)
{
...
...
mongoose.h
View file @
ecbf7913
...
@@ -25,8 +25,8 @@
...
@@ -25,8 +25,8 @@
extern
"C"
{
extern
"C"
{
#endif // __cplusplus
#endif // __cplusplus
struct
mg_context
;
//
Handle for the HTTP service itself
struct
mg_context
;
//
Web server instance
struct
mg_connection
;
// H
andle for the individual connection
struct
mg_connection
;
// H
TTP request descriptor
// This structure contains information about the HTTP request.
// This structure contains information about the HTTP request.
...
@@ -39,8 +39,6 @@ struct mg_request_info {
...
@@ -39,8 +39,6 @@ struct mg_request_info {
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
is_ssl
;
// 1 if SSL-ed, 0 if not
void
*
user_data
;
// User data pointer passed to mg_start()
void
*
conn_data
;
// Connection-specific, per-thread user data.
int
num_headers
;
// Number of HTTP headers
int
num_headers
;
// Number of HTTP headers
struct
mg_header
{
struct
mg_header
{
...
@@ -49,37 +47,32 @@ struct mg_request_info {
...
@@ -49,37 +47,32 @@ struct mg_request_info {
}
http_headers
[
64
];
// Maximum 64 headers
}
http_headers
[
64
];
// Maximum 64 headers
};
};
enum
mg_event
{
struct
mg_event
{
MG_REQUEST_BEGIN
,
int
type
;
// Event type, possible types are defined below
MG_REQUEST_END
,
#define MG_REQUEST_BEGIN 1 // event_param: NULL
MG_HTTP_ERROR
,
#define MG_REQUEST_END 2 // event_param: NULL
MG_EVENT_LOG
,
#define MG_HTTP_ERROR 3 // event_param: int status_code
MG_THREAD_BEGIN
,
#define MG_EVENT_LOG 4 // event_param: const char *message
MG_THREAD_END
#define MG_THREAD_BEGIN 5 // event_param: NULL
};
#define MG_THREAD_END 6 // event_param: NULL
typedef
int
(
*
mg_callback_t
)(
enum
mg_event
event
,
struct
mg_connection
*
conn
,
void
*
user_data
;
// User data pointer passed to mg_start()
void
*
data
);
void
*
conn_data
;
// Connection-specific, per-thread user data.
void
*
event_param
;
// Event-specific parameter
struct
mg_callbacks
{
int
(
*
begin_request
)(
struct
mg_connection
*
);
struct
mg_connection
*
conn
;
void
(
*
end_request
)(
const
struct
mg_connection
*
,
int
reply_status_code
);
struct
mg_request_info
*
request_info
;
int
(
*
log_message
)(
const
struct
mg_connection
*
,
const
char
*
message
);
int
(
*
init_ssl
)(
void
*
ssl_context
,
void
*
user_data
);
int
(
*
websocket_connect
)(
const
struct
mg_connection
*
);
void
(
*
websocket_ready
)(
struct
mg_connection
*
);
int
(
*
websocket_data
)(
struct
mg_connection
*
,
int
bits
,
char
*
data
,
size_t
data_len
);
void
(
*
upload
)(
struct
mg_connection
*
,
const
char
*
file_name
);
void
(
*
thread_start
)(
void
*
user_data
,
void
**
conn_data
);
void
(
*
thread_stop
)(
void
*
user_data
,
void
**
conn_data
);
};
};
struct
mg_context
*
mg_start
(
const
struct
mg_callbacks
*
callbacks
,
typedef
int
(
*
mg_event_handler_t
)(
struct
mg_event
*
event
);
void
*
user_data
,
const
char
**
configuration_options
);
struct
mg_context
*
mg_start
(
const
char
**
configuration_options
,
mg_event_handler_t
func
,
void
*
user_data
);
void
mg_stop
(
struct
mg_context
*
);
void
mg_stop
(
struct
mg_context
*
);
void
mg_websocket_handshake
(
struct
mg_connection
*
);
int
mg_websocket_read
(
struct
mg_connection
*
,
int
*
bits
,
char
**
data
);
// Get the value of particular configuration parameter.
// Get the value of particular configuration parameter.
// The value returned is read-only. Mongoose does not allow changing
// The value returned is read-only. Mongoose does not allow changing
...
@@ -114,17 +107,12 @@ int mg_modify_passwords_file(const char *passwords_file_name,
...
@@ -114,17 +107,12 @@ int mg_modify_passwords_file(const char *passwords_file_name,
const
char
*
user
,
const
char
*
user
,
const
char
*
password
);
const
char
*
password
);
// Return information associated with the request.
struct
mg_request_info
*
mg_get_request_info
(
struct
mg_connection
*
);
// Send data to the client.
// Send data to the client.
// Return:
// Return:
// 0 when the connection has been closed
// 0 when the connection has been closed
// -1 on error
// -1 on error
// >0 number of bytes written on success
// >0 number of bytes written on success
int
mg_write
(
struct
mg_connection
*
,
const
void
*
buf
,
size_
t
len
);
int
mg_write
(
struct
mg_connection
*
,
const
void
*
buf
,
in
t
len
);
// Send data to a websocket client wrapped in a websocket frame.
// Send data to a websocket client wrapped in a websocket frame.
...
@@ -184,7 +172,7 @@ void mg_send_file(struct mg_connection *conn, const char *path);
...
@@ -184,7 +172,7 @@ void mg_send_file(struct mg_connection *conn, const char *path);
// 0 connection has been closed by peer. No more data could be read.
// 0 connection has been closed by peer. No more data could be read.
// < 0 read error. No more data could be read from the connection.
// < 0 read error. No more data could be read from the connection.
// > 0 number of bytes read into the buffer.
// > 0 number of bytes read into the buffer.
int
mg_read
(
struct
mg_connection
*
,
void
*
buf
,
size_
t
len
);
int
mg_read
(
struct
mg_connection
*
,
void
*
buf
,
in
t
len
);
// Get the value of particular HTTP header.
// Get the value of particular HTTP header.
...
@@ -258,10 +246,13 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
...
@@ -258,10 +246,13 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
void
mg_close_connection
(
struct
mg_connection
*
conn
);
void
mg_close_connection
(
struct
mg_connection
*
conn
);
// File upload functionality. Each uploaded file gets saved into a temporary
// Read multipart-form-data POST buffer, save uploaded files into
// file and MG_UPLOAD event is sent.
// destination directory, and return path to the saved filed.
// Return number of uploaded files.
// This function can be called multiple times for the same connection,
int
mg_upload
(
struct
mg_connection
*
conn
,
const
char
*
destination_dir
);
// if more then one file is uploaded.
// Return: path to the uploaded file, or NULL if there are no more files.
FILE
*
mg_upload
(
struct
mg_connection
*
conn
,
const
char
*
destination_dir
,
char
*
path
,
int
path_len
);
// Convenience function -- create detached thread.
// Convenience function -- create detached thread.
...
...
test/unit_test.c
View file @
ecbf7913
// Copyright (c) 2004-2013 Sergey Lyubka
// Unit test for the mongoose web server.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Unit test for the mongoose web server. Tests embedded API.
#define USE_WEBSOCKET
#define USE_WEBSOCKET
#define USE_LUA
#define USE_LUA
...
@@ -65,6 +45,14 @@ static void test_parse_http_message() {
...
@@ -65,6 +45,14 @@ static void test_parse_http_message() {
char
req8
[]
=
" HTTP/1.1 200 OK
\n\n
"
;
char
req8
[]
=
" HTTP/1.1 200 OK
\n\n
"
;
char
req9
[]
=
"HTTP/1.1 200 OK
\r\n
Connection: close
\r\n\r\n
"
;
char
req9
[]
=
"HTTP/1.1 200 OK
\r\n
Connection: close
\r\n\r\n
"
;
ASSERT
(
get_request_len
(
"
\r\n
"
,
3
)
==
-
1
);
ASSERT
(
get_request_len
(
"
\r\n
"
,
2
)
==
0
);
ASSERT
(
get_request_len
(
"GET"
,
3
)
==
0
);
ASSERT
(
get_request_len
(
"
\n\n
"
,
2
)
==
2
);
ASSERT
(
get_request_len
(
"
\n\r\n
"
,
3
)
==
3
);
ASSERT
(
get_request_len
(
"
\xdd\xdd
"
,
2
)
==
0
);
ASSERT
(
get_request_len
(
"
\xdd\x03
"
,
2
)
==
-
1
);
ASSERT
(
parse_http_message
(
req9
,
sizeof
(
req9
),
&
ri
)
==
sizeof
(
req9
)
-
1
);
ASSERT
(
parse_http_message
(
req9
,
sizeof
(
req9
),
&
ri
)
==
sizeof
(
req9
)
-
1
);
ASSERT
(
ri
.
num_headers
==
1
);
ASSERT
(
ri
.
num_headers
==
1
);
...
@@ -72,15 +60,15 @@ static void test_parse_http_message() {
...
@@ -72,15 +60,15 @@ static void test_parse_http_message() {
ASSERT
(
strcmp
(
ri
.
http_version
,
"1.1"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_version
,
"1.1"
)
==
0
);
ASSERT
(
ri
.
num_headers
==
0
);
ASSERT
(
ri
.
num_headers
==
0
);
ASSERT
(
parse_http_message
(
req2
,
sizeof
(
req2
),
&
ri
)
==
-
1
);
ASSERT
(
parse_http_message
(
req2
,
sizeof
(
req2
)
-
1
,
&
ri
)
==
-
1
);
ASSERT
(
parse_http_message
(
req3
,
sizeof
(
req3
),
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
req3
,
sizeof
(
req3
)
-
1
,
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
req6
,
sizeof
(
req6
),
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
req6
,
sizeof
(
req6
)
-
1
,
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
req7
,
sizeof
(
req7
),
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
req7
,
sizeof
(
req7
)
-
1
,
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
""
,
0
,
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
""
,
0
,
&
ri
)
==
0
);
ASSERT
(
parse_http_message
(
req8
,
sizeof
(
req8
),
&
ri
)
==
sizeof
(
req8
)
-
1
);
ASSERT
(
parse_http_message
(
req8
,
sizeof
(
req8
)
-
1
,
&
ri
)
==
sizeof
(
req8
)
-
1
);
// TODO(lsm): Fix this. Header value may span multiple lines.
// TODO(lsm): Fix this. Header value may span multiple lines.
ASSERT
(
parse_http_message
(
req4
,
sizeof
(
req4
),
&
ri
)
==
sizeof
(
req4
)
-
1
);
ASSERT
(
parse_http_message
(
req4
,
sizeof
(
req4
)
-
1
,
&
ri
)
==
sizeof
(
req4
)
-
1
);
ASSERT
(
strcmp
(
ri
.
http_version
,
"1.1"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_version
,
"1.1"
)
==
0
);
ASSERT
(
ri
.
num_headers
==
3
);
ASSERT
(
ri
.
num_headers
==
3
);
ASSERT
(
strcmp
(
ri
.
http_headers
[
0
].
name
,
"A"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_headers
[
0
].
name
,
"A"
)
==
0
);
...
@@ -90,7 +78,7 @@ static void test_parse_http_message() {
...
@@ -90,7 +78,7 @@ static void test_parse_http_message() {
ASSERT
(
strcmp
(
ri
.
http_headers
[
2
].
name
,
"baz
\r\n\r
"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_headers
[
2
].
name
,
"baz
\r\n\r
"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_headers
[
2
].
value
,
""
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_headers
[
2
].
value
,
""
)
==
0
);
ASSERT
(
parse_http_message
(
req5
,
sizeof
(
req5
),
&
ri
)
==
sizeof
(
req5
)
-
1
);
ASSERT
(
parse_http_message
(
req5
,
sizeof
(
req5
)
-
1
,
&
ri
)
==
sizeof
(
req5
)
-
1
);
ASSERT
(
strcmp
(
ri
.
request_method
,
"GET"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
request_method
,
"GET"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_version
,
"1.1"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_version
,
"1.1"
)
==
0
);
}
}
...
@@ -201,79 +189,55 @@ static char *read_file(const char *path, int *size) {
...
@@ -201,79 +189,55 @@ static char *read_file(const char *path, int *size) {
}
}
static
const
char
*
fetch_data
=
"hello world!
\n
"
;
static
const
char
*
fetch_data
=
"hello world!
\n
"
;
static
const
char
*
upload_filename
=
"upload_test.txt"
;
static
const
char
*
upload_filename2
=
"upload_test2.txt"
;
static
const
char
*
upload_ok_message
=
"upload successful"
;
static
const
char
*
upload_ok_message
=
"upload successful"
;
static
void
upload_cb
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
static
void
test_upload
(
struct
mg_connection
*
conn
,
const
char
*
orig_path
,
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
const
char
*
uploaded_path
)
{
char
*
p1
,
*
p2
;
int
len1
,
len2
;
int
len1
,
len2
;
char
path
[
500
],
*
p1
,
*
p2
;
FILE
*
fp
;
if
(
atoi
(
ri
->
query_string
)
==
1
)
{
ASSERT
((
fp
=
mg_upload
(
conn
,
"."
,
path
,
sizeof
(
path
)))
!=
NULL
);
ASSERT
(
!
strcmp
(
path
,
"./upload_test.txt"
));
fclose
(
fp
);
ASSERT
((
p1
=
read_file
(
"main.c"
,
&
len1
))
!=
NULL
);
ASSERT
(
!
strcmp
(
path
,
uploaded_path
));
ASSERT
((
p2
=
read_file
(
path
,
&
len2
))
!=
NULL
);
ASSERT
((
p1
=
read_file
(
orig_path
,
&
len1
))
!=
NULL
);
ASSERT
(
len1
==
len2
);
ASSERT
(
memcmp
(
p1
,
p2
,
len1
)
==
0
);
free
(
p1
),
free
(
p2
);
remove
(
upload_filename
);
}
else
if
(
atoi
(
ri
->
query_string
)
==
2
)
{
if
(
!
strcmp
(
path
,
"./upload_test.txt"
))
{
ASSERT
((
p1
=
read_file
(
"lua_5.2.1.h"
,
&
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
);
}
else
if
(
!
strcmp
(
path
,
"./upload_test2.txt"
))
{
ASSERT
((
p1
=
read_file
(
"mod_lua.c"
,
&
len1
))
!=
NULL
);
ASSERT
((
p2
=
read_file
(
path
,
&
len2
))
!=
NULL
);
ASSERT
((
p2
=
read_file
(
path
,
&
len2
))
!=
NULL
);
ASSERT
(
len1
==
len2
);
ASSERT
(
len1
==
len2
);
ASSERT
(
memcmp
(
p1
,
p2
,
len1
)
==
0
);
ASSERT
(
memcmp
(
p1
,
p2
,
len1
)
==
0
);
free
(
p1
),
free
(
p2
);
free
(
p1
),
free
(
p2
);
remove
(
upload_filename
);
remove
(
path
);
}
else
{
ASSERT
(
0
);
}
}
else
{
ASSERT
(
0
);
}
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
)
{
static
int
event_handler
(
struct
mg_event
*
event
)
{
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
)
;
struct
mg_request_info
*
ri
=
event
->
request_info
;
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
if
(
!
strcmp
(
ri
->
uri
,
"/data"
))
{
if
(
!
strcmp
(
ri
->
uri
,
"/data"
))
{
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
mg_printf
(
event
->
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"%s"
,
fetch_data
);
"%s"
,
fetch_data
);
close_connection
(
conn
);
close_connection
(
event
->
conn
);
return
1
;
return
1
;
}
}
if
(
!
strcmp
(
ri
->
uri
,
"/upload"
))
{
if
(
!
strcmp
(
ri
->
uri
,
"/upload"
))
{
ASSERT
(
ri
->
query_string
!=
NULL
);
test_upload
(
event
->
conn
,
"lua_5.2.1.h"
,
"./f1.txt"
);
ASSERT
(
mg_upload
(
conn
,
"."
)
==
atoi
(
ri
->
query_string
)
);
test_upload
(
event
->
conn
,
"mod_lua.c"
,
"./f2.txt"
);
}
ASSERT
(
mg_upload
(
event
->
conn
,
"."
,
NULL
,
0
)
==
NULL
);
return
0
;
mg_printf
(
event
->
conn
,
"HTTP/1.0 200 OK
\r\n
"
}
"Content-Type: text/plain
\r\n\r\n
"
"%s"
,
upload_ok_message
);
close_connection
(
event
->
conn
);
return
1
;
}
}
else
if
(
event
->
type
==
MG_EVENT_LOG
)
{
printf
(
"%s
\n
"
,
(
const
char
*
)
event
->
event_param
);
}
static
int
log_message_cb
(
const
struct
mg_connection
*
conn
,
const
char
*
msg
)
{
(
void
)
conn
;
printf
(
"%s
\n
"
,
msg
);
return
0
;
return
0
;
}
}
static
const
struct
mg_callbacks
CALLBACKS
=
{
&
begin_request_handler_cb
,
NULL
,
&
log_message_cb
,
NULL
,
NULL
,
NULL
,
NULL
,
&
upload_cb
,
NULL
,
NULL
};
static
const
char
*
OPTIONS
[]
=
{
static
const
char
*
OPTIONS
[]
=
{
"document_root"
,
"."
,
"document_root"
,
"."
,
"listening_ports"
,
LISTENING_ADDR
,
"listening_ports"
,
LISTENING_ADDR
,
...
@@ -283,7 +247,7 @@ static const char *OPTIONS[] = {
...
@@ -283,7 +247,7 @@ static const char *OPTIONS[] = {
};
};
static
char
*
read_conn
(
struct
mg_connection
*
conn
,
int
*
size
)
{
static
char
*
read_conn
(
struct
mg_connection
*
conn
,
int
*
size
)
{
char
buf
[
100
],
*
data
=
NULL
;
char
buf
[
MG_BUF_LEN
],
*
data
=
NULL
;
int
len
;
int
len
;
*
size
=
0
;
*
size
=
0
;
while
((
len
=
mg_read
(
conn
,
buf
,
sizeof
(
buf
)))
>
0
)
{
while
((
len
=
mg_read
(
conn
,
buf
,
sizeof
(
buf
)))
>
0
)
{
...
@@ -300,7 +264,7 @@ static void test_mg_download(void) {
...
@@ -300,7 +264,7 @@ static void test_mg_download(void) {
struct
mg_connection
*
conn
;
struct
mg_connection
*
conn
;
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
ASSERT
((
ctx
=
mg_start
(
&
CALLBACKS
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
OPTIONS
,
event_handler
,
NULL
))
!=
NULL
);
ASSERT
(
mg_download
(
NULL
,
port
,
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
""
)
==
NULL
);
ASSERT
(
mg_download
(
NULL
,
port
,
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
""
)
==
NULL
);
ASSERT
(
mg_download
(
"localhost"
,
0
,
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
""
)
==
NULL
);
ASSERT
(
mg_download
(
"localhost"
,
0
,
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
""
)
==
NULL
);
...
@@ -362,33 +326,7 @@ static void test_mg_upload(void) {
...
@@ -362,33 +326,7 @@ static void test_mg_upload(void) {
char
ebuf
[
100
],
buf
[
20
],
*
file_data
,
*
file2_data
,
*
post_data
;
char
ebuf
[
100
],
buf
[
20
],
*
file_data
,
*
file2_data
,
*
post_data
;
int
file_len
,
file2_len
,
post_data_len
;
int
file_len
,
file2_len
,
post_data_len
;
ASSERT
((
ctx
=
mg_start
(
&
CALLBACKS
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
OPTIONS
,
event_handler
,
NULL
))
!=
NULL
);
// Upload one file
ASSERT
((
file_data
=
read_file
(
"main.c"
,
&
file_len
))
!=
NULL
);
post_data
=
NULL
;
post_data_len
=
alloc_printf
(
&
post_data
,
0
,
"--%s
\r\n
"
"Content-Disposition: form-data; "
"name=
\"
file
\"
; "
"filename=
\"
%s
\"\r\n\r\n
"
"%.*s
\r\n
"
"--%s--
\r\n
"
,
boundary
,
upload_filename
,
file_len
,
file_data
,
boundary
);
ASSERT
(
post_data_len
>
0
);
ASSERT
((
conn
=
mg_download
(
"localhost"
,
atoi
(
HTTPS_PORT
),
1
,
ebuf
,
sizeof
(
ebuf
),
"POST /upload?1 HTTP/1.1
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: multipart/form-data; "
"boundary=%s
\r\n\r\n
"
"%.*s"
,
post_data_len
,
boundary
,
post_data_len
,
post_data
))
!=
NULL
);
free
(
file_data
),
free
(
post_data
);
ASSERT
(
mg_read
(
conn
,
buf
,
sizeof
(
buf
))
==
(
int
)
strlen
(
upload_ok_message
));
ASSERT
(
memcmp
(
buf
,
upload_ok_message
,
strlen
(
upload_ok_message
))
==
0
);
mg_close_connection
(
conn
);
// Upload two files
// Upload two files
ASSERT
((
file_data
=
read_file
(
"lua_5.2.1.h"
,
&
file_len
))
!=
NULL
);
ASSERT
((
file_data
=
read_file
(
"lua_5.2.1.h"
,
&
file_len
))
!=
NULL
);
...
@@ -411,21 +349,20 @@ static void test_mg_upload(void) {
...
@@ -411,21 +349,20 @@ static void test_mg_upload(void) {
// Final boundary
// Final boundary
"--%s--
\r\n
"
,
"--%s--
\r\n
"
,
boundary
,
upload_filename
,
boundary
,
"f1.txt"
,
file_len
,
file_data
,
file_len
,
file_data
,
boundary
,
upload_filename2
,
boundary
,
"f2.txt"
,
file2_len
,
file2_data
,
file2_len
,
file2_data
,
boundary
);
boundary
);
ASSERT
(
post_data_len
>
0
);
ASSERT
(
post_data_len
>
0
);
ASSERT
((
conn
=
mg_download
(
"localhost"
,
atoi
(
HTTPS_PORT
),
1
,
ASSERT
((
conn
=
mg_download
(
"localhost"
,
atoi
(
HTTPS_PORT
),
1
,
ebuf
,
sizeof
(
ebuf
),
ebuf
,
sizeof
(
ebuf
),
"POST /upload
?2
HTTP/1.1
\r\n
"
"POST /upload HTTP/1.1
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: multipart/form-data; "
"Content-Type: multipart/form-data; "
"boundary=%s
\r\n\r\n
"
"boundary=%s
\r\n\r\n
"
"%.*s"
,
post_data_len
,
boundary
,
"%.*s"
,
post_data_len
,
boundary
,
post_data_len
,
post_data
))
!=
NULL
);
post_data_len
,
post_data
))
!=
NULL
);
free
(
file_data
),
free
(
file2_data
),
free
(
post_data
);
ASSERT
(
mg_read
(
conn
,
buf
,
sizeof
(
buf
))
==
(
int
)
strlen
(
upload_ok_message
));
ASSERT
(
mg_read
(
conn
,
buf
,
sizeof
(
buf
))
==
(
int
)
strlen
(
upload_ok_message
));
ASSERT
(
memcmp
(
buf
,
upload_ok_message
,
strlen
(
upload_ok_message
))
==
0
);
ASSERT
(
memcmp
(
buf
,
upload_ok_message
,
strlen
(
upload_ok_message
))
==
0
);
mg_close_connection
(
conn
);
mg_close_connection
(
conn
);
...
@@ -523,7 +460,7 @@ static void test_lua(void) {
...
@@ -523,7 +460,7 @@ static void test_lua(void) {
conn
.
ctx
=
&
ctx
;
conn
.
ctx
=
&
ctx
;
conn
.
buf
=
http_request
;
conn
.
buf
=
http_request
;
conn
.
buf_size
=
conn
.
data_len
=
strlen
(
http_request
);
conn
.
buf_size
=
conn
.
data_len
=
conn
.
num_bytes_read
=
strlen
(
http_request
);
conn
.
request_len
=
parse_http_message
(
conn
.
buf
,
conn
.
data_len
,
conn
.
request_len
=
parse_http_message
(
conn
.
buf
,
conn
.
data_len
,
&
conn
.
request_info
);
&
conn
.
request_info
);
conn
.
content_len
=
conn
.
data_len
-
conn
.
request_len
;
conn
.
content_len
=
conn
.
data_len
-
conn
.
request_len
;
...
@@ -595,7 +532,7 @@ static void test_request_replies(void) {
...
@@ -595,7 +532,7 @@ static void test_request_replies(void) {
{
NULL
,
NULL
},
{
NULL
,
NULL
},
};
};
ASSERT
((
ctx
=
mg_start
(
&
CALLBACKS
,
NULL
,
OPTIONS
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
OPTIONS
,
event_handler
,
NULL
))
!=
NULL
);
for
(
i
=
0
;
tests
[
i
].
request
!=
NULL
;
i
++
)
{
for
(
i
=
0
;
tests
[
i
].
request
!=
NULL
;
i
++
)
{
ASSERT
((
conn
=
mg_download
(
"localhost"
,
port
,
1
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
ASSERT
((
conn
=
mg_download
(
"localhost"
,
port
,
1
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
tests
[
i
].
request
))
!=
NULL
);
tests
[
i
].
request
))
!=
NULL
);
...
@@ -604,39 +541,42 @@ static void test_request_replies(void) {
...
@@ -604,39 +541,42 @@ static void test_request_replies(void) {
mg_stop
(
ctx
);
mg_stop
(
ctx
);
}
}
static
int
api_callback
(
struct
mg_connection
*
conn
)
{
static
const
char
*
api_uri
=
"/?a=%20&b=&c=xx"
;
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
static
int
api_cb
(
struct
mg_event
*
event
)
{
struct
mg_request_info
*
ri
=
event
->
request_info
;
char
post_data
[
100
]
=
""
;
char
post_data
[
100
]
=
""
;
ASSERT
(
ri
->
user_data
==
(
void
*
)
123
);
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
ASSERT
(
event
->
user_data
==
(
void
*
)
123
);
ASSERT
(
ri
->
num_headers
==
2
);
ASSERT
(
ri
->
num_headers
==
2
);
ASSERT
(
strcmp
(
mg_get_header
(
conn
,
"host"
),
"blah.com"
)
==
0
);
ASSERT
(
strcmp
(
mg_get_header
(
event
->
conn
,
"host"
),
"blah.com"
)
==
0
);
ASSERT
(
mg_read
(
conn
,
post_data
,
sizeof
(
post_data
))
==
3
);
ASSERT
(
mg_read
(
event
->
conn
,
post_data
,
sizeof
(
post_data
))
==
3
);
ASSERT
(
memcmp
(
post_data
,
"b=1"
,
3
)
==
0
);
ASSERT
(
memcmp
(
post_data
,
"b=1"
,
3
)
==
0
);
ASSERT
(
ri
->
query_string
!=
NULL
);
ASSERT
(
ri
->
query_string
!=
NULL
);
ASSERT
(
strcmp
(
ri
->
query_string
,
api_uri
+
2
)
==
0
);
ASSERT
(
ri
->
remote_ip
>
0
);
ASSERT
(
ri
->
remote_ip
>
0
);
ASSERT
(
ri
->
remote_port
>
0
);
ASSERT
(
ri
->
remote_port
>
0
);
ASSERT
(
strcmp
(
ri
->
http_version
,
"1.0"
)
==
0
);
ASSERT
(
strcmp
(
ri
->
http_version
,
"1.0"
)
==
0
);
mg_printf
(
conn
,
"HTTP/1.0 200 OK
\r\n\r\n
"
);
mg_printf
(
event
->
conn
,
"HTTP/1.0 200 OK
\r\n\r\n
"
);
return
1
;
return
1
;
}
return
0
;
}
}
static
void
test_api_calls
(
void
)
{
static
void
test_api_calls
(
void
)
{
char
ebuf
[
100
];
char
ebuf
[
100
];
struct
mg_callbacks
callbacks
;
struct
mg_connection
*
conn
;
struct
mg_connection
*
conn
;
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
static
const
char
*
request
=
"POST /?a=%20&b=&c=xx
HTTP/1.0
\r\n
"
static
const
char
*
fmt
=
"POST %s
HTTP/1.0
\r\n
"
"Host: blah.com
\n
"
// More spaces before
"Host: blah.com
\n
"
// More spaces before
"content-length: 3
\r\n
"
// Lower case header name
"content-length: 3
\r\n
"
// Lower case header name
"
\r\n
b=123456"
;
// Content size > content-length, test for mg_read()
"
\r\n
b=123456"
;
// Content size > content-length, test for mg_read()
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
ASSERT
((
ctx
=
mg_start
(
OPTIONS
,
api_cb
,
(
void
*
)
123
))
!=
NULL
);
callbacks
.
begin_request
=
api_callback
;
ASSERT
((
ctx
=
mg_start
(
&
callbacks
,
(
void
*
)
123
,
OPTIONS
))
!=
NULL
);
ASSERT
((
conn
=
mg_download
(
"localhost"
,
atoi
(
HTTPS_PORT
),
1
,
ASSERT
((
conn
=
mg_download
(
"localhost"
,
atoi
(
HTTPS_PORT
),
1
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
request
))
!=
NULL
);
ebuf
,
sizeof
(
ebuf
),
fmt
,
api_uri
))
!=
NULL
);
mg_close_connection
(
conn
);
mg_close_connection
(
conn
);
mg_stop
(
ctx
);
mg_stop
(
ctx
);
}
}
...
@@ -732,8 +672,8 @@ int __cdecl main(void) {
...
@@ -732,8 +672,8 @@ int __cdecl main(void) {
test_base64_encode
();
test_base64_encode
();
test_match_prefix
();
test_match_prefix
();
test_remove_double_dots
();
test_remove_double_dots
();
test_should_keep_alive
();
test_parse_http_message
();
test_parse_http_message
();
test_should_keep_alive
();
test_mg_download
();
test_mg_download
();
test_mg_get_var
();
test_mg_get_var
();
test_set_throttle
();
test_set_throttle
();
...
...
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