瀏覽代碼

Added new URI to handler mapping for C code.

Thomas Davis 12 年之前
父節點
當前提交
af000e03c7
共有 6 個文件被更改,包括 158 次插入119 次删除
  1. 5 0
      RELEASE_NOTES.md
  2. 1 1
      examples/embedded_cpp/embedded_cpp.cpp
  3. 9 41
      include/CivetServer.h
  4. 30 0
      include/civetweb.h
  5. 13 77
      src/CivetServer.cpp
  6. 100 0
      src/civetweb.c

+ 5 - 0
RELEASE_NOTES.md

@@ -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

+ 1 - 1
examples/embedded_cpp/embedded_cpp.cpp

@@ -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) {

+ 9 - 41
include/CivetServer.h

@@ -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,32 +125,13 @@ 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 
      * @param cookieName - cookie name to get the value from
@@ -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
-     */
-    virtual bool handleRequest(struct mg_connection *conn);
-
-    /**
-     *  Returns the index of the handler that matches the
-     *  URI exactly.
-     *
-     *  @param uri - the url to match
+     * @param cbdata - pointer to the CivetHandler instance.
+     * @returns 0 if implemented, false otherwise
      */
-    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);
 
 };
 

+ 30 - 0
include/civetweb.h

@@ -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

+ 13 - 77
src/CivetServer.cpp

@@ -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));
+        context = mg_start(&callbacks, this, options);
     }
-    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)

+ 100 - 0
src/civetweb.c

@@ -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) {