Using Server Name Indication (SNI) with HTTP Kit client
Update (2019, Feb 11): Code snippet updated to configure client mode.
More and more websites and web services are adopting HTTPS today, which makes SSL termination on dedicated IP addresses increasingly challenging. Server Name Indication is a common way to multiplex multiple SSL termination on a single IP address. SNI is implemented as a Transport Layer Security (TLS) extension, hence connecting with an SNI-enabled HTTPS endpoint requires an SNI-aware client.
HTTP Kit is a popular web server and client for the Clojure programming language. SNI support was recently added to the HTTP Kit client. However, we need to configure the HTTP Kit client to support SNI owing to the fact that HTTP Kit supports Java 6 or higher, whereas proper client SNI support requires specific Java 8 API. You will require a Java 8 (or higher) runtime for configuring HTTP Kit client to use SNI. More recent your Java 8 runtime version, the better chances you have at connecting to most HTTPS websites.
Configure client for SNI
First of all, make sure you are using Java 8 and HTTP Kit 2.3.0-alpha4 (or later) by specifying the dependency [http-kit “2.3.0-alpha4”] in your project. Next, you need a helper function to configure SNI on the SSLEngine.
(ns myapp.sni
(:import
[java.net URI]
[javax.net.ssl
SNIHostName SNIServerName SSLEngine SSLParameters]))(defn sni-configure
[^SSLEngine ssl-engine ^URI uri]
(let [^SSLParameters ssl-params (.getSSLParameters ssl-engine)]
(.setServerNames ssl-params [(SNIHostName. (.getHost uri))])
(.setUseClientMode ssl-engine true)
(.setSSLParameters ssl-engine ssl-params)))
This function may be used to create a client configured to use SNI. Below is an example how you can create a client.
(def sni-client (org.httpkit.client/make-client
{:ssl-configurer myapp.sni/sni-configure}))
Now, this client may be used to connect to SNI-enabled websites.
@(org.httpkit.client/get "https://soundcloud.com"
{:client sni-client})
Troubleshooting
When not using SNI-configured client for SNI-enabled websites, you will get javax.net.ssl.SSLException with the error message “Received fatal alert: handshake_failure”. When you are using SNI-configured client but your Java 8 version is old, you may encounter javax.net.ssl.SSLHandshakeException with a message “General SSLEngine problem”.