Updated to latest mongoose code in agreement with author (nw)

This commit is contained in:
Miodrag Milanovic 2014-05-30 10:18:47 +00:00
parent 7dc5e8b533
commit ff99c901e9
4 changed files with 4904 additions and 5612 deletions

View File

@ -20,34 +20,6 @@
// WEB ENGINE
//**************************************************************************
void web_engine::websocket_ready_handler(struct mg_connection *conn) {
static const char *message = "update_machine";
mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, message, strlen(message));
m_websockets.append(*global_alloc(simple_list_wrapper<mg_connection>(conn)));
}
// 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.
int web_engine::websocket_data_handler(struct mg_connection *conn, int flags,
char *data, size_t data_len)
{
// just Echo example for now
if ((flags & 0x0f) == WEBSOCKET_OPCODE_TEXT)
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);
}
static void get_qsvar(const struct mg_request_info *request_info,
const char *name, char *dst, size_t dst_len) {
const char *qs = request_info->query_string;
mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
}
char* websanitize_statefilename ( char* unsanitized )
{
// It's important that we remove any dangerous characters from any filename
@ -107,7 +79,8 @@ int web_engine::json_game_handler(struct mg_connection *conn)
// Returning non-zero tells mongoose that our function has replied to
// the client, and mongoose should not send client any more data.
return 1;
return MG_TRUE;
}
int web_engine::json_slider_handler(struct mg_connection *conn)
@ -116,7 +89,7 @@ int web_engine::json_slider_handler(struct mg_connection *conn)
astring tempstring;
Json::Value array(Json::arrayValue);
/* add all sliders */
// add all sliders
for (curslider = machine().ui().get_slider_list(); curslider != NULL; curslider = curslider->next)
{
INT32 curval = (*curslider->update)(machine(), curslider->arg, &tempstring, SLIDER_NOCHANGE);
@ -130,7 +103,7 @@ int web_engine::json_slider_handler(struct mg_connection *conn)
array.append(data);
}
/* add all sliders */
// add all sliders
for (curslider = (slider_state*)machine().osd().get_slider_list(); curslider != NULL; curslider = curslider->next)
{
INT32 curval = (*curslider->update)(machine(), curslider->arg, &tempstring, SLIDER_NOCHANGE);
@ -154,28 +127,27 @@ int web_engine::json_slider_handler(struct mg_connection *conn)
"%s",
(int)strlen(json), json);
return 1;
return MG_TRUE;
}
// This function will be called by mongoose on every new request.
int web_engine::begin_request_handler(struct mg_connection *conn)
{
const struct mg_request_info *request_info = mg_get_request_info(conn);
if (!strncmp(request_info->uri, "/json/",6))
if (!strncmp(conn->uri, "/json/",6))
{
if (!strcmp(request_info->uri, "/json/game"))
if (!strcmp(conn->uri, "/json/game"))
{
return json_game_handler(conn);
}
if (!strcmp(request_info->uri, "/json/slider"))
if (!strcmp(conn->uri, "/json/slider"))
{
return json_slider_handler(conn);
}
}
else if (!strncmp(request_info->uri, "/cmd",4))
else if (!strncmp(conn->uri, "/cmd",4))
{
char cmd_name[64];
get_qsvar(request_info, "name", cmd_name, sizeof(cmd_name));
mg_get_var(conn, "name", cmd_name, sizeof(cmd_name));
if(!strcmp(cmd_name,"softreset"))
{
@ -199,14 +171,14 @@ int web_engine::begin_request_handler(struct mg_connection *conn)
else if(!strcmp(cmd_name,"savestate"))
{
char cmd_val[64];
get_qsvar(request_info, "val", cmd_val, sizeof(cmd_val));
mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
char *filename = websanitize_statefilename(cmd_val);
m_machine->schedule_save(filename);
}
else if(!strcmp(cmd_name,"loadstate"))
{
char cmd_val[64];
get_qsvar(request_info, "val", cmd_val, sizeof(cmd_val));
mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
char *filename = cmd_val;
m_machine->schedule_load(filename);
}
@ -226,14 +198,14 @@ int web_engine::begin_request_handler(struct mg_connection *conn)
// Returning non-zero tells mongoose that our function has replied to
// the client, and mongoose should not send client any more data.
return 1;
return MG_TRUE;
}
else if (!strncmp(request_info->uri, "/slider",7))
else if (!strncmp(conn->uri, "/slider",7))
{
char cmd_id[64];
char cmd_val[64];
get_qsvar(request_info, "id", cmd_id, sizeof(cmd_id));
get_qsvar(request_info, "val", cmd_val, sizeof(cmd_val));
mg_get_var(conn, "id", cmd_id, sizeof(cmd_id));
mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
int cnt = 0;
int id = atoi(cmd_id);
const slider_state *curslider;
@ -260,106 +232,107 @@ int web_engine::begin_request_handler(struct mg_connection *conn)
// Returning non-zero tells mongoose that our function has replied to
// the client, and mongoose should not send client any more data.
return 1;
return MG_TRUE;
}
else if (!strncmp(request_info->uri, "/screenshot.png",15))
else if (!strncmp(conn->uri, "/screenshot.png",15))
{
screen_device_iterator iter(m_machine->root_device());
screen_device *screen = iter.first();
if (screen == NULL)
FILE *fp = (FILE *) conn->connection_param;
char buf[200];
size_t n = 0;
if (fp == NULL)
{
return 0;
screen_device_iterator iter(m_machine->root_device());
screen_device *screen = iter.first();
if (screen == NULL)
{
return 0;
}
astring fname("screenshot.png");
{
emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
file_error filerr = file.open(fname);
if (filerr != FILERR_NONE)
{
return 0;
}
m_machine->video().save_snapshot(screen, file);
astring fullpath(file.fullpath());
file.close();
}
{
emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_READ);
file_error filerr = file.open(fname);
if (filerr != FILERR_NONE)
{
return 0;
}
file.seek(0, SEEK_SET);
mg_send_header(conn, "Content-Type", "image/png");
mg_send_header(conn, "Cache-Control", "no-cache, no-store, must-revalidate");
mg_send_header(conn, "Pragma", "no-cache");
mg_send_header(conn, "Expires", "0");
do
{
n = file.read(buf, sizeof(buf));
mg_send_data(conn, buf, n);
}
while (n==sizeof(buf));
file.close();
}
}
astring fname("screenshot.png");
emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
file_error filerr = file.open(fname);
if (filerr != FILERR_NONE)
{
return 0;
}
m_machine->video().save_snapshot(screen, file);
astring fullpath(file.fullpath());
file.close();
mg_send_file(conn,fullpath);
return 1;
return MG_TRUE;
}
return 0;
}
void *web_engine::websocket_keepalive()
{
while(!m_exiting_core)
{
osd_ticks_t curtime = osd_ticks();
if ((curtime - m_lastupdatetime) > osd_ticks_per_second() * 5)
{
m_lastupdatetime = curtime;
for (simple_list_wrapper<mg_connection> *curitem = m_websockets.first(); curitem != NULL; curitem = curitem->next())
{
int status = mg_websocket_write(curitem->object(), WEBSOCKET_OPCODE_PING, NULL, 0);
if (status==0) m_websockets.detach(*curitem); // remove inactive clients
}
}
osd_sleep(osd_ticks_per_second()/5);
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
if (conn->is_websocket) {
// This handler is called for each incoming websocket frame, one or more
// times for connection lifetime.
// Echo websocket data back to the client.
//const char *msg = "update_machine";
//mg_websocket_write(conn, 1, msg, strlen(msg));
return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ? MG_FALSE : MG_TRUE;
} else {
web_engine *engine = static_cast<web_engine *>(conn->server_param);
return engine->begin_request_handler(conn);
}
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
static int iterate_callback(struct mg_connection *c, enum mg_event ev) {
if (ev == MG_POLL && c->is_websocket) {
char buf[20];
int len = snprintf(buf, sizeof(buf), "%lu",
(unsigned long) * (time_t *) c->callback_param);
mg_websocket_write(c, 1, buf, len);
}
return MG_TRUE;
}
static void *serve(void *server) {
time_t current_timer = 0, last_timer = time(NULL);
for (;;) mg_poll_server((struct mg_server *) server, 1000);
current_timer = time(NULL);
if (current_timer - last_timer > 0) {
last_timer = current_timer;
mg_iterate_over_connections((struct mg_server *)server, iterate_callback, &current_timer);
}
return NULL;
}
//-------------------------------------------------
// static callbacks
//-------------------------------------------------
static void websocket_ready_handler_static(struct mg_connection *conn)
{
const struct mg_request_info *request_info = mg_get_request_info(conn);
web_engine *engine = static_cast<web_engine *>(request_info->user_data);
engine->websocket_ready_handler(conn);
}
static int websocket_data_handler_static(struct mg_connection *conn, int flags,
char *data, size_t data_len)
{
const struct mg_request_info *request_info = mg_get_request_info(conn);
web_engine *engine = static_cast<web_engine *>(request_info->user_data);
return engine->websocket_data_handler(conn, flags, data, data_len);
}
static int begin_request_handler_static(struct mg_connection *conn)
{
const struct mg_request_info *request_info = mg_get_request_info(conn);
web_engine *engine = static_cast<web_engine *>(request_info->user_data);
return engine->begin_request_handler(conn);
}
static int begin_http_error_handler_static(struct mg_connection *conn, int status)
{
//const struct mg_request_info *request_info = mg_get_request_info(conn);
if (status == 404) // 404 -- File Not Found
{
{
mg_printf(conn,
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 14\r\n" // Always set Content-Length
"\r\n"
"Nothing to do.");
}
}
// 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 void *websocket_keepalive_static(void *thread_func_param)
{
web_engine *engine = static_cast<web_engine *>(thread_func_param);
return engine->websocket_keepalive();
}
//-------------------------------------------------
// web_engine - constructor
//-------------------------------------------------
@ -367,32 +340,18 @@ static void *websocket_keepalive_static(void *thread_func_param)
web_engine::web_engine(emu_options &options)
: m_options(options),
m_machine(NULL),
m_ctx(NULL),
m_server(NULL),
m_lastupdatetime(0),
m_exiting_core(false)
{
struct mg_callbacks callbacks;
// List of options. Last element must be NULL.
const char *web_options[] = {
"listening_ports", options.http_port(),
"document_root", options.http_path(),
NULL
};
// Prepare callbacks structure.
memset(&callbacks, 0, sizeof(callbacks));
callbacks.begin_request = begin_request_handler_static;
callbacks.websocket_ready = websocket_ready_handler_static;
callbacks.websocket_data = websocket_data_handler_static;
callbacks.http_error = begin_http_error_handler_static;
// Start the web server.
if (m_options.http()) {
m_ctx = mg_start(&callbacks, this, web_options);
mg_start_thread(websocket_keepalive_static, this);
m_server = mg_create_server(this, ev_handler);
mg_set_option(m_server, "listening_port", options.http_port());
mg_set_option(m_server, "document_root", options.http_path());
mg_start_thread(serve, m_server);
}
}
@ -414,21 +373,20 @@ web_engine::~web_engine()
void web_engine::close()
{
m_exiting_core = 1;
osd_sleep(osd_ticks_per_second()/5);
for (simple_list_wrapper<mg_connection> *curitem = m_websockets.first(); curitem != NULL; curitem = curitem->next())
{
mg_websocket_write(curitem->object(), WEBSOCKET_OPCODE_CONNECTION_CLOSE, NULL, 0);
}
// Stop the server.
mg_stop(m_ctx);
// Cleanup, and free server instance
mg_destroy_server(&m_server);
}
static int websocket_callback(struct mg_connection *c, enum mg_event ev) {
if (c->is_websocket) {
const char *message = (const char *)c->callback_param;
mg_websocket_write(c, 1, message, strlen(message));
}
return MG_TRUE;
}
void web_engine::push_message(const char *message)
{
for (simple_list_wrapper<mg_connection> *curitem = m_websockets.first(); curitem != NULL; curitem = curitem->next())
{
int status = mg_websocket_write(curitem->object(), WEBSOCKET_OPCODE_TEXT, message, strlen(message));
if (status==0) m_websockets.remove(*curitem); // remove inactive clients
}
if (m_server!=NULL)
mg_iterate_over_connections(m_server, websocket_callback, (void*)message);
}

View File

@ -13,7 +13,7 @@
#ifndef __WEB_ENGINE_H__
#define __WEB_ENGINE_H__
struct mg_context; // Handle for the HTTP service itself
struct mg_server; // Handle for the HTTP server itself
struct mg_connection; // Handle for the individual connection
class web_engine
@ -27,12 +27,7 @@ public:
void close();
void set_machine(running_machine &machine) { m_machine = &machine; }
void websocket_ready_handler(struct mg_connection *conn);
int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len);
int begin_request_handler(struct mg_connection *conn);
int begin_http_error_handler(struct mg_connection *conn, int status);
void *websocket_keepalive();
protected:
// getters
running_machine &machine() const { return *m_machine; }
@ -43,10 +38,9 @@ private:
// internal state
emu_options & m_options;
running_machine * m_machine;
struct mg_context * m_ctx;
struct mg_server * m_server;
osd_ticks_t m_lastupdatetime;
bool m_exiting_core;
simple_list<simple_list_wrapper<mg_connection> > m_websockets;
};
#endif /* __web_engine_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,380 +1,140 @@
// Copyright (c) 2004-2012 Sergey Lyubka
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013-2014 Cesanta Software Limited
// All rights reserved
//
// 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:
// This library is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>.
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// You are free to use this library under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// 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.
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/>.
//
// NOTE: Detailed API documentation is at http://cesanta.com/#docs
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
#include <stdio.h>
#include <stddef.h>
#define MONGOOSE_VERSION "5.4"
#include <stdio.h> // required for FILE
#include <stddef.h> // required for size_t
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
struct mg_context; // Handle for the HTTP service itself
struct mg_connection; // Handle for the individual connection
// This structure contains information about HTTP request.
struct mg_connection {
const char *request_method; // "GET", "POST", etc
const char *uri; // URL-decoded URI
const char *http_version; // E.g. "1.0", "1.1"
const char *query_string; // URL part after '?', not including '?', or NULL
char remote_ip[48]; // Max IPv6 string length is 45 characters
char local_ip[48]; // Local IP address
unsigned short remote_port; // Client's port
unsigned short local_port; // Local port number
// This structure contains information about the HTTP request.
struct mg_request_info {
const char *request_method; // "GET", "POST", etc
const char *uri; // URL-decoded URI
const char *http_version; // E.g. "1.0", "1.1"
const char *query_string; // URL part after '?', not including '?', or NULL
const char *remote_user; // Authenticated user, or NULL if no auth used
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()
int num_headers; // Number of HTTP headers
struct mg_header {
const char *name; // HTTP header name
const char *value; // HTTP header value
} http_headers[30];
int num_headers; // Number of HTTP headers
struct mg_header {
const char *name; // HTTP header name
const char *value; // HTTP header value
} http_headers[64]; // Maximum 64 headers
char *content; // POST (or websocket message) data, or NULL
size_t content_len; // Data length
int is_websocket; // Connection is a websocket connection
int status_code; // HTTP status code for HTTP error handler
int wsbits; // First byte of the websocket frame
void *server_param; // Parameter passed to mg_add_uri_handler()
void *connection_param; // Placeholder for connection-specific data
void *callback_param; // Needed by mg_iterate_over_connections()
};
// This structure needs to be passed to mg_start(), to let mongoose know
// which callbacks to invoke. For detailed description, see
// https://github.com/valenok/mongoose/blob/master/UserManual.md
struct mg_callbacks {
// Called when mongoose has received new HTTP request.
// If callback returns non-zero,
// callback must process the request by sending valid HTTP headers and body,
// and mongoose will not do any further processing.
// If callback returns 0, mongoose processes the request itself. In this case,
// callback must not send any data to the client.
int (*begin_request)(struct mg_connection *);
// Called when mongoose has finished processing request.
void (*end_request)(const struct mg_connection *, int reply_status_code);
// Called when mongoose is about to log a message. If callback returns
// non-zero, mongoose does not log anything.
int (*log_message)(const struct mg_connection *, const char *message);
// Called when mongoose initializes SSL library.
int (*init_ssl)(void *ssl_context, void *user_data);
// Called when websocket request is received, before websocket handshake.
// If callback returns 0, mongoose proceeds with handshake, otherwise
// cinnection is closed immediately.
int (*websocket_connect)(const struct mg_connection *);
// Called when websocket handshake is successfully completed, and
// connection is ready for data exchange.
void (*websocket_ready)(struct mg_connection *);
// Called when data frame has been received from the client.
// Parameters:
// bits: first byte of the websocket frame, see websocket RFC at
// http://tools.ietf.org/html/rfc6455, section 5.2
// data, data_len: payload, with mask (if any) already applied.
// Return value:
// non-0: keep this websocket connection opened.
// 0: close this websocket connection.
int (*websocket_data)(struct mg_connection *, int bits,
char *data, size_t data_len);
// Called when mongoose tries to open a file. Used to intercept file open
// calls, and serve file data from memory instead.
// Parameters:
// path: Full path to the file to open.
// data_len: Placeholder for the file size, if file is served from memory.
// Return value:
// NULL: do not serve file from memory, proceed with normal file open.
// non-NULL: pointer to the file contents in memory. data_len must be
// initilized with the size of the memory block.
const char * (*open_file)(const struct mg_connection *,
const char *path, size_t *data_len);
// Called when mongoose is about to serve Lua server page (.lp file), if
// Lua support is enabled.
// Parameters:
// lua_context: "lua_State *" pointer.
void (*init_lua)(struct mg_connection *, void *lua_context);
// Called when mongoose has uploaded a file to a temporary directory as a
// result of mg_upload() call.
// Parameters:
// file_file: full path name to the uploaded file.
void (*upload)(struct mg_connection *, const char *file_name);
// Called when mongoose is about to send HTTP error to the client.
// Implementing this callback allows to create custom error pages.
// Parameters:
// status: HTTP error status code.
int (*http_error)(struct mg_connection *, int status);
struct mg_server; // Opaque structure describing server instance
enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
enum mg_event {
MG_POLL = 100, // Callback return value is ignored
MG_CONNECT, // If callback returns MG_FALSE, connect fails
MG_AUTH, // If callback returns MG_FALSE, authentication fails
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
MG_REPLY, // If callback returns MG_FALSE, Mongoose closes connection
MG_CLOSE, // Connection is closed, callback return value is ignored
MG_WS_HANDSHAKE, // New websocket connection, handshake request
MG_HTTP_ERROR // If callback returns MG_FALSE, Mongoose continues with err
};
typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
// Start web server.
//
// Parameters:
// callbacks: mg_callbacks structure with user-defined callbacks.
// options: NULL terminated list of option_name, option_value pairs that
// specify Mongoose configuration parameters.
//
// Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
// processing is required for these, signal handlers must be set up
// after calling mg_start().
//
//
// Example:
// const char *options[] = {
// "document_root", "/var/www",
// "listening_ports", "80,443s",
// NULL
// };
// struct mg_context *ctx = mg_start(&my_func, NULL, options);
//
// Refer to https://github.com/valenok/mongoose/blob/master/UserManual.md
// for the list of valid option and their possible values.
//
// Return:
// web server context, or NULL on error.
struct mg_context *mg_start(const struct mg_callbacks *callbacks,
void *user_data,
const char **configuration_options);
// Stop the web server.
//
// Must be called last, when an application wants to stop the web server and
// release all associated resources. This function blocks until all Mongoose
// threads are stopped. Context pointer becomes invalid.
void mg_stop(struct mg_context *);
// Get the value of particular configuration parameter.
// The value returned is read-only. Mongoose does not allow changing
// configuration at run time.
// If given parameter name is not valid, NULL is returned. For valid
// names, return value is guaranteed to be non-NULL. If parameter is not
// set, zero-length string is returned.
const char *mg_get_option(const struct mg_context *ctx, const char *name);
// Return array of strings that represent valid configuration options.
// For each option, a short name, long name, and default value is returned.
// Array is NULL terminated.
const char **mg_get_valid_option_names(void);
// Add, edit or delete the entry in the passwords file.
//
// This function allows an application to manipulate .htpasswd files on the
// fly by adding, deleting and changing user records. This is one of the
// several ways of implementing authentication on the server side. For another,
// cookie-based way please refer to the examples/chat.c in the source tree.
//
// If password is not NULL, entry is added (or modified if already exists).
// If password is NULL, entry is deleted.
//
// Return:
// 1 on success, 0 on error.
int mg_modify_passwords_file(const char *passwords_file_name,
const char *domain,
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);
// Send data to a websocket client wrapped in a websocket frame.
// It is unsafe to read/write to this connection from another thread.
// This function is available when mongoose is compiled with -DUSE_WEBSOCKET
//
// Return:
// 0 when the connection has been closed
// -1 on error
// >0 number of bytes written on success
int mg_websocket_write(struct mg_connection* conn, int opcode,
const char *data, size_t data_len);
// Opcodes, from http://tools.ietf.org/html/rfc6455
// Websocket opcodes, from http://tools.ietf.org/html/rfc6455
enum {
WEBSOCKET_OPCODE_CONTINUATION = 0x0,
WEBSOCKET_OPCODE_TEXT = 0x1,
WEBSOCKET_OPCODE_BINARY = 0x2,
WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
WEBSOCKET_OPCODE_PING = 0x9,
WEBSOCKET_OPCODE_PONG = 0xa
WEBSOCKET_OPCODE_CONTINUATION = 0x0,
WEBSOCKET_OPCODE_TEXT = 0x1,
WEBSOCKET_OPCODE_BINARY = 0x2,
WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
WEBSOCKET_OPCODE_PING = 0x9,
WEBSOCKET_OPCODE_PONG = 0xa
};
// Server management functions
struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
int mg_poll_server(struct mg_server *, int milliseconds);
const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name);
void mg_set_listening_socket(struct mg_server *, int sock);
int mg_get_listening_socket(struct mg_server *);
void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
void mg_wakeup_server(struct mg_server *);
void mg_wakeup_server_ex(struct mg_server *, mg_handler_t, const char *, ...);
struct mg_connection *mg_connect(struct mg_server *, const char *, int, int);
// Macros for enabling compiler-specific checks for printf-like arguments.
#undef PRINTF_FORMAT_STRING
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#include <sal.h>
#if defined(_MSC_VER) && (_MSC_VER > 1400)
#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
#else
#define PRINTF_FORMAT_STRING(s) __format_string s
#endif
#else
#define PRINTF_FORMAT_STRING(s) s
#endif
// Connection management functions
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name, const char *val);
void mg_send_data(struct mg_connection *, const void *data, int data_len);
void mg_printf_data(struct mg_connection *, const char *format, ...);
#ifdef __GNUC__
#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
#else
#define PRINTF_ARGS(x, y)
#endif
int mg_websocket_write(struct mg_connection *, int opcode,
const char *data, size_t data_len);
int mg_websocket_printf(struct mg_connection* conn, int opcode,
const char *fmt, ...);
// Send data to the client using printf() semantics.
//
// Works exactly like mg_write(), but allows to do message formatting.
int mg_printf(struct mg_connection *,
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
// Deprecated in favor of mg_send_* interface
int mg_write(struct mg_connection *, const void *buf, int len);
int mg_printf(struct mg_connection *conn, const char *fmt, ...);
// Send contents of the entire file together with HTTP headers.
void mg_send_file(struct mg_connection *conn, const char *path);
// Read data from the remote end, return number of bytes read.
// Return:
// 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);
// Get the value of particular HTTP header.
//
// This is a helper function. It traverses request_info->http_headers array,
// and if the header is present in the array, returns its value. If it is
// not present, NULL is returned.
const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
int mg_parse_multipart(const char *buf, int buf_len,
char *var_name, int var_name_len,
char *file_name, int file_name_len,
const char **data, int *data_len);
// Get a value of particular form variable.
//
// Parameters:
// data: pointer to form-uri-encoded buffer. This could be either POST data,
// or request_info.query_string.
// data_len: length of the encoded data.
// var_name: variable name to decode from the buffer
// dst: destination buffer for the decoded variable
// dst_len: length of the destination buffer
//
// Return:
// On success, length of the decoded variable.
// On error:
// -1 (variable not found).
// -2 (destination buffer is NULL, zero length or too small to hold the
// decoded variable).
//
// Destination buffer is guaranteed to be '\0' - terminated if it is not
// NULL or zero length.
int mg_get_var(const char *data, size_t data_len,
const char *var_name, char *dst, size_t dst_len);
// Fetch value of certain cookie variable into the destination buffer.
//
// Destination buffer is guaranteed to be '\0' - terminated. In case of
// failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
// parameter. This function returns only first occurrence.
//
// Return:
// On success, value length.
// On error:
// -1 (either "Cookie:" header is not present at all or the requested
// parameter is not found).
// -2 (destination buffer is NULL, zero length or too small to hold the
// value).
int mg_get_cookie(const char *cookie, const char *var_name,
char *buf, size_t buf_len);
// Download data from the remote web server.
// host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
// port: port number, e.g. 80.
// use_ssl: wether to use SSL connection.
// error_buffer, error_buffer_size: error message placeholder.
// request_fmt,...: HTTP request.
// Return:
// On success, valid pointer to the new connection, suitable for mg_read().
// On error, NULL. error_buffer contains error message.
// Example:
// char ebuf[100];
// struct mg_connection *conn;
// conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
// "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
struct mg_connection *mg_download(const char *host, int port, int use_ssl,
char *error_buffer, size_t error_buffer_size,
PRINTF_FORMAT_STRING(const char *request_fmt),
...) PRINTF_ARGS(6, 7);
// Close the connection opened by mg_download().
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);
// Convenience function -- create detached thread.
// Return: 0 on success, non-0 on error.
typedef void * (*mg_thread_func_t)(void *);
int mg_start_thread(mg_thread_func_t f, void *p);
// Return builtin mime type for the given file name.
// For unrecognized extensions, "text/plain" is returned.
const char *mg_get_builtin_mime_type(const char *file_name);
// Return Mongoose version.
const char *mg_version(void);
// URL-decode input buffer into destination buffer.
// 0-terminate the destination buffer.
// form-url-encoded data differs from URI encoding in a way that it
// uses '+' as character for space, see RFC 1866 section 8.2.1
// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
// Return: length of the decoded data, or -1 if dst buffer is too small.
int mg_url_decode(const char *src, int src_len, char *dst,
int dst_len, int is_form_url_encoded);
// MD5 hash given strings.
// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
// ASCIIz strings. When function returns, buf will contain human-readable
// MD5 hash. Example:
// char buf[33];
// mg_md5(buf, "aa", "bb", NULL);
// Utility functions
void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...);
int mg_authorize_digest(struct mg_connection *c, FILE *fp);
int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int);
// Templates support
struct mg_expansion {
const char *keyword;
void (*handler)(struct mg_connection *);
};
void mg_template(struct mg_connection *, const char *text,
struct mg_expansion *expansions);
#ifdef __cplusplus