Tuesday, June 13, 2017

Java: debugging HttpsClient connections

Recently we had this case:


 java.io.EOFException: SSL peer shut down incorrectly    SSL peer shut down incorrectly
 at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:462)
 at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
 at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1323)
 at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1350)
 at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1334)
 at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:569)
 at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
 at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1075)
 at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
 at com.sun.xml.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:129)
 at com.sun.xml.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:187)
 at com.sun.xml.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:124)
 at com.sun.xml.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:118)
 at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:866)
 at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:815)
 at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:778)
 at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:680)
 at com.sun.xml.ws.client.Stub.process(Stub.java:272)
 at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:153)
 at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:115)
 at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:95)
 at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:136)
 at com.sun.proxy.$Proxy225.getInstruments30(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at weblogic.wsee.jaxws.spi.ClientInstanceInvocationHandler.invoke(ClientInstanceInvocationHandler.java:84)
 at com.sun.proxy.$Proxy227.getInstruments30(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)



Problem is, there is no way to trace the host, port, proxy parameters, protocols being used etc.

The classes involved are in jsse.jar and rt.jar (this is java 6!).

The other issue is that most attributes in those classes (HttpsClient, HttpClient...) have protected attributes, so you can't even access them easily with btrace or the like.

I ended up decompiling sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection from jsse.jar and changing the code to:

  public void connect()
    throws IOException
  {
    if (this.connected) {
      return;
    }
    plainConnect();
    if (this.cachedResponse != null) {
      return;
    }
    if ((!this.http.isCachedConnection()) && (this.http.needsTunneling())) {
      doTunneling();
    }
    try {
     java.lang.reflect.Field phost = HttpClient.class.getDeclaredField("host");
     phost.setAccessible(true);
     java.lang.reflect.Field pport = HttpClient.class.getDeclaredField("port");
     pport.setAccessible(true);
     System.out.println("PV host = " + phost.get(this.http) + " port = " + pport.get(this.http) + " usingProxy=" + this.http.usingProxy + " getProxyHostUsed=" + this.http.getProxyHostUsed() + " getProxyPortUsed=" + this.http.getProxyPortUsed());
    }
    catch (Throwable t) {
     System.out.println("PV an error occurred in AbstractDelegateHttpsURLConnection : ");
     t.printStackTrace();
    }
    ((HttpsClient)this.http).afterConnect();
  }

packaging the compiled class in pvjsse.jar and adding -Xbootclasspath/p:pvjsse.jar to the JVM parameters. It works !



No comments: