Servlet call hanging when using S3 Java SDK - gwt

I have this servlet I call using GWT FileUpload (I don't thing it matters so much that it is GWT):
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
try {
User user = ServerUtil.validateUser(request);
ServletFileUpload upload = new ServletFileUpload();
try {
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String saveFile = item.getName();
InputStream stream = item.openStream();
// Process the input stream
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[8192];
while ((len = stream.read(buffer, 0, buffer.length)) != -1) {
out.write(buffer, 0, len);
}
int maxFileSize = 10 * (1024 * 1024); //10 megs max
if (out.size() > maxFileSize) {
throw new RuntimeException("File is > than " + maxFileSize);
}
// save file data
String fileName = user.getUsername() + "_" + new Date().getTime() + "_" + saveFile;
// store to S3
String imageUrl = S3PhotoUtil.storeThumbnailImage(out.toByteArray(), fileName, 100);
// return the url of the file
writer.println(imageUrl);
response.flushBuffer();
return;
}
} catch (RuntimeException e) {
writer.println(("error=" + e.getMessage()).getBytes());
} catch (FileUploadException e) {
writer.println(("error=Could not read file").getBytes());
} catch(IOException e) {
writer.println(("error=Image type not supported!").getBytes());
}
} catch (EIException e) {
e.printStackTrace();
writer.println(("error=Not logged in").getBytes());
}
}
When called the POST hangs, I check on firebug, it looks like it never gets a response. If I debug I see that all instructions are executed without any problem and the method is ran fine. The files are stored on my S3 bucket.
Now if I remove the call relating to the S3 storage it stops hanging, although obviously it doesn't do anything anymore... My conclusion is that there is something in this S3 storage that messes up with my servlet. The code itself is taken from the travel log example application # http://aws.amazon.com/code/1264287584622066
It does say needs tomcat and I'm using jetty... could that be a problem?
Thanks,
Thomas

Related

POST multipart/form-data contents out of order

I am trying to build a web server using java sockets, everything is fine except when the browser sends POST request with file attached, when the request is received the content of the file is out of order , the file sent was txt file with line numbers when received the line numbers were out of order. is there any way I can avoid this I want ordered data (see pic 99522 is followed by 99712) THANKs
public class Server{
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
while(true) new Thread(new Client(server.accept())).start();
}
}
class Client implements Runnable {
Socket client;
OutputStream os = new FileOutputStream(new File("File12"));
InputStream in;
OutputStream out;
static ArrayList<Socket> clients = new ArrayList<Socket>();
String index;
String response;
Client(Socket client) throws IOException {
String listOfFiles = "<ol>";
this.client = client;
in = client.getInputStream();
out = client.getOutputStream();
clients.add(client);
for (File file : new File(".").listFiles()) if (file.isFile()) listOfFiles += "<li>" + file.getName() + "</li>";
listOfFiles += "</ol>";
index = "<!DOCTYPE html><html><body><h1>" + new Date() + "</h1><hr>"+listOfFiles+"<form id='upload' enctype='multipart/form-data' method='post' action='/upload'><input id='fileupload' multiple name='myfile' type='file' /><input type='submit' value='submit' id='submit' /></form></body></html>";
response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length:"+index.length()+"\r\n" +
"\r\n" +
index;
}
public void run() {
try {
String msg = "";
byte buffer[] = new byte[32*1024];
int read = in.read(buffer);
while(read != -1){
msg = new String(buffer);
System.out.println(msg);
if(msg.startsWith("POST")){
System.err.println("RAN IN POST");
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content-Type: text/plain\r\n".getBytes());
out.write(("Content-Length:"+ 4 +"\r\n").getBytes());
out.write("\r\n".getBytes());
out.write("done".getBytes());
}
if(msg.startsWith("GET")){
String path = msg.substring(msg.indexOf("/"), msg.indexOf("HTTP")).trim();
if(path.equals("/")) out.write(response.getBytes());
else {
String fileName = path.substring(1);
fileName = URLDecoder.decode(fileName,"UTF-8");
System.out.println(fileName);
File file = new File(fileName);
if(file.exists()){
System.out.println(file.getName() + " " + file.length());
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Accept-Ranges: bytes\r\n".getBytes());
out.write(("Transfer-Encoding: chunked\r\n").getBytes());
out.write("Content-Type: application/octet-stream\r\n".getBytes());
out.write(("Content-Disposition: attachment; filename=\""+file.getName()+"\"\r\n").getBytes());
out.write("\r\n".getBytes());
try{
Files.copy(Paths.get(file.getPath()) , out);
}catch(Exception e){
break;
}
}else System.out.println("file not existes");
}
}
out.flush();
os.close();
read = in.read(buffer);
}
System.err.println("closing scoket");
out.close();
in.close();
client.close();
clients.remove(client);
} catch (IOException e) {
e.printStackTrace();
}
}
}
ALL right found the bug I am not clearing the buffer hence it appears again

download file using JSF 2.2 return content-length=0

I'm trying to download file from a JSF page, but when checking the content-length in the browser I find it 0.
This is my method in the managed Bean :
public void downloadFile() throws IOException {
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
File file = new File("C:\\data\\contacts.doc");
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=contacts.doc");
response.setContentLength((int) file.length());
response.setContentType("application/octet-stream");
OutputStream out = response.getOutputStream();
try {
FileInputStream input = new FileInputStream(file);
byte[] buffer =new byte[2048];
int offset = 0;
int byteRead =0;
while ((offset= input.read(buffer))!= -1 ) {
offset += byteRead ;
out.write(buffer,0,offset);
}
out.flush();
out.close();
input.close();
FacesContext.getCurrentInstance().getResponseComplete();
} catch (IOException err) {
err.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException err) {
err.printStackTrace();
}
}
this is the xhtml page :
<h:form>
<h:commandButton value="Download" action="#{helloBean.downloadFile}" />
</h:form>
I'm using Eclispe + Glassfish 4.
I was a matter of extension I put .docx instead of .doc( .doc don't exist any more)

Write files from multiple rest requests

I have a rest service written to receive a file and save it.
The problem is that when I receive more than 2 requests, the files are not written only the last request is taken into consideration and written.
Here is my code:
#POST
#RequestMapping(value = "/media/{mediaName}/{mediaType}")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#ResponseBody
public String updateResourceLocally(#FormDataParam("rawData") InputStream rawData, #PathVariable("mediaName") String mediaName, #PathVariable("mediaType") String mediaType) {
logger.info("Entering updateResourceLocally for " + jobId + "; for media type: " + mediaType);
final String storeDir = "/tmp/test/" + mediaName + ("/");
final String finalExtension = mediaType;
final InputStream finalRawData = rawData;
// new Thread(new Runnable() {
// public void run() {
// writeToFile(finalRawData, storeDir, finalExtension);
// }
// }).start();
writeToFile(finalRawData, storeDir, finalExtension);
// int poolSize = 100;
// ExecutorService executor = Executors.newFixedThreadPool(poolSize);
// executor.execute(new Runnable() {
// #Override
// public void run() {
// writeToFile(rawData, storeDir, finalExtension);
// }
// });
logger.info("File uploaded to : " + storeDir);
return "Success 200";
}
I tried to put the writeToFile into threads, but still no success. Here is what writeToFile does
public synchronized void writeToFile(InputStream rawData,
String uploadedFileLocation, String extension) {
StringBuilder finalFileName = null;
String currentIncrement = "";
String fileName = "raw";
try {
File file = new File(uploadedFileLocation);
if (!file.exists()) {
file.mkdirs();
}
while (true) {
finalFileName = new StringBuilder(fileName);
if (!currentIncrement.equals("")) {
finalFileName.append("_").append(currentIncrement).append(extension);
}
File f = new File(uploadedFileLocation + finalFileName);
if (f.exists()) {
if (currentIncrement.equals("")) {
currentIncrement = "1";
} else {
currentIncrement = (Integer.parseInt(currentIncrement) + 1) + "";
}
} else {
break;
}
}
int read = 0;
byte[] bytes = new byte[1024];
OutputStream out = new FileOutputStream(new File(uploadedFileLocation + finalFileName));
while ((read = rawData.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
The writeToFile creates a folder and writes a file, if the file already exists, it appends 1 and then increments the 1 accordingly and writes the file, so I would get raw.zip, raw-1.zip, etc.
I think the inputstream bytes are being lost, am I correct in my assumption?
NOTE: I do not have a UI client, I am using Poster a Firefox extension.
Update: What I am trying to achieve here is very simple
I receive number of requests with files attached
I need to save them. If the mediaName and mediaType are the same, then I need to append something to the filename and save it in the same location
If they are different I do not have a problem
The problem I am facing with the current code is that, when I post multiple time to the same URL, I have file-names created according to what I want, but the file content is not right, they vary depending on when the request came in and only the last POST's request is written properly.
Eg. I have a zip file of size 250MB, when I post 5 time, the 1st four will have random sizes and the 5th will have the complete 250MB, but the previous four should also have the same content.
You must separate the stream copy from the free filename assignation. The stream copy must be done within the calling thread (jersey service). Only the file naming operation must be common to all threads/requests.
Here is your code with a little refactoring :
getNextFilename
This file naming operation must be synchronized to guarantee each call gives a free name. This functions creates an empty file to guarantee the next call to work, because the function relies on file.exists().
public synchronized File getNextFilename(String uploadedFileLocation, String extension)
throws IOException
{
// This function MUST be synchronized to guarantee unicity of files names
// Synchronized functions must be the shortest possible to avoid threads waiting each other.
// No long job such as copying streams here !
String fileName = "raw";
//Create directories (if not already existing)
File dir = new File(uploadedFileLocation);
if (!dir.exists())
dir.mkdirs();
//Search for next free filename (raw.<extension>, else raw_<increment>.<extension>)
int currentIncrement = 0;
String finalFileName = fileName + "." + extension;
File f = new File(uploadedFileLocation + finalFileName);
while (f.exists())
{
currentIncrement++;
finalFileName = fileName + "_" + currentIncrement + "." + extension;
f = new File(uploadedFileLocation + finalFileName);
}
//Creates the file with size 0 in order to physically reserve the file "raw_<n>.extension",
//so the next call to getNextFilename will find it (f.exists) and will return "raw_<n+1>.extension"
f.createNewFile();
//The file exists, let the caller fill it...
return f;
}
writeToFile
Must not be synchronized !
public void writeToFile(InputStream rawData, String uploadedFileLocation, String extension)
throws IOException
{
//(1) Gets next available filename (creates the file with 0 size)
File file = getNextFilename(uploadedFileLocation, extension);
//(2) Copies data from inputStream to file
int read = 0;
byte[] bytes = new byte[1024];
OutputStream out = new FileOutputStream(file);
while ((read = rawData.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
}

Send a file from server to client in GWT

I am using GWT.
I have to download a file file from server to client.
Document is in the external repository.
Client sends the id of the document through a Servlet.
On server side: Using this ID document is retrieved:
Document document = (Document)session.getObject(docId);
ContentStream contentStream = document.getContentStream();
ByteArrayInputStream inputStream = (ByteArrayInputStream) contentStream.getStream();
int c;
while ((c = inputStream.read()) != -1) {
System.out.print((char) c);
}
String mime = contentStream.getMimeType();
String name = contentStream.getFileName();
InputStream strm = contentStream.getStream();
Here I can read the document.
I want to send this to the client.
How do I make this a file and send it back to the client?
In Your Servlet:
Document document =(Document)session.getObject(docId);
ContentStream contentStream = document.getContentStream();
String name = contentStream.getFileName();
response.setHeader("Content-Type", "application/octet-stream;");
response.setHeader("Content-Disposition", "attachment;filename=\"" + name + "\"");
OutputStream os = response.getOutputStream();
InputStream is =
(ByteArrayInputStream) contentStream.getStream();
BufferedInputStream buf = new BufferedInputStream(is);
int readBytes=0;
while((readBytes=buf.read())!=-1) {
os.write(readBytes);
}
os.flush();
os.close();// *important*
return;
You can create a standard servlet (which extends HttpServlet and not RemoteServiceServlet) on server side and opportunity to submit the id as servlet parameter on client side.
Now you need after getting request create the excel file and send it to the client. Browser shows automatically popup with download dialog box.
But you should make sure that you set the right content-type response headers. This header will instruct the browser which type of file is it.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String fileId = reguest.getParameter("fileId"); // value of file id from request
File file = CreatorExel.getFile(fileId); // your method to create file from helper class
// setting response headers
response.setHeader("Content-Type", getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", file.length());
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
InputStream inputStream = new FileInputStream(file);
ServletOutputStream outputStream = response.getOutputStream();
input = new BufferedInputStream(fileInput);
output = new BufferedOutputStream(outputStream);
int count;
byte[] buffer = new byte[8192]; // buffer size is 512*16
while ((count = input.read(buffer)) > 0) {
output.write(buffer, 0, count);
}
} finally {
if (output != null) {
try {
output.close();
} catch (IOException ex) {
}
}
if (input != null) {
try {
input.close();
} catch (IOException ex) {
}
}
}

Weird EOF Exception while trying to download file from GWT application

I am trying to download a file from GWT client. At server side there is a servlet which generates content of file as per request and send it back to the client.
Test Scenarios:
Scenario 1 If I hit url of servlet directly, it always give me desired result without any problems.
Scenario 2
Using GWT client on IE8,I am able to download file without any code changes. However on some other computer as soon as I try to write file content on response output stream, I get EOF exception.
org.mortbay.jetty.EofException
at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:760)
at org.mortbay.jetty.AbstractGenerator$Output.flush(AbstractGenerator.java:566)
at org.mortbay.jetty.HttpConnection$Output.flush(HttpConnection.java:911)
at java.io.BufferedOutputStream.flush(Unknown Source)
atXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.doGet(ServiceDataExporterServlet.java:110)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)Creating input stream....
Code of servlet is as follows:
try
{
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
int bytesWritten=0;
while ((length = data.read(buffer)) > 0) {
bytesWritten+=length;
output.write(buffer, 0, length);
}
output.flush() // At this point I am facing EOF exception.
where data is inputStream
Via means of bytesWritten variable I have confirmed that in all the three scenarios content has been written in the same way in output stream. But not sure why it is not working in some computers.
Any points will be highly appereciated.
I do something like this to download files with GWT
In the server side:
public static void sendFileToClient(String path, String filename,
int contentLen, HttpServletRequest request,
HttpServletResponse response) throws UnsupportedEncodingException
{
String ua = request.getHeader("User-Agent").toLowerCase();
boolean isIE = ((ua.indexOf("msie 6.0") != -1) || (ua
.indexOf("msie 7.0") != -1)) ? true : false;
String encName = URLEncoder.encode(filename, "UTF-8");
// Derived from Squirrel Mail and from
// http://www.jspwiki.org/wiki/BugSSLAndIENoCacheBug
if (request.isSecure())
{
response.addHeader("Pragma", "no-cache");
response.addHeader("Expires", "-1");
response.addHeader("Cache-Control", "no-cache");
}
else
{
response.addHeader("Cache-Control", "private");
response.addHeader("Pragma", "public");
}
if (isIE)
{
response.addHeader("Content-Disposition", "attachment; filename=\"" + encName + "\"");
response.addHeader("Connection", "close");
response.setContentType("application/force-download; name=\"" + encName + "\"");
}
else
{
response.addHeader("Content-Disposition", "attachment; filename=\""
+ encName + "\"");
response.setContentType("application/octet-stream; name=\""
+ encName + "\"");
if (contentLen > 0)
response.setContentLength(contentLen);
}
try
{
FileInputStream zipIn = new FileInputStream(new File(path));
ServletOutputStream out = response.getOutputStream();
response.setBufferSize(8 * 1024);
int bufSize = response.getBufferSize();
byte[] buffer = new byte[bufSize];
BufferedInputStream bis = new BufferedInputStream(zipIn, bufSize);
int count;
while ((count = bis.read(buffer, 0, bufSize)) != -1)
{
out.write(buffer, 0, count);
}
bis.close();
zipIn.close();
out.flush();
out.close();
}
catch (FileNotFoundException e)
{
System.out.println("File not found");
}
catch (IOException e)
{
System.out.println("IO error");
}
}
I have a servlet that expects for an id and then I get the related file path and I serve it to the browser with the above code.
In the client side:
public class DownloadIFrame extends Frame implements LoadHandler,
HasLoadHandlers
{
public static final String DOWNLOAD_FRAME = "__gwt_downloadFrame";
public DownloadIFrame(String url)
{
super();
setSize("0px", "0px");
setVisible(false);
RootPanel rp = RootPanel.get(DOWNLOAD_FRAME);
if (rp != null)
{
addLoadHandler(this);
rp.add(this);
setUrl(url);
}
else
openURLInNewWindow(url);
}
native void openURLInNewWindow(String url) /*-{
$wnd.open(url);
}-*/;
public HandlerRegistration addLoadHandler(LoadHandler handler)
{
return addHandler(handler, LoadEvent.getType());
}
public void onLoad(LoadEvent event)
{
}
}
In you hosted page add this Iframe
<iframe src="javascript:''" id="__gwt_downloadFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
Then to download a file put something like this:
btnDownload.addClickHandler(new ClickHandler()
{
public void onClick(ClickEvent arg0)
{
String url = GWT.getModuleBaseURL()
+ "/downloadServlet?id=[FILE_ID]";
new DownloadIFrame(url);
}
});
I hope this helps you.
Happy coding!
It happens also if the OutputStream flushes after InputStream was closed, like this:
myInputStream.close();
myOutputStream.flush();
myOutputStream.close();
it should be like:
myOutputStream.flush();
myInputStream.close();
myOutputStream.close();
Hope it helps :-)