/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.undertow;
import java.io.IOException;
import java.nio.ByteBuffer;
import io.undertow.Handlers;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.form.EagerFormParsingHandler;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
import io.undertow.util.MimeMappings;
import io.undertow.util.StatusCodes;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.TypeConverter;
import org.apache.camel.impl.DefaultConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Undertow consumer which is also an Undertow HttpHandler implementation to handle incoming request.
*/
public class UndertowConsumer extends DefaultConsumer implements HttpHandler {
private static final Logger LOG = LoggerFactory.getLogger(UndertowConsumer.class);
private HttpHandlerRegistrationInfo registrationInfo;
public UndertowConsumer(UndertowEndpoint endpoint, Processor processor) {
super(endpoint, processor);
}
@Override
public UndertowEndpoint getEndpoint() {
return (UndertowEndpoint) super.getEndpoint();
}
@Override
protected void doStart() throws Exception {
super.doStart();
getEndpoint().getComponent().registerConsumer(this);
}
@Override
protected void doStop() throws Exception {
super.doStop();
getEndpoint().getComponent().unregisterConsumer(this);
}
public HttpHandlerRegistrationInfo getHttpHandlerRegistrationInfo() {
if (registrationInfo == null) {
UndertowEndpoint endpoint = getEndpoint();
registrationInfo = new HttpHandlerRegistrationInfo();
registrationInfo.setUri(endpoint.getHttpURI());
registrationInfo.setMethodRestrict(endpoint.getHttpMethodRestrict());
registrationInfo.setMatchOnUriPrefix(endpoint.getMatchOnUriPrefix());
}
return registrationInfo;
}
public HttpHandler getHttpHandler() {
// allow for HTTP 1.1 continue
return Handlers.httpContinueRead(
// wrap with EagerFormParsingHandler to enable undertow form parsers
new EagerFormParsingHandler().setNext(this));
}
@Override
public void handleRequest(HttpServerExchange httpExchange) throws Exception {
HttpString requestMethod = httpExchange.getRequestMethod();
if (Methods.OPTIONS.equals(requestMethod) && !getEndpoint().isOptionsEnabled()) {
String allowedMethods;
if (getEndpoint().getHttpMethodRestrict() != null) {
allowedMethods = "OPTIONS," + getEndpoint().getHttpMethodRestrict();
} else {
allowedMethods = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATCH";
}
//return list of allowed methods in response headers
httpExchange.setStatusCode(StatusCodes.OK);
httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_TYPE, MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_LENGTH, 0);
httpExchange.getResponseHeaders().put(Headers.ALLOW, allowedMethods);
httpExchange.getResponseSender().close();
return;
}
//perform blocking operation on exchange
if (httpExchange.isInIoThread()) {
httpExchange.dispatch(this);
return;
}
//create new Exchange
//binding is used to extract header and payload(if available)
Exchange camelExchange = getEndpoint().createExchange(httpExchange);
//Unit of Work to process the Exchange
createUoW(camelExchange);
try {
getProcessor().process(camelExchange);
} catch (Exception e) {
getExceptionHandler().handleException(e);
} finally {
doneUoW(camelExchange);
}
Object body = getResponseBody(httpExchange, camelExchange);
TypeConverter tc = getEndpoint().getCamelContext().getTypeConverter();
if (body == null) {
LOG.trace("No payload to send as reply for exchange: " + camelExchange);
httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_TYPE, MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
httpExchange.getResponseSender().send("No response available");
} else {
ByteBuffer bodyAsByteBuffer = tc.convertTo(ByteBuffer.class, body);
httpExchange.getResponseSender().send(bodyAsByteBuffer);
}
httpExchange.getResponseSender().close();
}
private Object getResponseBody(HttpServerExchange httpExchange, Exchange camelExchange) throws IOException {
Object result;
if (camelExchange.hasOut()) {
result = getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getOut());
} else {
result = getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getIn());
}
return result;
}
}