/* * Copyright (c) www.bugull.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.tooan.ynpay.third.mongodb.fs; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.gridfs.GridFSDBFile; import net.tooan.ynpay.third.jfinal.log.Logger; import net.tooan.ynpay.third.mongodb.mapper.StreamUtil; import net.tooan.ynpay.third.mongodb.mapper.StringUtil; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; /** * A convenient Servlet for getting a file from GridFS via http. * * @author Frank Wen(xbwen@hotmail.com) */ public class UploadedFileServlet extends HttpServlet { private final static Logger logger = Logger.getLogger(UploadedFileServlet.class); private final static String SLASH = "/"; private String allowBucket; private String forbidBucket; @Override public void init(ServletConfig config) throws ServletException { super.init(config); allowBucket = config.getInitParameter("allowBucket"); forbidBucket = config.getInitParameter("forbidBucket"); if (!StringUtil.isEmpty(allowBucket) && !StringUtil.isEmpty(forbidBucket)) { throw new ServletException("You can set only one param between allowBucket and forbidBucket."); } } protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String url = request.getRequestURI(); int second = url.indexOf(SLASH, 1); url = url.substring(second); int last = url.lastIndexOf(SLASH); String filename = url.substring(last + 1); DBObject query = new BasicDBObject(BuguFS.FILENAME, filename); query.put(ImageUploader.DIMENSION, null); String bucketName = BuguFS.DEFAULT_BUCKET; int first = url.indexOf(SLASH); if (first != last) { String sub = url.substring(first + 1, last); String[] arr = sub.split(SLASH); for (int i = 0; i < arr.length; i += 2) { if (arr[i].equals(BuguFS.BUCKET)) { bucketName = arr[i + 1]; } else { query.put(arr[i], arr[i + 1]); } } } //check if the bucket is allowed to access by this servlet if (!StringUtil.isEmpty(allowBucket) && !allowBucket.equalsIgnoreCase(bucketName)) { return; } if (!StringUtil.isEmpty(forbidBucket) && forbidBucket.equalsIgnoreCase(bucketName)) { return; } BuguFS fs = new BuguFS(bucketName); GridFSDBFile f = fs.findOne(query); if (f == null) { return; } OutputStream os = response.getOutputStream(); int fileLength = (int) f.getLength(); String ext = StringUtil.getExtention(filename); response.setContentType(getContentType(ext)); String range = request.getHeader("Range"); //normal http request, no "range" in header. if (StringUtil.isEmpty(range)) { response.setStatus(HttpServletResponse.SC_OK); response.setContentLength(fileLength); if (needCache(ext)) { String modifiedSince = request.getHeader("If-Modified-Since"); DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); df.setTimeZone(TimeZone.getTimeZone("GMT")); Date uploadDate = f.getUploadDate(); String lastModified = df.format(uploadDate); if (modifiedSince != null) { Date modifiedDate = null; Date sinceDate = null; try { modifiedDate = df.parse(lastModified); sinceDate = df.parse(modifiedSince); } catch (ParseException ex) { logger.error("Can not parse the Date", ex); } if (modifiedDate.compareTo(sinceDate) <= 0) { response.setStatus(304); //Not Modified return; } } long maxAge = 365L * 24L * 60L * 60L; //one year, in seconds response.setHeader("Cache-Control", "max-age=" + maxAge); response.setHeader("Last-Modified", lastModified); response.setDateHeader("Expires", uploadDate.getTime() + maxAge * 1000L); } else { response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); } f.writeTo(os); } //has "range" in header else { range = range.substring("bytes=".length()); if (StringUtil.isEmpty(range)) { return; } int begin = 0; int end = fileLength - 1; String[] rangeArray = range.split("-"); if (rangeArray.length == 1) { begin = Integer.parseInt(rangeArray[0]); } else if (rangeArray.length == 2) { begin = Integer.parseInt(rangeArray[0]); end = Integer.parseInt(rangeArray[1]); } response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); int contentLength = end - begin + 1; response.setContentLength(contentLength); response.setHeader("Content-Range", "bytes " + begin + "-" + end + "/" + contentLength); InputStream is = f.getInputStream(); is.skip(begin); int read = -1; int bufferSize = (int) f.getChunkSize(); byte[] buffer = new byte[bufferSize]; int remain = contentLength; int readSize = Math.min(bufferSize, remain); while ((read = is.read(buffer, 0, readSize)) != -1) { os.write(buffer, 0, read); remain -= read; if (remain <= 0) { break; } readSize = Math.min(bufferSize, remain); } StreamUtil.safeClose(is); } StreamUtil.safeClose(os); } /** * If it's an image file, cache it in browser * * @param ext * @return */ private boolean needCache(String ext) { if (StringUtil.isEmpty(ext)) { return false; } ext = ext.toLowerCase(); boolean need = false; String[] arr = {"jpg", "jpeg", "png", "gif", "bmp"}; for (String s : arr) { if (s.equals(ext)) { need = true; break; } } return need; } private String getContentType(String ext) { if (StringUtil.isEmpty(ext)) { return "application/octet-stream"; } ext = ext.toLowerCase(); String type = "application/octet-stream"; if (ext.equals("jpg")) { type = "image/jpeg"; } else if (ext.equals("jpeg") || ext.equals("png") || ext.equals("gif") || ext.equals("bmp")) { type = "image/" + ext; } else if (ext.equals("swf")) { type = "application/x-shockwave-flash"; } else if (ext.equals("flv")) { type = "video/x-flv"; } else if (ext.equals("mp3")) { type = "audio/mpeg"; } else if (ext.equals("mp4")) { type = "video/mp4"; } else if (ext.equals("3gp")) { type = "video/3gpp"; } else if (ext.equals("pdf")) { type = "application/pdf"; } else if (ext.equals("html") || ext.equals("htm")) { type = "text/html"; } return type; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } }