File Upload using HTTPHandler

自作多情 提交于 2019-12-28 03:10:20

问题


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--

回答1:


How to Upload Files with HttpHandler

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();
            }            
        }
    }
}



回答2:


I have faced same issue please use Apache httpClient API for it its best api for connection with URL(file uploading and dealing with multipart form data)



来源:https://stackoverflow.com/questions/33732110/file-upload-using-httphandler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!