Avoid exception while setting the status code of a committed response

Before this commit, it was not possible to set the status code of an
HTTP response without throwing an exception if it was already
committed. The consequence was a lot of errors in the logs for long
lived HTTP exchanges like Server-Sent Events for example.

After this commit, ServerHttpResponse#setStatusCode() returns
true if the operation succeeded and false if the status code has not
been set because the response has already been committed.

In term of implementation, that makes status code managed
consistently with headers and cookies:
AbstractServerHttpResponse#setStatusCode() stores the status
code that will be effectively set later in the response lifecycle by
the HTTP server via AbstractServerHttpResponse#writeStatusCode()
when the response will be committed.
This commit is contained in:
Sebastien Deleuze
2016-07-04 12:03:04 +02:00
parent b7b6704c7e
commit c1518c3fde
8 changed files with 82 additions and 24 deletions

View File

@@ -49,8 +49,9 @@ public class MockServerHttpResponse implements ServerHttpResponse {
@Override
public void setStatusCode(HttpStatus status) {
public boolean setStatusCode(HttpStatus status) {
this.status = status;
return true;
}
public HttpStatus getStatus() {

View File

@@ -28,7 +28,6 @@ import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import static junit.framework.TestCase.assertTrue;
@@ -36,6 +35,7 @@ import static org.junit.Assert.*;
/**
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
*/
public class ServerHttpResponseTests {
@@ -47,6 +47,7 @@ public class ServerHttpResponseTests {
TestServerHttpResponse response = new TestServerHttpResponse();
response.writeWith(Flux.just(wrap("a"), wrap("b"), wrap("c"))).block();
assertTrue(response.statusCodeWritten);
assertTrue(response.headersWritten);
assertTrue(response.cookiesWritten);
@@ -62,6 +63,7 @@ public class ServerHttpResponseTests {
IllegalStateException error = new IllegalStateException("boo");
response.writeWith(Flux.error(error)).otherwise(ex -> Mono.empty()).block();
assertFalse(response.statusCodeWritten);
assertFalse(response.headersWritten);
assertFalse(response.cookiesWritten);
assertTrue(response.body.isEmpty());
@@ -72,6 +74,7 @@ public class ServerHttpResponseTests {
TestServerHttpResponse response = new TestServerHttpResponse();
response.setComplete().block();
assertTrue(response.statusCodeWritten);
assertTrue(response.headersWritten);
assertTrue(response.cookiesWritten);
assertTrue(response.body.isEmpty());
@@ -87,6 +90,7 @@ public class ServerHttpResponseTests {
});
response.writeWith(Flux.just(wrap("a"), wrap("b"), wrap("c"))).block();
assertTrue(response.statusCodeWritten);
assertTrue(response.headersWritten);
assertTrue(response.cookiesWritten);
assertSame(cookie, response.getCookies().getFirst("ID"));
@@ -104,6 +108,7 @@ public class ServerHttpResponseTests {
response.beforeCommit(() -> Mono.error(error));
response.writeWith(Flux.just(wrap("a"), wrap("b"), wrap("c"))).block();
assertTrue("beforeCommit action errors should be ignored", response.statusCodeWritten);
assertTrue("beforeCommit action errors should be ignored", response.headersWritten);
assertTrue("beforeCommit action errors should be ignored", response.cookiesWritten);
assertNull(response.getCookies().get("ID"));
@@ -124,6 +129,7 @@ public class ServerHttpResponseTests {
});
response.setComplete().block();
assertTrue(response.statusCodeWritten);
assertTrue(response.headersWritten);
assertTrue(response.cookiesWritten);
assertTrue(response.body.isEmpty());
@@ -139,6 +145,8 @@ public class ServerHttpResponseTests {
private static class TestServerHttpResponse extends AbstractServerHttpResponse {
private boolean statusCodeWritten;
private boolean headersWritten;
private boolean cookiesWritten;
@@ -150,7 +158,9 @@ public class ServerHttpResponseTests {
}
@Override
public void setStatusCode(HttpStatus status) {
public void writeStatusCode() {
assertFalse(this.statusCodeWritten);
this.statusCodeWritten = true;
}
@Override