use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.
the class DefaultHttpClient method streamRequestThroughChannel.
private void streamRequestThroughChannel(io.micronaut.http.HttpRequest<?> parentRequest, AtomicReference<io.micronaut.http.HttpRequest> requestWrapper, FluxSink emitter, Channel channel, boolean failOnError) throws HttpPostRequestEncoder.ErrorDataEncoderException {
io.micronaut.http.HttpRequest<?> finalRequest = requestWrapper.get();
URI requestURI = finalRequest.getUri();
NettyRequestWriter requestWriter = prepareRequest(finalRequest, requestURI, emitter, false);
HttpRequest nettyRequest = requestWriter.getNettyRequest();
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(ChannelPipelineCustomizer.HANDLER_MICRONAUT_HTTP_RESPONSE_FULL, new SimpleChannelInboundHandlerInstrumented<FullHttpResponse>() {
final AtomicBoolean received = new AtomicBoolean(false);
@Override
public boolean acceptInboundMessage(Object msg) {
return msg instanceof FullHttpResponse;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (received.compareAndSet(false, true)) {
emitter.error(cause);
}
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent && received.compareAndSet(false, true)) {
// closed to idle ste
emitter.error(ReadTimeoutException.TIMEOUT_EXCEPTION);
}
}
@Override
protected void channelReadInstrumented(ChannelHandlerContext ctx, FullHttpResponse msg) {
if (received.compareAndSet(false, true)) {
HttpResponseStatus status = msg.status();
int statusCode = status.code();
HttpStatus httpStatus;
try {
httpStatus = HttpStatus.valueOf(statusCode);
} catch (IllegalArgumentException e) {
emitter.error(e);
return;
}
Publisher<HttpContent> bodyPublisher;
if (msg.content() instanceof EmptyByteBuf) {
bodyPublisher = Publishers.empty();
} else {
bodyPublisher = Publishers.just(new DefaultLastHttpContent(msg.content()));
}
DefaultStreamedHttpResponse nettyResponse = new DefaultStreamedHttpResponse(msg.protocolVersion(), msg.status(), msg.headers(), bodyPublisher);
NettyStreamedHttpResponse response = new NettyStreamedHttpResponse(nettyResponse, httpStatus);
HttpHeaders headers = msg.headers();
if (log.isTraceEnabled()) {
log.trace("HTTP Client Streaming Response Received ({}) for Request: {} {}", msg.status(), nettyRequest.method().name(), nettyRequest.uri());
traceHeaders(headers);
}
boolean errorStatus = statusCode >= 400;
if (errorStatus && failOnError) {
emitter.error(new HttpClientResponseException(response.getStatus().getReason(), response));
} else {
emitter.next(response);
emitter.complete();
}
}
}
});
pipeline.addLast(ChannelPipelineCustomizer.HANDLER_MICRONAUT_HTTP_RESPONSE_STREAM, new SimpleChannelInboundHandlerInstrumented<StreamedHttpResponse>() {
final AtomicBoolean received = new AtomicBoolean(false);
@Override
public boolean acceptInboundMessage(Object msg) {
return msg instanceof StreamedHttpResponse;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (received.compareAndSet(false, true)) {
emitter.error(cause);
}
}
@Override
protected void channelReadInstrumented(ChannelHandlerContext ctx, StreamedHttpResponse msg) {
if (received.compareAndSet(false, true)) {
HttpResponseStatus status = msg.status();
int statusCode = status.code();
HttpStatus httpStatus;
try {
httpStatus = HttpStatus.valueOf(statusCode);
} catch (IllegalArgumentException e) {
emitter.error(e);
return;
}
NettyStreamedHttpResponse response = new NettyStreamedHttpResponse(msg, httpStatus);
HttpHeaders headers = msg.headers();
if (log.isTraceEnabled()) {
log.trace("HTTP Client Streaming Response Received ({}) for Request: {} {}", msg.status(), nettyRequest.method().name(), nettyRequest.uri());
traceHeaders(headers);
}
if (statusCode > 300 && statusCode < 400 && configuration.isFollowRedirects() && headers.contains(HttpHeaderNames.LOCATION)) {
String location = headers.get(HttpHeaderNames.LOCATION);
Flux<io.micronaut.http.HttpResponse<Object>> redirectedExchange;
try {
MutableHttpRequest<Object> redirectRequest;
if (statusCode == 307) {
redirectRequest = io.micronaut.http.HttpRequest.create(finalRequest.getMethod(), location);
finalRequest.getBody().ifPresent(redirectRequest::body);
} else {
redirectRequest = io.micronaut.http.HttpRequest.GET(location);
}
setRedirectHeaders(nettyRequest, redirectRequest);
redirectedExchange = Flux.from(resolveRedirectURI(parentRequest, redirectRequest)).flatMap(uri -> buildStreamExchange(parentRequest, redirectRequest, uri, null));
// noinspection SubscriberImplementation
redirectedExchange.subscribe(new Subscriber<io.micronaut.http.HttpResponse<Object>>() {
Subscription sub;
@Override
public void onSubscribe(Subscription s) {
s.request(1);
this.sub = s;
}
@Override
public void onNext(io.micronaut.http.HttpResponse<Object> objectHttpResponse) {
emitter.next(objectHttpResponse);
}
@Override
public void onError(Throwable t) {
emitter.error(t);
}
@Override
public void onComplete() {
emitter.complete();
}
});
} catch (Exception e) {
emitter.error(e);
}
} else {
boolean errorStatus = statusCode >= 400;
if (errorStatus && failOnError) {
emitter.error(new HttpClientResponseException(response.getStatus().getReason(), response));
} else {
emitter.next(response);
emitter.complete();
}
}
}
}
});
if (log.isDebugEnabled()) {
debugRequest(requestURI, nettyRequest);
}
if (log.isTraceEnabled()) {
traceRequest(requestWrapper.get(), nettyRequest);
}
requestWriter.writeAndClose(channel, null, emitter);
}
use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.
the class RoutingInBoundHandler method createNettyResponse.
@NonNull
private NettyMutableHttpResponse<?> createNettyResponse(HttpResponse<?> message) {
HttpStatus httpStatus = message.status();
Object body = message.body();
io.netty.handler.codec.http.HttpHeaders nettyHeaders = new DefaultHttpHeaders(serverConfiguration.isValidateHeaders());
message.getHeaders().forEach((BiConsumer<String, List<String>>) nettyHeaders::set);
return new NettyMutableHttpResponse<>(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(httpStatus.getCode(), httpStatus.getReason()), body instanceof ByteBuf ? body : null, ConversionService.SHARED);
}
use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.
the class HttpConverterRegistrar method register.
@Override
public void register(ConversionService<?> conversionService) {
conversionService.addConverter(String.class, HttpVersion.class, s -> {
try {
return HttpVersion.valueOf(Double.parseDouble(s));
} catch (NumberFormatException e) {
return HttpVersion.valueOf(s);
}
});
conversionService.addConverter(Number.class, HttpVersion.class, s -> HttpVersion.valueOf(s.doubleValue()));
conversionService.addConverter(CharSequence.class, Readable.class, (object, targetType, context) -> {
String pathStr = object.toString();
Optional<ResourceLoader> supportingLoader = resourceResolver.getSupportingLoader(pathStr);
if (!supportingLoader.isPresent()) {
context.reject(pathStr, new ConfigurationException("No supported resource loader for path [" + pathStr + "]. Prefix the path with a supported prefix such as 'classpath:' or 'file:'"));
return Optional.empty();
} else {
final Optional<URL> resource = resourceResolver.getResource(pathStr);
if (resource.isPresent()) {
return Optional.of(Readable.of(resource.get()));
} else {
context.reject(object, new ConfigurationException("No resource exists for value: " + object));
return Optional.empty();
}
}
});
conversionService.addConverter(CharSequence.class, MediaType.class, (object, targetType, context) -> {
try {
return Optional.of(MediaType.of(object));
} catch (IllegalArgumentException e) {
context.reject(e);
return Optional.empty();
}
});
conversionService.addConverter(Number.class, HttpStatus.class, (object, targetType, context) -> {
try {
HttpStatus status = HttpStatus.valueOf(object.shortValue());
return Optional.of(status);
} catch (IllegalArgumentException e) {
context.reject(object, e);
return Optional.empty();
}
});
conversionService.addConverter(CharSequence.class, SocketAddress.class, (object, targetType, context) -> {
String address = object.toString();
try {
URL url = new URL(address);
int port = url.getPort();
if (port == -1) {
port = url.getDefaultPort();
}
if (port == -1) {
context.reject(object, new ConfigurationException("Failed to find a port in the given value"));
return Optional.empty();
}
return Optional.of(InetSocketAddress.createUnresolved(url.getHost(), port));
} catch (MalformedURLException malformedURLException) {
String[] parts = object.toString().split(":");
if (parts.length == 2) {
try {
int port = Integer.parseInt(parts[1]);
return Optional.of(InetSocketAddress.createUnresolved(parts[0], port));
} catch (IllegalArgumentException illegalArgumentException) {
context.reject(object, illegalArgumentException);
return Optional.empty();
}
} else {
context.reject(object, new ConfigurationException("The address is not in a proper format of IP:PORT or a standard URL"));
return Optional.empty();
}
}
});
conversionService.addConverter(CharSequence.class, ProxySelector.class, (object, targetType, context) -> {
if (object.toString().equals("default")) {
return Optional.of(ProxySelector.getDefault());
} else {
return Optional.empty();
}
});
}
use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.
the class HealthResultFilter method doFilterOnce.
@Override
protected Publisher<MutableHttpResponse<?>> doFilterOnce(HttpRequest<?> request, ServerFilterChain chain) {
return Publishers.map(chain.proceed(request), response -> {
Object body = response.body();
if (body instanceof HealthResult) {
HealthResult healthResult = (HealthResult) body;
HealthStatus status = healthResult.getStatus();
HttpStatus httpStatus = healthEndpoint.getStatusConfiguration().getHttpMapping().get(status.getName());
if (httpStatus != null) {
response.status(httpStatus);
} else {
boolean operational = status.getOperational().orElse(true);
if (!operational) {
response.status(HttpStatus.SERVICE_UNAVAILABLE);
}
}
}
return response;
});
}
use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.
the class ServiceHttpClientFactory method healthCheckStarter.
/**
* Creates a {@link ApplicationEventListener} that listens to {@link ServerStartupEvent} for each configured HTTP client
* in order to register a health check if necessary.
*
* @param configuration The configuration
* @param instanceList The instance list
* @return The event listener
*/
@EachBean(ServiceHttpClientConfiguration.class)
@Requires(condition = ServiceHttpClientCondition.class)
ApplicationEventListener<ServerStartupEvent> healthCheckStarter(@Parameter ServiceHttpClientConfiguration configuration, @Parameter StaticServiceInstanceList instanceList) {
if (configuration.isHealthCheck()) {
return event -> {
final List<URI> originalURLs = configuration.getUrls();
Collection<URI> loadBalancedURIs = instanceList.getLoadBalancedURIs();
final HttpClient httpClient = clientFactory.get().getClient(configuration.getHttpVersion(), configuration.getServiceId(), configuration.getPath().orElse(null));
final Duration initialDelay = configuration.getHealthCheckInterval();
Duration delay = configuration.getHealthCheckInterval();
taskScheduler.scheduleWithFixedDelay(initialDelay, delay, () -> Flux.fromIterable(originalURLs).flatMap(originalURI -> {
URI healthCheckURI = originalURI.resolve(configuration.getHealthCheckUri());
return Flux.from(httpClient.exchange(HttpRequest.GET(healthCheckURI))).onErrorResume(throwable -> {
if (throwable instanceof HttpClientResponseException) {
HttpClientResponseException responseException = (HttpClientResponseException) throwable;
return Flux.just((HttpResponse<ByteBuffer>) responseException.getResponse());
}
return Flux.just(HttpResponse.serverError());
}).map(response -> Collections.singletonMap(originalURI, response.getStatus()));
}).subscribe(uriToStatusMap -> {
Map.Entry<URI, HttpStatus> entry = uriToStatusMap.entrySet().iterator().next();
URI uri = entry.getKey();
HttpStatus status = entry.getValue();
if (status.getCode() >= 300) {
loadBalancedURIs.remove(uri);
} else if (!loadBalancedURIs.contains(uri)) {
loadBalancedURIs.add(uri);
}
}));
};
}
throw new DisabledBeanException("HTTP Client Health Check not enabled");
}
Aggregations