diff --git a/openvidu-java-client/pom.xml b/openvidu-java-client/pom.xml index 3d6d759b..b21aba0a 100644 --- a/openvidu-java-client/pom.xml +++ b/openvidu-java-client/pom.xml @@ -63,6 +63,11 @@ + + org.apache.httpcomponents.client5 + httpclient5 + 5.2.1 + com.google.code.gson gson diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java index a2d31b50..84eb3f5d 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java @@ -18,49 +18,66 @@ package io.openvidu.java.client; import java.io.IOException; -import java.net.HttpURLConnection; import java.net.MalformedURLException; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; -import java.net.http.HttpClient; -import java.net.http.HttpClient.Builder; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.time.Duration; import java.util.ArrayList; -import java.util.Base64; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedTrustManager; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpDelete; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.TrustStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; public class OpenVidu { private static final Logger log = LoggerFactory.getLogger(OpenVidu.class); protected String hostname; - protected HttpClient httpClient; + protected CloseableHttpClient httpClient; protected Map activeSessions = new ConcurrentHashMap<>(); - protected long requestTimeout = 30000; - protected Map headers = new HashMap<>(); protected final static String API_PATH = "openvidu/api"; protected final static String API_SESSIONS = API_PATH + "/sessions"; @@ -69,8 +86,6 @@ public class OpenVidu { protected final static String API_RECORDINGS_START = API_RECORDINGS + "/start"; protected final static String API_RECORDINGS_STOP = API_RECORDINGS + "/stop"; - private String defaultBasicAuth; - /** * @param hostname URL where your OpenVidu deployment is up an running. It must * be the full URL (e.g. https://12.34.56.78:1234/) @@ -80,138 +95,115 @@ public class OpenVidu { public OpenVidu(String hostname, String secret) { testHostname(hostname); - setDefaultBasicAuth(secret); - this.hostname = hostname; if (!this.hostname.endsWith("/")) { this.hostname += "/"; } + TrustStrategy trustStrategy = new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }; + + final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(null, -1), + new UsernamePasswordCredentials("OPENVIDUAPP", secret.toCharArray())); + SSLContext sslContext; try { - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { new X509ExtendedTrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type) { - } - - public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type) { - } - - public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final Socket a_socket) { - } - - public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final Socket a_socket) { - } - - public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final SSLEngine a_engine) { - } - - public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final SSLEngine a_engine) { - } - } }, null); - } catch (KeyManagementException | NoSuchAlgorithmException e) { + sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { throw new RuntimeException(e); } + final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() + .setSslContext(sslContext).build(); - Builder b = HttpClient.newBuilder(); - b.sslContext(sslContext); - b.connectTimeout(Duration.ofSeconds(30)); - this.httpClient = b.build(); + ConnectionConfig.Builder connectionConfigBuilder = ConnectionConfig.custom() + .setConnectTimeout(30, TimeUnit.SECONDS).setSocketTimeout(30, TimeUnit.SECONDS) + .setTimeToLive(30, TimeUnit.SECONDS); + + final HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslSocketFactory).setDefaultConnectionConfig(connectionConfigBuilder.build()) + .build(); + + RequestConfig requestBuilder = RequestConfig.custom().setConnectionRequestTimeout(30, TimeUnit.SECONDS).build(); + + this.httpClient = HttpClients.custom().setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestBuilder).setDefaultCredentialsProvider(credentialsProvider).build(); } /** - * @param hostname URL where your OpenVidu deployment is up an running. It - * must be the full URL (e.g. - * https://12.34.56.78:1234/) - * @param httpClient Object of class java.net.http.HttpClient. - * This overrides the internal HTTP client in use. This method - * allows you to custom configure the HTTP client to your - * needs. This may be interesting for many reasons, including: - *
    - *
  • Adding proxy configuration
  • - *
  • Customizing the SSLContext
  • - *
  • Modifying the connection timeout
  • - *
  • Adding a cookie handler
  • - *
+ * @param hostname URL where your OpenVidu deployment is up an running. It must + * be the full URL (e.g. https://12.34.56.78:1234/) + * + * @param secret Secret configured in your OpenVidu deployment + * + * @param builder An instance of org.apache.hc.client5.http.impl.classic.HttpClientBuilder. + * This overrides the internal HTTP client in use. This method + * allows you to custom configure the HTTP client to your needs. + * This may be interesting for many reasons, including: + *
    + *
  • Adding custom HTTP headers
  • + *
  • Adding proxy configuration
  • + *
  • Customizing the SSLContext
  • + *
  • Modifying the connection timeouts
  • + *
  • Setting up a cookie store
  • + *
+ * This method will override any CredentialsProvider of the + * {@code builder} with a BasicCredentialsProvider built with the + * param {@code secret}, which is the default configuration. */ - public OpenVidu(String hostname, String secret, HttpClient httpClient) { + public OpenVidu(String hostname, String secret, HttpClientBuilder builder) { testHostname(hostname); - setDefaultBasicAuth(secret); - this.hostname = hostname; if (!this.hostname.endsWith("/")) { this.hostname += "/"; } - Builder b = HttpClient.newBuilder(); - if (httpClient.authenticator().isPresent()) { - log.warn( - "The provided HttpClient contains a custom java.net.Authenticator. OpenVidu deployments require all HTTP requests to have an Authorization header with Basic Auth, with username \"OPENVIDUAPP\" and password your OpenVidu deployment's secret (configuration parameter OPENVIDU_SECRET). The default Authenticator adds this header. Make sure that your custom Authenticator does so as well or that you add it explicitly via OpenVidu#setRequestHeaders, or you will receive 401 responses"); - b.authenticator(httpClient.authenticator().get()); - } - if (httpClient.connectTimeout().isPresent()) { - b.connectTimeout(httpClient.connectTimeout().get()); - } - if (httpClient.cookieHandler().isPresent()) { - b.cookieHandler(httpClient.cookieHandler().get()); - } - if (httpClient.executor().isPresent()) { - b.executor(httpClient.executor().get()); - } - if (httpClient.proxy().isPresent()) { - b.proxy(httpClient.proxy().get()); - } - b.followRedirects(httpClient.followRedirects()); - b.sslContext(httpClient.sslContext()); - b.sslParameters(httpClient.sslParameters()); - b.version(httpClient.version()); - - this.httpClient = b.build(); + final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(null, -1), + new UsernamePasswordCredentials("OPENVIDUAPP", secret.toCharArray())); + this.httpClient = builder.setDefaultCredentialsProvider(credentialsProvider).build(); } /** - * Returns the current request timeout configured for all requests. - */ - public long getRequestTimeout() { - return this.requestTimeout; - } - - /** - * Sets the request timeout for all HTTP requests. This is the same as setting - * the HttpRequest.timeout() - * property for all requests. The default value is 30000 ms. + * @param hostname URL where your OpenVidu deployment is up an running. It must + * be the full URL (e.g. https://12.34.56.78:1234/) * - * @param requestTimeout Timeout in milliseconds + * @param builder An instance of org.apache.hc.client5.http.impl.classic.HttpClientBuilder. + * This overrides the internal HTTP client in use. This method + * allows you to custom configure the HTTP client to your needs. + * This may be interesting for many reasons, including: + *
    + *
  • Adding custom HTTP headers
  • + *
  • Adding proxy configuration
  • + *
  • Customizing the SSLContext
  • + *
  • Modifying the connection timeouts
  • + *
  • Setting up a cookie store
  • + *
*/ - public void setRequestTimeout(long requestTimeout) { - this.requestTimeout = requestTimeout; - } + public OpenVidu(String hostname, HttpClientBuilder builder) { - /** - * Returns the current collection of custom headers configured for all requests. - */ - public Map getRequestHeaders() { - return this.headers; - } + testHostname(hostname); + this.hostname = hostname; + if (!this.hostname.endsWith("/")) { + this.hostname += "/"; + } - /** - * Sets custom HTTP headers for all requests. Will override any previous value. - * - * @param headers Header names and values - */ - public void setRequestHeaders(Map headers) { - this.headers = headers; + this.httpClient = builder.build(); } /** @@ -275,37 +267,41 @@ public class OpenVidu { * API) */ public Recording startRecording(String sessionId, RecordingProperties properties) - throws OpenViduJavaClientException, OpenViduHttpException { + throws OpenViduHttpException, OpenViduJavaClientException { + + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Recording handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + Recording r = new Recording(httpResponseEntityToJson(response.getEntity())); + Session activeSession = activeSessions.get(r.getSessionId()); + if (activeSession != null) { + activeSession.setIsBeingRecorded(true); + } else { + log.warn( + "No active session found for sessionId '{}'. This instance of OpenVidu Java Client didn't create this session", + r.getSessionId()); + } + return r; + } else { + throw openViduHttpException(status); + } + } + }; + + JsonObject json = properties.toJson(); + json.addProperty("session", sessionId); + StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8); + + HttpPost request = new HttpPost(this.hostname + API_RECORDINGS_START); + request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + request.setEntity(params); try { - JsonObject json = properties.toJson(); - json.addProperty("session", sessionId); - - HttpRequest request = addHeaders( - HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(json.toString())) - .uri(new URI(this.hostname + API_RECORDINGS_START)) - .setHeader("Content-Type", "application/json").timeout(Duration.ofMillis(requestTimeout))) - .build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - - if ((response.statusCode() == HttpURLConnection.HTTP_OK)) { - Recording r = new Recording(Utils.httpResponseToJson(response)); - Session activeSession = this.activeSessions.get(r.getSessionId()); - if (activeSession != null) { - activeSession.setIsBeingRecorded(true); - } else { - log.warn( - "No active session found for sessionId '{}'. This instance of OpenVidu Java Client didn't create this session", - r.getSessionId()); - } - return r; - } else { - throw new OpenViduHttpException(response.statusCode()); - } - - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + return this.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw ioExceptionToOpenViduHttpException(e); } } @@ -376,29 +372,33 @@ public class OpenVidu { */ public Recording stopRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException { - try { - HttpRequest request = addHeaders(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.noBody()) - .uri(new URI(this.hostname + API_RECORDINGS_STOP + "/" + recordingId)) - .timeout(Duration.ofMillis(requestTimeout))).build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - Recording r = new Recording(Utils.httpResponseToJson(response)); - Session activeSession = this.activeSessions.get(r.getSessionId()); - if (activeSession != null) { - activeSession.setIsBeingRecorded(false); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Recording handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + Recording r = new Recording(httpResponseEntityToJson(response.getEntity())); + Session activeSession = activeSessions.get(r.getSessionId()); + if (activeSession != null) { + activeSession.setIsBeingRecorded(false); + } else { + log.warn( + "No active session found for sessionId '{}'. This instance of OpenVidu Java Client didn't create this session", + r.getSessionId()); + } + return r; } else { - log.warn( - "No active session found for sessionId '{}'. This instance of OpenVidu Java Client didn't create this session", - r.getSessionId()); + throw openViduHttpException(status); } - return r; - } else { - throw new OpenViduHttpException(response.statusCode()); } - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + }; + + HttpPost request = new HttpPost(this.hostname + API_RECORDINGS_STOP + "/" + recordingId); + + try { + return this.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw ioExceptionToOpenViduHttpException(e); } } @@ -417,21 +417,24 @@ public class OpenVidu { */ public Recording getRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException { - try { - HttpRequest request = addHeaders( - HttpRequest.newBuilder().GET().uri(new URI(this.hostname + API_RECORDINGS + "/" + recordingId)) - .timeout(Duration.ofMillis(requestTimeout))) - .build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - return new Recording(Utils.httpResponseToJson(response)); - } else { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Recording handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + return new Recording(httpResponseEntityToJson(response.getEntity())); + } else { + throw openViduHttpException(status); + } } - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + }; + + HttpGet request = new HttpGet(this.hostname + API_RECORDINGS + "/" + recordingId); + + try { + return this.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw ioExceptionToOpenViduHttpException(e); } } @@ -445,25 +448,31 @@ public class OpenVidu { */ public List listRecordings() throws OpenViduJavaClientException, OpenViduHttpException { - try { - HttpRequest request = addHeaders(HttpRequest.newBuilder().GET().uri(new URI(this.hostname + API_RECORDINGS)) - .timeout(Duration.ofMillis(requestTimeout))).build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - List recordings = new ArrayList<>(); - JsonObject json = Utils.httpResponseToJson(response); - JsonArray array = json.get("items").getAsJsonArray(); - array.forEach(item -> { - recordings.add(new Recording(item.getAsJsonObject())); - }); - return recordings; - } else { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler> responseHandler = new HttpClientResponseHandler>() { + @Override + public List handleResponse(final ClassicHttpResponse response) + throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + List recordings = new ArrayList<>(); + JsonObject json = httpResponseEntityToJson(response.getEntity()); + JsonArray array = json.get("items").getAsJsonArray(); + array.forEach(item -> { + recordings.add(new Recording(item.getAsJsonObject())); + }); + return recordings; + } else { + throw openViduHttpException(status); + } } - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + }; + + HttpGet request = new HttpGet(this.hostname + API_RECORDINGS); + + try { + return this.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw ioExceptionToOpenViduHttpException(e); } } @@ -485,19 +494,23 @@ public class OpenVidu { */ public void deleteRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException { - try { - HttpRequest request = addHeaders( - HttpRequest.newBuilder().DELETE().uri(new URI(this.hostname + API_RECORDINGS + "/" + recordingId)) - .timeout(Duration.ofMillis(requestTimeout))) - .build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() != HttpURLConnection.HTTP_NO_CONTENT) { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status != HttpStatus.SC_NO_CONTENT) { + throw openViduHttpException(status); + } + return null; } - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + }; + + HttpDelete request = new HttpDelete(this.hostname + API_RECORDINGS + "/" + recordingId); + + try { + this.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw ioExceptionToOpenViduHttpException(e); } } @@ -566,82 +579,125 @@ public class OpenVidu { */ public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException { - try { - HttpRequest request = addHeaders(HttpRequest.newBuilder().GET() - .uri(new URI(this.hostname + API_SESSIONS + "?pendingConnections=true")) - .timeout(Duration.ofMillis(requestTimeout))).build(); + final OpenVidu thisOV = this; + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Boolean handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + JsonObject jsonSessions = httpResponseEntityToJson(response.getEntity()); + JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray(); - if (response.statusCode() == HttpURLConnection.HTTP_OK) { + // Boolean to store if any Session has changed + final boolean[] hasChanged = { false }; - JsonObject jsonSessions = Utils.httpResponseToJson(response); - JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray(); + // 1. Set to store fetched sessionIds and later remove closed ones + Set fetchedSessionIds = new HashSet<>(); + jsonArraySessions.forEach(sessionJsonElement -> { - // Boolean to store if any Session has changed - final boolean[] hasChanged = { false }; + JsonObject sessionJson = sessionJsonElement.getAsJsonObject(); + final Session sessionObj = new Session(thisOV, sessionJson); + String id = sessionObj.getSessionId(); + fetchedSessionIds.add(id); - // 1. Set to store fetched sessionIds and later remove closed ones - Set fetchedSessionIds = new HashSet<>(); - jsonArraySessions.forEach(sessionJsonElement -> { + // 2. Update existing Session + activeSessions.computeIfPresent(id, (sId, s) -> { + String beforeJSON = s.toJson(); + s = s.resetWithJson(sessionJson); + String afterJSON = s.toJson(); + boolean changed = !beforeJSON.equals(afterJSON); + hasChanged[0] = hasChanged[0] || changed; + log.info("Available session '{}' info fetched. Any change: {}", id, changed); + return s; + }); - JsonObject sessionJson = sessionJsonElement.getAsJsonObject(); - final Session sessionObj = new Session(this, sessionJson); - String id = sessionObj.getSessionId(); - fetchedSessionIds.add(id); - - // 2. Update existing Session - this.activeSessions.computeIfPresent(id, (sId, s) -> { - String beforeJSON = s.toJson(); - s = s.resetWithJson(sessionJson); - String afterJSON = s.toJson(); - boolean changed = !beforeJSON.equals(afterJSON); - hasChanged[0] = hasChanged[0] || changed; - log.info("Available session '{}' info fetched. Any change: {}", id, changed); - return s; + // 3. Add new Session + activeSessions.computeIfAbsent(id, sId -> { + log.info("New session '{}' fetched", id); + hasChanged[0] = true; + return sessionObj; + }); }); - // 3. Add new Session - this.activeSessions.computeIfAbsent(id, sId -> { - log.info("New session '{}' fetched", id); - hasChanged[0] = true; - return sessionObj; + // 4. Remove closed sessions from local collection + activeSessions.entrySet().removeIf(entry -> { + if (fetchedSessionIds.contains(entry.getKey())) { + return false; + } else { + log.info("Removing closed session {}", entry.getKey()); + hasChanged[0] = true; + return true; + } }); - }); - // 4. Remove closed sessions from local collection - this.activeSessions.entrySet().removeIf(entry -> { - if (fetchedSessionIds.contains(entry.getKey())) { - return false; - } else { - log.info("Removing closed session {}", entry.getKey()); - hasChanged[0] = true; - return true; - } - }); - - log.info("Active sessions info fetched: {}", this.activeSessions.keySet()); - return hasChanged[0]; - - } else { - throw new OpenViduHttpException(response.statusCode()); + log.info("Active sessions info fetched: {}", activeSessions.keySet()); + return hasChanged[0]; + } else { + throw openViduHttpException(status); + } } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + HttpGet request = new HttpGet(this.hostname + API_SESSIONS + "?pendingConnections=true"); + + try { + return this.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw ioExceptionToOpenViduHttpException(e); } } - protected HttpRequest.Builder addHeaders(HttpRequest.Builder builder) { - // HTTP header names are case insensitive - Map headersLowerCase = new HashMap<>(); - this.headers.forEach((k, v) -> headersLowerCase.put(k.toLowerCase(), v)); - if (!headersLowerCase.containsKey("authorization")) { - // There is no custom Authorization header. Add default Basic Auth for OpenVidu - headersLowerCase.put("authorization", this.defaultBasicAuth); + protected static JsonObject httpResponseEntityToJson(HttpEntity responseEntity) throws IOException { + try { + JsonObject json = new Gson().fromJson(EntityUtils.toString(responseEntity, StandardCharsets.UTF_8), + JsonObject.class); + return json; + } catch (JsonSyntaxException | ParseException | IOException e) { + JsonObject json = new JsonObject(); + json.addProperty("openviduExceptionType", OpenViduJavaClientException.class.getSimpleName()); + json.addProperty("openviduExceptionMessage", e.getMessage()); + throw new IOException(json.toString(), e.getCause()); + } + } + + protected static IOException openViduHttpException(int status) { + JsonObject json = new JsonObject(); + json.addProperty("openviduExceptionType", OpenViduHttpException.class.getSimpleName()); + json.addProperty("openviduExceptionMessage", status); + return new IOException(json.toString()); + } + + protected static IOException openViduException(OpenViduException exception) { + JsonObject json = new JsonObject(); + json.addProperty("openviduExceptionType", exception.getClass().getSimpleName()); + json.addProperty("openviduExceptionMessage", exception.getMessage()); + return new IOException(json.toString()); + } + + protected static OpenViduHttpException ioExceptionToOpenViduHttpException(IOException exception) + throws OpenViduJavaClientException { + JsonObject json; + try { + String message = exception.getMessage(); + json = JsonParser.parseString(message).getAsJsonObject(); + } catch (Exception e) { + throw new OpenViduJavaClientException(exception.getMessage(), exception.getCause()); + } + if (json.has("openviduExceptionType")) { + String openviduExceptionType = json.get("openviduExceptionType").getAsString(); + if (OpenViduJavaClientException.class.getSimpleName().equals(openviduExceptionType)) { + throw new OpenViduJavaClientException(json.get("openviduExceptionMessage").getAsString()); + } else if (OpenViduHttpException.class.getSimpleName().equals(openviduExceptionType)) { + return new OpenViduHttpException(json.get("openviduExceptionMessage").getAsInt()); + } else { + log.error("Unknown OpenVidu Exception: " + openviduExceptionType); + throw new OpenViduJavaClientException(exception.getMessage(), exception.getCause()); + } + } else { + // Unlikely case when an unknown exception has a JSON format message + throw new OpenViduJavaClientException(exception.getMessage(), exception.getCause()); } - headersLowerCase.forEach((k, v) -> builder.setHeader(k, v)); - return builder; } private void testHostname(String hostnameStr) { @@ -652,7 +708,4 @@ public class OpenVidu { } } - private void setDefaultBasicAuth(String secret) { - this.defaultBasicAuth = "Basic " + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + secret).getBytes()); - } -} +} \ No newline at end of file diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java index 8179a0e9..7d53c655 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java @@ -18,12 +18,7 @@ package io.openvidu.java.client; import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; +import java.nio.charset.StandardCharsets; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -31,6 +26,16 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import org.apache.hc.client5.http.classic.methods.HttpDelete; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPatch; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; +import org.apache.hc.core5.http.io.entity.StringEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -113,34 +118,35 @@ public class Session { */ @Deprecated public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException { - if (!this.hasSessionId()) { this.getSessionId(); } - try { - JsonObject json = tokenOptions.toJsonObject(sessionId); - - HttpRequest request = this.openVidu - .addHeaders(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(json.toString())) - .uri(new URI(this.openVidu.hostname + OpenVidu.API_TOKENS)) - .setHeader("Content-Type", "application/json") - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))) - .build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - String token = Utils.httpResponseToJson(response).get("id").getAsString(); - log.info("Returning a TOKEN: {}", token); - return token; - } else { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public String handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + String token = OpenVidu.httpResponseEntityToJson(response.getEntity()).get("id").getAsString(); + log.info("Returning a TOKEN: {}", token); + return token; + } else { + throw OpenVidu.openViduHttpException(status); + } } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + JsonObject json = tokenOptions.toJsonObject(sessionId); + StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8); + + HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_TOKENS); + request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + request.setEntity(params); + + try { + return this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -175,33 +181,36 @@ public class Session { */ public Connection createConnection(ConnectionProperties connectionProperties) throws OpenViduJavaClientException, OpenViduHttpException { - if (!this.hasSessionId()) { this.getSessionId(); } - try { - JsonObject json = connectionProperties.toJson(sessionId); - - HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder() - .POST(HttpRequest.BodyPublishers.ofString(json.toString())) - .uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection")) - .setHeader("Content-Type", "application/json") - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - Connection connection = new Connection(Utils.httpResponseToJson(response)); - this.connections.put(connection.getConnectionId(), connection); - return connection; - } else { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Connection handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + Connection connection = new Connection(OpenVidu.httpResponseEntityToJson(response.getEntity())); + connections.put(connection.getConnectionId(), connection); + return connection; + } else { + throw OpenVidu.openViduHttpException(status); + } } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + JsonObject json = connectionProperties.toJson(sessionId); + StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8); + + HttpPost request = new HttpPost( + this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection"); + request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + request.setEntity(params); + + try { + return this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -214,23 +223,26 @@ public class Session { */ public void close() throws OpenViduJavaClientException, OpenViduHttpException { - try { - HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder().DELETE() - .uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId)) - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) { - this.openVidu.activeSessions.remove(this.sessionId); - log.info("Session {} closed", this.sessionId); - } else { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_NO_CONTENT) { + openVidu.activeSessions.remove(sessionId); + log.info("Session {} closed", sessionId); + } else { + throw OpenVidu.openViduHttpException(status); + } + return null; } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + HttpDelete request = new HttpDelete(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId); + + try { + this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -257,29 +269,31 @@ public class Session { */ public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException { - try { - final String beforeJSON = this.toJson(); + final String beforeJSON = this.toJson(); - HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder().GET() - .uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId - + "?pendingConnections=true")) - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - this.resetWithJson(Utils.httpResponseToJson(response)); - final String afterJSON = this.toJson(); - boolean hasChanged = !beforeJSON.equals(afterJSON); - log.info("Session info fetched for session '{}'. Any change: {}", this.sessionId, hasChanged); - return hasChanged; - } else { - throw new OpenViduHttpException(response.statusCode()); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Boolean handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + resetWithJson(OpenVidu.httpResponseEntityToJson(response.getEntity())); + final String afterJSON = toJson(); + boolean hasChanged = !beforeJSON.equals(afterJSON); + log.info("Session info fetched for session '{}'. Any change: {}", sessionId, hasChanged); + return hasChanged; + } else { + throw OpenVidu.openViduHttpException(status); + } } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + HttpGet request = new HttpGet( + this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "?pendingConnections=true"); + + try { + return this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -329,40 +343,43 @@ public class Session { */ public void forceDisconnect(String connectionId) throws OpenViduJavaClientException, OpenViduHttpException { - try { - - HttpRequest request = this.openVidu.addHeaders(HttpRequest - .newBuilder().DELETE().uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" - + this.sessionId + "/connection/" + connectionId)) - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) { - // Remove connection from activeConnections map - Connection connectionClosed = this.connections.remove(connectionId); - // Remove every Publisher of the closed connection from every subscriber list of - // other connections - if (connectionClosed != null) { - for (Publisher publisher : connectionClosed.getPublishers()) { - String streamId = publisher.getStreamId(); - for (Connection connection : this.connections.values()) { - connection.setSubscribers(connection.getSubscribers().stream() - .filter(subscriber -> !streamId.equals(subscriber)).collect(Collectors.toList())); + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_NO_CONTENT) { + // Remove connection from activeConnections map + Connection connectionClosed = connections.remove(connectionId); + // Remove every Publisher of the closed connection from every subscriber list of + // other connections + if (connectionClosed != null) { + for (Publisher publisher : connectionClosed.getPublishers()) { + String streamId = publisher.getStreamId(); + for (Connection connection : connections.values()) { + connection.setSubscribers(connection.getSubscribers().stream() + .filter(subscriber -> !streamId.equals(subscriber)) + .collect(Collectors.toList())); + } } + } else { + log.warn( + "The closed connection wasn't fetched in OpenVidu Java Client. No changes in the collection of active connections of the Session"); } + log.info("Connection {} closed", connectionId); } else { - log.warn( - "The closed connection wasn't fetched in OpenVidu Java Client. No changes in the collection of active connections of the Session"); + throw OpenVidu.openViduHttpException(status); } - log.info("Connection {} closed", connectionId); - } else { - throw new OpenViduHttpException(response.statusCode()); + return null; } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + HttpDelete request = new HttpDelete( + this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId); + + try { + this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -409,34 +426,34 @@ public class Session { */ public void forceUnpublish(String streamId) throws OpenViduJavaClientException, OpenViduHttpException { - try { - - HttpRequest request = this.openVidu - .addHeaders(HttpRequest.newBuilder().DELETE() - .uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId - + "/stream/" + streamId)) - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))) - .build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) { - for (Connection connection : this.connections.values()) { - // Try to remove the Publisher from the Connection publishers collection - if (connection.publishers.remove(streamId) != null) { - continue; + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_NO_CONTENT) { + for (Connection connection : connections.values()) { + // Try to remove the Publisher from the Connection publishers collection + if (connection.publishers.remove(streamId) != null) { + continue; + } + // Try to remove the Publisher from the Connection subscribers collection + connection.subscribers.remove(streamId); } - // Try to remove the Publisher from the Connection subscribers collection - connection.subscribers.remove(streamId); + log.info("Stream {} unpublished", streamId); + } else { + throw OpenVidu.openViduHttpException(status); } - log.info("Stream {} unpublished", streamId); - } else { - throw new OpenViduHttpException(response.statusCode()); + return null; } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + HttpDelete request = new HttpDelete( + this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/stream/" + streamId); + + try { + this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -481,45 +498,47 @@ public class Session { public Connection updateConnection(String connectionId, ConnectionProperties connectionProperties) throws OpenViduJavaClientException, OpenViduHttpException { + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Connection handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + log.info("Connection {} updated", connectionId); + } else if (status == HttpStatus.SC_NO_CONTENT) { + log.info("Properties of Connection {} remain the same", connectionId); + } else { + throw OpenVidu.openViduHttpException(status); + } + JsonObject json = OpenVidu.httpResponseEntityToJson(response.getEntity()); + + // Update the actual Connection object with the new options + Connection existingConnection = connections.get(connectionId); + + if (existingConnection == null) { + // The updated Connection is not available in local map + Connection newConnection = new Connection(json); + connections.put(connectionId, newConnection); + return newConnection; + } else { + // The updated Connection was available in local map + existingConnection.overrideConnectionProperties(connectionProperties); + return existingConnection; + } + } + }; + + JsonObject json = connectionProperties.toJson(this.sessionId); + StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8); + + HttpPatch request = new HttpPatch( + this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId); + request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + request.setEntity(params); + try { - - JsonObject jsonPayload = connectionProperties.toJson(this.sessionId); - - HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder() - .method("PATCH", HttpRequest.BodyPublishers.ofString(jsonPayload.toString())) - .uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" - + connectionId)) - .setHeader("Content-Type", "application/json") - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build(); - - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - log.info("Connection {} updated", connectionId); - } else if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) { - log.info("Properties of Connection {} remain the same", connectionId); - } else { - throw new OpenViduHttpException(response.statusCode()); - } - JsonObject json = Utils.httpResponseToJson(response); - - // Update the actual Connection object with the new options - Connection existingConnection = this.connections.get(connectionId); - - if (existingConnection == null) { - // The updated Connection is not available in local map - Connection newConnection = new Connection(json); - this.connections.put(connectionId, newConnection); - return newConnection; - } else { - // The updated Connection was available in local map - existingConnection.overrideConnectionProperties(connectionProperties); - return existingConnection; - } - - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + return this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -626,53 +645,59 @@ public class Session { } private void getSessionHttp() throws OpenViduJavaClientException, OpenViduHttpException { - if (this.hasSessionId()) { return; } - try { + final HttpClientResponseHandler responseHandler = new HttpClientResponseHandler() { + @Override + public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException { + final int status = response.getCode(); + if (status == HttpStatus.SC_OK) { + JsonObject responseJson = OpenVidu.httpResponseEntityToJson(response.getEntity()); + sessionId = responseJson.get("id").getAsString(); + createdAt = responseJson.get("createdAt").getAsLong(); - JsonObject json = properties.toJson(); + // Values that get filled by OpenVidu Server from its global or per-session + // configuration + VideoCodec forcedVideoCodec = VideoCodec + .valueOf(responseJson.get("forcedVideoCodec").getAsString()); + Boolean allowTranscoding = responseJson.get("allowTranscoding").getAsBoolean(); - HttpRequest request = this.openVidu - .addHeaders(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(json.toString())) - .uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS)) - .setHeader("Content-Type", "application/json") - .timeout(Duration.ofMillis(this.openVidu.requestTimeout))) - .build(); + SessionProperties responseProperties = new SessionProperties.Builder() + .mediaMode(properties.mediaMode()).recordingMode(properties.recordingMode()) + .defaultRecordingProperties(properties.defaultRecordingProperties()) + .customSessionId(properties.customSessionId()).mediaNode(properties.mediaNode()) + .forcedVideoCodec(forcedVideoCodec).allowTranscoding(allowTranscoding).build(); - HttpResponse response = this.openVidu.httpClient.send(request, - HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == HttpURLConnection.HTTP_OK) { - JsonObject responseJson = Utils.httpResponseToJson(response); - this.sessionId = responseJson.get("id").getAsString(); - this.createdAt = responseJson.get("createdAt").getAsLong(); - - // Values that get filled by OpenVidu Server from its global or per-session - // configuration - VideoCodec forcedVideoCodec = VideoCodec.valueOf(responseJson.get("forcedVideoCodec").getAsString()); - Boolean allowTranscoding = responseJson.get("allowTranscoding").getAsBoolean(); - - SessionProperties responseProperties = new SessionProperties.Builder().mediaMode(properties.mediaMode()) - .recordingMode(properties.recordingMode()) - .defaultRecordingProperties(properties.defaultRecordingProperties()) - .customSessionId(properties.customSessionId()).mediaNode(properties.mediaNode()) - .forcedVideoCodec(forcedVideoCodec).allowTranscoding(allowTranscoding).build(); - - this.properties = responseProperties; - log.info("Session '{}' created", this.sessionId); - } else if (response.statusCode() == HttpURLConnection.HTTP_CONFLICT) { - // 'customSessionId' already existed - this.sessionId = properties.customSessionId(); - this.fetch(); - } else { - throw new OpenViduHttpException(response.statusCode()); + properties = responseProperties; + log.info("Session '{}' created", sessionId); + } else if (status == HttpStatus.SC_CONFLICT) { + // 'customSessionId' already existed + sessionId = properties.customSessionId(); + try { + fetch(); + } catch (OpenViduJavaClientException | OpenViduHttpException e) { + throw OpenVidu.openViduException(e); + } + } else { + throw OpenVidu.openViduHttpException(status); + } + return null; } + }; - } catch (URISyntaxException | IOException | InterruptedException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); + JsonObject json = properties.toJson(); + StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8); + + HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_SESSIONS); + request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + request.setEntity(params); + + try { + this.openVidu.httpClient.execute(request, responseHandler); + } catch (IOException e) { + throw OpenVidu.ioExceptionToOpenViduHttpException(e); } } @@ -758,4 +783,4 @@ public class Session { return json.toString(); } -} +} \ No newline at end of file diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java index f4ddd029..384dc572 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java @@ -1,25 +1,10 @@ package io.openvidu.java.client; -import java.net.http.HttpResponse; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.google.gson.JsonSyntaxException; - /** * @hidden */ public class Utils { - public static JsonObject httpResponseToJson(HttpResponse response) throws OpenViduJavaClientException { - try { - JsonObject json = new Gson().fromJson(response.body(), JsonObject.class); - return json; - } catch (JsonSyntaxException e) { - throw new OpenViduJavaClientException(e.getMessage(), e.getCause()); - } - } - public static boolean isAcceptableRecordingResolution(String stringResolution) { // Matches every string with format "AxB", being A and B any number not starting // with 0 and 3 digits long or 4 digits long if they start with 1 diff --git a/openvidu-java-client/src/test/java/io/openvidu/java/client/test/OpenViduConstructorTest.java b/openvidu-java-client/src/test/java/io/openvidu/java/client/test/OpenViduConstructorTest.java index 3fbe2293..0c87b1b5 100644 --- a/openvidu-java-client/src/test/java/io/openvidu/java/client/test/OpenViduConstructorTest.java +++ b/openvidu-java-client/src/test/java/io/openvidu/java/client/test/OpenViduConstructorTest.java @@ -1,19 +1,28 @@ package io.openvidu.java.client.test; -import java.net.Authenticator; -import java.net.CookieManager; -import java.net.CookiePolicy; -import java.net.InetSocketAddress; -import java.net.PasswordAuthentication; -import java.net.ProxySelector; -import java.net.http.HttpClient; -import java.net.http.HttpClient.Redirect; -import java.time.Duration; -import java.util.Map; -import java.util.concurrent.Executors; +import java.util.List; +import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.message.BasicHeader; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -31,40 +40,57 @@ public class OpenViduConstructorTest { } @Test - public void buildWithHttpClientWithoutAuthenticator() { - HttpClient.Builder builder = HttpClient.newBuilder(); - builder.connectTimeout(Duration.ofMillis(10000)); - ProxySelector proxy = ProxySelector.of(new InetSocketAddress("https://my.proxy.hostname/", 4444)); - builder.proxy(proxy); - builder.followRedirects(Redirect.ALWAYS); + public void buildWithCustomHttpClient() { + + HttpClientBuilder builder = HttpClients.custom(); + + // Custom header + BasicHeader header = new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + builder.setDefaultHeaders(List.of(header)); + + // Custom request timeout + RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5, TimeUnit.SECONDS).build(); + builder.setDefaultRequestConfig(requestConfig); + + // Custom proxy to authenticate + HttpHost proxy = new HttpHost("https://localhost/", 8090); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); + + BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials("username_admin", "secret_password".toCharArray())); + + AuthCache authCache = new BasicAuthCache(); + BasicScheme basicAuth = new BasicScheme(); + authCache.put(proxy, basicAuth); + HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credentialsProvider); + context.setAuthCache(authCache); + + builder.setRoutePlanner(routePlanner); + + // Custom SSLContext SSLContext sslContext = null; try { sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); } catch (Exception e) { } - builder.sslContext(sslContext); - builder.executor(Executors.newFixedThreadPool(1)); - builder.cookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER)); - OpenVidu OV = new OpenVidu("https://localhost:4443/", "MY_SECRET", builder.build()); - Assertions.assertEquals(30000, OV.getRequestTimeout()); - Assertions.assertTrue(OV.getRequestHeaders().isEmpty()); - OV.setRequestTimeout(5000); - OV.setRequestHeaders(Map.of("header1", "value1", "header2", "value2")); - Assertions.assertEquals(5000, OV.getRequestTimeout()); - Assertions.assertEquals(2, OV.getRequestHeaders().size()); - } + final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() + .setSslContext(sslContext).build(); + final HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslSocketFactory).build(); + builder.setConnectionManager(connectionManager); - @Test - public void buildWithHttpClientWithAuthenticator() { - Authenticator authenticator = new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("OPENVIDUAPP", "secret".toCharArray()); - } - }; - HttpClient.Builder builder = HttpClient.newBuilder().authenticator(authenticator); - new OpenVidu("https://localhost:4443/", "MY_SECRET", builder.build()); + // Custom CredentialsProvider + final BasicCredentialsProvider customCredentialsProvider = new BasicCredentialsProvider(); + customCredentialsProvider.setCredentials(new AuthScope(null, -1), + new UsernamePasswordCredentials("OPENVIDUAPP", "MY_SECRET".toCharArray())); + builder.setDefaultCredentialsProvider(customCredentialsProvider); + + new OpenVidu("https://localhost", "MY_SECRET"); + new OpenVidu("https://localhost", "MY_SECRET", builder); + new OpenVidu("https://localhost", builder); } } diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java index ebd3baf5..8a6024f9 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java @@ -20,13 +20,11 @@ package io.openvidu.test.e2e; import static org.junit.jupiter.api.Assertions.fail; import java.io.File; -import java.net.Authenticator; import java.net.HttpURLConnection; -import java.net.PasswordAuthentication; -import java.net.Socket; -import java.net.http.HttpClient; import java.security.KeyManagementException; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Base64; @@ -43,11 +41,22 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedTrustManager; import org.apache.commons.lang3.RandomStringUtils; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.message.BasicHeader; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.TrustStrategy; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; @@ -2440,127 +2449,167 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { gracefullyLeaveParticipants(user, 2); } + private HttpClientBuilder getHttpClientBuilder() { + HttpClientBuilder builder = HttpClients.custom(); + TrustStrategy trustStrategy = new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }; + SSLContext sslContext; + try { + sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + throw new RuntimeException(e); + } + final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() + .setSslContext(sslContext).build(); + final HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslSocketFactory).build(); + builder.setConnectionManager(connectionManager); + return builder; + } + @Test @DisplayName("openvidu-java-client custom HttpClient test") void openViduJavaClientCustomHttpClientTest() throws Exception { + log.info("openvidu-java-client custom HttpClient test"); + // Test all possible combinations: custom Authenticator present and valid, // present and wrong and no present; in combination with custom Authorization // header present and valid, present and wrong and no present - HttpClient.Builder builder = HttpClient.newBuilder(); - SSLContext sslContext; - try { - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { new X509ExtendedTrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type) { - } - - public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type) { - } - - public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final Socket a_socket) { - } - - public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final Socket a_socket) { - } - - public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final SSLEngine a_engine) { - } - - public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type, - final SSLEngine a_engine) { - } - } }, null); - } catch (KeyManagementException | NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - builder.sslContext(sslContext); - - final String BASIC_AUTH = "Basic " - + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + OPENVIDU_SECRET).getBytes()); final String WRONG_SECRET = "WRONG_SECRET_" + RandomStringUtils.randomAlphanumeric(10); - // 1. No authenticator, no header, 200 - OpenVidu customHttpClientOV1 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build()); - customHttpClientOV1.fetch(); + final String VALID_BASIC_AUTH = "Basic " + + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + OPENVIDU_SECRET).getBytes()); + final String WRONG_BASIC_AUTH = "Basic " + + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + WRONG_SECRET).getBytes()); - // 2. No authenticator, wrong header, 401 - customHttpClientOV1.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER")); + final Collection
VALID_AUTH_HEADER = List + .of(new BasicHeader(HttpHeaders.AUTHORIZATION, VALID_BASIC_AUTH)); + final Collection
WRONG_AUTH_HEADER = List + .of(new BasicHeader(HttpHeaders.AUTHORIZATION, WRONG_BASIC_AUTH)); + + // 1. No valid certificate with no forgiving SSLContext + OpenVidu[] customOV = { new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, HttpClients.custom()) }; + Assertions.assertThrows(OpenViduJavaClientException.class, () -> { + customOV[0].fetch(); + }); + + // 2. No CredentialsProvider, no Authorization header, no secret, 401 + customOV[0] = new OpenVidu(OPENVIDU_URL, getHttpClientBuilder()); OpenViduHttpException thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> { - customHttpClientOV1.fetch(); + customOV[0].fetch(); }); Assertions.assertEquals(401, thrown.getStatus()); - // 3. No authenticator and valid header, 200 - customHttpClientOV1.setRequestHeaders(Map.of("Authorization", BASIC_AUTH)); - customHttpClientOV1.fetch(); + // 3. No CredentialsProvider, no Authorization header, valid secret, 200 + customOV[0] = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, getHttpClientBuilder()); + customOV[0].fetch(); - // 4. Wrong authenticator and no header, 401 - builder.authenticator(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("OPENVIDUAPP", WRONG_SECRET.toCharArray()); - } + // 4. No CredentialsProvider, no Authorization header, wrong secret, 401 + customOV[0] = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, getHttpClientBuilder()); + thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> { + customOV[0].fetch(); }); - OpenVidu customHttpClientOV2 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build()); - OpenViduJavaClientException thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> { - customHttpClientOV2.fetch(); + Assertions.assertEquals(401, thrown.getStatus()); + + // 5. No CredentialsProvider, wrong Authorization header, no secret, 401 + HttpClientBuilder builder = getHttpClientBuilder(); + builder.setDefaultHeaders(WRONG_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> { + customOV[0].fetch(); }); - Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts")); + Assertions.assertEquals(401, thrown.getStatus()); - // 5. Wrong authenticator and wrong header, 401 - customHttpClientOV2.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER")); - thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> { - customHttpClientOV2.fetch(); + // 6. No CredentialsProvider, wrong Authorization header, valid secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultHeaders(WRONG_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder); + customOV[0].fetch(); + + // 7. No CredentialsProvider, wrong Authorization header, wrong secret, 401 + builder = getHttpClientBuilder(); + builder.setDefaultHeaders(WRONG_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, builder); + thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> { + customOV[0].fetch(); }); - Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts")); + Assertions.assertEquals(401, thrown.getStatus()); - // 6. Wrong authenticator and valid header, 401 - customHttpClientOV2.setRequestHeaders(Map.of("Authorization", BASIC_AUTH)); - thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> { - customHttpClientOV2.fetch(); + // 8. No CredentialsProvider, valid Authorization header, no secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultHeaders(VALID_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + customOV[0].fetch(); + + // 9. No CredentialsProvider, valid Authorization header, valid secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultHeaders(VALID_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder); + customOV[0].fetch(); + + // 10. No CredentialsProvider, valid Authorization header, wrong secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultHeaders(VALID_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, builder); + customOV[0].fetch(); + + // 11. Valid CredentialsProvider, no Authorization header, no secret, 200 + final BasicCredentialsProvider validCredentialsProvider = new BasicCredentialsProvider(); + validCredentialsProvider.setCredentials(new AuthScope(null, -1), + new UsernamePasswordCredentials("OPENVIDUAPP", OPENVIDU_SECRET.toCharArray())); + builder = getHttpClientBuilder(); + builder.setDefaultCredentialsProvider(validCredentialsProvider); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + customOV[0].fetch(); + + // 12. Valid CredentialsProvider, valid Authorization header, no secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultCredentialsProvider(validCredentialsProvider); + builder.setDefaultHeaders(VALID_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + customOV[0].fetch(); + + // 13. Valid CredentialsProvider, wrong Authorization header, no secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultCredentialsProvider(validCredentialsProvider); + builder.setDefaultHeaders(WRONG_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + customOV[0].fetch(); + + // 14. Wrong CredentialsProvider, no Authorization header, no secret, 401 + final BasicCredentialsProvider wrongCredentialsProvider = new BasicCredentialsProvider(); + validCredentialsProvider.setCredentials(new AuthScope(null, -1), + new UsernamePasswordCredentials("OPENVIDUAPP", WRONG_SECRET.toCharArray())); + builder = getHttpClientBuilder(); + builder.setDefaultCredentialsProvider(wrongCredentialsProvider); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> { + customOV[0].fetch(); }); - Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts")); + Assertions.assertEquals(401, thrown.getStatus()); - // 7. Valid authenticator and no header, 200 - builder.authenticator(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("OPENVIDUAPP", OPENVIDU_SECRET.toCharArray()); - } + // 15. Wrong CredentialsProvider, valid Authorization header, no secret, 200 + builder = getHttpClientBuilder(); + builder.setDefaultCredentialsProvider(wrongCredentialsProvider); + builder.setDefaultHeaders(VALID_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + customOV[0].fetch(); + + // 16. Wrong CredentialsProvider, wrong Authorization header, no secret + builder = getHttpClientBuilder(); + builder.setDefaultCredentialsProvider(wrongCredentialsProvider); + builder.setDefaultHeaders(WRONG_AUTH_HEADER); + customOV[0] = new OpenVidu(OPENVIDU_URL, builder); + thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> { + customOV[0].fetch(); }); - OpenVidu customHttpClientOV3 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build()); - customHttpClientOV3.fetch(); - - // 8. Valid authenticator and wrong header, 200 - customHttpClientOV3.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER")); - customHttpClientOV3.fetch(); - - // 9. Valid authenticator and valid header, 200 - customHttpClientOV3.setRequestHeaders(Map.of("Authorization", BASIC_AUTH)); - customHttpClientOV3.fetch(); - - // 10. Wrong secret, valid authenticator, no header, 200 - OpenVidu customHttpClientOV4 = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, builder.build()); - customHttpClientOV4.fetch(); - - // 11. Wrong secret, valid authenticator, wrong header, 200 - customHttpClientOV4.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER")); - customHttpClientOV4.fetch(); - - // 12. Wrong secret, no authenticator, valid header, 200 - builder = HttpClient.newBuilder().sslContext(sslContext); - customHttpClientOV4 = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, builder.build()); - customHttpClientOV4.setRequestHeaders(Map.of("Authorization", BASIC_AUTH)); - customHttpClientOV4.fetch(); + Assertions.assertEquals(401, thrown.getStatus()); } @Test