Как загрузить файл с помощью API Java HTTPServer? - PullRequest
0 голосов
/ 25 октября 2018

РЕДАКТИРОВАТЬ: я попытался это сделать, используя загрузку нескольких файлов, и я получил 3 из 4 загруженных файлов, поэтому кажется, что механизм загрузки только устанавливает слишком большое смещение для первого файла.
Я нашел метод длязагрузка файлов с использованием com.sun.net.httpserver библиотеки здесь , но фактически она не обнаруживает никаких файлов из формы ввода.Он находит «начальную точку» загруженных файлов, представленную List<Integer> offsets, а затем просматривает файл, чтобы получить из него байты.Проблема заключается в том, что он устанавливает каждую часть offsets как число, очень близкое к концу данных формы, поэтому на самом деле ничего не анализируется.Вот моя HttpHandler:

package app;
import com.sun.net.httpserver.*;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FormDataHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        Headers headers = httpExchange.getRequestHeaders();
        String contentType = headers.getFirst("Content-Type");
        if(contentType.startsWith("multipart/form-data")){
            //found form data
            String boundary = contentType.substring(contentType.indexOf("boundary=")+9);
            // as of rfc7578 - prepend "\r\n--"
            byte[] boundaryBytes = ("\r\n--" + boundary).getBytes(Charset.forName("UTF-8"));
            byte[] payload = getInputAsBinary(httpExchange.getRequestBody());
            ArrayList<MultiPart> list = new ArrayList<>();
            List<Integer> offsets = searchBytes(payload, boundaryBytes, 0, payload.length - 1);
            System.out.println(offsets);
            for(int idx=0;idx<offsets.size();idx++){
                int startPart = offsets.get(idx);
                int endPart = payload.length;
                if(idx<offsets.size()-1){
                    endPart = offsets.get(idx+1);
                }
                byte[] part = Arrays.copyOfRange(payload,startPart,endPart);
                //look for header
                int headerEnd = indexOf(part,"\r\n\r\n".getBytes(Charset.forName("UTF-8")),0,part.length-1);
                /*This conditional is always false because headerEnd is not 
                found, due to part.length being to small, due to startPart 
                being too small, due to the current offset being to small*/
                if(headerEnd>0) {
                    MultiPart p = new MultiPart();
                    byte[] head = Arrays.copyOfRange(part, 0, headerEnd);
                    String header = new String(head);
                    // extract name from header
                    int nameIndex = header.indexOf("\r\nContent-Disposition: form-data; name=");
                    if (nameIndex >= 0) {
                        int startMarker = nameIndex + 39;
                        //check for extra filename field
                        int fileNameStart = header.indexOf("; filename=");
                        if (fileNameStart >= 0) {
                            String filename = header.substring(fileNameStart + 11, header.indexOf("\r\n", fileNameStart));
                            p.filename = filename.replace('"', ' ').replace('\'', ' ').trim();
                            p.name = header.substring(startMarker, fileNameStart).replace('"', ' ').replace('\'', ' ').trim();
                            p.type = PartType.FILE;
                        } else {
                            int endMarker = header.indexOf("\r\n", startMarker);
                            if (endMarker == -1)
                                endMarker = header.length();
                            p.name = header.substring(startMarker, endMarker).replace('"', ' ').replace('\'', ' ').trim();
                            p.type = PartType.TEXT;
                        }
                    } else {
                        // skip entry if no name is found
                        continue;
                    }
                    // extract content type from header
                    int typeIndex = header.indexOf("\r\nContent-Type:");
                    if (typeIndex >= 0) {
                        int startMarker = typeIndex + 15;
                        int endMarker = header.indexOf("\r\n", startMarker);
                        if (endMarker == -1)
                            endMarker = header.length();
                        p.contentType = header.substring(startMarker, endMarker).trim();
                    }

                    //handle content
                    if (p.type == PartType.TEXT) {
                        //extract text value
                        byte[] body = Arrays.copyOfRange(part, headerEnd + 4, part.length);
                        p.value = new String(body);
                    } else {
                        //must be a file upload
                        p.bytes = Arrays.copyOfRange(part, headerEnd + 4, part.length);
                    }
                    list.add(p);
                }
            }
            handle(httpExchange,list);
        }else{
            //if no form data is present, still call handle method
            handle(httpExchange,null);
        }
    }

    public void handle(HttpExchange he, List<MultiPart> parts) throws IOException {
        OutputStream os = he.getResponseBody();
        String response = "<h1>" + parts.size() + "</h1>";
        he.sendResponseHeaders(200, response.length());
        os.write(response.getBytes());
        os.close();
    }

    public static byte[] getInputAsBinary(InputStream requestStream) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            byte[] buf = new byte[100000];
            int bytesRead=0;
            while ((bytesRead = requestStream.read(buf)) != -1){
            //while (requestStream.available() > 0) {
            //    int i = requestStream.read(buf);
                bos.write(buf, 0, bytesRead);
            }
            requestStream.close();
            bos.close();
        } catch (IOException e) {

        }
        return bos.toByteArray();
    }

    /**
     * Search bytes in byte array returns indexes within this byte-array of all
     * occurrences of the specified(search bytes) byte array in the specified
     * range
     * borrowed from https://github.com/riversun/finbin/blob/master/src/main/java/org/riversun/finbin/BinarySearcher.java
     *
     * @param srcBytes
     * @param searchBytes
     * @param searchStartIndex
     * @param searchEndIndex
     * @return result index list
     */
    public List<Integer> searchBytes(byte[] srcBytes, byte[] searchBytes, int searchStartIndex, int searchEndIndex) {
        final int destSize = searchBytes.length;
        final List<Integer> positionIndexList = new ArrayList<Integer>();
        int cursor = searchStartIndex;
        while (cursor < searchEndIndex + 1) {
            int index = indexOf(srcBytes, searchBytes, cursor, searchEndIndex);
            if (index >= 0) {
                positionIndexList.add(index);
                cursor = index + destSize;
            } else {
                cursor++;
            }
        }
        return positionIndexList;
    }

    /**
     * Returns the index within this byte-array of the first occurrence of the
     * specified(search bytes) byte array.<br>
     * Starting the search at the specified index, and end at the specified
     * index.
     * borrowed from https://github.com/riversun/finbin/blob/master/src/main/java/org/riversun/finbin/BinarySearcher.java
     *
     * @param srcBytes
     * @param searchBytes
     * @param startIndex
     * @param endIndex
     * @return
     */
    public int indexOf(byte[] srcBytes, byte[] searchBytes, int startIndex, int endIndex) {
        if (searchBytes.length == 0 || (endIndex - startIndex + 1) < searchBytes.length) {
            return -1;
        }
        int maxScanStartPosIdx = srcBytes.length - searchBytes.length;
        final int loopEndIdx;
        if (endIndex < maxScanStartPosIdx) {
            loopEndIdx = endIndex;
        } else {
            loopEndIdx = maxScanStartPosIdx;
        }
        int lastScanIdx = -1;
        label: // goto label
        for (int i = startIndex; i <= loopEndIdx; i++) {
            for (int j = 0; j < searchBytes.length; j++) {
                if (srcBytes[i + j] != searchBytes[j]) {
                    continue label;
                }
                lastScanIdx = i + j;
            }
            if (endIndex < lastScanIdx || lastScanIdx - i + 1 < searchBytes.length) {
                // it becomes more than the last index
                // or less than the number of search bytes
                return -1;
            }
            return i;
        }
        return -1;
    }

    public static class MultiPart {
        public PartType type;
        public String contentType;
        public String name;
        public String filename;
        public String value;
        public byte[] bytes;
    }

    public enum PartType{
        TEXT,FILE
    }
}

А вот моя форма:

<form action="http://localhost:8080/upl" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit" value="Submit">
</form>

Кто-нибудь знает, почему это не сработает?Если нет, есть ли лучший вариант для загрузки файлов HttpServer?Я попробовал API Apache Commons, но это тоже не сработало.

...