001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.http.server.reactive;
018
019import java.net.URISyntaxException;
020import java.util.function.BiFunction;
021
022import io.netty.handler.codec.http.HttpResponseStatus;
023import org.apache.commons.logging.Log;
024import reactor.core.publisher.Mono;
025import reactor.netty.http.server.HttpServerRequest;
026import reactor.netty.http.server.HttpServerResponse;
027
028import org.springframework.core.io.buffer.NettyDataBufferFactory;
029import org.springframework.http.HttpLogging;
030import org.springframework.http.HttpMethod;
031import org.springframework.util.Assert;
032
033/**
034 * Adapt {@link HttpHandler} to the Reactor Netty channel handling function.
035 *
036 * @author Stephane Maldini
037 * @author Rossen Stoyanchev
038 * @since 5.0
039 */
040public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>> {
041
042        private static final Log logger = HttpLogging.forLogName(ReactorHttpHandlerAdapter.class);
043
044
045        private final HttpHandler httpHandler;
046
047
048        public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
049                Assert.notNull(httpHandler, "HttpHandler must not be null");
050                this.httpHandler = httpHandler;
051        }
052
053
054        @Override
055        public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
056                NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
057                try {
058                        ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
059                        ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
060
061                        if (request.getMethod() == HttpMethod.HEAD) {
062                                response = new HttpHeadResponseDecorator(response);
063                        }
064
065                        return this.httpHandler.handle(request, response)
066                                        .doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
067                                        .doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
068                }
069                catch (URISyntaxException ex) {
070                        if (logger.isDebugEnabled()) {
071                                logger.debug("Failed to get request URI: " + ex.getMessage());
072                        }
073                        reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
074                        return Mono.empty();
075                }
076        }
077
078}