Solved

Unexpected HttpURLConnection connection behavior

Posted on 2016-10-19
2
46 Views
Last Modified: 2016-10-20
Greetings.

I am converting an Applet into a Desktop Application, and one of the internal program's services includes a SOAP client, designed to send information to a remote server. Here is a piece of the code in charge of this process:

package my.package.app.utils;

import my.package.app.main.MainClass;
import my.package.app.org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SoapClient {
    
    public static JSONObject callMethod(String path, String method, Object... args) {
        HttpURLConnection connection = null;
        String            data       = null;
        try {
            data = parseXML(method, args);
            
            MainClass.debug("Making http POST connections to : " + path);
            
            URL           u  = new URL(path);
            URLConnection uc = u.openConnection();
            connection = (HttpURLConnection) uc;
            
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("SOAPAction", method);
            connection.setUseCaches(false);
            
            OutputStream out  = connection.getOutputStream();
            Writer       wout = new OutputStreamWriter(out);
            
            wout.write(data);
            wout.flush();
            wout.close();
            
            InputStream            in  = connection.getInputStream();
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder        db  = dbf.newDocumentBuilder();
            Document               doc = db.parse(in);
            
            doc.getDocumentElement().normalize();
            
            NodeList childs       = doc.getElementsByTagName("return");
            String   responseText = childs.item(0).getTextContent();
            
            if ("false".equals(responseText)) {
                return null;
            }
            
            JSONObject response = new JSONObject(responseText);
            
            in.close();
            return response;
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        return null;
    }
    
    private static String parseXML(String method, Object... args) {
        
        StringBuilder xml = new StringBuilder();
        
        xml.append(XMLTemplates.soapHeader);
        xml.append("<ns1:");
        xml.append(method);
        xml.append(">");
        
        for (int i = 0; i < args.length; i++) {
            
            String dataType = "xsi:type=\"xsd:string\"";
            
            xml.append("<param");
            xml.append(i);
            xml.append(" ");
            
            if (args[i] instanceof Integer) {
                dataType = "xsi:type=\"xsd:integer\"";
            }
            
            if (args[i] instanceof Double) {
                dataType = "xsi:type=\"xsd:decimal\"";
            }
            
            if (args[i] instanceof Boolean) {
                dataType = "xsi:type=\"xsd:boolean\"";
            }
            
            xml.append(dataType);
            xml.append(">");
            xml.append(String.valueOf(args[i]));
            xml.append("</param");
            xml.append(i);
            xml.append(">");
        }
        
        xml.append("</ns1:");
        xml.append(method);
        xml.append(">");
        
        xml.append(XMLTemplates.soapFooter);
        
        return xml.toString();
    }
    
}

Open in new window


When the callMethod  is used, it received in my case a path string with an URL with HTTPS protocol like this: "https://fileserver.myserver.net:9000/lf_soap_document_server_main.php".

When running the callMethod with that URL, the applet's Java console displays the following:

18:15:45.476-DEBUG: Making http POST connections to : https://fileserver.myserver.net:9000/lf_soap_document_server_main.php
network: Connecting https://fileserver.myserver.net:9000/lf_soap_document_server_main.php with proxy=DIRECT
network: Connecting http://fileserver.myserver.net:9000/ with proxy=DIRECT

Open in new window


and the process completes successfully.

But when the same piece of code, with the same information is executed from the Desktop Application version, the following happens:

18:28:29.991-DEBUG: Making http POST connections to : https://fileserver.myserver.net:9000/lf_soap_document_server_main.php
network: Connecting https://fileserver.myserver.net:9000/lf_soap_document_server_main.php with proxy=DIRECT
network: Connecting socket://fileserver.myserver.net:9000 with proxy=DIRECT
java.net.ConnectException: Connection timed out: connect

Open in new window


Here the problems occurs when OutputStream out  = connection.getOutputStream(); is called. And please note that the log message changes the protocol of the URL from https:// to socket://, and also seems to remove the last slash (/).

This is the full exception:
java.net.ConnectException: Connection timed out: connect
  at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
  at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
  at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
  at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
  at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
  at java.net.PlainSocketImpl.connect(Unknown Source)
  at java.net.SocksSocketImpl.connect(Unknown Source)
  at java.net.Socket.connect(Unknown Source)
  at sun.security.ssl.SSLSocketImpl.connect(Unknown Source)
  at sun.net.NetworkClient.doConnect(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source)
  at sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
  at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$6.run(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$6.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.AccessController.doPrivilegedWithCombiner(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
  at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.access$100(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$8.run(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$8.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.AccessController.doPrivilegedWithCombiner(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
  at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
  at my.package.app.utils.SoapClient.callMethod(SoapClient.java:42)
  at my.package.app.services.scanner.LFScanner$SoapUpload.run(LFScanner.java:746)

Open in new window


The desktop application uses Jetty to create a connection to a secure websocket server, and also creates a local websocket server in the user's machine, but none of them has business with the SoapClient class where the problem happens.

I have tested setting a 5 minutes timeout for connection and read to the HttpURLConnection instance but the problem keeps happening on the desktop application in less than a minute.

I am using 1.8.0_111-b14 as runtime to execute the programs (applet and desktop application), on a Windows 10 machine, 64 bits.

I need to know if there is anything wrong with this code, or if there is a missing setting here to prevent this from happening.

Any help is highly appreciated.

Thanks.
0
Comment
Question by:lfmaleon
2 Comments
 
LVL 35

Accepted Solution

by:
mccarl earned 500 total points
Comment Utility
Looking at the lines in your console output that start with "network:", my guess is that your application is installing some custom functionality that is logging those lines, and handling the redirection/scheme change and proxy details. It is probably doing this via the Socket.setSocketImplFactory() method. This maybe Jetty or some other part of your code, but the problem with the above is that it applies JVM wide. Can you try extracting just your SoapClient class above, into a totally separate project and running it standalone? I'm guessing that you WON'T see those "network:" lines and that it might just work, which will at least tell us if it is some other part of the app that is affecting the connection behaviour. If so, then you will have to dig further to find out what is being configued elsewhere in the app.
0
 

Author Comment

by:lfmaleon
Comment Utility
I did as mccarl suggested, and found that the isolated piece of code is failing sometimes as well, and sometimes it passes through correctly. I then tested in depth the SOAP URL and found that the general availability of that service is not 100% which explains the behavior of both programs.

It was more like a coincidence that the Applet code passes through and the Desktop Application code doesn't. But in the end the problem is the SOAP server itself.

Thanks for the suggestion.
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Read about why website design really matters in today's demanding market.
Boost your ability to deliver ambitious and competitive web apps by choosing the right JavaScript framework to best suit your project’s needs.
Viewers will get an overview of the benefits and risks of using Bitcoin to accept payments. What Bitcoin is: Legality: Risks: Benefits: Which businesses are best suited?: Other things you should know: How to get started:
The viewer will learn how to dynamically set the form action using jQuery.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now