Issue
I am currently creating a webpage that displays a table with data from an Mysql DB. One of the columns is a file (stored as a BLOB in the DB). The name of the file is an anchor tag that links to my download.java servlet. My download servlet works when deploying locally, however now that I have deployed to an AWS ElasticBeanstalk instance the servlet does not work.
In the log it says the following:
org.apache.coyote.http11.AbstractHttp11Processor.process Error parsing HTTP request header
Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
and
/usr/share/tomcat8/Downloads/sdc.png (No such file or directory)
The servlet code:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "dbURL?serverTimezone=" + TimeZone.getDefault().getID();
Connection conn = DriverManager.getConnection(url , "username" , "password");
String fn = request.getParameter("Id");
String selectSQL = "SELECT file FROM Requests WHERE fileID=?";
PreparedStatement pstmt = conn.prepareStatement(selectSQL);
pstmt.setString(1, fn);
ResultSet rs = pstmt.executeQuery();
// write binary stream into file
String home = System.getProperty("user.home");
File file = new File(home+"/Downloads/" + fn);
FileOutputStream output = new FileOutputStream(file);
System.out.println("Writing to file " + file.getAbsolutePath());
while (rs.next()) {
InputStream input = rs.getBinaryStream("file");
byte[] buffer = new byte[1024];
while (input.read(buffer) > 0) {
output.write(buffer);
}
}
RequestDispatcher rd = request.getRequestDispatcher("/requests.jsp");
rd.forward(request, response);
rs.close();
pstmt.close();
} catch (SQLException | IOException e) {
System.out.println(e.getMessage());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The servlet should download the file from the Mysql DB to the users download folder. However, this only works locally, on the AWS server it fails. I assume this is because:
String home = System.getProperty("user.home");
returns the home path of the AWS server instance, rather than the path of the users/visitors home path.
Please help me adjust my servlet so that it works on the AWS server
UPDATE: After some research I think that getting the path to the client's download folder is not possible. Now I think I need to make us of a 'save as' dialog box. Any tips on how to do this and resources that could help me do this is appreciated
Solution
I was able to get my servlet working using code posted in a question here
My working code now looks like this:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Connection conn = null;
try {
// Get Database Connection.
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "dbURL?serverTimezone=" + TimeZone.getDefault().getID();
conn = DriverManager.getConnection(url , "username" , "password");
String fileName = request.getParameter("Id");
System.out.println("File Name: " + fileName);
// queries the database
String sql = "SELECT file FROM requests WHERE fileID= ?";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString(1, file);
ResultSet result = statement.executeQuery();
if (result.next()) {
// gets file name and file blob data
Blob blob = result.getBlob("file");
InputStream inputStream = blob.getBinaryStream();
int fileLength = inputStream.available();
System.out.println("fileLength = " + fileLength);
ServletContext context = getServletContext();
// sets MIME type for the file download
String mimeType = context.getMimeType(fileID);
if (mimeType == null) {
mimeType = "application/octet-stream";
}
// set content properties and header attributes for the response
response.setContentType(mimeType);
response.setContentLength(fileLength);
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", fileID);
response.setHeader(headerKey, headerValue);
// writes the file to the client
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
}
else {
// no file found
response.getWriter().print("File not found for the fn: " + fileName);
}
} catch (Exception e) {
throw new ServletException(e);
}
}
Answered By - Alfie Danger