HttpData

HTTP Post请求的四种编码方式

文章目录

HttpData

HttpDataFactory

java 复制代码
public interface HttpDataFactory {
 
    void setMaxLimit(long max);

    Attribute createAttribute(HttpRequest request, String name);

    Attribute createAttribute(HttpRequest request, String name, long definedSize);

    Attribute createAttribute(HttpRequest request, String name, String value);

    FileUpload createFileUpload(HttpRequest request, 
                                String name, 
                                String filename,
                                String contentType, 
                                String contentTransferEncoding, Charset charset,
                                long size);

    void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data);

    void cleanRequestHttpData(HttpRequest request);

    void cleanAllHttpData();
}

DefaultHttpDataFactory

属性
java 复制代码
// 16 KB
public static final long MINSIZE = 0x4000;
public static final long MAXSIZE = -1;

final boolean useDisk;
final boolean checkSize;

long minSize;
long maxSize = -1;
Charset charset = HttpConstants.DEFAULT_CHARSET;
String baseDir;
boolean deleteOnExit;

final Map<HttpRequest, List<HttpData>> requestFileDeleteMap = 
    Collections.synchronizedMap(new IdentityHashMap<HttpRequest, List<HttpData>>());
构造方法
java 复制代码
// 
public DefaultHttpDataFactory() {
    
    useDisk = false;
    
    checkSize = true;
    
    // 默认16kB
    minSize = MINSIZE;
}

public DefaultHttpDataFactory(Charset charset) {
    this();
    this.charset = charset;
}


public DefaultHttpDataFactory(boolean useDisk) {
    this.useDisk = useDisk;
    checkSize = false;
}

public DefaultHttpDataFactory(boolean useDisk, Charset charset) {
    this(useDisk);
    this.charset = charset;
}

public DefaultHttpDataFactory(long minSize) {
    useDisk = false;
    checkSize = true;
    this.minSize = minSize;
}

public DefaultHttpDataFactory(long minSize, Charset charset) {
    this(minSize);
    this.charset = charset;
}
getList(HttpRequest)
java 复制代码
private List<HttpData> getList(HttpRequest request) {
    
    // 从 requestFileDeleteMap 中,获取指定 request对应的 HttpData 集合
    List<HttpData> list = requestFileDeleteMap.get(request);
    
    // 如果没有获取到,则初始化该 HttpData 集合
    if (list == null) {
        list = new ArrayList<HttpData>();
        requestFileDeleteMap.put(request, list);
    }
    
    // 返回 HttpData 集合
    return list;
}
createAttribute(HttpRequest, String name)
java 复制代码
@Override
public Attribute createAttribute(HttpRequest request, String name) {
    
    // 若useDisk为true
    if (useDisk) {
        
        // 创建的是 DiskAttribute
        Attribute attribute = new DiskAttribute(name, charset, baseDir, deleteOnExit);
        
        attribute.setMaxSize(maxSize);
        
        // 将创建的 DiskAttribute对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(attribute);
        
        return attribute;
    }
    
    // 此时 useDisk为false
    
    // 若checkSize为true
    if (checkSize) {
        
        // 创建的是 MixedAttribute
        Attribute attribute = new MixedAttribute(name, minSize, charset, baseDir, deleteOnExit);
        
        attribute.setMaxSize(maxSize);
        
        // 将创建的 MixedAttribute对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(attribute);
        
        return attribute;
    }
    
    // 此时 checkSize为false
    
    // 创建的是 MemoryAttribute
    MemoryAttribute attribute = new MemoryAttribute(name);
    
    attribute.setMaxSize(maxSize);
    
    return attribute;
}
createAttribute(HttpRequest request, String name, long definedSize)
java 复制代码
@Override
public Attribute createAttribute(HttpRequest request, String name, long definedSize) {
    
    // 若useDisk为true
    if (useDisk) {
        
        // 创建的是 DiskAttribute
        Attribute attribute = new DiskAttribute(name, definedSize, charset, baseDir, deleteOnExit);
        
        attribute.setMaxSize(maxSize);
        
        // 将创建的 DiskAttribute对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(attribute);
        
        return attribute;
    }
    
    // 此时 useDisk为false
    
    // 若checkSize为true
    if (checkSize) {
        
        // 创建的是 MixedAttribute
        Attribute attribute = new MixedAttribute(name, definedSize, minSize, charset, baseDir, deleteOnExit);
        
        attribute.setMaxSize(maxSize);
        
        // 将创建的 MixedAttribute对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(attribute);
        
        return attribute;
    }
    
    // 此时 checkSize为false
    
    // 创建的是 MemoryAttribute
    MemoryAttribute attribute = new MemoryAttribute(name, definedSize);
    
    attribute.setMaxSize(maxSize);
    
    return attribute;
}
createAttribute(HttpRequest request, String name, String value)
java 复制代码
@Override
public Attribute createAttribute(HttpRequest request, String name, String value) {
    
    // 若useDisk为true
    if (useDisk) {
        
        Attribute attribute;
        
        try {
            // 创建的是 DiskAttribute
            attribute = new DiskAttribute(name, value, charset, baseDir, deleteOnExit);
            attribute.setMaxSize(maxSize);
            
        } catch (IOException e) {
            // 发生异常, 则创建 MixedAttribute
            attribute = new MixedAttribute(name, value, minSize, charset, baseDir, deleteOnExit);
            attribute.setMaxSize(maxSize);
        }
        
        // 检查data.length() 与 maxSize 大小
        checkHttpDataSize(attribute);
        
        // 将创建的 MixedAttribute对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(attribute);
        
        return attribute;
    }
    
    // 若checkSize为true
    if (checkSize) {
        
        // 创建的是 MixedAttribute
        Attribute attribute = new MixedAttribute(name, value, minSize, charset, baseDir, deleteOnExit);
        attribute.setMaxSize(maxSize);
        
        // 检查data.length() 与 maxSize 大小
        checkHttpDataSize(attribute);
        
        // 将创建的 MixedAttribute对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(attribute);
        
        return attribute;
    }
    
    try {
        // 此时 checkSize为false
    
    	// 创建的是 MemoryAttribute
        MemoryAttribute attribute = new MemoryAttribute(name, value, charset);
        attribute.setMaxSize(maxSize);
        
        // 检查data.length() 与 maxSize 大小
        checkHttpDataSize(attribute);
        
        return attribute;
    } catch (IOException e) {
        throw new IllegalArgumentException(e);
    }
    
}
checkHttpDataSize(HttpData)
java 复制代码
private static void checkHttpDataSize(HttpData data) {
    try {
        // 检查data.length() 与 maxSize 大小, 如果超过maxSize, 则抛出异常
        data.checkSize(data.length());
    } catch (IOException ignored) {
        throw new IllegalArgumentException("Attribute bigger than maxSize allowed");
    }
}
createFileUpload
java 复制代码
@Override
public FileUpload createFileUpload(HttpRequest request, 
                                   String name, 
                                   String filename,
        						   String contentType, 
                                   String contentTransferEncoding, 
                                   Charset charset,
                                   long size) {
    
    // 若useDisk为true
    if (useDisk) {
        
        // 创建FileUpload对象 
        FileUpload fileUpload = new DiskFileUpload(name, 
                                                   filename, 
                                                   contentType,
                								   contentTransferEncoding, 
                                                   charset, 
                                                   size, 
                                                   baseDir, 
                                                   deleteOnExit);
        
        fileUpload.setMaxSize(maxSize);
        
        // 检查fileUpload.length() 与 maxSize 大小
        checkHttpDataSize(fileUpload);
        
        // 将创建的 fileUpload对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(fileUpload);
        
        return fileUpload;
    }
    
    // 若checkSize为true
    if (checkSize) {
        
        // 创建 MixedFileUpload对象
        FileUpload fileUpload = new MixedFileUpload(name, 
                                                    filename, 
                                                    contentType,
                                                    contentTransferEncoding, 
                                                    charset, 
                                                    size, 
                                                    minSize, 
                                                    baseDir, 
                                                    deleteOnExit);
        fileUpload.setMaxSize(maxSize);
        
        // 检查fileUpload.length() 与 maxSize 大小
        checkHttpDataSize(fileUpload);
        
        // 将创建的 fileUpload对象 放入 requestFileDeleteMap 中
        List<HttpData> list = getList(request);
        list.add(fileUpload);
        
        return fileUpload;
    }
    
    // 此时 checkSize为false
    
    // 创建的是 MemoryFileUpload
    MemoryFileUpload fileUpload = new MemoryFileUpload(name, 
                                                       filename, 
                                                       contentType,
            										   contentTransferEncoding, 
                                                       charset, 
                                                       size);
    fileUpload.setMaxSize(maxSize);
    
    // 检查data.length() 与 maxSize 大小
    checkHttpDataSize(fileUpload);
    
    return fileUpload;
}
removeHttpDataFromClean
java 复制代码
@Override
public void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data) {
    
    // data 必须是 InterfaceHttpData 类型
    if (!(data instanceof HttpData)) {
        return;
    }

    // 获取request对应的 HttpData 集合, 如果该集合为null, 直接返回
    List<HttpData> list = requestFileDeleteMap.get(request);
    if (list == null) {
        return;
    }

    // 从 HttpData 集合中,使用迭代器的方式 移除 data
    Iterator<HttpData> i = list.iterator();
    while (i.hasNext()) {
        HttpData n = i.next();
        if (n == data) {
            i.remove();
            if (list.isEmpty()) {
                requestFileDeleteMap.remove(request);
            }
            return;
        }
    }
}
cleanRequestHttpData
java 复制代码
@Override
public void cleanRequestHttpData(HttpRequest request) {
    
    // 获取request对应的 HttpData 集合
    List<HttpData> list = requestFileDeleteMap.remove(request);
    
    // 如果 HttpData 集合 不为null, 则遍历该 HttpData 集合, 并逐个释放 HttpData
    if (list != null) {
        for (HttpData data : list) {
            data.release();
        }
    }
}
cleanAllHttpData
java 复制代码
@Override
public void cleanAllHttpData() {
    
    // 获取 requestFileDeleteMap 的迭代器
    Iterator<Entry<HttpRequest, List<HttpData>>> i = requestFileDeleteMap.entrySet().iterator();
    
    // 遍历
    while (i.hasNext()) {
        
        // 获取当前遍历的 entry
        Entry<HttpRequest, List<HttpData>> e = i.next();

        // 逐个释放 HttpData
        List<HttpData> list = e.getValue();
        for (HttpData data : list) {
            data.release();
        }

        // 从 requestFileDeleteMap 中移除 entry
        i.remove();
    }
}

HttpData

java 复制代码
public interface HttpData extends InterfaceHttpData, ByteBufHolder {

    long getMaxSize();

    void setMaxSize(long maxSize);

    void checkSize(long newSize) throws IOException;

    void setContent(ByteBuf buffer) throws IOException;

    void addContent(ByteBuf buffer, boolean last) throws IOException;

    void setContent(File file) throws IOException;

    void setContent(InputStream inputStream) throws IOException;

    boolean isCompleted();

    long length();

    long definedLength();

    void delete();

    byte[] get() throws IOException;

    ByteBuf getByteBuf() throws IOException;

    ByteBuf getChunk(int length) throws IOException;

    String getString() throws IOException;

    String getString(Charset encoding) throws IOException;

    void setCharset(Charset charset);

    Charset getCharset();

    boolean renameTo(File dest) throws IOException;

    boolean isInMemory();

    File getFile() throws IOException;

    @Override
    HttpData copy();

    @Override
    HttpData duplicate();

    @Override
    HttpData retainedDuplicate();

    @Override
    HttpData replace(ByteBuf content);

    @Override
    HttpData retain();

    @Override
    HttpData retain(int increment);

    @Override
    HttpData touch();

    @Override
    HttpData touch(Object hint);
}

AbstractHttpData

java 复制代码
public abstract class AbstractHttpData extends AbstractReferenceCounted 
                                       implements HttpData {

    private static final Pattern STRIP_PATTERN = Pattern.compile("(?:^\\s+|\\s+$|\\n)");
    private static final Pattern REPLACE_PATTERN = Pattern.compile("[\\r\\t]");

    private final String name;
    
    protected long definedSize;
    
    protected long size;
    
    private Charset charset = HttpConstants.DEFAULT_CHARSET;
    
    private boolean completed;
    
    private long maxSize = DefaultHttpDataFactory.MAXSIZE;

    protected AbstractHttpData(String name, Charset charset, long size) {
        ObjectUtil.checkNotNull(name, "name");

        name = REPLACE_PATTERN.matcher(name).replaceAll(" ");
        name = STRIP_PATTERN.matcher(name).replaceAll("");

        this.name = checkNonEmpty(name, "name");
        if (charset != null) {
            setCharset(charset);
        }
        definedSize = size;
    }

    @Override
    public long getMaxSize() {
        return maxSize;
    }

    @Override
    public void setMaxSize(long maxSize) {
        this.maxSize = maxSize;
    }

    @Override
    public void checkSize(long newSize) throws IOException {
        if (maxSize >= 0 && newSize > maxSize) {
            throw new IOException("Size exceed allowed maximum capacity");
        }
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public boolean isCompleted() {
        return completed;
    }

    protected void setCompleted() {
        completed = true;
    }

    @Override
    public Charset getCharset() {
        return charset;
    }

    @Override
    public void setCharset(Charset charset) {
        this.charset = ObjectUtil.checkNotNull(charset, "charset");
    }

    @Override
    public long length() {
        return size;
    }

    @Override
    public long definedLength() {
        return definedSize;
    }

    @Override
    public ByteBuf content() {
        try {
            return getByteBuf();
        } catch (IOException e) {
            throw new ChannelException(e);
        }
    }

    @Override
    protected void deallocate() {
        delete();
    }

    @Override
    public HttpData retain() {
        super.retain();
        return this;
    }

    @Override
    public HttpData retain(int increment) {
        super.retain(increment);
        return this;
    }

    @Override
    public abstract HttpData touch();

    @Override
    public abstract HttpData touch(Object hint);
}
AbstractDiskHttpData
java 复制代码
public abstract class AbstractDiskHttpData extends AbstractHttpData {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractDiskHttpData.class);

    private File file;
    private boolean isRenamed;
    private FileChannel fileChannel;

    protected AbstractDiskHttpData(String name, Charset charset, long size) {
        super(name, charset, size);
    }

    /**
     *
     * @return the real DiskFilename (basename)
     */
    protected abstract String getDiskFilename();
    /**
     *
     * @return the default prefix
     */
    protected abstract String getPrefix();
    /**
     *
     * @return the default base Directory
     */
    protected abstract String getBaseDirectory();
    /**
     *
     * @return the default postfix
     */
    protected abstract String getPostfix();
    /**
     *
     * @return True if the file should be deleted on Exit by default
     */
    protected abstract boolean deleteOnExit();

    /**
     * @return a new Temp File from getDiskFilename(), default prefix, postfix and baseDirectory
     */
    private File tempFile() throws IOException {
        String newpostfix;
        String diskFilename = getDiskFilename();
        if (diskFilename != null) {
            newpostfix = '_' + diskFilename;
        } else {
            newpostfix = getPostfix();
        }
        File tmpFile;
        if (getBaseDirectory() == null) {
            // create a temporary file
            tmpFile = PlatformDependent.createTempFile(getPrefix(), newpostfix, null);
        } else {
            tmpFile = PlatformDependent.createTempFile(getPrefix(), newpostfix, new File(
                    getBaseDirectory()));
        }
        if (deleteOnExit()) {
            // See https://github.com/netty/netty/issues/10351
            DeleteFileOnExitHook.add(tmpFile.getPath());
        }
        return tmpFile;
    }

    @Override
    public void setContent(ByteBuf buffer) throws IOException {
        ObjectUtil.checkNotNull(buffer, "buffer");
        try {
            size = buffer.readableBytes();
            checkSize(size);
            if (definedSize > 0 && definedSize < size) {
                throw new IOException("Out of size: " + size + " > " + definedSize);
            }
            if (file == null) {
                file = tempFile();
            }
            if (buffer.readableBytes() == 0) {
                // empty file
                if (!file.createNewFile()) {
                    if (file.length() == 0) {
                        return;
                    } else {
                        if (!file.delete() || !file.createNewFile()) {
                            throw new IOException("file exists already: " + file);
                        }
                    }
                }
                return;
            }
            RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
            try {
                accessFile.setLength(0);
                FileChannel localfileChannel = accessFile.getChannel();
                ByteBuffer byteBuffer = buffer.nioBuffer();
                int written = 0;
                while (written < size) {
                    written += localfileChannel.write(byteBuffer);
                }
                buffer.readerIndex(buffer.readerIndex() + written);
                localfileChannel.force(false);
            } finally {
                accessFile.close();
            }
            setCompleted();
        } finally {
            // Release the buffer as it was retained before and we not need a reference to it at all
            // See https://github.com/netty/netty/issues/1516
            buffer.release();
        }
    }

    @Override
    public void addContent(ByteBuf buffer, boolean last)
            throws IOException {
        if (buffer != null) {
            try {
                int localsize = buffer.readableBytes();
                checkSize(size + localsize);
                if (definedSize > 0 && definedSize < size + localsize) {
                    throw new IOException("Out of size: " + (size + localsize) +
                            " > " + definedSize);
                }
                if (file == null) {
                    file = tempFile();
                }
                if (fileChannel == null) {
                    RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
                    fileChannel = accessFile.getChannel();
                }
                int remaining = localsize;
                long position = fileChannel.position();
                int index = buffer.readerIndex();
                while (remaining > 0) {
                    int written = buffer.getBytes(index, fileChannel, position, remaining);
                    if (written < 0) {
                        break;
                    }
                    remaining -= written;
                    position += written;
                    index += written;
                }
                fileChannel.position(position);
                buffer.readerIndex(index);
                size += localsize - remaining;
            } finally {
                // Release the buffer as it was retained before and we not need a reference to it at all
                // See https://github.com/netty/netty/issues/1516
                buffer.release();
            }
        }
        if (last) {
            if (file == null) {
                file = tempFile();
            }
            if (fileChannel == null) {
                RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
                fileChannel = accessFile.getChannel();
            }
            try {
                fileChannel.force(false);
            } finally {
                fileChannel.close();
            }
            fileChannel = null;
            setCompleted();
        } else {
            ObjectUtil.checkNotNull(buffer, "buffer");
        }
    }

    @Override
    public void setContent(File file) throws IOException {
        long size = file.length();
        checkSize(size);
        this.size = size;
        if (this.file != null) {
            delete();
        }
        this.file = file;
        isRenamed = true;
        setCompleted();
    }

    @Override
    public void setContent(InputStream inputStream) throws IOException {
        ObjectUtil.checkNotNull(inputStream, "inputStream");
        if (file != null) {
            delete();
        }
        file = tempFile();
        RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
        int written = 0;
        try {
            accessFile.setLength(0);
            FileChannel localfileChannel = accessFile.getChannel();
            byte[] bytes = new byte[4096 * 4];
            ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
            int read = inputStream.read(bytes);
            while (read > 0) {
                byteBuffer.position(read).flip();
                written += localfileChannel.write(byteBuffer);
                checkSize(written);
                read = inputStream.read(bytes);
            }
            localfileChannel.force(false);
        } finally {
            accessFile.close();
        }
        size = written;
        if (definedSize > 0 && definedSize < size) {
            if (!file.delete()) {
                logger.warn("Failed to delete: {}", file);
            }
            file = null;
            throw new IOException("Out of size: " + size + " > " + definedSize);
        }
        isRenamed = true;
        setCompleted();
    }

    @Override
    public void delete() {
        if (fileChannel != null) {
            try {
                fileChannel.force(false);
            } catch (IOException e) {
                logger.warn("Failed to force.", e);
            } finally {
                try {
                    fileChannel.close();
                } catch (IOException e) {
                    logger.warn("Failed to close a file.", e);
                }
            }
            fileChannel = null;
        }
        if (!isRenamed) {
            String filePath = null;

            if (file != null && file.exists()) {
                filePath = file.getPath();
                if (!file.delete()) {
                    filePath = null;
                    logger.warn("Failed to delete: {}", file);
                }
            }

            // If you turn on deleteOnExit make sure it is executed.
            if (deleteOnExit() && filePath != null) {
                DeleteFileOnExitHook.remove(filePath);
            }
            file = null;
        }
    }

    @Override
    public byte[] get() throws IOException {
        if (file == null) {
            return EmptyArrays.EMPTY_BYTES;
        }
        return readFrom(file);
    }

    @Override
    public ByteBuf getByteBuf() throws IOException {
        if (file == null) {
            return EMPTY_BUFFER;
        }
        byte[] array = readFrom(file);
        return wrappedBuffer(array);
    }

    @Override
    public ByteBuf getChunk(int length) throws IOException {
        if (file == null || length == 0) {
            return EMPTY_BUFFER;
        }
        if (fileChannel == null) {
            RandomAccessFile accessFile = new RandomAccessFile(file, "r");
            fileChannel = accessFile.getChannel();
        }
        int read = 0;
        ByteBuffer byteBuffer = ByteBuffer.allocate(length);
        try {
            while (read < length) {
                int readnow = fileChannel.read(byteBuffer);
                if (readnow == -1) {
                    fileChannel.close();
                    fileChannel = null;
                    break;
                }
                read += readnow;
            }
        } catch (IOException e) {
            fileChannel.close();
            fileChannel = null;
            throw e;
        }
        if (read == 0) {
            return EMPTY_BUFFER;
        }
        byteBuffer.flip();
        ByteBuf buffer = wrappedBuffer(byteBuffer);
        buffer.readerIndex(0);
        buffer.writerIndex(read);
        return buffer;
    }

    @Override
    public String getString() throws IOException {
        return getString(HttpConstants.DEFAULT_CHARSET);
    }

    @Override
    public String getString(Charset encoding) throws IOException {
        if (file == null) {
            return "";
        }
        if (encoding == null) {
            byte[] array = readFrom(file);
            return new String(array, HttpConstants.DEFAULT_CHARSET.name());
        }
        byte[] array = readFrom(file);
        return new String(array, encoding.name());
    }

    @Override
    public boolean isInMemory() {
        return false;
    }

    @Override
    public boolean renameTo(File dest) throws IOException {
        ObjectUtil.checkNotNull(dest, "dest");
        if (file == null) {
            throw new IOException("No file defined so cannot be renamed");
        }
        if (!file.renameTo(dest)) {
            // must copy
            IOException exception = null;
            RandomAccessFile inputAccessFile = null;
            RandomAccessFile outputAccessFile = null;
            long chunkSize = 8196;
            long position = 0;
            try {
                inputAccessFile = new RandomAccessFile(file, "r");
                outputAccessFile = new RandomAccessFile(dest, "rw");
                FileChannel in = inputAccessFile.getChannel();
                FileChannel out = outputAccessFile.getChannel();
                while (position < size) {
                    if (chunkSize < size - position) {
                        chunkSize = size - position;
                    }
                    position += in.transferTo(position, chunkSize, out);
                }
            } catch (IOException e) {
                exception = e;
            } finally {
                if (inputAccessFile != null) {
                    try {
                        inputAccessFile.close();
                    } catch (IOException e) {
                        if (exception == null) { // Choose to report the first exception
                            exception = e;
                        } else {
                            logger.warn("Multiple exceptions detected, the following will be suppressed {}", e);
                        }
                    }
                }
                if (outputAccessFile != null) {
                    try {
                        outputAccessFile.close();
                    } catch (IOException e) {
                        if (exception == null) { // Choose to report the first exception
                            exception = e;
                        } else {
                            logger.warn("Multiple exceptions detected, the following will be suppressed {}", e);
                        }
                    }
                }
            }
            if (exception != null) {
                throw exception;
            }
            if (position == size) {
                if (!file.delete()) {
                    logger.warn("Failed to delete: {}", file);
                }
                file = dest;
                isRenamed = true;
                return true;
            } else {
                if (!dest.delete()) {
                    logger.warn("Failed to delete: {}", dest);
                }
                return false;
            }
        }
        file = dest;
        isRenamed = true;
        return true;
    }

    /**
     * Utility function
     *
     * @return the array of bytes
     */
    private static byte[] readFrom(File src) throws IOException {
        long srcsize = src.length();
        if (srcsize > Integer.MAX_VALUE) {
            throw new IllegalArgumentException(
                    "File too big to be loaded in memory");
        }
        RandomAccessFile accessFile = new RandomAccessFile(src, "r");
        byte[] array = new byte[(int) srcsize];
        try {
            FileChannel fileChannel = accessFile.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.wrap(array);
            int read = 0;
            while (read < srcsize) {
                read += fileChannel.read(byteBuffer);
            }
        } finally {
            accessFile.close();
        }
        return array;
    }

    @Override
    public File getFile() throws IOException {
        return file;
    }

    @Override
    public HttpData touch() {
        return this;
    }

    @Override
    public HttpData touch(Object hint) {
        return this;
    }
}
AbstractMemoryHttpData
java 复制代码
public abstract class AbstractMemoryHttpData extends AbstractHttpData {

    private ByteBuf byteBuf;
    private int chunkPosition;

    protected AbstractMemoryHttpData(String name, Charset charset, long size) {
        super(name, charset, size);
        byteBuf = EMPTY_BUFFER;
    }

    @Override
    public void setContent(ByteBuf buffer) throws IOException {
        ObjectUtil.checkNotNull(buffer, "buffer");
        long localsize = buffer.readableBytes();
        try {
            checkSize(localsize);
        } catch (IOException e) {
            buffer.release();
            throw e;
        }
        if (definedSize > 0 && definedSize < localsize) {
            buffer.release();
            throw new IOException("Out of size: " + localsize + " > " +
                    definedSize);
        }
        if (byteBuf != null) {
            byteBuf.release();
        }
        byteBuf = buffer;
        size = localsize;
        setCompleted();
    }

    @Override
    public void setContent(InputStream inputStream) throws IOException {
        ObjectUtil.checkNotNull(inputStream, "inputStream");

        byte[] bytes = new byte[4096 * 4];
        ByteBuf buffer = buffer();
        int written = 0;
        try {
            int read = inputStream.read(bytes);
            while (read > 0) {
                buffer.writeBytes(bytes, 0, read);
                written += read;
                checkSize(written);
                read = inputStream.read(bytes);
            }
        } catch (IOException e) {
            buffer.release();
            throw e;
        }
        size = written;
        if (definedSize > 0 && definedSize < size) {
            buffer.release();
            throw new IOException("Out of size: " + size + " > " + definedSize);
        }
        if (byteBuf != null) {
            byteBuf.release();
        }
        byteBuf = buffer;
        setCompleted();
    }

    @Override
    public void addContent(ByteBuf buffer, boolean last)
            throws IOException {
        if (buffer != null) {
            long localsize = buffer.readableBytes();
            try {
                checkSize(size + localsize);
            } catch (IOException e) {
                buffer.release();
                throw e;
            }
            if (definedSize > 0 && definedSize < size + localsize) {
                buffer.release();
                throw new IOException("Out of size: " + (size + localsize) +
                        " > " + definedSize);
            }
            size += localsize;
            if (byteBuf == null) {
                byteBuf = buffer;
            } else if (localsize == 0) {
                // Nothing to add and byteBuf already exists
                buffer.release();
            } else if (byteBuf.readableBytes() == 0) {
                // Previous buffer is empty, so just replace it
                byteBuf.release();
                byteBuf = buffer;
            } else if (byteBuf instanceof CompositeByteBuf) {
                CompositeByteBuf cbb = (CompositeByteBuf) byteBuf;
                cbb.addComponent(true, buffer);
            } else {
                CompositeByteBuf cbb = compositeBuffer(Integer.MAX_VALUE);
                cbb.addComponents(true, byteBuf, buffer);
                byteBuf = cbb;
            }
        }
        if (last) {
            setCompleted();
        } else {
            ObjectUtil.checkNotNull(buffer, "buffer");
        }
    }

    @Override
    public void setContent(File file) throws IOException {
        ObjectUtil.checkNotNull(file, "file");

        long newsize = file.length();
        if (newsize > Integer.MAX_VALUE) {
            throw new IllegalArgumentException("File too big to be loaded in memory");
        }
        checkSize(newsize);
        RandomAccessFile accessFile = new RandomAccessFile(file, "r");
        ByteBuffer byteBuffer;
        try {
            FileChannel fileChannel = accessFile.getChannel();
            try {
                byte[] array = new byte[(int) newsize];
                byteBuffer = ByteBuffer.wrap(array);
                int read = 0;
                while (read < newsize) {
                    read += fileChannel.read(byteBuffer);
                }
            } finally {
                fileChannel.close();
            }
        } finally {
            accessFile.close();
        }
        byteBuffer.flip();
        if (byteBuf != null) {
            byteBuf.release();
        }
        byteBuf = wrappedBuffer(Integer.MAX_VALUE, byteBuffer);
        size = newsize;
        setCompleted();
    }

    @Override
    public void delete() {
        if (byteBuf != null) {
            byteBuf.release();
            byteBuf = null;
        }
    }

    @Override
    public byte[] get() {
        if (byteBuf == null) {
            return EMPTY_BUFFER.array();
        }
        byte[] array = new byte[byteBuf.readableBytes()];
        byteBuf.getBytes(byteBuf.readerIndex(), array);
        return array;
    }

    @Override
    public String getString() {
        return getString(HttpConstants.DEFAULT_CHARSET);
    }

    @Override
    public String getString(Charset encoding) {
        if (byteBuf == null) {
            return "";
        }
        if (encoding == null) {
            encoding = HttpConstants.DEFAULT_CHARSET;
        }
        return byteBuf.toString(encoding);
    }

    /**
     * Utility to go from a In Memory FileUpload
     * to a Disk (or another implementation) FileUpload
     * @return the attached ByteBuf containing the actual bytes
     */
    @Override
    public ByteBuf getByteBuf() {
        return byteBuf;
    }

    @Override
    public ByteBuf getChunk(int length) throws IOException {
        if (byteBuf == null || length == 0 || byteBuf.readableBytes() == 0) {
            chunkPosition = 0;
            return EMPTY_BUFFER;
        }
        int sizeLeft = byteBuf.readableBytes() - chunkPosition;
        if (sizeLeft == 0) {
            chunkPosition = 0;
            return EMPTY_BUFFER;
        }
        int sliceLength = length;
        if (sizeLeft < length) {
            sliceLength = sizeLeft;
        }
        ByteBuf chunk = byteBuf.retainedSlice(chunkPosition, sliceLength);
        chunkPosition += sliceLength;
        return chunk;
    }

    @Override
    public boolean isInMemory() {
        return true;
    }

    @Override
    public boolean renameTo(File dest) throws IOException {
        ObjectUtil.checkNotNull(dest, "dest");
        if (byteBuf == null) {
            // empty file
            if (!dest.createNewFile()) {
                throw new IOException("file exists already: " + dest);
            }
            return true;
        }
        int length = byteBuf.readableBytes();
        long written = 0;
        RandomAccessFile accessFile = new RandomAccessFile(dest, "rw");
        try {
            FileChannel fileChannel = accessFile.getChannel();
            try {
                if (byteBuf.nioBufferCount() == 1) {
                    ByteBuffer byteBuffer = byteBuf.nioBuffer();
                    while (written < length) {
                        written += fileChannel.write(byteBuffer);
                    }
                } else {
                    ByteBuffer[] byteBuffers = byteBuf.nioBuffers();
                    while (written < length) {
                        written += fileChannel.write(byteBuffers);
                    }
                }
                fileChannel.force(false);
            } finally {
                fileChannel.close();
            }
        } finally {
            accessFile.close();
        }
        return written == length;
    }

    @Override
    public File getFile() throws IOException {
        throw new IOException("Not represented by a file");
    }

    @Override
    public HttpData touch() {
        return touch(null);
    }

    @Override
    public HttpData touch(Object hint) {
        if (byteBuf != null) {
            byteBuf.touch(hint);
        }
        return this;
    }
}
相关推荐
佩奇的技术笔记17 分钟前
TCP Keep-Alive 和 HTTP Keep-Alive区别
网络协议·tcp/ip·http
w_t_y_y2 小时前
http通信鉴权(三)基于 Session + CSRF Token 的 Cookie 认证
网络协议·http·csrf
xiangxiongfly9152 小时前
Node http
http·node·文件上传·请求·文件下载·响应
马达加斯加D3 小时前
Web系统设计 --- HTTP + GraphQL
前端·http·graphql
源远流长jerry19 小时前
http协议和https协议的连接流程
网络·http·https
松涛和鸣20 小时前
44、HTML与HTTP服务器交互笔记
linux·运维·服务器·http·链表·html
源远流长jerry21 小时前
DNS解析过程以及CDN流程
http·缓存
REDcker1 天前
WebRTC-HTTP 出口协议 (WHEP) draft-murillo-whep-01 中文翻译
网络协议·http·webrtc
源远流长jerry1 天前
HTTP 1.x ~ HTTP 3 完整详解
网络·网络协议·http
松涛和鸣1 天前
DAY 44 HTML and HTTP Server Interaction Notes
linux·前端·网络·数据库·http·sqlite·html