diff --git a/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexApiConnector.java b/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexApiConnector.java index 6f9db9018..7a95ece6e 100644 --- a/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexApiConnector.java +++ b/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexApiConnector.java @@ -17,13 +17,17 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.Base64; import java.util.Properties; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; @@ -129,11 +133,12 @@ public class PlexApiConnector { */ public @Nullable MediaContainer getSessionData() { try { - String url = "http://" + host + ":" + String.valueOf(port) + "/status/sessions" + "?X-Plex-Token=" + token; + String url = "https://" + host + ":" + String.valueOf(port) + "/status/sessions" + "?X-Plex-Token=" + token; logger.debug("Getting session data '{}'", url); - MediaContainer mediaContainer = doHttpRequest("GET", url, getClientHeaders(), MediaContainer.class); + MediaContainer mediaContainer = getFromXml(doHttpRequest("GET", url, getClientHeaders(), false), + MediaContainer.class); return mediaContainer; - } catch (IOException e) { + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { logger.debug("An exception occurred while polling the PLEX Server: '{}'", e.getMessage()); return null; } @@ -151,7 +156,7 @@ public class PlexApiConnector { } /** - * This method will get an X-Token from the PLEX server if one is not provided in the bridge config + * This method will get an X-Token from the PLEX.tv server if one is not provided in the bridge config * and use this in the communication with the plex server */ public void getToken() { @@ -161,8 +166,8 @@ public class PlexApiConnector { headers.put("Authorization", "Basic " + authString); try { - user = doHttpRequest("POST", SIGNIN_URL, headers, User.class); - } catch (IOException e) { + user = getFromXml(doHttpRequest("POST", SIGNIN_URL, headers, true), User.class); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { logger.debug("An exception occurred while fetching PLEX user token :'{}'", e.getMessage(), e); throw new ConfigurationException("Error occurred while fetching PLEX user token, please check config"); } @@ -176,11 +181,12 @@ public class PlexApiConnector { } /** - * This method will get the Api information from the PLEX servers. + * This method will get the Api information from the PLEX.tv servers. */ public boolean getApi() { try { - MediaContainer api = doHttpRequest("GET", API_URL, getClientHeaders(), MediaContainer.class); + MediaContainer api = getFromXml(doHttpRequest("GET", API_URL, getClientHeaders(), true), + MediaContainer.class); logger.debug("MediaContainer {}", api.getSize()); if (api.getDevice() != null) { for (Device tmpDevice : api.getDevice()) { @@ -198,28 +204,58 @@ public class PlexApiConnector { } } return false; - } catch (IOException e) { + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { logger.debug("An exception occurred while fetching API :'{}'", e.getMessage(), e); } return false; } /** - * Make an HTTP request and return the class object that was used when calling. + * Make an HTTP request and return the response as a string. * - * @param Class being used(dto) * @param method GET/POST * @param url What URL to call * @param headers Additional headers that will be used - * @param type class type for the XML parsing - * @return Returns a class object from the data returned by the call + * @param verify Flag to indicate if ssl certificate checking should be done + * @return Returns a string of the http response * @throws IOException + * @throws ExecutionException + * @throws TimeoutException + * @throws InterruptedException */ - private T doHttpRequest(String method, String url, Properties headers, Class type) throws IOException { - String response = HttpUtil.executeUrl(method, url, headers, null, null, REQUEST_TIMEOUT_MS); + private String doHttpRequest(String method, String url, Properties headers, boolean verify) + throws IOException, InterruptedException, TimeoutException, ExecutionException { + final String response; + if (verify) { + // Requests sent to the PLEX.tv servers should use certificate checking + response = HttpUtil.executeUrl(method, url, headers, null, null, REQUEST_TIMEOUT_MS); + } else { + // Requests sent to the local server need to bypass certificate checking via the custom httpClient + final Request request = httpClient.newRequest(url).method(HttpUtil.createHttpMethod(method)); + for (String httpHeaderKey : headers.stringPropertyNames()) { + if (httpHeaderKey.equalsIgnoreCase(HttpHeader.USER_AGENT.toString())) { + request.agent(headers.getProperty(httpHeaderKey)); + } else { + request.header(httpHeaderKey, headers.getProperty(httpHeaderKey)); + } + } + final ContentResponse res = request.send(); + response = res.getContentAsString(); + } + logger.debug("HTTP response: {}", response); + return response; + } + + /** + * Return the class object that was represented by the xml input string. + * + * @param response The xml response to parse + * @param type Class type for the XML parsing + * @return Returns a class object from the input sring + */ + private T getFromXml(String response, Class type) { @SuppressWarnings("unchecked") T obj = (T) xStream.fromXML(response); - logger.debug("HTTP response {}", response); return obj; } @@ -230,7 +266,7 @@ public class PlexApiConnector { */ private Properties getClientHeaders() { Properties headers = new Properties(); - headers.put(HttpHeader.USER_AGENT, "openHAB / PLEX binding "); // + VERSION); + headers.put(HttpHeader.USER_AGENT, "openHAB/" + org.openhab.core.OpenHAB.getVersion() + " PLEX binding"); headers.put("X-Plex-Client-Identifier", CLIENT_ID); headers.put("X-Plex-Product", "openHAB"); headers.put("X-Plex-Version", ""); @@ -377,11 +413,11 @@ public class PlexApiConnector { if (commandPath != null) { try { - String url = "http://" + host + ":" + String.valueOf(port) + commandPath; + String url = "https://" + host + ":" + String.valueOf(port) + commandPath; Properties headers = getClientHeaders(); headers.put("X-Plex-Target-Client-Identifier", playerID); - HttpUtil.executeUrl("GET", url, headers, null, null, REQUEST_TIMEOUT_MS); - } catch (IOException e) { + doHttpRequest("GET", url, headers, false); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { logger.debug("An exception occurred trying to send command '{}' to the player: {}", commandPath, e.getMessage()); } diff --git a/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexServerHandler.java b/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexServerHandler.java index ca6a93ff1..16423c07f 100644 --- a/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexServerHandler.java +++ b/bundles/org.openhab.binding.plex/src/main/java/org/openhab/binding/plex/internal/handler/PlexServerHandler.java @@ -90,6 +90,7 @@ public class PlexServerHandler extends BaseBridgeHandler implements PlexUpdateLi try { SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setEndpointIdentificationAlgorithm(null); + sslContextFactory.setTrustAll(true); HttpClient localHttpClient = httpClient = httpClientFactory.createHttpClient(httpClientName, sslContextFactory); localHttpClient.start();