Java – upload files using HTTP handler
I'm trying to upload files (Multi - part form data) using HTTP handler
WebKit boundary is writing to the target file, destroying the file
The input file can be any type of file, including text, zip, APK, etc
Code:
public void handle(HttpExchange httpExchange) throws IOException { URI uri = httpExchange.getRequestURI(); String httpReqMethod = httpExchange.getRequestMethod(); Headers headers = httpExchange.getRequestHeaders(); InputStream inputStrm = null; FileOutputStream destFile = null; String contentType = ((headers.get("Content-type") != null) ? (headers.get("Content-type").toString()) : (null)); httpExchange.getRequestURI().getQuery()); Map<String,String> queryParams = queryToMap(httpExchange.getRequestURI().getQuery()); Set<String> keys= headers.keySet(); Iterator<String> itr = keys.iterator(); while(itr.hasNext()) { String key = (String)itr.next(); } File file = new File(ACEConstants.WEB_SERVER_CTX_ROOT + uri.getPath()).getCanonicalFile(); String resource = uri.getPath().substring( uri.getPath().indexOf(ACEConstants.WEB_SERVER_CTX_ROOT)+ACEConstants.WEB_SERVER_CTX_ROOT.length()+1); if(httpReqMethod.equals(ACEConstants.HTTP_Request_METHOD_POST) ) { if(contentType != null && contentType.contains("multipart/form-data")) { if(resource.equals("fileUpload")) { inputStrm = httpExchange.getRequestBody(); destFile = new FileOutputStream(new File("D:\\"+queryParams.get("fileName"))); String contentLength = headers.get("Content-length").toString(); long fileSize = (Long.parseLong(contentLength.substring(1,contentLength.length()-1))); int iteration = 1; long bytesToBeRead = (fileSize > 1024) ? ((iteration * 1024)) : (inputStrm.available()); long bytesRemaining = (fileSize) - (iteration * 1024); byte[] bytes = new byte[1024]; if(fileSize <= 1024) { bytes = new byte[inputStrm.available()]; inputStrm.read(bytes); destFile.write(bytes); } else { while (inputStrm.read(bytes) != -1) { iteration++; destFile.write(bytes); bytesRemaining = ( fileSize - ((iteration-1) * 1024)); if (bytesRemaining >= 1024) { bytesToBeRead = 1024; bytes = new byte[1024]; } else { bytes = new byte[inputStrm.available()]; inputStrm.read(bytes); destFile.write(bytes); break; } } } destFile.close(); } } } }
This is HTML code
<!DOCTYPE html> <html> <head lang="en"> <Meta charset="UTF-8"> <title></title> <script type="text/javascript"> function processForm(frm) { var fu1 = document.getElementsByName("datafile"); var filename = fu1[0].value; filename = filename.substring(filename.lastIndexOf("\\")+1); alert("You selected " + filename); frm.action = "http://localhost:64444/ACE/fileUpload?fileName="+filename; return true; } </script> </head> <body> <form name="myForm" enctype="multipart/form-data" method="post" acceptcharset="UTF-8" onsubmit="processForm(this);"> <p> Please specify a file,or a set of files:<br> <input type="file" name="datafile" size="40"> </p> <div> <input type="submit" value="Send"> </div> </form> </body> </html>
What's wrong here? Thank you very much for your help
Edit 1:
If the input file is a text file containing text: 1234567890 the output file contains:
------WebKitFormBoundaryKBRUiUWrIpW9wq2j Content-Disposition: form-data; name="textline" ------WebKitFormBoundaryKBRUiUWrIpW9wq2j Content-Disposition: form-data; name="datafile"; filename="test.txt" Content-Type: text/plain 1234567890 ------WebKitFormBoundaryKBRUiUWrIpW9wq2j--
Solution
How to upload files using HttpHandler
Uploading the file to HttpHandler causes boundary and other mime information to be written to the request content Because parsing this information is very complex and error prone, you can use common fileUpload, which has proved very useful in the classic servlet environment
Consider using this example of a custom contextrequest This will handle all parsing of the boundary added to the request body by multipart / form data, while still allowing you to keep the HttpHandler interface
The main idea includes implementing its own version of contextrequest to process the data provided in HttpHandler:
public HttpHandlerRequestContext implements RequestContext { private HttpExchange http; public HttpHandlerRequestContext(HttpExchange http) { this.http = http; } @Override public String getCharacterEncoding() { //Need to figure this out yet return "UTF-8"; } @Override public int getContentLength() { //tested to work with 0 as return. Deprecated anyways return 0; } @Override public String getContentType() { //Content-Type includes the boundary needed for parsing return http.getRequestHeaders().getFirst("Content-type"); } @Override public InputStream getInputStream() throws IOException { //pass on input stream return http.getRequestBody(); } }
For reference: This is a working example of listing received documents
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.util.List; import java.util.Map.Entry; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.RequestContext; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class HttpServerTest { public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8000),0); server.createContext("/fileupload",new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); } static class MyHandler implements HttpHandler { @Override public void handle(final HttpExchange t) throws IOException { for(Entry<String,List<String>> header : t.getRequestHeaders().entrySet()) { System.out.println(header.getKey() + ": " + header.getValue().get(0)); } DiskFileItemFactory d = new DiskFileItemFactory(); try { ServletFileUpload up = new ServletFileUpload(d); List<FileItem> result = up.parseRequest(new RequestContext() { @Override public String getCharacterEncoding() { return "UTF-8"; } @Override public int getContentLength() { return 0; //tested to work with 0 as return } @Override public String getContentType() { return t.getRequestHeaders().getFirst("Content-type"); } @Override public InputStream getInputStream() throws IOException { return t.getRequestBody(); } }); t.getResponseHeaders().add("Content-type","text/plain"); t.sendResponseHeaders(200,0); OutputStream os = t.getResponseBody(); for(FileItem fi : result) { os.write(fi.getName().getBytes()); os.write("\r\n".getBytes()); System.out.println("File-Item: " + fi.getFieldName() + " = " + fi.getName()); } os.close(); } catch (Exception e) { e.printStackTrace(); } } } }