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
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
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
410 additions
and
490 deletions
+410
-490
main.c
build/main.c
+5
-7
chat.c
examples/chat.c
+10
-9
hello.c
examples/hello.c
+27
-27
post.c
examples/post.c
+31
-29
upload.c
examples/upload.c
+32
-41
websocket.c
examples/websocket.c
+35
-21
mongoose.c
mongoose.c
+153
-170
mongoose.h
mongoose.h
+33
-42
unit_test.c
test/unit_test.c
+84
-144
No files found.
build/main.c
View file @
ecbf7913
...
...
@@ -271,9 +271,10 @@ static void init_server_name(void) {
mg_version
());
}
static
int
log_message
(
const
struct
mg_connection
*
conn
,
const
char
*
message
)
{
(
void
)
conn
;
printf
(
"%s
\n
"
,
message
);
static
int
event_handler
(
struct
mg_event
*
event
)
{
if
(
event
->
type
==
MG_EVENT_LOG
)
{
printf
(
"%s
\n
"
,
(
const
char
*
)
event
->
event_param
);
}
return
0
;
}
...
...
@@ -341,7 +342,6 @@ static void set_absolute_path(char *options[], const char *option_name,
}
static
void
start_mongoose
(
int
argc
,
char
*
argv
[])
{
struct
mg_callbacks
callbacks
;
char
*
options
[
MAX_OPTIONS
];
int
i
;
...
...
@@ -385,9 +385,7 @@ static void start_mongoose(int argc, char *argv[]) {
signal
(
SIGINT
,
signal_handler
);
// Start Mongoose
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
log_message
=
&
log_message
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
(
const
char
**
)
options
);
ctx
=
mg_start
((
const
char
**
)
options
,
event_handler
,
NULL
);
for
(
i
=
0
;
options
[
i
]
!=
NULL
;
i
++
)
{
free
(
options
[
i
]);
}
...
...
examples/chat.c
View file @
ecbf7913
...
...
@@ -326,9 +326,12 @@ static void redirect_to_ssl(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
);
int
processed
=
1
;
static
int
event_handler
(
struct
mg_event
*
event
)
{
struct
mg_request_info
*
request_info
=
event
->
request_info
;
struct
mg_connection
*
conn
=
event
->
conn
;
int
result
=
1
;
if
(
event
->
type
!=
MG_REQUEST_BEGIN
)
return
0
;
if
(
!
request_info
->
is_ssl
)
{
redirect_to_ssl
(
conn
,
request_info
);
...
...
@@ -343,9 +346,10 @@ static int begin_request_handler(struct mg_connection *conn) {
}
else
{
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
processed
=
0
;
result
=
0
;
}
return
processed
;
return
result
;
}
static
const
char
*
options
[]
=
{
...
...
@@ -357,7 +361,6 @@ 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
...
...
@@ -365,9 +368,7 @@ int main(void) {
srand
((
unsigned
)
time
(
0
));
// Setup and start Mongoose
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
if
((
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
))
==
NULL
)
{
if
((
ctx
=
mg_start
(
options
,
event_handler
,
NULL
))
==
NULL
)
{
printf
(
"%s
\n
"
,
"Cannot start chat server, fatal exit"
);
exit
(
EXIT_FAILURE
);
}
...
...
examples/hello.c
View file @
ecbf7913
...
...
@@ -3,42 +3,42 @@
#include "mongoose.h"
// 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
];
// 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
;
static
int
event_handler
(
struct
mg_event
*
event
)
{
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
char
content
[
100
];
// Prepare the message we're going to send
int
content_length
=
snprintf
(
content
,
sizeof
(
content
),
"Hello from mongoose! Requested: [%s] [%s]"
,
event
->
request_info
->
request_method
,
event
->
request_info
->
uri
);
// Send HTTP reply to the client
mg_printf
(
event
->
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
;
}
// We do not handle any other event
return
0
;
}
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
};
// 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
);
ctx
=
mg_start
(
options
,
&
event_handler
,
NULL
);
// Wait until user hits "enter". Server is running in separate thread.
// Navigating to http://localhost:8080 will invoke begin_request_handler().
...
...
examples/post.c
View file @
ecbf7913
...
...
@@ -10,45 +10,47 @@ static const char *html_form =
"<input type=
\"
submit
\"
/>"
"</form></body></html>"
;
static
int
begin_request_handler
(
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
static
int
event_handler
(
struct
mg_event
*
event
)
{
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
{
// 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
);
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
post_data_len
=
mg_read
(
event
->
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
(
event
->
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
(
event
->
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 event as processed
}
return
1
;
// Mark request as processed
// All other events are left not processed
return
0
;
}
int
main
(
void
)
{
struct
mg_context
*
ctx
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
NULL
};
struct
mg_callbacks
callbacks
;
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
ctx
=
mg_start
(
options
,
&
event_handler
,
NULL
);
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
...
...
examples/upload.c
View file @
ecbf7913
...
...
@@ -3,57 +3,48 @@
#include <stdio.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"
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
);
static
int
event_handler
(
struct
mg_event
*
event
)
{
if
(
event
->
type
==
MG_REQUEST_BEGIN
)
{
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
{
// 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
(
event
->
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 request as processed
return
1
;
}
//
Mark request as
processed
//
All other events left un
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
;
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
begin_request
=
begin_request_handler
;
callbacks
.
upload
=
upload_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
ctx
=
mg_start
(
options
,
event_handler
,
NULL
);
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
...
...
examples/websocket.c
View file @
ecbf7913
...
...
@@ -5,38 +5,52 @@
#include <string.h>
#include "mongoose.h"
static
void
websocket_ready_handler
(
struct
mg_connection
*
conn
)
{
static
const
char
*
message
=
"server ready"
;
mg_websocket_write
(
conn
,
WEBSOCKET_OPCODE_TEXT
,
message
,
strlen
(
message
));
}
static
int
event_handler
(
struct
mg_event
*
event
)
{
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:
// flags: first byte of websocket frame, see websocket RFC,
// http://tools.ietf.org/html/rfc6455, section 5.2
// data, data_len: payload data. Mask, if any, is already applied.
static
int
websocket_data_handler
(
struct
mg_connection
*
conn
,
int
flags
,
char
*
data
,
size_t
data_len
)
{
(
void
)
flags
;
// Unused
mg_websocket_write
(
conn
,
WEBSOCKET_OPCODE_TEXT
,
data
,
data_len
);
// Returning zero means stoping websocket conversation.
// Close the conversation if client has sent us "exit" string.
return
memcmp
(
data
,
"exit"
,
4
);
// Handshake, and send initial server message
mg_websocket_handshake
(
event
->
conn
);
mg_websocket_write
(
event
->
conn
,
WEBSOCKET_OPCODE_TEXT
,
server_ready_message
,
strlen
(
server_ready_message
));
while
((
len
=
mg_websocket_read
(
event
->
conn
,
&
bits
,
&
data
))
>
0
)
{
// Echo message back to the client
mg_websocket_write
(
event
->
conn
,
WEBSOCKET_OPCODE_TEXT
,
data
,
len
);
if
(
memcmp
(
data
,
"exit"
,
4
)
==
0
)
{
mg_websocket_write
(
event
->
conn
,
WEBSOCKET_OPCODE_CONNECTION_CLOSE
,
""
,
0
);
break
;
}
}
}
return
1
;
}
}
return
0
;
}
int
main
(
void
)
{
struct
mg_context
*
ctx
;
struct
mg_callbacks
callbacks
;
const
char
*
options
[]
=
{
"listening_ports"
,
"8080"
,
"document_root"
,
"websocket_html_root"
,
NULL
};
memset
(
&
callbacks
,
0
,
sizeof
(
callbacks
));
callbacks
.
websocket_ready
=
websocket_ready_handler
;
callbacks
.
websocket_data
=
websocket_data_handler
;
ctx
=
mg_start
(
&
callbacks
,
NULL
,
options
);
ctx
=
mg_start
(
options
,
&
event_handler
,
NULL
);
getchar
();
// Wait until user hits "enter"
mg_stop
(
ctx
);
...
...
mongoose.c
View file @
ecbf7913
This diff is collapsed.
Click to expand it.
mongoose.h
View file @
ecbf7913
...
...
@@ -25,8 +25,8 @@
extern
"C"
{
#endif // __cplusplus
struct
mg_context
;
//
Handle for the HTTP service itself
struct
mg_connection
;
// H
andle for the individual connection
struct
mg_context
;
//
Web server instance
struct
mg_connection
;
// H
TTP request descriptor
// This structure contains information about the HTTP request.
...
...
@@ -39,8 +39,6 @@ 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
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
struct
mg_header
{
...
...
@@ -49,37 +47,32 @@ struct mg_request_info {
}
http_headers
[
64
];
// Maximum 64 headers
};
enum
mg_event
{
MG_REQUEST_BEGIN
,
MG_REQUEST_END
,
MG_HTTP_ERROR
,
MG_EVENT_LOG
,
MG_THREAD_BEGIN
,
MG_THREAD_END
};
typedef
int
(
*
mg_callback_t
)(
enum
mg_event
event
,
struct
mg_connection
*
conn
,
void
*
data
);
struct
mg_callbacks
{
int
(
*
begin_request
)(
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
*
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_event
{
int
type
;
// Event type, possible types are defined below
#define MG_REQUEST_BEGIN 1 // event_param: NULL
#define MG_REQUEST_END 2 // event_param: NULL
#define MG_HTTP_ERROR 3 // event_param: int status_code
#define MG_EVENT_LOG 4 // event_param: const char *message
#define MG_THREAD_BEGIN 5 // event_param: NULL
#define MG_THREAD_END 6 // event_param: NULL
void
*
user_data
;
// User data pointer passed to mg_start()
void
*
conn_data
;
// Connection-specific, per-thread user data.
void
*
event_param
;
// Event-specific parameter
struct
mg_connection
*
conn
;
struct
mg_request_info
*
request_info
;
};
struct
mg_context
*
mg_start
(
const
struct
mg_callbacks
*
callbacks
,
void
*
user_data
,
const
char
**
configuration_options
);
typedef
int
(
*
mg_event_handler_t
)(
struct
mg_event
*
event
);
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_websocket_handshake
(
struct
mg_connection
*
);
int
mg_websocket_read
(
struct
mg_connection
*
,
int
*
bits
,
char
**
data
);
// Get the value of particular configuration parameter.
// 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,
const
char
*
user
,
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.
// Return:
// 0 when the connection has been closed
// -1 on error
// >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.
...
...
@@ -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 read error. No more data could be read from the connection.
// > 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.
...
...
@@ -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
);
// File upload functionality. Each uploaded file gets saved into a temporary
// file and MG_UPLOAD event is sent.
// Return number of uploaded files.
int
mg_upload
(
struct
mg_connection
*
conn
,
const
char
*
destination_dir
);
// Read multipart-form-data POST buffer, save uploaded files into
// destination directory, and return path to the saved filed.
// This function can be called multiple times for the same connection,
// 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.
...
...
test/unit_test.c
View file @
ecbf7913
This diff is collapsed.
Click to expand it.
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