package com.hotent.base.request;

import com.hotent.base.enums.ResponseErrorEnums;
import com.hotent.base.exception.BaseException;
import com.hotent.base.util.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * sql注入
 */
public class SqlInjectHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public static final Logger log = LoggerFactory.getLogger(SqlInjectHttpServletRequestWrapper .class);
    /**
     * 存储body数据的容器
     */
    private final byte[] body;

    /**
     * 构造请求对象
     *
     * @param request
     */
    public SqlInjectHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        // 将body数据存储起来
        body = getBodyString(request).getBytes(Charset.defaultCharset());
    }

    /**
     * 获取请求Body
     *
     * @param request request
     * @return String
     */
    public String getBodyString(final ServletRequest request) {
        try {
            return inputStream2String(request.getInputStream());
        } catch (IOException e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取头部参数
     *
     * @param v 参数值
     */
    @Override
    public String getHeader(String v) {
        String header = super.getHeader(v);
        if (header == null || "".equals(header)) {
            return header;
        }
        return sqlFilter(header);
    }
    /**
     * 获取参数
     *
     * @param v 参数值
     */
    @Override
    public String getParameter(String v) {
        String param = super.getParameter(v);
        if (param == null || "".equals(param)) {
            return param;
        }
        return sqlFilter(param);
    }
    /**
     * 获取参数值
     *
     * @param v 参数值
     */
    @Override
    public String[] getParameterValues(String v) {
        String[] values = super.getParameterValues(v);
        if (values == null) {
            return values;
        }
        int length = values.length;
        String[] resultValues = new String[length];
        for (int i = 0; i < length; i++) {
            // 过滤特殊字符
            resultValues[i] = sqlFilter(values[i]);
            if (!(resultValues[i]).equals(values[i])) {
                log.debug("SQL注入过滤器 => 过滤前：{} => 过滤后：{}", values[i], resultValues[i]);
            }
        }
        return resultValues;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException{
        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);

        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return inputStream.read();
            }

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

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

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

    /**
     * 预编译SQL过滤正则表达式
     */
    private Pattern sqlPattern = Pattern.compile(
            "(?:\\.\\.)|(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select |update |delete |insert |trancate |char|into|substr|ascii|declare|exec|count|master|into|drop |execute)\\b)",
            Pattern.CASE_INSENSITIVE);
    /**
     * SQL过滤
     *
     * @param v 参数值
     * @return
     */
    private String sqlFilter(String v) {
        if (v != null) {
            String resultVal = v;
//            Matcher matcher = sqlPattern.matcher(resultVal);
//            if (matcher.find()) {
//                throw new BaseException(ResponseErrorEnums.SQL_INJECT);
//            }
//            if (!resultVal.equals(v)) {
//                return "";
//            }
            return resultVal;
        }
        return null;
    }

    /**
     * 将inputStream里的数据读取出来并转换成字符串
     *
     * @param inputStream inputStream
     * @return String
     */
    private String inputStream2String(InputStream inputStream) {
        String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
                .parallel().collect(Collectors.joining("\n"));
        sqlFilter(result);
        //上传过滤注释掉
        return result;
    }
}
