improving API to allow clients to associate state with a connection and to be notified about request termination

This commit is contained in:
Christian Grothoff
2007-08-30 06:59:15 +00:00
parent 44f694198b
commit b259da7c7f
12 changed files with 156 additions and 30 deletions
+33 -19
View File
@@ -180,6 +180,22 @@ MHD_need_100_continue (struct MHD_Connection *connection)
&& (connection->continuePos < strlen (HTTP_100_CONTINUE)));
}
/**
* 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
@@ -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;
+15 -1
View File
@@ -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);
+2 -1
View File
@@ -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;
}
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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;
+12
View File
@@ -202,6 +202,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)
*/
+2 -1
View File
@@ -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;
+80 -2
View File
@@ -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,
};
/**
@@ -361,6 +375,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).
*/
@@ -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