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