You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2015/07/23 14:58:04 UTC
[02/24] camel git commit: camel-http-common - as a common module
camel-http-common - as a common module
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e51b7f8d
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e51b7f8d
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e51b7f8d
Branch: refs/heads/master
Commit: e51b7f8d9320072a64f60a23836c7ce15ffb45e7
Parents: 600063a
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Jul 23 09:23:46 2015 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Jul 23 15:04:30 2015 +0200
----------------------------------------------------------------------
.../camel/http/common/CamelFileDataSource.java | 52 ++
.../apache/camel/http/common/CamelServlet.java | 247 ++++++++++
.../camel/http/common/DefaultHttpBinding.java | 494 +++++++++++++++++++
.../apache/camel/http/common/HttpBinding.java | 160 ++++++
.../camel/http/common/HttpCommonComponent.java | 75 +++
.../camel/http/common/HttpCommonEndpoint.java | 383 ++++++++++++++
.../camel/http/common/HttpConfiguration.java | 143 ++++++
.../apache/camel/http/common/HttpConstants.java | 26 +
.../apache/camel/http/common/HttpConsumer.java | 80 +++
.../apache/camel/http/common/HttpConverter.java | 98 ++++
.../http/common/HttpHeaderFilterStrategy.java | 49 ++
.../apache/camel/http/common/HttpHelper.java | 429 ++++++++++++++++
.../apache/camel/http/common/HttpMessage.java | 81 +++
.../common/HttpOperationFailedException.java | 75 +++
.../HttpProtocolHeaderFilterStrategy.java | 87 ++++
.../HttpServletResolveConsumerStrategy.java | 50 ++
.../http/common/HttpServletUrlRewrite.java | 45 ++
.../common/ServletResolveConsumerStrategy.java | 37 ++
.../apache/camel/http/common/UrlRewrite.java | 41 ++
.../UrlRewriteHttpServletRequestAdapter.java | 49 ++
20 files changed, 2701 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelFileDataSource.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelFileDataSource.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelFileDataSource.java
new file mode 100644
index 0000000..8cb4c91
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelFileDataSource.java
@@ -0,0 +1,52 @@
+/**
+ * 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.http.common;
+
+import java.io.File;
+import javax.activation.FileDataSource;
+import javax.activation.FileTypeMap;
+
+public class CamelFileDataSource extends FileDataSource {
+ private final String fileName;
+ private FileTypeMap typeMap;
+
+ public CamelFileDataSource(File file, String fileName) {
+ super(file);
+ this.fileName = fileName;
+ }
+
+ public String getContentType() {
+ if (typeMap == null) {
+ return FileTypeMap.getDefaultFileTypeMap().getContentType(fileName);
+ } else {
+ return typeMap.getContentType(fileName);
+ }
+ }
+
+ public void setFileTypeMap(FileTypeMap map) {
+ typeMap = map;
+ }
+
+ public String getName() {
+ if (fileName != null) {
+ return fileName;
+ } else {
+ return super.getName();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
new file mode 100644
index 0000000..061bf47
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
@@ -0,0 +1,247 @@
+/**
+ * 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.http.common;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.impl.DefaultExchange;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A servlet to use as a Camel route as entry.
+ */
+public class CamelServlet extends HttpServlet {
+ private static final long serialVersionUID = -7061982839117697829L;
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * We have to define this explicitly so the name can be set as we can not always be
+ * sure that it is already set via the init method
+ */
+ private String servletName;
+
+ private ServletResolveConsumerStrategy servletResolveConsumerStrategy = new HttpServletResolveConsumerStrategy();
+ private final ConcurrentMap<String, HttpConsumer> consumers = new ConcurrentHashMap<String, HttpConsumer>();
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+ this.servletName = config.getServletName();
+ }
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ log.trace("Service: {}", request);
+
+ // Is there a consumer registered for the request.
+ HttpConsumer consumer = resolve(request);
+ if (consumer == null) {
+ log.debug("No consumer to service request {}", request);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ // are we suspended?
+ if (consumer.isSuspended()) {
+ log.debug("Consumer suspended, cannot service request {}", request);
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ return;
+ }
+
+ // if its an OPTIONS request then return which method is allowed
+ if ("OPTIONS".equals(request.getMethod())) {
+ String s;
+ if (consumer.getEndpoint().getHttpMethodRestrict() != null) {
+ s = "OPTIONS," + consumer.getEndpoint().getHttpMethodRestrict();
+ } else {
+ // allow them all
+ s = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATCH";
+ }
+ response.addHeader("Allow", s);
+ response.setStatus(HttpServletResponse.SC_OK);
+ return;
+ }
+
+ if (consumer.getEndpoint().getHttpMethodRestrict() != null
+ && !consumer.getEndpoint().getHttpMethodRestrict().contains(request.getMethod())) {
+ response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ return;
+ }
+
+ if ("TRACE".equals(request.getMethod()) && !consumer.isTraceEnabled()) {
+ response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ return;
+ }
+
+ // create exchange and set data on it
+ Exchange exchange = new DefaultExchange(consumer.getEndpoint(), ExchangePattern.InOut);
+
+ if (consumer.getEndpoint().isBridgeEndpoint()) {
+ exchange.setProperty(Exchange.SKIP_GZIP_ENCODING, Boolean.TRUE);
+ exchange.setProperty(Exchange.SKIP_WWW_FORM_URLENCODED, Boolean.TRUE);
+ }
+ if (consumer.getEndpoint().isDisableStreamCache()) {
+ exchange.setProperty(Exchange.DISABLE_HTTP_STREAM_CACHE, Boolean.TRUE);
+ }
+
+ // we override the classloader before building the HttpMessage just in case the binding
+ // does some class resolution
+ ClassLoader oldTccl = overrideTccl(exchange);
+ HttpHelper.setCharsetFromContentType(request.getContentType(), exchange);
+ exchange.setIn(new HttpMessage(exchange, request, response));
+ // set context path as header
+ String contextPath = consumer.getEndpoint().getPath();
+ exchange.getIn().setHeader("CamelServletContextPath", contextPath);
+
+ String httpPath = (String)exchange.getIn().getHeader(Exchange.HTTP_PATH);
+ // here we just remove the CamelServletContextPath part from the HTTP_PATH
+ if (contextPath != null
+ && httpPath.startsWith(contextPath)) {
+ exchange.getIn().setHeader(Exchange.HTTP_PATH,
+ httpPath.substring(contextPath.length()));
+ }
+
+ // we want to handle the UoW
+ try {
+ consumer.createUoW(exchange);
+ } catch (Exception e) {
+ log.error("Error processing request", e);
+ throw new ServletException(e);
+ }
+
+ try {
+ if (log.isTraceEnabled()) {
+ log.trace("Processing request for exchangeId: {}", exchange.getExchangeId());
+ }
+ // process the exchange
+ consumer.getProcessor().process(exchange);
+ } catch (Exception e) {
+ exchange.setException(e);
+ }
+
+ try {
+ // now lets output to the response
+ if (log.isTraceEnabled()) {
+ log.trace("Writing response for exchangeId: {}", exchange.getExchangeId());
+ }
+ Integer bs = consumer.getEndpoint().getResponseBufferSize();
+ if (bs != null) {
+ log.trace("Using response buffer size: {}", bs);
+ response.setBufferSize(bs);
+ }
+ consumer.getBinding().writeResponse(exchange, response);
+ } catch (IOException e) {
+ log.error("Error processing request", e);
+ throw e;
+ } catch (Exception e) {
+ log.error("Error processing request", e);
+ throw new ServletException(e);
+ } finally {
+ consumer.doneUoW(exchange);
+ restoreTccl(exchange, oldTccl);
+ }
+ }
+
+ /**
+ * @deprecated use {@link ServletResolveConsumerStrategy#resolve(javax.servlet.http.HttpServletRequest, java.util.Map)}
+ */
+ @Deprecated
+ protected HttpConsumer resolve(HttpServletRequest request) {
+ return getServletResolveConsumerStrategy().resolve(request, getConsumers());
+ }
+
+ public void connect(HttpConsumer consumer) {
+ log.debug("Connecting consumer: {}", consumer);
+ consumers.put(consumer.getEndpoint().getEndpointUri(), consumer);
+ }
+
+ public void disconnect(HttpConsumer consumer) {
+ log.debug("Disconnecting consumer: {}", consumer);
+ consumers.remove(consumer.getEndpoint().getEndpointUri());
+ }
+
+ public String getServletName() {
+ return servletName;
+ }
+
+ public void setServletName(String servletName) {
+ this.servletName = servletName;
+ }
+
+ public ServletResolveConsumerStrategy getServletResolveConsumerStrategy() {
+ return servletResolveConsumerStrategy;
+ }
+
+ public void setServletResolveConsumerStrategy(ServletResolveConsumerStrategy servletResolveConsumerStrategy) {
+ this.servletResolveConsumerStrategy = servletResolveConsumerStrategy;
+ }
+
+ public Map<String, HttpConsumer> getConsumers() {
+ return Collections.unmodifiableMap(consumers);
+ }
+
+ /**
+ * Override the Thread Context ClassLoader if need be.
+ *
+ * @param exchange
+ * @return old classloader if overridden; otherwise returns null
+ */
+ protected ClassLoader overrideTccl(final Exchange exchange) {
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ ClassLoader appCtxCl = exchange.getContext().getApplicationContextClassLoader();
+ if (oldClassLoader == null || appCtxCl == null) {
+ return null;
+ }
+
+ if (!oldClassLoader.equals(appCtxCl)) {
+ Thread.currentThread().setContextClassLoader(appCtxCl);
+ if (log.isTraceEnabled()) {
+ log.trace("Overrode TCCL for exchangeId {} to {} on thread {}",
+ new Object[] {exchange.getExchangeId(), appCtxCl, Thread.currentThread().getName()});
+ }
+ return oldClassLoader;
+ }
+ return null;
+ }
+
+ /**
+ * Restore the Thread Context ClassLoader if the old TCCL is not null.
+ */
+ protected void restoreTccl(final Exchange exchange, ClassLoader oldTccl) {
+ if (oldTccl == null) {
+ return;
+ }
+ Thread.currentThread().setContextClassLoader(oldTccl);
+ if (log.isTraceEnabled()) {
+ log.trace("Restored TCCL for exchangeId {} to {} on thread {}",
+ new String[] {exchange.getExchangeId(), oldTccl.toString(), Thread.currentThread().getName()});
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
new file mode 100644
index 0000000..dcb3f20
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
@@ -0,0 +1,494 @@
+/**
+ * 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.http.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import javax.activation.DataHandler;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.StreamCache;
+import org.apache.camel.converter.stream.CachedOutputStream;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.util.GZIPHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.MessageHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Binding between {@link HttpMessage} and {@link HttpServletResponse}.
+ * <p/>
+ * Uses by default the {@link org.apache.camel.http.common.HttpHeaderFilterStrategy}
+ */
+public class DefaultHttpBinding implements HttpBinding {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultHttpBinding.class);
+ private boolean useReaderForPayload;
+ private boolean eagerCheckContentAvailable;
+ private boolean transferException;
+ private HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy();
+
+ public DefaultHttpBinding() {
+ }
+
+ @Deprecated
+ public DefaultHttpBinding(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ }
+
+ @Deprecated
+ public DefaultHttpBinding(HttpCommonEndpoint endpoint) {
+ this.headerFilterStrategy = endpoint.getHeaderFilterStrategy();
+ this.transferException = endpoint.isTransferException();
+ }
+
+ public void readRequest(HttpServletRequest request, HttpMessage message) {
+ LOG.trace("readRequest {}", request);
+
+ // lets force a parse of the body and headers
+ message.getBody();
+ // populate the headers from the request
+ Map<String, Object> headers = message.getHeaders();
+
+ //apply the headerFilterStrategy
+ Enumeration<?> names = request.getHeaderNames();
+ while (names.hasMoreElements()) {
+ String name = (String)names.nextElement();
+ String value = request.getHeader(name);
+ // use http helper to extract parameter value as it may contain multiple values
+ Object extracted = HttpHelper.extractHttpParameterValue(value);
+ // mapping the content-type
+ if (name.toLowerCase().equals("content-type")) {
+ name = Exchange.CONTENT_TYPE;
+ }
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(name, extracted, message.getExchange())) {
+ HttpHelper.appendHeader(headers, name, extracted);
+ }
+ }
+
+ if (request.getCharacterEncoding() != null) {
+ headers.put(Exchange.HTTP_CHARACTER_ENCODING, request.getCharacterEncoding());
+ message.getExchange().setProperty(Exchange.CHARSET_NAME, request.getCharacterEncoding());
+ }
+
+ try {
+ populateRequestParameters(request, message);
+ } catch (Exception e) {
+ throw new RuntimeCamelException("Cannot read request parameters due " + e.getMessage(), e);
+ }
+
+ Object body = message.getBody();
+ // reset the stream cache if the body is the instance of StreamCache
+ if (body instanceof StreamCache) {
+ ((StreamCache)body).reset();
+ }
+
+ // store the method and query and other info in headers as String types
+ headers.put(Exchange.HTTP_METHOD, request.getMethod());
+ headers.put(Exchange.HTTP_QUERY, request.getQueryString());
+ headers.put(Exchange.HTTP_URL, request.getRequestURL().toString());
+ headers.put(Exchange.HTTP_URI, request.getRequestURI());
+ headers.put(Exchange.HTTP_PATH, request.getPathInfo());
+ headers.put(Exchange.CONTENT_TYPE, request.getContentType());
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("HTTP method {}", request.getMethod());
+ LOG.trace("HTTP query {}", request.getQueryString());
+ LOG.trace("HTTP url {}", request.getRequestURL());
+ LOG.trace("HTTP uri {}", request.getRequestURI());
+ LOG.trace("HTTP path {}", request.getPathInfo());
+ LOG.trace("HTTP content-type {}", request.getContentType());
+ }
+
+ // if content type is serialized java object, then de-serialize it to a Java object
+ if (request.getContentType() != null && HttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(request.getContentType())) {
+ try {
+ InputStream is = message.getExchange().getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, body);
+ Object object = HttpHelper.deserializeJavaObjectFromStream(is, message.getExchange().getContext());
+ if (object != null) {
+ message.setBody(object);
+ }
+ } catch (Exception e) {
+ throw new RuntimeCamelException("Cannot deserialize body to Java object", e);
+ }
+ }
+
+ populateAttachments(request, message);
+ }
+
+ protected void populateRequestParameters(HttpServletRequest request, HttpMessage message) throws Exception {
+ //we populate the http request parameters without checking the request method
+ Map<String, Object> headers = message.getHeaders();
+ Enumeration<?> names = request.getParameterNames();
+ while (names.hasMoreElements()) {
+ String name = (String)names.nextElement();
+ // there may be multiple values for the same name
+ String[] values = request.getParameterValues(name);
+ LOG.trace("HTTP parameter {} = {}", name, values);
+
+ if (values != null) {
+ for (String value : values) {
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, message.getExchange())) {
+ HttpHelper.appendHeader(headers, name, value);
+ }
+ }
+ }
+ }
+
+ LOG.trace("HTTP method {} with Content-Type {}", request.getMethod(), request.getContentType());
+ Boolean flag = message.getHeader(Exchange.SKIP_WWW_FORM_URLENCODED, Boolean.class);
+ boolean skipWwwFormUrlEncoding = flag != null ? flag : false;
+ if (request.getMethod().equals("POST") && request.getContentType() != null
+ && request.getContentType().startsWith(HttpConstants.CONTENT_TYPE_WWW_FORM_URLENCODED)
+ && !skipWwwFormUrlEncoding) {
+ String charset = request.getCharacterEncoding();
+ if (charset == null) {
+ charset = "UTF-8";
+ }
+ // Push POST form params into the headers to retain compatibility with DefaultHttpBinding
+ String body = message.getBody(String.class);
+ if (ObjectHelper.isNotEmpty(body)) {
+ for (String param : body.split("&")) {
+ String[] pair = param.split("=", 2);
+ if (pair.length == 2) {
+ String name = URLDecoder.decode(pair[0], charset);
+ String value = URLDecoder.decode(pair[1], charset);
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, message.getExchange())) {
+ HttpHelper.appendHeader(headers, name, value);
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid parameter, expected to be a pair but was " + param);
+ }
+ }
+ }
+ }
+ }
+
+ protected void populateAttachments(HttpServletRequest request, HttpMessage message) {
+ // check if there is multipart files, if so will put it into DataHandler
+ Enumeration<?> names = request.getAttributeNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ Object object = request.getAttribute(name);
+ LOG.trace("HTTP attachment {} = {}", name, object);
+ if (object instanceof File) {
+ String fileName = request.getParameter(name);
+ message.addAttachment(fileName, new DataHandler(new CamelFileDataSource((File)object, fileName)));
+ }
+ }
+ }
+
+ public void writeResponse(Exchange exchange, HttpServletResponse response) throws IOException {
+ Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
+ if (exchange.isFailed()) {
+ if (exchange.getException() != null) {
+ doWriteExceptionResponse(exchange.getException(), response);
+ } else {
+ // it must be a fault, no need to check for the fault flag on the message
+ doWriteFaultResponse(target, response, exchange);
+ }
+ } else {
+ if (exchange.hasOut()) {
+ // just copy the protocol relates header if we do not have them
+ copyProtocolHeaders(exchange.getIn(), exchange.getOut());
+ }
+ doWriteResponse(target, response, exchange);
+ }
+ }
+
+ private void copyProtocolHeaders(Message request, Message response) {
+ if (request.getHeader(Exchange.CONTENT_ENCODING) != null) {
+ String contentEncoding = request.getHeader(Exchange.CONTENT_ENCODING, String.class);
+ response.setHeader(Exchange.CONTENT_ENCODING, contentEncoding);
+ }
+ if (checkChunked(response, response.getExchange())) {
+ response.setHeader(Exchange.TRANSFER_ENCODING, "chunked");
+ }
+ }
+
+ public void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException {
+ // 500 for internal server error
+ response.setStatus(500);
+
+ if (isTransferException()) {
+ // transfer the exception as a serialized java object
+ HttpHelper.writeObjectToServletResponse(response, exception);
+ } else {
+ // write stacktrace as plain text
+ response.setContentType("text/plain");
+ PrintWriter pw = response.getWriter();
+ exception.printStackTrace(pw);
+ pw.flush();
+ }
+ }
+
+ public void doWriteFaultResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException {
+ message.setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
+ doWriteResponse(message, response, exchange);
+ }
+
+ public void doWriteResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException {
+ // set the status code in the response. Default is 200.
+ if (message.getHeader(Exchange.HTTP_RESPONSE_CODE) != null) {
+ int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
+ response.setStatus(code);
+ }
+ // set the content type in the response.
+ String contentType = MessageHelper.getContentType(message);
+ if (contentType != null) {
+ response.setContentType(contentType);
+ }
+
+ // append headers
+ // must use entrySet to ensure case of keys is preserved
+ for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ // use an iterator as there can be multiple values. (must not use a delimiter)
+ final Iterator<?> it = ObjectHelper.createIterator(value, null);
+ while (it.hasNext()) {
+ String headerValue = exchange.getContext().getTypeConverter().convertTo(String.class, it.next());
+ if (headerValue != null && headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, exchange)) {
+ response.addHeader(key, headerValue);
+ }
+ }
+ }
+
+ // write the body.
+ if (message.getBody() != null) {
+ if (GZIPHelper.isGzip(message)) {
+ doWriteGZIPResponse(message, response, exchange);
+ } else {
+ doWriteDirectResponse(message, response, exchange);
+ }
+ }
+ }
+
+ protected boolean isText(String contentType) {
+ if (contentType != null) {
+ String temp = contentType.toLowerCase();
+ if (temp.indexOf("text") >= 0 || temp.indexOf("html") >= 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected int copyStream(InputStream is, OutputStream os, int bufferSize) throws IOException {
+ try {
+ // copy stream, and must flush on each write as etc Jetty has better performance when
+ // flushing after writing to its servlet output stream
+ return IOHelper.copy(is, os, bufferSize, true);
+ } finally {
+ IOHelper.close(os, is);
+ }
+ }
+
+ protected void doWriteDirectResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException {
+ // if content type is serialized Java object, then serialize and write it to the response
+ String contentType = message.getHeader(Exchange.CONTENT_TYPE, String.class);
+ if (contentType != null && HttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) {
+ try {
+ Object object = message.getMandatoryBody(Serializable.class);
+ HttpHelper.writeObjectToServletResponse(response, object);
+ // object is written so return
+ return;
+ } catch (InvalidPayloadException e) {
+ throw new IOException(e);
+ }
+ }
+
+ // prefer streaming
+ InputStream is = null;
+ if (checkChunked(message, exchange)) {
+ is = message.getBody(InputStream.class);
+ } else {
+ // try to use input stream first, so we can copy directly
+ if (!isText(contentType)) {
+ is = exchange.getContext().getTypeConverter().tryConvertTo(InputStream.class, message.getBody());
+ }
+ }
+
+ if (is != null) {
+ ServletOutputStream os = response.getOutputStream();
+ if (!checkChunked(message, exchange)) {
+ CachedOutputStream stream = new CachedOutputStream(exchange);
+ try {
+ // copy directly from input stream to the cached output stream to get the content length
+ int len = copyStream(is, stream, response.getBufferSize());
+ // we need to setup the length if message is not chucked
+ response.setContentLength(len);
+ OutputStream current = stream.getCurrentStream();
+ if (current instanceof ByteArrayOutputStream) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Streaming (direct) response in non-chunked mode with content-length {}");
+ }
+ ByteArrayOutputStream bos = (ByteArrayOutputStream) current;
+ bos.writeTo(os);
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Streaming response in non-chunked mode with content-length {} and buffer size: {}", len, len);
+ }
+ copyStream(stream.getInputStream(), os, len);
+ }
+ } finally {
+ IOHelper.close(is, os);
+ }
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Streaming response in chunked mode with buffer size {}", response.getBufferSize());
+ }
+ copyStream(is, os, response.getBufferSize());
+ }
+ } else {
+ // not convertable as a stream so fallback as a String
+ String data = message.getBody(String.class);
+ if (data != null) {
+ // set content length and encoding before we write data
+ String charset = IOHelper.getCharsetName(exchange, true);
+ final int dataByteLength = data.getBytes(charset).length;
+ response.setCharacterEncoding(charset);
+ response.setContentLength(dataByteLength);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Writing response in non-chunked mode as plain text with content-length {} and buffer size: {}", dataByteLength, response.getBufferSize());
+ }
+ try {
+ response.getWriter().print(data);
+ } finally {
+ response.getWriter().flush();
+ }
+ }
+ }
+ }
+
+ protected boolean checkChunked(Message message, Exchange exchange) {
+ boolean answer = true;
+ if (message.getHeader(Exchange.HTTP_CHUNKED) == null) {
+ // check the endpoint option
+ Endpoint endpoint = exchange.getFromEndpoint();
+ if (endpoint instanceof HttpCommonEndpoint) {
+ answer = ((HttpCommonEndpoint)endpoint).isChunked();
+ }
+ } else {
+ answer = message.getHeader(Exchange.HTTP_CHUNKED, boolean.class);
+ }
+ return answer;
+ }
+
+ protected void doWriteGZIPResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException {
+ byte[] bytes;
+ try {
+ bytes = message.getMandatoryBody(byte[].class);
+ } catch (InvalidPayloadException e) {
+ throw ObjectHelper.wrapRuntimeCamelException(e);
+ }
+
+ byte[] data = GZIPHelper.compressGZIP(bytes);
+ ServletOutputStream os = response.getOutputStream();
+ try {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Streaming response as GZIP in non-chunked mode with content-length {} and buffer size: {}", data.length, response.getBufferSize());
+ }
+ response.setContentLength(data.length);
+ os.write(data);
+ os.flush();
+ } finally {
+ IOHelper.close(os);
+ }
+ }
+
+ public Object parseBody(HttpMessage httpMessage) throws IOException {
+ // lets assume the body is a reader
+ HttpServletRequest request = httpMessage.getRequest();
+ // there is only a body if we have a content length, or its -1 to indicate unknown length
+ int len = request.getContentLength();
+ LOG.trace("HttpServletRequest content-length: {}", len);
+ if (len == 0) {
+ return null;
+ }
+ if (isUseReaderForPayload()) {
+ // use reader to read the response body
+ return request.getReader();
+ } else {
+ // if we do not know if there is any data at all, then make sure to check the stream first
+ if (len < 0 && isEagerCheckContentAvailable()) {
+ InputStream is = request.getInputStream();
+ if (is.available() == 0) {
+ // no data so return null
+ return null;
+ }
+ }
+ // read the response body from servlet request
+ return HttpHelper.readRequestBodyFromServletRequest(request, httpMessage.getExchange());
+ }
+ }
+
+ public boolean isUseReaderForPayload() {
+ return useReaderForPayload;
+ }
+
+ public void setUseReaderForPayload(boolean useReaderForPayload) {
+ this.useReaderForPayload = useReaderForPayload;
+ }
+
+ public boolean isEagerCheckContentAvailable() {
+ return eagerCheckContentAvailable;
+ }
+
+ public void setEagerCheckContentAvailable(boolean eagerCheckContentAvailable) {
+ this.eagerCheckContentAvailable = eagerCheckContentAvailable;
+ }
+
+ public boolean isTransferException() {
+ return transferException;
+ }
+
+ public void setTransferException(boolean transferException) {
+ this.transferException = transferException;
+ }
+
+ public HeaderFilterStrategy getHeaderFilterStrategy() {
+ return headerFilterStrategy;
+ }
+
+ public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpBinding.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpBinding.java
new file mode 100644
index 0000000..d76ba10
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpBinding.java
@@ -0,0 +1,160 @@
+/**
+ * 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.http.common;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.spi.HeaderFilterStrategy;
+
+/**
+ * A pluggable strategy for configuring the http binding so reading request and writing response
+ * can be customized using the Java Servlet API.
+ * <p/>
+ * This is also used by the <tt>camel-jetty</tt> component in the <tt>JettyHttpConsumer</tt> class.
+ */
+public interface HttpBinding {
+
+ /**
+ * Strategy to read the given request and bindings it to the given message.
+ *
+ * @param request the request
+ * @param message the message to populate with data from request
+ */
+ void readRequest(HttpServletRequest request, HttpMessage message);
+
+ /**
+ * Parses the body from a {@link org.apache.camel.http.common.HttpMessage}
+ *
+ * @param httpMessage the http message
+ * @return the parsed body returned as either a {@link java.io.InputStream} or a {@link java.io.Reader}
+ * depending on the {@link #setUseReaderForPayload(boolean)} property.
+ * @throws java.io.IOException can be thrown
+ */
+ Object parseBody(HttpMessage httpMessage) throws IOException;
+
+ /**
+ * Writes the exchange to the servlet response.
+ * <p/>
+ * Default implementation will delegate to the following methods depending on the status of the exchange
+ * <ul>
+ * <li>doWriteResponse - processing returns a OUT message </li>
+ * <li>doWriteFaultResponse - processing returns a fault message</li>
+ * <li>doWriteResponse - processing returns an exception and status code 500</li>
+ * </ul>
+ *
+ * @param exchange the exchange
+ * @param response the http response
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void writeResponse(Exchange exchange, HttpServletResponse response) throws IOException;
+
+ /**
+ * Strategy method that writes the response to the http response stream when an exception occurred
+ *
+ * @param exception the exception occurred
+ * @param response the http response
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException;
+
+ /**
+ * Strategy method that writes the response to the http response stream for a fault message
+ *
+ * @param message the fault message
+ * @param response the http response
+ * @param exchange the exchange to provide context for header filtering
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void doWriteFaultResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException;
+
+ /**
+ * Strategy method that writes the response to the http response stream for an OUT message
+ *
+ * @param message the OUT message
+ * @param response the http response
+ * @param exchange the exchange to provide context for header filtering
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void doWriteResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException;
+
+ /**
+ * Should reader by used instead of input stream.
+ *
+ * @see #setUseReaderForPayload(boolean) for more details
+ * @return <tt>true</tt> if reader should be used
+ */
+ boolean isUseReaderForPayload();
+
+ /**
+ * Should the {@link javax.servlet.http.HttpServletRequest#getReader()} be exposed as the payload of input messages in the Camel
+ * {@link org.apache.camel.Message#getBody()} or not. If false then the {@link javax.servlet.http.HttpServletRequest#getInputStream()} will be exposed.
+ * <p/>
+ * Is default <tt>false</tt>.
+ *
+ * @param useReaderForPayload whether to use reader or not
+ */
+ void setUseReaderForPayload(boolean useReaderForPayload);
+
+ /**
+ * If enabled and an Exchange failed processing on the consumer side, and if the caused Exception was send back
+ * serialized in the response as a application/x-java-serialized-object content type (for example using Jetty or
+ * Servlet Camel components). On the producer side the exception will be deserialized and thrown as is,
+ * instead of the HttpOperationFailedException. The caused exception is required to be serialized.
+ */
+ boolean isTransferException();
+
+ /**
+ * Whether to eager check whether the HTTP requests has content if the content-length header is 0 or not present.
+ * This can be turned on in case HTTP clients do not send streamed data.
+ */
+ boolean isEagerCheckContentAvailable();
+
+ /**
+ * Whether to eager check whether the HTTP requests has content if the content-length header is 0 or not present.
+ * This can be turned on in case HTTP clients do not send streamed data.
+ */
+ void setEagerCheckContentAvailable(boolean eagerCheckContentAvailable);
+
+ /**
+ * If enabled and an Exchange failed processing on the consumer side, and if the caused Exception was send back
+ * serialized in the response as a application/x-java-serialized-object content type (for example using Jetty or
+ * Servlet Camel components). On the producer side the exception will be deserialized and thrown as is,
+ * instead of the HttpOperationFailedException. The caused exception is required to be serialized.
+ */
+ void setTransferException(boolean transferException);
+
+ /**
+ * Gets the header filter strategy
+ *
+ * @return the strategy
+ */
+ HeaderFilterStrategy getHeaderFilterStrategy();
+
+ /**
+ * Sets the header filter strategy to use.
+ * <p/>
+ * Will default use {@link org.apache.camel.http.common.HttpHeaderFilterStrategy}
+ *
+ * @param headerFilterStrategy the custom strategy
+ */
+ void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy);
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
new file mode 100644
index 0000000..711a878
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
@@ -0,0 +1,75 @@
+/**
+ * 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.http.common;
+
+import org.apache.camel.impl.HeaderFilterStrategyComponent;
+
+public abstract class HttpCommonComponent extends HeaderFilterStrategyComponent {
+
+ protected HttpBinding httpBinding;
+ protected HttpConfiguration httpConfiguration;
+
+ public HttpCommonComponent(Class<? extends HttpCommonEndpoint> endpointClass) {
+ super(endpointClass);
+ }
+
+ /**
+ * Connects the URL specified on the endpoint to the specified processor.
+ *
+ * @param consumer the consumer
+ * @throws Exception can be thrown
+ */
+ public void connect(HttpConsumer consumer) throws Exception {
+ }
+
+ /**
+ * Disconnects the URL specified on the endpoint from the specified processor.
+ *
+ * @param consumer the consumer
+ * @throws Exception can be thrown
+ */
+ public void disconnect(HttpConsumer consumer) throws Exception {
+ }
+
+ @Override
+ protected boolean useIntrospectionOnEndpoint() {
+ return false;
+ }
+
+ public HttpBinding getHttpBinding() {
+ return httpBinding;
+ }
+
+ /**
+ * To use a custom HttpBinding to control the mapping between Camel message and HttpClient.
+ */
+ public void setHttpBinding(HttpBinding httpBinding) {
+ this.httpBinding = httpBinding;
+ }
+
+ public HttpConfiguration getHttpConfiguration() {
+ return httpConfiguration;
+ }
+
+ /**
+ * To use the shared HttpConfiguration as base configuration.
+ */
+ public void setHttpConfiguration(HttpConfiguration httpConfiguration) {
+ this.httpConfiguration = httpConfiguration;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
new file mode 100644
index 0000000..4ba2163
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
@@ -0,0 +1,383 @@
+/**
+ * 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.http.common;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.HeaderFilterStrategyAware;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class HttpCommonEndpoint extends DefaultEndpoint implements HeaderFilterStrategyAware {
+
+ // Note: all options must be documented with description in annotations so extended components can access the documentation
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpCommonEndpoint.class);
+
+ HttpCommonComponent component;
+ UrlRewrite urlRewrite;
+
+ @UriPath(label = "producer", description = "The url of the HTTP endpoint to call.") @Metadata(required = "true")
+ URI httpUri;
+ @UriParam(description = "To use a custom HeaderFilterStrategy to filter header to and from Camel message.")
+ HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy();
+ @UriParam(description = "To use a custom HttpBinding to control the mapping between Camel message and HttpClient.")
+ HttpBinding binding;
+ @UriParam(label = "producer", defaultValue = "true",
+ description = "Option to disable throwing the HttpOperationFailedException in case of failed responses from the remote server."
+ + " This allows you to get all responses regardless of the HTTP status code.")
+ boolean throwExceptionOnFailure = true;
+ @UriParam(label = "producer",
+ description = "If the option is true, HttpProducer will ignore the Exchange.HTTP_URI header, and use the endpoint's URI for request."
+ + " You may also set the option throwExceptionOnFailure to be false to let the HttpProducer send all the fault response back.")
+ boolean bridgeEndpoint;
+ @UriParam(label = "consumer",
+ description = "Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found.")
+ boolean matchOnUriPrefix;
+ @UriParam(defaultValue = "true", description = "If this option is false Jetty servlet will disable the HTTP streaming and set the content-length header on the response")
+ boolean chunked = true;
+ @UriParam(label = "consumer",
+ description = "Determines whether or not the raw input stream from Jetty is cached or not"
+ + " (Camel will read the stream into a in memory/overflow to file, Stream caching) cache."
+ + " By default Camel will cache the Jetty input stream to support reading it multiple times to ensure it Camel"
+ + " can retrieve all data from the stream. However you can set this option to true when you for example need"
+ + " to access the raw stream, such as streaming it directly to a file or other persistent store."
+ + " DefaultHttpBinding will copy the request input stream into a stream cache and put it into message body"
+ + " if this option is false to support reading the stream multiple times."
+ + " If you use Jetty to bridge/proxy an endpoint then consider enabling this option to improve performance,"
+ + " in case you do not need to read the message payload multiple times.")
+ boolean disableStreamCache;
+ @UriParam(label = "producer", description = "The proxy host name")
+ String proxyHost;
+ @UriParam(label = "producer", description = "The proxy port number")
+ int proxyPort;
+ @UriParam(label = "producer", enums = "Basic,Digest,NTLM", description = "Authentication method for proxy, either as Basic, Digest or NTLM.")
+ String authMethodPriority;
+ @UriParam(description = "Option to disable throwing the HttpOperationFailedException in case of failed responses from the remote server."
+ + " This allows you to get all responses regardless of the HTTP status code.")
+ boolean transferException;
+ @UriParam(label = "consumer",
+ description = "Specifies whether to enable HTTP TRACE for this Jetty consumer. By default TRACE is turned off.")
+ boolean traceEnabled;
+ @UriParam(label = "consumer",
+ description = "Used to only allow consuming if the HttpMethod matches, such as GET/POST/PUT etc. Multiple methods can be specified separated by comma.")
+ String httpMethodRestrict;
+ @UriParam(label = "consumer",
+ description = "To use a custom buffer size on the javax.servlet.ServletResponse.")
+ Integer responseBufferSize;
+ @UriParam(label = "producer",
+ description = "If this option is true, The http producer won't read response body and cache the input stream")
+ boolean ignoreResponseBody;
+ @UriParam(label = "producer", defaultValue = "true",
+ description = "If this option is true then IN exchange headers will be copied to OUT exchange headers according to copy strategy."
+ + " Setting this to false, allows to only include the headers from the HTTP response (not propagating IN headers).")
+ boolean copyHeaders = true;
+ @UriParam(label = "consumer",
+ description = "Whether to eager check whether the HTTP requests has content if the content-length header is 0 or not present."
+ + " This can be turned on in case HTTP clients do not send streamed data.")
+ boolean eagerCheckContentAvailable;
+
+ public HttpCommonEndpoint() {
+ }
+
+ public HttpCommonEndpoint(String endPointURI, HttpCommonComponent component, URI httpURI) throws URISyntaxException {
+ super(endPointURI, component);
+ this.component = component;
+ this.httpUri = httpURI;
+ }
+
+ public void connect(HttpConsumer consumer) throws Exception {
+ component.connect(consumer);
+ }
+
+ public void disconnect(HttpConsumer consumer) throws Exception {
+ component.disconnect(consumer);
+ }
+
+ public boolean isLenientProperties() {
+ // true to allow dynamic URI options to be configured and passed to external system for eg. the HttpProducer
+ return true;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ // Properties
+ //-------------------------------------------------------------------------
+
+ public HttpBinding getBinding() {
+ if (binding == null) {
+ // create a new binding and use the options from this endpoint
+ binding = new DefaultHttpBinding();
+ binding.setHeaderFilterStrategy(getHeaderFilterStrategy());
+ binding.setTransferException(isTransferException());
+ binding.setEagerCheckContentAvailable(isEagerCheckContentAvailable());
+ }
+ return binding;
+ }
+
+ /**
+ * To use a custom HttpBinding to control the mapping between Camel message and HttpClient.
+ */
+ public void setBinding(HttpBinding binding) {
+ this.binding = binding;
+ }
+
+ public String getPath() {
+ //if the path is empty, we just return the default path here
+ return httpUri.getPath().length() == 0 ? "/" : httpUri.getPath();
+ }
+
+ public int getPort() {
+ if (httpUri.getPort() == -1) {
+ if ("https".equals(getProtocol())) {
+ return 443;
+ } else {
+ return 80;
+ }
+ }
+ return httpUri.getPort();
+ }
+
+ public String getProtocol() {
+ return httpUri.getScheme();
+ }
+
+ public URI getHttpUri() {
+ return httpUri;
+ }
+
+ /**
+ * The url of the HTTP endpoint to call.
+ */
+ public void setHttpUri(URI httpUri) {
+ this.httpUri = httpUri;
+ }
+
+ public HeaderFilterStrategy getHeaderFilterStrategy() {
+ return headerFilterStrategy;
+ }
+
+ /**
+ * To use a custom HeaderFilterStrategy to filter header to and from Camel message.
+ */
+ public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ }
+
+ public boolean isThrowExceptionOnFailure() {
+ return throwExceptionOnFailure;
+ }
+
+ /**
+ * Option to disable throwing the HttpOperationFailedException in case of failed responses from the remote server.
+ * This allows you to get all responses regardless of the HTTP status code.
+ */
+ public void setThrowExceptionOnFailure(boolean throwExceptionOnFailure) {
+ this.throwExceptionOnFailure = throwExceptionOnFailure;
+ }
+
+ public boolean isBridgeEndpoint() {
+ return bridgeEndpoint;
+ }
+
+ /**
+ * If the option is true, HttpProducer will ignore the Exchange.HTTP_URI header, and use the endpoint's URI for request.
+ * You may also set the option throwExceptionOnFailure to be false to let the HttpProducer send all the fault response back.
+ */
+ public void setBridgeEndpoint(boolean bridge) {
+ this.bridgeEndpoint = bridge;
+ }
+
+ public boolean isMatchOnUriPrefix() {
+ return matchOnUriPrefix;
+ }
+
+ /**
+ * Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found.
+ * <p/>
+ * See more details at: http://camel.apache.org/how-do-i-let-jetty-match-wildcards.html
+ */
+ public void setMatchOnUriPrefix(boolean match) {
+ this.matchOnUriPrefix = match;
+ }
+
+ public boolean isDisableStreamCache() {
+ return this.disableStreamCache;
+ }
+
+ /**
+ * Determines whether or not the raw input stream from Jetty is cached or not
+ * (Camel will read the stream into a in memory/overflow to file, Stream caching) cache.
+ * By default Camel will cache the Jetty input stream to support reading it multiple times to ensure it Camel
+ * can retrieve all data from the stream. However you can set this option to true when you for example need
+ * to access the raw stream, such as streaming it directly to a file or other persistent store.
+ * DefaultHttpBinding will copy the request input stream into a stream cache and put it into message body
+ * if this option is false to support reading the stream multiple times.
+ * If you use Jetty to bridge/proxy an endpoint then consider enabling this option to improve performance,
+ * in case you do not need to read the message payload multiple times.
+ */
+ public void setDisableStreamCache(boolean disable) {
+ this.disableStreamCache = disable;
+ }
+
+ public boolean isChunked() {
+ return this.chunked;
+ }
+
+ /**
+ * If this option is false Jetty servlet will disable the HTTP streaming and set the content-length header on the response
+ */
+ public void setChunked(boolean chunked) {
+ this.chunked = chunked;
+ }
+
+ public String getProxyHost() {
+ return proxyHost;
+ }
+
+ /**
+ * The proxy host name
+ */
+ public void setProxyHost(String proxyHost) {
+ this.proxyHost = proxyHost;
+ }
+
+ public int getProxyPort() {
+ return proxyPort;
+ }
+
+ /**
+ * The proxy port number
+ */
+ public void setProxyPort(int proxyPort) {
+ this.proxyPort = proxyPort;
+ }
+
+ public String getAuthMethodPriority() {
+ return authMethodPriority;
+ }
+
+ /**
+ * Authentication method for proxy, either as Basic, Digest or NTLM.
+ */
+ public void setAuthMethodPriority(String authMethodPriority) {
+ this.authMethodPriority = authMethodPriority;
+ }
+
+ public boolean isTransferException() {
+ return transferException;
+ }
+
+ /**
+ * Option to disable throwing the HttpOperationFailedException in case of failed responses from the remote server.
+ * This allows you to get all responses regardless of the HTTP status code.
+ */
+ public void setTransferException(boolean transferException) {
+ this.transferException = transferException;
+ }
+
+ public boolean isTraceEnabled() {
+ return this.traceEnabled;
+ }
+
+ /**
+ * Specifies whether to enable HTTP TRACE for this Jetty consumer. By default TRACE is turned off.
+ */
+ public void setTraceEnabled(boolean traceEnabled) {
+ this.traceEnabled = traceEnabled;
+ }
+
+ public String getHttpMethodRestrict() {
+ return httpMethodRestrict;
+ }
+
+ /**
+ * Used to only allow consuming if the HttpMethod matches, such as GET/POST/PUT etc.
+ * Multiple methods can be specified separated by comma.
+ */
+ public void setHttpMethodRestrict(String httpMethodRestrict) {
+ this.httpMethodRestrict = httpMethodRestrict;
+ }
+
+ public UrlRewrite getUrlRewrite() {
+ return urlRewrite;
+ }
+
+ /**
+ * Refers to a custom org.apache.camel.component.http.UrlRewrite which allows you to rewrite urls when you bridge/proxy endpoints.
+ * See more details at http://camel.apache.org/urlrewrite.html
+ */
+ public void setUrlRewrite(UrlRewrite urlRewrite) {
+ this.urlRewrite = urlRewrite;
+ }
+
+ public Integer getResponseBufferSize() {
+ return responseBufferSize;
+ }
+
+ /**
+ * To use a custom buffer size on the javax.servlet.ServletResponse.
+ */
+ public void setResponseBufferSize(Integer responseBufferSize) {
+ this.responseBufferSize = responseBufferSize;
+ }
+
+ public boolean isIgnoreResponseBody() {
+ return ignoreResponseBody;
+ }
+
+ /**
+ * If this option is true, The http producer won't read response body and cache the input stream.
+ */
+ public void setIgnoreResponseBody(boolean ignoreResponseBody) {
+ this.ignoreResponseBody = ignoreResponseBody;
+ }
+
+ /**
+ * If this option is true then IN exchange headers will be copied to OUT exchange headers according to copy strategy.
+ * Setting this to false, allows to only include the headers from the HTTP response (not propagating IN headers).
+ */
+ public boolean isCopyHeaders() {
+ return copyHeaders;
+ }
+
+ public void setCopyHeaders(boolean copyHeaders) {
+ this.copyHeaders = copyHeaders;
+ }
+
+ public boolean isEagerCheckContentAvailable() {
+ return eagerCheckContentAvailable;
+ }
+
+ /**
+ * Whether to eager check whether the HTTP requests has content if the content-length header is 0 or not present.
+ * This can be turned on in case HTTP clients do not send streamed data.
+ */
+ public void setEagerCheckContentAvailable(boolean eagerCheckContentAvailable) {
+ this.eagerCheckContentAvailable = eagerCheckContentAvailable;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
new file mode 100644
index 0000000..6a3e646
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
@@ -0,0 +1,143 @@
+/**
+ * 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.http.common;
+
+import java.io.Serializable;
+
+public class HttpConfiguration implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String authMethod;
+ private String authUsername;
+ private String authPassword;
+ private String authDomain;
+ private String authHost;
+
+ private String proxyAuthMethod;
+ private String proxyAuthUsername;
+ private String proxyAuthPassword;
+ private String proxyAuthDomain;
+ private String proxyAuthHost;
+
+ private String proxyHost;
+ private int proxyPort;
+ private String authMethodPriority;
+
+ public String getAuthUsername() {
+ return authUsername;
+ }
+
+ public void setAuthUsername(String authUsername) {
+ this.authUsername = authUsername;
+ }
+
+ public String getAuthPassword() {
+ return authPassword;
+ }
+
+ public void setAuthPassword(String authPassword) {
+ this.authPassword = authPassword;
+ }
+
+ public String getAuthDomain() {
+ return authDomain;
+ }
+
+ public void setAuthDomain(String authDomain) {
+ this.authDomain = authDomain;
+ }
+
+ public String getAuthHost() {
+ return authHost;
+ }
+
+ public void setAuthHost(String authHost) {
+ this.authHost = authHost;
+ }
+
+ public String getProxyAuthUsername() {
+ return proxyAuthUsername;
+ }
+
+ public void setProxyAuthUsername(String proxyAuthUsername) {
+ this.proxyAuthUsername = proxyAuthUsername;
+ }
+
+ public String getProxyAuthPassword() {
+ return proxyAuthPassword;
+ }
+
+ public void setProxyAuthPassword(String proxyAuthPassword) {
+ this.proxyAuthPassword = proxyAuthPassword;
+ }
+
+ public String getProxyAuthDomain() {
+ return proxyAuthDomain;
+ }
+
+ public void setProxyAuthDomain(String proxyAuthDomain) {
+ this.proxyAuthDomain = proxyAuthDomain;
+ }
+
+ public String getProxyAuthHost() {
+ return proxyAuthHost;
+ }
+
+ public void setProxyAuthHost(String proxyAuthHost) {
+ this.proxyAuthHost = proxyAuthHost;
+ }
+
+ public String getAuthMethod() {
+ return authMethod;
+ }
+
+ public void setAuthMethod(String authMethod) {
+ this.authMethod = authMethod;
+ }
+
+ public String getProxyAuthMethod() {
+ return proxyAuthMethod;
+ }
+
+ public void setProxyAuthMethod(String proxyAuthMethod) {
+ this.proxyAuthMethod = proxyAuthMethod;
+ }
+
+ public String getProxyHost() {
+ return proxyHost;
+ }
+
+ public void setProxyHost(String proxyHost) {
+ this.proxyHost = proxyHost;
+ }
+
+ public int getProxyPort() {
+ return proxyPort;
+ }
+
+ public void setProxyPort(int proxyPort) {
+ this.proxyPort = proxyPort;
+ }
+
+ public String getAuthMethodPriority() {
+ return authMethodPriority;
+ }
+
+ public void setAuthMethodPriority(String authMethodPriority) {
+ this.authMethodPriority = authMethodPriority;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConstants.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConstants.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConstants.java
new file mode 100644
index 0000000..bccf724
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConstants.java
@@ -0,0 +1,26 @@
+/**
+ * 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.http.common;
+
+public final class HttpConstants {
+
+ public static final String CONTENT_TYPE_JAVA_SERIALIZED_OBJECT = "application/x-java-serialized-object";
+ public static final String CONTENT_TYPE_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded";
+
+ private HttpConstants() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConsumer.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConsumer.java
new file mode 100644
index 0000000..f389081
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConsumer.java
@@ -0,0 +1,80 @@
+/**
+ * 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.http.common;
+
+import org.apache.camel.Processor;
+import org.apache.camel.SuspendableService;
+import org.apache.camel.impl.DefaultConsumer;
+
+public class HttpConsumer extends DefaultConsumer implements SuspendableService {
+ private volatile boolean suspended;
+ private boolean traceEnabled;
+
+ public HttpConsumer(HttpCommonEndpoint endpoint, Processor processor) {
+ super(endpoint, processor);
+ if (endpoint.isTraceEnabled()) {
+ setTraceEnabled(true);
+ }
+ }
+
+ @Override
+ public HttpCommonEndpoint getEndpoint() {
+ return (HttpCommonEndpoint)super.getEndpoint();
+ }
+
+ public HttpBinding getBinding() {
+ return getEndpoint().getBinding();
+ }
+
+ public String getPath() {
+ return getEndpoint().getPath();
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+ getEndpoint().connect(this);
+ suspended = false;
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ suspended = false;
+ getEndpoint().disconnect(this);
+ super.doStop();
+ }
+
+ public void suspend() {
+ suspended = true;
+ }
+
+ public void resume() {
+ suspended = false;
+ }
+
+ public boolean isSuspended() {
+ return suspended;
+ }
+
+ public boolean isTraceEnabled() {
+ return this.traceEnabled;
+ }
+
+ public void setTraceEnabled(boolean traceEnabled) {
+ this.traceEnabled = traceEnabled;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConverter.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConverter.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConverter.java
new file mode 100644
index 0000000..8efa895
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConverter.java
@@ -0,0 +1,98 @@
+/**
+ * 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.http.common;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.util.GZIPHelper;
+
+/**
+ * Some converter methods making it easy to convert the body of a message to servlet types or to switch between
+ * the underlying {@link ServletInputStream} or {@link BufferedReader} payloads etc.
+ */
+@Converter
+public final class HttpConverter {
+
+ private HttpConverter() {
+ }
+
+ @Converter
+ public static HttpServletRequest toServletRequest(Message message) {
+ if (message == null) {
+ return null;
+ }
+ return message.getHeader(Exchange.HTTP_SERVLET_REQUEST, HttpServletRequest.class);
+ }
+
+ @Converter
+ public static HttpServletResponse toServletResponse(Message message) {
+ if (message == null) {
+ return null;
+ }
+ return message.getHeader(Exchange.HTTP_SERVLET_RESPONSE, HttpServletResponse.class);
+ }
+
+ @Converter
+ public static ServletInputStream toServletInputStream(HttpMessage message) throws IOException {
+ HttpServletRequest request = toServletRequest(message);
+ if (request != null) {
+ return request.getInputStream();
+ }
+ return null;
+ }
+
+ @Converter
+ public static InputStream toInputStream(HttpMessage message, Exchange exchange) throws Exception {
+ return toInputStream(toServletRequest(message), exchange);
+ }
+
+ @Converter
+ public static BufferedReader toReader(HttpMessage message) throws IOException {
+ HttpServletRequest request = toServletRequest(message);
+ if (request != null) {
+ return request.getReader();
+ }
+ return null;
+ }
+
+ @Converter
+ public static InputStream toInputStream(HttpServletRequest request, Exchange exchange) throws IOException {
+ if (request == null) {
+ return null;
+ }
+ InputStream is = request.getInputStream();
+ if (is != null && is.available() <= 0) {
+ // there is no data, so we cannot uncompress etc.
+ return is;
+ }
+ if (exchange == null || !exchange.getProperty(Exchange.SKIP_GZIP_ENCODING, Boolean.FALSE, Boolean.class)) {
+ String contentEncoding = request.getHeader(Exchange.CONTENT_ENCODING);
+ return GZIPHelper.uncompressGzip(contentEncoding, is);
+ } else {
+ return is;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/e51b7f8d/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHeaderFilterStrategy.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHeaderFilterStrategy.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHeaderFilterStrategy.java
new file mode 100644
index 0000000..6df5b34
--- /dev/null
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHeaderFilterStrategy.java
@@ -0,0 +1,49 @@
+/**
+ * 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.http.common;
+
+import org.apache.camel.impl.DefaultHeaderFilterStrategy;
+
+public class HttpHeaderFilterStrategy extends DefaultHeaderFilterStrategy {
+
+ public HttpHeaderFilterStrategy() {
+ initialize();
+ }
+
+ protected void initialize() {
+ getOutFilter().add("content-length");
+ getOutFilter().add("content-type");
+ getOutFilter().add("host");
+ // Add the filter for the Generic Message header
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.5
+ getOutFilter().add("cache-control");
+ getOutFilter().add("connection");
+ getOutFilter().add("date");
+ getOutFilter().add("pragma");
+ getOutFilter().add("trailer");
+ getOutFilter().add("transfer-encoding");
+ getOutFilter().add("upgrade");
+ getOutFilter().add("via");
+ getOutFilter().add("warning");
+
+ setLowerCase(true);
+
+ // filter headers begin with "Camel" or "org.apache.camel"
+ // must ignore case for Http based transports
+ setOutFilterPattern("(?i)(Camel|org\\.apache\\.camel)[\\.|a-z|A-z|0-9]*");
+ }
+}