getAttributeNames() {
- return Collections.enumeration(new LinkedHashSet<>(this.attributes.keySet()));
- }
-
- @Override
- @Nullable
- public String getCharacterEncoding() {
- return this.characterEncoding;
- }
-
- @Override
- public void setCharacterEncoding(@Nullable String characterEncoding) {
- this.characterEncoding = characterEncoding;
- updateContentTypeHeader();
- }
-
- private void updateContentTypeHeader() {
- if (StringUtils.hasLength(this.contentType)) {
- String value = this.contentType;
- if (StringUtils.hasLength(this.characterEncoding)
- && !this.contentType.toLowerCase().contains(CHARSET_PREFIX)) {
- value += ';' + CHARSET_PREFIX + this.characterEncoding;
- }
- doAddHeaderValue(HttpHeaders.CONTENT_TYPE, value, true);
- }
- }
-
- /**
- * Set the content of the request body as a byte array.
- *
- * If the supplied byte array represents text such as XML or JSON, the
- * {@link #setCharacterEncoding character encoding} should typically be set as
- * well.
- *
- * @see #setCharacterEncoding(String)
- * @see #getContentAsByteArray()
- * @see #getContentAsString()
- */
- public void setContent(@Nullable byte[] content) {
- this.content = content;
- this.inputStream = null;
- this.reader = null;
- }
-
- /**
- * Get the content of the request body as a byte array.
- *
- * @return the content as a byte array (potentially {@code null})
- * @since 5.0
- * @see #setContent(byte[])
- * @see #getContentAsString()
- */
- @Nullable
- public byte[] getContentAsByteArray() {
- return this.content;
- }
-
- /**
- * Get the content of the request body as a {@code String}, using the configured
- * {@linkplain #getCharacterEncoding character encoding}.
- *
- * @return the content as a {@code String}, potentially {@code null}
- * @throws IllegalStateException if the character encoding has not been
- * set
- * @throws UnsupportedEncodingException if the character encoding is not
- * supported
- * @since 5.0
- * @see #setContent(byte[])
- * @see #setCharacterEncoding(String)
- * @see #getContentAsByteArray()
- */
- @Nullable
- public String getContentAsString() throws IllegalStateException, UnsupportedEncodingException {
- Assert.state(this.characterEncoding != null, "Cannot get content as a String for a null character encoding. "
- + "Consider setting the characterEncoding in the request.");
-
- if (this.content == null) {
- return null;
- }
- return new String(this.content, this.characterEncoding);
- }
-
- @Override
- public int getContentLength() {
- return (this.content != null ? this.content.length : -1);
- }
-
- @Override
- public long getContentLengthLong() {
- return getContentLength();
- }
-
- public void setContentType(@Nullable String contentType) {
- this.contentType = contentType;
- if (contentType != null) {
- try {
- MediaType mediaType = MediaType.parseMediaType(contentType);
- if (mediaType.getCharset() != null) {
- this.characterEncoding = mediaType.getCharset().name();
- }
- }
- catch (IllegalArgumentException ex) {
- // Try to get charset value anyway
- int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
- if (charsetIndex != -1) {
- this.characterEncoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length());
- }
- }
- updateContentTypeHeader();
- }
- }
-
- @Override
- @Nullable
- public String getContentType() {
- return this.contentType;
- }
-
- @Override
- public ServletInputStream getInputStream() {
- InputStream stream = new ByteArrayInputStream(this.content);
- return new ServletInputStream() {
-
- boolean finished = false;
-
- @Override
- public int read() throws IOException {
- int readByte = stream.read();
- if (readByte == -1) {
- finished = true;
- }
- return readByte;
- }
-
- @Override
- public void setReadListener(ReadListener readListener) {
- }
-
- @Override
- public boolean isReady() {
- return !finished;
- }
-
- @Override
- public boolean isFinished() {
- return finished;
- }
- };
- }
-
- /**
- * Set a single value for the specified HTTP parameter.
- *
- * If there are already one or more values registered for the given parameter
- * name, they will be replaced.
- */
- public void setParameter(String name, String value) {
- setParameter(name, new String[] { value });
- }
-
- /**
- * Set an array of values for the specified HTTP parameter.
- *
- * If there are already one or more values registered for the given parameter
- * name, they will be replaced.
- */
- public void setParameter(String name, String... values) {
- Assert.notNull(name, "Parameter name must not be null");
- this.parameters.put(name, values);
- }
-
- /**
- * Set all provided parameters replacing any existing values
- * for the provided parameter names. To add without replacing existing values,
- * use {@link #addParameters(java.util.Map)}.
- */
- public void setParameters(Map params) {
- Assert.notNull(params, "Parameter map must not be null");
- params.forEach((key, value) -> {
- if (value instanceof String) {
- setParameter(key, (String) value);
- }
- else if (value instanceof String[]) {
- setParameter(key, (String[]) value);
- }
- else {
- throw new IllegalArgumentException("Parameter map value must be single value " + " or array of type ["
- + String.class.getName() + "]");
- }
- });
- }
-
- /**
- * Add a single value for the specified HTTP parameter.
- *
- * If there are already one or more values registered for the given parameter
- * name, the given value will be added to the end of the list.
- */
- public void addParameter(String name, @Nullable String value) {
- addParameter(name, new String[] { value });
- }
-
- /**
- * Add an array of values for the specified HTTP parameter.
- *
- * If there are already one or more values registered for the given parameter
- * name, the given values will be added to the end of the list.
- */
- public void addParameter(String name, String... values) {
- Assert.notNull(name, "Parameter name must not be null");
- String[] oldArr = this.parameters.get(name);
- if (oldArr != null) {
- String[] newArr = new String[oldArr.length + values.length];
- System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
- System.arraycopy(values, 0, newArr, oldArr.length, values.length);
- this.parameters.put(name, newArr);
- }
- else {
- this.parameters.put(name, values);
- }
- }
-
- /**
- * Add all provided parameters without replacing any existing
- * values. To replace existing values, use
- * {@link #setParameters(java.util.Map)}.
- */
- public void addParameters(Map params) {
- Assert.notNull(params, "Parameter map must not be null");
- params.forEach((key, value) -> {
- if (value instanceof String) {
- addParameter(key, (String) value);
- }
- else if (value instanceof String[]) {
- addParameter(key, (String[]) value);
- }
- else {
- throw new IllegalArgumentException("Parameter map value must be single value " + " or array of type ["
- + String.class.getName() + "]");
- }
- });
- }
-
- /**
- * Remove already registered values for the specified HTTP parameter, if any.
- */
- public void removeParameter(String name) {
- Assert.notNull(name, "Parameter name must not be null");
- this.parameters.remove(name);
- }
-
- /**
- * Remove all existing parameters.
- */
- public void removeAllParameters() {
- this.parameters.clear();
- }
-
- @Override
- @Nullable
- public String getParameter(String name) {
- Assert.notNull(name, "Parameter name must not be null");
- String[] arr = this.parameters.get(name);
- return (arr != null && arr.length > 0 ? arr[0] : null);
- }
-
- @Override
- public Enumeration getParameterNames() {
- return Collections.enumeration(this.parameters.keySet());
- }
-
- @Override
- public String[] getParameterValues(String name) {
- Assert.notNull(name, "Parameter name must not be null");
- return this.parameters.get(name);
- }
-
- @Override
- public Map getParameterMap() {
- return Collections.unmodifiableMap(this.parameters);
- }
-
- @Override
- public String getProtocol() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getScheme() {
- throw new UnsupportedOperationException();
- }
-
- public void setServerName(String serverName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getServerName() {
- throw new UnsupportedOperationException();
- }
-
- public void setServerPort(int serverPort) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getServerPort() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public BufferedReader getReader() throws UnsupportedEncodingException {
- if (this.reader != null) {
- return this.reader;
- }
- else if (this.inputStream != null) {
- throw new IllegalStateException(
- "Cannot call getReader() after getInputStream() has already been called for the current request");
- }
-
- if (this.content != null) {
- InputStream sourceStream = new ByteArrayInputStream(this.content);
- Reader sourceReader = (this.characterEncoding != null)
- ? new InputStreamReader(sourceStream, this.characterEncoding)
- : new InputStreamReader(sourceStream);
- this.reader = new BufferedReader(sourceReader);
- }
- else {
- this.reader = EMPTY_BUFFERED_READER;
- }
- return this.reader;
- }
-
- public void setRemoteAddr(String remoteAddr) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getRemoteAddr() {
- return "proxy";
- }
-
- public void setRemoteHost(String remoteHost) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getRemoteHost() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setAttribute(String name, @Nullable Object value) {
- Assert.notNull(name, "Attribute name must not be null");
- if (value != null) {
- this.attributes.put(name, value);
- }
- else {
- this.attributes.remove(name);
- }
- }
-
- @Override
- public void removeAttribute(String name) {
- Assert.notNull(name, "Attribute name must not be null");
- this.attributes.remove(name);
- }
-
- /**
- * Clear all of this request's attributes.
- */
- public void clearAttributes() {
- this.attributes.clear();
- }
-
- /**
- * Add a new preferred locale, before any existing locales.
- *
- * @see #setPreferredLocales
- */
- public void addPreferredLocale(Locale locale) {
- Assert.notNull(locale, "Locale must not be null");
- this.locales.addFirst(locale);
- updateAcceptLanguageHeader();
- }
-
- /**
- * Set the list of preferred locales, in descending order, effectively replacing
- * any existing locales.
- *
- * @since 3.2
- * @see #addPreferredLocale
- */
- public void setPreferredLocales(List locales) {
- Assert.notEmpty(locales, "Locale list must not be empty");
- this.locales.clear();
- this.locales.addAll(locales);
- updateAcceptLanguageHeader();
- }
-
- private void updateAcceptLanguageHeader() {
- HttpHeaders headers = new HttpHeaders();
- headers.setAcceptLanguageAsLocales(this.locales);
- doAddHeaderValue(HttpHeaders.ACCEPT_LANGUAGE, headers.getFirst(HttpHeaders.ACCEPT_LANGUAGE), true);
- }
-
- /**
- * Return the first preferred {@linkplain Locale locale} configured in this mock
- * request.
- *
- * If no locales have been explicitly configured, the default, preferred
- * {@link Locale} for the server mocked by this request is
- * {@link Locale#ENGLISH}.
- *
- * In contrast to the Servlet specification, this mock implementation does
- * not take into consideration any locales specified via the
- * {@code Accept-Language} header.
- *
- * @see javax.servlet.ServletRequest#getLocale()
- * @see #addPreferredLocale(Locale)
- * @see #setPreferredLocales(List)
- */
- @Override
- public Locale getLocale() {
- return this.locales.getFirst();
- }
-
- /**
- * Return an {@linkplain Enumeration enumeration} of the preferred
- * {@linkplain Locale locales} configured in this mock request.
- *
- * If no locales have been explicitly configured, the default, preferred
- * {@link Locale} for the server mocked by this request is
- * {@link Locale#ENGLISH}.
- *
- * In contrast to the Servlet specification, this mock implementation does
- * not take into consideration any locales specified via the
- * {@code Accept-Language} header.
- *
- * @see javax.servlet.ServletRequest#getLocales()
- * @see #addPreferredLocale(Locale)
- * @see #setPreferredLocales(List)
- */
- @Override
- public Enumeration getLocales() {
- return Collections.enumeration(this.locales);
- }
-
- /**
- * Return {@code true} if the {@link #setSecure secure} flag has been set to
- * {@code true} or if the {@link #getScheme scheme} is {@code https}.
- *
- * @see javax.servlet.ServletRequest#isSecure()
- */
- @Override
- public boolean isSecure() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public RequestDispatcher getRequestDispatcher(String path) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- @Deprecated
- public String getRealPath(String path) {
- return this.servletContext.getRealPath(path);
- }
-
- public void setRemotePort(int remotePort) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getRemotePort() {
- throw new UnsupportedOperationException();
- }
-
- public void setLocalName(String localName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getLocalName() {
- throw new UnsupportedOperationException();
- }
-
- public void setLocalAddr(String localAddr) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getLocalAddr() {
- return "proxy";
- }
-
- public void setLocalPort(int localPort) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getLocalPort() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AsyncContext startAsync() {
- return startAsync(this, null);
- }
-
- @Override
- public AsyncContext startAsync(ServletRequest request, @Nullable ServletResponse response) {
- throw new UnsupportedOperationException();
- }
-
- public void setAsyncStarted(boolean asyncStarted) {
- this.asyncStarted = asyncStarted;
- }
-
- @Override
- public boolean isAsyncStarted() {
- return this.asyncStarted;
- }
-
- public void setAsyncSupported(boolean asyncSupported) {
- this.asyncSupported = asyncSupported;
- }
-
- @Override
- public boolean isAsyncSupported() {
- return this.asyncSupported;
- }
-
- public void setAsyncContext(@Nullable AsyncContext asyncContext) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- @Nullable
- public AsyncContext getAsyncContext() {
- return null;
- }
-
- public void setDispatcherType(DispatcherType dispatcherType) {
- this.dispatcherType = dispatcherType;
- }
-
- @Override
- public javax.servlet.DispatcherType getDispatcherType() {
- return this.dispatcherType;
- }
-
- public void setAuthType(@Nullable String authType) {
- this.authType = authType;
- }
-
- @Override
- @Nullable
- public String getAuthType() {
- return this.authType;
- }
-
- @Override
- @Nullable
- public Cookie[] getCookies() {
- return this.cookies;
- }
-
- /**
- * Add an HTTP header entry for the given name.
- *
- * While this method can take any {@code Object} as a parameter, it is
- * recommended to use the following types:
- *
- * - String or any Object to be converted using {@code toString()}; see
- * {@link #getHeader}.
- * - String, Number, or Date for date headers; see
- * {@link #getDateHeader}.
- * - String or Number for integer headers; see {@link #getIntHeader}.
- * - {@code String[]} or {@code Collection} for multiple values; see
- * {@link #getHeaders}.
- *
- *
- * @see #getHeaderNames
- * @see #getHeaders
- * @see #getHeader
- * @see #getDateHeader
- */
- public void addHeader(String name, Object value) {
- if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name) && !this.headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
- setContentType(value.toString());
- }
- else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(name)
- && !this.headers.containsKey(HttpHeaders.ACCEPT_LANGUAGE)) {
- try {
- HttpHeaders headers = new HttpHeaders();
- headers.add(HttpHeaders.ACCEPT_LANGUAGE, value.toString());
- List locales = headers.getAcceptLanguageAsLocales();
- this.locales.clear();
- this.locales.addAll(locales);
- if (this.locales.isEmpty()) {
- this.locales.add(Locale.ENGLISH);
- }
- }
- catch (IllegalArgumentException ex) {
- // Invalid Accept-Language format -> just store plain header
- }
- doAddHeaderValue(name, value, true);
- }
- else {
- doAddHeaderValue(name, value, false);
- }
- }
-
- private void doAddHeaderValue(String name, @Nullable Object value, boolean replace) {
- HeaderValueHolder header = this.headers.get(name);
- Assert.notNull(value, "Header value must not be null");
- if (header == null || replace) {
- header = new HeaderValueHolder();
- this.headers.put(name, header);
- }
- if (value instanceof Collection) {
- header.addValues((Collection>) value);
- }
- else if (value.getClass().isArray()) {
- header.addValueArray(value);
- }
- else {
- header.addValue(value);
- }
- }
-
- /**
- * Return the long timestamp for the date header with the given {@code name}.
- *
- * If the internal value representation is a String, this method will try to
- * parse it as a date using the supported date formats:
- *
- * - "EEE, dd MMM yyyy HH:mm:ss zzz"
- * - "EEE, dd-MMM-yy HH:mm:ss zzz"
- * - "EEE MMM dd HH:mm:ss yyyy"
- *
- *
- * @param name the header name
- * @see Section
- * 7.1.1.1 of RFC 7231
- */
- @Override
- public long getDateHeader(String name) {
- HeaderValueHolder header = this.headers.get(name);
- Object value = (header != null ? header.getValue() : null);
- if (value instanceof Date) {
- return ((Date) value).getTime();
- }
- else if (value instanceof Number) {
- return ((Number) value).longValue();
- }
- else if (value instanceof String) {
- return parseDateHeader(name, (String) value);
- }
- else if (value != null) {
- throw new IllegalArgumentException(
- "Value for header '" + name + "' is not a Date, Number, or String: " + value);
- }
- else {
- return -1L;
- }
- }
-
- private long parseDateHeader(String name, String value) {
- for (String dateFormat : DATE_FORMATS) {
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat, Locale.US);
- simpleDateFormat.setTimeZone(GMT);
- try {
- return simpleDateFormat.parse(value).getTime();
- }
- catch (ParseException ex) {
- // ignore
- }
- }
- throw new IllegalArgumentException("Cannot parse date value '" + value + "' for '" + name + "' header");
- }
-
- @Override
- @Nullable
- public String getHeader(String name) {
- HeaderValueHolder header = this.headers.get(name);
- return (header != null ? header.getStringValue() : null);
- }
-
- @Override
- public Enumeration getHeaders(String name) {
- HeaderValueHolder header = this.headers.get(name);
- return Collections.enumeration(header != null ? header.getStringValues() : new LinkedList<>());
- }
-
- @Override
- public Enumeration getHeaderNames() {
- return Collections.enumeration(this.headers.keySet());
- }
-
- @Override
- public int getIntHeader(String name) {
- HeaderValueHolder header = this.headers.get(name);
- Object value = (header != null ? header.getValue() : null);
- if (value instanceof Number) {
- return ((Number) value).intValue();
- }
- else if (value instanceof String) {
- return Integer.parseInt((String) value);
- }
- else if (value != null) {
- throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value);
- }
- else {
- return -1;
- }
- }
-
- public void setMethod(@Nullable String method) {
- this.method = method;
- }
-
- @Override
- @Nullable
- public String getMethod() {
- return this.method;
- }
-
- public void setPathInfo(@Nullable String pathInfo) {
- this.pathInfo = pathInfo;
- }
-
- @Override
- @Nullable
- public String getPathInfo() {
- return this.pathInfo;
- }
-
- @Override
- @Nullable
- public String getPathTranslated() {
- return (this.pathInfo != null ? getRealPath(this.pathInfo) : null);
- }
-
- public void setContextPath(String contextPath) {
- this.contextPath = contextPath;
- }
-
- @Override
- public String getContextPath() {
- return this.contextPath;
- }
-
- public void setQueryString(@Nullable String queryString) {
- this.queryString = queryString;
- }
-
- @Override
- @Nullable
- public String getQueryString() {
- return this.queryString;
- }
-
- public void setRemoteUser(@Nullable String remoteUser) {
- this.remoteUser = remoteUser;
- }
-
- @Override
- @Nullable
- public String getRemoteUser() {
- return this.remoteUser;
- }
-
- public void addUserRole(String role) {
- this.userRoles.add(role);
- }
-
- @Override
- public boolean isUserInRole(String role) {
- throw new UnsupportedOperationException();
- }
-
- public void setUserPrincipal(@Nullable Principal userPrincipal) {
- this.userPrincipal = userPrincipal;
- }
-
- @Override
- @Nullable
- public Principal getUserPrincipal() {
- return this.userPrincipal;
- }
-
- public void setRequestedSessionId(@Nullable String requestedSessionId) {
- this.requestedSessionId = requestedSessionId;
- }
-
- @Override
- @Nullable
- public String getRequestedSessionId() {
- return this.requestedSessionId;
- }
-
- public void setRequestURI(@Nullable String requestURI) {
- this.requestURI = requestURI;
- }
-
- @Override
- @Nullable
- public String getRequestURI() {
- return this.requestURI;
- }
-
- @Override
- public StringBuffer getRequestURL() {
- throw new UnsupportedOperationException();
- }
-
- public void setServletPath(String servletPath) {
- this.servletPath = servletPath;
- }
-
- @Override
- public String getServletPath() {
- return this.servletPath;
- }
-
- public void setSession(HttpSession session) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- @Nullable
- public HttpSession getSession(boolean create) {
- return this.session;
- }
-
- @Override
- @Nullable
- public HttpSession getSession() {
- return getSession(true);
- }
-
- @Override
- public String changeSessionId() {
- throw new UnsupportedOperationException();
- }
-
- public void setRequestedSessionIdValid(boolean requestedSessionIdValid) {
- this.requestedSessionIdValid = requestedSessionIdValid;
- }
-
- @Override
- public boolean isRequestedSessionIdValid() {
- return this.requestedSessionIdValid;
- }
-
- public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) {
- this.requestedSessionIdFromCookie = requestedSessionIdFromCookie;
- }
-
- @Override
- public boolean isRequestedSessionIdFromCookie() {
- return this.requestedSessionIdFromCookie;
- }
-
- public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) {
- this.requestedSessionIdFromURL = requestedSessionIdFromURL;
- }
-
- @Override
- public boolean isRequestedSessionIdFromURL() {
- return this.requestedSessionIdFromURL;
- }
-
- @Override
- @Deprecated
- public boolean isRequestedSessionIdFromUrl() {
- return isRequestedSessionIdFromURL();
- }
-
- @Override
- public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void login(String username, String password) throws ServletException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void logout() throws ServletException {
- this.userPrincipal = null;
- this.remoteUser = null;
- this.authType = null;
- }
-
- public void addPart(Part part) {
- this.parts.add(part.getName(), part);
- }
-
- @Override
- @Nullable
- public Part getPart(String name) throws IOException, ServletException {
- return this.parts.getFirst(name);
- }
-
- @Override
- public Collection getParts() throws IOException, ServletException {
- List result = new LinkedList<>();
- for (List list : this.parts.values()) {
- result.addAll(list);
- }
- return result;
- }
-
- @Override
- public T upgrade(Class handlerClass) throws IOException, ServletException {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletResponse.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletResponse.java
deleted file mode 100644
index 6feb0ebe1..000000000
--- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletResponse.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright 2023-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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 org.springframework.web.client;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-
-import org.springframework.http.HttpHeaders;
-import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
-import org.springframework.util.LinkedCaseInsensitiveMap;
-import org.springframework.web.util.WebUtils;
-
-public class ProxyHttpServletResponse implements HttpServletResponse {
-
- private static final String CHARSET_PREFIX = "charset=";
-
- private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
-
- private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
-
- // ---------------------------------------------------------------------
- // ServletResponse properties
- // ---------------------------------------------------------------------
-
- private boolean outputStreamAccessAllowed = true;
-
- private String defaultCharacterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
-
- private String characterEncoding = this.defaultCharacterEncoding;
-
- /**
- * {@code true} if the character encoding has been explicitly set through
- * {@link HttpServletResponse} methods or through a {@code charset} parameter on
- * the {@code Content-Type}.
- */
- private boolean characterEncodingSet = false;
-
- private final ByteArrayOutputStream content = new ByteArrayOutputStream(1024);
-
- private final ServletOutputStream outputStream = new ResponseServletOutputStream();
-
- private long contentLength = 0;
-
- private String contentType;
-
- private int bufferSize = 4096;
-
- private boolean committed;
-
- private Locale locale = Locale.getDefault();
-
- // ---------------------------------------------------------------------
- // HttpServletResponse properties
- // ---------------------------------------------------------------------
-
- private final List cookies = new ArrayList<>();
-
- private final Map headers = new LinkedCaseInsensitiveMap<>();
-
- private int status = HttpServletResponse.SC_OK;
-
- @Nullable
- private String errorMessage;
-
- // ---------------------------------------------------------------------
- // ServletResponse interface
- // ---------------------------------------------------------------------
-
- @Override
- public void setCharacterEncoding(String characterEncoding) {
- setExplicitCharacterEncoding(characterEncoding);
- updateContentTypePropertyAndHeader();
- }
-
- private void setExplicitCharacterEncoding(String characterEncoding) {
- Assert.notNull(characterEncoding, "'characterEncoding' must not be null");
- this.characterEncoding = characterEncoding;
- this.characterEncodingSet = true;
- }
-
- private void updateContentTypePropertyAndHeader() {
- if (this.contentType != null) {
- String value = this.contentType;
- if (this.characterEncodingSet && !value.toLowerCase().contains(CHARSET_PREFIX)) {
- value += ';' + CHARSET_PREFIX + getCharacterEncoding();
- this.contentType = value;
- }
- doAddHeaderValue(HttpHeaders.CONTENT_TYPE, value, true);
- }
- }
-
- @Override
- public String getCharacterEncoding() {
- return this.characterEncoding;
- }
-
- @Override
- public ServletOutputStream getOutputStream() {
- Assert.state(this.outputStreamAccessAllowed, "OutputStream access not allowed");
- return this.outputStream;
- }
-
- @Override
- public PrintWriter getWriter() throws UnsupportedEncodingException {
- throw new UnsupportedOperationException();
- }
-
- public byte[] getContentAsByteArray() {
- return this.content.toByteArray();
- }
-
- /**
- * Get the content of the response body as a {@code String}, using the charset
- * specified for the response by the application, either through
- * {@link HttpServletResponse} methods or through a charset parameter on the
- * {@code Content-Type}. If no charset has been explicitly defined, the
- * {@linkplain #setDefaultCharacterEncoding(String) default character encoding}
- * will be used.
- *
- * @return the content as a {@code String}
- * @throws UnsupportedEncodingException if the character encoding is not
- * supported
- * @see #getContentAsString(Charset)
- * @see #setCharacterEncoding(String)
- * @see #setContentType(String)
- */
- public String getContentAsString() throws UnsupportedEncodingException {
- return this.content.toString(getCharacterEncoding());
- }
-
- /**
- * Get the content of the response body as a {@code String}, using the provided
- * {@code fallbackCharset} if no charset has been explicitly defined and
- * otherwise using the charset specified for the response by the application,
- * either through {@link HttpServletResponse} methods or through a charset
- * parameter on the {@code Content-Type}.
- *
- * @return the content as a {@code String}
- * @throws UnsupportedEncodingException if the character encoding is not
- * supported
- * @since 5.2
- * @see #getContentAsString()
- * @see #setCharacterEncoding(String)
- * @see #setContentType(String)
- */
- public String getContentAsString(Charset fallbackCharset) throws UnsupportedEncodingException {
- String charsetName = (this.characterEncodingSet ? getCharacterEncoding() : fallbackCharset.name());
- return this.content.toString(charsetName);
- }
-
- @Override
- public void setContentLength(int contentLength) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setContentLengthLong(long len) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setContentType(@Nullable String contentType) {
- this.contentType = contentType;
- }
-
- @Override
- @Nullable
- public String getContentType() {
- return this.contentType;
- }
-
- @Override
- public void setBufferSize(int bufferSize) {
- this.bufferSize = bufferSize;
- }
-
- @Override
- public int getBufferSize() {
- return this.bufferSize;
- }
-
- @Override
- public void flushBuffer() {
-
- }
-
- @Override
- public void resetBuffer() {
- Assert.state(!isCommitted(), "Cannot reset buffer - response is already committed");
- this.content.reset();
- }
-
- public void setCommitted(boolean committed) {
- this.committed = committed;
- }
-
- @Override
- public boolean isCommitted() {
- return this.committed;
- }
-
- @Override
- public void reset() {
- resetBuffer();
- this.characterEncoding = this.defaultCharacterEncoding;
- this.characterEncodingSet = false;
- this.contentLength = 0;
- this.contentType = null;
- this.locale = Locale.getDefault();
- this.cookies.clear();
- this.headers.clear();
- this.status = HttpServletResponse.SC_OK;
- this.errorMessage = null;
- }
-
- @Override
- public void setLocale(@Nullable Locale locale) {
- // Although the Javadoc for javax.servlet.ServletResponse.setLocale(Locale) does
- // not
- // state how a null value for the supplied Locale should be handled, both Tomcat
- // and
- // Jetty simply ignore a null value. So we do the same here.
- if (locale == null) {
- return;
- }
- this.locale = locale;
- doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, locale.toLanguageTag(), true);
- }
-
- @Override
- public Locale getLocale() {
- return this.locale;
- }
-
- // ---------------------------------------------------------------------
- // HttpServletResponse interface
- // ---------------------------------------------------------------------
-
- @Override
- public void addCookie(Cookie cookie) {
- throw new UnsupportedOperationException();
- }
-
- @Nullable
- public Cookie getCookie(String name) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean containsHeader(String name) {
- return this.headers.containsKey(name);
- }
-
- /**
- * Return the names of all specified headers as a Set of Strings.
- *
- * As of Servlet 3.0, this method is also defined in
- * {@link HttpServletResponse}.
- *
- * @return the {@code Set} of header name {@code Strings}, or an empty
- * {@code Set} if none
- */
- @Override
- public Collection getHeaderNames() {
- return this.headers.keySet();
- }
-
- /**
- * Return the primary value for the given header as a String, if any. Will
- * return the first value in case of multiple values.
- *
- * As of Servlet 3.0, this method is also defined in
- * {@link HttpServletResponse}. As of Spring 3.1, it returns a stringified value
- * for Servlet 3.0 compatibility. Consider using {@link #getHeaderValue(String)}
- * for raw Object access.
- *
- * @param name the name of the header
- * @return the associated header value, or {@code null} if none
- */
- @Override
- @Nullable
- public String getHeader(String name) {
- HeaderValueHolder header = this.headers.get(name);
- return (header != null ? header.getStringValue() : null);
- }
-
- /**
- * Return all values for the given header as a List of Strings.
- *
- * As of Servlet 3.0, this method is also defined in
- * {@link HttpServletResponse}. As of Spring 3.1, it returns a List of
- * stringified values for Servlet 3.0 compatibility. Consider using
- * {@link #getHeaderValues(String)} for raw Object access.
- *
- * @param name the name of the header
- * @return the associated header values, or an empty List if none
- */
- @Override
- public List getHeaders(String name) {
- HeaderValueHolder header = this.headers.get(name);
- if (header != null) {
- return header.getStringValues();
- }
- else {
- return Collections.emptyList();
- }
- }
-
- /**
- * Return the primary value for the given header, if any.
- *
- * Will return the first value in case of multiple values.
- *
- * @param name the name of the header
- * @return the associated header value, or {@code null} if none
- */
- @Nullable
- public Object getHeaderValue(String name) {
- HeaderValueHolder header = this.headers.get(name);
- return (header != null ? header.getValue() : null);
- }
-
- /**
- * Return all values for the given header as a List of value objects.
- *
- * @param name the name of the header
- * @return the associated header values, or an empty List if none
- */
- public List