mod_h2

bringing HTTP/2 to Apache

Apache Protocols directive

The introduction of ALPN and mod_h2 into Apache httpd was done by enhancing mod_ssl with callback functions and registrations similar to what google had done for spdy.

Now that mod_h2 gets tightly integrated into httpd, a little broader handling of protocol upgrades is desired. TLS+ALPN as well as the HTTP/1 Upgrade header (and possible future transoorts) should be configurable with the same directives.

This is a proposal how the API of httpd core could look like.

The directives

# default  "http/1.1" ("http/1.1" as umbrella for 0.9-1.1 support)
Protocols h2 http/1.1 spdy/3.1

# default "Server"
ProtocolsOrdering Server|Client

                

The API Additions in http_protocol.h

#define AP_PROTOCOL_HTTP1		"http/1.1"

/**
 * Negotiate a possible protocol switch on the connection. The negotiation
 * may start without any request sent, in which case the request is NULL. Or
 * it may be triggered by the request received, e.g. through the "Upgrade"
 * header.
 * 
 * The identifiers for protocols are taken from the TLS extension type ALPN:
 * https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml
 *
 * If no protocols are added to the proposals, the server will always fallback
 * to "http/1.1" which is the default protocol for connections that Apache
 * handles. If the protocol selected from the proposals is the protocol
 * already in place, no "protocol_switch" will be invoked.
 *
 * All hooks are run, unless one returns an error. Proposals may contain
 * duplicates. The order in which proposals are added is usually ignored.
 * 
 * @param c The current connection
 * @param r The current request or NULL
 * @param offers a list of protocol identifiers offered by the client
 * @param proposals the list of protocol identifiers proposed by the hooks
 * @return OK or DECLINED
 */
AP_DECLARE_HOOK(int,protocol_propose,(conn_rec *c, request_rec *r,
                                      const apr_array_header_t *offers,
                                      apr_array_header_t *proposals))

/**
 * Perform a protocol switch on the connection. The exact requirements for
 * that depend on the protocol in place and the one switched to. The first 
 * protocol module to handle the switch is the last module run.
 * 
 * For a connection level switch (r == NULL), the handler must on return
 * leave the conn_rec in a state suitable for processing the switched
 * protocol, e.g. correct filters in place.
 *
 * For a request triggered switch (r != NULL), the protocol switch is done
 * before the response is sent out. When switching from "http/1.1" via Upgrade
 * header, the 101 intermediate response will have been sent. The
 * hook needs then to process the connection until it can be closed. Which
 * the server will enforce on hook return.
 * Any error the hook might encounter must already be sent by the hook itself
 * to the client in whatever form the new protocol requires.
 *
 * @param c The current connection
 * @param r The current request or NULL
 * @param choices a list of protocol identifiers, normally the clients whishes
 * @param proposals the list of protocol identifiers proposed by the hooks
 * @return OK or DECLINED
 */
AP_DECLARE_HOOK(int,protocol_switch,(conn_rec *c, request_rec *r,
                                     const char *protocol))

/**
 * Return the protocol used on the connection. This is either the
 * default protocol of the connection or the one last switched to.
 * This allows modules to extends the type of connections that 
 * Apache understands.
 * @param c The current connection
 * @return The identifier of the protocol in place
 */
AP_DECLARE_HOOK(const char *,protocol_get,(const conn_rec *c))
    
/**
 * Select a protocol for the given connection and optional request. Will return
 * the protocol identifier selected which may be the protocol already in place
 * on the connection. The server may ignore the choices given.
 *
 * @param c The current connection
 * @param r The current request or NULL
 * @param choices a list of protocol identifiers, normally the clients whishes
 * @return the selected protocol
 */
AP_DECLARE(const char *) ap_select_protocol(conn_rec *c, request_rec *r, 
                                            apr_array_header_t *choices);

/**
 * Perform the actual protocol switch. The protocol given must have been
 * selected before on the very same connection and request pair.
 *
 * @param c The current connection
 * @param r The current request or NULL
 * @param protocol the protocol to switch to
 * @return APR_SUCCESS, if caller may continue processing as usual
 *         APR_EOF,     if caller needs to stop processing the connection
 *         APR_EINVAL,  if the protocol is already in place
 *         APR_NOTIMPL, if no module performed the switch
 *         Other errors where appropriate
 */
AP_DECLARE(apr_status_t) ap_switch_protocol(conn_rec *c, request_rec *r, 
                                            const char *protocol);