]> git.basschouten.com Git - openhab-addons.git/blob
c2d312c9d8bc98bbae35783c0bf488ddfe32b9ca
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.hpprinter.internal.api;
14
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;
21
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24 import javax.xml.parsers.ParserConfigurationException;
25
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;
36
37 /**
38  * The {@link HPWebServerClient} is responsible for handling reading of data from the HP Embedded Web Server.
39  *
40  * @author Stewart Cossey - Initial contribution
41  */
42 @NonNullByDefault
43 public class HPWebServerClient {
44     public static final int REQUEST_TIMEOUT_SEC = 10;
45     private final Logger logger = LoggerFactory.getLogger(HPWebServerClient.class);
46
47     private final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
48     private final HttpClient httpClient;
49     private final String serverAddress;
50
51     /**
52      * Creates a new HP Web Server Client object.
53      *
54      * @param httpClient {HttpClient} The HttpClient to use for HTTP requests.
55      * @param address The address for the Embedded Web Server.
56      */
57     public HPWebServerClient(HttpClient httpClient, String address) {
58         this.httpClient = httpClient;
59         serverAddress = "http://" + address;
60
61         logger.debug("Create printer connection {}", serverAddress);
62     }
63
64     /**
65      * Gets the Status information from the Embedded Web Server.
66      *
67      * @return The status information.
68      */
69     public HPServerResult<HPStatus> getStatus() {
70         return fetchData(serverAddress + HPStatus.ENDPOINT, (HPStatus::new));
71     }
72
73     public HPServerResult<HPProductUsageFeatures> getProductFeatures() {
74         return fetchData(serverAddress + HPProductUsageFeatures.ENDPOINT, (HPProductUsageFeatures::new));
75     }
76
77     public HPServerResult<HPFeatures> getProductUsageFeatures() {
78         return fetchData(serverAddress + HPFeatures.ENDPOINT, (HPFeatures::new));
79     }
80
81     public HPServerResult<HPScannerStatusFeatures> getScannerFeatures() {
82         return fetchData(serverAddress + HPScannerStatusFeatures.ENDPOINT, (HPScannerStatusFeatures::new));
83     }
84
85     /**
86      * Gets the Usage information from the Embedded Web Server.
87      *
88      * @return The usage information.
89      */
90     public HPServerResult<HPUsage> getUsage() {
91         return fetchData(serverAddress + HPUsage.ENDPOINT, (HPUsage::new));
92     }
93
94     public HPServerResult<HPScannerStatus> getScannerStatus() {
95         return fetchData(serverAddress + HPScannerStatus.ENDPOINT, (HPScannerStatus::new));
96     }
97
98     public HPServerResult<HPProperties> getProperties() {
99         return fetchData(serverAddress + HPProperties.ENDPOINT, (HPProperties::new));
100     }
101
102     private <T> HPServerResult<T> fetchData(String endpoint, Function<Document, T> function) {
103         try {
104             logger.trace("HTTP Client Load {}", endpoint);
105             ContentResponse cr = httpClient.newRequest(endpoint).method(HttpMethod.GET)
106                     .timeout(REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS).send();
107
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
115                 | IOException ex) {
116             logger.trace("HTTP Client Exception {}", ex.getMessage());
117             return new HPServerResult<>(RequestStatus.ERROR, ex.getMessage());
118         }
119     }
120
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);
132     }
133 }