diff --git a/spring-cloud-cloudfoundry-connector/src/test/java/org/springframework/cloud/cloudfoundry/CloudFoundryConnectorSqlServerServiceTest.java b/spring-cloud-cloudfoundry-connector/src/test/java/org/springframework/cloud/cloudfoundry/CloudFoundryConnectorSqlServerServiceTest.java index de3d99e..8214dd8 100644 --- a/spring-cloud-cloudfoundry-connector/src/test/java/org/springframework/cloud/cloudfoundry/CloudFoundryConnectorSqlServerServiceTest.java +++ b/spring-cloud-cloudfoundry-connector/src/test/java/org/springframework/cloud/cloudfoundry/CloudFoundryConnectorSqlServerServiceTest.java @@ -2,10 +2,13 @@ package org.springframework.cloud.cloudfoundry; import org.junit.Test; import org.springframework.cloud.service.ServiceInfo; +import org.springframework.cloud.service.common.RelationalServiceInfo; import org.springframework.cloud.service.common.SqlServerServiceInfo; +import org.springframework.cloud.util.UriInfo; import java.util.List; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.when; @@ -30,6 +33,23 @@ public class CloudFoundryConnectorSqlServerServiceTest extends AbstractUserProvi assertUriBasedServiceInfoFields(info, SQLSERVER_SCHEME, hostname, port, username, password, INSTANCE_NAME); } + @Test + public void sqlServerServiceCreationWithSpecialChars() { + String userWithSpecialChars = "u%u:u+"; + String passwordWithSpecialChars = "p%p:p+"; + + when(mockEnvironment.getEnvValue("VCAP_SERVICES")) + .thenReturn(getServicesPayload( + getUserProvidedServicePayload(SERVICE_NAME, hostname, port, userWithSpecialChars, passwordWithSpecialChars, INSTANCE_NAME, SQLSERVER_SCHEME + ":"))); + List serviceInfos = testCloudConnector.getServiceInfos(); + + ServiceInfo info = getServiceInfo(serviceInfos, SERVICE_NAME); + assertServiceFoundOfType(info, SqlServerServiceInfo.class); + assertEquals(getJdbcUrl(hostname, port, SQLSERVER_SCHEME, INSTANCE_NAME, + userWithSpecialChars, passwordWithSpecialChars), ((RelationalServiceInfo)info).getJdbcUrl()); + assertUriBasedServiceInfoFields(info, SQLSERVER_SCHEME, hostname, port, userWithSpecialChars, passwordWithSpecialChars, INSTANCE_NAME); + } + @Test public void sqlServerServiceCreationWithNoUri() { when(mockEnvironment.getEnvValue("VCAP_SERVICES")) @@ -55,6 +75,23 @@ public class CloudFoundryConnectorSqlServerServiceTest extends AbstractUserProvi assertUriBasedServiceInfoFields(info, SQLSERVER_SCHEME, hostname, port, username, password, INSTANCE_NAME); } + @Test + public void sqlServerServiceCreationWithJdbcUrlAndSpecialChars() { + String userWithSpecialChars = "u%u:u+"; + String passwordWithSpecialChars = "p%p:p+"; + + when(mockEnvironment.getEnvValue("VCAP_SERVICES")) + .thenReturn(getServicesPayload( + getSqlServerServicePayloadWithJdbcurl(SERVICE_NAME, hostname, port, userWithSpecialChars, passwordWithSpecialChars, INSTANCE_NAME, SQLSERVER_SCHEME + ":"))); + List serviceInfos = testCloudConnector.getServiceInfos(); + + ServiceInfo info = getServiceInfo(serviceInfos, SERVICE_NAME); + assertServiceFoundOfType(info, SqlServerServiceInfo.class); + assertEquals(getJdbcUrl(hostname, port, SQLSERVER_SCHEME, INSTANCE_NAME, + userWithSpecialChars, passwordWithSpecialChars), ((RelationalServiceInfo)info).getJdbcUrl()); + assertUriBasedServiceInfoFields(info, SQLSERVER_SCHEME, hostname, port, userWithSpecialChars, passwordWithSpecialChars, INSTANCE_NAME); + } + protected String getSqlServerServicePayloadWithJdbcurl(String serviceName, String hostname, int port, String user, String password, String name, String scheme) { String payload = getRelationalPayload("test-sqlserver-info-jdbc-url.json", serviceName, @@ -65,4 +102,9 @@ public class CloudFoundryConnectorSqlServerServiceTest extends AbstractUserProvi protected String getJdbcUrl(String scheme, String name) { return String.format("%s%s://%s:%d;database=%s;user=%s;password=%s", JDBC_PREFIX, scheme, hostname, port, name, username, password); } + + private String getJdbcUrl(String hostname, int port, String scheme, String name, String username, String password) { + return String.format("%s%s://%s:%d;database=%s;user=%s;password=%s", JDBC_PREFIX, scheme, hostname, port, + name, UriInfo.urlEncode(username), UriInfo.urlEncode(password)); + } } diff --git a/spring-cloud-core/src/main/java/org/springframework/cloud/service/common/SqlServerServiceInfo.java b/spring-cloud-core/src/main/java/org/springframework/cloud/service/common/SqlServerServiceInfo.java index e0344b5..96b8194 100644 --- a/spring-cloud-core/src/main/java/org/springframework/cloud/service/common/SqlServerServiceInfo.java +++ b/spring-cloud-core/src/main/java/org/springframework/cloud/service/common/SqlServerServiceInfo.java @@ -1,6 +1,7 @@ package org.springframework.cloud.service.common; import org.springframework.cloud.service.ServiceInfo; +import org.springframework.cloud.util.UriInfo; @ServiceInfo.ServiceLabel("sqlserver") public class SqlServerServiceInfo extends RelationalServiceInfo { @@ -18,6 +19,6 @@ public class SqlServerServiceInfo extends RelationalServiceInfo { protected String buildJdbcUrl() { return String.format("jdbc:%s://%s:%d;database=%s;user=%s;password=%s", jdbcUrlDatabaseType, - getHost(), getPort(), getPath(), getUserName(), getPassword()); + getHost(), getPort(), getPath(), UriInfo.urlEncode(getUserName()), UriInfo.urlEncode(getPassword())); } } diff --git a/spring-cloud-core/src/main/java/org/springframework/cloud/util/UriInfo.java b/spring-cloud-core/src/main/java/org/springframework/cloud/util/UriInfo.java index 671d171..4f3baf0 100644 --- a/spring-cloud-core/src/main/java/org/springframework/cloud/util/UriInfo.java +++ b/spring-cloud-core/src/main/java/org/springframework/cloud/util/UriInfo.java @@ -5,7 +5,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; /** * Utility class that allows expressing URIs in alternative forms: individual fields or a URI string