Socket Timeout is not working in Servlet - java

I have a Java servlet which tries to connect to the source(Using request ip address).
Method is as :
String ip = request.getRemoteAddr();
private void connect(String ip) throws SocketException, IOException {
Socket socket = new Socket();
socket.setSoTimeout(1000);
socket.connect(new InetSocketAddress(ip, Constant.PORT));
}
Now if it doesn't connect withint a second it should throw exception but it is not throwing exception in one second but takes a while like 10-15 seconds.
Could someone help why this is happening?

SO_TIMEOUT (which is set by socket.setSoTimeout) only affects socket.getInputStream().read(). To specify connect timeout, specify a second parameter to socket.connect:
socket.connect(new InetSocketAddress(ip, Constant.PORT), 1000);

Related

Java shutdown http server after receiving request

I have a setup a simple http server in java that only deals with one type of post request.
The server code:
int port = 5555;
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
System.out.println("server started at " + port);
server.createContext("/echoPost", new echoPost());
server.setExecutor(null);
server.start();
The echoPost() class:
public class echoPost implements HttpHandler {
#Override
public void handle(HttpExchange http) throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(http.getRequestBody(), "utf-8");
BufferedReader bufferReader = new BufferedReader(inputStreamReader);
String incoming = br.readLine();
System.out.println(incoming);
String response = "response";
http.sendResponseHeaders(200, response.length());
OutputStream outputStream = http.getResponseBody();
os.write(response.toString().getBytes());
os.close();
}
}
I want the server to stop after a post request is received. Is there a way to do this so straight after one post request is handled the server stops?
What's wrong with calling server.stop(delay), where the delay is small enough (0 or 1)? You'll need to pass server as argument to the echoPost constructor.
Use
System.exit(0);
It doesn't matter where this line of code is executed, it will terminate the JVM and quit.

How to force Commons HTTPClient 3.1 to use TLS 1.2 only for HTTPS?

I wish to force Apache Commons HTTP-Client (version 3.1) to use TLS 1.2 as the only protocol for HTTPS.
This is due to the server supposedly being upgraded to TLS 1.2 and not accepting any older protocol anymore (causing 'Connection Reset' to be returned).
For further context, probably irrelevant, the HTTP-Client is used along with Axis2 to make a SOAP; some of the code used for setting up the HttpClient is below:
MultiThreadedHttpConnectionManager connMgr = new MultiThreadedHttpConnectionManager();
this.httpClient = new HttpClient(connMgr);
// initialize HttpClient parameters
HttpClientParams hcParams = this.httpClient.getParams();
// Maximum time to wait to receive connection from pool
hcParams.setConnectionManagerTimeout(this.maxWait);
hcParams.setSoTimeout(this.timeout);
hcParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(this.retryCount, false));
// Initialize global Connection manager parameters
HttpConnectionManagerParams cmParams = connMgr.getParams();
cmParams.setDefaultMaxConnectionsPerHost(this.maxActive);
cmParams.setStaleCheckingEnabled(this.checkStaleConnections);
cmParams.setConnectionTimeout(this.timeout);
Thanks a lot for the help!
Too bad nobody answered; I was able to do it, first you write a CustomHttpSocketFactory, then you do:
String scheme = "https";
Protocol baseHttps = Protocol.getProtocol(scheme);
int defaultPort = baseHttps.getDefaultPort();
ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory();
ProtocolSocketFactory customFactory = new CustomHttpsSocketFactory(baseFactory);
Protocol customHttps = new Protocol(scheme, customFactory, defaultPort);
Protocol.registerProtocol(scheme, customHttps);
A sample custom socket factory code is found here, but instead I did:
public class CustomHttpsSocketFactory implements SecureProtocolSocketFactory
{
private final SecureProtocolSocketFactory base;
public CustomHttpsSocketFactory(ProtocolSocketFactory base)
{
if(base == null || !(base instanceof SecureProtocolSocketFactory)) throw new IllegalArgumentException();
this.base = (SecureProtocolSocketFactory) base;
}
private Socket acceptOnlyTLS12(Socket socket)
{
if(!(socket instanceof SSLSocket)) return socket;
SSLSocket sslSocket = (SSLSocket) socket;
sslSocket.setEnabledProtocols(new String[]{"TLSv1.2" });
return sslSocket;
}
#Override
public Socket createSocket(String host, int port) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port));
}
#Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort));
}
#Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort, params));
}
#Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException
{
return acceptOnlyTLS12(base.createSocket(socket, host, port, autoClose));
}
}
You need a Socket reference in your code. Then you can set enabled protocols on it like this:
if (socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
}
It depends on how you are writing your clients and what JRE versions you are using:
If you are using JRE8 (unless you have replaced the default SunJSSE that comes with JRE8), there is a system property "jdk.tls.client.protocols". By default, whatever you mention here will be used for all client communication.
If you are using HttpsURLConnection object for client connection, u can use the system property "https.protocols". This will work for all JRE versions, not just JRE8.
If you don't specify anything, for TLS clients, in JRE8, TLSv1, v1.1 and v1.2 are enabled, so it will work with a server what supports any one of this versions. However in JRE7 by default TLSv1 alone is enabled.
In your code u can always override the default or what u pass through the system properties. What u set in the code will take higher precedence. To override in the code...
1) If you are using raw socket and SSLEngine, u can set the protocol and ciphers in the SSLEngine (sslEngine.setEnabledProtocols(..)
2) If you are using SSLSocket, u can set the protocol and ciphers in the SSLSocket (sslSocket.setEnabledProtocols(..)
You can also get an SSLContext with the required protocol enabled and use that for whatever SSL components you use. SSLContext.getInstance("TLSvx.x"). Note that by default it will return a context with all the protocols lesser that TLSvx.x enabled. If u have configured "jdk.tls.client.protocols", this will return a context with those protocols enabled.
It would not be a good idea to hard coded the protocols in the code. Quite often, we will encounter certain customers want specific version either because they use old servers or some serious vulnerabilities are encountered in some TLS versions. Either set it through the system properties or even if you are explicitly setting in sslsocket or sslengine, read that from some conf file.
Also refer:
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html
http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html

InetAddress throws hostname can't be null

is there any way to override the constructor of InetSocketAddress ? our current IP doesnt have a hostname and when i try to connect my websocket to our server it throws hostname can't be null due to
#Override
public InetSocketAddress getLocalAddress() {
return new InetSocketAddress(this.servletRequest.getLocalName(), this.servletRequest.getLocalPort());
}
in ServletServerHttpRequest.class. or can i modify my inetaddress through web.xml or filter?

Unable to get Proxy working with Socket

I am trying to get Proxy working with Socket. But everytime I tried, it would returned a "Exception in thread "pool-1-thread-1" java.lang.IllegalArgumentException: Invalid Proxy" exception error
at java.net.Socket.(Socket.java:131)
But if its Proxy.Type.SOCKS, it works.
public void Test()
{
Socket s = null;
SocketAddress addr = null;
Proxy proxy = null;
addr = new InetSocketAddress("127.0.0.1", 8080);
proxy = new Proxy(Proxy.Type.HTTP, addr);
socket = new Socket(proxy); // This is the line that is triggering the exception
}
Sadly this is a bug in (Oracle) Java - only DIRECT and SOCKS proxy is supported for Socket. See http://bugs.sun.com/view_bug.do?bug_id=6370908.

How to use a custom socketfactory in Apache HttpComponents

I have been trying to use a custom SocketFactory in the httpclient library from the Apache HTTPComponents project. So far without luck. I was expecting that I could just set a socket factory for a HttpClient instance, but it is obviously not so easy.
The documentation for HttpComponents at http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html does mention socket factories, but does not say how to use them.
Does anybody know how this is done?
oleg's answer is of course correct, I just wanted to put the information directly here, in case the link goes bad. In the code that creates a HttpClient, I use this code to let it use my socket factory:
CustomSocketFactory socketFactory = new CustomSocketFactory();
Scheme scheme = new Scheme("http", 80, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(scheme);
CustomSocketFactory is my own socket factory, and I want to use it for normal HTTP traffic, that's why I use "http" and 80 as parameters.
My CustomSchemeSocketFactory looks similar to this:
public class CustomSchemeSocketFactory implements SchemeSocketFactory {
#Override
public Socket connectSocket( Socket socket, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpParams params ) throws IOException, UnknownHostException, ConnectTimeoutException {
if (localAddress != null) {
socket.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
socket.bind(localAddress);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
try {
socket.setSoTimeout(soTimeout);
socket.connect(remoteAddress, connTimeout );
} catch (SocketTimeoutException ex) {
throw new ConnectTimeoutException("Connect to " + remoteAddress + " timed out");
}
return socket;
}
#Override
public Socket createSocket( HttpParams params ) throws IOException {
// create my own socket and return it
}
#Override
public boolean isSecure( Socket socket ) throws IllegalArgumentException {
return false;
}
}
We use a custom socket factory to allow HttpClient connections to connect to HTTPS URLs with untrusted certificates.
Here is how we did it:
We adapted implementations of both the 'EasySSLProtocolSocketFactory' and 'EasyX509TrustManager' classes from the examples source directory referenced by Oleg.
In our HttpClient startup code, we do the following to enable the new socket factory:
HttpClient httpClient = new HttpClient();
Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", easyhttps);
So that any time we request an https:// URL, this socket factory is used.

Categories