package chat.upload; import java.io.File; import java.io.RandomAccessFile; import java.text.SimpleDateFormat; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import chat.security.DES; import chat.server.im.ResultPool; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.multipart.Attribute; import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import io.netty.handler.codec.http.multipart.FileUpload; import io.netty.handler.codec.http.multipart.HttpDataFactory; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.util.internal.StringUtil; public class UploadFile { private static final String KEY = "imfile"; private static final Logger logger = LoggerFactory.getLogger(UploadFile.class); private static final HttpDataFactory factory = new DefaultHttpDataFactory(false); public static String multipartUpload(FullHttpRequest request, String requestId) { HttpPostRequestDecoder decoder = null; String key = ""; try { decoder = new HttpPostRequestDecoder(factory, request); } catch (Exception e) { logger.error("Failed to decode file data!", e); e.printStackTrace(); return ""; } if (decoder != null) { if (request instanceof HttpContent) { HttpContent chunk = (HttpContent) request; try { decoder.offer(chunk); } catch (Exception e) { e.printStackTrace(); return ""; } long fileTotalSize = 0; if (request.headers().contains("X-File-Total-Size")) { try { fileTotalSize = Integer.parseInt(request.headers().get("X-File-Total-Size")); } catch (Exception e) { logger.warn("invalid X-File-Total-Size value!"); } } UploadFile uploadFile = new UploadFile(); key = uploadFile.readHttpDataChunkByChunk(decoder, requestId, HttpHeaders.isKeepAlive(request)); } } return key; } private String readHttpDataChunkByChunk(HttpPostRequestDecoder decoder, String requestId, boolean isKeepAlive) { String returnValue = ""; try { int[] bucket = new int[1]; bucket[0] = -1; while (decoder.hasNext()) { InterfaceHttpData data = decoder.next(); if (data != null) { try { returnValue = writeFileUploadData(data, requestId, isKeepAlive, bucket); if (returnValue == null) { break; } } finally { data.release(); } } } } catch(Exception e) { logger.info("chunk end"); return returnValue; //e.printStackTrace(); } return returnValue; } private String writeFileUploadData(InterfaceHttpData data, String requestId, boolean isKeepAlive, int[] bucket) { String relativePath = ""; try { if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) { FileUpload fileUpload = (FileUpload) data; String remoteFileName = fileUpload.getFilename(); long remoteFileSize = fileUpload.length(); if(bucket[0] == -1) { logger.info("Not authenticated!"); return null; } if (StringUtil.isNullOrEmpty(remoteFileName)) { logger.info("remoteFileName is empty!"); return null; } if (StringUtil.isNullOrEmpty(requestId)) { logger.info("requestId is empty!"); return null; } if (remoteFileSize > 100 * 1024 * 1024) { logger.info("file over limit!(" + remoteFileSize + ")"); return null; } String remoteFileExt = ""; if (remoteFileName.lastIndexOf(".") == -1) { remoteFileExt = "octetstream"; remoteFileName = remoteFileName + "." + remoteFileExt; } else { remoteFileExt = getFileExt(remoteFileName); } if (StringUtil.isNullOrEmpty(remoteFileExt) || remoteFileExt.equals("ing")) { logger.info("Invalid file extention name"); return null; } int remoteFileTotalSize = (int) remoteFileSize; ByteBuf byteBuf = null; int savedThunkSize = 0; int offset = 0; Date nowTime = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/HH"); String datePath = sdf.format(nowTime); datePath = "fs/" + bucket[0] + "/" + datePath; String dir = "D:/media/" + datePath; File dirFile = new File(dir); if (!dirFile.exists()) { if (!dirFile.mkdirs()) { logger.info("无法创建文件"); return null; } } String filePath = dir + "/" + (StringUtil.isNullOrEmpty(remoteFileName) ? requestId : remoteFileName); File tmpFile = new File(filePath); boolean isError = false; while (true) { byte[] thunkData; try { byteBuf = fileUpload.getChunk(128 * 1024); int readableBytesSize = byteBuf.readableBytes(); thunkData = new byte[readableBytesSize]; byteBuf.readBytes(thunkData); put(tmpFile, offset, thunkData); savedThunkSize += readableBytesSize; offset += readableBytesSize; if (savedThunkSize >= remoteFileSize) { byteBuf.release(); fileUpload.release(); relativePath = datePath + "/" + (StringUtil.isNullOrEmpty(remoteFileName) ? requestId : remoteFileName); break; } } catch(Exception e) { logger.info("save thunckData error!"); if (fileUpload != null) { fileUpload.release(); } if (byteBuf != null) { byteBuf.release(); } isError = true; return null; } finally { thunkData = null; if (isError) { tmpFile.delete(); } } } } else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) { Attribute attribute = (Attribute) data; if (attribute.getName().equals("token")) { String token = attribute.getValue(); try { bucket[0] = validateToken(token); relativePath = ""; } catch(Exception e) { logger.info("无效的token!"); return null; } } } } catch(Exception e) { logger.info("writeHttpData error!", e); return null; } return relativePath; } public String getFileExt(String fileName) { int index = fileName.lastIndexOf("."); if (index == -1) { return ""; } return fileName.substring(index + 1).toLowerCase(); } public void put(File file, long pos, byte[] data) throws Exception { RandomAccessFile raf = null; try { raf = new RandomAccessFile(file, "rwd"); raf.seek(pos); raf.write(data); } finally { try { if (raf != null) { raf.close(); } } catch (Exception e) { logger.info("release error!"); e.printStackTrace(); } } } public int validateToken(String token) throws InvalidateTokenExecption { try { String signKey = DES.decryptDES(token); String[] parts = signKey.split("\\|"); if(parts.length == 3) { if(parts[0].equals(KEY)) { long timestamp = Long.parseLong(parts[1]); if(Math.abs(System.currentTimeMillis() - timestamp) < 2 * 60 * 60 * 1000) { return Integer.parseInt(parts[2]); } } } } catch (Exception e) { e.printStackTrace(); } throw new InvalidateTokenExecption(); } public static class InvalidateTokenExecption extends Exception {} }