In Groovy, how to properly get the file from HttpServletRequest - java

I am writing a REST API in Groovy script that will receive a file upload from client side.
The REST API will receive the file via HttpServletRequest.
I am trying to get the file from HttpServletRequest by getting its InputStream, then convert it to File to save to proper folder.
My code is as below:
RestApiResponse doHandle(HttpServletRequest request, RestApiResponseBuilder apiResponseBuilder, RestAPIContext context) {
InputStream inputStream = request.getInputStream()
def file = new File(tempFolder + "//" + fileName)
FileOutputStream outputStream = null
try
{
outputStream = new FileOutputStream(file, false)
int read;
byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
}
finally {
if (outputStream != null) {
outputStream.close();
}
}
inputStream.close();
// the rest of the code
}
The files are created, but all of them are corrupted.
When I try to open them with Notepad, all of them have, at the beginning, some thing similar to the below:
-----------------------------134303111730200325402357640857
Content-Disposition: form-data; name="pbUpload1"; filename="Book1.xlsx"
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Am I doing this wrong? How do I get the file correctly?

Found the solution with MultipartStream
import org.apache.commons.fileupload.MultipartStream
import org.apache.commons.io.FileUtils
InputStream inputStream = request.getInputStream()
//file << inputStream;
String fileName = "";
final String CD = "Content-Disposition: "
MultipartStream multipartStream = new MultipartStream(inputStream, boundary);
//Block below line because it always return false for some reason
// but should be used as stated in document
//boolean nextPart = multipartStream.skipPreamble();
//Block below line as in my case, the part I need is at the first part
// or maybe I should use it and break after successfully get the file name
//while(nextPart) {
String[] headers = multipartStream.readHeaders().split("\\r\\n")
ContentDisposition cd = null
for (String h in headers) {
if (h.startsWith(CD)) {
cd = new ContentDisposition(h.substring(CD.length()));
fileName = cd.getParameter("filename"); }
}
def file = new File(tempFolder + "//" + fileName)
ByteArrayOutputStream output = new ByteArrayOutputStream(1024)
try
{
multipartStream.readBodyData(output)
FileUtils.writeByteArrayToFile(file, output.toByteArray());
}
finally {
if (output != null) {
output.flush();
output.close();
}
}
inputStream.close();

Related

remove or not return BufferedOutputStream file in java

i would like not to download the BufferedOutputStream when return java method.
my code:
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
response.setHeader("Content-Disposition", "attachment; filename=\"" + "Invoice.zip\";");
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
ZipOutputStream zos = new ZipOutputStream(bos);
for(SalesEInvObject InvoiceObj : this.InvoiceTable){ // MAIN FOR-LOOP STARTS
if (InvoiceObj.getInvoiceNo() != null) {
javax.servlet.http.HttpSession httpSession =(javax.servlet.http.HttpSession) ctx.getExternalContext().getSession(false);
httpSession.setAttribute(BaseHttpServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE,
reportOutput.getInternalReportObject());
byte[] bytes = reportOutput.getReportOutputBytes();
int length = ((bytes == null) ? 0 : bytes.length);
response.setContentLength(length*tableSize);
final ZipEntry ze = new ZipEntry(reportOutputFileName+".pdf");
zos.putNextEntry(ze);
zos.write(bytes, 0, bytes.length);
zos.closeEntry();
}else {
return null;
}
}//LOOP ENDS
zos.close();
ctx.responseComplete();
my problem is when the invoices has Number it generates invoice and download in compressed zip file. but when it has no Number i dont want to download zip. but still zip file downloads but with empty no file in it.
if no pdf generated i dont want to download zip file.
any help...
Once you have started generating and writing the ZIP to the response output stream, there is no turning back. Just opening the stream causes the response to "commit" ... meaning that you can no longer change the response code or headers.
Basically, you need to check if there are any invoices before you start generating the response. Then it should just be a matter of reorganizing the existing code.
Something like .....
boolean hasInvoices = false;
for (SalesEInvObject invoiceObj : this.InvoiceTable) {
if (invoiceObj.getInvoiceNo() != null) {
hasInvoices = true;
break;
}
}
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletResponse response =
(HttpServletResponse) ctx.getExternalContext().getResponse();
if (hasInvoices) {
response.setHeader("Content-Disposition",
"attachment; filename=\"" + "Invoice.zip\";");
BufferedOutputStream bos =
new BufferedOutputStream(response.getOutputStream());
ZipOutputStream zos = new ZipOutputStream(bos);
for (SalesEInvObject invoiceObj : this.InvoiceTable) {
if (invoiceObj.getInvoiceNo() != null) {
javax.servlet.http.HttpSession httpSession =
(javax.servlet.http.HttpSession) ctx.getExternalContext()
.getSession(false);
httpSession.setAttribute(
BaseHttpServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE,
reportOutput.getInternalReportObject());
byte[] bytes = reportOutput.getReportOutputBytes();
int length = ((bytes == null) ? 0 : bytes.length);
response.setContentLength(length * tableSize);
final ZipEntry ze = new ZipEntry(reportOutputFileName + ".pdf");
zos.putNextEntry(ze);
zos.write(bytes, 0, bytes.length);
zos.closeEntry();
}
}
zos.close();
} else {
// do you want to set a response code or something?
}
ctx.responseComplete();
I have fixed some bad style. See if you can spot the changes ...
There is another problem that I haven't addressed: namely that the various resources that are opened in this code ought to be managed using try with resources. However, it may not be necessary since it looks like the resources are all based on with the request output stream. That will be closed automatically by the servlet infrastructure.

Blank pages in pdf after downloading it from web

I am trying to download a PDF file with HttpClient, it is downloading the PDF file but pages are blank. I can see the bytes on console from response if I print them. But when I try to write it to file it is producing a blank file.
FileUtils.writeByteArrayToFile(new File(outputFilePath), bytes);
However the file is showing correct size of 103KB and 297KB as expected but its just blank!!
I tried with Output stream as well like:
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
fileOutputStream.write(bytes);
Also tried to write with UTF-8 coding like:
Writer out = new BufferedWriter( new OutputStreamWriter(
new FileOutputStream(outFile), "UTF-8"));
String str = new String(bytes, StandardCharsets.UTF_8);
try {
out.write(str);
} finally {
out.close();
}
Nothing is working for me. Any suggestion is highly appreciated..
Update: I am using DefaultHttpClient.
HttpGet httpget = new HttpGet(targetURI);
HttpResponse response = null;
String htmlContents = null;
try {
httpget = new HttpGet(url);
response = httpclient.execute(httpget);
InputStreamReader dataStream=new InputStreamReader(response.getEntity().getContent());
byte[] bytes = IOUtils.toByteArray(dataStream);
...
You do
InputStreamReader dataStream=new InputStreamReader(response.getEntity().getContent());
byte[] bytes = IOUtils.toByteArray(dataStream);
As has already been mentioned in comments, using a Reader class can damage binary data, e.g. PDF files. Thus, you should not wrap your content in an InputStreamReader.
As your content can be used to construct an InputStreamReader, though, I assume response.getEntity().getContent() returns an InputStream. Such an InputStream usually can be directly used as IOUtils.toByteArray argument.
So:
InputStream dataStream=response.getEntity().getContent();
byte[] bytes = IOUtils.toByteArray(dataStream);
should already work for you!
Here is a method I use to download a PDF file from a specific URL. The method requires two string arguments, an url string (example: "https://www.ibm.com/support/knowledgecenter/SSWRCJ_4.1.0/com.ibm.safos.doc_4.1/Planning_and_Installation.pdf") and a destination folder path to download the PDF file (or whatever) into. If the destination path does not exist within the local file system then it is automatically created:
public boolean downloadFile(String urlString, String destinationFolderPath) {
boolean result = false; // will turn to true if download is successful
if (!destinationFolderPath.endsWith("/") && !destinationFolderPath.endsWith("\\")) {
destinationFolderPath+= "/";
}
// If the destination path does not exist then create it.
File foldersToMake = new File(destinationFolderPath);
if (!foldersToMake.exists()) {
foldersToMake.mkdirs();
}
try {
// Open Connection
URL url = new URL(urlString);
// Get just the file Name from URL
String fileName = new File(url.getPath()).getName();
// Try with Resources....
try (InputStream in = url.openStream(); FileOutputStream outStream =
new FileOutputStream(new File(destinationFolderPath + fileName))) {
// Read from resource and write to file...
int length = -1;
byte[] buffer = new byte[1024]; // buffer for portion of data from connection
while ((length = in.read(buffer)) > -1) {
outStream.write(buffer, 0, length);
}
}
// File Successfully Downloaded");
result = true;
}
catch (MalformedURLException ex) { ex.printStackTrace(); }
catch (IOException ex) { ex.printStackTrace(); }
return result;
}

How to create a ZIP InputStream in Android without creating a ZIP file first?

I use NanoHTTPD as web server in my Android APP, I hope to compress some files and create a InputStream in server side, and I download the InputStream in client side using Code A.
I have read Code B at How to zip and unzip the files?, but how to create a ZIP InputStream in Android without creating a ZIP file first?
BTW, I don't think Code C is good way, because it make ZIP file first, then convert ZIP file to FileInputStream , I hope to create a ZIP InputStream directly!
Code A
private Response ActionDownloadSingleFile(InputStream fis) {
Response response = null;
response = newChunkedResponse(Response.Status.OK, "application/octet-stream",fis);
response.addHeader("Content-Disposition", "attachment; filename="+"my.zip");
return response;
}
Code B
public static void zip(String[] files, String zipFile) throws IOException {
BufferedInputStream origin = null;
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
try {
byte data[] = new byte[BUFFER_SIZE];
for (int i = 0; i < files.length; i++) {
FileInputStream fi = new FileInputStream(files[i]);
origin = new BufferedInputStream(fi, BUFFER_SIZE);
try {
ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1));
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
out.write(data, 0, count);
}
}
finally {
origin.close();
}
}
}
finally {
out.close();
}
}
Code C
File file= new File("my.zip");
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
} catch (FileNotFoundException ex)
{
}
ZipInputStream as per the documentation ZipInputStream
ZipInputStream is an input stream filter for reading files in the ZIP file format. Includes support for both compressed and uncompressed entries.
Earlier I answered to this question in a way that it is not possible using ZipInputStream. I am Sorry.
But after investing some time I found that it is possible as per the below code
It is very much obvious that since you are sending files in zip format
over the network.
//Create proper background thread pool. Not best but just for solution
new Thread(new Runnable() {
#Override
public void run() {
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
HttpURLConnection httpURLConnection = null;
byte[] buffer = new byte[2048];
try {
//Your http connection
httpURLConnection = (HttpURLConnection) new URL("https://s3-ap-southeast-1.amazonaws.com/uploads-ap.hipchat.com/107225/1251522/SFSCjI8ZRB7FjV9/zvsd.zip").openConnection();
//Change below path to Environment.getExternalStorageDirectory() or something of your
// own by creating storage utils
File outputFilePath = new File ("/mnt/sdcard/Android/data/somedirectory/");
ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(httpURLConnection.getInputStream()));
ZipEntry zipEntry = zipInputStream.getNextEntry();
int readLength;
while(zipEntry != null){
File newFile = new File(outputFilePath, zipEntry.getName());
if (!zipEntry.isDirectory()) {
FileOutputStream fos = new FileOutputStream(newFile);
while ((readLength = zipInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, readLength);
}
fos.close();
} else {
newFile.mkdirs();
}
Log.i("zip file path = ", newFile.getPath());
zipInputStream.closeEntry();
zipEntry = zipInputStream.getNextEntry();
}
// Close Stream and disconnect HTTP connection. Move to finally
zipInputStream.closeEntry();
zipInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
// Close Stream and disconnect HTTP connection.
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
}
}).start();

How to download .msi file in Java

I want to download .msi file using Java. I have tried to download file using following code
PrintWriter out = null;
FileInputStream fileToDownload = null;
BufferedReader bufferedReader = null;
try {
out = response.getWriter();
fileToDownload = new FileInputStream(DOWNLOAD_DIRECTORY + FILE_NAME);
bufferedReader = new BufferedReader(new InputStreamReader(fileToDownload));
//response.setContentType("application/text");
//response.setContentType("application/x-msi");
//response.setContentType("application/msi");
//response.setContentType("octet-stream");
response.setContentType("application/octet-stream");
//response.setContentType("application/x-7z-compressed");
//response.setContentType("application/zip");
response.setHeader("Content-disposition","attachment; filename=" +FILE_NAME );
response.setContentLength(fileToDownload.available());
System.out.println("\n now file download is starting");
String NextLine = "";
while((NextLine = bufferedReader.readLine()) != null){
out.println(NextLine);
}
out.flush();
} catch (IOException e) {
out.write("<center><h2>The Installer is not Available on Server</h2></center>");
System.out.println("\n Got Exception while getting the input Stream from the file==>"+e);
log.error("Error::", e);
}
finally{
if(null != bufferedReader){
try {
bufferedReader.close();
} catch (IOException e) {
System.out.println("\n Error in closing buffer Reader==>"+e);
log.error("Error::", e);
}
}// End of if
if(null != fileToDownload){
try {
fileToDownload.close();
} catch (IOException e) {
System.out.println("\n Error in closing input stream==>"+e);
log.error("Error::", e);
}
}// End of if
}// End of finally
You Can't read binary(msi) file with readline() in this case.Your Code is totally wrong and will not work.
Here is a simple function which lets you do what you want.
private void doDownload( HttpServletRequest req, HttpServletResponse resp,String filename, String original_filename )throws IOException
{
File f = new File(filename);
int length = 0;
ServletOutputStream op = resp.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType( filename );
resp.setContentType( (mimetype != null) ? mimetype : "application/octet-stream" );
resp.setContentLength( (int)f.length() );
resp.setHeader( "Content-Disposition", "attachment; filename=\"" + original_filename + "\"" );
byte[] bbuf = new byte[BUFSIZE];
DataInputStream in = new DataInputStream(new FileInputStream(f));
while ((in != null) && ((length = in.read(bbuf)) != -1)){
op.write(bbuf,0,length);
}
in.close();
op.flush();
op.close();
}
Create doDownload() function in your servlet and pass requierd parameters to that function from doGet,doPost or whatever valid place you like.
Parameters:
#param req The request
#param resp The response
#param filename The name of the file you want to download.
#param original_filename The name the browser should receive.

file upload using java servlet as a service without a web browser

I am very new to java and servlet programming.
I am not sure whether it is possible to write a servlet which when passed a URL from the local client machine, uploads the file to the server.
basically on the client machine we have a C# program and on the server side we have Apache-tomcat installed. I need to upload file(s) to the server using C# program on client machine.
Should I provide any more information (?)
Thanks in Advance
Note this code illustrates the general idea and not guaranteed to work without modification.
The C# file upload part
// this code shows you how the browsers wrap the file upload request, you still can fine a way simpler code to do the same thing.
public void PostMultipleFiles(string url, string[] files)
{
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.Method = "POST";
httpWebRequest.KeepAlive = true;
httpWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes =System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary +"\r\n");
string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
memStream.Write(boundarybytes, 0, boundarybytes.Length);
for (int i = 0; i < files.Length; i++)
{
string header = string.Format(headerTemplate, "file" + i, files[i]);
//string header = string.Format(headerTemplate, "uplTheFile", files[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(files[i], FileMode.Open,
FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
memStream.Write(boundarybytes, 0, boundarybytes.Length);
fileStream.Close();
}
httpWebRequest.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
try
{
WebResponse webResponse = httpWebRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string var = reader.ReadToEnd();
}
catch (Exception ex)
{
response.InnerHtml = ex.Message;
}
httpWebRequest = null;
}
and to understand how the above code was written you might wanna take a look at How does HTTP file upload work?
POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
... other headers ...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"
100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object
... contents of file goes here ...
------WebKitFormBoundaryePkpFF7tjBAqx29L--
and finally all you have to do is to implement a servlet that can handle the file upload request, then you do whatever that you want to do with the file, take a look at this file upload tutorial
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// Create path components to save the file
final String path = request.getParameter("destination");
final Part filePart = request.getPart("file");
final String fileName = getFileName(filePart);
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
out = new FileOutputStream(new File(path + File.separator
+ fileName));
filecontent = filePart.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
writer.println("New file " + fileName + " created at " + path);
LOGGER.log(Level.INFO, "File{0}being uploaded to {1}",
new Object[]{fileName, path});
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
writer.println("<br/> ERROR: " + fne.getMessage());
LOGGER.log(Level.SEVERE, "Problems during file upload. Error: {0}",
new Object[]{fne.getMessage()});
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
}
private String getFileName(final Part part) {
final String partHeader = part.getHeader("content-disposition");
LOGGER.log(Level.INFO, "Part Header = {0}", partHeader);
for (String content : part.getHeader("content-disposition").split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(
content.indexOf('=') + 1).trim().replace("\"", "");
}
}
return null;
}

Categories

Resources