urlconnection not reading content-length - java

When opening a URLConnection I use the following code in order to get the content length, however it returns -1.
URL url = new URL(sUrl[0]);
URLConnection connection = url.openConnection();
connection.connect();
int fileLength = connection.getContentLength();
I presumed then that the server was not setting a content-length header (and a dig in the connection object confirms the value is -1), and so set one myself using the following in PHP:
header('Content-Length: '.strlen($output));
When I print out the value of strlen($output) I get the correct value, but this header does not seem to make it to Java.
Any suggestions or further code required?
Thanks

If the content length header is indeed being sent back to you from the server you are connecting to, then the code you have will work. You can prove that by hitting a simple web service that does return Content-Length like in the following code:
URL url = new URL("http://freegeoip.net/json/199.201.1.200");
URLConnection connection = url.openConnection();
int fileLength = connection.getContentLength();
System.out.println(fileLength);
When you run this, you will see it print out a content length.

Turns out content-length should be ignored when transfer-encoding is set to chunked. It would appear that my web host, takes this one further and strips out the header completely even if I set it manually in PHP. Confirmed with Chrome's advanced REST app.

Related

JAVA POST request and then redirect to it?

What I need to do is send POST request to specific URL with two parameters and when the request is sent, I need to redirect user to that link so that he would be able to access functionality.
So far, what I have managed to do from various examples is this:
private void postRemoteAdvisoryLink() throws IOException {
URL obj = new URL(KdrmApplicationContext.getRemoteAdvisoryUrlPath());
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setConnectTimeout(60000);
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
// For post only - start
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
os.write(("?auth=ssor&TransportKey=" + ssorTransportKey).getBytes());
os.flush();
os.close();
int responseCode = con.getResponseCode();
}
The problem is that now I get connection time out when trying to execute OutputStream os = con.getOutputStream(); line. Also, I still have no idea how to redirect user when request is completed.
Any ideas?
Using the basic Java URL classes would require you to manually handle the details of HTTP protocol - it's better to use libraries like Apache Http Components, as they deal with the underlying protocols for you. Some examples including POST requests can be found on their website.
Given the original question, the Timeout is likely related to host not responding or your Java application being unable to connect to given URL (due to no proxy configuration for example).
If you want to redirect a request based on the answer, you need to check the response headers and http status - if the status is 302, then there should be a header called Location, which will contain the URL you should make another request to.
Before getting an OutputStream, also make sure to set the Content-Length header (and ideally the Content-Type header as well).

Android get an error when i try to setRequestProperty to HttpURLConnection

i'm wrote simple download manager and i'm trying to set RESUME for all downloads. after googleing for how to do that. i know must be setRequestProperty for connection, but my code does not work and i get this error:
FATAL EXCEPTION: Thread-882
java.lang.IllegalStateException: Cannot set request property after connection is made
at libcore.net.http.HttpURLConnectionImpl.setRequestProperty(HttpURLConnectionImpl.java:510)
My code is:
URL url = new URL(downloadPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
final int fileSize = connection.getContentLength();
File file = new File(filepath);
if (file.exists() && fileSize == file.length()) {
return;
} else if (file.exists()) {
connection.setRequestProperty("Range", "bytes="+(file.length())+"-");
}else
connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
how to resolve this problem and correctly set setRequestProperty to connection?
The problem is that you're calling connection.getContentLength() before you're calling setRequestProperty(). The content length is only available after you've made a request, at which point you can't set the request property...
It's not entirely clear what you're trying to do, but one option is to use a HEAD request just to get the content length, and then make a separate request if you need to get just a portion of the data. Be aware that it's possible that the content length will change between requests, of course.
However, I would actually suggest keeping more metadata somewhere in your download manager - so that when you first start downloading the data, you keep a record of the total size, so that you don't need to make the HEAD request when resuming - you can tell just from the local information whether or not you've already downloaded a file. (This has the same problem in terms of content changing, but that's a different matter.)
I had the same error than OP.
WHY
The problem is that when you try to set the params to the request to resume the download, you have to be disconnected from the Http.
The moment you invoke the method connection.getContentLenght(); what happens is that connection.connect(); so if you then try to set the properties to the connection you will get the error mentioned.
FIX
What I did was that I closed the connection to Http after I invoked the method long totalFileSize = connection.getContentLength();
connection.disconnect()//Disconnect from http
And after that you can set the the parameters you want to the connection and invoke connection.connect() whenever needed.
TIP
In my particular case I was trying to download a file and needed to support resumable downloads, so to do it what I did was:
Check if file exists.
If file exists then get the lenght of the file:
long bytesDownloaded = file.getLenght();
Use this lenght to set it to the connection so it can resume from exactly the bytes it was paused.
Write the bytes to the end of the file.
You should set properties before getContentLength()
If you set range equal to exist file length you will receive remain bytes when call getContentLength() so if content length was equal to "0" that means that file downloaded completely.
But if you want to build a download manager, #Jon Skeet's method is reasonable.
Edit:
public abstract long getContentLength ()
Added in API level 1 Tells the length of the content, if known.
Returns the number of bytes of the content, or a negative number if
unknown. If the content length is known but exceeds Long.MAX_VALUE, a
negative number is returned.

How can I read a text file from the internet with Java?

I want to read the second line of the text at this URL: "http://vuln2014.picoctf.com:51818/" (this is a capture-the-flag competition but only asking for flags or direction to flags breaks the competition rules). I am attempting to open an input stream from the URL but I get an Invalid HTTP Response exception. Any help is appreciated, and I recognize that my error is likely quite foolish.
Code:
URL url = new URL("http://vuln2014.picoctf.com:51818");
URLConnection con = url.openConnection();
InputStream is = con.getInputStream()
The error occurs at the third line.
java.io.IOException: Invalid Http response at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1342) at name.main(name.java:41)
curl happily gets the text from the page, and it is perfectly accessible from a web browser.
When you do this:
URL url = new URL("http://vuln2014.picoctf.com:51818");
URLConnection con = url.openConnection();
You are entering into a contract that says that this URL uses the http protocol. When you call openConnection it expects to get http responses because you used http:// in the URL as the protocol. The Java Documentation says:
If for the URL's protocol (such as HTTP or JAR), there exists a public, specialized URLConnection subclass belonging to one of the following packages or one of their subpackages: java.lang, java.io, java.util, java.net, the connection returned will be of that subclass. For example, for HTTP an HttpURLConnection will be returned, and for JAR a JarURLConnection will be returned.
The server you are connecting to just returns a couple lines of data. I retrieved them with the command nc vuln2014.picoctf.com 51818. There is no http response code like HTTP/1.1 200 OK:
Welcome to the Daedalus Corp Spies RSA Key Generation Service. The public modulus you should use to send your updates is below. Remember to use exponent 65537.
b4ab920c4772c5247e7d89ec7570af7295f92e3b584fc1a1a5624d19ca07cd72ab4ab9c8ec58a63c09f382aa319fa5a714a46ffafcb6529026bbc058fc49fb1c29ae9f414db4aa609a5cab6ff5c7b4c4cfc7c18844f048e3899934999510b2fe25fcf8c572514dd2e14c6e19c4668d9ad82fe647cf9e700dcf6dc23496be30bb
In this case I would use java.net.Socket to establish a connection and then read the lines. This is a simplistic approach that assumes there are 2 lines of data:
Socket theSocket;
try {
theSocket = new Socket("vuln2014.picoctf.com", 51818);
BufferedReader inFile = new BufferedReader(new InputStreamReader(theSocket.getInputStream()));
String strGreet = inFile.readLine();
String strData = inFile.readLine();
} catch (IOException e) {
e.printStackTrace();
}
As for why curl and browsers may render it properly? They are likely more lenient about the data they read and will just dump what is read from the port even if it doesn't conform to the specified protocol (like http)

To read a header of a remote file, it is necessary to process the full file?

I have a webservice that returns resources, text or images.
I'm getting the header of these resources, and the problem is that when i get the header of a text, the header comes in miliseconds, but when i get the header of a image, the header takes two or three seconds to come.
¿Why is this possible? Is the java method getHeaderField processing the full object before returning the field of the header?
this is my sample code:
URLConnection connection;
URL url = new URL(this.url);
connection = url.openConnection();
String date = connection.getHeaderField("Last-Modified"));
use http HEAD not GET
You can set this by calling connection.setRequestMethod("HEAD") on your (HTTP)URLConnection object.
See
http://docs.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html#setRequestMethod(java.lang.String)

How i reset an URL connection

I use URL connection to download stream in the Internet. But after i reset the modem, i can't continue download this stream caz it error: Connection reset. How i solve it?
Here is my code:
URL url = new URL(_URL);
HttpURLConnection hUC = (HttpURLConnection) url.openConnection();
hUC.connect();
while (true) {
if ((_data.num = is.read(_data.b)) == -1) {
break;
}
//write to file
fos.write(_data.b, 0, _data.num);
}
You can't - at least, not how you may be expecting.
Instead, you need to handle your exception, and determine how much data you've already read. Once your Internet connection is re-established - assuming that the HTTP server you're downloading from supports requestable byte ranges - you can then set custom HTTP Headers on the request and re-download the remaining portions. (This will require a new HttpURLConnection.)
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 shows the related HTTP specifications involved to make this work.
This is a bit more complicated if you're looking for a "resume" type feature.
You would need to reissue the request once the internet comes back after a disconnect, and add a header to the request in order to resume the download at the byte number where you left off.
You need to set the Range property in the request header in order to specify how far in you're resuming. Then you would just continue to write to the "fos" object from there.
Check out this url: Java: resume Download in URLConnection

Categories

Resources