mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
improving API to allow clients to associate state with a connection and to be notified about request termination
This commit is contained in:
+33
-19
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user