Using java class HttpsURLConnection - java

I have a small piece of code which basically impements a HTTP-Client,
i.e. it POSTS request and works with re RESPONSE. As long as HTTP is
concenerned everthing work well. For some reason I now have to support
HTTPS too. So here is briefly what I do in order to get a connection opened:
URL url = new URL(serverAddress);
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
This fails, stating:
sun.net.www.protocol.https.HttpsURLConnectionImpl cannot be cast to com.sun.net.ssl.HttpsURLConnection
I guess this is kinda trivial, but I just don't get what I'm doing wrong in this one...
Googled it, and the code just looks right - not?
any ideas are appreciated!

Just keep it java.net.URLConnection or cast it to java.net.HttpURLConnection instead. Both offers methods to do the desired task as good.
A side remark unrelated to the technical problem: you should never explicitly import/use Sun Java SE implementation specific classes in your code. Those are undocumented classes and are subject to changes which may cause your code break when you upgrade the JVM. On the other hand, your code may also break when you run it at a different brand JVM.
Update: since you seem to accidentally have imported it, go to Window > Preferences > Java > Appearance > Type Filters and Add com.sun.* and sun.* to the list. This way you won't ever import them accidentally:

Your url's protocol should also be https and not http. Check your url.

The above problem is only caused by two issues
Using wrong import
Using http in the string you create url from use instead https

Instead of creating a URL object using standard constructor like
URL wsURL = new URL(url);
Use
java.net.URL wsURL = new URL(null, url,new sun.net.www.protocol.https.Handler());
which would solve this problem

Check your imports, you should be using
java.net.HttpURLConnection
or
javax.net.ssl.HttpsURLConnection

Check value of your "serverAddress" variable. It should https and not http

Change:
import javax.net.ssl.HttpsURLConnection;
and
URL url = new URL(serverAddress);
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
Change To:
import java.net.HttpURLConnection;
and
URL url = new URL(serverAddress);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();

Hard to tell without seeing the whole file, but it looks like you're importing com.sun.net.ssl.HttpsURLConnection when you really want javax.net.ssl.HttpsURLConnection.

In my case, the protocol and port were not correct while invoking the httpsUrlConnection.
Port and protocol were defined as static class variables. And the step prior to the failed step, was invoking an httpUrlConnection. That method changed the port/protocol to 80/http, but didn't set it back to /https at the end. So eventhough httpsUrlConnection was invoked, it was still using http/80. Once I reset those at the end of the httpUrlConnection method, the error disappeared.

Related

Calling Rest API in java from Hackerrank IDE

I was trying to call an api like below. It works in my IDE(Intellij), where as it fails in hackerrank IDE while getting input stream.
import java.io.*;
import java.util.*;
import java.net.*;
URL url = new URL("https://jsonmock.hackerrank.com/api/article_users?page=1");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.addRequestProperty("Content-Type", "application/json");
InputStream is = connection.getInputStream();
Getting an error:
error while calling: java.net.UnknownHostException: jsonmock.hackerrank.com
inside hacker rank IDE.
Please let me know your suggestions
just remove s from https
URL url = new URL("http://jsonmock.hackerrank.com/api/article_users?page=1");
Are you sure Hackerrank IDE has api call feature?
Perhaps for security or some other reason, this feature may be blocked or not supported.
It may be the case that Hackerrank does not let Java code make outbound network requests. Similar questions here and here suggest that you may need to choose a different language that Hackerrank supports. I imagine they should list it somewhere on their site, or on the IDE page directly.

HttpURLConnection with a non system-wide CookieHandler

I have a web application that makes HTTP requests using HttpURLConnection. I need it to handle cookies. I know that it's easily done by adding just one line of code, something like
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
The problem is this way I'm setting the system-wide cookie handler as the documentation describes. This also affects other web applications that run in the same servlet container. For example if I want CookiePolicy.ACCEPT_ORIGINAL_SERVER in one application and CookiePolicy.ACCEPT_ALL in another, it won't work.
Is there a way to have a CookieHandler that is only used by a single HttpURLConnection instance?
In standard oracle implementation the HttpURLConnection get the default CookieHandler on the constructor, so this is one possible solution. Create a synchronized singleton factory that create the HttpURLConnections using a specific manager for each application. Not good idea in my opinion.
Other bad idea is provide your own CookiePolicy and do the trick on the shouldAccept method.
Or you can manually control cookies on the app that should not share the CookieHandler:
HttpURLConnection firstCall = (HttpURLConnection) new URL("http://www.google.com").openConnection();
firstCall.connect();
List<HttpCookie> cookieList = HttpCookie.parse(firstCall.getHeaderField("Set-Cookie"));
firstCall.disconnect();
StringBuilder cookies = new StringBuilder();
for(HttpCookie cookie:cookieList) {
//if(cookie.SOME_VALIDATION) {
if(cookies.length() > 0) {
cookies.append("; ");
}
cookies.append(cookie.toString());
//}
}
HttpURLConnection secondCall = (HttpURLConnection) new URL("http://www.google.com").openConnection();
secondCall.setRequestProperty("Cookie", cookies.toString());
secondCall.connect();
//dosomething
secondCall.disconnect();

301/302 Redirect not working in Android (work differently in different versions)

When using a URLConnection, the 301 redirect doesn't work, doesn't even show a Location header, using getHeaderFields(). It is a blank list, except in newer Android (I tested 4.1 and it worked). It looks like something this has been reported in the default browser here as well, though in my test it worked in the Android browser. Is there some workaround for this bug in older Android?
I tried:
URLConnection conn = u.openConnection();
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
(conn).setInstanceFollowRedirects(true);
but it still returns an empty list, except in newer Android.
Update: It may be a related issue, it seems sometimes the URLConnection isn't even sending a request in some cases. (I checked with Wireshark on a pc with emulator). Is there a way to work-around this bug?
Update: I tried testing for 3xx redirect, redirects worked fine, but normal links didn't work with Ian's Cookie Manager. After making sure the setCookies was called directly after openConnection, it works great:
URL u = new URL(_url);
...
int tries = 4;
int code = 301;
URLConnection conn = null;
while (tries > 0 && code/100 == 3) {
conn = null;
conn = u.openConnection();
_CM.setCookies(conn);
((HttpURLConnection)conn).setInstanceFollowRedirects(false);//Required
code =((HttpURLConnection)conn).getResponseCode();
if (code/100 == 3) {
String loc = conn.getHeaderField("Location");
u = new URL(loc);
}
}
//conn.addRequestProperty("Accept-Encoding", "gzip");
conn.connect();
_CM.storeCookies(conn);
The really strange thing is, for newer Android (4.1 emulator) the FollowRedirect line (commented "Required") is not necessary. On older Android (2.2), it gives Connection Reset by Peer error. This was probably the reason my redirect experimental code was failing on 2.2, not 4.1. Any reason for the differences in functionality? According to comments here, redirection https apparently has different behavior depending on the JVM version, could it be that Android's URLConnection/HTTPUrlConnection has changed in different versions as well?
Not sure about URLConnection, but I know that HttpClient honors redirects and we use it all the way back to Android 2.1
http://developer.android.com/reference/org/apache/http/client/HttpClient.html
(Based on apache commons HttpClient)

Java HttpURLConnection class Program

I am learning Java through use of a textbook, which contains the following code describing the use of a HttpURLConnection ...
class HttpURLDemo {
public static void main(String args[]) throws Exception {
URL hp = new URL("http://www.google.com");
HttpURLConnection hpCon = (HttpURLConnection) hp.openConnection();
// Display request method.
System.out.println("Request method is " + hpCon.getRequestMethod());
}
}
Could someone please explain why the hpCon object is declared in the following way...
HttpURLConnection hpCon = (HttpURLConnection) hp.openConnection();
instead of declaring it like this...
HttpURLConnection hpCon = new HttpURLConnection();
The textbook author provided the following explanation, which I don't really understand...
Java provides a subclass of URLConnection that provides support for HTTP connections.
This class is called HttpURLConnection. You obtain an HttpURLConnection in the same
way just shown, by calling openConnection( ) on a URL object, but you must cast the result
to HttpURLConnection. (Of course, you must make sure that you are actually opening an
HTTP connection.) Once you have obtained a reference to an HttpURLConnection object,
you can use any of the methods inherited from URLConnection
The declaration that you don't understand why not to use:
HttpURLConnection hpCon = new HttpURLConnection();
Does not provide information about the URL to which you want to open the connection. This is the reason why you should use:
HttpURLConnection hpCon = new HttpURLConnection(hp);
Because this way the constructor knows that you want to open a connection to the url "http://www.google.com".
java.net.URLConnection is an abstract class that facilitates in communication with various types of servers via various protocols (ftp http etc).
The protocol specific subclasses are hidden inside SUN's packages and these hidden classes are responsible for the concrete implementation of the protocols.
In your example since your URL is a http://www.google.com by parsing the URL the internals of the URL class knows that an HTTP handler/subclass must be used.
So when you open a connection to the server hp.openConnection(); you get a concrete instance of a class that implements the HTTP protocol.
That class is an instance of HttpURLConnection (actually a subclass since HTTPURLConnection is also abstract and that is why you can do:
HttpURLConnection hpCon = (HttpURLConnection) hp.openConnection(); and not get class cast exception.
So with Java's design you can't do HttpURLConnection hpCon = new HttpURLConnection(hp); as you ask, since that is not how the designers want you to use these APIs.
You are expected to work arround URLs and URLConnections and only worry about input/output.
You shouldn't worry about the rest

Can I override the Host header where using java's HttpUrlConnection class?

I'm using the following code to open a http connection in java:
URL url = new URL("http://stackoverflow.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("GET");
conn.setRequestProperty("Host", "Test:8080");
conn.getOutputStream();
However calling conn.setRequestProperty("Host", "Test:8080") appears to have no effect regardless of what order I call the methods and the Host is reset to the destination server. Is there any way to override the Host header without using a different library?
TIA Matt
This used to work in the past, but it has been disabled as part of a security-fix. Apparently without a note in the changelog. There are even bugs like #7022056 for this at bugs.sun.com.
There is a similar question for another header, where the answer goes more into the details, so I just link it instead of writing it myself. :-)
The only workarounds seem to be setting sun.net.http.allowRestrictedHeaders to true or use another http-library like the already mentioned http components.
The Host header is filled by the HttpURLConnection based on the URL. You can't open foo.com with Host=bar.com. From the RFC
The Host request-header field specifies the Internet host and port number of the resource being requested, as obtained from the original URI given by the user or referring resource (generally an HTTP URL)
Btw, you can also try apache http components.
This is an issue with how volley handles HTTPUrlConnection and retry policy.
A Quick fix for it is to extend "HurlStack" class and override the "createConnection" function to return a HTTPUrlConnection with ChunkStreamMode of 0
public class CustomHurlStack extends HurlStack {
public CustomHurlStack(){
super();
}
#Override
protected HttpURLConnection createConnection(URL url) throws IOException {
HttpURLConnection connection = super.createConnection(url);
connection.setChunkedStreamingMode(0);
return connection;
}
}

Categories