summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-08-30 06:59:15 +0000
committerChristian Grothoff <christian@grothoff.org>2007-08-30 06:59:15 +0000
commitb259da7c7f97e1fbafeef634bd16af3a21f83e72 (patch)
tree6d51feb9f34832e27e831c8a05bc865186f35a67
parent44f694198ba0d2b9b7172468989a83f6e1e51929 (diff)
improving API to allow clients to associate state with a connection and to be notified about request termination
-rw-r--r--src/daemon/connection.c52
-rw-r--r--src/daemon/daemon.c16
-rw-r--r--src/daemon/daemontest.c3
-rw-r--r--src/daemon/daemontest_get.c3
-rw-r--r--src/daemon/daemontest_large_put.c3
-rw-r--r--src/daemon/daemontest_long_header.c3
-rw-r--r--src/daemon/daemontest_post.c3
-rw-r--r--src/daemon/daemontest_put.c3
-rw-r--r--src/daemon/fileserver_example.c3
-rw-r--r--src/daemon/internal.h12
-rw-r--r--src/daemon/minimal_example.c3
-rw-r--r--src/include/microhttpd.h82
12 files changed, 156 insertions, 30 deletions
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index cdc8540b..1b7a04ed 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -181,6 +181,22 @@ MHD_need_100_continue (struct MHD_Connection *connection)
}
/**
+ * A serious error occured, close the
+ * connection (and notify the application).
+ */
+static void
+connection_close_error(struct MHD_Connection * connection)
+{
+ CLOSE (connection->socket_fd);
+ connection->socket_fd = -1;
+ if (connection->daemon->notify_completed != NULL)
+ connection->daemon->notify_completed(connection->daemon->notify_completed_cls,
+ connection,
+ &connection->client_context,
+ MHD_REQUEST_TERMINATED_WITH_ERROR);
+}
+
+/**
* Prepare the response buffer of this connection for
* sending. Assumes that the response mutex is
* already held. If the transmission is complete,
@@ -209,8 +225,7 @@ ready_response (struct MHD_Connection *connection)
"Closing connection (end of response)\n");
#endif
response->total_size = connection->messagePos;
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_NO;
}
response->data_start = connection->messagePos;
@@ -746,8 +761,7 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
DIE:
MHD_DLOG (connection->daemon,
"Closing connection (problem parsing headers)\n");
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
}
@@ -889,13 +903,13 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
connection->url,
connection->method,
connection->version,
- connection->read_buffer, &processed))
+ connection->read_buffer, &processed,
+ &connection->client_context))
{
/* serios internal error, close connection */
MHD_DLOG (connection->daemon,
"Internal application error, closing connection.\n");
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return;
}
/* dh left "processed" bytes in buffer for next time... */
@@ -934,8 +948,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
if (connection->pool == NULL)
{
MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_NO;
}
if ((connection->readLoc >= connection->read_buffer_size) &&
@@ -973,8 +986,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
return MHD_NO;
MHD_DLOG (connection->daemon,
"Failed to receive data: %s\n", STRERROR (errno));
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_YES;
}
if (bytes_read == 0)
@@ -1150,8 +1162,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
return MHD_YES;
MHD_DLOG (connection->daemon,
"Failed to send data: %s\n", STRERROR (errno));
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_YES;
}
#if DEBUG_SEND_DATA
@@ -1176,8 +1187,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
/* oops - close! */
MHD_DLOG (connection->daemon,
"Closing connection (failed to create response header)\n");
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_NO;
}
ret = SEND (connection->socket_fd,
@@ -1189,8 +1199,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
return MHD_YES;
MHD_DLOG (connection->daemon,
"Failed to send data: %s\n", STRERROR (errno));
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_YES;
}
#if DEBUG_SEND_DATA
@@ -1240,8 +1249,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
return MHD_YES;
MHD_DLOG (connection->daemon,
"Failed to send data: %s\n", STRERROR (errno));
- CLOSE (connection->socket_fd);
- connection->socket_fd = -1;
+ connection_close_error(connection);
return MHD_YES;
}
#if DEBUG_SEND_DATA
@@ -1259,6 +1267,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
(connection->headersReceived == 0))
abort (); /* internal error */
MHD_destroy_response (response);
+ if (connection->daemon->notify_completed != NULL)
+ connection->daemon->notify_completed(connection->daemon->notify_completed_cls,
+ connection,
+ &connection->client_context,
+ MHD_REQUEST_TERMINATED_COMPLETED_OK);
+ connection->client_context = NULL;
connection->continuePos = 0;
connection->responseCode = 0;
connection->response = NULL;
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 35eeccce..2dd7551f 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -354,6 +354,11 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
#endif
CLOSE (pos->socket_fd);
pos->socket_fd = -1;
+ if (pos->daemon->notify_completed != NULL)
+ pos->daemon->notify_completed(pos->daemon->notify_completed_cls,
+ pos,
+ &pos->client_context,
+ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
}
if (pos->socket_fd == -1)
{
@@ -680,6 +685,10 @@ MHD_start_daemon (unsigned int options,
case MHD_OPTION_CONNECTION_TIMEOUT:
retVal->connection_timeout = va_arg (ap, unsigned int);
break;
+ case MHD_OPTION_NOTIFY_COMPLETED:
+ retVal->notify_completed = va_arg(ap, MHD_RequestCompletedCallback);
+ retVal->notify_completed_cls = va_arg(ap, void *);
+ break;
default:
fprintf (stderr,
"Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n");
@@ -733,7 +742,12 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
MHD_DLOG (daemon,
"MHD shutdown, closing active connections\n");
#endif
- CLOSE (daemon->connections->socket_fd);
+ if (daemon->notify_completed != NULL)
+ daemon->notify_completed(daemon->notify_completed_cls,
+ daemon->connections,
+ &daemon->connections->client_context,
+ MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
+ CLOSE (daemon->connections->socket_fd);
daemon->connections->socket_fd = -1;
}
MHD_cleanup_connections (daemon);
diff --git a/src/daemon/daemontest.c b/src/daemon/daemontest.c
index 53f56989..2ecb87f2 100644
--- a/src/daemon/daemontest.c
+++ b/src/daemon/daemontest.c
@@ -64,7 +64,8 @@ ahc_nothing (void *cls,
const char *url,
const char *method,
const char *version,
- const char *upload_data, unsigned int *upload_data_size)
+ const char *upload_data, unsigned int *upload_data_size,
+ void ** unused)
{
return MHD_NO;
}
diff --git a/src/daemon/daemontest_get.c b/src/daemon/daemontest_get.c
index e8ce1e7a..79726a11 100644
--- a/src/daemon/daemontest_get.c
+++ b/src/daemon/daemontest_get.c
@@ -63,7 +63,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *version,
- const char *upload_data, unsigned int *upload_data_size)
+ const char *upload_data, unsigned int *upload_data_size,
+ void ** unused)
{
const char *me = cls;
struct MHD_Response *response;
diff --git a/src/daemon/daemontest_large_put.c b/src/daemon/daemontest_large_put.c
index e176d29c..f4ae5583 100644
--- a/src/daemon/daemontest_large_put.c
+++ b/src/daemon/daemontest_large_put.c
@@ -85,7 +85,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *version,
- const char *upload_data, unsigned int *upload_data_size)
+ const char *upload_data, unsigned int *upload_data_size,
+ void ** unused)
{
int *done = cls;
struct MHD_Response *response;
diff --git a/src/daemon/daemontest_long_header.c b/src/daemon/daemontest_long_header.c
index 6377ac07..6a451136 100644
--- a/src/daemon/daemontest_long_header.c
+++ b/src/daemon/daemontest_long_header.c
@@ -69,7 +69,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *version,
- const char *upload_data, unsigned int *upload_data_size)
+ const char *upload_data, unsigned int *upload_data_size,
+ void ** unused)
{
const char *me = cls;
struct MHD_Response *response;
diff --git a/src/daemon/daemontest_post.c b/src/daemon/daemontest_post.c
index ec60575b..10f6ea97 100644
--- a/src/daemon/daemontest_post.c
+++ b/src/daemon/daemontest_post.c
@@ -69,7 +69,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *version,
- const char *upload_data, unsigned int *upload_data_size)
+ const char *upload_data, unsigned int *upload_data_size,
+ void ** unused)
{
struct MHD_Response *response;
int ret;
diff --git a/src/daemon/daemontest_put.c b/src/daemon/daemontest_put.c
index bd3e0a52..f61cfb8e 100644
--- a/src/daemon/daemontest_put.c
+++ b/src/daemon/daemontest_put.c
@@ -76,7 +76,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *version,
- const char *upload_data, unsigned int *upload_data_size)
+ const char *upload_data, unsigned int *upload_data_size,
+ void ** unused)
{
int *done = cls;
struct MHD_Response *response;
diff --git a/src/daemon/fileserver_example.c b/src/daemon/fileserver_example.c
index 85b154e3..15b6aa24 100644
--- a/src/daemon/fileserver_example.c
+++ b/src/daemon/fileserver_example.c
@@ -52,7 +52,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *upload_data,
- const char *version, unsigned int *upload_data_size)
+ const char *version, unsigned int *upload_data_size,
+ void ** unused)
{
struct MHD_Response *response;
int ret;
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index 353312b4..b6f8336e 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -203,6 +203,14 @@ struct MHD_Connection
struct MemoryPool *pool;
/**
+ * We allow the main application to associate some
+ * pointer with the connection. Here is where we
+ * store it. (MHD does not know or care what it
+ * is).
+ */
+ void * client_context;
+
+ /**
* Request method. Should be GET/POST/etc. Allocated
* in pool.
*/
@@ -376,6 +384,10 @@ struct MHD_Daemon
void *apc_cls;
+ MHD_RequestCompletedCallback notify_completed;
+
+ void * notify_completed_cls;
+
/**
* PID of the select thread (if we have internal select)
*/
diff --git a/src/daemon/minimal_example.c b/src/daemon/minimal_example.c
index 8de0064e..80442072 100644
--- a/src/daemon/minimal_example.c
+++ b/src/daemon/minimal_example.c
@@ -41,7 +41,8 @@ ahc_echo (void *cls,
const char *url,
const char *method,
const char *upload_data,
- const char *version, unsigned int *upload_data_size)
+ const char *version, unsigned int *upload_data_size,
+ void ** unused)
{
const char *me = cls;
struct MHD_Response *response;
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index d09c66a9..3a46c085 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -84,7 +84,7 @@ extern "C"
/**
* Current version of the library.
*/
-#define MHD_VERSION 0x00000003
+#define MHD_VERSION 0x00000004
/**
* MHD-internal return codes.
@@ -319,6 +319,20 @@ enum MHD_OPTION
*/
MHD_OPTION_CONNECTION_TIMEOUT = 3,
+ /**
+ * Register a function that should be called whenever a request has
+ * been completed (this can be used for application-specific clean
+ * up). Requests that have never been presented to the application
+ * (via MHD_AccessHandlerCallback) will not result in
+ * notifications.<p>
+ *
+ * This option should be followed by TWO pointers. First a pointer
+ * to a function of type "MHD_RequestCompletedCallback" and second a
+ * pointer to a closure to pass to the request completed callback.
+ * The second pointer maybe NULL.
+ */
+ MHD_OPTION_NOTIFY_COMPLETED = 4,
+
};
/**
@@ -362,6 +376,40 @@ enum MHD_ValueKind
};
/**
+ * The MHD_RequestTerminationCode specifies reasons
+ * why a request has been terminated (or completed).
+ */
+enum MHD_RequestTerminationCode
+{
+
+ /**
+ * We finished sending the response.
+ */
+ MHD_REQUEST_TERMINATED_COMPLETED_OK = 0,
+
+ /**
+ * Error handling the connection (resources
+ * exhausted, other side closed connection,
+ * application error accepting request, etc.)
+ */
+ MHD_REQUEST_TERMINATED_WITH_ERROR = 1,
+
+ /**
+ * No activity on the connection for the number
+ * of seconds specified using
+ * MHD_OPTION_CONNECTION_TIMEOUT.
+ */
+ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2,
+
+ /**
+ * We had to close the session since MHD was being
+ * shut down.
+ */
+ MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3,
+
+};
+
+/**
* Handle for the daemon (listening on a socket for HTTP traffic).
*/
struct MHD_Daemon;
@@ -398,6 +446,8 @@ typedef int
* callbacks to provide content to give back to the client and return
* an HTTP status code (i.e. 200 for OK, 404, etc.).
*
+ * @param cls argument given together with the function
+ * pointer when the handler was registered with MHD
* @param url the requested url
* @param method the HTTP method used ("GET", "PUT", etc.)
* @param version the HTTP version string (i.e. "HTTP/1.1")
@@ -411,6 +461,16 @@ typedef int
* @param upload_data_size set initially to the size of the
* upload_data provided; the method must update this
* value to the number of bytes NOT processed;
+ * @param con_cls pointer that the callback can set to some
+ * address and that will be preserved by MHD for future
+ * calls for this request; since the access handler may
+ * be called many times (i.e., for a PUT/POST operation
+ * with plenty of upload data) this allows the application
+ * to easily associate some request-specific state.
+ * If necessary, this state can be cleaned up in the
+ * global "MHD_RequestCompleted" callback (which
+ * can be set with the MHD_OPTION_NOTIFY_COMPLETED).
+ * Initially, <tt>*con_cls</tt> will be NULL.
* @return MHS_YES if the connection was handled successfully,
* MHS_NO if the socket must be closed due to a serios
* error while handling the request
@@ -422,7 +482,25 @@ typedef int
const char *method,
const char *version,
const char *upload_data,
- unsigned int *upload_data_size);
+ unsigned int *upload_data_size,
+ void ** con_cls);
+
+/**
+ * Signature of the callback used by MHD to notify the
+ * application about completed requests.
+ *
+ * @param cls client-defined closure
+ * @param connection connection handle
+ * @param con_cls value as set by the last call to
+ * the MHD_AccessHandlerCallback
+ * @param toe reason for request termination
+ * @see MHD_OPTION_NOTIFY_COMPLETED
+ */
+typedef void
+ (*MHD_RequestCompletedCallback) (void *cls,
+ struct MHD_Connection * connection,
+ void ** con_cls,
+ enum MHD_RequestTerminationCode toe);
/**
* Iterator over key-value pairs. This iterator