Refactor ResponseBodySubscriber to Processor
This commit changes the AbstractResponseBodySubscriber into a AbstractResponseBodyProcessor<DataBuffer, Void>, so that the processor can be used as a return value for writeWith. Additional, this commit no longer closes the response after an eror occurred. This fixes #59.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-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.springframework.http.server.reactive;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.server.reactive.boot.ReactorHttpServer;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class ErrorHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTests {
|
||||
|
||||
private ErrorHandler handler = new ErrorHandler();
|
||||
|
||||
@Override
|
||||
protected HttpHandler createHttpHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void response() throws Exception {
|
||||
// TODO: fix Reactor
|
||||
assumeFalse(server instanceof ReactorHttpServer);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER);
|
||||
|
||||
ResponseEntity<String> response = restTemplate
|
||||
.getForEntity(new URI("http://localhost:" + port + "/response"),
|
||||
String.class);
|
||||
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnValue() throws Exception {
|
||||
// TODO: fix Reactor
|
||||
assumeFalse(server instanceof ReactorHttpServer);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER);
|
||||
|
||||
ResponseEntity<String> response = restTemplate
|
||||
.getForEntity(new URI("http://localhost:" + port + "/returnValue"),
|
||||
String.class);
|
||||
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
|
||||
}
|
||||
|
||||
private static class ErrorHandler implements HttpHandler {
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
Exception error = new UnsupportedOperationException();
|
||||
String path = request.getURI().getPath();
|
||||
if (path.endsWith("response")) {
|
||||
return response.writeWith(Mono.error(error));
|
||||
}
|
||||
else if (path.endsWith("returnValue")) {
|
||||
return Mono.error(error);
|
||||
}
|
||||
else {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResponseErrorHandler NO_OP_ERROR_HANDLER =
|
||||
new ResponseErrorHandler() {
|
||||
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -21,8 +21,6 @@ import java.util.Random;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -31,12 +29,9 @@ import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.server.reactive.boot.ReactorHttpServer;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTests {
|
||||
|
||||
@@ -60,7 +55,6 @@ public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegratio
|
||||
@Test
|
||||
public void random() throws Throwable {
|
||||
// TODO: fix Reactor support
|
||||
assumeFalse(server instanceof ReactorHttpServer);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@@ -72,14 +66,6 @@ public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegratio
|
||||
assertEquals(RESPONSE_SIZE,
|
||||
response.getHeaders().getContentLength());
|
||||
assertEquals(RESPONSE_SIZE, response.getBody().length);
|
||||
|
||||
while (!handler.requestComplete) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
if (handler.requestError != null) {
|
||||
throw handler.requestError;
|
||||
}
|
||||
assertEquals(REQUEST_SIZE, handler.requestSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,45 +79,21 @@ public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegratio
|
||||
|
||||
public static final int CHUNKS = 16;
|
||||
|
||||
private volatile boolean requestComplete;
|
||||
|
||||
private int requestSize;
|
||||
|
||||
private Throwable requestError;
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
requestError = null;
|
||||
Mono<Integer> requestSizeMono = request.getBody().
|
||||
reduce(0, (integer, dataBuffer) -> integer +
|
||||
dataBuffer.readableByteCount()).
|
||||
doAfterTerminate((size, throwable) -> {
|
||||
assertNull(throwable);
|
||||
assertEquals(REQUEST_SIZE, (long) size);
|
||||
});
|
||||
|
||||
request.getBody().subscribe(new Subscriber<DataBuffer>() {
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Subscription s) {
|
||||
requestComplete = false;
|
||||
requestSize = 0;
|
||||
requestError = null;
|
||||
s.request(Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(DataBuffer bytes) {
|
||||
requestSize += bytes.readableByteCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
requestComplete = true;
|
||||
requestError = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
requestComplete = true;
|
||||
}
|
||||
});
|
||||
|
||||
response.getHeaders().setContentLength(RESPONSE_SIZE);
|
||||
return response.writeWith(multipleChunks());
|
||||
|
||||
return requestSizeMono.then(response.writeWith(multipleChunks()));
|
||||
}
|
||||
|
||||
private Publisher<DataBuffer> singleChunk() {
|
||||
|
||||
Reference in New Issue
Block a user