HtmlUnit: Determine file size - java

I am downloading a file from the web via HtmlUnit.
This is what my (working) code looks like:
Page dlPage = client.getPage(url);
FileOutputStream fos = new FileOutputStream(destinationFile);
try
{
IOUtils.copy(dlPage.getWebResponse().getContentAsStream(), fos);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
fos.close();
}
I want to show the download progress. Therefore I need to know the file size. The Content-Length header is sent by the server but the problem is that I can read the headers after the file is downloaded. the getPage() method is blocking until the file is downloaded.
Is there any way to read just the response headers first in HtmlUnit and then the content? Or is there any other way to solve this problem?
Thanks!

You can use getContentLength() method of URLConnection to get the length when the connection is established.

Okay, I figured out a way to get this working: Before the download I send a HEAD request to the server so I can use the response to read the content length:
WebRequest wr = new WebRequest(new URL(url), HttpMethod.HEAD);
Page wrPage = client.getPage(wr);
long contentLength = Integer.valueOf(wrPage.getWebResponse().getResponseHeaderValue("Content-Length"));
System.out.println(contentLength);

Related

Is there a way to render a pdf document in thymeleaf, which is stored in a remote server and without downloading it?

I have to write an application to render PDF documents with Thymeleaf. These documents are stored in a remote server and are accesed through HTTP.
I know it is possible to render PDF documents, when they are stored in the project´s ressource folder. But I don`t want to download them.
Is there any possible way?
I am receiving the file with the following code:
URL url = new URL("http://10.139.1.240:8080/document.pdf");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection.getResponseCode() == 200) {
try (InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
BufferedReader br = new BufferedReader(streamReader);
Stream<String> lines = br.lines()) {
Desktop.getDesktop().browse(url.toURI());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
You could create a method in your controller that allows user to download that file as described in answer to this question, then on the client side, place an iframe pointing to that endpoint .:
<iframe sec="/controller_mapping/method_mapping"/>
You can control it's width and height using style tag.

How do I save a large file from a URL to the local

I have tried this below code which is working fine with the small size files.
URL url = new URL(downloadLink);
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
FileOutputStream fos = new FileOutputStream(newFile);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
If the file is a large file, it is giving an error like :
java.io.IOException:Server returned HTTP response code: 400 for URL:https://dl.dropboxusercontent.com/1/view/79q8i6f9zqx7y2w/Paragliding in Himalayas.avi
Can anyone help me.
The URL you're trying to download is invalid. URLs can't contain spaces. You need to URL encode it:
https://dl.dropboxusercontent.com/1/view/79q8i6f9zqx7y2w/Paragliding%20in%20Himalayas.avi
Have a look at: how do I encode a complete http url String correctly?, for an approach to encoding the URL. Unfortunately, just using URLEncoder.encode() won't cut it, since it encodes slashes, etc.
You can hand this task over to Os itself by using DownloadManager
private fun startDownload(url: String) {
val request = DownloadManager.Request(Uri.parse(url))
request.allowScanningByMediaScanner()
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, url.substring(url.lastIndexOf("/")))
val dm = activity!!.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
dm.enqueue(request)
Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show()
}

Sending in-memory generated .docx files from server to client with Spark

I am creating a web application using the Spark Java framework. The front-end is developed using AngularJS.
I want to generate a .docx file on the server (in-memory) and send this to the client for download.
To achieve this I created an angular service with the following function being called after the user clicks on a download button:
functions.generateWord = function () {
$http.post('/api/v1/surveys/genword', data.currentSurvey).success(function (response) {
var element = angular.element('<a/>');
element.attr({
href: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document' + response,
target: '_blank',
download: 'test.docx'
})[0].click();
});
};
On the server, this api call gets forwarded to the following method:
public Response exportToWord(Response response) {
try {
File file = new File("src/main/resources/template.docx");
FileInputStream inputStream = new FileInputStream(file);
byte byteStream[] = new byte[(int)file.length()];
inputStream.read(byteStream);
response.raw().setContentType("data:attachment;chatset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.raw().setContentLength((int) file.length());
response.raw().getOutputStream().write(byteStream);
response.raw().getOutputStream().flush();
response.raw().getOutputStream().close();
return response;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I have tried to solve this in MANY different ways and I always end up with a corrupted 'test.docx' that looks like this:
Solved it by using blobs and specifying the response type as 'arraybuffer' in the $http.post api call. The only bad thing with this solution (as far as I know) is that it doesn't play well with IE, but that's a problem for another day.
functions.generateWord = function () {
$http.post('/api/v1/surveys/genword', data.currentSurvey, {responseType: 'arraybuffer'})
.success(function (response) {
var blob = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var element = angular.element('<a/>');
element.attr({
href: url,
target: '_blank',
download: 'survey.docx'
})[0].click();
});
};
I think what went wrong was that the byte stream got encoded as plain text when I tried to create a URL with:
href: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document' + response
thus corrupting it.
When using blobs instead, I get a "direct" link to the generated byte stream and no encoding is done on it since the response type is set to 'arraybuffer'.
Note that this is just my own reasoning of why things went wrong with the original code. I might be terribly wrong, so feel free to correct me if that's the case.

JSoup BodyAsBytes connection to FileOutputStream to save temp file doesn't work?

I used JSoup to parse a website with cookies. I want to download a file from the website using JSoup and the cookies which were saved in a hashmap using this piece of code:
Connection.Response res = Jsoup.connect("http://www.webpage.com/downloadpage).execute();
Map<String, String> cookies = res.cookies();
So when I try to download the file, I use this:
downloadFile(Jsoup.connect("http://www.webpage.com/file.ext).cookies(cookies).ignoreContentType(true).execute().bodyAsBytes());
and
private void downloadFile(byte[] fileByteArray) {
try {
File temprFile = File.createTempFile("tempfile", "ext", getCacheDir());
temprFile.deleteOnExit();
FileOutputStream fos = new FileOutputStream(temprFile);
fos.write(fileByteArray);
fos.close();
} catch (MalformedURLException e){
e.printStackTrace();
} catch (IOException ex) {
String s = ex.toString();
ex.printStackTrace();
}
}
The program runs without errors, but when I try to open the temporary file, it appears the file isn't complete. Each time, exactly 1.408.576 bytes are downloaded. For example when I download an mp3-file this way, the temporary file contains only 40 seconds of the original file. What am I missing here?
Help would be appreciated.
Thanks.
Guess I came to soon here to ask my question. Found the solution myself in the GitHub docs for JSoup. Thanks anyway for the responses!
https://github.com/jhy/jsoup/blob/master/src/main/java/org/jsoup/Connection.java
/**
* Set the maximum bytes to read from the (uncompressed) connection into the body, before the connection is closed,
* and the input truncated. The default maximum is 1MB. A max size of zero is treated as an infinite amount (bounded
* only by your patience and the memory available on your machine).
* #param bytes number of bytes to read from the input before truncating
* #return this Connection, for chaining
*/
public Connection maxBodySize(int bytes);
Thanks anyway!
I added 0 to maxBodySize(0) and got full video downloaded. example Jsoup.connect(url).maxBodySize(0).ignoreContentType(true).execute().bodyAsBytes()

sending video file to browser over websocket

I want to send a video file from a server written in java to a web browser client.
The socket connection works fine and I have no trouble sending text.
The library I'm using to make a socket server is this https://github.com/TooTallNate/Java-WebSocket
This is the code for sending the file
public void sendFile(WebSocket conn,String path)
{
try
{
File file = new File(path);
byte[] data = new byte[(int)file.length()];
DataInputStream stream = new DataInputStream(new FileInputStream(file));
stream.readFully(data);
stream.close();
conn.send(data);
..snip catch statements..
Here is my javascript code for catching the file
function connect()
{
conn = new WebSocket('ws://localhost:8887');
conn.onopen = function(){alert("Connection Open");};
conn.onmessage = function(evt){if(evt.data instanceof Blob){readFile(evt);}else{alert(evt.data);}};
conn.onclose = function(){alert('connection closed');};
}
function readFile(file_data)
{
var video = document.getElementById('area');
video.src = window.URL.createObjectURL(file_data.data);
}
..skip to html element for playing the file..
<video id='area' controls="controls"></video>
I want to be able to receive the file in the browser and play it.
The error I get while trying to send a webm video file to fireox is:
HTTP "Content-Type" of "application/octet-stream" is not supported. Load of media resource blob:794345a5-4b6d-4585-b92b-3acb51612a6c failed.
Is it possible to receive a video file from a websocket and play it?
Am I implementing something wrong?
Video element requires right content-type, ws Blob comes with generic one, and it seems (to me) there is no way to set it serverside or clientside.
Fortunately, Blob has slice(start, end, contentType) method:
var rightBlob = originalBlob.slice(0, originalBlob.size, 'video/webm')

Categories