From 0c82bca08a65766225d67670c080ba41c079e315 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Mon, 6 Mar 2023 18:54:52 +0100 Subject: [PATCH] Make spring-cloud-function-adapter-aws-web depend on base module --- spring-cloud-function-adapters/pom.xml | 2 + .../pom.xml | 5 + .../adapter/aws/web/WebProxyInvoker.java | 23 +- .../web/client/HeaderValueHolder.java | 78 -- .../web/client/ProxyHttpServletRequest.java | 1118 ----------------- .../web/client/ProxyHttpServletResponse.java | 601 --------- .../springframework/web/client/ProxyMvc.java | 224 ---- .../web/client/ProxyServletContext.java | 397 ------ .../org/springframework/web/client/README.md | 3 - .../web/ProxyHttpServletRequest.java | 12 +- .../function/serverless/web/ProxyMvc.java | 2 - .../adapter/aws/web/RequestResponseTests.java | 29 +- 12 files changed, 44 insertions(+), 2450 deletions(-) delete mode 100644 spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/HeaderValueHolder.java delete mode 100644 spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletRequest.java delete mode 100644 spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletResponse.java delete mode 100644 spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyMvc.java delete mode 100644 spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyServletContext.java delete mode 100644 spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/README.md diff --git a/spring-cloud-function-adapters/pom.xml b/spring-cloud-function-adapters/pom.xml index caf403641..b92bd61a3 100644 --- a/spring-cloud-function-adapters/pom.xml +++ b/spring-cloud-function-adapters/pom.xml @@ -21,6 +21,8 @@ spring-cloud-function-adapter-gcp spring-cloud-function-grpc spring-cloud-function-grpc-cloudevent-ext + spring-cloud-function-serverless-web + spring-cloud-function-adapter-aws-web diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/pom.xml b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/pom.xml index db6aa34ce..51609db00 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/pom.xml +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/pom.xml @@ -22,6 +22,11 @@ com.fasterxml.jackson.core jackson-databind + + org.springframework.cloud + spring-cloud-function-serverless-web + ${project.version} + org.springframework spring-webmvc diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/cloud/function/adapter/aws/web/WebProxyInvoker.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/cloud/function/adapter/aws/web/WebProxyInvoker.java index 318c06419..be5809b23 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/cloud/function/adapter/aws/web/WebProxyInvoker.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/cloud/function/adapter/aws/web/WebProxyInvoker.java @@ -36,14 +36,12 @@ import javax.servlet.http.HttpServletRequest; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - - +import org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest; +import org.springframework.cloud.function.serverless.web.ProxyHttpServletResponse; +import org.springframework.cloud.function.serverless.web.ProxyMvc; +import org.springframework.cloud.function.serverless.web.ProxyServletContext; import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; -import org.springframework.web.client.ProxyHttpServletRequest; -import org.springframework.web.client.ProxyHttpServletResponse; -import org.springframework.web.client.ProxyMvc; -import org.springframework.web.client.ProxyServletContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; @@ -61,21 +59,12 @@ public class WebProxyInvoker { private final ProxyMvc mvc; - private final ServletContext servletContext; ObjectMapper mapper = new ObjectMapper(); public WebProxyInvoker() throws ServletException { Class startClass = FunctionClassUtils.getStartClass(); - AnnotationConfigWebApplicationContext applpicationContext = new AnnotationConfigWebApplicationContext(); - applpicationContext.register(startClass); - - this.servletContext = new ProxyServletContext(); - ServletConfig servletConfig = new ProxyServletConfig(this.servletContext); - - DispatcherServlet servlet = new DispatcherServlet(applpicationContext); - servlet.init(servletConfig); - this.mvc = new ProxyMvc(servlet, applpicationContext); + this.mvc = ProxyMvc.INSTANCE(startClass); } /* @@ -96,7 +85,7 @@ public class WebProxyInvoker { logger.debug("httpMethod: " + httpMethod); logger.debug("path: " + path); } - ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(servletContext, httpMethod, path); + ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(null, httpMethod, path); if (StringUtils.hasText((String) request.get("body"))) { httpRequest.setContent(((String) request.get("body")).getBytes()); } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/HeaderValueHolder.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/HeaderValueHolder.java deleted file mode 100644 index 74cef84db..000000000 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/HeaderValueHolder.java +++ /dev/null @@ -1,78 +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.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.lang.Nullable; -import org.springframework.util.CollectionUtils; - -class HeaderValueHolder { - - private final List values = new LinkedList<>(); - - void setValue(@Nullable Object value) { - this.values.clear(); - if (value != null) { - this.values.add(value); - } - } - - void addValue(Object value) { - this.values.add(value); - } - - void addValues(Collection values) { - this.values.addAll(values); - } - - void addValueArray(Object values) { - CollectionUtils.mergeArrayIntoCollection(values, this.values); - } - - List getValues() { - return Collections.unmodifiableList(this.values); - } - - List getStringValues() { - List stringList = new ArrayList<>(this.values.size()); - for (Object value : this.values) { - stringList.add(value.toString()); - } - return Collections.unmodifiableList(stringList); - } - - @Nullable - Object getValue() { - return (!this.values.isEmpty() ? this.values.get(0) : null); - } - - @Nullable - String getStringValue() { - return (!this.values.isEmpty() ? String.valueOf(this.values.get(0)) : null); - } - - @Override - public String toString() { - return this.values.toString(); - } - -} diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletRequest.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletRequest.java deleted file mode 100644 index f899a5c9d..000000000 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyHttpServletRequest.java +++ /dev/null @@ -1,1118 +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.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; - -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.ReadListener; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpUpgradeHandler; -import javax.servlet.http.Part; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.LinkedCaseInsensitiveMap; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.util.StringUtils; - -public class ProxyHttpServletRequest implements HttpServletRequest { - - private static final String CHARSET_PREFIX = "charset="; - - private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); - - private static final BufferedReader EMPTY_BUFFERED_READER = new BufferedReader(new StringReader("")); - - /** - * Date formats as specified in the HTTP RFC. - * - * @see Section - * 7.1.1.1 of RFC 7231 - */ - private static final String[] DATE_FORMATS = new String[] { "EEE, dd MMM yyyy HH:mm:ss zzz", - "EEE, dd-MMM-yy HH:mm:ss zzz", "EEE MMM dd HH:mm:ss yyyy" }; - - private final ServletContext servletContext; - - private boolean active = true; - - // --------------------------------------------------------------------- - // ServletRequest properties - // --------------------------------------------------------------------- - - private final Map attributes = new LinkedHashMap<>(); - - @Nullable - private String characterEncoding; - - @Nullable - private byte[] content; - - @Nullable - private String contentType; - - @Nullable - private ServletInputStream inputStream; - - @Nullable - private BufferedReader reader; - - private final Map parameters = new LinkedHashMap<>(16); - - /** List of locales in descending order. */ - private final LinkedList locales = new LinkedList<>(); - - - private boolean asyncStarted = false; - - private boolean asyncSupported = false; - - private DispatcherType dispatcherType = DispatcherType.REQUEST; - - // --------------------------------------------------------------------- - // HttpServletRequest properties - // --------------------------------------------------------------------- - - @Nullable - private String authType; - - @Nullable - private Cookie[] cookies; - - private final Map headers = new LinkedCaseInsensitiveMap<>(); - - @Nullable - private String method; - - @Nullable - private String pathInfo; - - private String contextPath = ""; - - @Nullable - private String queryString; - - @Nullable - private String remoteUser; - - private final Set userRoles = new HashSet<>(); - - @Nullable - private Principal userPrincipal; - - @Nullable - private String requestedSessionId; - - @Nullable - private String requestURI; - - private String servletPath = ""; - - @Nullable - private HttpSession session; - - private boolean requestedSessionIdValid = true; - - private boolean requestedSessionIdFromCookie = true; - - private boolean requestedSessionIdFromURL = false; - - private final MultiValueMap parts = new LinkedMultiValueMap<>(); - - - public ProxyHttpServletRequest(ServletContext servletContext, String method, String requestURI) { - this.servletContext = servletContext; - this.method = method; - this.requestURI = requestURI; - this.locales.add(Locale.ENGLISH); - } - - /** - * Return the ServletContext that this request is associated with. (Not - * available in the standard HttpServletRequest interface for some reason.) - */ - @Override - public ServletContext getServletContext() { - return this.servletContext; - } - - @Override - public Object getAttribute(String name) { - return this.attributes.get(name); - } - - @Override - public Enumeration 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 getHeaderValues(String name) { - HeaderValueHolder header = this.headers.get(name); - if (header != null) { - return header.getValues(); - } - else { - return Collections.emptyList(); - } - } - - /** - * The default implementation returns the given URL String as-is. - *

- * Can be overridden in subclasses, appending a session id or the like. - */ - @Override - public String encodeURL(String url) { - return url; - } - - /** - * The default implementation delegates to {@link #encodeURL}, returning the - * given URL String as-is. - *

- * Can be overridden in subclasses, appending a session id or the like in a - * redirect-specific fashion. For general URL encoding rules, override the - * common {@link #encodeURL} method instead, applying to redirect URLs as well - * as to general URLs. - */ - @Override - public String encodeRedirectURL(String url) { - return encodeURL(url); - } - - @Override - @Deprecated - public String encodeUrl(String url) { - return encodeURL(url); - } - - @Override - @Deprecated - public String encodeRedirectUrl(String url) { - return encodeRedirectURL(url); - } - - @Override - public void sendError(int status, String errorMessage) throws IOException { - Assert.state(!isCommitted(), "Cannot set error status - response is already committed"); - this.status = status; - this.errorMessage = errorMessage; - setCommitted(true); - } - - @Override - public void sendError(int status) throws IOException { - Assert.state(!isCommitted(), "Cannot set error status - response is already committed"); - this.status = status; - setCommitted(true); - } - - @Override - public void sendRedirect(String url) throws IOException { - Assert.state(!isCommitted(), "Cannot send redirect - response is already committed"); - Assert.notNull(url, "Redirect URL must not be null"); - setHeader(HttpHeaders.LOCATION, url); - setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - setCommitted(true); - } - - @Nullable - public String getRedirectedUrl() { - return getHeader(HttpHeaders.LOCATION); - } - - @Override - public void setDateHeader(String name, long value) { - setHeaderValue(name, formatDate(value)); - } - - @Override - public void addDateHeader(String name, long value) { - addHeaderValue(name, formatDate(value)); - } - - public long getDateHeader(String name) { - String headerValue = getHeader(name); - if (headerValue == null) { - return -1; - } - try { - return newDateFormat().parse(getHeader(name)).getTime(); - } - catch (ParseException ex) { - throw new IllegalArgumentException("Value for header '" + name + "' is not a valid Date: " + headerValue); - } - } - - private String formatDate(long date) { - return newDateFormat().format(new Date(date)); - } - - private DateFormat newDateFormat() { - SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US); - dateFormat.setTimeZone(GMT); - return dateFormat; - } - - @Override - public void setHeader(String name, @Nullable String value) { - setHeaderValue(name, value); - } - - @Override - public void addHeader(String name, @Nullable String value) { - addHeaderValue(name, value); - } - - @Override - public void setIntHeader(String name, int value) { - setHeaderValue(name, value); - } - - @Override - public void addIntHeader(String name, int value) { - addHeaderValue(name, value); - } - - private void setHeaderValue(String name, @Nullable Object value) { - if (value == null) { - return; - } - boolean replaceHeader = true; - doAddHeaderValue(name, value, replaceHeader); - } - - private void addHeaderValue(String name, @Nullable Object value) { - if (value == null) { - return; - } - boolean replaceHeader = false; - doAddHeaderValue(name, value, replaceHeader); - } - - private void doAddHeaderValue(String name, Object value, boolean replace) { - Assert.notNull(value, "Header value must not be null"); - HeaderValueHolder header = this.headers.computeIfAbsent(name, key -> new HeaderValueHolder()); - if (replace) { - header.setValue(value); - } - else { - header.addValue(value); - } - } - - @Override - public void setStatus(int status) { - if (!this.isCommitted()) { - this.status = status; - } - } - - @Override - @Deprecated - public void setStatus(int status, String errorMessage) { - throw new UnsupportedOperationException(); - } - - @Override - public int getStatus() { - return this.status; - } - - @Nullable - public String getErrorMessage() { - return this.errorMessage; - } - - // --------------------------------------------------------------------- - // Methods for MockRequestDispatcher - // --------------------------------------------------------------------- - - @Nullable - public String getForwardedUrl() { - throw new UnsupportedOperationException(); - } - - @Nullable - public String getIncludedUrl() { - throw new UnsupportedOperationException(); - } - - /** - * Inner class that adapts the ServletOutputStream to mark the response as - * committed once the buffer size is exceeded. - */ - private class ResponseServletOutputStream extends ServletOutputStream { - - private WriteListener listener; - - @Override - public boolean isReady() { - return true; - } - - @Override - public void setWriteListener(WriteListener writeListener) { - if (writeListener != null) { - try { - writeListener.onWritePossible(); - } - catch (IOException e) { - // log.error("Output stream is not writable", e); - } - - listener = writeListener; - } - } - - @Override - public void write(int b) throws IOException { - try { - content.write(b); - } - catch (Exception e) { - if (listener != null) { - listener.onError(e); - } - } - } - - @Override - public void close() throws IOException { - super.close(); - flushBuffer(); - } - } - -} diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyMvc.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyMvc.java deleted file mode 100644 index e9c646d9c..000000000 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyMvc.java +++ /dev/null @@ -1,224 +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.IOException; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.web.context.ConfigurableWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; - -public class ProxyMvc { - - static final String MVC_RESULT_ATTRIBUTE = ProxyMvc.class.getName().concat(".MVC_RESULT_ATTRIBUTE"); - - private final DispatcherServlet servlet; - - private final Filter[] filters; - - private final ConfigurableWebApplicationContext applicationContext; - - @Nullable - private Charset defaultResponseCharacterEncoding; - - /** - * Private constructor, not for direct instantiation. - * - * @see org.springframework.test.web.servlet.setup.MockMvcBuilders - */ - public ProxyMvc(DispatcherServlet servlet, ConfigurableWebApplicationContext applicationContext) { - Assert.notNull(servlet, "DispatcherServlet is required"); - this.applicationContext = applicationContext; - - this.servlet = servlet; - this.filters = applicationContext.getBeansOfType(Filter.class).values().toArray(new Filter[0]); - } - - public void stop() { - this.applicationContext.stop(); - } - - /** - * The default character encoding to be applied to every response. - * - * @see org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder#defaultResponseCharacterEncoding(Charset) - */ - void setDefaultResponseCharacterEncoding(@Nullable Charset defaultResponseCharacterEncoding) { - this.defaultResponseCharacterEncoding = defaultResponseCharacterEncoding; - } - - /** - * Return the underlying {@link DispatcherServlet} instance that this - * {@code MockMvc} was initialized with. - *

- * This is intended for use in custom request processing scenario where a - * request handling component happens to delegate to the - * {@code DispatcherServlet} at runtime and therefore needs to be injected with - * it. - *

- * For most processing scenarios, simply use {@link MockMvc#perform}, or if you - * need to configure the {@code DispatcherServlet}, provide a - * {@link DispatcherServletCustomizer} to the {@code MockMvcBuilder}. - * - * @since 5.1 - */ - public DispatcherServlet getDispatcherServlet() { - return this.servlet; - } - - /** - * Perform a request and return a type that allows chaining further actions, - * such as asserting expectations, on the result. - * - * @param requestBuilder used to prepare the request to execute; see static - * factory methods in - * {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders} - * @return an instance of {@link ResultActions} (never {@code null}) - * @see org.springframework.test.web.servlet.request.MockMvcRequestBuilders - * @see org.springframework.test.web.servlet.result.MockMvcResultMatchers - */ - public void service(HttpServletRequest request, HttpServletResponse response) throws Exception { - ProxyFilterChain filterChain = new ProxyFilterChain(this.servlet, this.filters); - filterChain.doFilter(request, response); - } - - public ConfigurableWebApplicationContext getApplicationContext() { - return applicationContext; - } - - private static class ProxyFilterChain implements FilterChain { - - @Nullable - private ServletRequest request; - - @Nullable - private ServletResponse response; - - private final List filters; - - @Nullable - private Iterator iterator; - - - /** - * Create a {@code FilterChain} with Filter's and a Servlet. - * - * @param servlet the {@link Servlet} to invoke in this {@link FilterChain} - * @param filters the {@link Filter}'s to invoke in this {@link FilterChain} - * @since 3.2 - */ - ProxyFilterChain(Servlet servlet, Filter... filters) { - Assert.notNull(filters, "filters cannot be null"); - Assert.noNullElements(filters, "filters cannot contain null values"); - this.filters = initFilterList(servlet, filters); - } - - private static List initFilterList(Servlet servlet, Filter... filters) { - Filter[] allFilters = ObjectUtils.addObjectToArray(filters, new ServletFilterProxy(servlet)); - return Arrays.asList(allFilters); - } - - /** - * Return the request that {@link #doFilter} has been called with. - */ - @Nullable - public ServletRequest getRequest() { - return this.request; - } - - /** - * Return the response that {@link #doFilter} has been called with. - */ - @Nullable - public ServletResponse getResponse() { - return this.response; - } - - /** - * Invoke registered {@link Filter Filters} and/or {@link Servlet} also saving - * the request and response. - */ - @Override - public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(response, "Response must not be null"); - Assert.state(this.request == null, "This FilterChain has already been called!"); - - if (this.iterator == null) { - this.iterator = this.filters.iterator(); - } - - if (this.iterator.hasNext()) { - Filter nextFilter = this.iterator.next(); - nextFilter.doFilter(request, response, this); - } - - this.request = request; - this.response = response; - } - - /** - * A filter that simply delegates to a Servlet. - */ - private static final class ServletFilterProxy implements Filter { - - private final Servlet delegateServlet; - - private ServletFilterProxy(Servlet servlet) { - Assert.notNull(servlet, "servlet cannot be null"); - this.delegateServlet = servlet; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - - this.delegateServlet.service(request, response); - } - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - @Override - public void destroy() { - } - - @Override - public String toString() { - return this.delegateServlet.toString(); - } - } - - } -} diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyServletContext.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyServletContext.java deleted file mode 100644 index 504911b5e..000000000 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/ProxyServletContext.java +++ /dev/null @@ -1,397 +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.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.servlet.Filter; -import javax.servlet.FilterRegistration; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; -import javax.servlet.ServletRegistration.Dynamic; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.descriptor.JspConfigDescriptor; - -public class ProxyServletContext implements ServletContext { - - @Override - public Enumeration getInitParameterNames() { - List arrlist = new ArrayList(); - return Collections.enumeration(arrlist); - } - - @Override - public Enumeration getAttributeNames() { - List arrlist = new ArrayList(); - return Collections.enumeration(arrlist); - } - - @Override - public String getContextPath() { - // TODO Auto-generated method stub - return null; - } - - @Override - public ServletContext getContext(String uripath) { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getMajorVersion() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getMinorVersion() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getEffectiveMajorVersion() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getEffectiveMinorVersion() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public String getMimeType(String file) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Set getResourcePaths(String path) { - // TODO Auto-generated method stub - return null; - } - - @Override - public URL getResource(String path) throws MalformedURLException { - // TODO Auto-generated method stub - return null; - } - - @Override - public InputStream getResourceAsStream(String path) { - // TODO Auto-generated method stub - return null; - } - - @Override - public RequestDispatcher getRequestDispatcher(String path) { - // TODO Auto-generated method stub - return null; - } - - @Override - public RequestDispatcher getNamedDispatcher(String name) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Servlet getServlet(String name) throws ServletException { - // TODO Auto-generated method stub - return null; - } - - @Override - public Enumeration getServlets() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Enumeration getServletNames() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void log(String msg) { - // TODO Auto-generated method stub - - } - - @Override - public void log(Exception exception, String msg) { - // TODO Auto-generated method stub - - } - - @Override - public void log(String message, Throwable throwable) { - // TODO Auto-generated method stub - - } - - @Override - public String getRealPath(String path) { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getServerInfo() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getInitParameter(String name) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean setInitParameter(String name, String value) { - // TODO Auto-generated method stub - return false; - } - - @Override - public Object getAttribute(String name) { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setAttribute(String name, Object object) { - // TODO Auto-generated method stub - - } - - @Override - public void removeAttribute(String name) { - // TODO Auto-generated method stub - - } - - @Override - public String getServletContextName() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Dynamic addServlet(String servletName, String className) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Dynamic addServlet(String servletName, Servlet servlet) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Dynamic addServlet(String servletName, Class servletClass) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Dynamic addJspFile(String jspName, String jspFile) { - // TODO Auto-generated method stub - return null; - } - - @Override - public T createServlet(Class c) throws ServletException { - // TODO Auto-generated method stub - return null; - } - - @Override - public ServletRegistration getServletRegistration(String servletName) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Map getServletRegistrations() { - // TODO Auto-generated method stub - return null; - } - - @Override - public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, String className) { - // TODO Auto-generated method stub - return null; - } - - @Override - public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { - // TODO Auto-generated method stub - return null; - } - - @Override - public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { - // TODO Auto-generated method stub - return null; - } - - @Override - public T createFilter(Class c) throws ServletException { - // TODO Auto-generated method stub - return null; - } - - @Override - public FilterRegistration getFilterRegistration(String filterName) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Map getFilterRegistrations() { - // TODO Auto-generated method stub - return null; - } - - @Override - public SessionCookieConfig getSessionCookieConfig() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setSessionTrackingModes(Set sessionTrackingModes) { - // TODO Auto-generated method stub - - } - - @Override - public Set getDefaultSessionTrackingModes() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Set getEffectiveSessionTrackingModes() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void addListener(String className) { - // TODO Auto-generated method stub - - } - - @Override - public void addListener(T t) { - // TODO Auto-generated method stub - - } - - @Override - public void addListener(Class listenerClass) { - // TODO Auto-generated method stub - - } - - @Override - public T createListener(Class c) throws ServletException { - // TODO Auto-generated method stub - return null; - } - - @Override - public JspConfigDescriptor getJspConfigDescriptor() { - // TODO Auto-generated method stub - return null; - } - - @Override - public ClassLoader getClassLoader() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void declareRoles(String... roleNames) { - // TODO Auto-generated method stub - - } - - @Override - public String getVirtualServerName() { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getSessionTimeout() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void setSessionTimeout(int sessionTimeout) { - // TODO Auto-generated method stub - - } - - @Override - public String getRequestCharacterEncoding() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setRequestCharacterEncoding(String encoding) { - // TODO Auto-generated method stub - - } - - @Override - public String getResponseCharacterEncoding() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setResponseCharacterEncoding(String encoding) { - // TODO Auto-generated method stub - - } -} diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/README.md b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/README.md deleted file mode 100644 index 46ee43c43..000000000 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/src/main/java/org/springframework/web/client/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Classes in this package should ideally reside in spring-web somewhere as a light weight HTTP proxy, since they are independent of the -context of the execution (i.e., AWS or Azure or whatever). -In fact classes in these package is a slimed-down copy of similar classes in MockMVC. diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyHttpServletRequest.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyHttpServletRequest.java index 1cf864164..d5af925c7 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyHttpServletRequest.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyHttpServletRequest.java @@ -111,7 +111,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest { /** List of locales in descending order. */ private final LinkedList locales = new LinkedList<>(); - private boolean asyncStarted = false; private boolean asyncSupported = false; @@ -168,7 +167,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest { private final MultiValueMap parts = new LinkedMultiValueMap<>(); - public ProxyHttpServletRequest(ServletContext servletContext, String method, String requestURI) { this.servletContext = servletContext; this.method = method; @@ -318,11 +316,11 @@ public class ProxyHttpServletRequest implements HttpServletRequest { @Override public int read() throws IOException { - int readByte = stream.read(); - if (readByte == -1) { - finished = true; - } - return readByte; + int readByte = stream.read(); + if (readByte == -1) { + finished = true; + } + return readByte; } @Override diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyMvc.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyMvc.java index 3e1eff91f..519fa5404 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyMvc.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ProxyMvc.java @@ -41,8 +41,6 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.web.context.ConfigurableWebApplicationContext; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/adapter/aws/web/RequestResponseTests.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/adapter/aws/web/RequestResponseTests.java index 26e0c735e..6a29ba3ab 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/adapter/aws/web/RequestResponseTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/adapter/aws/web/RequestResponseTests.java @@ -1,21 +1,44 @@ +/* + * 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.cloud.function.adapter.aws.web; -import static org.assertj.core.api.Assertions.assertThat; + import java.util.List; import javax.servlet.http.HttpServletRequest; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest; import org.springframework.cloud.function.serverless.web.ProxyHttpServletResponse; import org.springframework.cloud.function.serverless.web.ProxyMvc; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; +import static org.assertj.core.api.Assertions.assertThat; +/** + * + * @author Oleg Zhurakousky + * + */ public class RequestResponseTests { private ObjectMapper mapper = new ObjectMapper();