/** * 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.http4; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; import java.util.Optional; import org.apache.camel.http.common.HttpHelper; import org.apache.camel.impl.verifier.DefaultComponentVerifier; import org.apache.camel.impl.verifier.ResultBuilder; import org.apache.camel.impl.verifier.ResultErrorBuilder; import org.apache.camel.util.FileUtil; import org.apache.camel.util.ObjectHelper; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; final class HttpComponentVerifier extends DefaultComponentVerifier { private final HttpComponent component; HttpComponentVerifier(HttpComponent component) { super("http4", component.getCamelContext()); this.component = component; } // ********************************* // Parameters validation // ********************************* @Override protected Result verifyParameters(Map<String, Object> parameters) { // Default is success final ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS); // Make a copy to avoid clashing with parent validation final HashMap<String, Object> verifyParams = new HashMap<>(parameters); // Check if validation is rest-related final boolean isRest = verifyParams.entrySet().stream().anyMatch(e -> e.getKey().startsWith("rest.")); if (isRest) { // Build the httpUri from rest configuration verifyParams.put("httpUri", buildHttpUriFromRestParameters(parameters)); // Cleanup parameters map from rest related stuffs verifyParams.entrySet().removeIf(e -> e.getKey().startsWith("rest.")); } // Validate using the catalog super.verifyParametersAgainstCatalog(builder, verifyParams); return builder.build(); } // ********************************* // Connectivity validation // ********************************* @Override protected Result verifyConnectivity(Map<String, Object> parameters) { // Default is success final ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.CONNECTIVITY); // Make a copy to avoid clashing with parent validation final HashMap<String, Object> verifyParams = new HashMap<>(parameters); // Check if validation is rest-related final boolean isRest = verifyParams.entrySet().stream().anyMatch(e -> e.getKey().startsWith("rest.")); if (isRest) { // Build the httpUri from rest configuration verifyParams.put("httpUri", buildHttpUriFromRestParameters(parameters)); // Cleanup parameters from rest related stuffs verifyParams.entrySet().removeIf(e -> e.getKey().startsWith("rest.")); } String httpUri = getOption(verifyParams, "httpUri", String.class).orElse(null); if (ObjectHelper.isEmpty(httpUri)) { builder.error( ResultErrorBuilder.withMissingOption("httpUri") .detail("rest", isRest) .build() ); } try { CloseableHttpClient httpclient = createHttpClient(verifyParams); HttpUriRequest request = new HttpGet(httpUri); try (CloseableHttpResponse response = httpclient.execute(request)) { int code = response.getStatusLine().getStatusCode(); String okCodes = getOption(verifyParams, "okStatusCodeRange", String.class).orElse("200-299"); if (!HttpHelper.isStatusCodeOk(code, okCodes)) { if (code == 401) { // Unauthorized, add authUsername and authPassword to the list // of parameters in error builder.error( ResultErrorBuilder.withHttpCode(code) .description(response.getStatusLine().getReasonPhrase()) .parameterKey("authUsername") .parameterKey("authPassword") .build() ); } else if (code >= 300 && code < 400) { // redirect builder.error( ResultErrorBuilder.withHttpCode(code) .description(response.getStatusLine().getReasonPhrase()) .parameterKey("httpUri") .detail(VerificationError.HttpAttribute.HTTP_REDIRECT, () -> HttpUtil.responseHeaderValue(response, "location")) .build() ); } else if (code >= 400) { // generic http error builder.error( ResultErrorBuilder.withHttpCode(code) .description(response.getStatusLine().getReasonPhrase()) .build() ); } } } catch (UnknownHostException e) { builder.error( ResultErrorBuilder.withException(e) .parameterKey("httpUri") .build() ); } } catch (Exception e) { builder.error(ResultErrorBuilder.withException(e).build()); } return builder.build(); } // ********************************* // Helpers // ********************************* private String buildHttpUriFromRestParameters(Map<String, Object> parameters) { // We are doing rest endpoint validation but as today the endpoint // can't do any param substitution so the validation is performed // against the http uri String httpUri = getOption(parameters, "rest.host", String.class).orElse(null); String path = getOption(parameters, "rest.path", String.class).map(FileUtil::stripLeadingSeparator).orElse(null); if (ObjectHelper.isNotEmpty(httpUri) && ObjectHelper.isNotEmpty(path)) { httpUri = httpUri + "/" + path; } return httpUri; } private Optional<HttpClientConfigurer> configureAuthentication(Map<String, Object> parameters) { Optional<String> authUsername = getOption(parameters, "authUsername", String.class); Optional<String> authPassword = getOption(parameters, "authPassword", String.class); if (authUsername.isPresent() && authPassword.isPresent()) { Optional<String> authDomain = getOption(parameters, "authDomain", String.class); Optional<String> authHost = getOption(parameters, "authHost", String.class); return Optional.of( new BasicAuthenticationHttpClientConfigurer( authUsername.get(), authPassword.get(), authDomain.orElse(null), authHost.orElse(null) ) ); } return Optional.empty(); } private Optional<HttpClientConfigurer> configureProxy(Map<String, Object> parameters) { Optional<String> uri = getOption(parameters, "httpUri", String.class); Optional<String> proxyAuthHost = getOption(parameters, "proxyAuthHost", String.class); Optional<Integer> proxyAuthPort = getOption(parameters, "proxyAuthPort", Integer.class); if (proxyAuthHost.isPresent() && proxyAuthPort.isPresent()) { Optional<String> proxyAuthScheme = getOption(parameters, "proxyAuthScheme", String.class); Optional<String> proxyAuthUsername = getOption(parameters, "proxyAuthUsername", String.class); Optional<String> proxyAuthPassword = getOption(parameters, "proxyAuthPassword", String.class); Optional<String> proxyAuthDomain = getOption(parameters, "proxyAuthDomain", String.class); Optional<String> proxyAuthNtHost = getOption(parameters, "proxyAuthNtHost", String.class); if (!proxyAuthScheme.isPresent()) { proxyAuthScheme = Optional.of(HttpHelper.isSecureConnection(uri.get()) ? "https" : "http"); } if (proxyAuthUsername != null && proxyAuthPassword != null) { return Optional.of( new ProxyHttpClientConfigurer( proxyAuthHost.get(), proxyAuthPort.get(), proxyAuthScheme.get(), proxyAuthUsername.orElse(null), proxyAuthPassword.orElse(null), proxyAuthDomain.orElse(null), proxyAuthNtHost.orElse(null)) ); } else { return Optional.of( new ProxyHttpClientConfigurer( proxyAuthHost.get(), proxyAuthPort.get(), proxyAuthScheme.get()) ); } } return Optional.empty(); } private CloseableHttpClient createHttpClient(Map<String, Object> parameters) throws Exception { CompositeHttpConfigurer configurer = new CompositeHttpConfigurer(); configureAuthentication(parameters).ifPresent(configurer::addConfigurer); configureProxy(parameters).ifPresent(configurer::addConfigurer); HttpClientBuilder builder = HttpClientBuilder.create(); configurer.configureHttpClient(builder); RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); // Apply custom http client properties like httpClient.redirectsEnabled setProperties(builder, "httpClient.", parameters); setProperties(requestConfigBuilder, "httpClient.", parameters); return builder.setDefaultRequestConfig(requestConfigBuilder.build()) .build(); } }