2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.hpprinter.internal.api;
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
20 import java.util.function.Function;
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24 import javax.xml.parsers.ParserConfigurationException;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jetty.client.HttpClient;
28 import org.eclipse.jetty.client.api.ContentResponse;
29 import org.eclipse.jetty.http.HttpMethod;
30 import org.openhab.binding.hpprinter.internal.api.HPServerResult.RequestStatus;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.w3c.dom.Document;
34 import org.xml.sax.InputSource;
35 import org.xml.sax.SAXException;
38 * The {@link HPWebServerClient} is responsible for handling reading of data from the HP Embedded Web Server.
40 * @author Stewart Cossey - Initial contribution
43 public class HPWebServerClient {
44 public static final int REQUEST_TIMEOUT_SEC = 10;
45 private final Logger logger = LoggerFactory.getLogger(HPWebServerClient.class);
47 private final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
48 private final HttpClient httpClient;
49 private final String serverAddress;
52 * Creates a new HP Web Server Client object.
54 * @param httpClient {HttpClient} The HttpClient to use for HTTP requests.
55 * @param address The address for the Embedded Web Server.
57 public HPWebServerClient(HttpClient httpClient, String address) {
58 this.httpClient = httpClient;
59 serverAddress = "http://" + address;
61 logger.debug("Create printer connection {}", serverAddress);
65 * Gets the Status information from the Embedded Web Server.
67 * @return The status information.
69 public HPServerResult<HPStatus> getStatus() {
70 return fetchData(serverAddress + HPStatus.ENDPOINT, (HPStatus::new));
73 public HPServerResult<HPProductUsageFeatures> getProductFeatures() {
74 return fetchData(serverAddress + HPProductUsageFeatures.ENDPOINT, (HPProductUsageFeatures::new));
77 public HPServerResult<HPFeatures> getProductUsageFeatures() {
78 return fetchData(serverAddress + HPFeatures.ENDPOINT, (HPFeatures::new));
81 public HPServerResult<HPScannerStatusFeatures> getScannerFeatures() {
82 return fetchData(serverAddress + HPScannerStatusFeatures.ENDPOINT, (HPScannerStatusFeatures::new));
86 * Gets the Usage information from the Embedded Web Server.
88 * @return The usage information.
90 public HPServerResult<HPUsage> getUsage() {
91 return fetchData(serverAddress + HPUsage.ENDPOINT, (HPUsage::new));
94 public HPServerResult<HPScannerStatus> getScannerStatus() {
95 return fetchData(serverAddress + HPScannerStatus.ENDPOINT, (HPScannerStatus::new));
98 public HPServerResult<HPProperties> getProperties() {
99 return fetchData(serverAddress + HPProperties.ENDPOINT, (HPProperties::new));
102 private <T> HPServerResult<T> fetchData(String endpoint, Function<Document, T> function) {
104 logger.trace("HTTP Client Load {}", endpoint);
105 ContentResponse cr = httpClient.newRequest(endpoint).method(HttpMethod.GET)
106 .timeout(REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS).send();
108 String contentAsString = cr.getContentAsString();
109 logger.trace("HTTP Client Result {} Size {}", cr.getStatus(), contentAsString.length());
110 return new HPServerResult<>(function.apply(getDocument(contentAsString)));
111 } catch (TimeoutException ex) {
112 logger.trace("HTTP Client Timeout Exception {}", ex.getMessage());
113 return new HPServerResult<>(RequestStatus.TIMEOUT, ex.getMessage());
114 } catch (InterruptedException | ExecutionException | ParserConfigurationException | SAXException
116 logger.trace("HTTP Client Exception {}", ex.getMessage());
117 return new HPServerResult<>(RequestStatus.ERROR, ex.getMessage());
121 private synchronized Document getDocument(String contentAsString)
122 throws ParserConfigurationException, SAXException, IOException {
123 // see https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
124 factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
125 factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
126 factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
127 factory.setXIncludeAware(false);
128 factory.setExpandEntityReferences(false);
129 DocumentBuilder builder = factory.newDocumentBuilder();
130 InputSource source = new InputSource(new StringReader(contentAsString));
131 return builder.parse(source);