1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-07-29 21:01:13 +03:00

Added new URI to handler mapping for C code.

This commit is contained in:
Thomas Davis
2013-09-01 00:43:10 -04:00
parent acbe6db15f
commit af000e03c7
6 changed files with 158 additions and 119 deletions

View File

@ -1,7 +1,12 @@
Release Notes v1.4 (UNDER DEVELOPMENT)
===
### Objectives: *???*
The ma
- Added mg_set_request_handler() which provides a URI mapping for callbacks.
This is a new alternative to overriding callbacks.begin_request.
- Externalized mg_url_encode()
- Externalized mg_strncasecmp() for utiliy
- Added CivetServer::getParam methods
- Added CivetServer::urlDecode methods
- Added CivetServer::urlEncode methods

View File

@ -51,7 +51,7 @@ int main(int argc, char *argv[]) {
server.addHandler(EXIT_URI, new ExitHandler());
printf("Browse files at http://localhost:%s/\n", PORT);
printf("Run example at http://localhost:%s%s\n", PORT, EXIT_URI);
printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI);
while (!exitNow) {

View File

@ -81,7 +81,6 @@ public:
*
* @param options - the web server options.
* @param callbacks - optional web server callback methods.
* Note that this class overrides begin_request callback.
*/
CivetServer(const char **options, const struct mg_callbacks *callbacks = 0);
@ -110,8 +109,7 @@ public:
* addHandler(const std::string &, CivetHandler *)
*
* Adds a URI handler. If there is existing URI handler, it will
* be replaced with this one. The handler is "owned" by this server
* and will be deallocated with it.
* be replaced with this one.
*
* URI's are ordered and partcial URI's are supported. For example,
* consider two URIs in order: /a/b and /a; /a matches
@ -127,31 +125,12 @@ public:
/**
* removeHandler(const std::string &)
*
* Removes a handler, deleting it if found.
* Removes a handler.
*
* @param - the exact URL used in addHandler().
*/
void removeHandler(const std::string &uri);
/**
* getHandler(const std::string &uri)
*
* @param uri - the URI
* @returns the handler that matches the requested URI or 0 if none were found.
*/
CivetHandler *getHandler(const std::string &uri) const {
return getHandler(uri.data(), (unsigned int)uri.length());
}
/**
* getHandler(const char *uri, unsigned urilen)
*
* @param uri - the URI
* @param urilen - the length of the URI
* @returns the handler that matches the requested URI or 0 if none were found.
*/
CivetHandler *getHandler(const char *uri, unsigned urilen) const;
/**
* getCookie(struct mg_connection *conn, const std::string &cookieName, std::string &cookieValue)
* @param conn - the connection information
@ -293,30 +272,19 @@ public:
protected:
struct mg_context *context;
private:
/**
* handleRequest(struct mg_connection *)
* requestHandler(struct mg_connection *, void *cbdata)
*
* Handles the incomming request.
*
* @param conn - the connection information
* @returns true if implemented, false otherwise
* @param cbdata - pointer to the CivetHandler instance.
* @returns 0 if implemented, false otherwise
*/
virtual bool handleRequest(struct mg_connection *conn);
/**
* Returns the index of the handler that matches the
* URI exactly.
*
* @param uri - the url to match
*/
int getIndex(const std::string &uri) const;
std::vector<std::string> uris;
std::vector<CivetHandler *> handlers;
struct mg_context *context;
private:
static int begin_request_callback(struct mg_connection *conn);
static int requestHandler(struct mg_connection *conn, void *cbdata);
};

View File

@ -168,6 +168,36 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
// threads are stopped. Context pointer becomes invalid.
void mg_stop(struct mg_context *);
// mg_request_handler
//
// Called when a new request comes in. This callback is URI based
// and configured with mg_sethandler().
//
// Parameters:
// conn: current connection information.
// cbdata: the callback data configured with mg_sethandler().
// Returns:
// 0: the handler could not handle the request, so fall through.
// 1: the handler processed the request.
typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata);
// mg_set_request_handler
//
// Sets or removes a URI mapping for a request handler.
//
// URI's are ordered and partcial URI's are supported. For example,
// consider two URIs in order: /a/b and /a; /a matches
// /a, /a/b matches /a/b, /a/c matches /a. Reversing the order to
// /a and /a/b; /a matches /a/b, /a/b matches /a. /a/c matches /a.
//
// Parameters:
// ctx: server context
// uri: the URI to configure
// handler: the callback handler to use when the URI is requested.
// If NULL, the URI will be removed.
// cbdata: the callback data to give to the handler when it s requested.
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata);
// Get the value of particular configuration parameter.
// The value returned is read-only. Civetweb does not allow changing

View File

@ -37,109 +37,51 @@ bool CivetHandler::handleDelete(CivetServer *server, struct mg_connection *conn)
return false;
}
int CivetServer::begin_request_callback(struct mg_connection *conn) {
int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata) {
struct mg_request_info *request_info = mg_get_request_info(conn);
if (!request_info->user_data)
return 0;
CivetServer *me = (CivetServer*) (request_info->user_data);
CivetHandler *handler = (CivetHandler *)cbdata;
if (me->handleRequest(conn)) {
return 1; // Mark as processed
}
return 0;
}
bool CivetServer::handleRequest(struct mg_connection *conn) {
struct mg_request_info *request_info = mg_get_request_info(conn);
CivetHandler *handler = getHandler(request_info->uri);
if (handler) {
if (strcmp(request_info->request_method, "GET") == 0) {
return handler->handleGet(this, conn);
return handler->handleGet(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "POST") == 0) {
return handler->handlePost(this, conn);
return handler->handlePost(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "PUT") == 0) {
return !handler->handlePost(this, conn);
return !handler->handlePut(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "DELETE") == 0) {
return !handler->handlePost(this, conn);
return !handler->handleDelete(me, conn) ? 1 : 0;
}
}
return false; // No handler found
return 0; // No handler found
}
CivetServer::CivetServer(const char **options,
const struct mg_callbacks *_callbacks) :
context(0) {
struct mg_callbacks callbacks;
if (_callbacks) {
memcpy(&callbacks, _callbacks, sizeof(callbacks));
context = mg_start(_callbacks, this, options);
} else {
struct mg_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
}
callbacks.begin_request = &begin_request_callback;
context = mg_start(&callbacks, this, options);
}
}
CivetServer::~CivetServer() {
close();
}
CivetHandler *CivetServer::getHandler(const char *uri, unsigned urilen) const {
for (unsigned index = 0; index < uris.size(); index++) {
const std::string &handlerURI = uris[index];
// first try for an exact match
if (handlerURI == uri) {
return handlers[index];
}
// next try for a partial match
// we will accept uri/something
if (handlerURI.length() < urilen
&& uri[handlerURI.length()] == '/'
&& handlerURI.compare(0, handlerURI.length(), uri, handlerURI.length()) == 0) {
return handlers[index];
}
}
return 0; // none found
}
void CivetServer::addHandler(const std::string &uri, CivetHandler *handler) {
int index = getIndex(uri);
if (index < 0) {
uris.push_back(uri);
handlers.push_back(handler);
} else if (handlers[index] != handler) {
delete handlers[index];
handlers[index] = handler;
}
mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
}
void CivetServer::removeHandler(const std::string &uri) {
int index = getIndex(uri);
if (index >= 0) {
uris.erase(uris.begin() + index, uris.begin() + index + 1);
handlers.erase(handlers.begin() + index, handlers.begin() + index + 1);
}
}
int CivetServer::getIndex(const std::string &uri) const {
for (unsigned index = 0; index < uris.size(); index++) {
if (uris[index].compare(uri) == 0)
return index;
}
return -1;
mg_set_request_handler(context, uri.c_str(), NULL, NULL);
}
void CivetServer::close() {
@ -147,12 +89,6 @@ void CivetServer::close() {
mg_stop (context);
context = 0;
}
for (int i = (int) handlers.size() - 1; i >= 0; i--) {
delete handlers[i];
}
handlers.clear();
uris.clear();
}
int CivetServer::getCookie(struct mg_connection *conn, const std::string &cookieName, std::string &cookieValue)

View File

@ -494,6 +494,14 @@ static const char *config_options[] = {
NULL
};
struct mg_request_handler_info {
char *uri;
size_t uri_len;
mg_request_handler handler;
void *cbdata;
struct mg_request_handler_info *next;
};
struct mg_context {
volatile int stop_flag; // Should we stop event loop
SSL_CTX *ssl_ctx; // SSL context
@ -513,6 +521,9 @@ struct mg_context {
volatile int sq_tail; // Tail of the socket queue
pthread_cond_t sq_full; // Signaled when socket is produced
pthread_cond_t sq_empty; // Signaled when socket is consumed
// linked list of uri handlers
struct mg_request_handler_info *request_handlers;
};
struct mg_connection {
@ -4265,6 +4276,81 @@ static void redirect_to_https_port(struct mg_connection *conn, int ssl_index) {
lsa.sin.sin_port), conn->request_info.uri);
}
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata) {
struct mg_request_handler_info *tmp_rh, *lastref = 0;
// first see it the uri exists
for (tmp_rh = ctx->request_handlers;
tmp_rh != NULL && strcmp(uri, tmp_rh->uri);
lastref = tmp_rh, tmp_rh = tmp_rh->next)
;
if (tmp_rh != NULL) {
// already there...
if (handler != NULL) {
// change this entry
tmp_rh->handler = handler;
tmp_rh->cbdata = cbdata;
} else {
// remove this entry
if (lastref != NULL)
lastref->next = tmp_rh->next;
else
ctx->request_handlers = tmp_rh->next;
free(tmp_rh->uri);
free(tmp_rh);
}
return;
}
if (handler == NULL) {
// no handler to set, this was a remove request
return;
}
tmp_rh = (struct mg_request_handler_info *)malloc(sizeof(struct mg_request_handler_info));
tmp_rh->uri = mg_strdup(uri);
tmp_rh->uri_len = strlen(uri);
tmp_rh->handler = handler;
tmp_rh->cbdata = cbdata;
tmp_rh->next = NULL;
if (lastref == NULL)
ctx->request_handlers = tmp_rh;
else
lastref->next = tmp_rh;
}
static int use_request_handler(struct mg_connection *conn) {
struct mg_request_info *request_info = mg_get_request_info(conn);
const char *uri = request_info->uri;
size_t urilen = strlen(uri);
struct mg_request_handler_info *tmp_rh = conn->ctx->request_handlers;
for (; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
// first try for an exact match
if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri,uri)) {
return tmp_rh->handler(conn, tmp_rh->cbdata);
}
// next try for a partial match
// we will accept uri/something
if (tmp_rh->uri_len < urilen
&& uri[tmp_rh->uri_len] == '/'
&& memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
return tmp_rh->handler(conn, tmp_rh->cbdata);
}
}
return 0; // none found
}
// This is the heart of the Civetweb's logic.
// This function is called when the request is read, parsed and validated,
// and Civetweb must decide what action to take: serve a file, or
@ -4297,6 +4383,9 @@ static void handle_request(struct mg_connection *conn) {
} else if (conn->ctx->callbacks.begin_request != NULL &&
conn->ctx->callbacks.begin_request(conn)) {
// Do nothing, callback has served the request
} else if (conn->ctx->request_handlers != NULL &&
use_request_handler(conn)) {
// Do nothing, callback has served the request
#if defined(USE_WEBSOCKET)
} else if (is_websocket_request(conn)) {
handle_websocket_request(conn);
@ -5182,6 +5271,8 @@ static void *master_thread(void *thread_func_param) {
static void free_context(struct mg_context *ctx) {
int i;
struct mg_request_handler_info *tmp_rh;
if (ctx == NULL)
return;
@ -5194,6 +5285,14 @@ static void free_context(struct mg_context *ctx) {
free(ctx->config[i]);
}
// Deallocate request handlers
while (ctx->request_handlers) {
tmp_rh = ctx->request_handlers;
ctx->request_handlers = tmp_rh->next;
free(tmp_rh->uri);
free(tmp_rh);
}
#ifndef NO_SSL
// Deallocate SSL context
if (ctx->ssl_ctx != NULL) {
@ -5244,6 +5343,7 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
}
ctx->callbacks = *callbacks;
ctx->user_data = user_data;
ctx->request_handlers = 0;
while (options && (name = *options++) != NULL) {
if ((i = get_option_index(name)) == -1) {