title: How do a send an HTTPS request through a proxy in Java?
body: <p>I am trying to send a request to a server using the HttpsUrlConnection class.  The server has certificate issues, so I set up a TrustManager that trusts everything, as well as a hostname verifier that is equally lenient.  This manager works just fine when I make my request directly, but it doesn't seem to be used at all when I send the request through a proxy.</p>
  <p>I set my proxy settings like this:</p>
  <pre><code>Properties systemProperties = System.getProperties();
  systemProperties.setProperty( &quot;http.proxyHost&quot;, &quot;proxyserver&quot; );
  systemProperties.setProperty( &quot;http.proxyPort&quot;, &quot;8080&quot; );
  systemProperties.setProperty( &quot;https.proxyHost&quot;, &quot;proxyserver&quot; );
  systemProperties.setProperty( &quot;https.proxyPort&quot;, &quot;8080&quot; );
  </code></pre>
  <p>The TrustManager for the default SSLSocketFactory is set up like this:</p>
  <pre><code>SSLContext sslContext = SSLContext.getInstance( &quot;SSL&quot; );
  
  // set up a TrustManager that trusts everything
  sslContext.init( null, new TrustManager[]
      {
          new X509TrustManager()
          {
              public X509Certificate[] getAcceptedIssuers()
              {
                  return null;
              }
  
              public void checkClientTrusted( X509Certificate[] certs, String authType )
              {
                  // everything is trusted
              }
  
              public void checkServerTrusted( X509Certificate[] certs, String authType )
              {
                  // everything is trusted
              }
          }
      }, new SecureRandom() );
  
  // this doesn't seem to apply to connections through a proxy
  HttpsURLConnection.setDefaultSSLSocketFactory( sslContext.getSocketFactory() );
  
  // setup a hostname verifier that verifies everything
  HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier()
  {
      public boolean verify( String arg0, SSLSession arg1 )
      {
          return true;
      }
  } );
  </code></pre>
  <p>If I run the following code, I end up with an SSLHandshakException (&quot;Remote host closed connection during handshake&quot;):</p>
  <pre><code>URL url = new URL( &quot;https://someurl&quot; );
  
  HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
  connection.setDoOutput( true );
  
  connection.setRequestMethod( &quot;POST&quot; );
  connection.setRequestProperty( &quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot; );
  connection.setRequestProperty( &quot;Content-Length&quot;, &quot;0&quot; );
  
  connection.connect();
  </code></pre>
  <p>I assume I am missing some kind of setting having to do with using a proxy when dealing with SSL.  If I don't use a proxy, my checkServerTrusted method gets called; this is what I need to happen when I am going through the proxy as well.</p>
  <p>I don't usually deal with Java and I don't have much experience with HTTP/web stuff.  I believe I have provided all the detail necessary to understand what I am trying to do.  If this isn't the case, let me know.</p>
  <p><strong>Update:</strong></p>
  <p>After reading the article suggested by ZZ Coder, I made the following changes to the connection code:</p>
  <pre><code>HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
  connection.setSSLSocketFactory( new SSLTunnelSocketFactory( proxyHost, proxyPort ) );
  
  connection.setDoOutput( true );
  connection.setRequestMethod( &quot;POST&quot; );
  connection.setRequestProperty( &quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot; );
  connection.setRequestProperty( &quot;Content-Length&quot;, &quot;0&quot; );
  
  connection.connect();
  </code></pre>
  <p>The result (SSLHandshakeException) is the same.  When I set the SLLSocketFactory here to the SSLTunnelSocketFactory (the class explained in the article), the stuff I did with the TrustManager and the SSLContext is overridden.  Don't I still need that?</p>
  <p><strong>Another Update:</strong></p>
  <p>I modified the SSLTunnelSocketFactory class to use the SSLSocketFactory that uses my TrustManager that trusts everything.  It doesn't appear that this has made any difference.  This is the createSocket method of SSLTunnelSocketFactory:</p>
  <pre><code>public Socket createSocket( Socket s, String host, int port, boolean autoClose )
      throws IOException, UnknownHostException
  {
      Socket tunnel = new Socket( tunnelHost, tunnelPort );
  
      doTunnelHandshake( tunnel, host, port );
  
      SSLSocket result = (SSLSocket)dfactory.createSocket(
          tunnel, host, port, autoClose );
  
      result.addHandshakeCompletedListener(
          new HandshakeCompletedListener()
          {
              public void handshakeCompleted( HandshakeCompletedEvent event )
              {
                  System.out.println( &quot;Handshake finished!&quot; );
                  System.out.println(
                      &quot;\t CipherSuite:&quot; + event.getCipherSuite() );
                  System.out.println(
                      &quot;\t SessionId &quot; + event.getSession() );
                  System.out.println(
                      &quot;\t PeerHost &quot; + event.getSession().getPeerHost() );
              }
          } );
  
      result.startHandshake();
  
      return result;
  }
  </code></pre>
  <p>When my code calls connection.connect, this method is called, and the call to doTunnelHandshake is successful.  The next line of code uses my SSLSocketFactory to create an SSLSocket; the toString value of result after this call is:</p>
  <p><strong>&quot;1d49247[SSL_NULL_WITH_NULL_NULL: Socket[addr=/proxyHost,port=proxyPort,localport=24372]]&quot;</strong>.</p>
  <p>This is meaningless to me, but it might be the reason things break down after this.</p>
  <p>When result.startHandshake() is called, the same createSocket method is called again from, according to the call stack, HttpsClient.afterConnect, with the same arguments, except Socket s is null, and when it comes around to result.startHandshake() again, the result is the same SSLHandshakeException.</p>
  <p>Am I still missing an important piece to this increasingly complicated puzzle?</p>
  <p>This is the stack trace:</p>
  <pre>
  javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:808)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
    at gsauthentication.SSLTunnelSocketFactory.createSocket(SSLTunnelSocketFactory.java:106)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:391)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
    at gsauthentication.GSAuthentication.main(GSAuthentication.java:52)
  Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789)
    ... 8 more
  </pre>