diff --git a/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java b/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java index cb271bd8309..76fca3346eb 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -26,13 +26,13 @@ import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.Iterator; +import java.util.LinkedHashMap; 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 java.util.LinkedHashMap; import org.springframework.util.Assert; import org.springframework.util.LinkedCaseInsensitiveMap; @@ -93,9 +93,40 @@ public class HttpHeaders implements MultiValueMap { private static TimeZone GMT = TimeZone.getTimeZone("GMT"); + private final Map> headers; + + /** + * Private constructor that can create read-only {@code HttpHeader} instances. + */ + private HttpHeaders(Map> headers, boolean readOnly) { + Assert.notNull(headers, "'headers' must not be null"); + if (readOnly) { + Map> map = + new LinkedCaseInsensitiveMap>(headers.size(), Locale.ENGLISH); + for (Entry> entry : headers.entrySet()) { + List values = Collections.unmodifiableList(entry.getValue()); + map.put(entry.getKey(), values); + } + this.headers = Collections.unmodifiableMap(map); + } + else { + this.headers = headers; + } + } - private final Map> headers = new LinkedCaseInsensitiveMap>(8); + /** + * Constructs a new instance of the {@code HttpHeaders} object. + */ + public HttpHeaders() { + this(new LinkedCaseInsensitiveMap>(8, Locale.ENGLISH), false); + } + /** + * Returns {@code HttpHeaders} object that can only be read, not written to. + */ + public static HttpHeaders readOnlyHttpHeaders(HttpHeaders headers) { + return new HttpHeaders(headers, true); + } /** * Set the list of acceptable {@linkplain MediaType media types}, as specified by the {@code Accept} header. diff --git a/org.springframework.web/src/main/java/org/springframework/http/client/AbstractClientHttpRequest.java b/org.springframework.web/src/main/java/org/springframework/http/client/AbstractClientHttpRequest.java index ab479b11cac..60afb7d4b9d 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/client/AbstractClientHttpRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/http/client/AbstractClientHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -20,8 +20,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import org.springframework.util.Assert; import org.springframework.http.HttpHeaders; +import org.springframework.util.Assert; /** * Abstract base for {@link ClientHttpRequest} that makes sure that headers and body are not written multiple times. @@ -39,8 +39,7 @@ public abstract class AbstractClientHttpRequest implements ClientHttpRequest { public final HttpHeaders getHeaders() { - checkExecuted(); - return this.headers; + return executed ? HttpHeaders.readOnlyHttpHeaders(headers) : this.headers; } public final OutputStream getBody() throws IOException { diff --git a/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java b/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java index a40ab6759a2..af7ab7e449a 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java +++ b/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -22,9 +22,9 @@ import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; -import org.springframework.util.Assert; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.util.Assert; /** * {@link ServerHttpResponse} implementation that is based on a {@link HttpServletResponse}. @@ -56,7 +56,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse { } public HttpHeaders getHeaders() { - return this.headers; + return headersWritten ? HttpHeaders.readOnlyHttpHeaders(headers) : this.headers; } public OutputStream getBody() throws IOException { diff --git a/org.springframework.web/src/test/java/org/springframework/http/client/AbstractHttpRequestFactoryTestCase.java b/org.springframework.web/src/test/java/org/springframework/http/client/AbstractHttpRequestFactoryTestCase.java index 0eb05af8e11..c7fa64c632b 100644 --- a/org.springframework.web/src/test/java/org/springframework/http/client/AbstractHttpRequestFactoryTestCase.java +++ b/org.springframework.web/src/test/java/org/springframework/http/client/AbstractHttpRequestFactoryTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -124,7 +124,7 @@ public abstract class AbstractHttpRequestFactoryTestCase { } } - @Test(expected = IllegalStateException.class) + @Test(expected = UnsupportedOperationException.class) public void headersAfterExecute() throws Exception { ClientHttpRequest request = factory.createRequest(new URI(BASE_URL + "/echo"), HttpMethod.POST); request.getHeaders().add("MyHeader", "value");