/* * Copyright 2011-2016 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.glowroot.agent.plugin.servlet; import java.util.List; import java.util.Locale; import java.util.Map; import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.mock.web.MockHttpServletResponse; import org.glowroot.agent.it.harness.AppUnderTest; import org.glowroot.agent.it.harness.Container; import org.glowroot.agent.it.harness.Containers; import org.glowroot.agent.plugin.servlet.TestServlet.PatchedMockHttpServletResponse; import org.glowroot.wire.api.model.TraceOuterClass.Trace; import static org.assertj.core.api.Assertions.assertThat; public class ResponseHeaderIT { private static final String PLUGIN_ID = "servlet"; private static Container container; @BeforeClass public static void setUp() throws Exception { container = Containers.create(); } @AfterClass public static void tearDown() throws Exception { container.close(); } @After public void afterEachTest() throws Exception { container.checkAndReset(); } @Test public void testStandardResponseHeaders() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "Content-Type, Content-Length, Content-Language"); // when Trace trace = container.execute(SetStandardResponseHeaders.class); // then Map<String, Object> responseHeaders = getResponseHeaders(trace); assertThat(responseHeaders.get("Content-Type")).isEqualTo("text/plain;charset=UTF-8"); assertThat(responseHeaders.get("Content-Length")).isEqualTo("1"); assertThat(responseHeaders.get("Content-Language")).isEqualTo("en"); assertThat(responseHeaders.get("Extra")).isNull(); } @Test public void testStandardResponseHeadersUsingSetHeader() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "Content-Type, Content-Length, Content-Language"); // when Trace trace = container.execute(SetStandardResponseHeadersUsingSetHeader.class); // then Map<String, Object> responseHeaders = getResponseHeaders(trace); assertThat(responseHeaders.get("Content-Type")).isEqualTo("text/plain;charset=UTF-8"); assertThat(responseHeaders.get("Content-Length")).isEqualTo("1"); assertThat(responseHeaders.get("Content-Language")).isEqualTo("en"); assertThat(responseHeaders.get("Extra")).isNull(); } @Test public void testStandardResponseHeadersUsingAddHeader() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "Content-Type, Content-Length, Content-Language"); // when Trace trace = container.execute(SetStandardResponseHeadersUsingAddHeader.class); // then Map<String, Object> responseHeaders = getResponseHeaders(trace); assertThat(responseHeaders.get("Content-Type")).isEqualTo("text/plain;charset=UTF-8"); assertThat(responseHeaders.get("Content-Length")).isEqualTo("1"); assertThat(responseHeaders.get("Content-Language")).isEqualTo("en"); assertThat(responseHeaders.get("Extra")).isNull(); } @Test public void testStandardResponseHeadersLowercase() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "Content-Type, Content-Length"); // when Trace trace = container.execute(SetStandardResponseHeadersLowercase.class); // then Map<String, Object> responseHeaders = getResponseHeaders(trace); assertThat(responseHeaders.get("content-type")).isEqualTo("text/plain;charset=UTF-8"); assertThat(responseHeaders.get("content-length")).isEqualTo("1"); assertThat(responseHeaders.get("extra")).isNull(); } @Test public void testWithoutAnyHeaderCapture() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", ""); // when Trace trace = container.execute(SetStandardResponseHeaders.class); // then assertThat(getResponseHeaders(trace)).isNull(); } @Test public void testWithoutAnyInterestingHeaderCapture() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "ABC"); // when Trace trace = container.execute(SetStandardResponseHeaders.class); // then assertThat(getResponseHeaders(trace)).isNull(); } @Test public void testWithoutAnyHeaderCaptureUsingSetHeader() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", ""); // when Trace trace = container.execute(SetStandardResponseHeadersUsingSetHeader.class); // then assertThat(getResponseHeaders(trace)).isNull(); } @Test public void testWithoutAnyHeaderCaptureUsingAddHeader() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", ""); // when Trace trace = container.execute(SetStandardResponseHeadersUsingAddHeader.class); // then assertThat(getResponseHeaders(trace)).isNull(); } @Test public void testLotsOfResponseHeaders() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "One,Two,Date-One,Date-Two,Int-One,Int-Two,X-One"); // when Trace trace = container.execute(SetLotsOfResponseHeaders.class); // then Map<String, Object> responseHeaders = getResponseHeaders(trace); @SuppressWarnings("unchecked") List<String> one = (List<String>) responseHeaders.get("One"); @SuppressWarnings("unchecked") List<String> dOne = (List<String>) responseHeaders.get("Date-One"); @SuppressWarnings("unchecked") List<String> iOne = (List<String>) responseHeaders.get("Int-One"); @SuppressWarnings("unchecked") List<String> xOne = (List<String>) responseHeaders.get("X-One"); assertThat(one).containsExactly("ab", "xy"); assertThat(responseHeaders.get("Two")).isEqualTo("1"); assertThat(responseHeaders.get("Three")).isNull(); assertThat(dOne).containsExactly("Fri, 28 Feb 2014 02:06:52 GMT", "Fri, 28 Feb 2014 02:06:53 GMT"); assertThat(responseHeaders.get("Date-Two")).isEqualTo("Fri, 28 Feb 2014 02:06:54 GMT"); assertThat(responseHeaders.get("Date-Three")).isNull(); assertThat(iOne).containsExactly("2", "3"); assertThat(responseHeaders.get("Int-Two")).isEqualTo("4"); assertThat(responseHeaders.get("Int-Three")).isNull(); assertThat(xOne).containsExactly("xy", "Fri, 28 Feb 2014 02:06:56 GMT", "6"); } @Test public void testOutsideServlet() throws Exception { // given container.getConfigService().setPluginProperty(PLUGIN_ID, "captureResponseHeaders", "Content-Type, Content-Length, Content-Language"); // when container.executeNoExpectedTrace(SetStandardResponseHeadersOutsideServlet.class); // then // basically just testing that it should not generate any errors } static @Nullable Map<String, Object> getDetailMap(Trace trace, String name) { List<Trace.DetailEntry> details = trace.getHeader().getDetailEntryList(); Trace.DetailEntry found = null; for (Trace.DetailEntry detail : details) { if (detail.getName().equals(name)) { found = detail; break; } } if (found == null) { return null; } Map<String, Object> responseHeaders = Maps.newLinkedHashMap(); for (Trace.DetailEntry detail : found.getChildEntryList()) { List<Trace.DetailValue> values = detail.getValueList(); if (values.size() == 1) { responseHeaders.put(detail.getName(), values.get(0).getString()); } else { List<String> vals = Lists.newArrayList(); for (Trace.DetailValue value : values) { vals.add(value.getString()); } responseHeaders.put(detail.getName(), vals); } } return responseHeaders; } private static @Nullable Map<String, Object> getResponseHeaders(Trace trace) { return getDetailMap(trace, "Response headers"); } @SuppressWarnings("serial") public static class SetStandardResponseHeaders extends TestServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.setContentLength(1); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.setLocale(Locale.ENGLISH); } } @SuppressWarnings("serial") public static class SetStandardResponseHeadersUsingSetHeader extends TestServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.setHeader("Content-Type", "text/plain;charset=UTF-8"); response.setHeader("Content-Length", "1"); response.setHeader("Extra", "abc"); response.setLocale(Locale.ENGLISH); } } @SuppressWarnings("serial") public static class SetStandardResponseHeadersUsingAddHeader extends TestServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.addHeader("Content-Type", "text/plain;charset=UTF-8"); response.addHeader("Content-Length", "1"); response.addHeader("Extra", "abc"); response.setLocale(Locale.ENGLISH); } } @SuppressWarnings("serial") public static class SetStandardResponseHeadersLowercase extends TestServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.setHeader("content-type", "text/plain;charset=UTF-8"); response.setHeader("content-length", "1"); response.setHeader("extra", "abc"); } } @SuppressWarnings("serial") public static class SetLotsOfResponseHeaders extends TestServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.setHeader("One", "abc"); response.setHeader("one", "ab"); response.addHeader("one", "xy"); response.setHeader("Two", "1"); response.setHeader("Three", "xyz"); response.setDateHeader("Date-One", 1393553211832L); response.setDateHeader("Date-one", 1393553212832L); response.addDateHeader("Date-one", 1393553213832L); response.setDateHeader("Date-Two", 1393553214832L); response.setDateHeader("Date-Thr", 1393553215832L); response.addDateHeader("Date-Four", 1393553215832L); response.setIntHeader("Int-One", 1); response.setIntHeader("Int-one", 2); response.addIntHeader("Int-one", 3); response.setIntHeader("Int-Two", 4); response.setIntHeader("Int-Thr", 5); response.addIntHeader("Int-Four", 6); response.addHeader("X-One", "xy"); response.addDateHeader("X-one", 1393553216832L); response.addIntHeader("X-one", 6); } } public static class SetStandardResponseHeadersOutsideServlet implements AppUnderTest { @Override public void executeApp() throws Exception { MockHttpServletResponse response = new PatchedMockHttpServletResponse(); response.setContentLength(1); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.setLocale(Locale.ENGLISH); } } }