From 2d59b1ba4228d952f9c6b89d78cdc924bc8880eb Mon Sep 17 00:00:00 2001 From: Hazem Date: Tue, 25 Apr 2023 16:03:35 +0200 Subject: [PATCH 1/2] feat(server): add https support to client --- .../local/AppiumDriverLocalService.java | 20 ++++++++++++++++--- .../service/local/AppiumServiceBuilder.java | 8 +++++++- .../service/local/ServerBuilderTest.java | 6 ++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java b/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java index d2b4d37fc..dd732e51a 100644 --- a/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java +++ b/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java @@ -52,7 +52,9 @@ public final class AppiumDriverLocalService extends DriverService { - private static final String URL_MASK = "http://%s:%d/"; + private static final String URL_MASK = "%s://%s:%d/"; + private static final String HTTP_PROTOCOL = "http"; + private static final String HTTPS_PROTOCOL = "https"; private static final Logger LOG = LoggerFactory.getLogger(AppiumDriverLocalService.class); private static final Pattern LOGGER_CONTEXT_PATTERN = Pattern.compile("^(\\[debug\\] )?\\[(.+?)\\]"); private static final String APPIUM_SERVICE_SLF4J_LOGGER_PREFIX = "appium.service"; @@ -66,10 +68,11 @@ public final class AppiumDriverLocalService extends DriverService { private final ListOutputStream stream = new ListOutputStream().add(System.out); private final URL url; private String basePath; + private boolean isSecureConnection; private CommandLine process = null; - AppiumDriverLocalService(String ipAddress, File nodeJSExec, + AppiumDriverLocalService(String ipAddress, boolean isSecureConnection, File nodeJSExec, int nodeJSPort, Duration startupTimeout, List nodeJSArgs, Map nodeJSEnvironment ) throws IOException { @@ -78,7 +81,9 @@ public final class AppiumDriverLocalService extends DriverService { this.nodeJSArgs = nodeJSArgs; this.nodeJSEnvironment = nodeJSEnvironment; this.startupTimeout = startupTimeout; - this.url = new URL(String.format(URL_MASK, ipAddress, nodeJSPort)); + this.isSecureConnection = isSecureConnection; + String protocol = this.isSecureConnection ? HTTPS_PROTOCOL : HTTP_PROTOCOL; + this.url = new URL(String.format(URL_MASK, protocol, ipAddress, nodeJSPort)); } public static AppiumDriverLocalService buildDefaultService() { @@ -98,6 +103,15 @@ public String getBasePath() { return this.basePath; } + public AppiumDriverLocalService withSecureConnection(boolean secureConnection) { + this.isSecureConnection = secureConnection; + return this; + } + + public boolean isSecureConnection() { + return this.isSecureConnection; + } + @SneakyThrows private static URL addSuffix(URL url, String suffix) { return url.toURI().resolve("." + (suffix.startsWith("/") ? suffix : "/" + suffix)).toURL(); diff --git a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java index 0b795872d..e40fb588d 100644 --- a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java +++ b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java @@ -81,6 +81,7 @@ public final class AppiumServiceBuilder private String ipAddress = BROADCAST_IP_ADDRESS; private Capabilities capabilities; private boolean autoQuoteCapabilitiesOnWindows = false; + private boolean secure = false; private static final Function APPIUM_JS_NOT_EXIST_ERROR = (fullPath) -> String.format( "The main Appium script does not exist at '%s'", fullPath.getAbsolutePath()); private static final Function NODE_JS_NOT_EXIST_ERROR = (fullPath) -> @@ -447,6 +448,11 @@ public AppiumServiceBuilder usingAnyFreePort() { return super.usingAnyFreePort(); } + public AppiumServiceBuilder usingSecureConnection(boolean secure) { + this.secure = secure; + return this; + } + /** * Defines the environment for the launched appium server. * @@ -478,7 +484,7 @@ protected AppiumDriverLocalService createDriverService(File nodeJSExecutable, in Map nodeEnvironment) { String basePath = serverArguments.getOrDefault( GeneralServerFlag.BASEPATH.getArgument(), serverArguments.get("-pa")); - return new AppiumDriverLocalService(ipAddress, nodeJSExecutable, nodeJSPort, startupTimeout, nodeArguments, + return new AppiumDriverLocalService(ipAddress, secure, nodeJSExecutable, nodeJSPort, startupTimeout, nodeArguments, nodeEnvironment).withBasePath(basePath); } } \ No newline at end of file diff --git a/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java b/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java index 5d4fd5715..2c6bd8d55 100644 --- a/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java +++ b/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java @@ -132,6 +132,12 @@ void checkAbilityToStartServiceOnAFreePort() { assertTrue(service.isRunning()); } + @Test + void checkSecureConnectionFlagStartsServerCorrectly() { + service = new AppiumServiceBuilder().usingSecureConnection(true).build(); + assertTrue(service.getUrl().toString().startsWith("https")); + } + @Test void checkAbilityToStartServiceUsingNonLocalhostIP() { service = new AppiumServiceBuilder().withIPAddress(testIP).build(); From db454239004fc3a483127afd28d4b614f3b21e40 Mon Sep 17 00:00:00 2001 From: Hazem Date: Wed, 26 Apr 2023 14:58:23 +0200 Subject: [PATCH 2/2] feat(server): add domainName support to client --- build.gradle | 1 + .../local/AppiumDriverLocalService.java | 5 +- .../service/local/AppiumServiceBuilder.java | 18 ++++- .../service/local/ServerBuilderTest.java | 71 +++++++++++++++++++ 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 88070b21e..c020e4b3a 100644 --- a/build.gradle +++ b/build.gradle @@ -51,6 +51,7 @@ dependencies { } } implementation 'com.google.code.gson:gson:2.10.1' + implementation 'com.google.guava:guava:31.1-jre' implementation 'cglib:cglib:3.3.0' implementation 'commons-validator:commons-validator:1.7' implementation 'org.apache.commons:commons-lang3:3.12.0' diff --git a/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java b/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java index dd732e51a..d2947e17e 100644 --- a/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java +++ b/src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java @@ -72,7 +72,7 @@ public final class AppiumDriverLocalService extends DriverService { private CommandLine process = null; - AppiumDriverLocalService(String ipAddress, boolean isSecureConnection, File nodeJSExec, + AppiumDriverLocalService(String ipAddress, String domainName, boolean isSecureConnection, File nodeJSExec, int nodeJSPort, Duration startupTimeout, List nodeJSArgs, Map nodeJSEnvironment ) throws IOException { @@ -83,7 +83,8 @@ public final class AppiumDriverLocalService extends DriverService { this.startupTimeout = startupTimeout; this.isSecureConnection = isSecureConnection; String protocol = this.isSecureConnection ? HTTPS_PROTOCOL : HTTP_PROTOCOL; - this.url = new URL(String.format(URL_MASK, protocol, ipAddress, nodeJSPort)); + String address = StringUtils.isNoneBlank(domainName) ? domainName : ipAddress; + this.url = new URL(String.format(URL_MASK, protocol, address, nodeJSPort)); } public static AppiumDriverLocalService buildDefaultService() { diff --git a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java index e40fb588d..940d94438 100644 --- a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java +++ b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java @@ -17,6 +17,7 @@ package io.appium.java_client.service.local; import com.google.common.collect.ImmutableList; +import com.google.common.net.InternetDomainName; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import io.appium.java_client.internal.ReflectionHelpers; @@ -82,6 +83,7 @@ public final class AppiumServiceBuilder private Capabilities capabilities; private boolean autoQuoteCapabilitiesOnWindows = false; private boolean secure = false; + private String domainName; private static final Function APPIUM_JS_NOT_EXIST_ERROR = (fullPath) -> String.format( "The main Appium script does not exist at '%s'", fullPath.getAbsolutePath()); private static final Function NODE_JS_NOT_EXIST_ERROR = (fullPath) -> @@ -280,6 +282,11 @@ public AppiumServiceBuilder withIPAddress(String ipAddress) { return this; } + public AppiumServiceBuilder withDomainName(String domainName){ + this.domainName = domainName; + return this; + } + @Nullable private static File loadPathFromEnv(String envVarName) { String fullPath = System.getProperty(envVarName); @@ -401,6 +408,13 @@ protected ImmutableList createArgs() { argList.add(capabilitiesToCmdlineArg()); } + if(domainName != null) { + if(!InternetDomainName.isValid(domainName)){ + throw new IllegalArgumentException( + String.format("The invalid domainName '%s' is defined", domainName)); + } + } + return new ImmutableList.Builder().addAll(argList).build(); } @@ -484,7 +498,7 @@ protected AppiumDriverLocalService createDriverService(File nodeJSExecutable, in Map nodeEnvironment) { String basePath = serverArguments.getOrDefault( GeneralServerFlag.BASEPATH.getArgument(), serverArguments.get("-pa")); - return new AppiumDriverLocalService(ipAddress, secure, nodeJSExecutable, nodeJSPort, startupTimeout, nodeArguments, - nodeEnvironment).withBasePath(basePath); + return new AppiumDriverLocalService(ipAddress, domainName, secure, nodeJSExecutable, nodeJSPort, startupTimeout, + nodeArguments, nodeEnvironment).withBasePath(basePath); } } \ No newline at end of file diff --git a/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java b/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java index 2c6bd8d55..3bbe8ea90 100644 --- a/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java +++ b/src/test/java/io/appium/java_client/service/local/ServerBuilderTest.java @@ -34,6 +34,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -357,4 +358,74 @@ void checkAbilityToValidateBasePathForBlankBasePath() { void checkAbilityToValidateBasePathForNullBasePath() { assertThrows(NullPointerException.class, () -> new AppiumServiceBuilder().withArgument(BASEPATH, null)); } + + @Test + void checkAbilityToValidateInvalidSpecialCharDomainName() { + assertThrows(IllegalArgumentException.class, () -> new AppiumServiceBuilder().usingAnyFreePort() + .withDomainName("*").build()); + } + + @Test + void checkAbilityToValidateInvalidEmptyDomainName() { + assertThrows(IllegalArgumentException.class, () -> new AppiumServiceBuilder().usingAnyFreePort() + .withDomainName("").build()); + } + + @Test + void checkAbilityToValidateInvalidDomainNameWithProtocol() { + assertThrows(IllegalArgumentException.class, () -> new AppiumServiceBuilder().usingAnyFreePort() + .withDomainName("https://one.two.com/").build()); + } + + @Test + void checkAbilityToValidateInvalidDomainNameWithIpAddress() { + assertThrows(IllegalArgumentException.class, () -> new AppiumServiceBuilder().usingAnyFreePort() + .withDomainName("0.0.0.0").build()); + } + + @Test + void checkAbilityToValidateValidDomainName() { + assertDoesNotThrow(() -> new AppiumServiceBuilder().usingAnyFreePort() + .withDomainName("onetwo.com").build()); + } + + @Test + void checkSecureUrlIsBuiltCorrectly() { + AppiumDriverLocalService builder = new AppiumServiceBuilder().usingAnyFreePort() + .usingSecureConnection(true) + .withDomainName("onetwo.com") + .usingPort(1234) + .build(); + assertEquals("https://onetwo.com:1234/", builder.getUrl().toString()); + } + + @Test + void checkNoneSecureUrlIsBuiltCorrectly() { + AppiumDriverLocalService builder = new AppiumServiceBuilder().usingAnyFreePort() + .usingSecureConnection(false) + .withDomainName("onetwo.com") + .usingPort(1234) + .build(); + assertEquals("http://onetwo.com:1234/", builder.getUrl().toString()); + } + + @Test + void checkNoneSecureIpAddressIsBuiltCorrectly() { + AppiumDriverLocalService builder = new AppiumServiceBuilder().usingAnyFreePort() + .usingSecureConnection(false) + .withIPAddress("1.1.1.1") + .usingPort(1234) + .build(); + assertEquals("http://1.1.1.1:1234/", builder.getUrl().toString()); + } + + @Test + void checkSecureIpAddressIsBuiltCorrectly() { + AppiumDriverLocalService builder = new AppiumServiceBuilder().usingAnyFreePort() + .usingSecureConnection(true) + .withIPAddress("1.1.1.1") + .usingPort(1234) + .build(); + assertEquals("https://1.1.1.1:1234/", builder.getUrl().toString()); + } }