use of ratpack.func.Action in project ratpack by ratpack.
the class NettyHandlerAdapter method newRequest.
private void newRequest(final ChannelHandlerContext ctx, final HttpRequest nettyRequest) throws Exception {
if (!nettyRequest.decoderResult().isSuccess()) {
sendError(ctx, HttpResponseStatus.BAD_REQUEST);
return;
}
Headers requestHeaders = new NettyHeadersBackedHeaders(nettyRequest.headers());
//Find the content length we will use this as an indicator of a body
Long contentLength = HttpUtil.getContentLength(nettyRequest, -1L);
String transferEncoding = requestHeaders.get(HttpHeaderNames.TRANSFER_ENCODING);
//If there is a content length or transfer encoding that indicates there is a body
boolean hasBody = (contentLength > 0) || (transferEncoding != null);
RequestBody requestBody = hasBody ? new RequestBody(contentLength, nettyRequest, ctx) : null;
final Channel channel = ctx.channel();
if (requestBody != null) {
channel.attr(BODY_ACCUMULATOR_KEY).set(requestBody);
}
InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
InetSocketAddress socketAddress = (InetSocketAddress) channel.localAddress();
final DefaultRequest request = new DefaultRequest(Instant.now(), requestHeaders, nettyRequest.method(), nettyRequest.protocolVersion(), nettyRequest.uri(), remoteAddress, socketAddress, serverRegistry.get(ServerConfig.class), requestBody);
final HttpHeaders nettyHeaders = new DefaultHttpHeaders(false);
final MutableHeaders responseHeaders = new NettyHeadersBackedMutableHeaders(nettyHeaders);
final AtomicBoolean transmitted = new AtomicBoolean(false);
final DefaultResponseTransmitter responseTransmitter = new DefaultResponseTransmitter(transmitted, channel, nettyRequest, request, nettyHeaders, requestBody);
ctx.channel().attr(DefaultResponseTransmitter.ATTRIBUTE_KEY).set(responseTransmitter);
Action<Action<Object>> subscribeHandler = thing -> {
transmitted.set(true);
ctx.channel().attr(CHANNEL_SUBSCRIBER_ATTRIBUTE_KEY).set(thing);
};
final DefaultContext.RequestConstants requestConstants = new DefaultContext.RequestConstants(applicationConstants, request, channel, responseTransmitter, subscribeHandler);
final Response response = new DefaultResponse(responseHeaders, ctx.alloc(), responseTransmitter);
requestConstants.response = response;
DefaultContext.start(channel.eventLoop(), requestConstants, serverRegistry, handlers, execution -> {
if (requestBody != null) {
requestBody.close();
channel.attr(BODY_ACCUMULATOR_KEY).set(null);
}
if (!transmitted.get()) {
Handler lastHandler = requestConstants.handler;
StringBuilder description = new StringBuilder();
description.append("No response sent for ").append(request.getMethod().getName()).append(" request to ").append(request.getUri());
if (lastHandler != null) {
description.append(" (last handler: ");
if (lastHandler instanceof DescribingHandler) {
((DescribingHandler) lastHandler).describeTo(description);
} else {
DescribingHandlers.describeTo(lastHandler, description);
}
description.append(")");
}
String message = description.toString();
LOGGER.warn(message);
response.getHeaders().clear();
ByteBuf body;
if (development) {
CharBuffer charBuffer = CharBuffer.wrap(message);
body = ByteBufUtil.encodeString(ctx.alloc(), charBuffer, CharsetUtil.UTF_8);
response.contentType(HttpHeaderConstants.PLAIN_TEXT_UTF8);
} else {
body = Unpooled.EMPTY_BUFFER;
}
response.getHeaders().set(HttpHeaderConstants.CONTENT_LENGTH, body.readableBytes());
responseTransmitter.transmit(HttpResponseStatus.INTERNAL_SERVER_ERROR, body);
}
});
}
use of ratpack.func.Action in project ratpack by ratpack.
the class Guice method buildInjector.
static Injector buildInjector(Registry baseRegistry, Action<? super BindingsSpec> bindingsAction, Function<? super Module, ? extends Injector> injectorFactory) throws Exception {
List<Action<? super Binder>> binderActions = Lists.newLinkedList();
List<Module> modules = Lists.newLinkedList();
ServerConfig serverConfig = baseRegistry.get(ServerConfig.class);
BindingsSpec bindings = new DefaultBindingsSpec(serverConfig, binderActions, modules);
bindings.module(new RatpackBaseRegistryModule(baseRegistry));
try {
bindingsAction.execute(bindings);
} catch (Exception e) {
throw uncheck(e);
}
modules.add(new AdHocModule(binderActions));
modules.add(new ConfigModule(serverConfig.getRequiredConfig()));
Optional<BindingsImposition> bindingsImposition = Impositions.current().get(BindingsImposition.class);
if (bindingsImposition.isPresent()) {
BindingsImposition imposition = bindingsImposition.get();
List<Action<? super Binder>> imposedBinderActions = Lists.newLinkedList();
List<Module> imposedModules = Lists.newLinkedList();
BindingsSpec imposedBindings = new DefaultBindingsSpec(serverConfig, imposedBinderActions, imposedModules);
imposition.getBindings().execute(imposedBindings);
imposedModules.add(new AdHocModule(imposedBinderActions));
Module imposedModule = imposedModules.stream().reduce((acc, next) -> Modules.override(acc).with(next)).get();
modules.add(imposedModule);
}
Module masterModule = modules.stream().reduce((acc, next) -> Modules.override(acc).with(next)).get();
return injectorFactory.apply(masterModule);
}
use of ratpack.func.Action in project ratpack by ratpack.
the class DefaultExecHarness method run.
@Override
public void run(Action<? super RegistrySpec> registry, Action<? super Execution> action) throws Exception {
final AtomicReference<Throwable> thrown = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);
controller.fork().onError(thrown::set).register(registry).onComplete(e -> latch.countDown()).start(action::execute);
latch.await();
Throwable throwable = thrown.get();
if (throwable != null) {
throw Exceptions.toException(throwable);
}
}
use of ratpack.func.Action in project ratpack by ratpack.
the class DefaultExecHarness method yield.
@Override
public <T> ExecResult<T> yield(Action<? super RegistrySpec> registry, final Function<? super Execution, ? extends Promise<T>> func) throws Exception {
AtomicReference<ExecResult<T>> reference = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
controller.fork().register(registry).onError(throwable -> reference.set(new ResultBackedExecResult<>(Result.<T>error(throwable)))).onComplete(exec -> latch.countDown()).start(execution -> {
reference.set(ExecResult.complete());
Promise<T> promise = func.apply(execution);
if (promise == null) {
reference.set(null);
} else {
promise.then(t -> reference.set(new ResultBackedExecResult<>(Result.success(t))));
}
});
latch.await();
return reference.get();
}
use of ratpack.func.Action in project ratpack by ratpack.
the class RequestActionSupport method addCommonResponseHandlers.
private void addCommonResponseHandlers(ChannelPipeline p, Downstream<? super T> downstream) throws Exception {
if (channelKey.ssl && p.get(SSL_HANDLER_NAME) == null) {
//this is added once because netty is not able to properly replace this handler on
//pooled channels from request to request. Because a pool is unique to a uri,
//doing this works, as subsequent requests would be passing in the same certs.
p.addLast(SSL_HANDLER_NAME, createSslHandler());
}
p.addLast(CLIENT_CODEC_HANDLER_NAME, new HttpClientCodec(4096, 8192, 8192, false));
p.addLast(READ_TIMEOUT_HANDLER_NAME, new ReadTimeoutHandler(requestConfig.readTimeout.toNanos(), TimeUnit.NANOSECONDS));
p.addLast(REDIRECT_HANDLER_NAME, new SimpleChannelInboundHandler<HttpObject>(false) {
boolean redirected;
HttpResponse response;
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
forceDispose(ctx.pipeline());
if (cause instanceof ReadTimeoutException) {
cause = new HttpClientReadTimeoutException("Read timeout (" + requestConfig.readTimeout + ") waiting on HTTP server at " + requestConfig.uri);
}
error(downstream, cause);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Exception e = new PrematureChannelClosureException("Server " + requestConfig.uri + " closed the connection prematurely");
error(downstream, e);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if (msg instanceof HttpResponse) {
this.response = (HttpResponse) msg;
int maxRedirects = requestConfig.maxRedirects;
int status = response.status().code();
String locationValue = response.headers().getAsString(HttpHeaderConstants.LOCATION);
Action<? super RequestSpec> redirectConfigurer = RequestActionSupport.this.requestConfigurer;
if (isRedirect(status) && redirectCount < maxRedirects && locationValue != null) {
final Function<? super ReceivedResponse, Action<? super RequestSpec>> onRedirect = requestConfig.onRedirect;
if (onRedirect != null) {
final Action<? super RequestSpec> onRedirectResult = onRedirect.apply(toReceivedResponse(response));
if (onRedirectResult == null) {
redirectConfigurer = null;
} else {
redirectConfigurer = redirectConfigurer.append(onRedirectResult);
}
}
if (redirectConfigurer != null) {
Action<? super RequestSpec> redirectRequestConfig = s -> {
if (status == 301 || status == 302) {
s.get();
}
};
redirectRequestConfig = redirectRequestConfig.append(redirectConfigurer);
URI locationUrl;
if (ABSOLUTE_PATTERN.matcher(locationValue).matches()) {
locationUrl = new URI(locationValue);
} else {
locationUrl = new URI(channelKey.ssl ? "https" : "http", null, channelKey.host, channelKey.port, locationValue, null, null);
}
onRedirect(locationUrl, redirectCount + 1, redirectRequestConfig).connect(downstream);
redirected = true;
dispose(ctx.pipeline(), response);
}
}
}
if (!redirected) {
ctx.fireChannelRead(msg);
}
}
});
if (requestConfig.decompressResponse) {
p.addLast(DECOMPRESS_HANDLER_NAME, new HttpContentDecompressor());
}
addResponseHandlers(p, downstream);
}
Aggregations