package org.nutz.mvc; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.nutz.filepool.UU32FilePool; import org.nutz.lang.Each; import org.nutz.lang.Lang; import org.nutz.lang.Mirror; import org.nutz.lang.util.NutMap; import org.nutz.log.LogAdapter; import org.nutz.log.Logs; import org.nutz.mvc.upload.FastUploading; import org.nutz.mvc.upload.TempFile; import org.nutz.mvc.upload.UploadException; import org.nutz.mvc.upload.UploadingContext; public class WhaleFilter implements Filter { protected Properties props = new Properties(); protected String inputEnc; protected String outputEnc; protected String methodParam; protected boolean allowHTTPMethodOverride; protected boolean uploadEnable; private static WhaleFilter _me; protected ServletContext sc; protected Object uc; public static WhaleFilter me() { return _me; } public void init(FilterConfig c) throws ServletException { sc = c.getServletContext(); _me = this; try { String path = c.getInitParameter("config-file"); if (path != null) { InputStream ins = getClass().getClassLoader().getResourceAsStream(path); if (ins == null) ins = c.getServletContext().getResourceAsStream(path); if (ins == null) { throw new ServletException("config-file=" + path + " not found"); } init(ins); } else { String config = c.getInitParameter("config"); if (config != null) { init(new ByteArrayInputStream(config.getBytes())); } } } catch (Exception e) { throw new ServletException(e); } } public void init(InputStream ins) throws Exception { props.load(ins); if (props.contains("log.adapter")) { LogAdapter la = (LogAdapter) Class.forName(props.getProperty("log.adapter")).newInstance(); Logs.setAdapter(la); } inputEnc = props.getProperty("enc.input"); outputEnc = props.getProperty("enc.output"); methodParam = props.getProperty("http.hidden_method_param"); allowHTTPMethodOverride = "true".equals(props.getProperty("http.method_override")); uploadEnable = "true".equals(props.getProperty("upload.enable")); if (uploadEnable) { String tmpPath = props.getProperty("upload.tmpdir", System.getProperty("java.io.tmpdir") + "/whale"); UU32FilePool fp = new UU32FilePool(tmpPath); UploadingContext uc = new UploadingContext(fp); Mirror<UploadingContext> mirror = Mirror.me(uc); for (Object _key : props.keySet()) { String key = _key.toString(); if (!key.startsWith("upload.")) { continue; } key = key.substring("upload.".length()); if ("tmpdir".equals(key) || "exclusions".equals(key)) { continue; } mirror.setValue(uc, key, props.get(_key)); } this.uc = uc; } } @SuppressWarnings("unchecked") @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { final HttpServletRequest req = (HttpServletRequest) request; final HttpServletResponse resp = (HttpServletResponse) response; // 设置req的编码 if (inputEnc != null) req.setCharacterEncoding(inputEnc); // 设置resp的编码 if (outputEnc != null) resp.setCharacterEncoding(outputEnc); // 如果是POST请求,有很多可以hack的东西 if ("POST".equals(req.getMethod())) { // 处理隐藏HTTP METHOD, _method参数模式 if (methodParam != null) { String qs = req.getQueryString(); if (qs != null && qs.contains("_method=")) { final NutMap map = Mvcs.toParamMap(new StringReader(qs), inputEnc == null ? Charset.defaultCharset().name() : inputEnc); request = new HttpServletRequestWrapper(req) { public String getMethod() { return map.getString(methodParam); } }; } } // 处理 X-HTTP-Method-Override else if (allowHTTPMethodOverride && req.getHeader("X-HTTP-Method-Override") != null) { request = new HttpServletRequestWrapper(req) { public String getMethod() { return req.getHeader("X-HTTP-Method-Override"); } }; } // 处理文件上传 String contentType = req.getContentType(); if (contentType != null) { if (uc != null && contentType.contains("multipart/form-data")) { request = handleUpload(req); } } } try { chain.doFilter(request, response); } finally { try { List<TempFile> files = (List<TempFile>) req.getAttribute("_files"); if (files != null) { for (TempFile tf : files) { if (tf != null) tf.delete(); } } } catch (Exception e) { } } } public void destroy() {} @SuppressWarnings("unchecked") public HttpServletRequest handleUpload(HttpServletRequest req) throws ServletException { try { FastUploading fup = new FastUploading(); final Map<String, Object> params = fup.parse(req, (UploadingContext) uc); final List<TempFile> files = new ArrayList<TempFile>(); Iterator<Entry<String, Object>> it = params.entrySet().iterator(); while (it.hasNext()) { Object obj = it.next().getValue(); final boolean[] re = new boolean[1]; Lang.each(obj, new Each<Object>() { public void invoke(int index, Object ele, int length){ if (ele != null && ele instanceof TempFile) { files.add((TempFile) ele); re[0] = true; } } }); if (re[0]) it.remove(); } req.setAttribute("_files", files); params.putAll(req.getParameterMap()); return new HttpServletRequestWrapper(req) { public String getParameter(String name) { return (String) params.get(name); } @SuppressWarnings("rawtypes") public Map getParameterMap() { return params; } @SuppressWarnings("rawtypes") public Enumeration getParameterNames() { return Collections.enumeration(params.keySet()); } public String[] getParameterValues(String name) { if (params.containsKey(name)) return new String[]{(String) params.get(name)}; return null; } }; } catch (UploadException e) { throw new ServletException("upload fail", e); } } }