Java HttpURLConnection class Program - java

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

Related

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();

Set new object equal to otherObject.method()?

I'm learning java and come across something which confuses me quite a bit. I'm watching a video on an explanation of how http requests work...
URL theURL = new URL("http://www.google.com");
**URLConnection theConn = theURL.openConnection();**
I understand the first line in that it is just creating a URL object with an actual url as an argument. But I don't understand how in the second line, a URLConnection object is being created and being set equal to a method of the other object, or is that method returning something?
The method is returning a URLConnection as documented by the URL.openConnection() Javadoc which says (in part)
Returns a URLConnection instance that represents a connection to the remote object referred to by the URL.

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;
}
}

Using java class HttpsURLConnection

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.

Does new URL(...).openConnection() necessarily imply a POST?

If I create an HTTP java.net.URL and then call openConnection() on it, does it necessarily imply that an HTTP post is going to happen? I know that openStream() implies a GET. If so, how do you perform one of the other HTTP verbs without having to work with the raw socket layer?
If you retrieve the URLConnection object using openConnection() it doesn't actually start communicating with the server. That doesn't happen until you get the stream from the URLConnection(). When you first get the connection you can add/change headers and other connection properties before actually opening it.
URLConnection's life cycle is a bit odd. It doesn't send the headers to the server until you've gotten one of the streams. If you just get the input stream then I believe it does a GET, sends the headers, then lets you read the output. If you get the output stream then I believe it sends it as a POST, as it assumes you'll be writing data to it (You may need to call setDoOutput(true) for the output stream to work). As soon as you get the input stream the output stream is closed and it waits for the response from the server.
For example, this should do a POST:
URL myURL = new URL("http://example.com/my/path");
URLConnection conn = myURL.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
OutputStream os = conn.getOutputStream();
os.write("Hi there!");
os.close();
InputStream is = conn.getInputStream();
// read stuff here
While this would do a GET:
URL myURL = new URL("http://example.com/my/path");
URLConnection conn = myURL.openConnection();
conn.setDoOutput(false);
conn.setDoInput(true);
InputStream is = conn.getInputStream();
// read stuff here
URLConnection will also do other weird things. If the server specifies a content length then URLConnection will keep the underlying input stream open until it receives that much data, even if you explicitly close it. This caused a lot of problems for us as it made shutting our client down cleanly a bit hard, as the URLConnection would keep the network connection open. This probably probably exists even if you just use getStream() though.
No it does not. But if the protocol of the URL is HTTP, you'll get a HttpURLConnection as a return object. This class has a setRequestMethod method to specify which HTTP method you want to use.
If you want to do more sophisticated stuff you're probably better off using a library like Jakarta HttpClient.

Categories