How to Debug HttpRequestExecutor.execute(request, connection, context);.? - java

The below lines of code
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
HttpResponse response2 = httpexecutor.execute(request2, conn, context);
log.info("Status Line "+response2.getStatusLine());
while executing the second statement my request/response is blocked by proxy. How to debug this.?
While the same statement executing from my local environment where no proxy is configured, am able to see
the log returns the below code
"Status Line HTTP/1.1 200 OK"

I think what you are looking for is to set a timeout on the request - basically telling the executor to give up if no connection can be established within a certain period of time.
This SO article covers this: Java HTTP Client Request with defined timeout
the accepted answer has important information about the fact that Apache's implementation has two timeouts - be sure to read that.
Note that it won't be possible for you to actually distinguish between a connection failure that was caused by some other problem - all you will know is that your attempt timed out. In your response to the user, you'll probably wind up saying "Unable to connect to host XXXXX. Possible causes are that your Internet connection is down, or that you have a proxy server that prevents outbound connections to that host."

Related

How to set TCP keep Alive from HttpClient?

My Java application which resides in AWS private subnet connects to an http server via AWS Nat gateway. I am calling a POST request via HttpClient to the HTTP server. That request will take more than 10 minutes to complete. I have configured a socket time out and connection timeout of 1 hour as this this a background task . But the intermediate AWS NAT gateway will send back a RST packet after 300 secs [5 mins] and cause the connection to get resetted , there is no way i can increase the NAT gateway timeout. So i need to handle the problem from my application side.
My strategy is to use a TCP keep alive time which will send a packet say every 240 secs to keep the connection active. I have configured this
as below
CloseableHttpClient httpClient = HttpClients.createDefault()
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 3600000); //connection Timeout
HttpConnectionParams.setSoTimeout(params, 3600000); // Socket Time out
HttpConnectionParams.setSoKeepalive(params, true); //Enable Socket level keep alive time
and then call the post request via execute method
HttpPost post = new HttpPost("http://url");
HttpResponse response = httpClient.execute(post);
Since I am using a Linux system I have configured the server with following sysctl values:
sysctl -w net.ipv4.tcp_keepalive_time=240
sysctl -w net.ipv4.tcp_keepalive_intvl=240
sysctl -w net.ipv4.tcp_keepalive_probes=10
But while executing the program the keep alive is not enabled and connection fails as previous.
I have checked this with netstat -o option and as shown below keep alive is off
tcp 0 0 192.168.1.141:43770 public_ip:80 ESTABLISHED 18134/java off (0.00/0/0)
Is there any way i can set TCP keep alive from java code using httpclient . Also I can see HttpConnectionParams are deprecated. But I couldn't find any new class which can set keep alive
I have found a solution to the problem . Curious case is there is no way i can use some builder class in httpclient to pass socket keep alive . One method as i specified in the question is using HttpConnectionParams as below but this is not working and this class is now deprecated.
HttpParams params = httpClient.getParams();
HttpConnectionParams.setSoKeepalive(params, true);
So while checking apache http docs I can see that now connection parameters are passed to httpclient via RequestConfig class . Builders of this class provide solution to set connection_time_out and socket_time_out. But checking the socurce code of this I couldnt see an option to enable SocketKeepAlive which is what we want. So the only solution is directly creating a Socket using SocketBuilder class and pass that to the HttpClientBuilder.
Following is the working code
SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setSoTimeout(3600000).build(); //We need to set socket keep alive
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(3600000).build();
CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).
setDefaultSocketConfig(socketConfig).build();
HttpPost post = new HttpPost(url.toString());
HttpResponse response = httpClient.execute(post);
While executing above i can see that keep alive is properly set in the socket based on the sysctl values i set in linux kernel
tcp 0 0 localip:48314 public_ip:443 ESTABLISHED 14863/java keepalive (234.11/0/0)
If some one has a better solution to enable Socket Keep alive from Requestconfig class or any other high level builder class i am open to suggestions.
Keeping an HTTP connection open but inactive for a long period is a bad design choice. HTTP is a request-response protocol, with the implication that requests and responses are quick.
Holding a connection open holds resources. From the perspective of the server (and network firewalls and routers) a client that opens a connection and begins a request (A POST in your case) but does not send any bytes for a long period is indistinguishable from a client that will never send any more data, because it is faulty or malicious (conducting a DOS attack). The server (and network hardware) is right to conclude that the right thing to do is to shutdown the connection and reclaim the resources used for it. You are trying to fight against correct behaviour that occurs for good reasons. Even if you manage to workaround the TCP shutdown you will find other problems, such as HTTP server timeouts and database timeouts.
You should instead be reconsidered the design of communication between the two components. That is, this looks like an XY Problem. You might consider
Having the client wait until it has a complete upload to perform before starting the POST.
Splitting the uploads into smaller, more frequent uploads.
Use a protocol other than HTTP.
The approach above with Socket worked beautifully with a reset of tcp_keepalive_intvl value below the AWS Network Load Balancer timeout. Using both, reset the NLB tcp idle timeout that allowed java hour+ connections.
Sometimes, if the configuration is overwritten, the configuration does not take effect.My initial modification of setDefaultSocketConfig in buildClient didn't take effect.Because it is overwritten by getConnectionManager()
public CloseableHttpClient buildClient() throws Exception {
HttpClientBuilder builder = HttpClientBuilder.create()
.setDefaultSocketConfig(SocketConfig.custom().setSoKeepAlive(true).build()) // did not work
.setConnectionManager(getConnectionManager())
.setRetryHandler(getRequestRetryHandler())
.setConnectionReuseStrategy(getConnectionReuseStrategy())
.setDefaultConnectionConfig(getConnectionConfig())
.setDefaultRequestConfig(getRequestConfig())
.setDefaultHeaders(getDefaultHeaders())
.setDefaultCredentialsProvider(getDefaultCredentialsProvider())
.disableContentCompression() // gzip is not needed. Use lz4 when compress=1
.setDefaultCookieStore(cookieStoreProvider.getCookieStore(properties))
.disableRedirectHandling();
String clientName = properties != null ? properties.getClientName() : null;
if (!Utils.isNullOrEmptyString(clientName)) {
builder.setUserAgent(clientName);
}
return builder.build();
And then I move the config to getConnectionManager(),and it work.
private PoolingHttpClientConnectionManager getConnectionManager()
throws CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException {
RegistryBuilder<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory());
if (properties.getSsl()) {
HostnameVerifier verifier = "strict".equals(properties.getSslMode()) ? SSLConnectionSocketFactory.getDefaultHostnameVerifier() : NoopHostnameVerifier.INSTANCE;
registry.register("https", new SSLConnectionSocketFactory(getSSLContext(), verifier));
}
//noinspection resource
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
registry.build(),
null,
null,
new IpVersionPriorityResolver(),
properties.getTimeToLiveMillis(),
TimeUnit.MILLISECONDS
);
connectionManager.setDefaultMaxPerRoute(properties.getDefaultMaxPerRoute());
connectionManager.setMaxTotal(properties.getMaxTotal());
connectionManager.setDefaultConnectionConfig(getConnectionConfig());
connectionManager.setDefaultSocketConfig(SocketConfig.custom().setSoKeepAlive(true).build());
return connectionManager;
}

Apache HTTPClient ignores timeout configuration when outbound stream interrupted by remote failure?

I have a client on Host A using Apache HTTPClient (4.2.5) to POST a message to a server on Host B. On Host A, I am setting the connect and read/socket timeouts in (what I believe to be) the recommended fashion:
client = new DefaultHttpClient();
params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 20000);
I am attempting to test the timeout behavior in the event that the client transmission is abruptly terminated (e.g. by a crash of the target server on Host B) after some but not all of the data stream has been transmitted. My testing methodology has been thus:
Initiate HTTP POST from client application on Host A.
Shortly after the logs indicate that the client has invoked the underlying Apache HTTPClient framework, enable a firewall rule on Host B to block traffic from Host A.
I can confirm (via packet captures) that the test is, in fact, cutting off the request data mid-stream.
I would have expected the client application to subsequently time out after the read timeout interval (20 seconds), but what I'm seeing instead is that the client hangs for a much longer interval (in the 500-600 seconds range) before finally encountering a connect timeout.
Can anyone explain (or failing that, venture a guess) as to why the client is ignoring what I have specified as the timeout? Is there any way that I can enforce a timeout in this case?
Not sure why that isn't working but you could try an alternate approach where you create the Params object prior to instantiating the HttpClient.
Something to this effect:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 20000);
HttpClient httpClient = new DefaultHttpClient(params);
There is also a set of parameters unique to each http message which would override the setting of the client connection object. You might want to check to see if they specify the timeout themselves and thus leave the one you set unused (shouldn't happen unless explicitly set, but worth checking)
HttpMessage#getParam
Further, you could try to explicity set those parameters on your HttpGet or HttPost objects yourself and see if that alters the behavior.
So what happens is, the timeout property is applicable on each address that is obtained by DNS resolution. E.g abc.come resolved to 4 different ip address and you have set a timeout of 10 sec. So your request will wait for 4 x 10 = 40 sec in total before timing out.

Understanding if URLConnection connections are really being pooled?

I'm using URLConnection for my http client. Using Wireshark, I can see that setting up an https connection can take up to four seconds. Therefore I would like to pool connections if possible to avoid the https setup time. My flow looks like this:
public String work(String url) {
HttpURLConnection conn = (HttpURLConnection)(new URL(url)).openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String response = br.readResponseFromConnection();
conn.disconnect();
br.close();
return response;
}
public void onBtnClickTest() {
work("https://example.com/echo?param=abc");
}
With the above setup, I click my test button twice, but it looks like the https setup is done for each call, which makes me think the connection isn't really being reused (at least not in the way that I was hoping). Through Wireshark I see something like the following :
// first click
Client Hello
Server Hello
Certificate, Server Hello Done
Client Key Exchange, Change Cipher Spec, Encrypted...
Encrypted Handshake Message...
Application Data
// second click, 20 seconds after my first click.
Client Hello
Server Hello
Certificate, Server Hello Done
Client Key Exchange, Change Cipher Spec, Encrypted...
Encrypted Handshake Message...
Application Data
However, if I click the test button twice within a span of < 5 seconds, it looks like the handshake is skipped for the second run, and I immediately see the "Application Data" message. I think I remember reading somewhere that URLConnection only keeps connections pooled for 5 seconds.
So my questions:
Can URLConnection actually pool my connections in the way that I want, in that subsequent connections can skip the https handshake (if hitting the same domain)?
If the above is possible, is there a way to increase the duration that connections stay pooled? My application is unlikely to make http calls within 5 seconds of eachother.
I know HttpClient offers a pool manager to reuse a connection, but looks more complicated than URLConnection. Can it get me around # 1 & 2 if they won't do what I need?
Thank you
You can use Keep-Alive header property to persisit any httpconnection. Here is documentation on Http Keep-alive Http Keep Alive
section What can you do to help with Keep-Alive gives exact information what you are looking for. Quick search in SO gave me another link which is exactly like your question.
SO disucssion link

How to debug SocketTimeoutException?

We are getting a java.net.SocketTimeoutException on server B when client A connects to server B. No idea why. The client is sending data to the server and the server then throws this exception. How would one troubleshoot this issue?
Note currently this has happened only once. Not sure if this is reproduceable. Attempting to setup the test again..
I had same problems, when my users used 3G or 2G network. It means, that you send request to server, and can't estabilish connection, because of weak internet signal. You can increase timeouts on your connection
URLConnection connection;
int timeout = 30 * 1000;
connection.setConnectTimeout(timeout);
connection.setReadTimeout(timeout);
But if you have weaaak weeeaaaak internet connection, timeouts does not help you.
I'm just created 1 testFunction in WebService (or you can use one of yours) for testing connection with server before calling another required functions, and if I get SockectTimeoutException calling this function - just report to user notification "Weak internet connection!".
No data arrived at the receiver within the timeout period. That's all it means. Debugging it means finding out why the data you think was sent wasn't sent. A missing flush() for example.

How to set the timeout for a MQTT client?

I'm using the IA92 Java implementation for MQTT, which allows me to connect to a MQTT broker. In order to establish the connection, I'm doing something like this:
// Create connection spec
String mqttConnSpec = "tcp://the_server#the_port";
// Create the client and connect
mqttClient = MqttClient.createMqttClient(mqttConnSpec, null);
mqttClient.connect("the_id", true, 666);
The problem is that sometimes the server takes too much time to send a response, and it throws a timeout exception:
org.apache.harmony.luni.platform.OSNetworkSystem.connectStreamWithTimeoutSocket(OSNetworkSystem.java:130)
at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:246)
at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:533)
at java.net.Socket.connect(Socket.java:1055)
at com.ibm.mqtt.j2se.MqttJava14NetSocket.<init>((null):-1)
at com.ibm.mqtt.j2se.MqttJavaNetSocket.setConnection((null):-1)
at com.ibm.mqtt.Mqtt.tcpipConnect((null):-1)
at com.ibm.mqtt.MqttBaseClient.doConnect((null):-1)
at com.ibm.mqtt.MqttBaseClient.connect((null):-1)
at com.ibm.mqtt.MqttClient.connect((null):-1)
at com.ibm.mqtt.MqttClient.connect((null):-1)
What I need to do is setting a timeout manually, instead of letting the mqtt client decide that. The documentation says: There are also methods for setting attributes of the MQ Telemetry Transport connection, such as timeouts and retries.
But, honestly, I haven't found anything about it. I have taken a look at the whole javadoc reference and there's no evidence of timeout configuration. I can't see the source code since it's not open source.
So how can I set the timeout for the Mqtt connection?
If you have confusion you can go to MqttConnectionOptions for detail.
String userName="Ohelig";
String password="Pojke";
MqttClient client = new MqttClient("tcp://192.168.1.4:1883","Sending");
MqttConnectOptions authen = new MqttConnectOptions();
authen.setUserName(userName);
authen.setPassword(password.toCharArray());
authen.setKeepAliveInterval(30);
authen.setConnectionTimeout(300);
client.connect(authen);
I don't know anything about ia92, but I'd imagine that the 666 in the connect() call is what you're trying to set the timeout to?
The timeout the documentation is referring to is probably the keepalive timeout. This is the maximum number of seconds (chosen by the client) that can elapse without communication between the server and client. I think this is what you're most interested in.
Retries on the other hand are most likely to refer to the retrying of messages that seem to have gone astray when sending messages with QoS>0. This will be something handled by the client library code though, rather than the broker. This is something that comes into play only after you've connected though, so I very much doubt it's your problem.
To be sure that the keepalive timeout is being set correctly, I'd try pointing your client at a modified mosquitto broker. You can modify mqtt3_handle_connect() in src/read_handle_server.c to print out the keepalive value when you connect. This will ensure it's doing what you think, but won't help with the actual problem I'm afraid!
What broker do you use? Really Small Message Broker V1.1 Alpha, Mosquitto, the broker that comes with IBM WebSphere? You need to set this timeout value in your server configuration. Because the system works that way. You set a keep alive value in your broker and send a ping from the client before that interval expires, in order not for the broker to close the client-server connection, and the process restarts. Actually, even if that interval expires, server will still not close the connection until the 'grace period' ends. See http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect

Categories

Resources