title: How to enable SNI in HTTP request using Apache HTTPComponents HttpClient?
body: <p>I am trying to figure out  how to send a successful HTTP GET request to a server requiring SNI.</p>
  
  <p>I searched on SO and other places, and found some articles that said that SNI is now supported in JDK7, as well as Apache HTTP Components.</p>
  
  <p><a href="https://issues.apache.org/jira/browse/HTTPCLIENT-1119" rel="noreferrer">https://issues.apache.org/jira/browse/HTTPCLIENT-1119</a>
  <a href="https://wiki.apache.org/HttpComponents/SNISupport" rel="noreferrer">https://wiki.apache.org/HttpComponents/SNISupport</a></p>
  
  <p>Relevant SO article: <a href="https://stackoverflow.com/questions/17975295/certificate-chain-different-between-httpsurlconnection-and-apache-system-defau/18000174#18000174">Certificate chain different between HTTPSURLconnection and Apache (System) DefaultHttpClient</a></p>
  
  <p>--</p>
  
  <p>However, I cannot seem to find any docs that show how to get this to work.</p>
  
  <p>Here is the code I am using...</p>
  
  <p><pre><code>
              KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
              String trustedCertsPath = System.getenv("JAVA_HOME") + "/jre/lib/security/cacerts";
              FileInputStream certstream = new FileInputStream(new File(trustedCertsPath));
              try {
                  trustStore.load(certstream, "changeit".toCharArray());
              } finally {
                  certstream.close();
              }</p>
  
          // Trust own CA and all self-signed certs
          SSLContext sslcontext = SSLContexts.custom()
                  .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
                  .build();
  
          // Allow TLSv1 protocol only
          SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                  sslcontext,
                  new String[] { "TLSv1" },
                  null,
                  SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
  
          CloseableHttpClient httpclient2 = HttpClients.custom()
                  .setSSLSocketFactory(sslsf)
                  .build();
  
          CloseableHttpClient httpclient = HttpClients.createDefault();
  
          HttpGet httpget = new HttpGet(uri);
          CloseableHttpResponse response = httpclient.execute(httpget);
          try {
              HttpEntity entity = response.getEntity();
              if (entity != null) {
                  tempFile = File.createTempFile(httpFile.getTempFilePrefix(), httpFile.getTempFilePosfix());
                  FileOutputStream os = new FileOutputStream(tempFile);
  
                  InputStream instream = entity.getContent();
                  try {
                      IOUtils.copy(instream, os);
                  } finally {
                      try { instream.close(); } catch (Exception e) {}
                      try { os.close(); } catch (Exception e) {}
                  }
              }
          } finally {
              response.close();
          }
  </code></pre>
  
  <p></p>
  
  <p>When I run this, the request fails.</p>
  
  <p>The server requires SNI in the request, and without it, it returns an expired cert that has the wrong CommonName, due to which it gets rejected.</p>
  
  <p>If I use the httpclient2 instance, that is setup using a custom SSL context to allow all hTTP certs, then the request succeeds. However, that is not something I want to enable on a server that does a lot of downloads per day against different hosts.</p>
  
  <p>I am using httpclient v 4.3.5</p>
  
  <p>Any help appreciated.</p>
  
  <p>Thanks.</p>