001/* 002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.benchmarking.common.http; 017 018import de.cuioss.tools.logging.CuiLogger; 019 020import javax.net.ssl.SSLContext; 021import javax.net.ssl.TrustManager; 022import javax.net.ssl.X509TrustManager; 023import java.net.http.HttpClient; 024import java.security.KeyManagementException; 025import java.security.NoSuchAlgorithmException; 026import java.security.SecureRandom; 027import java.security.cert.X509Certificate; 028import java.time.Duration; 029 030import static de.cuioss.benchmarking.common.util.BenchmarkingLogMessages.INFO.*; 031 032/** 033 * Factory for creating Java HttpClient instances for benchmarking. 034 * Uses singleton pattern for efficient resource usage. 035 */ 036public class HttpClientFactory { 037 038 private HttpClientFactory() { 039 // Utility class 040 } 041 042 private static final CuiLogger LOGGER = new CuiLogger(HttpClientFactory.class); 043 044 private static final int CONNECT_TIMEOUT_SECONDS = 5; 045 046 /** 047 * System property to configure HTTP protocol version. 048 * Values: "http2" (default), "http1" (HTTP/1.1 only) 049 * Set -Dbenchmark.http.protocol=http1 to force HTTP/1.1 050 */ 051 private static final String HTTP_PROTOCOL_PROPERTY = "benchmark.http.protocol"; 052 private static final String DEFAULT_HTTP_PROTOCOL = "http2"; 053 054 private static final HttpClient CLIENT = createClient(); 055 056 public static HttpClient getInsecureClient() { 057 return CLIENT; 058 } 059 060 @SuppressWarnings("java:S4830") // ok for testing purposes 061 private static HttpClient createClient() { 062 try { 063 TrustManager[] trustAllCerts = new TrustManager[]{ 064 new X509TrustManager() { 065 @Override 066 public void checkClientTrusted(X509Certificate[] chain, String authType) { 067 // Accept all client certificates for benchmark testing 068 } 069 070 @Override 071 public void checkServerTrusted(X509Certificate[] chain, String authType) { 072 // Accept all server certificates for benchmark testing with self-signed certs 073 } 074 075 @Override 076 public X509Certificate[] getAcceptedIssuers() { 077 return new X509Certificate[0]; 078 } 079 } 080 }; 081 082 SSLContext sslContext = SSLContext.getInstance("TLS"); 083 sslContext.init(null, trustAllCerts, new SecureRandom()); 084 085 HttpClient.Version version = getHttpVersion(); 086 087 HttpClient client = HttpClient.newBuilder() 088 .version(version) 089 .connectTimeout(Duration.ofSeconds(CONNECT_TIMEOUT_SECONDS)) 090 .sslContext(sslContext) 091 .build(); 092 093 LOGGER.info(HTTP_CLIENT_CREATED, version, CONNECT_TIMEOUT_SECONDS); 094 return client; 095 096 } catch (NoSuchAlgorithmException | KeyManagementException e) { 097 throw new IllegalStateException("Failed to create Java HttpClient", e); 098 } 099 } 100 101 /** 102 * Determines which HTTP protocol version to use based on system property configuration. 103 * @return HTTP version to use (HTTP/2 by default, HTTP/1.1 if configured) 104 */ 105 private static HttpClient.Version getHttpVersion() { 106 String protocol = System.getProperty(HTTP_PROTOCOL_PROPERTY, DEFAULT_HTTP_PROTOCOL).toLowerCase(); 107 108 return switch (protocol) { 109 case "http1" -> { 110 LOGGER.info(USING_HTTP_1_1, HTTP_PROTOCOL_PROPERTY); 111 yield HttpClient.Version.HTTP_1_1; 112 } 113 default -> { 114 LOGGER.info(USING_HTTP_2, HTTP_PROTOCOL_PROPERTY); 115 yield HttpClient.Version.HTTP_2; 116 } 117 }; 118 } 119}