View Javadoc
1   /*
2    * Copyright 2012-2025 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.helper;
17  
18  import static org.codelibs.core.stream.StreamUtil.split;
19  
20  import java.io.FileInputStream;
21  import java.io.InputStream;
22  import java.nio.charset.StandardCharsets;
23  import java.security.KeyStore;
24  import java.security.cert.Certificate;
25  import java.security.cert.CertificateFactory;
26  
27  import javax.net.ssl.SSLContext;
28  import javax.net.ssl.SSLSocketFactory;
29  import javax.net.ssl.TrustManagerFactory;
30  
31  import org.apache.logging.log4j.LogManager;
32  import org.apache.logging.log4j.Logger;
33  import org.codelibs.core.lang.StringUtil;
34  import org.codelibs.curl.Curl.Method;
35  import org.codelibs.curl.CurlRequest;
36  import org.codelibs.fesen.client.curl.FesenRequest;
37  import org.codelibs.fesen.client.node.NodeManager;
38  import org.codelibs.fess.mylasta.direction.FessConfig;
39  import org.codelibs.fess.util.ComponentUtil;
40  import org.codelibs.fess.util.ResourceUtil;
41  
42  import jakarta.annotation.PostConstruct;
43  
44  /**
45   * Helper class for managing HTTP requests using cURL-like operations.
46   */
47  public class CurlHelper {
48  
49      /**
50       * Default constructor.
51       */
52      public CurlHelper() {
53          // Empty constructor
54      }
55  
56      private static final Logger logger = LogManager.getLogger(CurlHelper.class);
57  
58      private SSLSocketFactory sslSocketFactory;
59  
60      private NodeManager nodeManager;
61  
62      /**
63       * Initializes the CurlHelper with SSL configuration and node manager.
64       */
65      @PostConstruct
66      public void init() {
67          final FessConfig fessConfig = ComponentUtil.getFessConfig();
68          final String authorities = fessConfig.getFesenHttpSslCertificateAuthorities();
69          if (StringUtil.isNotBlank(authorities)) {
70              if (logger.isDebugEnabled()) {
71                  logger.debug("Loading certificate_authorities: path={}", authorities);
72              }
73              try (final InputStream in = new FileInputStream(authorities)) {
74                  final Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(in);
75  
76                  final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
77                  keyStore.load(null, null);
78                  keyStore.setCertificateEntry("server", certificate);
79  
80                  final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
81                  trustManagerFactory.init(keyStore);
82  
83                  final SSLContext sslContext = SSLContext.getInstance("TLS");
84                  sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
85                  sslSocketFactory = sslContext.getSocketFactory();
86              } catch (final Exception e) {
87                  logger.warn("Failed to load certificate_authorities: path={}", authorities, e);
88              }
89          }
90  
91          final String[] hosts = split(ResourceUtil.getFesenHttpUrl(), ",")
92                  .get(stream -> stream.map(String::trim).filter(StringUtil::isNotEmpty).toArray(n -> new String[n]));
93          nodeManager = new NodeManager(hosts, node -> request(new CurlRequest(Method.GET, node.getUrl("/"))));
94          nodeManager.setHeartbeatInterval(fessConfig.getFesenHeartbeatInterval());
95      }
96  
97      /**
98       * Creates a GET request for the specified path.
99       * @param path the request path
100      * @return the configured CurlRequest
101      */
102     public CurlRequest get(final String path) {
103         return request(Method.GET, path).header("Content-Type", "application/json");
104     }
105 
106     /**
107      * Creates a POST request for the specified path.
108      * @param path the request path
109      * @return the configured CurlRequest
110      */
111     public CurlRequest post(final String path) {
112         return request(Method.POST, path).header("Content-Type", "application/json");
113     }
114 
115     /**
116      * Creates a PUT request for the specified path.
117      * @param path the request path
118      * @return the configured CurlRequest
119      */
120     public CurlRequest put(final String path) {
121         return request(Method.PUT, path).header("Content-Type", "application/json");
122     }
123 
124     /**
125      * Creates a DELETE request for the specified path.
126      * @param path the request path
127      * @return the configured CurlRequest
128      */
129     public CurlRequest delete(final String path) {
130         return request(Method.DELETE, path).header("Content-Type", "application/json");
131     }
132 
133     /**
134      * Creates a request with the specified HTTP method and path.
135      * @param method the HTTP method
136      * @param path the request path
137      * @return the configured CurlRequest
138      */
139     public CurlRequest request(final Method method, final String path) {
140         return request(new FesenRequest(new CurlRequest(method, null), nodeManager, path));
141     }
142 
143     /**
144      * Configures the request with authentication and SSL settings.
145      * @param request the request to configure
146      * @return the configured request
147      */
148     protected CurlRequest request(final CurlRequest request) {
149         final FessConfig fessConfig = ComponentUtil.getFessConfig();
150         final String username = fessConfig.getFesenUsername();
151         final String password = fessConfig.getFesenPassword();
152         if (StringUtil.isNotBlank(username) && StringUtil.isNotBlank(password)) {
153             final String value = username + ":" + password;
154             final String basicAuth = "Basic " + java.util.Base64.getEncoder().encodeToString(value.getBytes(StandardCharsets.UTF_8));
155             request.header("Authorization", basicAuth);
156         }
157         if (sslSocketFactory != null) {
158             request.sslSocketFactory(sslSocketFactory);
159         }
160         return request;
161     }
162 }