I read the data from BLOB in Oracle, then assign to an object as byte []. I know the data is UTF-8 encoded XML therefore create a big String from the raw byte array and write directly to the PrintWriter of the ServletResponse object.
The response is expected to be downloaded on the client browser side as an attachment. But
the downloaded file is corrupt, the encoding is not correctly set in my opinion. Should I not set the HTTP Headers explicitly? I cannot figure out why I cannot reconstruct the XML as it is in the Database. any idea?
String filename = data_src.getFilename() + ".xml";
byte [] data = data_src.getByte_data();
String xml_UTF_8 = new String(data, "UTF-8");
// Init Servlet Response.
response.reset();
response.setHeader("Content-Type", "application/xml;charset=utf-8");
response.setHeader("Content-Encoding", "UTF-8");
response.setHeader("Content-Length", "" + xml_UTF_8.length() /*data.length ???*/);
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); //inline vs attachment
PrintWriter writer = response.getWriter();
writer.write(xml_UTF_8);
writer.flush();
writer.close();
} finally {
// close streams.
response.flushBuffer();
}
// Inform JSF that it doesn't need to handle the response.
// This is very important, otherwise you will get the following exception in the logs:
// java.lang.IllegalStateException: Cannot forward after response has been committed.
facesContext.responseComplete();
}`
Related
I own a mock project maven spring-rest with the end point
#RequestMapping(value = "/rest/{nid}/{fileName:.+}", method = RequestMethod.GET, produces = MediaType.APPLICATION_PDF_VALUE)
public String getPjSae(#PathVariable String nid, #PathVariable String fileName, HttpServletResponse response) throws IOException {
LOGGER.info("NID : " + nid);
LOGGER.info("NOM FICHIER : " + fileName);
File file = new File(saePath+File.separatorChar + fileName);
LOGGER.info("CHEMIN PJ : " + file);
if (file.exists()) {
InputStream inputStream = new FileInputStream(file); //load the file
// here I use Commons IO API to copy this file to the response output stream, I don't know which API you use.
IOUtils.copy(inputStream, response.getOutputStream());
// here we define the content of this file to tell the browser how to handle it
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".pdf");
response.flushBuffer();
}
return response.getOutputStream().toString();
}
I get the downloaded file and convert it to base64 to write it to an XML file. I have to make the comparison later and the problem is the writing of the signature of the object in the byte stream of the base 64: CoyoteOutputStream
At the end of each base64 of pdf I have a piece:
CnN0YXJ0eHJlZgo0NjkyOAolJUVPRgpvcmcuYXBhY2hlLmNhdGFsaW5hLmNvbm5lY3Rvci5Db3lvdGVPdXRwdXRTdHJlYW1ANDA4YTViYzI=
that is different each time because:
startxref
46928
%% EOF
org.apache.catalina.connector.CoyoteOutputStream#408a5bc2
So, this pit but comparison because : #408a5bc2 is unique
You eventually return this:
return response.getOutputStream().toString();
This returns the default toString output for the output stream in question, i.e. your CoyoteOutputStream object signature. If you want to avoid this, don't return it.
I am currently implementing the WOPI with my application. Our domain is already whitelisted by Microsoft. While implementation I am currently facing two problems as mentioned below:
The exception is thrown when trying to validate content as JSON: 'Unexpected character encountered while parsing value.' I am sending my response "Value=application/octet-stream" but I don't understand why the server is trying to parse the stream as JSON.
After every new request coming from "iframe" is initiating a new session in the JAVA.
Here are more details:
My current URL is https://onenote.officeapps-df.live.com/hosting/WopiTestFrame.aspx?ui=en-US&rs=en-US&dchat=1&hid=26D7CA2A10F60A68720106BF599F84B9&&WOPISrc=https://domain/wopiEditor/files/73346e47-697b-11e6-a8bc-c26cd8f74b91/courses/independentConcepts/concept_adminGlo_5/assets/Setting url for static ip.docx&access_token=DEADBEEFDEADBEEFDEADBEEF&access_token_ttl=1532765580679
And My Java code is as following:
public void getFile(HttpServletRequest request, HttpServletResponse response, String name) {
Println.getInstance().log(request.getSession().getId() + "re" + request.getRequestURI());
InputStream fis = null;
OutputStream toClient = null;
try {
String path = getFilePath(request) + name;
File file = new File(path);
String filename = file.getName();
// XWPFDocument xDoc = new XWPFDocument(OPCPackage.open(fis));
fis = new BufferedInputStream(new FileInputStream(path));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
response.reset();
response.addHeader("Content-Disposition",
"attachment;filename=" + new String(filename.getBytes("utf-8"), "ISO-8859-1"));
response.addHeader("Content-Length", "" + file.length());
response.addHeader("Content-Type", "" + "application/octet-stream");
//Println.getInstance().log(file.length() + "l" + file);
toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
fis.close();
toClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The test frame image is attached
The error you are seeing is on the CheckFileInfo request which is supposed to be returned as JSON. The Java snippit that you provided is for the getFile request which is a separate call that is made from the Office Online server. You should look over https://wopi.readthedocs.io/projects/wopirest/en/latest/ for how to write your implementation.
One thought is maybe you need to set the Content-Type header more specifically instead of the application/octet-stream you are sending?
Also there are quite a lot of other header values you are supposed to be returning, some of them may matter as well:
https://wopi.readthedocs.io/projects/wopirest/en/latest/common_headers.html#common-headers
I am trying to download a zip file from a fixed location present in server.
In my Rest method , I am just passing the file name from client (browser) .
(Please see below code ).
In my Rest method I am sending the zip file to the client.
The file gets downloaded on the browser without any issue.
My Issue is that the zip file gets downloaded on browser without .zip extension.
#RequestMapping(value = "/zip/{filePath}", method = RequestMethod.GET)
public #ResponseBody void downloadZip(#PathVariable("filePath") String filePath, HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletContext context = request.getServletContext();
File downloadFile = new File(filePath);
FileInputStream inputStream = new FileInputStream(downloadFile);
// get output stream of the response
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[(int) downloadFile.length()];
int bytesRead = -1;
// write bytes read from the input stream into the output stream
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
// get MIME type of the file
String mimeType = context.getMimeType(fullPath);
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/octet-stream";
}
System.out.println("MIME type: " + mimeType);
// set content attributes for the response
response.setContentType(mimeType);
response.setContentLength((int) downloadFile.length());
response.setHeader("Content-Disposition",
String.format("attachment; filename=\"%s\"", downloadFile.getName()));
logger.error("Filename = " + downloadFile.getName());
inputStream.close();
outStream.close();
}
PS: The file gets downloaded on some machine with ZIP and in some machine without ZIP. I have tested only on chrome (as per client requirement).
I think, there is an issue with the Chrome settings which I need to look upon (just a guess).
Can someone help upon this?
Thanks in advance....
Change the order between setting the response headers and shoving the file down the output stream - after all, the headers need to leave first.
[Edited]
"Why setting HttpServletResponse in starting effects the code."
Well, simple: the client is supposed to receive instructions of what to do with the payload by interpreting the HTTP response headers. If those are not set in the beginning, sending those headers at the end of the transmission comes too late. And this assumes the HttpServletResponse will actually send those headers when invoked with setHeader, which is a big assumption - I suspect those headers will not actually be sent after calling response.getOutputStream - it is unlikely the response will buffer the entire payload to wait for the caller to specify those headers.
I have a use-case where I have to set "Content-type" and "content-disposition" after writing in http response outputstream instead of downloading as a file. Following sample code depicts the case :-
#Context
HttpServletResponse response;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String downloadFile() throws IOException {
File file = new File("/var/tmp/input.txt");
FileInputStream fs = new FileInputStream(file);
copyStream(fs, response.getOutputStream());
response.setContentType("text/csv");
response.setHeader("Content-Disposition","attachment;filename=\"" + "ts.csv" + "\"");
return "";
}
When I give a small input (input.txt file), my browser gives me option to download it but when the input is large, it prints the file content directly in the browser tab.
Any pointers what I can do such that it gives a file downoad option for large input as well?
As per documentation at ServletResponse.setContentType:
Sets the content type of the response being sent to the client, if the response has not been committed yet.
And, as per documentation at ServletResponse.getWriter:
Returns a PrintWriter object that can send character text to the client.
In your coding, you are writing content to the response object before setting the content-type.
You should have not written into the response output stream, for your custom content type to work.
Change your code:
copyStream(fs, response.getOutputStream());
response.setContentType( "text/csv" );
response.setHeader( "Content-Disposition",
"attachment;filename=\"" + "ts.csv" + "\"" );
To:
response.setContentType( "text/csv" );
response.setHeader( "Content-Disposition",
"attachment;filename=\"" + "ts.csv" + "\"" );
copyStream(fs, response.getOutputStream());
In order to upload a binary file to an URL, I have been advised to use this guide. However, the file is not in a directory, but is stored in a BLOB field in MySql db. The BLOB field is mapped as a byte[] property in JPA:
byte[] binaryFile;
I have slightly modified the code taken from the guide, in this way:
HttpURLConnection connection = (HttpURLConnection ) new URL(url).openConnection();
// set some connection properties
OutputStream output = connection.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, CHARSET), true);
// set some headers with writer
InputStream file = new ByteArrayInputStream(myEntity.getBinaryFile());
System.out.println("Size: " + file.available());
try {
byte[] buffer = new byte[4096];
int length;
while ((length = file.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
writer.append(CRLF).flush();
writer.append("--" + boundary + "--").append(CRLF).flush();
}
// catch and close streams
I am not using chunked streaming. The headers used are:
username and password
Content-Disposition: form-data; name=\"file\"; filename=\"myFileName\"\r\nContent-Type: application/octet-stream"
Content-Transfer-Encoding: binary
All the headers are received correctly by the host. It also receives the uploaded file, but unfortunately complains that the file is not readable, and asserts that the size of the received file is 37 bytes larger than the size outputed by my code.
My knowledge of streams, connections and byte[] is too limited for grasping the way to fix this. Any hints appreciated.
EDIT
As suggested by the commenter, I have tried also to write the byte[] directly, without using the ByteArrayInputStream:
output.write(myEntity.getBinaryFile());
Unfortunately the host gives exactly the same answer as the other way.
My code was correct.
The host was giving an error because it didn't expect the Content-Transfer-Encoding header. After removing it, everything went fine.