package app.hongs.serv.common;

import app.hongs.action.ActionDriver.FilterCheck;
import app.hongs.util.Synt;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 跨站攻击拦截
 * @author Hongs
 */
public class XsrfFilter implements Filter {

    private static final Pattern DOMAIN = Pattern.compile("^(?:\\w+\\:)?//(.+?)(?:\\:\\d+)?/");

    private String      inside = null; // 过滤器标识
    private FilterCheck ignore = null; // 待忽略用例

    @Override
    public void init(FilterConfig fc) throws ServletException {
        inside = XsrfFilter.class.getName()+":"+fc.getFilterName()+":INSIDE";
        ignore = new FilterCheck(
            fc.getInitParameter("ignore-urls"),
            fc.getInitParameter("attend-urls")
        );
    }

    @Override
    public void doFilter(ServletRequest rxq, ServletResponse rxp, FilterChain fc) throws IOException, ServletException {
        HttpServletRequest  req = (HttpServletRequest ) rxq;
        HttpServletResponse rsp = (HttpServletResponse) rxp;

        /**
         * 对于嵌套相同过滤, 不在内部重复执行;
         * 如外部设置了忽略, 则跳过忽略的路径.
         */
        if (inside != null &&  Synt.declare(req.getAttribute(inside), false)
        ||  ignore != null && ignore.ignore(req.getServletPath() ) ) {
            fc.doFilter(req, rsp);
            return;
        }

        // 如果有 X-Requested-With 表示请求来自 AJAX 或 APP
        String ret = req.getHeader("X-Requested-With" );
        if (ret != null && ret.length() != 0) {
            try {
                req.setAttribute(inside,true);
                fc.doFilter(rxq, rxp);
            } finally {
                req.removeAttribute( inside );
            }
            return;
        }

        // 提取到 Referer 并与当前请求的 URL 比对来判断同域
        String ref = req.getHeader("Referer");
        String dmn = req.getServerName();
        Matcher ma = DOMAIN.matcher(ref);
        if (ma.find(  ) && ma.group( 1 ).equals( dmn )) {
            try {
                req.setAttribute(inside,true);
                fc.doFilter(rxq, rxp);
            } finally {
                req.removeAttribute( inside );
            }
            return;
        }

        rsp.setStatus(HttpServletResponse.SC_FORBIDDEN);
        rsp.getWriter().print("XSRF Access Forbidden!");
    }

    @Override
    public void destroy() {
        // Nothing todo.
    }

}

@@ -2140,19 +2140,66 @@
 verName(
+ 
 );%0A
+        if (ref != null && dmn != null) %7B%0A    
         
@@ -2208,16 +2208,17 @@
 tcher ma
+t
  = DOMAI
@@ -2245,29 +2245,33 @@
     
+   
+ 
 if (ma
+t
 .find(
- 
  ) && ma
 .gro
@@ -2270,18 +2270,17 @@
 & ma
+t
 .group(
- 1 
+1
 ).eq
@@ -2288,18 +2288,20 @@
 als(
- 
 dmn
- 
 )) %7B%0A
+    
     
@@ -2322,32 +2322,36 @@
                 
+ 
+   
 req.setAttribute
@@ -2373,32 +2373,36 @@
                 
+   
+ 
 fc.doFilter(rxq,
@@ -2412,32 +2412,36 @@
 p);%0A            
+    
 %7D finally %7B%0A    
@@ -2444,32 +2444,36 @@
                 
+ 
+   
 req.removeAttrib
@@ -2491,34 +2491,42 @@
  );%0A            
-%7D%0A
+    %7D%0A    
             retu
@@ -2521,32 +2521,46 @@
         return;%0A
+            %7D%0A
         %7D%0A%0A     

修复 null 问题