[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [libmicrohttpd] new API proposal for HTTP UPGRADE / websockets
From: |
Simon Newton |
Subject: |
Re: [libmicrohttpd] new API proposal for HTTP UPGRADE / websockets |
Date: |
Sun, 25 Nov 2012 07:55:40 -0800 |
This looks good to me.
On Sun, Nov 25, 2012 at 5:11 AM, Christian Grothoff
<address@hidden> wrote:
> Dear all,
>
> I've finally made up my mind on a decent API for the "HTTP UPGRADE"
> implementation. HTTP UPGRADE is used for websockets (and possibly other
> HTTP-extensions) to switch a TCP socket from HTTP-mode to some other,
> application-specific bi-directional protocol. As mentioned here a few
> months ago, the problem here is to fit this into MHD's execution model.
> Specifically, a first "trivial" API that I proposed had the serious
> disadvantage of not being implementable with HTTPS. So here is my second
> attempt. I'm specifically trying to achieve the following key design goals:
>
> 1) Make the HTTP-UPGRADE API look exactly the same for HTTP and HTTPS. If
> you 'upgrade' an SSL-connection, it should look and feel the same as if you
> upgrade an HTTP connection, the only difference being is that your
> application-protocol is still encrypted with SSL.
>
> 2) Make the API work nicely with all of our threading models
> (internal/external/threaded, etc.).
>
> 3) Expose limited, but useful low-level TCP capabilities (specifically,
> uncorking) that are useful for high-performance application protocols,
> without exposing the actual socket to the application (remember, we may not
> have a socket, as this may be an HTTPS-connection).
>
> 4) Keep it simple (yeah, right).
>
> I've pasted the new definitions from the API below. Nothing has been
> implemented at this point, but comments on the API would be appreciated ---
> especially if it for some reason does NOT fit someone's needs / desires.
>
> Happy hacking!
>
>
> Christian
> ///////////////////////////
>
> /**
> * Bits in an event mask that specifies which actions
> * MHD should perform and under which conditions it
> * should call the 'upgrade' callback again.
> */
> enum MHD_UpgradeEventMask
> {
>
> /**
> * Never call the handler again; finish sending bytes
> * in the 'write' buffer and then close the socket.
> */
> MHD_UPGRADE_EVENT_TERMINATE = 0,
>
> /**
> * Call the handler again once there is data ready
> * for reading.
> */
> MHD_UPGRADE_EVENT_READ = 1,
>
> /**
> * Call the handler again once there is buffer space
> * available for writing.
> */
> MHD_UPGRADE_EVENT_WRITE = 2,
>
> /**
> * Do not wait on any socket actions, we're waiting on
> * an 'external' event. Run the function again once
> * the 'select' call returns _without_ this socket even
> * being involved in the select sets (useful in
> * conjunction with the external select loop).
> */
> MHD_UPGRADE_EVENT_EXTERNAL = 4,
>
> /**
> * Uncork the TCP write buffer (that is, tell the OS to transmit all
> * bytes in the buffer now, and to not use TCP-CORKing). This is
> * not really an event flag, but an additional request (which MHD
> * may ignore if the platform does not support it). Note that
> * only returning 'CORK' will *also* cause the socket to be closed!
> */
> MHD_UPGRADE_EVENT_CORK = 8
>
> };
>
>
> /**
> * Function called after a protocol "upgrade" response was sent
> * successfully and the socket should now be controlled by some
> * protocol other than HTTP.
> *
> * Any data received on the socket will be made available in
> * 'data_in'. The function should update 'data_in_size' to
> * reflect the number of bytes consumed from 'data_in' (the remaining
> * bytes will be made available in the next call to the handler).
> *
> * Any data that should be transmitted on the socket should be
> * stored in 'data_out'. '*data_out_size' is initially set to
> * the available buffer space in 'data_out'. It should be set to
> * the number of bytes stored in 'data_out' (which can be zero).
> *
> * The return value is a BITMASK that indicates how the function
> * intends to interact with the event loop. It can request to be
> * notified for reading, writing, request to UNCORK the send buffer
> * (which MHD is allowed to ignore, if it is not possible to uncork on
> * the local platform), to wait for the 'external' select loop to
> * trigger another round. It is also possible to specify "no events"
> * to terminate the connection; in this case, the
> * MHD_RequestCompletedCallback will be called and all resources of
> * the connection will be released.
> *
> * Except when in 'thread-per-connection' mode, implementations
> * of this function should never block (as it will still be called
> * from within the main event loop).
> *
> * @param cls closure
> * @param connection original HTTP connection handle,
> * giving the function a last chance
> * to inspect the original HTTP request
> * @param con_cls value as set by the last call to the
> * MHD_AccessHandlerCallback; will afterwards
> * be also given to the MHD_RequestCompletedCallback
> * @param data_in_size available data for reading, set to data read
> * @param data_in data read from the socket
> * @param data_out_size available buffer for writing, set to bytes
> * written to 'data_out'
> * @param data_out buffer for sending data via the connection
> * @return desired actions for event handling loop
> */
> typedef enum MHD_UpgradeEventMask (*MHD_UpgradeHandler)(void *cls,
> struct MHD_Connection *connection,
> void **con_cls,
> size_t *data_in_size,
> const char *data_in,
> size_t *data_out_size,
> char *data_out);
>
>
> /**
> * 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 if 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 'upgrade_handler'
> * @return NULL on error (i.e. invalid arguments, out of memory)
> */
> struct MHD_Response *
> MHD_create_response_for_upgrade (MHD_UpgradeHandler upgrade_handler,
> void *upgrade_handler_cls);
>