blob: f4b16889fbf6aa27ab8b9f8d327ff8b1fed245f8 [file] [log] [blame]
/**
* 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.http;
import java.net.URI;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.apache.camel.Endpoint;
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.impl.HeaderFilterStrategyComponent;
import org.apache.camel.util.CastUtils;
import org.apache.camel.util.CollectionHelper;
import org.apache.camel.util.IntrospectionSupport;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.URISupport;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.params.HttpClientParams;
/**
* Defines the <a href="http://camel.apache.org/http.html">HTTP
* Component</a>
*
* @version
*/
public class HttpComponent extends HeaderFilterStrategyComponent {
protected HttpClientConfigurer httpClientConfigurer;
protected HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
protected HttpBinding httpBinding;
protected HttpConfiguration httpConfiguration;
/**
* 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 {
}
/**
* Creates the HttpClientConfigurer based on the given parameters
*
* @param parameters the map of parameters
* @return the configurer
*/
protected HttpClientConfigurer createHttpClientConfigurer(Map<String, Object> parameters, Set<AuthMethod> authMethods) {
// prefer to use endpoint configured over component configured
HttpClientConfigurer configurer = resolveAndRemoveReferenceParameter(parameters, "httpClientConfigurerRef", HttpClientConfigurer.class);
if (configurer == null) {
// try without ref
configurer = resolveAndRemoveReferenceParameter(parameters, "httpClientConfigurer", HttpClientConfigurer.class);
}
if (configurer == null) {
// fallback to component configured
configurer = getHttpClientConfigurer();
}
// authentication can be endpoint configured
String authUsername = getAndRemoveParameter(parameters, "authUsername", String.class);
AuthMethod authMethod = getAndRemoveParameter(parameters, "authMethod", AuthMethod.class);
// validate that if auth username is given then the auth method is also provided
if (authUsername != null && authMethod == null) {
throw new IllegalArgumentException("Option authMethod must be provided to use authentication");
}
if (authMethod != null) {
String authPassword = getAndRemoveParameter(parameters, "authPassword", String.class);
String authDomain = getAndRemoveParameter(parameters, "authDomain", String.class);
String authHost = getAndRemoveParameter(parameters, "authHost", String.class);
configurer = configureAuth(configurer, authMethod, authUsername, authPassword, authDomain, authHost, authMethods);
} else if (httpConfiguration != null) {
// or fallback to use component configuration
configurer = configureAuth(configurer, httpConfiguration.getAuthMethod(), httpConfiguration.getAuthUsername(),
httpConfiguration.getAuthPassword(), httpConfiguration.getAuthDomain(), httpConfiguration.getAuthHost(), authMethods);
}
// proxy authentication can be endpoint configured
String proxyAuthUsername = getAndRemoveParameter(parameters, "proxyAuthUsername", String.class);
AuthMethod proxyAuthMethod = getAndRemoveParameter(parameters, "proxyAuthMethod", AuthMethod.class);
// validate that if proxy auth username is given then the proxy auth method is also provided
if (proxyAuthUsername != null && proxyAuthMethod == null) {
throw new IllegalArgumentException("Option proxyAuthMethod must be provided to use proxy authentication");
}
if (proxyAuthMethod != null) {
String proxyAuthPassword = getAndRemoveParameter(parameters, "proxyAuthPassword", String.class);
String proxyAuthDomain = getAndRemoveParameter(parameters, "proxyAuthDomain", String.class);
String proxyAuthHost = getAndRemoveParameter(parameters, "proxyAuthHost", String.class);
configurer = configureProxyAuth(configurer, proxyAuthMethod, proxyAuthUsername, proxyAuthPassword, proxyAuthDomain, proxyAuthHost, authMethods);
} else if (httpConfiguration != null) {
// or fallback to use component configuration
configurer = configureProxyAuth(configurer, httpConfiguration.getProxyAuthMethod(), httpConfiguration.getProxyAuthUsername(),
httpConfiguration.getProxyAuthPassword(), httpConfiguration.getProxyAuthDomain(), httpConfiguration.getProxyAuthHost(), authMethods);
}
return configurer;
}
/**
* Configures the authentication method to be used
*
* @return configurer to used
*/
protected HttpClientConfigurer configureAuth(HttpClientConfigurer configurer, AuthMethod authMethod, String username,
String password, String domain, String host, Set<AuthMethod> authMethods) {
// no auth is in use
if (username == null && authMethod == null) {
return configurer;
}
// validate mandatory options given
if (username != null && authMethod == null) {
throw new IllegalArgumentException("Option authMethod must be provided to use authentication");
}
ObjectHelper.notNull(authMethod, "authMethod");
ObjectHelper.notNull(username, "authUsername");
ObjectHelper.notNull(password, "authPassword");
// add it as a auth method used
authMethods.add(authMethod);
if (authMethod == AuthMethod.Basic || authMethod == AuthMethod.Digest) {
return CompositeHttpConfigurer.combineConfigurers(configurer,
new BasicAuthenticationHttpClientConfigurer(false, username, password));
} else if (authMethod == AuthMethod.NTLM) {
// domain is mandatory for NTLM
ObjectHelper.notNull(domain, "authDomain");
return CompositeHttpConfigurer.combineConfigurers(configurer,
new NTLMAuthenticationHttpClientConfigurer(false, username, password, domain, host));
}
throw new IllegalArgumentException("Unknown authMethod " + authMethod);
}
/**
* Configures the proxy authentication method to be used
*
* @return configurer to used
*/
protected HttpClientConfigurer configureProxyAuth(HttpClientConfigurer configurer, AuthMethod authMethod, String username,
String password, String domain, String host, Set<AuthMethod> authMethods) {
// no proxy auth is in use
if (username == null && authMethod == null) {
return configurer;
}
// validate mandatory options given
if (username != null && authMethod == null) {
throw new IllegalArgumentException("Option proxyAuthMethod must be provided to use proxy authentication");
}
ObjectHelper.notNull(authMethod, "proxyAuthMethod");
ObjectHelper.notNull(username, "proxyAuthUsername");
ObjectHelper.notNull(password, "proxyAuthPassword");
// add it as a auth method used
authMethods.add(authMethod);
if (authMethod == AuthMethod.Basic || authMethod == AuthMethod.Digest) {
return CompositeHttpConfigurer.combineConfigurers(configurer,
new BasicAuthenticationHttpClientConfigurer(true, username, password));
} else if (authMethod == AuthMethod.NTLM) {
// domain is mandatory for NTML
ObjectHelper.notNull(domain, "proxyAuthDomain");
return CompositeHttpConfigurer.combineConfigurers(configurer,
new NTLMAuthenticationHttpClientConfigurer(true, username, password, domain, host));
}
throw new IllegalArgumentException("Unknown proxyAuthMethod " + authMethod);
}
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
String addressUri = uri;
if (!uri.startsWith("http:") && !uri.startsWith("https:")) {
addressUri = remaining;
}
Map<String, Object> httpClientParameters = new HashMap<String, Object>(parameters);
// must extract well known parameters before we create the endpoint
HttpBinding binding = resolveAndRemoveReferenceParameter(parameters, "httpBindingRef", HttpBinding.class);
if (binding == null) {
// try without ref
binding = resolveAndRemoveReferenceParameter(parameters, "httpBinding", HttpBinding.class);
}
Boolean throwExceptionOnFailure = getAndRemoveParameter(parameters, "throwExceptionOnFailure", Boolean.class);
Boolean transferException = getAndRemoveParameter(parameters, "transferException", Boolean.class);
Boolean bridgeEndpoint = getAndRemoveParameter(parameters, "bridgeEndpoint", Boolean.class);
Boolean matchOnUriPrefix = getAndRemoveParameter(parameters, "matchOnUriPrefix", Boolean.class);
Boolean disableStreamCache = getAndRemoveParameter(parameters, "disableStreamCache", Boolean.class);
String proxyHost = getAndRemoveParameter(parameters, "proxyHost", String.class);
Integer proxyPort = getAndRemoveParameter(parameters, "proxyPort", Integer.class);
String authMethodPriority = getAndRemoveParameter(parameters, "authMethodPriority", String.class);
// http client can be configured from URI options
HttpClientParams clientParams = new HttpClientParams();
IntrospectionSupport.setProperties(clientParams, parameters, "httpClient.");
// validate that we could resolve all httpClient. parameters as this component is lenient
validateParameters(uri, parameters, "httpClient.");
// create the configurer to use for this endpoint (authMethods contains the used methods created by the configurer)
final Set<AuthMethod> authMethods = new LinkedHashSet<AuthMethod>();
HttpClientConfigurer configurer = createHttpClientConfigurer(parameters, authMethods);
URI endpointUri = URISupport.createRemainingURI(new URI(addressUri), CastUtils.cast(httpClientParameters));
// restructure uri to be based on the parameters left as we dont want to include the Camel internal options
URI httpUri = URISupport.createRemainingURI(new URI(addressUri), CastUtils.cast(parameters));
// validate http uri that end-user did not duplicate the http part that can be a common error
String part = httpUri.getSchemeSpecificPart();
if (part != null) {
part = part.toLowerCase();
if (part.startsWith("//http//") || part.startsWith("//https//") || part.startsWith("//http://") || part.startsWith("//https://")) {
throw new ResolveEndpointFailedException(uri,
"The uri part is not configured correctly. You have duplicated the http(s) protocol.");
}
}
// need to keep the parameters of http client configure to avoid unwiser endpoint caching
// create the endpoint
HttpEndpoint endpoint = new HttpEndpoint(endpointUri.toString(), this, httpUri, clientParams, httpConnectionManager, configurer);
setEndpointHeaderFilterStrategy(endpoint);
// prefer to use endpoint configured over component configured
if (binding == null) {
// fallback to component configured
binding = getHttpBinding();
}
if (binding != null) {
endpoint.setBinding(binding);
}
// should we use an exception for failed error codes?
if (throwExceptionOnFailure != null) {
endpoint.setThrowExceptionOnFailure(throwExceptionOnFailure);
}
// should we transfer exception as serialized object
if (transferException != null) {
endpoint.setTransferException(transferException);
}
if (bridgeEndpoint != null) {
endpoint.setBridgeEndpoint(bridgeEndpoint);
}
if (matchOnUriPrefix != null) {
endpoint.setMatchOnUriPrefix(matchOnUriPrefix);
}
if (disableStreamCache != null) {
endpoint.setDisableStreamCache(disableStreamCache);
}
if (proxyHost != null) {
endpoint.setProxyHost(proxyHost);
endpoint.setProxyPort(proxyPort);
} else if (httpConfiguration != null) {
endpoint.setProxyHost(httpConfiguration.getProxyHost());
endpoint.setProxyPort(httpConfiguration.getProxyPort());
}
if (authMethodPriority != null) {
endpoint.setAuthMethodPriority(authMethodPriority);
} else if (httpConfiguration != null && httpConfiguration.getAuthMethodPriority() != null) {
endpoint.setAuthMethodPriority(httpConfiguration.getAuthMethodPriority());
} else {
// no explicit auth method priority configured, so use convention over configuration
// and set priority based on auth method
if (!authMethods.isEmpty()) {
authMethodPriority = CollectionHelper.collectionAsCommaDelimitedString(authMethods);
endpoint.setAuthMethodPriority(authMethodPriority);
}
}
setProperties(endpoint, parameters);
return endpoint;
}
@Override
protected boolean useIntrospectionOnEndpoint() {
return false;
}
public HttpClientConfigurer getHttpClientConfigurer() {
return httpClientConfigurer;
}
public void setHttpClientConfigurer(HttpClientConfigurer httpClientConfigurer) {
this.httpClientConfigurer = httpClientConfigurer;
}
public HttpConnectionManager getHttpConnectionManager() {
return httpConnectionManager;
}
public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) {
this.httpConnectionManager = httpConnectionManager;
}
public HttpBinding getHttpBinding() {
return httpBinding;
}
public void setHttpBinding(HttpBinding httpBinding) {
this.httpBinding = httpBinding;
}
public HttpConfiguration getHttpConfiguration() {
return httpConfiguration;
}
public void setHttpConfiguration(HttpConfiguration httpConfiguration) {
this.httpConfiguration = httpConfiguration;
}
}