* We shouldn't be recreating wrapped REST handlers over and over for every request. We only use this hook in x-pack and the wrapper there does not have any per request state. This is inefficient and could lead to some very unexpected memory behavior => I made the logic create the wrapper on handler registration and adjusted the x-pack wrapper implementation to correctly forward the circuit breaker and content stream flags
This commit is contained in:
parent
56da35b706
commit
c7d7230524
|
@ -152,8 +152,9 @@ public class RestController implements HttpServerTransport.Dispatcher {
|
||||||
if (handler instanceof BaseRestHandler) {
|
if (handler instanceof BaseRestHandler) {
|
||||||
usageService.addRestHandler((BaseRestHandler) handler);
|
usageService.addRestHandler((BaseRestHandler) handler);
|
||||||
}
|
}
|
||||||
handlers.insertOrUpdate(path, new MethodHandlers(path, handler, method), (mHandlers, newMHandler) -> {
|
final RestHandler maybeWrappedHandler = handlerWrapper.apply(handler);
|
||||||
return mHandlers.addMethods(handler, method);
|
handlers.insertOrUpdate(path, new MethodHandlers(path, maybeWrappedHandler, method), (mHandlers, newMHandler) -> {
|
||||||
|
return mHandlers.addMethods(maybeWrappedHandler, method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +237,7 @@ public class RestController implements HttpServerTransport.Dispatcher {
|
||||||
// iff we could reserve bytes for the request we need to send the response also over this channel
|
// iff we could reserve bytes for the request we need to send the response also over this channel
|
||||||
responseChannel = new ResourceHandlingHttpChannel(channel, circuitBreakerService, contentLength);
|
responseChannel = new ResourceHandlingHttpChannel(channel, circuitBreakerService, contentLength);
|
||||||
|
|
||||||
final RestHandler wrappedHandler = mHandler.map(h -> handlerWrapper.apply(h)).get();
|
final RestHandler wrappedHandler = mHandler.get();
|
||||||
wrappedHandler.handleRequest(request, responseChannel, client);
|
wrappedHandler.handleRequest(request, responseChannel, client);
|
||||||
requestHandled = true;
|
requestHandled = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -57,7 +57,6 @@ import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.UnaryOperator;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -80,7 +79,6 @@ public class RestControllerTests extends ESTestCase {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
Settings settings = Settings.EMPTY;
|
|
||||||
circuitBreakerService = new HierarchyCircuitBreakerService(
|
circuitBreakerService = new HierarchyCircuitBreakerService(
|
||||||
Settings.builder()
|
Settings.builder()
|
||||||
.put(HierarchyCircuitBreakerService.IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_LIMIT_SETTING.getKey(), BREAKER_LIMIT)
|
.put(HierarchyCircuitBreakerService.IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_LIMIT_SETTING.getKey(), BREAKER_LIMIT)
|
||||||
|
@ -205,16 +203,19 @@ public class RestControllerTests extends ESTestCase {
|
||||||
public void testRestHandlerWrapper() throws Exception {
|
public void testRestHandlerWrapper() throws Exception {
|
||||||
AtomicBoolean handlerCalled = new AtomicBoolean(false);
|
AtomicBoolean handlerCalled = new AtomicBoolean(false);
|
||||||
AtomicBoolean wrapperCalled = new AtomicBoolean(false);
|
AtomicBoolean wrapperCalled = new AtomicBoolean(false);
|
||||||
RestHandler handler = (RestRequest request, RestChannel channel, NodeClient client) -> {
|
final RestHandler handler = (RestRequest request, RestChannel channel, NodeClient client) -> handlerCalled.set(true);
|
||||||
handlerCalled.set(true);
|
final HttpServerTransport httpServerTransport = new TestHttpServerTransport();
|
||||||
};
|
final RestController restController =
|
||||||
UnaryOperator<RestHandler> wrapper = h -> {
|
new RestController(Collections.emptySet(),
|
||||||
assertSame(handler, h);
|
h -> {
|
||||||
return (RestRequest request, RestChannel channel, NodeClient client) -> wrapperCalled.set(true);
|
assertSame(handler, h);
|
||||||
};
|
return (RestRequest request, RestChannel channel, NodeClient client) -> wrapperCalled.set(true);
|
||||||
final RestController restController = new RestController(Collections.emptySet(), wrapper, null,
|
}, null, circuitBreakerService, usageService);
|
||||||
circuitBreakerService, usageService);
|
restController.registerHandler(RestRequest.Method.GET, "/wrapped", handler);
|
||||||
restController.dispatchRequest(new FakeRestRequest.Builder(xContentRegistry()).build(), null, null, Optional.of(handler));
|
RestRequest request = testRestRequest("/wrapped", "{}", XContentType.JSON);
|
||||||
|
AssertingChannel channel = new AssertingChannel(request, true, RestStatus.BAD_REQUEST);
|
||||||
|
restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY));
|
||||||
|
httpServerTransport.start();
|
||||||
assertTrue(wrapperCalled.get());
|
assertTrue(wrapperCalled.get());
|
||||||
assertFalse(handlerCalled.get());
|
assertFalse(handlerCalled.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.security.rest;
|
package org.elasticsearch.xpack.security.rest;
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||||
import org.apache.logging.log4j.util.Supplier;
|
import org.apache.logging.log4j.util.Supplier;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
|
@ -70,7 +70,17 @@ public class SecurityRestFilter implements RestHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestRequest maybeWrapRestRequest(RestRequest restRequest) throws IOException {
|
@Override
|
||||||
|
public boolean canTripCircuitBreaker() {
|
||||||
|
return restHandler.canTripCircuitBreaker();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsContentStream() {
|
||||||
|
return restHandler.supportsContentStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestRequest maybeWrapRestRequest(RestRequest restRequest) throws IOException {
|
||||||
if (restHandler instanceof RestRequestFilter) {
|
if (restHandler instanceof RestRequestFilter) {
|
||||||
return ((RestRequestFilter)restHandler).getFilteredRequest(restRequest);
|
return ((RestRequestFilter)restHandler).getFilteredRequest(restRequest);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue