I have a servlet which just read a file and send it to the browser.
The file is readen correctly, but on OutputStream.flush(), the browser receive no data.
Firefox says :
"Corrupted Content Error
The page you are trying to view cannot be shown because an error in the data transmission was detected.". Firebug shows the status "Aborted".
IE open or save an empty file.
I tried little or big files.
The code is :
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Use a ServletOutputStream because we may pass binary information
response.reset();
OutputStream out = response.getOutputStream();
// Get the file to view
String file = request.getParameter("path");
// Get and set the type and size of the file
String contentType = getServletContext().getMimeType(file);
response.setContentType(contentType);
long fileSize = (new File(file)).length();
response.setHeader("Content-Length:", "" + fileSize);
File f = new File(file);
response.setHeader("Content-Disposition", "attachment;filename="+f.getName());
response.setContentLength((int) fileSize);
// Return the file
try {
returnFile(file, out, response);
} catch (Exception e) {
Logger.getLogger(AffichageItemsServlet.class).error("", e);
} finally {
out.close();
}
}
// Send the contents of the file to the output stream
public static void returnFile(String filename, OutputStream out, HttpServletResponse resp)
throws FileNotFoundException, IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(filename);
byte[] buff = new byte[8* 1024];
int nbRead = 0;
while ((nbRead = fis.read(buff, 0, buff.length)) !=-1) {
out.write(buff, 0, nbRead);
}
out.flush();
} finally {
if (fis != null) {
fis.close();
}
}
}
The response is sent on "out.flush".
Any idea ?
For one thing, remove this line (you call setContentLength() below that):
response.setHeader("Content-Length:", "" + fileSize);
Also, you might try moving the getOutputStream() call to just before you start using the stream.
Related
I have a web service app in Java and I'm trying to do an export functionality to export some data from the database to an excel file
For this I'm using HttpServletResponse, but even I set up a filename and a encoding type, the file exported is not using those.
I need to set up the name of the file with the corresponding export date and the encoding type to allow UTF-8 characters like á,ó,ñ, etc --> This was fixed, see Edit 1 below.
Below you have my code:
#RequestMapping(value = "/export", method = RequestMethod.GET)
public #ResponseBody
void export(HttpServletRequest request, HttpServletResponse r) {
Response response = new Response();
try {
response = service.export();
if(response.isSuccess()){
r.setHeader( "Content-Disposition","attachment; filename=export_20171216.xls");
r.setContentType("application/vnd.ms-excel");
r.setCharacterEncoding("UTF-8");
OutputStream out = r.getOutputStream();
byte[] buffer = new byte[4096];
int length;
while ((length = ((InputStream) response.getData()).read(buffer)) > 0){
out.write(buffer, 0, length);
}
out.flush();
out.close();
}
else{
r.sendError(801, response.toString());
}
} catch (Exception e) {
e.printStackTrace();;
}
}
As the result, I'm getting files with the name like 2ea4a24e-b0b4-4d50-9604-4fcdb3713b90.xls and inside the file words like: Número instead of Número
--- Edit 1
I fixed the stress vowels with the follwing code when creating the ByteArray
new ByteArrayInputStream(sb.toString().getBytes("ISO-8859-15"));
If I got your issue correctly you are trying to keep filenames with symbols that have to be encoded. According setHeaders method docs:
the header value If it contains octet string, it should be
* encoded according to RFC 2047
* (http://www.ietf.org/rfc/rfc2047.txt)
And more likely your input filenames are in ASCII that are octets. Try to use java.nio.charset.CharsetDecoder with appropriate decoding when you set header with your fancy symbols.
A bit more explanations: ISO-8859-15 is not Unicode format and any symbol above of it leads to encoding the whole string for HTTP attributes.
public static void sendResponse (InputStream inputData, String fileName, HttpServletResponse res)
throws IOException {
try {
String contenttype = new ConfigurableMimeFileTypeMap().getContentType(fileName);
res.reset();
res.setContentType(contenttype);
res.addHeader("Content-Disposition", String.format("attachment;filename=\"%s\"", name));
ByteStreams.copy(inputData, res.getOutputStream());
} catch (Exception e) {
throw new IOException(e);
}
}
Please try with this:-I have used this in my code it works..
Let me know if still problem perisists
public void downloadFile(String fileName, String paramName,
HttpServletResponse response) {
File fileToBeDownloaded = null;
InputStream fileInputStream = null;
ServletOutputStream servletOutputStream;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
response.addHeader("Content-Disposition", "attachment; filename=" +
fileName);
servletOutputStream = response.getOutputStream();
IOUtil.copyCompletely(fileInputStream, servletOutputStream);
servletOutputStream.flush();
servletOutputStream.close();
}
I Need to create a java proxyservlet that sends all incoming data (XML) to another Server.
But how do i post my incoming data to the remote Server?
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String server = "http://server.tld";
String subURI = request.getRequestURI().split("/ProxyServlet")[1];
System.out.println("ProxyServlet: " + server + subURI);
URL remoteServer = new URL(server + subURI);
HttpURLConnection connection = (HttpURLConnection) remoteServer.openConnection();
//somehow apply request to remoteServer and receive response
}
As simple as using CloseableHttpClient for newer as Java7 or using HttpClient for too old Java version?
Then read your OutPutStream into Byte Array and write to InputStream of CloseableHttpClient?
Finally i could solve it, with the help of this article:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String server = "http://server.tld";
String subURI = request.getRequestURI().split("/ProxyServlet")[1];
System.out.println("ProxyServlet: " + server + subURI);
URL remoteServerURL = new URL(server+subURI);
HttpURLConnection remoteServer = (HttpURLConnection) remoteServerURL.openConnection();
remoteServer.setRequestMethod("POST");
remoteServer.setDoOutput(true);
remoteServer.getOutputStream().write(readBytes(request.getInputStream()));
response.getOutputStream().write(readBytes(remoteServer.getInputStream()));
}
/**
* Read and return the entire contents of the supplied {#link InputStream stream}. This method always closes the stream when
* finished reading.
*
* #param stream the stream to the contents; may be null
* #return the contents, or an empty byte array if the supplied reader is null
* #throws IOException if there is an error reading the content
*/
private byte[] readBytes( InputStream stream ) throws IOException {
if (stream == null) return new byte[] {};
byte[] buffer = new byte[1024];
ByteArrayOutputStream output = new ByteArrayOutputStream();
boolean error = false;
try {
int numRead = 0;
while ((numRead = stream.read(buffer)) > -1) {
output.write(buffer, 0, numRead);
}
} catch (IOException e) {
error = true; // this error should be thrown, even if there is an error closing stream
throw e;
} catch (RuntimeException e) {
error = true; // this error should be thrown, even if there is an error closing stream
throw e;
} finally {
try {
stream.close();
} catch (IOException e) {
if (!error) throw e;
}
}
output.flush();
return output.toByteArray();
}
Well, i'm trying to use a FileServlet to download video from my webserver (Apache Tomcat), but this video BROKEN. I know that video is OK because if i download with FileZilla everything works fine.
See my class:
public class FileServlet extends HttpServlet {
// Constants
// ----------------------------------------------------------------------------------
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
// Properties
// ---------------------------------------------------------------------------------
private String filePath;
// Actions
// ------------------------------------------------------------------------------------
private static abstract class InnerFacesContext extends FacesContext {
protected static void setFacesContextAsCurrentInstance(
FacesContext facesContext) {
FacesContext.setCurrentInstance(facesContext);
}
private InnerFacesContext() {
}
}
public void init() throws ServletException {
// In a Windows environment with the Applicationserver running on the
// c: volume, the above path is exactly the same as "c:\files".
// In UNIX, it is just straightforward "/files".
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
this.filePath = getFacesContext(request, response).getExternalContext()
.getInitParameter("tmpDirectory");
// Get requested file by path info.
String requestedFile = request.getPathInfo();
// Check if file is actually supplied to the request URI.
if (requestedFile == null) {
// Do your thing if the file is not supplied to the request URI.
// Throw an exception, or send 404, or show default/warning page, or
// just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Decode the file name (might contain spaces and on) and prepare file
// object.
File file = new File(filePath, URLDecoder.decode(requestedFile, "UTF-8"));
// Check if file actually exists in filesystem.
if (!file.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning page, or
// just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Get content type by filename.
String contentType = getServletContext().getMimeType(file.getName());
// If content type is unknown, then set the default value.
// For all content types, see:
// http://www.w3schools.com/media/media_mimeref.asp
// To add new content types, add new mime-mapping entry in web.xml.
if (contentType == null) {
contentType = "application/octet-stream";
}
// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
// Open streams.
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
// Gently close streams.
close(output);
close(input);
}
}
// Helpers (can be refactored to public utility class)
// ----------------------------------------
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail
// it.
e.printStackTrace();
}
}
}
protected FacesContext getFacesContext(HttpServletRequest request,
HttpServletResponse response) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null) {
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder
.getFactory("javax.faces.context.FacesContextFactory");
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
.getFactory("javax.faces.lifecycle.LifecycleFactory");
javax.faces.lifecycle.Lifecycle lifecycle = lifecycleFactory
.getLifecycle("DEFAULT");
facesContext = contextFactory.getFacesContext(request.getSession()
.getServletContext(), request, response, lifecycle);
InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);
javax.faces.component.UIViewRoot view = facesContext
.getApplication().getViewHandler()
.createView(facesContext, "");
facesContext.setViewRoot(view);
}
return facesContext;
}
}
PS: This class if from BalusC blog.
i have implemented a servlet to download doc files available under my application classpath.
what happening is; file is downloading but ms-word is unable to open it property.
see the screenshot of ms-word:
Servlet implementation is as follows:
public class DownloadFileServlet extends HttpServlet {
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fileName = "test.doc";
ClassPathResource resource = new ClassPathResource(File.separator + fileName);
ServletOutputStream sos = null;
FileInputStream fis = null;
try {
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment; fileName=\"" + fileName + "\"" );
fis = new FileInputStream(new File(resource.getURI().getPath()));
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(fis);
sos = response.getOutputStream();
sos.write(bytes);
sos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if( fis != null) {
fis.close();
}
if( sos != null) {
sos.close();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
i have tried almost all suggested Content Types for ms-word files. but still it is not working.
application/msword
application/ms-word
application/vnd.ms-word
Kindly suggest I'm making a mistake or is there any other way to achieve.
Note: i have tried almost all approaches available on SO.
Instead of reading, converting to byte[] simply write directly to the OutputStream. You shouldn't close the OutputStream as that is being handled by the container for you.
I would rewrite your servlet method to more or less the following (also why is it a servlet and not a (#)Controller?
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fileName = "test.doc";
ClassPathResource resource = new ClassPathResource(File.separator + fileName);
InputStream input = resource.getInputStream();
try {
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment; fileName=\"" + fileName + "\"" );
org.springframework.util.StreamUtils.copy(input, response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOEXception ie) {}
}
}
}
i do not know what a ClassPathResource class does. hence modified the code a bit.
ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
InputStream is = clsLoader.getResourceAsStream("test.doc");
and in the try block use:
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(is);
this should work fine. i placed the doc in the classpath. modify it to suit your needs.
Regarding the mime mapping, open your server properties and you will find a list of mime mapping. Eg. in eclipse for tomcat, just double click on the server and you should be able to find the mime mapping list there. application/msword worked fine
I am tryig to make a song available for download on my website. I am using a download servlet that I have used before to make zip files available for download. I have run through the code and everything appears to be working, the output stream reads the entire file but the save dialog box does not appear. Any ideas? Thanks for your help. Code is as follows:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String song = request.getParameter("song");
StringBuilder filePath = new StringBuilder();
try {
Thread.sleep(1);
String[] info = getSongInfo(song);
filePath.append("D:\\My Music\\My Song.m4a");
File file = new File(filePath.toString());
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath());
}
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Type", "audio/mp4a-latm");
response.setHeader("Content-disposition", "attachment; filename="+song+".m4a");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[4096];
while (true) {
int length = bis.read(buf);
if (length == -1) {
break;
}
bos.write(buf, 0, length);
}
bos.flush();
bos.close();
bis.close();
} catch (InterruptedException e) {
System.err.println("Error message: " + e.getMessage());
}
}
Called using:
dojo.xhrGet(
{
url: "/downloadSong?song="+item.title[0]
});
You cannot download files by ajax. JavaScript has due to security reasons no facility to spawn a Save As dialogue nor to store them in disk. It will consume the response, but it can't do anything sensible with it.
You need to use window.location instead:
window.location = "/downloadSong?song=" + item.title[0];
Thanks to the Content-Disposition: attachment header, it won't affect the currently opened page.