I am trying to upload file (multi part form data) using HTTPHandler.
WebKit Boundary is getting written to the destination file, thus corrupting the file.
Input files can be any kind of files, 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();
}
}
}
}
Here's the 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 is going wrong here? Help would be much appreciated.
EDIT 1:
If the input file is a text file containing text : 1234567890
The output file has contents :
------WebKitFormBoundaryKBRUiUWrIpW9wq2j
Content-Disposition: form-data; name="textline"
------WebKitFormBoundaryKBRUiUWrIpW9wq2j
Content-Disposition: form-data; name="datafile"; filename="test.txt"
Content-Type: text/plain
1234567890
------WebKitFormBoundaryKBRUiUWrIpW9wq2j--
File Upload to HttpHandler results in boundary and other MIME information being written into the request contents. As parsing this information is quite comples and error-prone, one could resort to use Commons FileUpload which is proven to work great in classic Servlet
environments.
Consider this example with a custom made ContextRequest
. This would handle all the parsing of boundaries added into your request body by multipart/form-data
while still allowing you to keep HttpHandler
interface.
The main idea consists of implementing an own version of ContextRequest
to work with 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: Here's a working example listing the received files.
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();
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With