diff options
author | Christian Grothoff <christian@grothoff.org> | 2007-08-30 06:59:15 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2007-08-30 06:59:15 +0000 |
commit | b259da7c7f97e1fbafeef634bd16af3a21f83e72 (patch) | |
tree | 6d51feb9f34832e27e831c8a05bc865186f35a67 | |
parent | 44f694198ba0d2b9b7172468989a83f6e1e51929 (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.c | 52 | ||||
-rw-r--r-- | src/daemon/daemon.c | 16 | ||||
-rw-r--r-- | src/daemon/daemontest.c | 3 | ||||
-rw-r--r-- | src/daemon/daemontest_get.c | 3 | ||||
-rw-r--r-- | src/daemon/daemontest_large_put.c | 3 | ||||
-rw-r--r-- | src/daemon/daemontest_long_header.c | 3 | ||||
-rw-r--r-- | src/daemon/daemontest_post.c | 3 | ||||
-rw-r--r-- | src/daemon/daemontest_put.c | 3 | ||||
-rw-r--r-- | src/daemon/fileserver_example.c | 3 | ||||
-rw-r--r-- | src/daemon/internal.h | 12 | ||||
-rw-r--r-- | src/daemon/minimal_example.c | 3 | ||||
-rw-r--r-- | src/include/microhttpd.h | 82 |
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 |