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.io.IOException; 020import java.net.URISyntaxException; 021 022import io.undertow.server.HttpServerExchange; 023import org.apache.commons.logging.Log; 024import org.reactivestreams.Subscriber; 025import org.reactivestreams.Subscription; 026 027import org.springframework.core.io.buffer.DataBufferFactory; 028import org.springframework.core.io.buffer.DefaultDataBufferFactory; 029import org.springframework.http.HttpLogging; 030import org.springframework.http.HttpMethod; 031import org.springframework.util.Assert; 032 033/** 034 * Adapt {@link HttpHandler} to the Undertow {@link io.undertow.server.HttpHandler}. 035 * 036 * @author Marek Hawrylczak 037 * @author Rossen Stoyanchev 038 * @author Arjen Poutsma 039 * @since 5.0 040 */ 041public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandler { 042 043 private static final Log logger = HttpLogging.forLogName(UndertowHttpHandlerAdapter.class); 044 045 046 private final HttpHandler httpHandler; 047 048 private DataBufferFactory bufferFactory = new DefaultDataBufferFactory(false); 049 050 051 public UndertowHttpHandlerAdapter(HttpHandler httpHandler) { 052 Assert.notNull(httpHandler, "HttpHandler must not be null"); 053 this.httpHandler = httpHandler; 054 } 055 056 057 public void setDataBufferFactory(DataBufferFactory bufferFactory) { 058 Assert.notNull(bufferFactory, "DataBufferFactory must not be null"); 059 this.bufferFactory = bufferFactory; 060 } 061 062 public DataBufferFactory getDataBufferFactory() { 063 return this.bufferFactory; 064 } 065 066 067 @Override 068 public void handleRequest(HttpServerExchange exchange) { 069 UndertowServerHttpRequest request = null; 070 try { 071 request = new UndertowServerHttpRequest(exchange, getDataBufferFactory()); 072 } 073 catch (URISyntaxException ex) { 074 if (logger.isWarnEnabled()) { 075 logger.debug("Failed to get request URI: " + ex.getMessage()); 076 } 077 exchange.setStatusCode(400); 078 return; 079 } 080 ServerHttpResponse response = new UndertowServerHttpResponse(exchange, getDataBufferFactory(), request); 081 082 if (request.getMethod() == HttpMethod.HEAD) { 083 response = new HttpHeadResponseDecorator(response); 084 } 085 086 HandlerResultSubscriber resultSubscriber = new HandlerResultSubscriber(exchange, request); 087 this.httpHandler.handle(request, response).subscribe(resultSubscriber); 088 } 089 090 091 private class HandlerResultSubscriber implements Subscriber<Void> { 092 093 private final HttpServerExchange exchange; 094 095 private final String logPrefix; 096 097 098 public HandlerResultSubscriber(HttpServerExchange exchange, UndertowServerHttpRequest request) { 099 this.exchange = exchange; 100 this.logPrefix = request.getLogPrefix(); 101 } 102 103 @Override 104 public void onSubscribe(Subscription subscription) { 105 subscription.request(Long.MAX_VALUE); 106 } 107 108 @Override 109 public void onNext(Void aVoid) { 110 // no-op 111 } 112 113 @Override 114 public void onError(Throwable ex) { 115 logger.trace(this.logPrefix + "Failed to complete: " + ex.getMessage()); 116 if (this.exchange.isResponseStarted()) { 117 try { 118 logger.debug(this.logPrefix + "Closing connection"); 119 this.exchange.getConnection().close(); 120 } 121 catch (IOException ex2) { 122 // ignore 123 } 124 } 125 else { 126 logger.debug(this.logPrefix + "Setting HttpServerExchange status to 500 Server Error"); 127 this.exchange.setStatusCode(500); 128 this.exchange.endExchange(); 129 } 130 } 131 132 @Override 133 public void onComplete() { 134 logger.trace(this.logPrefix + "Handling completed"); 135 this.exchange.endExchange(); 136 } 137 } 138 139}