mirror of https://github.com/OpenVidu/openvidu.git
openvidu-java-client: refactoring to use Java HttpClient. Allow custom client
parent
836fa84cd1
commit
b78b127447
|
@ -63,11 +63,6 @@
|
|||
</distributionManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
|
@ -106,6 +101,7 @@
|
|||
<version>${version.javadoc.plugin}</version>
|
||||
<configuration>
|
||||
<show>public</show>
|
||||
<excludePackageNames>io.openvidu.java.client.utils</excludePackageNames>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
@ -142,6 +138,7 @@
|
|||
<configuration>
|
||||
<show>public</show>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<excludePackageNames>io.openvidu.java.client.utils</excludePackageNames>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
|
|
|
@ -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:
|
||||
* <ul>
|
||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7065#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7064#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
||||
* </ul>
|
||||
*/
|
||||
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:
|
||||
* <ul>
|
||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7065#section-3.1"
|
||||
* target=
|
||||
* "_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7064#section-3.1"
|
||||
* target=
|
||||
* "_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
||||
* </ul>
|
||||
*/
|
||||
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:
|
||||
* <ul>
|
||||
* <li><a href="https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00" target="_blank">https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00</a></li>
|
||||
* <li><a href="https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf" target="_blank">https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf</a></li>
|
||||
* </ul>
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li><a href="https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00"
|
||||
* target=
|
||||
* "_blank">https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00</a></li>
|
||||
* <li><a href=
|
||||
* "https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf" target=
|
||||
* "_blank">https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf</a></li>
|
||||
* </ul>
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7065#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7064#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
||||
* </ul>
|
||||
*/
|
||||
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:
|
||||
* <ul>
|
||||
* <li><a href=
|
||||
* "https://datatracker.ietf.org/doc/html/rfc7065#section-3.1"
|
||||
* target=
|
||||
* "_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
||||
* <li><a href=
|
||||
* "https://datatracker.ietf.org/doc/html/rfc7064#section-3.1"
|
||||
* target=
|
||||
* "_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
||||
* </ul>
|
||||
*/
|
||||
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<String> TURN_PROTOCOLS = new HashSet<>(Arrays.asList(
|
||||
"turn",
|
||||
"turns"
|
||||
));
|
||||
final Set<String> STUN_PROTOCOLS = new HashSet<>(Arrays.asList(
|
||||
"stun",
|
||||
"stuns"
|
||||
));
|
||||
// Protocols which accepts transport=tcp and transport=udp
|
||||
final Set<String> TURN_PROTOCOLS = new HashSet<>(Arrays.asList("turn", "turns"));
|
||||
final Set<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<String, Session> activeSessions = new ConcurrentHashMap<>();
|
||||
protected long requestTimeout = 30000;
|
||||
protected Map<String, String> 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.
|
||||
* <code>https://12.34.56.78:1234/</code>)
|
||||
* @param hostname URL where your OpenVidu deployment is up an running. It must
|
||||
* be the full URL (e.g. <code>https://12.34.56.78:1234/</code>)
|
||||
*
|
||||
* @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.
|
||||
* <code>https://12.34.56.78:1234/</code>)
|
||||
* @param httpClient Object of class <a target="_blank" href=
|
||||
* "https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html">java.net.http.HttpClient</a>.
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>Adding proxy configuration</li>
|
||||
* <li>Customizing the SSLContext</li>
|
||||
* <li>Modifying the connection timeout</li>
|
||||
* <li>Adding a cookie handler</li>
|
||||
* </ul>
|
||||
*/
|
||||
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 <a target="_blank" href=
|
||||
* "https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpRequest.html#timeout()">HttpRequest.timeout()</a>
|
||||
* 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<String, String> 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<String, String> 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<String> 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</a>)
|
||||
*/
|
||||
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<String> 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</a>)
|
||||
*/
|
||||
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<String> 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<Recording> 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<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||
List<Recording> 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</a>)
|
||||
*/
|
||||
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<String> 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<String> 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<String, String> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ public class Recording {
|
|||
* URL of the recording. You can access the file from there. It is
|
||||
* <code>null</code> until recording reaches "ready" or "failed" status. If
|
||||
* <a href="https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/">
|
||||
* OpenVidu Server configuration </a> property
|
||||
* OpenVidu configuration </a> property
|
||||
* <code>OPENVIDU_RECORDING_PUBLIC_ACCESS</code> is false, this path will be
|
||||
* secured with OpenVidu credentials
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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) {
|
||||
|
|
|
@ -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<String> 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
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String> 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<Integer> 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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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<IceServerProperties> 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");
|
||||
}
|
||||
|
|
|
@ -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<JsonObject> {
|
|||
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()) {
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<artifactId>java-client</artifactId>
|
||||
<version>${version.appium}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.14</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
@ -112,6 +112,11 @@
|
|||
<artifactId>java-string-similarity</artifactId>
|
||||
<version>${version.stringsimilarity}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.14</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue