From 718641a1e5ca6d3273b0c280d82bce232d15fb3c Mon Sep 17 00:00:00 2001 From: Ankur Pathak Date: Sun, 20 Jan 2019 10:15:35 +0530 Subject: [PATCH] Added CompositeHeaderWriter 1. Added new CompositeHeaderWriter 2. Improvement in HeaderWriterFilter using CompositeHeaderWriter. Fixes: gh-6453 --- .../web/header/HeaderWriterFilter.java | 33 +++++---- .../header/writers/CompositeHeaderWriter.java | 50 ++++++++++++++ .../writers/CompositeHeaderWriterTests.java | 69 +++++++++++++++++++ 3 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 web/src/main/java/org/springframework/security/web/header/writers/CompositeHeaderWriter.java create mode 100644 web/src/test/java/org/springframework/security/web/header/writers/CompositeHeaderWriterTests.java diff --git a/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java b/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java index a06d1b93d2..7503e8e4fc 100644 --- a/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java +++ b/web/src/main/java/org/springframework/security/web/header/HeaderWriterFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; +import org.springframework.security.web.header.writers.CompositeHeaderWriter; import org.springframework.security.web.util.OnCommittedResponseWrapper; import org.springframework.util.Assert; import org.springframework.web.filter.OncePerRequestFilter; @@ -38,55 +39,55 @@ import org.springframework.web.filter.OncePerRequestFilter; * * @author Marten Deinum * @author Josh Cummings + * @author Ankur Pathak * @since 3.2 - * */ public class HeaderWriterFilter extends OncePerRequestFilter { + /** - * Collection of {@link HeaderWriter} instances to write out the headers to the + * Composite {@link CompositeHeaderWriter} containing Collection of {@link HeaderWriter} instances to write out the headers to the * response. */ - private final List headerWriters; + private final HeaderWriter headerWriter; /** * Creates a new instance. * * @param headerWriters the {@link HeaderWriter} instances to write out headers to the - * {@link HttpServletResponse}. + * {@link HttpServletResponse}. */ public HeaderWriterFilter(List headerWriters) { Assert.notEmpty(headerWriters, "headerWriters cannot be null or empty"); - this.headerWriters = headerWriters; + this.headerWriter = new CompositeHeaderWriter(headerWriters); } @Override protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { + HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse(request, - response, this.headerWriters); + response, this.headerWriter); HeaderWriterRequest headerWriterRequest = new HeaderWriterRequest(request, headerWriterResponse); try { filterChain.doFilter(headerWriterRequest, headerWriterResponse); - } - finally { + } finally { headerWriterResponse.writeHeaders(); } } static class HeaderWriterResponse extends OnCommittedResponseWrapper { private final HttpServletRequest request; - private final List headerWriters; + private final HeaderWriter headerWriter; HeaderWriterResponse(HttpServletRequest request, HttpServletResponse response, - List headerWriters) { + HeaderWriter headerWriter) { super(response); this.request = request; - this.headerWriters = headerWriters; + this.headerWriter = headerWriter; } /* @@ -105,9 +106,7 @@ public class HeaderWriterFilter extends OncePerRequestFilter { if (isDisableOnResponseCommitted()) { return; } - for (HeaderWriter headerWriter : this.headerWriters) { - headerWriter.writeHeaders(this.request, getHttpResponse()); - } + this.headerWriter.writeHeaders(this.request, getHttpResponse()); } private HttpServletResponse getHttpResponse() { diff --git a/web/src/main/java/org/springframework/security/web/header/writers/CompositeHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/CompositeHeaderWriter.java new file mode 100644 index 0000000000..4f5eaac549 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/header/writers/CompositeHeaderWriter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2019 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.web.header.writers; + +import org.springframework.security.web.header.HeaderWriter; +import org.springframework.util.Assert; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * A {@link HeaderWriter} that delegates to several other {@link HeaderWriter}s. + * + * @author Ankur Pathak + * @since 5.2 + */ +public class CompositeHeaderWriter implements HeaderWriter { + + private final List headerWriters; + + /** + * Creates a new instance. + * + * @param headerWriters the {@link HeaderWriter} instances to write out headers to the + * {@link HttpServletResponse}. + */ + public CompositeHeaderWriter(List headerWriters) { + Assert.notEmpty(headerWriters, "headerWriters cannot be empty"); + this.headerWriters = headerWriters; + } + + @Override + public void writeHeaders(HttpServletRequest request, HttpServletResponse response) { + this.headerWriters.forEach(headerWriter -> headerWriter.writeHeaders(request, response)); + } +} diff --git a/web/src/test/java/org/springframework/security/web/header/writers/CompositeHeaderWriterTests.java b/web/src/test/java/org/springframework/security/web/header/writers/CompositeHeaderWriterTests.java new file mode 100644 index 0000000000..c509bbebf7 --- /dev/null +++ b/web/src/test/java/org/springframework/security/web/header/writers/CompositeHeaderWriterTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2019 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.web.header.writers; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.web.header.HeaderWriter; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for class {@link CompositeHeaderWriter}/. + * + * @author Ankur Pathak + * @since 5.2 + */ +public class CompositeHeaderWriterTests { + private MockHttpServletRequest request; + + private MockHttpServletResponse response; + + private CompositeHeaderWriter writer; + + @Before + public void setup() { + this.request = new MockHttpServletRequest(); + this.response = new MockHttpServletResponse(); + HeaderWriter writerA = (request, response) -> { + if (!response.containsHeader("A")) { + response.setHeader("A", "a"); + } + }; + + HeaderWriter writerB = (request, response) -> { + if (!response.containsHeader("B")) { + response.setHeader("B", "b"); + } + }; + this.writer = new CompositeHeaderWriter(Arrays.asList(writerA, writerB)); + } + + + @Test + public void doCompositeHeaderWrite(){ + this.writer.writeHeaders(request, response); + assertThat(this.response.containsHeader("A")).isTrue(); + assertThat(this.response.containsHeader("B")).isTrue(); + assertThat(this.response.getHeader("A")).isEqualTo("a"); + assertThat(this.response.getHeader("B")).isEqualTo("b"); + } +}