summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-08-26 21:15:34 +0000
committerChristian Grothoff <christian@grothoff.org>2016-08-26 21:15:34 +0000
commit2669ca22a4d30949c54cead24958d24215276967 (patch)
tree4369262a3228072acf980cc624e84e1ca13cb376
parenta0dcd1ab1b234bbdfb5e2d4c92e48c7ea949cc6c (diff)
sketching how I envision handling Upgrade
-rw-r--r--src/include/microhttpd.h12
-rw-r--r--src/microhttpd/internal.h145
-rw-r--r--src/microhttpd/response.c239
-rw-r--r--src/microhttpd/response.h5
4 files changed, 322 insertions, 79 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index eef50c70..27576f5f 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -2311,6 +2311,14 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
* @param connection original HTTP connection handle,
* giving the function a last chance
* to inspect the original HTTP request
+ * @param extra_in if we happened to have read bytes after the
+ * HTTP header already (because the client sent
+ * more than the HTTP header of the request before
+ * we sent the upgrade response),
+ * these are the extra bytes already read from @a sock
+ * by MHD. The application should treat these as if
+ * it had read them from @a sock.
+ * @param extra_in_size number of bytes in @a extra_in
* @param sock socket to use for bi-directional communication
* with the client. For HTTPS, this may not be a socket
* that is directly connected to the client and thus certain
@@ -2324,6 +2332,8 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
typedef void
(*MHD_UpgradeHandler)(void *cls,
struct MHD_Connection *connection,
+ const char *extra_in,
+ size_t extra_in_size,
MHD_SOCKET sock,
struct MHD_UpgradeResponseHandle *urh);
@@ -2852,7 +2862,7 @@ enum MHD_FEATURE
* @ingroup specialized
*/
_MHD_EXTERN int
-MHD_is_feature_supported(enum MHD_FEATURE feature);
+MHD_is_feature_supported (enum MHD_FEATURE feature);
#if 0 /* keep Emacsens' auto-indent happy */
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 863def56..d6f1177c 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -102,68 +102,68 @@ extern void *mhd_panic_cls;
* State of the socket with respect to epoll (bitmask).
*/
enum MHD_EpollState
- {
-
- /**
- * The socket is not involved with a defined state in epoll() right
- * now.
- */
- MHD_EPOLL_STATE_UNREADY = 0,
-
- /**
- * epoll() told us that data was ready for reading, and we did
- * not consume all of it yet.
- */
- MHD_EPOLL_STATE_READ_READY = 1,
-
- /**
- * epoll() told us that space was available for writing, and we did
- * not consume all of it yet.
- */
- MHD_EPOLL_STATE_WRITE_READY = 2,
-
- /**
- * Is this connection currently in the 'eready' EDLL?
- */
- MHD_EPOLL_STATE_IN_EREADY_EDLL = 4,
-
- /**
- * Is this connection currently in the epoll() set?
- */
- MHD_EPOLL_STATE_IN_EPOLL_SET = 8,
-
- /**
- * Is this connection currently suspended?
- */
- MHD_EPOLL_STATE_SUSPENDED = 16
- };
+{
+
+ /**
+ * The socket is not involved with a defined state in epoll() right
+ * now.
+ */
+ MHD_EPOLL_STATE_UNREADY = 0,
+
+ /**
+ * epoll() told us that data was ready for reading, and we did
+ * not consume all of it yet.
+ */
+ MHD_EPOLL_STATE_READ_READY = 1,
+
+ /**
+ * epoll() told us that space was available for writing, and we did
+ * not consume all of it yet.
+ */
+ MHD_EPOLL_STATE_WRITE_READY = 2,
+
+ /**
+ * Is this connection currently in the 'eready' EDLL?
+ */
+ MHD_EPOLL_STATE_IN_EREADY_EDLL = 4,
+
+ /**
+ * Is this connection currently in the epoll() set?
+ */
+ MHD_EPOLL_STATE_IN_EPOLL_SET = 8,
+
+ /**
+ * Is this connection currently suspended?
+ */
+ MHD_EPOLL_STATE_SUSPENDED = 16
+};
/**
* What is this connection waiting for?
*/
enum MHD_ConnectionEventLoopInfo
- {
- /**
- * We are waiting to be able to read.
- */
- MHD_EVENT_LOOP_INFO_READ = 0,
+{
+ /**
+ * We are waiting to be able to read.
+ */
+ MHD_EVENT_LOOP_INFO_READ = 0,
- /**
- * We are waiting to be able to write.
- */
- MHD_EVENT_LOOP_INFO_WRITE = 1,
+ /**
+ * We are waiting to be able to write.
+ */
+ MHD_EVENT_LOOP_INFO_WRITE = 1,
- /**
- * We are waiting for the application to provide data.
- */
- MHD_EVENT_LOOP_INFO_BLOCK = 2,
+ /**
+ * We are waiting for the application to provide data.
+ */
+ MHD_EVENT_LOOP_INFO_BLOCK = 2,
- /**
- * We are finished and are awaiting cleanup.
- */
- MHD_EVENT_LOOP_INFO_CLEANUP = 3
- };
+ /**
+ * We are finished and are awaiting cleanup.
+ */
+ MHD_EVENT_LOOP_INFO_CLEANUP = 3
+};
/**
@@ -202,7 +202,8 @@ struct MHD_NonceNc
*/
void
MHD_DLOG (const struct MHD_Daemon *daemon,
- const char *format, ...);
+ const char *format,
+ ...);
#endif
@@ -273,6 +274,20 @@ struct MHD_Response
*/
MHD_ContentReaderFreeCallback crfc;
+#if 0
+ /**
+ * Application function to call once we are done sending the headers
+ * of the response; NULL unless this is a response created with
+ * #MHD_create_response_for_upgrade().
+ */
+ MHD_UpgradeHandler upgrade_handler;
+
+ /**
+ * Closure for @e uh.
+ */
+ void *upgrade_handler_cls;
+#endif
+
/**
* Mutex to synchronize access to @e data, @e size and
* @e reference_count.
@@ -569,14 +584,12 @@ struct MHD_Connection
struct MHD_Response *response;
/**
- * The memory pool is created whenever we first read
- * from the TCP stream and destroyed at the end of
- * each request (and re-created for the next request).
- * In the meantime, this pointer is NULL. The
- * pool is used for all connection-related data
- * except for the response (which maybe shared between
- * connections) and the IP address (which persists
- * across individual requests).
+ * The memory pool is created whenever we first read from the TCP
+ * stream and destroyed at the end of each request (and re-created
+ * for the next request). In the meantime, this pointer is NULL.
+ * The pool is used for all connection-related data except for the
+ * response (which maybe shared between connections) and the IP
+ * address (which persists across individual requests).
*/
struct MemoryPool *pool;
@@ -598,8 +611,7 @@ struct MHD_Connection
void *socket_context;
/**
- * Request method. Should be GET/POST/etc. Allocated
- * in pool.
+ * Request method. Should be GET/POST/etc. Allocated in pool.
*/
char *method;
@@ -616,9 +628,8 @@ struct MHD_Connection
char *version;
/**
- * Buffer for reading requests. Allocated
- * in pool. Actually one byte larger than
- * @e read_buffer_size (if non-NULL) to allow for
+ * Buffer for reading requests. Allocated in pool. Actually one
+ * byte larger than @e read_buffer_size (if non-NULL) to allow for
* 0-termination.
*/
char *read_buffer;
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 3e967e68..f0ebf5c6 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -101,7 +101,8 @@ add_response_entry (struct MHD_Response *response,
*/
int
MHD_add_response_header (struct MHD_Response *response,
- const char *header, const char *content)
+ const char *header,
+ const char *content)
{
return add_response_entry (response,
MHD_HEADER_KIND,
@@ -121,7 +122,8 @@ MHD_add_response_header (struct MHD_Response *response,
*/
int
MHD_add_response_footer (struct MHD_Response *response,
- const char *footer, const char *content)
+ const char *footer,
+ const char *content)
{
return add_response_entry (response,
MHD_FOOTER_KIND,
@@ -184,7 +186,8 @@ MHD_del_response_header (struct MHD_Response *response,
*/
int
MHD_get_response_headers (struct MHD_Response *response,
- MHD_KeyValueIterator iterator, void *iterator_cls)
+ MHD_KeyValueIterator iterator,
+ void *iterator_cls)
{
struct MHD_HTTP_Header *pos;
int numHeaders = 0;
@@ -316,7 +319,10 @@ MHD_set_response_options (struct MHD_Response *response,
* @return number of bytes written
*/
static ssize_t
-file_reader (void *cls, uint64_t pos, char *buf, size_t max)
+file_reader (void *cls,
+ uint64_t pos,
+ char *buf,
+ size_t max)
{
struct MHD_Response *response = cls;
ssize_t n;
@@ -397,7 +403,9 @@ MHD_create_response_from_fd_at_offset (size_t size,
int fd,
off_t offset)
{
- return MHD_create_response_from_fd_at_offset64 (size, fd, offset);
+ return MHD_create_response_from_fd_at_offset64 (size,
+ fd,
+ offset);
}
@@ -461,7 +469,9 @@ struct MHD_Response *
MHD_create_response_from_fd (size_t size,
int fd)
{
- return MHD_create_response_from_fd_at_offset64 (size, fd, 0);
+ return MHD_create_response_from_fd_at_offset64 (size,
+ fd,
+ 0);
}
@@ -482,7 +492,9 @@ _MHD_EXTERN struct MHD_Response *
MHD_create_response_from_fd64 (uint64_t size,
int fd)
{
- return MHD_create_response_from_fd_at_offset64 (size, fd, 0);
+ return MHD_create_response_from_fd_at_offset64 (size,
+ fd,
+ 0);
}
@@ -502,7 +514,9 @@ MHD_create_response_from_fd64 (uint64_t size,
*/
struct MHD_Response *
MHD_create_response_from_data (size_t size,
- void *data, int must_free, int must_copy)
+ void *data,
+ int must_free,
+ int must_copy)
{
struct MHD_Response *response;
void *tmp;
@@ -513,7 +527,7 @@ MHD_create_response_from_data (size_t size,
return NULL;
memset (response, 0, sizeof (struct MHD_Response));
response->fd = -1;
- if (!MHD_mutex_init_ (&response->mutex))
+ if (! MHD_mutex_init_ (&response->mutex))
{
free (response);
return NULL;
@@ -563,6 +577,208 @@ MHD_create_response_from_buffer (size_t size,
}
+#if 0
+/**
+ * Handle given to the application to manage special
+ * actions relating to MHD responses that "upgrade"
+ * the HTTP protocol (i.e. to WebSockets).
+ */
+struct MHD_UpgradeResponseHandle
+{
+
+ /**
+ * The connection for which this is an upgrade handle. Note that
+ * because a response may be shared over many connections, this may
+ * not be the only upgrade handle for the response of this connection.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * The socket we gave to the application (r/w).
+ */
+ MHD_SOCKET app_sock;
+
+ /**
+ * If @a app_sock was a socketpair, our end of it, otherwise
+ * #MHD_INVALID_SOCKET; (r/w).
+ */
+ MHD_SOCKET mhd_sock;
+
+};
+
+
+/**
+ * This connection-specific callback is provided by MHD to
+ * applications (unusual) during the #MHD_UpgradeHandler.
+ * It allows applications to perform 'special' actions on
+ * the underlying socket from the upgrade.
+ *
+ * @param urh the handle identifying the connection to perform
+ * the upgrade @a action on.
+ * @param action which action should be performed
+ * @param ... arguments to the action (depends on the action)
+ * @return #MHD_NO on error, #MHD_YES on success
+ */
+_MHD_EXTERN int
+MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
+ enum MHD_UpgradeAction action,
+ ...)
+{
+ switch (action)
+ {
+ case MHD_UPGRADE_ACTION_CLOSE:
+ /* Application is done with this connection, tear it down! */
+ if ( (MHD_INVALID_SOCKET != urh->app_socket) &&
+ (0 != MHD_socket_close (urh->app_socket)) )
+ MHD_PANIC ("close failed\n");
+ if ( (MHD_INVALID_SOCKET != urh->mhd_socket) &&
+ (0 != MHD_socket_close (urh->mhd_socket)) )
+ MHD_PANIC ("close failed\n");
+ MHD_connection_resume (urh->connection);
+ MHD_connection_close_ (urh->connection,
+ MHD_REQUEST_TERMINATED_COMPLETED_OK);
+ free (urh);
+ return MHD_YES;
+ case MHD_UPGRADE_ACTION_CORK:
+ /* FIXME: not implemented */
+ return MHD_NO;
+ default:
+ /* we don't understand this one */
+ return MHD_NO;
+ }
+}
+
+
+/**
+ * We are done sending the header of a given response
+ * to the client. Now it is time to perform the upgrade
+ * and hand over the connection to the application.
+ *
+ * @param response the response that was created for an upgrade
+ * @param connection the specific connection we are upgrading
+ * @return #MHD_YES on success, #MHD_NO on failure (will cause
+ * connection to be closed)
+ */
+// FIXME: This function will need to be called at the right place(s)
+// in the connection processing (just after we are done sending the header)
+// (for responses that have the 'upgrade_header' callback set).
+int
+MHD_response_execute_upgrade_ (struct MHD_Response *response,
+ struct MHD_Connection *connection)
+{
+ struct MHD_UpgradeResponseHandle *urh;
+ int sv[2];
+ size_t rbo;
+
+ urh = malloc (sizeof (struct MHD_UpgradeResponseHandle));
+ if (NULL == urh)
+ return MHD_NO;
+#if HTTPS_SUPPORT
+ if (0 != (connection->daemon->flags & MHD_USE_SSL) )
+ {
+ /* FIXME: this is non-portable for now; W32 port pending... */
+ if (0 != socketpair (AF_UNIX,
+ SOCK_STREAM,
+ 0,
+ sv))
+ {
+ free (urh);
+ return MHD_NO;
+ }
+ urh->app_socket = sv[0];
+ urh->mhd_socket = sv[1];
+ urh->connection = connection;
+ rbo = connection->read_buffer_offset;
+ connection->read_buffer_offset = 0;
+ response->upgrade_handler (response->upgrade_handler_cls,
+ connection,
+ connection->read_buffer,
+ rbo,
+ urh->app_sock,
+ urh);
+ /* As far as MHD is concerned, this connection is
+ suspended; it will be resumed once we are done
+ in the #MHD_upgrade_action() function */
+ MHD_connection_suspend (connection);
+ /* FIXME: also need to start some processing logic in _all_ MHD
+ event loops for the sv traffic! (NOT IMPLEMENTED!!!) */
+ return MHD_YES;
+ }
+#endif
+ urh->app_socket = MHD_INVALID_SOCKET;
+ urh->mhd_socket = MHD_INVALID_SOCKET;
+ rbo = connection->read_buffer_offset;
+ connection->read_buffer_offset = 0;
+ response->upgrade_handler (response->upgrade_handler_cls,
+ connection,
+ connection->read_buffer,
+ rbo,
+ connection->socket_fd,
+ urh);
+ /* As far as MHD is concerned, this connection is
+ suspended; it will be resumed once we are done
+ in the #MHD_upgrade_action() function */
+ MHD_connection_suspend (connection);
+ return MHD_YES;
+}
+
+
+/**
+ * Create a response object that can be used for 101 UPGRADE
+ * responses, for example to implement WebSockets. After sending the
+ * response, control over the data stream is given to the callback (which
+ * can then, for example, start some bi-directional communication).
+ * If the response is queued for multiple connections, the callback
+ * will be called for each connection. The callback
+ * will ONLY be called after the response header was successfully passed
+ * to the OS; if there are communication errors before, the usual MHD
+ * connection error handling code will be performed.
+ *
+ * Setting the correct HTTP code (i.e. MHD_HTTP_SWITCHING_PROTOCOLS)
+ * and setting correct HTTP headers for the upgrade must be done
+ * manually (this way, it is possible to implement most existing
+ * WebSocket versions using this API; in fact, this API might be useful
+ * for any protocol switch, not just WebSockets). Note that
+ * draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this
+ * way as the header "HTTP/1.1 101 WebSocket Protocol Handshake"
+ * cannot be generated; instead, MHD will always produce "HTTP/1.1 101
+ * Switching Protocols" (if the response code 101 is used).
+ *
+ * As usual, the response object can be extended with header
+ * information and then be used any number of times (as long as the
+ * header information is not connection-specific).
+ *
+ * @param upgrade_handler function to call with the 'upgraded' socket
+ * @param upgrade_handler_cls closure for @a upgrade_handler
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+_MHD_EXTERN struct MHD_Response *
+MHD_create_response_for_upgrade (MHD_UpgradeHandler upgrade_handler,
+ void *upgrade_handler_cls)
+{
+ struct MHD_Response *response;
+
+ if (NULL == upgrade_header)
+ return NULL; /* invalid request */
+ response = malloc (sizeof (struct MHD_Response));
+ if (NULL == response)
+ return NULL;
+ memset (response, 0, sizeof (struct MHD_Response));
+ if (! MHD_mutex_init_ (&response->mutex))
+ {
+ free (response);
+ return NULL;
+ }
+ urh->response = response;
+ response->upgrade_handler = upgrade_handler;
+ response->upgrade_handler_cls = upgrade_handler_cls;
+ response->total_size = MHD_SIZE_UNKNOWN;
+ response->reference_count = 1;
+ return response;
+}
+#endif
+
+
/**
* Destroy a response object and associated resources. Note that
* libmicrohttpd may keep some of the resources around if the response
@@ -601,6 +817,11 @@ MHD_destroy_response (struct MHD_Response *response)
}
+/**
+ * Increments the reference counter for the @a response.
+ *
+ * @param response object to modify
+ */
void
MHD_increment_response_rc (struct MHD_Response *response)
{
diff --git a/src/microhttpd/response.h b/src/microhttpd/response.h
index 5785ec96..a13683d1 100644
--- a/src/microhttpd/response.h
+++ b/src/microhttpd/response.h
@@ -28,8 +28,9 @@
#define RESPONSE_H
/**
- * Increment response RC. Should this be part of the
- * public API?
+ * Increments the reference counter for the @a response.
+ *
+ * @param response object to modify
*/
void
MHD_increment_response_rc (struct MHD_Response *response);