UrlUtils.java
/*-
* ========================LICENSE_START=================================
* flyway-core
* ========================================================================
* Copyright (C) 2010 - 2025 Red Gate Software Ltd
* ========================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================LICENSE_END==================================
*/
package org.flywaydb.core.internal.util;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import org.flywaydb.core.extensibility.Tier;
import org.flywaydb.core.internal.license.FlywayEditionUpgradeRequiredException;
/**
* Collection of utility methods for working with URLs.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class UrlUtils {
/**
* Retrieves the file path of this URL, with any trailing slashes removed.
*
* @param url The URL to get the file path for.
* @return The file path.
*/
public static String toFilePath(URL url) {
String filePath = new File(decodeURLSafe(url.getPath())).getAbsolutePath();
if (filePath.endsWith("/")) {
return filePath.substring(0, filePath.length() - 1);
}
return filePath;
}
/**
* Decodes this UTF-8 encoded URL.
*
* Shall be made private, new code shall always call decodeURLSafe() instead.
*
* @param url The url to decode.
* @return The decoded URL.
*/
public static String decodeURL(String url) {
try {
return URLDecoder.decode(url, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Can never happen", e);
}
}
public static String decodeURLSafe(String url) {
return decodeURL(url.replace("+", "%2b"));
}
public static boolean isSecretManagerUrl(final String url, final String databaseType) {
if (url.startsWith("jdbc-secretsmanager:" + databaseType + ":")) {
throw new FlywayEditionUpgradeRequiredException((Tier) null, "jdbc-secretsmanager");
}
return false;
}
public static boolean isAwsWrapperUrl(final String url, final String databaseType) {
return url.startsWith("jdbc:aws-wrapper:" + databaseType + ":");
}
public static Map<String, String> extractQueryParams(String uri) {
uri = uri.replace('\\', '/');
try {
int queryIndex = uri.indexOf("?");
// No query parameters detected in the connection string
if (queryIndex == -1) {
return Collections.emptyMap();
}
String baseUri = uri.substring(0, queryIndex);
String queryPart = uri.substring(queryIndex + 1);
String encodedQuery = URLEncoder.encode(queryPart, StandardCharsets.UTF_8);
URI parsedUri = new URI(baseUri + "?" + encodedQuery);
String query = parsedUri.getQuery();
Map<String, String> queryParams = new HashMap<>();
if (query != null) {
String[] pairs = query.split("&");
for (String pair : pairs) {
String[] keyValue = pair.split("=", 2);
if (keyValue.length == 2) {
queryParams.put(keyValue[0], keyValue[1]);
}
}
}
return queryParams;
} catch (Exception e) {
return Collections.emptyMap();
}
}
}