mirror of
https://github.com/holub/mame
synced 2025-04-24 17:30:55 +03:00
Updated to latest mongoose code in agreement with author (nw)
This commit is contained in:
parent
7dc5e8b533
commit
ff99c901e9
@ -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, ¤t_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);
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user