/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 de.rgielen.struts1.filter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

/**
 * ParamWrapperFilter.
 *
 * @author Alvaro Munoz, HP Fortify Team
 * @author Rene Gielen, Apache Struts Team
 */
public class ParamWrapperFilter implements Filter {

    private static final Log LOG = LogFactory.getLog(ParamWrapperFilter.class);

    private static final String DEFAULT_BLACKLIST_PATTERN = "(.*\\.|^|.*|\\[('|\"))(c|C)lass(\\.|('|\")]|\\[).*";
    private static final String INIT_PARAM_NAME = "excludeParams";

    private Pattern pattern;

    public void init( FilterConfig filterConfig ) throws ServletException {
        final String toCompile;
        final String initParameter = filterConfig.getInitParameter(INIT_PARAM_NAME);
        if (initParameter != null && initParameter.trim().length()>0) {
            toCompile = initParameter;
        } else {
            toCompile = DEFAULT_BLACKLIST_PATTERN;
        }
        this.pattern = Pattern.compile(toCompile, Pattern.DOTALL);
    }

    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
            throws IOException, ServletException {

        ParamFilteredRequest wrapper = null;
        if (request instanceof HttpServletRequest)
            wrapper = new ParamFilteredRequest(request, pattern);

        if (wrapper != null)
            chain.doFilter(wrapper,response);
        else
            chain.doFilter(request,response);
    }

    public void destroy() {
    }

    static class ParamFilteredRequest extends HttpServletRequestWrapper {

        private static final int BUFFER_SIZE = 128;
        private static final String CONTENT_LENGTH_PATTERN = "(?i)content-length";

        private final String body;
        private final Pattern pattern;
        private final Pattern content_length_pattern;
        private boolean read_stream = false;

        public ParamFilteredRequest( ServletRequest request, Pattern pattern ) {
            super((HttpServletRequest) request);
            this.pattern = pattern;
            this.content_length_pattern = Pattern.compile(CONTENT_LENGTH_PATTERN, Pattern.DOTALL);


            StringBuilder stringBuilder = new StringBuilder();
            BufferedReader bufferedReader = null;

            try {
                InputStream inputStream = request.getInputStream();

                if (inputStream != null) {
                    String characterEncoding = this.getCharacterEncoding();
                    if (characterEncoding == null ) {
                        bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    }
                    else {
                        bufferedReader = new BufferedReader(new InputStreamReader(inputStream, characterEncoding));
                    }
                    char[] charBuffer = new char[BUFFER_SIZE];
                    int bytesRead = -1;

                    while ( (bytesRead = bufferedReader.read(charBuffer)) > 0 ) {
                        stringBuilder.append(charBuffer, 0, bytesRead);
                    }
                } else {
                    stringBuilder.append("");
                }
            } catch ( IOException ex ) {
                logCatchedException(ex);
            } finally {
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch ( IOException ex ) {
                        logCatchedException(ex);
                    }
                }
            }
            body = stringBuilder.toString();
        }

        @Override
        public Enumeration getParameterNames() {
            List finalParameterNames = new ArrayList();
            List parameterNames = Collections.list((Enumeration) super.getParameterNames());
            final Iterator iterator = parameterNames.iterator();
            while ( iterator.hasNext() ) {
                String parameterName = (String) iterator.next();
                if (!pattern.matcher(parameterName).matches()) {
                    finalParameterNames.add(parameterName);
                }
            }
            return Collections.enumeration(finalParameterNames);
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (LOG.isTraceEnabled()) {
                LOG.trace(body);
            }
            final ByteArrayInputStream byteArrayInputStream;
            if (pattern.matcher(body).matches()) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn("[getInputStream]: found body to match blacklisted parameter pattern");
                }
                byteArrayInputStream = new ByteArrayInputStream("".getBytes());
            } else if (read_stream) {
                byteArrayInputStream = new ByteArrayInputStream("".getBytes());
            } else {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("[getInputStream]: OK - body does not match blacklisted parameter pattern");
                }
                byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
                read_stream = true;
            }

            return new ServletInputStream() {
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
            };
        }

        @Override
        public String getHeader(String name) {
            if (pattern.matcher(body).matches() && content_length_pattern.matcher(name).matches()) {
                return "0";
            }
            return super.getHeader(name);
        }

        @Override
        public int getContentLength() {
            if (pattern.matcher(body).matches()) {
                return 0;
            }
            return super.getContentLength();
        }

        private void logCatchedException( IOException ex ) {
            LOG.error("[ParamFilteredRequest]: Exception catched: ", ex);
        }


    }
}

@@ -808,18 +808,19 @@
 package 
-de
+net
 .rgielen
@@ -1437,50 +1437,8 @@
 er;%0A
-import java.nio.charset.StandardCharsets;%0A
 impo

fix package name