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