001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.filter;
018
019import java.io.IOException;
020import javax.servlet.FilterChain;
021import javax.servlet.ServletException;
022import javax.servlet.http.HttpServletRequest;
023import javax.servlet.http.HttpServletResponse;
024
025import org.springframework.util.Assert;
026
027/**
028 * Servlet Filter that allows one to specify a character encoding for requests.
029 * This is useful because current browsers typically do not set a character
030 * encoding even if specified in the HTML page or form.
031 *
032 * <p>This filter can either apply its encoding if the request does not already
033 * specify an encoding, or enforce this filter's encoding in any case
034 * ("forceEncoding"="true"). In the latter case, the encoding will also be
035 * applied as default response encoding (although this will usually be overridden
036 * by a full content type set in the view).
037 *
038 * @author Juergen Hoeller
039 * @since 15.03.2004
040 * @see #setEncoding
041 * @see #setForceEncoding
042 * @see javax.servlet.http.HttpServletRequest#setCharacterEncoding
043 * @see javax.servlet.http.HttpServletResponse#setCharacterEncoding
044 */
045public class CharacterEncodingFilter extends OncePerRequestFilter {
046
047        private String encoding;
048
049        private boolean forceRequestEncoding = false;
050
051        private boolean forceResponseEncoding = false;
052
053
054        /**
055         * Create a default {@code CharacterEncodingFilter},
056         * with the encoding to be set via {@link #setEncoding}.
057         * @see #setEncoding
058         */
059        public CharacterEncodingFilter() {
060        }
061
062        /**
063         * Create a {@code CharacterEncodingFilter} for the given encoding.
064         * @param encoding the encoding to apply
065         * @since 4.2.3
066         * @see #setEncoding
067         */
068        public CharacterEncodingFilter(String encoding) {
069                this(encoding, false);
070        }
071
072        /**
073         * Create a {@code CharacterEncodingFilter} for the given encoding.
074         * @param encoding the encoding to apply
075         * @param forceEncoding whether the specified encoding is supposed to
076         * override existing request and response encodings
077         * @since 4.2.3
078         * @see #setEncoding
079         * @see #setForceEncoding
080         */
081        public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
082                this(encoding, forceEncoding, forceEncoding);
083        }
084
085        /**
086         * Create a {@code CharacterEncodingFilter} for the given encoding.
087         * @param encoding the encoding to apply
088         * @param forceRequestEncoding whether the specified encoding is supposed to
089         * override existing request encodings
090         * @param forceResponseEncoding whether the specified encoding is supposed to
091         * override existing response encodings
092         * @since 4.3
093         * @see #setEncoding
094         * @see #setForceRequestEncoding(boolean)
095         * @see #setForceResponseEncoding(boolean)
096         */
097        public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
098                Assert.hasLength(encoding, "Encoding must not be empty");
099                this.encoding = encoding;
100                this.forceRequestEncoding = forceRequestEncoding;
101                this.forceResponseEncoding = forceResponseEncoding;
102        }
103
104
105        /**
106         * Set the encoding to use for requests. This encoding will be passed into a
107         * {@link javax.servlet.http.HttpServletRequest#setCharacterEncoding} call.
108         * <p>Whether this encoding will override existing request encodings
109         * (and whether it will be applied as default response encoding as well)
110         * depends on the {@link #setForceEncoding "forceEncoding"} flag.
111         */
112        public void setEncoding(String encoding) {
113                this.encoding = encoding;
114        }
115
116        /**
117         * Return the configured encoding for requests and/or responses.
118         * @since 4.3
119         */
120        public String getEncoding() {
121                return this.encoding;
122        }
123
124        /**
125         * Set whether the configured {@link #setEncoding encoding} of this filter
126         * is supposed to override existing request and response encodings.
127         * <p>Default is "false", i.e. do not modify the encoding if
128         * {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()}
129         * returns a non-null value. Switch this to "true" to enforce the specified
130         * encoding in any case, applying it as default response encoding as well.
131         * <p>This is the equivalent to setting both {@link #setForceRequestEncoding(boolean)}
132         * and {@link #setForceResponseEncoding(boolean)}.
133         * @see #setForceRequestEncoding(boolean)
134         * @see #setForceResponseEncoding(boolean)
135         */
136        public void setForceEncoding(boolean forceEncoding) {
137                this.forceRequestEncoding = forceEncoding;
138                this.forceResponseEncoding = forceEncoding;
139        }
140
141        /**
142         * Set whether the configured {@link #setEncoding encoding} of this filter
143         * is supposed to override existing request encodings.
144         * <p>Default is "false", i.e. do not modify the encoding if
145         * {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()}
146         * returns a non-null value. Switch this to "true" to enforce the specified
147         * encoding in any case.
148         * @since 4.3
149         */
150        public void setForceRequestEncoding(boolean forceRequestEncoding) {
151                this.forceRequestEncoding = forceRequestEncoding;
152        }
153
154        /**
155         * Return whether the encoding should be forced on requests
156         * @since 4.3
157         */
158        public boolean isForceRequestEncoding() {
159                return this.forceRequestEncoding;
160        }
161
162        /**
163         * Set whether the configured {@link #setEncoding encoding} of this filter
164         * is supposed to override existing response encodings.
165         * <p>Default is "false", i.e. do not modify the encoding.
166         * Switch this to "true" to enforce the specified encoding
167         * for responses in any case.
168         * @since 4.3
169         */
170        public void setForceResponseEncoding(boolean forceResponseEncoding) {
171                this.forceResponseEncoding = forceResponseEncoding;
172        }
173
174        /**
175         * Return whether the encoding should be forced on responses.
176         * @since 4.3
177         */
178        public boolean isForceResponseEncoding() {
179                return this.forceResponseEncoding;
180        }
181
182
183        @Override
184        protected void doFilterInternal(
185                        HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
186                        throws ServletException, IOException {
187
188                String encoding = getEncoding();
189                if (encoding != null) {
190                        if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
191                                request.setCharacterEncoding(encoding);
192                        }
193                        if (isForceResponseEncoding()) {
194                                response.setCharacterEncoding(encoding);
195                        }
196                }
197                filterChain.doFilter(request, response);
198        }
199
200}