I want to know that if the website content change during SSL handshake or TCP handshake what happen?
For example:
The TCP or SSL handshake start exactly at 16:02:00 o'clock between the client and server.And some reason the handshake take a long time.Let's say 5 seconds.
So handshake finish at 16:02:05 with some latency but succesfully.And client start to the take content.
But if the site content change while ssl handshake.For example if it change at 16:02:03 what happen?
Let's say at 16:02:00 the site content is: "ABCD" (when ssl or tcp handshake start)
And at 16:02:03 it changes to: "ABCD1234"(while handshake continue)
So the client get which one of them; "ABCD" or "ABCD1234" ?
And here is the my client side java code for get the server response:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
URL obj = new URL(url); // url is https
HttpURLConnection con = (HttpURLConnection) obj.openConnection(proxy);
con.setConnectTimeout(10000);
con.setReadTimeout(15000);
int responseCode = con.getResponseCode();
InputStream is = con.getInputStream();
The server sends the response which is current at the time it opens the response file (or wherever it gets the response from). The full URL is only known after the server received the HTTP request. This request is only done after the SSL handshake inside the established SSL tunnel. Thus it will not serve the version from before the handshake.
Your code included in your post doesn't use clearly SSL, but with SSL, handshake must be done before anything else. No content will be downloaded before handshake is done (and valid) because no request can be done before that. Handskake must be finished to encode and decode correctly the request.
Related
I have a problem with HTTP digest authentication on a Java client. I'm running a Web Service (SOAP) client on Wildfly, but the same problem occurs if I use URL.openConnection(), ie. the failing part is the underlying sun.net.www.protocol.http.HttpURLConnection and its authentication handling. I'm setting the credentials through java.net.Authenticator.
java.net.Authenticator.setDefault(new java.net.Authenticator() {
#Override
protected java.net.PasswordAuthentication getPasswordAuthentication() {
return new java.net.PasswordAuthentication("username", "password");
}
});
URL url = new URL(requestUri);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
conn.setRequestMethod("GET");
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while (rd.readLine() != null) { }
rd.close();
All is running well initially, but after a couple of weeks, all the HTTP calls gets response '400 Bad request' from the server. If I restart the JVM all the calls work again. The only thing I can think of is that the server thinks that there is something wrong with the digest auth (such as an incorrect nonce counter) and responds with HTTP 400. HttpURLConnection (or actually Authenticator?) does not understand HTTP 400 as failed authentication and continues to use the same auth tokens. After restarting JVM the calls naturally request new server nonce and starts nonce counter from 0, and everything works again.
Is there something I can do? Is there something I'm doing wrong? Can I somehow force the underlying JRE implementation to either understand HTTP 400 as failed authentication or to force the client to request new server nonce for all requests?
The server I'm making the request to is MS Dynamics NAV. Another section of my app is making similar HTTP requests to the same server but using the Apache HTTP Client, and there are no problems whatsoever.
Update:
I'm running Oracle's Server JRE 8u152
I am attempting to connect to an HTTPS endpoint in Java. Every method I have tried (more details below) ends up generating this stack trace:
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:753)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
I have tried:
Connecting with the javax SOAP libs and a new URL("https://...")
Connecting with new URL("https://...").openConnection()
Creating an SSL connection by hand:
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("...", 443);
Writer out = new OutputStreamWriter(socket.getOutputStream());
// https requires the full URL in the GET line
//
out.write("GET / HTTP/1.0\r\n");
out.write("\r\n");
out.flush();
// read response
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
int c;
while ((c = in.read()) != -1) {
System.out.write(c);
}
out.close();
in.close();
socket.close();
A few more details:
Every method I have tried has worked against other SSL servers, it's this particular server (I am not at liberty to discuss what server, it's a business partner)
I can connect to this server both with a web browser, and with a faked up SOAP request with curl; This is something Java-specific.
So, it seems pretty clear that there is some disagreement between Java and the HTTPS server over how the handshake should go down, which probably means the server has some strange SSL configuration. However, I don't have direct access to the server, and the people who do are halfway around the world, so communication is a little strained due to very different timezones.
If my assumptions there are correct, what possible SSL problems could there be? What might cause something like this? Where can I ask the people in control of the server to look for issues? When I do the request with curl, I get back these server configuration headers:
Server: Apache/2.2.9 (Debian) mod_jk/1.2.26 PHP/5.2.6-1+lenny10 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8g mod_perl/2.0.4 Perl/v5.10.0
X-Powered-By: PHP/5.2.6-1+lenny10
X-SOAP-Server: NuSOAP/0.7.3 (1.114)
It is an SSL version problem. The server only supports SSLv3, and Java will start at v2, and attempt to negotiate upwards, but not all servers support that type of negotiation.
Forcing java to use SSLv3 only is the only solution I'm aware of.
Edit, there are two ways to do this that I'm aware of:
If you are creating the socket by hand, you can set the enabled protocols
socket.setEnabledProtocols(new String[] { "SSLv3" });
If you are using a higher level library, you probably need to set all SSL requests to use v3 only, which is accomplished with the "https.protocols" system property:
java -Dhttps.protocols=SSLv3
Maybe also try setting the HTTP version to 1.1 instead of 1.0, as there's some real advantages to the newer standard.
The query I have has something do with an implementation I`m doing.
When a HTTP request is sent from the client Port to the Server Port, I understand that
the response is also sent back to the same port(Port to Port communication).
In my case, the server is forwarding the response to a URL with Query String to a host server on our network. So what I get when reading the response using the InputStream of the URLConnection object is the HTML content corresponding to the Login page of the forwarded URL with no query string.
I suspect this is because the URL is modified by our host server.
Now the question is, in this scenario there seems to be an intermediate entity which is the our host server to which URL is forwarded. So, when I read the response(URL forwarded by server) back in the InputStream, I`m not sure which of the following 2 is the actual scenario happening:
1.) Response is directly read from the external Server(as this is a Port to Port communication)
OR
2.)Response received from the intermediate Host Server which sees to be the case.
(If the 2nd scenario is correct, would the intermediate host server know which client to correctly forward the response to?)
URL url = new URL(httpsURL);
HttpsURLConnection urlConnection = (HttpsURLConnection) url
.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
///
Omitting code for SSL
///
String urlParameters = "CCNumber=4111111111111111";
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
BufferedReader in = new BufferedReader(new InputStreamReader(
urlConnection.getInputStream()));
String inputLine;
if (urlConnection.getResponseCode() == HttpsURLConnection.HTTP_OK){
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
}
You receive the response from the intermediate server.
It sounds like your intermediate server acts as a (reverse) proxy server. When you make a request to your intermediate server, it in turn makes a request to the server on your network (just as you described it). However, the "real" server has usually no idea that the request was initiated by you. In particular, it does not know your IP address or the port you sent your request from. The only thing it does know is the IP address and port of the intermediate (the proxy) server. The proxy server on the other hand still knows the IP address and port from which you sent your request.
So you send your request to the proxy, the proxy sends it to the "real" server, the real server sends its response back to the proxy, which sends it back to you. You and the "real" server do not communicate directly with each other.
I wrote some simple code in Java, the method should connect to the website and return the BufferedReader.
private BufferedReader getConnection(String url_a) {
URL url;
try {
System.out.println("getting connection");
url = new URL(url_a);
HttpURLConnection urlConnection = (HttpURLConnection)
url.openConnection();
urlConnection.addRequestProperty("User-Agent",
"Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924"
+ "Epiphany/1.4.4 (Ubuntu)");
inStream = new InputStreamReader(urlConnection.getInputStream());
return new BufferedReader(inStream);
} catch (Exception ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
When I use it on my PC, it works fine but when I put .jar file on the server I get this error:
java.net.SocketException: Unexpected end of file from server
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:718)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:579)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:715)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:579)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1322)
at dataconverter.Reader.getConnection(Reader.java.260)
Problem is quite strange because the exception isn't thrown each time, sometimes everything is OK and program works fine.
Has anybody got any ideas?
"Unexpected end of file" implies that the remote server accepted and closed the connection without sending a response. It's possible that the remote system is too busy to handle the request, or that there's a network bug that randomly drops connections.
It's also possible there is a bug in the server: something in the request causes an internal error, and the server simply closes the connection instead of sending a HTTP error response like it should. Several people suggest this is caused by missing headers or invalid header values in the request.
With the information available it's impossible to say what's going wrong. If you have access to the servers in question you can use packet sniffing tools to find what exactly is sent and received, and look at logs to of the server process to see if there are any error messages.
Summary
This exception is encountered when you are expecting a response, but the socket has been abruptly closed.
Detailed Explanation
Java's HTTPClient, found here, throws a SocketException with message "Unexpected end of file from server" in a very specific circumstance.
After making a request, HTTPClient gets an InputStream tied to the socket associated with the request. It then polls that InputStream repeatedly until it either:
Finds the string "HTTP/1."
The end of the InputStream is reached before 8 characters are read
Finds a string other than "HTTP/1."
In case of number 2, HTTPClient will throw this SocketException if any of the following are true:
The HTTP method is CONNECT
The HTTP method is POST and the client is set to streaming mode
Why would this happen
This indicates that the TCP socket has been closed before the server was able to send a response. This could happen for any number of reasons, but some possibilities are:
Network connection was lost
The server decided to close the connection
Something in between the client and the server (nginx, router, etc) terminated the request
Note: When Nginx reloads its config, it forcefully closes any in-flight HTTP Keep-Alive connections (even POSTs), causing this exact error.
I do get this error when I do not set the Authentication header or I set wrong credentials.
I would suggest using wire shark to trace packets. If you are using Ubuntu, sudo-apt get wireshark. Like Joni stated the only way to figure out whats going wrong is to follow the GET requests and their associated responses.
http://www.wireshark.org/download.html
In my case it was solved just passing proxy to connection. Thanks to #Andreas Panagiotidis.
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("<YOUR.HOST>", 80)));
HttpsURLConnection con = (HttpsURLConnection) url.openConnection(proxy);
In my case url contained wrong chars like spaces . Overall log your url and in some cases use browser.
Most likely the headers you are setting is incorrect or not acceptable.
Example:
connnection.setRequestProperty("content-type", "application/json");
I got this exception too. MY error code is below
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(requestMethod);
connection.setRequestProperty("Content-type", "JSON");
I found "Content-type" should not be "JSON",is wrong!
I solved this exception by update this line to below
connection.setRequestProperty("Content-type", "application/json");
you can check up your "Content-type"
I am attempting to connect to an HTTPS endpoint in Java. Every method I have tried (more details below) ends up generating this stack trace:
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:753)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
I have tried:
Connecting with the javax SOAP libs and a new URL("https://...")
Connecting with new URL("https://...").openConnection()
Creating an SSL connection by hand:
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("...", 443);
Writer out = new OutputStreamWriter(socket.getOutputStream());
// https requires the full URL in the GET line
//
out.write("GET / HTTP/1.0\r\n");
out.write("\r\n");
out.flush();
// read response
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
int c;
while ((c = in.read()) != -1) {
System.out.write(c);
}
out.close();
in.close();
socket.close();
A few more details:
Every method I have tried has worked against other SSL servers, it's this particular server (I am not at liberty to discuss what server, it's a business partner)
I can connect to this server both with a web browser, and with a faked up SOAP request with curl; This is something Java-specific.
So, it seems pretty clear that there is some disagreement between Java and the HTTPS server over how the handshake should go down, which probably means the server has some strange SSL configuration. However, I don't have direct access to the server, and the people who do are halfway around the world, so communication is a little strained due to very different timezones.
If my assumptions there are correct, what possible SSL problems could there be? What might cause something like this? Where can I ask the people in control of the server to look for issues? When I do the request with curl, I get back these server configuration headers:
Server: Apache/2.2.9 (Debian) mod_jk/1.2.26 PHP/5.2.6-1+lenny10 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8g mod_perl/2.0.4 Perl/v5.10.0
X-Powered-By: PHP/5.2.6-1+lenny10
X-SOAP-Server: NuSOAP/0.7.3 (1.114)
It is an SSL version problem. The server only supports SSLv3, and Java will start at v2, and attempt to negotiate upwards, but not all servers support that type of negotiation.
Forcing java to use SSLv3 only is the only solution I'm aware of.
Edit, there are two ways to do this that I'm aware of:
If you are creating the socket by hand, you can set the enabled protocols
socket.setEnabledProtocols(new String[] { "SSLv3" });
If you are using a higher level library, you probably need to set all SSL requests to use v3 only, which is accomplished with the "https.protocols" system property:
java -Dhttps.protocols=SSLv3
Maybe also try setting the HTTP version to 1.1 instead of 1.0, as there's some real advantages to the newer standard.