diff --git a/openvidu-java-client/pom.xml b/openvidu-java-client/pom.xml
index 271679d4..3d6d759b 100644
--- a/openvidu-java-client/pom.xml
+++ b/openvidu-java-client/pom.xml
@@ -63,11 +63,6 @@
-
- org.apache.httpcomponents
- httpclient
- 4.5.13
-
com.google.code.gson
gson
@@ -106,6 +101,7 @@
${version.javadoc.plugin}
public
+ io.openvidu.java.client.utils
@@ -142,6 +138,7 @@
public
${java.home}/bin/javadoc
+ io.openvidu.java.client.utils
diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java
index c044a336..3235e7a4 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java
@@ -17,19 +17,23 @@
package io.openvidu.java.client;
-import com.google.gson.JsonObject;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.validator.routines.DomainValidator;
-import org.apache.commons.validator.routines.InetAddressValidator;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.validator.routines.DomainValidator;
+import org.apache.commons.validator.routines.InetAddressValidator;
+
+import com.google.gson.JsonObject;
/**
* See
@@ -37,331 +41,352 @@ import java.util.*;
*/
public class IceServerProperties {
- private String url;
- private String username;
- private String credential;
+ private String url;
+ private String username;
+ private String credential;
- /**
- * Returns the defined ICE Server url for this {@link IceServerProperties} object.
- */
- public String getUrl() {
- return url;
- }
+ /**
+ * Returns the defined ICE Server url for this {@link IceServerProperties}
+ * object.
+ */
+ public String getUrl() {
+ return url;
+ }
- /**
- * Returns the Username to be used for TURN connections at the defined {@link IceServerProperties#getUrl()}
- * and {@link IceServerProperties#getCredential()} for this {@link IceServerProperties} object.
- */
- public String getUsername() {
- return username;
- }
+ /**
+ * Returns the Username to be used for TURN connections at the defined
+ * {@link IceServerProperties#getUrl()} and
+ * {@link IceServerProperties#getCredential()} for this
+ * {@link IceServerProperties} object.
+ */
+ public String getUsername() {
+ return username;
+ }
- /**
- * Returns the credential to be used for TURN connections at the defined {@link IceServerProperties#getUrl()}
- * and {@link IceServerProperties#getUsername()} for this {@link IceServerProperties} object.
- */
- public String getCredential() {
- return credential;
- }
+ /**
+ * Returns the credential to be used for TURN connections at the defined
+ * {@link IceServerProperties#getUrl()} and
+ * {@link IceServerProperties#getUsername()} for this
+ * {@link IceServerProperties} object.
+ */
+ public String getCredential() {
+ return credential;
+ }
- private IceServerProperties(String url, String username, String credential) {
- this.url = url;
- this.username = username;
- this.credential = credential;
- }
+ private IceServerProperties(String url, String username, String credential) {
+ this.url = url;
+ this.username = username;
+ this.credential = credential;
+ }
- /**
- * @hidden
- */
- public JsonObject toJson() {
- JsonObject json = new JsonObject();
- json.addProperty("url", getUrl());
- if (getUsername() != null && !getUsername().isEmpty()) {
- json.addProperty("username", getUsername());
- }
- if (getCredential() != null && !getCredential().isEmpty()) {
- json.addProperty("credential", getCredential());
- }
- return json;
- }
+ /**
+ * @hidden
+ */
+ public JsonObject toJson() {
+ JsonObject json = new JsonObject();
+ json.addProperty("url", getUrl());
+ if (getUsername() != null && !getUsername().isEmpty()) {
+ json.addProperty("username", getUsername());
+ }
+ if (getCredential() != null && !getCredential().isEmpty()) {
+ json.addProperty("credential", getCredential());
+ }
+ return json;
+ }
- /**
- * Builder for {@link IceServerProperties}
- */
- public static class Builder {
+ /**
+ * Builder for {@link IceServerProperties}
+ */
+ public static class Builder {
- private String url;
- private String username;
- private String credential;
- private String staticAuthSecret;
- private boolean ignoreEmptyUrl = false;
+ private String url;
+ private String username;
+ private String credential;
+ private String staticAuthSecret;
+ private boolean ignoreEmptyUrl = false;
- /**
- * Set the url for the ICE Server you want to use.
- * It should follow a valid format:
- *
- */
- public IceServerProperties.Builder url(String url) {
- this.url = url;
- return this;
- }
+ /**
+ * Set the url for the ICE Server you want to use. It should follow a valid
+ * format:
+ *
+ */
+ public IceServerProperties.Builder url(String url) {
+ this.url = url;
+ return this;
+ }
- /**
- * Set a username for the ICE Server you want to use.
- * This parameter should be defined only for TURN, not for STUN ICE Servers.
- */
- public IceServerProperties.Builder username(String userName) {
- this.username = userName;
- return this;
- }
+ /**
+ * Set a username for the ICE Server you want to use. This parameter should be
+ * defined only for TURN, not for STUN ICE Servers.
+ */
+ public IceServerProperties.Builder username(String userName) {
+ this.username = userName;
+ return this;
+ }
- /**
- * Set a credential for the ICE Server you want to use.
- * This parameter should be defined only for TURN, not for STUN ICE Servers.
- */
- public IceServerProperties.Builder credential(String credential) {
- this.credential = credential;
- return this;
- }
+ /**
+ * Set a credential for the ICE Server you want to use. This parameter should be
+ * defined only for TURN, not for STUN ICE Servers.
+ */
+ public IceServerProperties.Builder credential(String credential) {
+ this.credential = credential;
+ return this;
+ }
- /**
- * Secret for TURN authentication based on:
- *
- * This will generate credentials valid for 24 hours which is the recommended value. You need to setup in your TURN service this same secret value
- * which uses HMAC SHA1 as encryption algorithm. A TURN implementation which by default uses this is COTURN with static-auth-secret parameter.
- */
- public IceServerProperties.Builder staticAuthSecret(String staticAuthSecret) {
- this.staticAuthSecret = staticAuthSecret;
- return this;
- }
+ /**
+ * Secret for TURN authentication based on:
+ *
+ * This will generate credentials valid for 24 hours which is the recommended
+ * value. You need to setup in your TURN service this same secret value which
+ * uses HMAC SHA1 as encryption algorithm. A TURN implementation which by
+ * default uses this is COTURN with static-auth-secret parameter.
+ */
+ public IceServerProperties.Builder staticAuthSecret(String staticAuthSecret) {
+ this.staticAuthSecret = staticAuthSecret;
+ return this;
+ }
- public IceServerProperties.Builder ignoreEmptyUrl(boolean ignore) {
- this.ignoreEmptyUrl = true;
- return this;
- }
+ public IceServerProperties.Builder ignoreEmptyUrl(boolean ignore) {
+ this.ignoreEmptyUrl = true;
+ return this;
+ }
- public IceServerProperties.Builder clone() {
- return new Builder().url(this.url)
- .username(this.username)
- .credential(this.credential)
- .staticAuthSecret(this.staticAuthSecret);
- }
+ public IceServerProperties.Builder clone() {
+ return new Builder().url(this.url).username(this.username).credential(this.credential)
+ .staticAuthSecret(this.staticAuthSecret);
+ }
- /**
- * Builder for {@link io.openvidu.java.client.RecordingProperties}
- * @throws IllegalArgumentException if the defined properties does not follows
- * common STUN/TURN RFCs:
- *
- */
- public IceServerProperties build() throws IllegalArgumentException {
- if (this.ignoreEmptyUrl) {
- if (this.staticAuthSecret != null && this.username == null && this.credential == null) {
- try {
- this.generateTURNCredentials();
- return new IceServerProperties(this.url, this.username, this.credential);
- } catch (NoSuchAlgorithmException | InvalidKeyException e) {
- throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
- }
- } else {
- throw new IllegalArgumentException("ignoreEmptyUrl=true can only be used with staticAuthSecret defined");
- }
- }
- if (this.url == null) {
- throw new IllegalArgumentException("External turn url cannot be null");
- }
- this.checkValidStunTurn(this.url);
- if (this.url.startsWith("turn")) {
- if (this.staticAuthSecret != null) {
- if (this.username != null || this.credential != null) {
- throw new IllegalArgumentException("You can't define username or credential if staticAuthSecret is defined");
- }
- try {
- this.generateTURNCredentials();
- } catch (NoSuchAlgorithmException | InvalidKeyException e) {
- throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
- }
- }
- if ((this.username == null || this.credential == null)) {
- throw new IllegalArgumentException("Credentials must be defined while using turn");
- }
- } else if (this.url.startsWith("stun")) {
- if (this.username != null || this.credential != null) {
- // Credentials can not be defined using stun
- throw new IllegalArgumentException("Credentials can not be defined while using stun.");
- }
- }
- return new IceServerProperties(this.url, this.username, this.credential);
- }
+ /**
+ * Builder for {@link io.openvidu.java.client.RecordingProperties}
+ *
+ * @throws IllegalArgumentException if the defined properties does not follows
+ * common STUN/TURN RFCs:
+ *
+ */
+ public IceServerProperties build() throws IllegalArgumentException {
+ if (this.ignoreEmptyUrl) {
+ if (this.staticAuthSecret != null && this.username == null && this.credential == null) {
+ try {
+ this.generateTURNCredentials();
+ return new IceServerProperties(this.url, this.username, this.credential);
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "ignoreEmptyUrl=true can only be used with staticAuthSecret defined");
+ }
+ }
+ if (this.url == null) {
+ throw new IllegalArgumentException("External turn url cannot be null");
+ }
+ this.checkValidStunTurn(this.url);
+ if (this.url.startsWith("turn")) {
+ if (this.staticAuthSecret != null) {
+ if (this.username != null || this.credential != null) {
+ throw new IllegalArgumentException(
+ "You can't define username or credential if staticAuthSecret is defined");
+ }
+ try {
+ this.generateTURNCredentials();
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
+ }
+ }
+ if ((this.username == null || this.credential == null)) {
+ throw new IllegalArgumentException("Credentials must be defined while using turn");
+ }
+ } else if (this.url.startsWith("stun")) {
+ if (this.username != null || this.credential != null) {
+ // Credentials can not be defined using stun
+ throw new IllegalArgumentException("Credentials can not be defined while using stun.");
+ }
+ }
+ return new IceServerProperties(this.url, this.username, this.credential);
+ }
- private void checkValidStunTurn(String uri) throws IllegalArgumentException {
- final String TCP_TRANSPORT_SUFFIX = "?transport=tcp";
- final String UDP_TRANSPORT_SUFFIX = "?transport=udp";
+ private void checkValidStunTurn(String uri) throws IllegalArgumentException {
+ final String TCP_TRANSPORT_SUFFIX = "?transport=tcp";
+ final String UDP_TRANSPORT_SUFFIX = "?transport=udp";
- // Protocols which accepts transport=tcp and transport=udp
- final Set TURN_PROTOCOLS = new HashSet<>(Arrays.asList(
- "turn",
- "turns"
- ));
- final Set STUN_PROTOCOLS = new HashSet<>(Arrays.asList(
- "stun",
- "stuns"
- ));
+ // Protocols which accepts transport=tcp and transport=udp
+ final Set TURN_PROTOCOLS = new HashSet<>(Arrays.asList("turn", "turns"));
+ final Set STUN_PROTOCOLS = new HashSet<>(Arrays.asList("stun", "stuns"));
- // Fails if no colons
- int firstColonPos = uri.indexOf(':');
- if (firstColonPos == -1) {
- throw new IllegalArgumentException("Not a valid TURN/STUN uri provided. " +
- "No colons found in: '" + uri + "'");
- }
+ // Fails if no colons
+ int firstColonPos = uri.indexOf(':');
+ if (firstColonPos == -1) {
+ throw new IllegalArgumentException(
+ "Not a valid TURN/STUN uri provided. " + "No colons found in: '" + uri + "'");
+ }
- // Get protocol and check
- String protocol = uri.substring(0, firstColonPos);
- if (!TURN_PROTOCOLS.contains(protocol) && !STUN_PROTOCOLS.contains(protocol)) {
- throw new IllegalArgumentException("The protocol '" + protocol + "' is invalid. Only valid values are: "
- + TURN_PROTOCOLS + " " + STUN_PROTOCOLS);
- }
+ // Get protocol and check
+ String protocol = uri.substring(0, firstColonPos);
+ if (!TURN_PROTOCOLS.contains(protocol) && !STUN_PROTOCOLS.contains(protocol)) {
+ throw new IllegalArgumentException("The protocol '" + protocol + "' is invalid. Only valid values are: "
+ + TURN_PROTOCOLS + " " + STUN_PROTOCOLS);
+ }
- // Check if query param with transport exist
- int qmarkPos = uri.indexOf('?');
- String hostAndPort = uri.substring(firstColonPos + 1);
- if (qmarkPos != -1) {
- if (TURN_PROTOCOLS.contains(protocol)) {
- // Only Turn uses transport arg
- String rawTransportType = uri.substring(qmarkPos);
- hostAndPort = uri.substring(firstColonPos + 1, qmarkPos);
- if (!TCP_TRANSPORT_SUFFIX.equals(rawTransportType) && !UDP_TRANSPORT_SUFFIX.equals(rawTransportType)) {
- // If other argument rather than transport is specified, it is a wrong query for a STUN/TURN uri
- throw new IllegalArgumentException("Wrong value specified in STUN/TURN uri: '"
- + uri + "'. " + "Unique valid arguments after '?' are '"
- + TCP_TRANSPORT_SUFFIX + "' or '" + UDP_TRANSPORT_SUFFIX);
- }
- } else {
- throw new IllegalArgumentException("STUN uri can't have any '?' query param");
- }
- }
+ // Check if query param with transport exist
+ int qmarkPos = uri.indexOf('?');
+ String hostAndPort = uri.substring(firstColonPos + 1);
+ if (qmarkPos != -1) {
+ if (TURN_PROTOCOLS.contains(protocol)) {
+ // Only Turn uses transport arg
+ String rawTransportType = uri.substring(qmarkPos);
+ hostAndPort = uri.substring(firstColonPos + 1, qmarkPos);
+ if (!TCP_TRANSPORT_SUFFIX.equals(rawTransportType)
+ && !UDP_TRANSPORT_SUFFIX.equals(rawTransportType)) {
+ // If other argument rather than transport is specified, it is a wrong query for
+ // a STUN/TURN uri
+ throw new IllegalArgumentException("Wrong value specified in STUN/TURN uri: '" + uri + "'. "
+ + "Unique valid arguments after '?' are '" + TCP_TRANSPORT_SUFFIX + "' or '"
+ + UDP_TRANSPORT_SUFFIX);
+ }
+ } else {
+ throw new IllegalArgumentException("STUN uri can't have any '?' query param");
+ }
+ }
- // Check if port is defined
- int portColon = hostAndPort.indexOf(':');
- // IPv6 are defined between brackets
- int startIpv6Index = hostAndPort.indexOf('[');
- int endIpv6Index = hostAndPort.indexOf(']');
- if (startIpv6Index == -1 ^ endIpv6Index == -1) {
- throw new IllegalArgumentException("Not closed bracket '[' or ']' in uri: " + uri);
- }
+ // Check if port is defined
+ int portColon = hostAndPort.indexOf(':');
+ // IPv6 are defined between brackets
+ int startIpv6Index = hostAndPort.indexOf('[');
+ int endIpv6Index = hostAndPort.indexOf(']');
+ if (startIpv6Index == -1 ^ endIpv6Index == -1) {
+ throw new IllegalArgumentException("Not closed bracket '[' or ']' in uri: " + uri);
+ }
- if (portColon != -1) {
- if (startIpv6Index == -1 && endIpv6Index == -1) {
- // If Ipv4 and port defined
- String[] splittedHostAndPort = hostAndPort.split(":");
- if (splittedHostAndPort.length != 2) {
- throw new IllegalArgumentException("Host or port are not correctly " +
- "defined in STUN/TURN uri: '" + uri + "'");
- }
- String host = splittedHostAndPort[0];
- String port = splittedHostAndPort[1];
+ if (portColon != -1) {
+ if (startIpv6Index == -1 && endIpv6Index == -1) {
+ // If Ipv4 and port defined
+ String[] splittedHostAndPort = hostAndPort.split(":");
+ if (splittedHostAndPort.length != 2) {
+ throw new IllegalArgumentException(
+ "Host or port are not correctly " + "defined in STUN/TURN uri: '" + uri + "'");
+ }
+ String host = splittedHostAndPort[0];
+ String port = splittedHostAndPort[1];
- // Check if host is defined. Valid Host (Domain or IP) will be done at server side
- checkHostAndPort(uri, host, port);
- } else {
- // If portColon is found and Ipv6
- String ipv6 = hostAndPort.substring(startIpv6Index + 1, endIpv6Index);
- String auxPort = hostAndPort.substring(endIpv6Index + 1);
- if (auxPort.startsWith(":")) {
- if (auxPort.length() == 1) {
- throw new IllegalArgumentException("Host or port are not correctly defined in STUN/TURN uri: " + uri);
- }
- // If port is defined
- // Get port without colon and check host and port
- String host = ipv6;
- String port = auxPort.substring(1);
- checkHostAndPort(uri, host, port);
- } else if (auxPort.length() > 0) {
- // If auxPort = 0, no port is defined
- throw new IllegalArgumentException("Port is not specified correctly after IPv6 in uri: '" + uri + "'");
- }
- }
- } else {
- // If portColon not found, only host is defined
- String host = hostAndPort;
- checkHost(uri, host);
- }
- }
+ // Check if host is defined. Valid Host (Domain or IP) will be done at server
+ // side
+ checkHostAndPort(uri, host, port);
+ } else {
+ // If portColon is found and Ipv6
+ String ipv6 = hostAndPort.substring(startIpv6Index + 1, endIpv6Index);
+ String auxPort = hostAndPort.substring(endIpv6Index + 1);
+ if (auxPort.startsWith(":")) {
+ if (auxPort.length() == 1) {
+ throw new IllegalArgumentException(
+ "Host or port are not correctly defined in STUN/TURN uri: " + uri);
+ }
+ // If port is defined
+ // Get port without colon and check host and port
+ String host = ipv6;
+ String port = auxPort.substring(1);
+ checkHostAndPort(uri, host, port);
+ } else if (auxPort.length() > 0) {
+ // If auxPort = 0, no port is defined
+ throw new IllegalArgumentException(
+ "Port is not specified correctly after IPv6 in uri: '" + uri + "'");
+ }
+ }
+ } else {
+ // If portColon not found, only host is defined
+ String host = hostAndPort;
+ checkHost(uri, host);
+ }
+ }
- private void checkHost(String uri, String host) {
- if (host == null || host.isEmpty()) {
- throw new IllegalArgumentException("Host defined in '" + uri + "' is empty or null");
- }
- if (DomainValidator.getInstance().isValid(host)) {
- return;
- }
- InetAddressValidator ipValidator = InetAddressValidator.getInstance();
- if (ipValidator.isValid(host)) {
- return;
- }
- try {
- Inet6Address.getByName(host).getHostAddress();
- return;
- } catch (UnknownHostException e) {
- throw new IllegalArgumentException("Is not a valid Internet Address (IP or Domain Name): '" + host + "'");
- }
- }
+ private void checkHost(String uri, String host) {
+ if (host == null || host.isEmpty()) {
+ throw new IllegalArgumentException("Host defined in '" + uri + "' is empty or null");
+ }
+ if (DomainValidator.getInstance().isValid(host)) {
+ return;
+ }
+ InetAddressValidator ipValidator = InetAddressValidator.getInstance();
+ if (ipValidator.isValid(host)) {
+ return;
+ }
+ try {
+ Inet6Address.getByName(host).getHostAddress();
+ return;
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException(
+ "Is not a valid Internet Address (IP or Domain Name): '" + host + "'");
+ }
+ }
- private void checkPort(String uri, String port) {
- if (port == null || port.isEmpty()) {
- throw new IllegalArgumentException("Port defined in '" + uri + "' is empty or null");
- }
+ private void checkPort(String uri, String port) {
+ if (port == null || port.isEmpty()) {
+ throw new IllegalArgumentException("Port defined in '" + uri + "' is empty or null");
+ }
- try {
- int parsedPort = Integer.parseInt(port);
- if (parsedPort <= 0 || parsedPort > 65535) {
- throw new IllegalArgumentException("The port defined in '" + uri + "' is not a valid port number (0-65535)");
- }
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("The port defined in '" + uri + "' is not a number (0-65535)");
- }
- }
+ try {
+ int parsedPort = Integer.parseInt(port);
+ if (parsedPort <= 0 || parsedPort > 65535) {
+ throw new IllegalArgumentException(
+ "The port defined in '" + uri + "' is not a valid port number (0-65535)");
+ }
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("The port defined in '" + uri + "' is not a number (0-65535)");
+ }
+ }
- private void checkHostAndPort(String uri, String host, String port) {
- this.checkHost(uri, host);
- this.checkPort(uri, port);
- }
+ private void checkHostAndPort(String uri, String host, String port) {
+ this.checkHost(uri, host);
+ this.checkPort(uri, port);
+ }
+ private void generateTURNCredentials() throws NoSuchAlgorithmException, InvalidKeyException {
+ // 1. Generate random username
+ char[] ALPHANUMERIC = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJK" + "LMNOPQRSTUVWXYZ0123456789").toCharArray();
+ int MAX_LENGTH = 8;
+ StringBuilder randomUsername = new StringBuilder();
+ for (int i = 0; i < MAX_LENGTH; i++) {
+ int index = new SecureRandom().nextInt(ALPHANUMERIC.length);
+ randomUsername.append(ALPHANUMERIC[index]);
+ }
+ // 2. Get unix timestamp adding 24 hours to define max credential valid time
+ String unixTimestamp = Long.toString((System.currentTimeMillis() / 1000) + 24 * 3600);
- private void generateTURNCredentials() throws NoSuchAlgorithmException, InvalidKeyException {
- // 1. Generate random username
- char[] ALPHANUMERIC =("abcdefghijklmnopqrstuvwxyzABCDEFGHIJK" +
- "LMNOPQRSTUVWXYZ0123456789").toCharArray();
- int MAX_LENGTH = 8;
- StringBuilder randomUsername = new StringBuilder();
- for(int i =0; i < MAX_LENGTH; i++) {
- int index = new SecureRandom().nextInt(ALPHANUMERIC.length);
- randomUsername.append(ALPHANUMERIC[index]);
- }
- // 2. Get unix timestamp adding 24 hours to define max credential valid time
- String unixTimestamp = Long.toString((System.currentTimeMillis() / 1000) + 24*3600);
+ // 3. Generate TURN username
+ String username = unixTimestamp + ":" + randomUsername;
- // 3. Generate TURN username
- String username = unixTimestamp + ":" + randomUsername;
+ // 4. Generate HMAC SHA-1 password
+ SecretKeySpec signingKey = new SecretKeySpec(staticAuthSecret.getBytes(), "HmacSHA1");
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(signingKey);
+ String credential = new String(Base64.getEncoder().encode(mac.doFinal(username.getBytes())));
- // 4. Generate HMAC SHA-1 password
- SecretKeySpec signingKey = new SecretKeySpec(staticAuthSecret.getBytes(), "HmacSHA1");
- Mac mac = Mac.getInstance("HmacSHA1");
- mac.init(signingKey);
- String credential = new String(Base64.encodeBase64(mac.doFinal(username.getBytes())));
-
- // Set credentials in builder
- this.username = username;
- this.credential = credential;
- }
- }
+ // Set credentials in builder
+ this.username = username;
+ this.credential = credential;
+ }
+ }
}
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 00e00281..a2d31b50 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,55 +18,49 @@
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.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.http.HttpHeaders;
-import org.apache.http.HttpResponse;
-import org.apache.http.ParseException;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.conn.ssl.NoopHostnameVerifier;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicCredentialsProvider;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.ssl.SSLContextBuilder;
-import org.apache.http.ssl.TrustStrategy;
-import org.apache.http.util.EntityUtils;
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.JsonSyntaxException;
public class OpenVidu {
private static final Logger log = LoggerFactory.getLogger(OpenVidu.class);
- private String secret;
protected String hostname;
protected HttpClient 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";
@@ -75,49 +69,149 @@ 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 instance of OpenVidu Server is up an running.
- * It must be the full URL (e.g.
- * https://12.34.56.78:1234/
)
+ * @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 used on OpenVidu Server initialization
+ * @param secret Secret configured in your OpenVidu deployment
*/
public OpenVidu(String hostname, String secret) {
- this.hostname = hostname;
+ testHostname(hostname);
+ setDefaultBasicAuth(secret);
+ this.hostname = hostname;
if (!this.hostname.endsWith("/")) {
this.hostname += "/";
}
- this.secret = secret;
-
- TrustStrategy trustStrategy = new TrustStrategy() {
- @Override
- public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- return true;
- }
- };
-
- CredentialsProvider provider = new BasicCredentialsProvider();
- UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("OPENVIDUAPP", this.secret);
- provider.setCredentials(AuthScope.ANY, credentials);
-
SSLContext sslContext;
-
try {
- sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build();
- } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
+ 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);
}
- RequestConfig.Builder requestBuilder = RequestConfig.custom();
- requestBuilder = requestBuilder.setConnectTimeout(30000);
- requestBuilder = requestBuilder.setConnectionRequestTimeout(30000);
+ Builder b = HttpClient.newBuilder();
+ b.sslContext(sslContext);
+ b.connectTimeout(Duration.ofSeconds(30));
+ this.httpClient = b.build();
+ }
- this.httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestBuilder.build())
- .setConnectionTimeToLive(30, TimeUnit.SECONDS).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
- .setSSLContext(sslContext).setDefaultCredentialsProvider(provider).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
+ *
+ */
+ public OpenVidu(String hostname, String secret, HttpClient httpClient) {
+
+ 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();
+ }
+
+ /**
+ * 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 requestTimeout Timeout in milliseconds
+ */
+ public void setRequestTimeout(long requestTimeout) {
+ this.requestTimeout = requestTimeout;
+ }
+
+ /**
+ * Returns the current collection of custom headers configured for all requests.
+ */
+ public Map getRequestHeaders() {
+ return this.headers;
+ }
+
+ /**
+ * 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;
}
/**
@@ -183,23 +277,20 @@ public class OpenVidu {
public Recording startRecording(String sessionId, RecordingProperties properties)
throws OpenViduJavaClientException, OpenViduHttpException {
- HttpPost request = new HttpPost(this.hostname + API_RECORDINGS_START);
-
- JsonObject json = properties.toJson();
- json.addProperty("session", sessionId);
-
- StringEntity params = new StringEntity(json.toString(), "UTF-8");
-
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
- request.setEntity(params);
-
- HttpResponse response = null;
try {
- response = this.httpClient.execute(request);
+ JsonObject json = properties.toJson();
+ json.addProperty("session", sessionId);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- Recording r = new Recording(httpResponseToJson(response));
+ 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);
@@ -210,15 +301,11 @@ public class OpenVidu {
}
return r;
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -288,14 +375,16 @@ public class OpenVidu {
* API)
*/
public Recording stopRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
- HttpPost request = new HttpPost(this.hostname + API_RECORDINGS_STOP + "/" + recordingId);
- HttpResponse response = null;
- try {
- response = this.httpClient.execute(request);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- Recording r = new Recording(httpResponseToJson(response));
+ 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);
@@ -306,14 +395,10 @@ public class OpenVidu {
}
return r;
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -331,24 +416,22 @@ public class OpenVidu {
* API)
*/
public Recording getRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
- HttpGet request = new HttpGet(this.hostname + API_RECORDINGS + "/" + recordingId);
- HttpResponse response = null;
+
try {
- response = this.httpClient.execute(request);
+ HttpRequest request = addHeaders(
+ HttpRequest.newBuilder().GET().uri(new URI(this.hostname + API_RECORDINGS + "/" + recordingId))
+ .timeout(Duration.ofMillis(requestTimeout)))
+ .build();
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- return new Recording(httpResponseToJson(response));
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() == HttpURLConnection.HTTP_OK) {
+ return new Recording(Utils.httpResponseToJson(response));
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
-
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -361,30 +444,26 @@ public class OpenVidu {
* @throws OpenViduHttpException
*/
public List listRecordings() throws OpenViduJavaClientException, OpenViduHttpException {
- HttpGet request = new HttpGet(this.hostname + API_RECORDINGS);
- HttpResponse response = null;
- try {
- response = this.httpClient.execute(request);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
+ 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 = httpResponseToJson(response);
+ 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(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
-
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -405,22 +484,20 @@ public class OpenVidu {
* API)
*/
public void deleteRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
- HttpDelete request = new HttpDelete(this.hostname + API_RECORDINGS + "/" + recordingId);
- HttpResponse response = null;
+
try {
- response = this.httpClient.execute(request);
+ HttpRequest request = addHeaders(
+ HttpRequest.newBuilder().DELETE().uri(new URI(this.hostname + API_RECORDINGS + "/" + recordingId))
+ .timeout(Duration.ofMillis(requestTimeout)))
+ .build();
- int statusCode = response.getStatusLine().getStatusCode();
- if (!(statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
- throw new OpenViduHttpException(statusCode);
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
+ throw new OpenViduHttpException(response.statusCode());
}
-
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -488,16 +565,17 @@ public class OpenVidu {
* @throws OpenViduJavaClientException
*/
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
- HttpGet request = new HttpGet(this.hostname + API_SESSIONS + "?pendingConnections=true");
- HttpResponse response = null;
try {
- response = this.httpClient.execute(request);
+ HttpRequest request = addHeaders(HttpRequest.newBuilder().GET()
+ .uri(new URI(this.hostname + API_SESSIONS + "?pendingConnections=true"))
+ .timeout(Duration.ofMillis(requestTimeout))).build();
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
- JsonObject jsonSessions = httpResponseToJson(response);
+ if (response.statusCode() == HttpURLConnection.HTTP_OK) {
+
+ JsonObject jsonSessions = Utils.httpResponseToJson(response);
JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray();
// Boolean to store if any Session has changed
@@ -546,26 +624,35 @@ public class OpenVidu {
return hasChanged[0];
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
- private JsonObject httpResponseToJson(HttpResponse response) throws OpenViduJavaClientException {
+ 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);
+ }
+ headersLowerCase.forEach((k, v) -> builder.setHeader(k, v));
+ return builder;
+ }
+
+ private void testHostname(String hostnameStr) {
try {
- JsonObject json = new Gson().fromJson(EntityUtils.toString(response.getEntity(), "UTF-8"),
- JsonObject.class);
- return json;
- } catch (JsonSyntaxException | ParseException | IOException e) {
- throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
+ new URL(hostnameStr);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("The hostname \"" + hostnameStr + "\" is not a valid URL: " + e.getMessage());
}
}
+ private void setDefaultBasicAuth(String secret) {
+ this.defaultBasicAuth = "Basic " + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + secret).getBytes());
+ }
}
diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Recording.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Recording.java
index d709b442..c284c832 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Recording.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Recording.java
@@ -238,7 +238,7 @@ public class Recording {
* URL of the recording. You can access the file from there. It is
* null
until recording reaches "ready" or "failed" status. If
*
- * OpenVidu Server configuration property
+ * OpenVidu configuration property
* OPENVIDU_RECORDING_PUBLIC_ACCESS
is false, this path will be
* secured with OpenVidu credentials
*/
diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/RecordingProperties.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/RecordingProperties.java
index 5b46b728..5028b54a 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/RecordingProperties.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/RecordingProperties.java
@@ -22,7 +22,6 @@ import java.util.Map;
import com.google.gson.JsonObject;
import io.openvidu.java.client.Recording.OutputMode;
-import io.openvidu.java.client.utils.FormatChecker;
/**
* See
@@ -559,7 +558,7 @@ public class RecordingProperties {
}
if (nameParam != null && !nameParam.isEmpty()) {
- if (!FormatChecker.isValidRecordingName(nameParam)) {
+ if (!Utils.isValidRecordingName(nameParam)) {
throw new IllegalArgumentException(
"Parameter 'name' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-~]+");
}
@@ -620,7 +619,7 @@ public class RecordingProperties {
}
if (resolutionParam != null) {
- if (!FormatChecker.isAcceptableRecordingResolution(resolutionParam)) {
+ if (!Utils.isAcceptableRecordingResolution(resolutionParam)) {
throw new IllegalStateException(
"Wrong 'resolution' parameter. Acceptable values from 100 to 1999 for both width and height");
}
@@ -630,7 +629,7 @@ public class RecordingProperties {
}
if (frameRateParam != null) {
- if (!FormatChecker.isAcceptableRecordingFrameRate(frameRateParam.intValue())) {
+ if (!Utils.isAcceptableRecordingFrameRate(frameRateParam.intValue())) {
throw new IllegalStateException(
"Wrong 'frameRate' parameter. Acceptable values are within range [1,120]");
}
@@ -640,7 +639,7 @@ public class RecordingProperties {
}
if (shmSizeParam != null) {
- if (!FormatChecker.isAcceptableRecordingShmSize(shmSizeParam)) {
+ if (!Utils.isAcceptableRecordingShmSize(shmSizeParam)) {
throw new IllegalStateException("Wrong 'shmSize' parameter. Must be 134217728 (128 MB) minimum");
}
shmSizeFinal = shmSizeParam;
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 106e7755..8179a0e9 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,6 +18,12 @@
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.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -25,14 +31,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
-import org.apache.http.HttpHeaders;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPatch;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,7 +38,6 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonSyntaxException;
public class Session {
@@ -116,35 +113,34 @@ public class Session {
*/
@Deprecated
public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException {
+
if (!this.hasSessionId()) {
this.getSessionId();
}
- HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_TOKENS);
- StringEntity params = new StringEntity(tokenOptions.toJsonObject(sessionId).toString(), "UTF-8");
-
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
- request.setEntity(params);
-
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
+ JsonObject json = tokenOptions.toJsonObject(sessionId);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- String token = httpResponseToJson(response).get("id").getAsString();
+ 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(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -179,36 +175,33 @@ public class Session {
*/
public Connection createConnection(ConnectionProperties connectionProperties)
throws OpenViduJavaClientException, OpenViduHttpException {
+
if (!this.hasSessionId()) {
this.getSessionId();
}
- HttpPost request = new HttpPost(
- this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection");
- StringEntity params = new StringEntity(connectionProperties.toJson(sessionId).toString(), "UTF-8");
-
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
- request.setEntity(params);
-
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
+ JsonObject json = connectionProperties.toJson(sessionId);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- Connection connection = new Connection(httpResponseToJson(response));
+ 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(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -220,27 +213,24 @@ public class Session {
* @throws OpenViduHttpException
*/
public void close() throws OpenViduJavaClientException, OpenViduHttpException {
- HttpDelete request = new HttpDelete(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId);
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
+ 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();
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
+ 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(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -266,32 +256,30 @@ public class Session {
* @throws OpenViduJavaClientException
*/
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
- final String beforeJSON = this.toJson();
- HttpGet request = new HttpGet(
- this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "?pendingConnections=true");
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
+ final String beforeJSON = this.toJson();
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- this.resetWithJson(httpResponseToJson(response));
+ 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(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -340,16 +328,18 @@ public class Session {
* @throws OpenViduHttpException
*/
public void forceDisconnect(String connectionId) throws OpenViduJavaClientException, OpenViduHttpException {
- HttpDelete request = new HttpDelete(
- this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId);
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
+ 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
@@ -368,15 +358,11 @@ public class Session {
}
log.info("Connection {} closed", connectionId);
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -422,16 +408,20 @@ public class Session {
* @throws OpenViduHttpException
*/
public void forceUnpublish(String streamId) throws OpenViduJavaClientException, OpenViduHttpException {
- HttpDelete request = new HttpDelete(
- this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/stream/" + streamId);
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
+ 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) {
@@ -442,15 +432,11 @@ public class Session {
}
log.info("Stream {} unpublished", streamId);
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -495,26 +481,28 @@ public class Session {
public Connection updateConnection(String connectionId, ConnectionProperties connectionProperties)
throws OpenViduJavaClientException, OpenViduHttpException {
- HttpPatch request = new HttpPatch(
- this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId);
- StringEntity params = new StringEntity(connectionProperties.toJson(this.sessionId).toString(), "UTF-8");
-
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
- request.setEntity(params);
-
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
+ 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 ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
+ } else if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) {
log.info("Properties of Connection {} remain the same", connectionId);
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- JsonObject json = httpResponseToJson(response);
+ JsonObject json = Utils.httpResponseToJson(response);
// Update the actual Connection object with the new options
Connection existingConnection = this.connections.get(connectionId);
@@ -530,12 +518,8 @@ public class Session {
return existingConnection;
}
- } catch (IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
}
}
@@ -642,23 +626,27 @@ public class Session {
}
private void getSessionHttp() throws OpenViduJavaClientException, OpenViduHttpException {
+
if (this.hasSessionId()) {
return;
}
- HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_SESSIONS);
- StringEntity params = new StringEntity(properties.toJson().toString(), "UTF-8");
-
- request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
- request.setEntity(params);
-
- HttpResponse response = null;
try {
- response = this.openVidu.httpClient.execute(request);
- int statusCode = response.getStatusLine().getStatusCode();
- if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
- JsonObject responseJson = httpResponseToJson(response);
+ JsonObject json = properties.toJson();
+
+ 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();
+
+ 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();
@@ -675,31 +663,17 @@ public class Session {
this.properties = responseProperties;
log.info("Session '{}' created", this.sessionId);
- } else if (statusCode == org.apache.http.HttpStatus.SC_CONFLICT) {
+ } else if (response.statusCode() == HttpURLConnection.HTTP_CONFLICT) {
// 'customSessionId' already existed
this.sessionId = properties.customSessionId();
this.fetch();
} else {
- throw new OpenViduHttpException(statusCode);
+ throw new OpenViduHttpException(response.statusCode());
}
- } catch (IOException e) {
- throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
- } finally {
- if (response != null) {
- EntityUtils.consumeQuietly(response.getEntity());
- }
- }
- }
-
- private JsonObject httpResponseToJson(HttpResponse response) throws OpenViduJavaClientException {
- JsonObject json;
- try {
- json = new Gson().fromJson(EntityUtils.toString(response.getEntity(), "UTF-8"), JsonObject.class);
- } catch (JsonSyntaxException | IOException e) {
+ } catch (URISyntaxException | IOException | InterruptedException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
}
- return json;
}
protected void setIsBeingRecorded(boolean recording) {
diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/utils/FormatChecker.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java
similarity index 65%
rename from openvidu-java-client/src/main/java/io/openvidu/java/client/utils/FormatChecker.java
rename to openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java
index 7a417b1b..f4ddd029 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/utils/FormatChecker.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Utils.java
@@ -1,9 +1,24 @@
-package io.openvidu.java.client.utils;
+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 final class FormatChecker {
+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
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
new file mode 100644
index 00000000..3fbe2293
--- /dev/null
+++ b/openvidu-java-client/src/test/java/io/openvidu/java/client/test/OpenViduConstructorTest.java
@@ -0,0 +1,70 @@
+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 javax.net.ssl.SSLContext;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import io.openvidu.java.client.OpenVidu;
+
+public class OpenViduConstructorTest {
+
+ @Test
+ public void wrongHostname() {
+ RuntimeException thrown = Assertions.assertThrows(RuntimeException.class, () -> {
+ new OpenVidu("WRONG_URL", "MY_SECRET");
+ });
+ Assertions.assertEquals("The hostname \"WRONG_URL\" is not a valid URL: no protocol: WRONG_URL",
+ thrown.getMessage());
+ }
+
+ @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);
+ 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());
+ }
+
+ @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());
+ }
+
+}
diff --git a/openvidu-java-client/src/test/java/io/openvidu/java/client/test/FormatCheckerTest.java b/openvidu-java-client/src/test/java/io/openvidu/java/client/test/UtilsFormatCheckerTest.java
similarity index 74%
rename from openvidu-java-client/src/test/java/io/openvidu/java/client/test/FormatCheckerTest.java
rename to openvidu-java-client/src/test/java/io/openvidu/java/client/test/UtilsFormatCheckerTest.java
index ebfd2184..07ecbefc 100644
--- a/openvidu-java-client/src/test/java/io/openvidu/java/client/test/FormatCheckerTest.java
+++ b/openvidu-java-client/src/test/java/io/openvidu/java/client/test/UtilsFormatCheckerTest.java
@@ -6,9 +6,9 @@ import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import io.openvidu.java.client.utils.FormatChecker;
+import io.openvidu.java.client.Utils;
-public class FormatCheckerTest {
+public class UtilsFormatCheckerTest {
@Test
public void testCustomSessionIdFormat() {
@@ -23,9 +23,9 @@ public class FormatCheckerTest {
"session-_", "123_session-1");
for (String id : invalidCustomSessionIds)
- Assertions.assertFalse(FormatChecker.isValidCustomSessionId(id));
+ Assertions.assertFalse(Utils.isValidCustomSessionId(id));
for (String id : validCustomSessionIds)
- Assertions.assertTrue(FormatChecker.isValidCustomSessionId(id));
+ Assertions.assertTrue(Utils.isValidCustomSessionId(id));
}
@Test
@@ -37,9 +37,9 @@ public class FormatCheckerTest {
List validResolutions = Arrays.asList("1920x1080", "1280x720", "100x1999");
for (String resolution : invalidResolutions)
- Assertions.assertFalse(FormatChecker.isAcceptableRecordingResolution(resolution));
+ Assertions.assertFalse(Utils.isAcceptableRecordingResolution(resolution));
for (String resolution : validResolutions)
- Assertions.assertTrue(FormatChecker.isAcceptableRecordingResolution(resolution));
+ Assertions.assertTrue(Utils.isAcceptableRecordingResolution(resolution));
}
@Test
@@ -50,9 +50,9 @@ public class FormatCheckerTest {
List validFramerates = Arrays.asList(1, 2, 30, 60, 119, 120);
for (int framerate : invalidFrameRates)
- Assertions.assertFalse(FormatChecker.isAcceptableRecordingFrameRate(framerate));
+ Assertions.assertFalse(Utils.isAcceptableRecordingFrameRate(framerate));
for (int framerate : validFramerates)
- Assertions.assertTrue(FormatChecker.isAcceptableRecordingFrameRate(framerate));
+ Assertions.assertTrue(Utils.isAcceptableRecordingFrameRate(framerate));
}
}
\ No newline at end of file
diff --git a/openvidu-node-client/src/OpenVidu.ts b/openvidu-node-client/src/OpenVidu.ts
index 36e10e79..7a6aedaa 100644
--- a/openvidu-node-client/src/OpenVidu.ts
+++ b/openvidu-node-client/src/OpenVidu.ts
@@ -87,10 +87,10 @@ export class OpenVidu {
activeSessions: Session[] = [];
/**
- * @param hostname URL where your instance of OpenVidu Server is up an running.
+ * @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 used on OpenVidu Server initialization
+ * @param secret Secret configured in your OpenVidu deployment
*/
constructor(private hostname: string, secret: string) {
this.setHostnameAndPort();
diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java
index bd2684cb..83040a84 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java
@@ -53,7 +53,6 @@ import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.OpenViduRole;
import io.openvidu.java.client.Recording;
import io.openvidu.java.client.SessionProperties;
-import io.openvidu.java.client.utils.FormatChecker;
import io.openvidu.server.cdr.CDREventRecordingStatusChanged;
import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.coturn.CoturnCredentialsService;
@@ -194,7 +193,7 @@ public abstract class SessionManager {
String connectionId);
public abstract void stopRtmpIfNecessary(Session session);
-
+
public void onEcho(String participantPrivateId, Integer requestId) {
sessionEventsHandler.onEcho(participantPrivateId, requestId);
}
@@ -338,7 +337,7 @@ public abstract class SessionManager {
public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
KurentoOptions kurentoOptions, List customIceServers) throws Exception {
- if (!FormatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
+ if (!io.openvidu.java.client.Utils.isServerMetadataFormatCorrect(serverMetadata)) {
log.error("Data invalid format");
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java b/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java
index 807f177c..d31bc27e 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java
@@ -49,7 +49,6 @@ import io.openvidu.client.internal.ProtocolElements;
import io.openvidu.java.client.ConnectionProperties;
import io.openvidu.java.client.ConnectionType;
import io.openvidu.java.client.OpenViduRole;
-import io.openvidu.java.client.utils.FormatChecker;
import io.openvidu.server.config.OpenviduBuildInfo;
import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.core.EndReason;
@@ -304,7 +303,7 @@ public class RpcHandler extends DefaultJsonRpcHandler {
if (tokenObj != null) {
String clientMetadata = getStringParam(request, ProtocolElements.JOINROOM_METADATA_PARAM);
- if (FormatChecker.isServerMetadataFormatCorrect(clientMetadata)) {
+ if (io.openvidu.java.client.Utils.isServerMetadataFormatCorrect(clientMetadata)) {
// While closing a session users can't join
if (session.closingLock.readLock().tryLock()) {
diff --git a/openvidu-test-browsers/pom.xml b/openvidu-test-browsers/pom.xml
index 8631f253..0fe9197d 100644
--- a/openvidu-test-browsers/pom.xml
+++ b/openvidu-test-browsers/pom.xml
@@ -102,6 +102,11 @@
java-client
${version.appium}
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
diff --git a/openvidu-test-e2e/pom.xml b/openvidu-test-e2e/pom.xml
index cee8cb7a..bc0399f0 100644
--- a/openvidu-test-e2e/pom.xml
+++ b/openvidu-test-e2e/pom.xml
@@ -112,6 +112,11 @@
java-string-similarity
${version.stringsimilarity}
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
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 dde2e592..f455b540 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,6 +20,13 @@ package io.openvidu.test.e2e;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.Socket;
+import java.net.http.HttpClient;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
@@ -34,6 +41,12 @@ import java.util.concurrent.TimeoutException;
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.http.HttpStatus;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@@ -2427,6 +2440,129 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
gracefullyLeaveParticipants(user, 2);
}
+ @Test
+ @DisplayName("openvidu-java-client custom HttpClient test")
+ void openViduJavaClientCustomHttpClientTest() throws Exception {
+
+ // 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();
+
+ // 2. No authenticator, wrong header, 401
+ customHttpClientOV1.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER"));
+ OpenViduHttpException thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> {
+ customHttpClientOV1.fetch();
+ });
+ Assertions.assertEquals(401, thrown.getStatus());
+
+ // 3. No authenticator and valid header, 200
+ customHttpClientOV1.setRequestHeaders(Map.of("Authorization", BASIC_AUTH));
+ customHttpClientOV1.fetch();
+
+ // 4. Wrong authenticator and no header, 401
+ builder.authenticator(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication("OPENVIDUAPP", WRONG_SECRET.toCharArray());
+ }
+ });
+ OpenVidu customHttpClientOV2 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build());
+ OpenViduJavaClientException thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> {
+ customHttpClientOV2.fetch();
+ });
+ Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts"));
+
+ // 5. Wrong authenticator and wrong header, 401
+ customHttpClientOV2.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER"));
+ thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> {
+ customHttpClientOV2.fetch();
+ });
+ Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts"));
+
+ // 6. Wrong authenticator and valid header, 401
+ customHttpClientOV2.setRequestHeaders(Map.of("Authorization", BASIC_AUTH));
+ thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> {
+ customHttpClientOV2.fetch();
+ });
+ Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts"));
+
+ // 7. Valid authenticator and no header, 200
+ builder.authenticator(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication("OPENVIDUAPP", OPENVIDU_SECRET.toCharArray());
+ }
+ });
+ 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();
+ }
+
@Test
@DisplayName("openvidu-java-client test")
void openViduJavaClientTest() throws Exception {