Permalink
Browse files

API CHANGE: using struct mg_callbacks

  • Loading branch information...
1 parent 62162ff commit ee55d38b5592cbb55b78c74c2c36fc768fc22a07 @cpq cpq committed Feb 1, 2013
Showing with 284 additions and 386 deletions.
  1. +20 −26 examples/chat.c
  2. +35 −21 examples/hello.c
  3. +30 −35 examples/post.c
  4. +29 −27 examples/upload.c
  5. +46 −45 examples/websocket.c
  6. +8 −9 main.c
  7. +54 −59 mongoose.c
  8. +13 −115 mongoose.h
  9. +1 −1 test/test.pl
  10. +48 −48 test/unit_test.c
View
46 examples/chat.c
@@ -325,34 +325,25 @@ static void redirect_to_ssl(struct mg_connection *conn,
}
}
-static void *event_handler(enum mg_event event,
- struct mg_connection *conn) {
+static int begin_request_handler(struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
- void *processed = "yes";
-
- if (event == MG_NEW_REQUEST) {
- if (!request_info->is_ssl) {
- redirect_to_ssl(conn, request_info);
- } else if (!is_authorized(conn, request_info)) {
- redirect_to_login(conn, request_info);
- } else if (strcmp(request_info->uri, authorize_url) == 0) {
- authorize(conn, request_info);
- } else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
- ajax_get_messages(conn, request_info);
- } else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
- ajax_send_message(conn, request_info);
- } else {
- // No suitable handler found, mark as not processed. Mongoose will
- // try to serve the request.
- processed = NULL;
- }
- } else if (event == MG_EVENT_LOG) {
- printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
- processed = NULL;
+ int processed = 1;
+
+ if (!request_info->is_ssl) {
+ redirect_to_ssl(conn, request_info);
+ } else if (!is_authorized(conn, request_info)) {
+ redirect_to_login(conn, request_info);
+ } else if (strcmp(request_info->uri, authorize_url) == 0) {
+ authorize(conn, request_info);
+ } else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
+ ajax_get_messages(conn, request_info);
+ } else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
+ ajax_send_message(conn, request_info);
} else {
- processed = NULL;
+ // No suitable handler found, mark as not processed. Mongoose will
+ // try to serve the request.
+ processed = 0;
}
-
return processed;
}
@@ -365,14 +356,17 @@ 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
// the session identifier creation.
srand((unsigned) time(0));
// Setup and start Mongoose
- if ((ctx = mg_start(&event_handler, NULL, options)) == NULL) {
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+ if ((ctx = mg_start(&callbacks, NULL, options)) == NULL) {
printf("%s\n", "Cannot start chat server, fatal exit");
exit(EXIT_FAILURE);
}
View
56 examples/hello.c
@@ -2,35 +2,49 @@
#include <string.h>
#include "mongoose.h"
-static void *callback(enum mg_event event,
- struct mg_connection *conn) {
+// This function will be called by mongoose on every new request.
+static int begin_request_handler(struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
+ char content[100];
- if (event == MG_NEW_REQUEST) {
- char content[1024];
- int content_length = snprintf(content, sizeof(content),
- "Hello from mongoose! Remote port: %d",
- request_info->remote_port);
- mg_printf(conn,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/plain\r\n"
- "Content-Length: %d\r\n" // Always set Content-Length
- "\r\n"
- "%s",
- content_length, content);
- // Mark as processed
- return "";
- } else {
- return NULL;
- }
+ // Prepare the message we're going to send
+ int content_length = snprintf(content, sizeof(content),
+ "Hello from mongoose! Remote port: %d",
+ request_info->remote_port);
+
+ // Send HTTP reply to the client
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: %d\r\n" // Always set Content-Length
+ "\r\n"
+ "%s",
+ content_length, content);
+
+ // Returning non-zero tells mongoose that our function has replied to
+ // the client, and mongoose should not send client any more data.
+ return 1;
}
int main(void) {
struct mg_context *ctx;
+ struct mg_callbacks callbacks;
+
+ // List of options. Last element must be NULL.
const char *options[] = {"listening_ports", "8080", NULL};
- ctx = mg_start(&callback, NULL, options);
- getchar(); // Wait until user hits "enter"
+ // Prepare callbacks structure. We have only one callback, the rest are NULL.
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+
+ // Start the web server.
+ ctx = mg_start(&callbacks, NULL, options);
+
+ // Wait until user hits "enter". Server is running in separate thread.
+ // Navigating to http://localhost:8080 will invoke begin_request_handler().
+ getchar();
+
+ // Stop the server.
mg_stop(ctx);
return 0;
View
65 examples/post.c
@@ -10,50 +10,45 @@ static const char *html_form =
"<input type=\"submit\" />"
"</form></body></html>";
-static void *callback(enum mg_event event,
- struct mg_connection *conn) {
+static int begin_request_handler(struct mg_connection *conn) {
const struct mg_request_info *ri = mg_get_request_info(conn);
-
- if (event == MG_NEW_REQUEST) {
- if (!strcmp(ri->uri, "/handle_post_request")) {
- // User has submitted a form, show submitted data and a variable value
- char post_data[1024],
- input1[sizeof(post_data)], input2[sizeof(post_data)];
- int post_data_len;
-
- // Read POST data
- post_data_len = mg_read(conn, post_data, sizeof(post_data));
-
- // Parse form data. input1 and input2 are guaranteed to be NUL-terminated
- mg_get_var(post_data, post_data_len, "input_1", input1, sizeof(input1));
- mg_get_var(post_data, post_data_len, "input_2", input2, sizeof(input2));
-
- mg_printf(conn, "HTTP/1.0 200 OK\r\n"
- "Content-Type: text/plain\r\n\r\n"
- "Submitted data: [%.*s]\n"
- "Submitted data length: %d bytes\n"
- "input_1: [%s]\n"
- "input_2: [%s]\n",
- post_data_len, post_data, post_data_len, input1, input2);
- } else {
- // Show HTML form.
- mg_printf(conn, "HTTP/1.0 200 OK\r\n"
- "Content-Length: %d\r\n"
- "Content-Type: text/html\r\n\r\n%s",
- (int) strlen(html_form), html_form);
- }
- // Mark as processed
- return "";
+ char post_data[1024], input1[sizeof(post_data)], input2[sizeof(post_data)];
+ int post_data_len;
+
+ if (!strcmp(ri->uri, "/handle_post_request")) {
+ // User has submitted a form, show submitted data and a variable value
+ post_data_len = mg_read(conn, post_data, sizeof(post_data));
+
+ // Parse form data. input1 and input2 are guaranteed to be NUL-terminated
+ mg_get_var(post_data, post_data_len, "input_1", input1, sizeof(input1));
+ mg_get_var(post_data, post_data_len, "input_2", input2, sizeof(input2));
+
+ // Send reply to the client, showing submitted form values.
+ mg_printf(conn, "HTTP/1.0 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "Submitted data: [%.*s]\n"
+ "Submitted data length: %d bytes\n"
+ "input_1: [%s]\n"
+ "input_2: [%s]\n",
+ post_data_len, post_data, post_data_len, input1, input2);
} else {
- return NULL;
+ // Show HTML form.
+ mg_printf(conn, "HTTP/1.0 200 OK\r\n"
+ "Content-Length: %d\r\n"
+ "Content-Type: text/html\r\n\r\n%s",
+ (int) strlen(html_form), html_form);
}
+ return 1; // Mark request as processed
}
int main(void) {
struct mg_context *ctx;
const char *options[] = {"listening_ports", "8080", NULL};
+ struct mg_callbacks callbacks;
- ctx = mg_start(&callback, NULL, options);
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+ ctx = mg_start(&callbacks, NULL, options);
getchar(); // Wait until user hits "enter"
mg_stop(ctx);
View
56 examples/upload.c
@@ -17,42 +17,44 @@ typedef __int64 int64_t;
#include "mongoose.h"
-static void *callback(enum mg_event event, struct mg_connection *conn) {
- if (event == MG_NEW_REQUEST) {
- if (!strcmp(mg_get_request_info(conn)->uri, "/handle_post_request")) {
- mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n");
- mg_upload(conn, "/tmp");
- } else {
- // Show HTML form. Make sure it has enctype="multipart/form-data" attr.
- static const char *html_form =
- "<html><body>Upload example."
- "<form method=\"POST\" action=\"/handle_post_request\" "
- " enctype=\"multipart/form-data\">"
- "<input type=\"file\" name=\"file\" /> <br/>"
- "<input type=\"submit\" value=\"Upload\" />"
- "</form></body></html>";
-
- mg_printf(conn, "HTTP/1.0 200 OK\r\n"
- "Content-Length: %d\r\n"
- "Content-Type: text/html\r\n\r\n%s",
- (int) strlen(html_form), html_form);
- }
- // Mark as processed
- return "";
- } else if (event == MG_UPLOAD) {
- mg_printf(conn, "Saved [%s]", mg_get_request_info(conn)->ev_data);
+static int begin_request_handler(struct mg_connection *conn) {
+ if (!strcmp(mg_get_request_info(conn)->uri, "/handle_post_request")) {
+ mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n");
+ mg_upload(conn, "/tmp");
+ } else {
+ // Show HTML form. Make sure it has enctype="multipart/form-data" attr.
+ static const char *html_form =
+ "<html><body>Upload example."
+ "<form method=\"POST\" action=\"/handle_post_request\" "
+ " enctype=\"multipart/form-data\">"
+ "<input type=\"file\" name=\"file\" /> <br/>"
+ "<input type=\"submit\" value=\"Upload\" />"
+ "</form></body></html>";
+
+ mg_printf(conn, "HTTP/1.0 200 OK\r\n"
+ "Content-Length: %d\r\n"
+ "Content-Type: text/html\r\n\r\n%s",
+ (int) strlen(html_form), html_form);
}
- return NULL;
+ // Mark request as processed
+ return 1;
+}
+
+static void upload_handler(struct mg_connection *conn, const char *path) {
+ mg_printf(conn, "Saved [%s]", path);
}
int main(void) {
struct mg_context *ctx;
const char *options[] = {"listening_ports", "8080", NULL};
+ struct mg_callbacks callbacks;
- ctx = mg_start(&callback, NULL, options);
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+ callbacks.upload = upload_handler;
+ ctx = mg_start(&callbacks, NULL, options);
getchar(); // Wait until user hits "enter"
- pause();
mg_stop(ctx);
return 0;
View
91 examples/websocket.c
@@ -5,69 +5,70 @@
#include <string.h>
#include "mongoose.h"
-static void *callback(enum mg_event event, struct mg_connection *conn) {
- if (event == MG_WEBSOCKET_READY) {
- unsigned char buf[40];
- buf[0] = 0x81;
- buf[1] = snprintf((char *) buf + 2, sizeof(buf) - 2, "%s", "server ready");
- mg_write(conn, buf, 2 + buf[1]);
- return ""; // MG_WEBSOCKET_READY return value is ignored
- } else if (event == MG_WEBSOCKET_MESSAGE) {
- unsigned char buf[200], reply[200];
- int n, i, mask_len, xor, msg_len, len;
+static void websocket_ready_handler(struct mg_connection *conn) {
+ unsigned char buf[40];
+ buf[0] = 0x81;
+ buf[1] = snprintf((char *) buf + 2, sizeof(buf) - 2, "%s", "server ready");
+ mg_write(conn, buf, 2 + buf[1]);
+}
+
+static int websocket_data_handler(struct mg_connection *conn) {
+ unsigned char buf[200], reply[200];
+ int n, i, mask_len, xor, msg_len, len;
- // Read message from the client.
- // Accept only small (<126 bytes) messages.
- len = 0;
- msg_len = mask_len = 0;
- for (;;) {
- if ((n = mg_read(conn, buf + len, sizeof(buf) - len)) <= 0) {
- return ""; // Read error, close websocket
+ // Read message from the client.
+ // Accept only small (<126 bytes) messages.
+ len = 0;
+ msg_len = mask_len = 0;
+ for (;;) {
+ if ((n = mg_read(conn, buf + len, sizeof(buf) - len)) <= 0) {
+ return 0; // Read error, close websocket
+ }
+ len += n;
+ if (len >= 2) {
+ msg_len = buf[1] & 127;
+ mask_len = (buf[1] & 128) ? 4 : 0;
+ if (msg_len > 125) {
+ return 0; // Message is too long, close websocket
}
- len += n;
- if (len >= 2) {
- msg_len = buf[1] & 127;
- mask_len = (buf[1] & 128) ? 4 : 0;
- if (msg_len > 125) {
- return ""; // Message is too long, close websocket
- }
- // If we've buffered the whole message, exit the loop
- if (len >= 2 + mask_len + msg_len) {
- break;
- }
+ // If we've buffered the whole message, exit the loop
+ if (len >= 2 + mask_len + msg_len) {
+ break;
}
}
+ }
- // Prepare frame
- reply[0] = 0x81; // text, FIN set
- reply[1] = msg_len;
+ // Prepare frame
+ reply[0] = 0x81; // text, FIN set
+ reply[1] = msg_len;
- // Copy message from request to reply, applying the mask if required.
- for (i = 0; i < msg_len; i++) {
- xor = mask_len == 0 ? 0 : buf[2 + (i % 4)];
- reply[i + 2] = buf[i + 2 + mask_len] ^ xor;
- }
+ // Copy message from request to reply, applying the mask if required.
+ for (i = 0; i < msg_len; i++) {
+ xor = mask_len == 0 ? 0 : buf[2 + (i % 4)];
+ reply[i + 2] = buf[i + 2 + mask_len] ^ xor;
+ }
- // Echo the message back to the client
- mg_write(conn, reply, 2 + msg_len);
+ // Echo the message back to the client
+ mg_write(conn, reply, 2 + msg_len);
- // Return non-NULL means stoping websocket conversation.
- // Close the conversation if client has sent us "exit" string.
- return memcmp(reply + 2, "exit", 4) == 0 ? "" : NULL;
- } else {
- return NULL;
- }
+ // Returnint zero means stoping websocket conversation.
+ // Close the conversation if client has sent us "exit" string.
+ return memcmp(reply + 2, "exit", 4);
}
int main(void) {
struct mg_context *ctx;
+ struct mg_callbacks callbacks;
const char *options[] = {
"listening_ports", "8080",
"document_root", "websocket_html_root",
NULL
};
- ctx = mg_start(&callback, NULL, options);
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.websocket_ready = websocket_ready_handler;
+ callbacks.websocket_data = websocket_data_handler;
+ ctx = mg_start(&callbacks, NULL, options);
getchar(); // Wait until user hits "enter"
mg_stop(ctx);
View
17 main.c
@@ -266,17 +266,14 @@ static void init_server_name(void) {
mg_version());
}
-static void *mongoose_callback(enum mg_event ev, struct mg_connection *conn) {
- if (ev == MG_EVENT_LOG) {
- printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
- }
-
- // Returning NULL marks request as not handled, signalling mongoose to
- // proceed with handling it.
- return NULL;
+static int log_message(const struct mg_connection *conn, const char *message) {
+ (void) conn;
+ printf("%s\n", message);
+ return 0;
}
static void start_mongoose(int argc, char *argv[]) {
+ struct mg_callbacks callbacks;
char *options[MAX_OPTIONS];
int i;
@@ -302,7 +299,9 @@ static void start_mongoose(int argc, char *argv[]) {
signal(SIGINT, signal_handler);
/* Start Mongoose */
- ctx = mg_start(&mongoose_callback, NULL, (const char **) options);
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.log_message = &log_message;
+ ctx = mg_start(&callbacks, NULL, (const char **) options);
for (i = 0; options[i] != NULL; i++) {
free(options[i]);
}
View
113 mongoose.c
@@ -466,11 +466,11 @@ static const char *config_options[] = {
#define ENTRIES_PER_CONFIG_OPTION 3
struct mg_context {
- volatile int stop_flag; // Should we stop event loop
- SSL_CTX *ssl_ctx; // SSL context
- char *config[NUM_OPTIONS]; // Mongoose configuration parameters
- mg_callback_t user_callback; // User-defined callback function
- void *user_data; // User-defined data
+ volatile int stop_flag; // Should we stop event loop
+ SSL_CTX *ssl_ctx; // SSL context
+ char *config[NUM_OPTIONS]; // Mongoose configuration parameters
+ struct mg_callbacks callbacks; // User-defined callback function
+ void *user_data; // User-defined data
struct socket *listening_sockets;
int num_listening_sockets;
@@ -512,20 +512,12 @@ const char **mg_get_valid_option_names(void) {
return config_options;
}
-static void *call_user(struct mg_connection *conn, enum mg_event event) {
- if (conn != NULL && conn->ctx != NULL) {
- conn->request_info.user_data = conn->ctx->user_data;
- }
- return conn == NULL || conn->ctx == NULL || conn->ctx->user_callback == NULL ?
- NULL : conn->ctx->user_callback(event, conn);
-}
-
static int is_file_in_memory(struct mg_connection *conn, const char *path,
struct file *filep) {
- conn->request_info.ev_data = (void *) path;
- if ((filep->membuf = call_user(conn, MG_OPEN_FILE)) != NULL) {
- filep->size = (long) conn->request_info.ev_data;
- }
+ size_t size = 0;
+ filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
+ conn->ctx->callbacks.open_file(conn, path, &size);
+ filep->size = size;
return filep->membuf != NULL;
}
@@ -610,8 +602,8 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
// Do not lock when getting the callback value, here and below.
// I suppose this is fine, since function cannot disappear in the
// same way string option can.
- conn->request_info.ev_data = buf;
- if (call_user(conn, MG_EVENT_LOG) == NULL) {
+ if (conn->ctx->callbacks.log_message == NULL ||
+ conn->ctx->callbacks.log_message(conn, buf) == 0) {
fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
@@ -634,7 +626,6 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
fclose(fp);
}
}
- conn->request_info.ev_data = NULL;
}
// Return fake connection structure. Used for logging, if connection
@@ -917,31 +908,27 @@ static void send_http_error(struct mg_connection *conn, int status,
const char *reason, const char *fmt, ...) {
char buf[MG_BUF_LEN];
va_list ap;
- int len;
+ int len = 0;
conn->status_code = status;
- conn->request_info.ev_data = (void *) (long) status;
- if (call_user(conn, MG_HTTP_ERROR) == NULL) {
- buf[0] = '\0';
- len = 0;
-
- // Errors 1xx, 204 and 304 MUST NOT send a body
- if (status > 199 && status != 204 && status != 304) {
- len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
- buf[len++] = '\n';
-
- va_start(ap, fmt);
- len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
- va_end(ap);
- }
- DEBUG_TRACE(("[%s]", buf));
+ buf[0] = '\0';
- mg_printf(conn, "HTTP/1.1 %d %s\r\n"
- "Content-Length: %d\r\n"
- "Connection: %s\r\n\r\n", status, reason, len,
- suggest_connection_header(conn));
- conn->num_bytes_sent += mg_printf(conn, "%s", buf);
+ // Errors 1xx, 204 and 304 MUST NOT send a body
+ if (status > 199 && status != 204 && status != 304) {
+ len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
+ buf[len++] = '\n';
+
+ va_start(ap, fmt);
+ len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
+ va_end(ap);
}
+ DEBUG_TRACE(("[%s]", buf));
+
+ mg_printf(conn, "HTTP/1.1 %d %s\r\n"
+ "Content-Length: %d\r\n"
+ "Connection: %s\r\n\r\n", status, reason, len,
+ suggest_connection_header(conn));
+ conn->num_bytes_sent += mg_printf(conn, "%s", buf);
}
#if defined(_WIN32) && !defined(__SYMBIAN32__)
@@ -2609,7 +2596,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
// print_dir_entry(). memset is required only if mg_stat()
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
- // mg_stat will memset the whole struct file with zeroes.
+ memset(&de.file, 0, sizeof(de.file));
mg_stat(conn, path, &de.file);
de.file_name = dp->d_name;
@@ -3797,7 +3784,8 @@ static void read_websocket(struct mg_connection *conn) {
}
if (conn->content_len > 0) {
- if (call_user(conn, MG_WEBSOCKET_MESSAGE) != NULL) {
+ if (conn->ctx->callbacks.websocket_data != NULL &&
+ conn->ctx->callbacks.websocket_data(conn) == 0) {
break; // Callback signalled to exit
}
discard_len = conn->content_len > body_len ?
@@ -3819,13 +3807,15 @@ static void read_websocket(struct mg_connection *conn) {
static void handle_websocket_request(struct mg_connection *conn) {
if (strcmp(mg_get_header(conn, "Sec-WebSocket-Version"), "13") != 0) {
send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
- } else if (call_user(conn, MG_WEBSOCKET_CONNECT) != NULL) {
- // Callback has returned non-NULL, do not proceed with handshake
+ } else if (conn->ctx->callbacks.websocket_connect != NULL &&
+ conn->ctx->callbacks.websocket_connect(conn) != 0) {
+ // Callback has returned non-zero, do not proceed with handshake
} else {
send_websocket_handshake(conn);
- call_user(conn, MG_WEBSOCKET_READY);
+ if (conn->ctx->callbacks.websocket_ready != NULL) {
+ conn->ctx->callbacks.websocket_ready(conn);
+ }
read_websocket(conn);
- call_user(conn, MG_WEBSOCKET_CLOSE);
}
}
@@ -4035,8 +4025,9 @@ static void handle_lsp_request(struct mg_connection *conn, const char *path,
} else {
// We're not sending HTTP headers here, Lua page must do it.
prepare_lua_environment(conn, L);
- conn->request_info.ev_data = L;
- call_user(conn, MG_INIT_LUA);
+ if (conn->ctx->callbacks.init_lua != NULL) {
+ conn->ctx->callbacks.init_lua(conn, L);
+ }
lsp(conn, filep->membuf == NULL ? p : filep->membuf, filep->size, L);
}
@@ -4135,8 +4126,9 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
fwrite(buf, 1, i, fp);
fflush(fp);
num_uploaded_files++;
- conn->request_info.ev_data = (void *) path;
- call_user(conn, MG_UPLOAD);
+ if (conn->ctx->callbacks.upload != NULL) {
+ conn->ctx->callbacks.upload(conn, path);
+ }
memmove(buf, &buf[i + bl], len - (i + bl));
len -= i + bl;
break;
@@ -4203,7 +4195,8 @@ static void handle_request(struct mg_connection *conn) {
get_remote_ip(conn), ri->uri);
DEBUG_TRACE(("%s", ri->uri));
- if (call_user(conn, MG_NEW_REQUEST) != NULL) {
+ if (conn->ctx->callbacks.begin_request != NULL &&
+ conn->ctx->callbacks.begin_request(conn)) {
// Do nothing, callback has served the request
} else if (!conn->client.is_ssl && conn->client.ssl_redir &&
(ssl_index = get_first_ssl_listener_index(conn->ctx)) > -1) {
@@ -4550,8 +4543,8 @@ static int set_ssl_option(struct mg_context *ctx) {
// If user callback returned non-NULL, that means that user callback has
// set up certificate itself. In this case, skip sertificate setting.
- fc(ctx)->request_info.ev_data = ctx->ssl_ctx;
- if (call_user(fc(ctx), MG_INIT_SSL) == NULL &&
+ if ((ctx->callbacks.init_ssl == NULL ||
+ !ctx->callbacks.init_ssl(ctx->ssl_ctx)) &&
(SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0)) {
cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
@@ -4608,7 +4601,7 @@ static int set_acl_option(struct mg_context *ctx) {
}
static void reset_per_request_attributes(struct mg_connection *conn) {
- conn->path_info = conn->request_info.ev_data = NULL;
+ conn->path_info = NULL;
conn->num_bytes_sent = conn->consumed_content = 0;
conn->status_code = -1;
conn->must_close = conn->request_len = conn->throttle = 0;
@@ -4811,8 +4804,9 @@ static void process_new_connection(struct mg_connection *conn) {
if (ebuf[0] == '\0') {
handle_request(conn);
- conn->request_info.ev_data = (void *) (long) conn->status_code;
- call_user(conn, MG_REQUEST_COMPLETE);
+ if (conn->ctx->callbacks.end_request != NULL) {
+ conn->ctx->callbacks.end_request(conn, conn->status_code);
+ }
log_access(conn);
}
if (ri->remote_user != NULL) {
@@ -5087,7 +5081,8 @@ void mg_stop(struct mg_context *ctx) {
#endif // _WIN32
}
-struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,
+struct mg_context *mg_start(const struct mg_callbacks *callbacks,
+ void *user_data,
const char **options) {
struct mg_context *ctx;
const char *name, *value, *default_value;
@@ -5104,7 +5099,7 @@ struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,
if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
return NULL;
}
- ctx->user_callback = user_callback;
+ ctx->callbacks = *callbacks;
@jmucchiello
jmucchiello Feb 10, 2013

Need to test for NULL here. Why did you get rid of my stub functions? The code would be much easier to read and maintain using the stub functions rather than testing the existence of a callback at each callback site.

ctx->user_data = user_data;
while (options && (name = *options++) != NULL) {
View
128 mongoose.h
@@ -42,140 +42,37 @@ struct mg_request_info {
long remote_ip; // Client's IP address
int remote_port; // Client's port
int is_ssl; // 1 if SSL-ed, 0 if not
- int num_headers; // Number of headers
+ void *user_data; // User data pointer passed to mg_start()
+
+ int num_headers; // Number of HTTP headers
struct mg_header {
const char *name; // HTTP header name
const char *value; // HTTP header value
} http_headers[64]; // Maximum 64 headers
- void *user_data; // User data pointer passed to mg_start()
- void *ev_data; // Event-specific data pointer
};
// 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 {
- int (*request_start)(struct mg_connection *);
- void (*request_done)(struct mg_connection *, int reply_status_code);
- int (*log_message)(struct mg_connection *, const char *message);
+ 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 (*websocket_connect)(struct mg_connection *);
+ int (*websocket_connect)(const struct mg_connection *);
void (*websocket_ready)(struct mg_connection *);
int (*websocket_data)(struct mg_connection *);
- void (*websocket_close)(struct mg_connection *);
- void (*open_file)(struct mg_connection *, char **data, size_t *data_len);
+ const char * (*open_file)(const struct mg_connection *,
+ const char *path, size_t *data_len);
void (*init_lua)(struct mg_connection *, void *lua_context);
void (*upload)(struct mg_connection *, const char *file_name);
};
-
-// Various events on which user-defined callback function is called by Mongoose.
-enum mg_event {
- // New HTTP request has arrived from the client.
- // If callback returns non-NULL, Mongoose stops handling current request.
- // ev_data contains NULL.
- MG_NEW_REQUEST,
-
- // Mongoose has finished handling the request.
- // Callback return value is ignored.
- // ev_data contains integer HTTP status code:
- // int http_reply_status_code = (long) request_info->ev_data;
- MG_REQUEST_COMPLETE,
-
- // HTTP error must be returned to the client.
- // If callback returns non-NULL, Mongoose stops handling error.
- // ev_data contains HTTP error code:
- // int http_reply_status_code = (long) request_info->ev_data;
- MG_HTTP_ERROR,
-
- // Mongoose logs a message.
- // If callback returns non-NULL, Mongoose stops handling that event.
- // ev_data contains a message to be logged:
- // const char *log_message = request_info->ev_data;
- MG_EVENT_LOG,
-
- // SSL initialization, sent before certificate setup.
- // If callback returns non-NULL, Mongoose does not set up certificates.
- // ev_data contains server's OpenSSL context:
- // SSL_CTX *ssl_context = request_info->ev_data;
- MG_INIT_SSL,
-
- // Sent on HTTP connect, before websocket handshake.
- // If user callback returns NULL, then mongoose proceeds
- // with handshake, otherwise it closes the connection.
- // ev_data contains NULL.
- MG_WEBSOCKET_CONNECT,
-
- // Handshake has been successfully completed.
- // Callback's return value is ignored.
- // ev_data contains NULL.
- MG_WEBSOCKET_READY,
-
- // Incoming message from the client, data could be read with mg_read().
- // If user callback returns non-NULL, mongoose closes the websocket.
- // ev_data contains NULL.
- MG_WEBSOCKET_MESSAGE,
-
- // Client has closed the connection.
- // Callback's return value is ignored.
- // ev_data contains NULL.
- MG_WEBSOCKET_CLOSE,
-
- // Mongoose tries to open file.
- // If callback returns non-NULL, Mongoose will not try to open it, but
- // will use the returned value as a pointer to the file data. This allows
- // for example to serve files from memory.
- // ev_data contains file path, including document root path.
- // Upon return, ev_data should return file size, which should be a long int.
- //
- // const char *file_name = request_info->ev_data;
- // if (strcmp(file_name, "foo.txt") == 0) {
- // request_info->ev_data = (void *) (long) 4;
- // return "data";
- // }
- // return NULL;
- //
- // Note that this even is sent multiple times during one request. Each
- // time mongoose tries to open or stat the file, this event is sent, e.g.
- // for opening .htpasswd file, stat-ting requested file, opening requested
- // file, etc.
- MG_OPEN_FILE,
-
- // Mongoose initializes Lua server page. Sent only if Lua support is enabled.
- // Callback's return value is ignored.
- // ev_data contains lua_State pointer.
- MG_INIT_LUA,
-
- // Mongoose has uploaded file to a temporary directory.
- // Callback's return value is ignored.
- // ev_data contains NUL-terminated file name.
- MG_UPLOAD,
-};
-
-
-// Prototype for the user-defined function. Mongoose calls this function
-// on every MG_* event.
-//
-// Parameters:
-// event: which event has been triggered.
-// conn: opaque connection handler. Could be used to read, write data to the
-// client, etc. See functions below that have "mg_connection *" arg.
-//
-// Return:
-// If handler returns non-NULL, that means that handler has processed the
-// request by sending appropriate HTTP reply to the client. Mongoose treats
-// the request as served.
-// If handler returns NULL, that means that handler has not processed
-// the request. Handler must not send any data to the client in this case.
-// Mongoose proceeds with request handling as if nothing happened.
-typedef void *(*mg_callback_t)(enum mg_event event, struct mg_connection *conn);
-
-
// Start web server.
//
// Parameters:
-// callback: user defined event handling function or NULL.
+// callbacks: mg_callbacks structure with user-defined callbacks.
// options: NULL terminated list of option_name, option_value pairs that
// specify Mongoose configuration parameters.
//
@@ -197,8 +94,9 @@ typedef void *(*mg_callback_t)(enum mg_event event, struct mg_connection *conn);
//
// Return:
// web server context, or NULL on error.
-struct mg_context *mg_start(mg_callback_t callback, void *user_data,
- const char **options);
+struct mg_context *mg_start(const struct mg_callbacks *callbacks,
+ void *user_data,
+ const char **configuration_options);
// Stop the web server.
View
2 test/test.pl
@@ -426,7 +426,7 @@ sub kill_spawned_child {
do_PUT_test();
kill_spawned_child();
do_unit_test();
- do_embedded_test();
+#do_embedded_test();
}
sub do_PUT_test {
View
96 test/unit_test.c
@@ -189,44 +189,61 @@ static const char *inmemory_file_data = "hi there";
static const char *upload_filename = "upload_test.txt";
static const char *upload_ok_message = "upload successful";
-static void *event_handler(enum mg_event event, struct mg_connection *conn) {
- const struct mg_request_info *request_info = mg_get_request_info(conn);
+static const char *open_file_cb(const struct mg_connection *conn,
+ const char *path, size_t *size) {
+ (void) conn;
+ if (!strcmp(path, "./blah")) {
+ *size = strlen(inmemory_file_data);
+ return inmemory_file_data;
+ }
+ return NULL;
+}
+
+static void upload_cb(struct mg_connection *conn, const char *path) {
+ char *p1, *p2;
+ int len1, len2;
+
+ ASSERT(!strcmp(path, "./upload_test.txt"));
+ ASSERT((p1 = read_file("mongoose.c", &len1)) != NULL);
+ ASSERT((p2 = read_file(path, &len2)) != NULL);
+ ASSERT(len1 == len2);
+ ASSERT(memcmp(p1, p2, len1) == 0);
+ free(p1), free(p2);
+ remove(upload_filename);
+
+ mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s",
+ (int) strlen(upload_ok_message), upload_ok_message);
+}
+
+static int begin_request_handler_cb(struct mg_connection *conn) {
+ const struct mg_request_info *ri = mg_get_request_info(conn);
- if (event == MG_NEW_REQUEST && !strcmp(request_info->uri, "/data")) {
+ if (!strcmp(ri->uri, "/data")) {
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/plain\r\n\r\n"
"%s", (int) strlen(fetch_data), fetch_data);
- return "";
- } else if (event == MG_NEW_REQUEST && !strcmp(request_info->uri, "/upload")) {
+ return 1;
+ }
+
+ if (!strcmp(ri->uri, "/upload")) {
ASSERT(mg_upload(conn, ".") == 1);
- } else if (event == MG_OPEN_FILE) {
- const char *path = request_info->ev_data;
- if (strcmp(path, "./blah") == 0) {
- mg_get_request_info(conn)->ev_data =
- (void *) (long) strlen(inmemory_file_data);
- return (void *) inmemory_file_data;
- }
- } else if (event == MG_EVENT_LOG) {
- } else if (event == MG_UPLOAD) {
- char *p1, *p2;
- int len1, len2;
-
- ASSERT(!strcmp((char *) request_info->ev_data, "./upload_test.txt"));
- ASSERT((p1 = read_file("mongoose.c", &len1)) != NULL);
- ASSERT((p2 = read_file(upload_filename, &len2)) != NULL);
- ASSERT(len1 == len2);
- ASSERT(memcmp(p1, p2, len1) == 0);
- free(p1), free(p2);
- remove(upload_filename);
-
- mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s",
- (int) strlen(upload_ok_message), upload_ok_message);
}
- return NULL;
+ return 0;
+}
+
+static int log_message_cb(const struct mg_connection *conn, const char *msg) {
+ (void) conn;
+ printf("%s\n", msg);
+ return 0;
}
+static const struct mg_callbacks CALLBACKS = {
+ &begin_request_handler_cb, NULL, &log_message_cb, NULL, NULL, NULL, NULL,
+ &open_file_cb, NULL, &upload_cb
+};
+
static const char *OPTIONS[] = {
"document_root", ".",
"listening_ports", LISTENING_ADDR,
@@ -252,7 +269,7 @@ static void test_mg_download(void) {
struct mg_connection *conn;
struct mg_context *ctx;
- ASSERT((ctx = mg_start(event_handler, NULL, OPTIONS)) != NULL);
+ ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL);
ASSERT(mg_download(NULL, port, 0, ebuf, sizeof(ebuf), "%s", "") == NULL);
ASSERT(mg_download("localhost", 0, 0, ebuf, sizeof(ebuf), "%s", "") == NULL);
@@ -323,7 +340,7 @@ static void test_mg_upload(void) {
char ebuf[100], buf[20], *file_data, *post_data = NULL;
int file_len, post_data_len;
- ASSERT((ctx = mg_start(event_handler, NULL, OPTIONS)) != NULL);
+ ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL);
ASSERT((file_data = read_file("mongoose.c", &file_len)) != NULL);
post_data_len = alloc_printf(&post_data, 0,
"--%s\r\n"
@@ -462,22 +479,6 @@ static void test_lua(void) {
}
#endif
-static void *user_data_tester(enum mg_event event, struct mg_connection *conn) {
- struct mg_request_info *ri = mg_get_request_info(conn);
- ASSERT(ri->user_data == (void *) 123);
- ASSERT(event == MG_NEW_REQUEST || event == MG_INIT_SSL);
- return NULL;
-}
-
-static void test_user_data(void) {
- struct mg_context *ctx;
-
- ASSERT((ctx = mg_start(user_data_tester, (void *) 123, OPTIONS)) != NULL);
- ASSERT(ctx->user_data == (void *) 123);
- call_user(fc(ctx), MG_NEW_REQUEST);
- mg_stop(ctx);
-}
-
static void test_mg_stat(void) {
static struct mg_context ctx;
struct file file = STRUCT_FILE_INITIALIZER;
@@ -529,7 +530,7 @@ static void test_request_replies(void) {
{NULL, NULL},
};
- ASSERT((ctx = mg_start(event_handler, NULL, OPTIONS)) != NULL);
+ ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL);
for (i = 0; tests[i].request != NULL; i++) {
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
tests[i].request)) != NULL);
@@ -549,7 +550,6 @@ int __cdecl main(void) {
test_mg_get_var();
test_set_throttle();
test_next_option();
- test_user_data();
test_mg_stat();
test_skip_quoted();
test_mg_upload();

0 comments on commit ee55d38

Please sign in to comment.