package io.cattle.platform.core.util; import io.github.ibuildthecloud.gdapi.exception.ClientVisibleException; import io.github.ibuildthecloud.gdapi.util.ResponseCodes; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; /** * This class is to parse the port specs defined for the load balancer, in format * [[[domain:][sourcePort][/path]=][targetPort]] * * example.com:80/path=81 * example.com * example.com:80 * example.com:80/path * example.com:80/path=81 * example.com:80=81 * example.com/path * example.com/path=81 * example.com=81 * 80/path * 80/path=81 * 80=81 * /path * /path=81 * 81 */ public class LoadBalancerTargetPortSpec { private static final Pattern PATTERN = Pattern.compile("([0-9]+)(:(.*)?)?"); public static final String WRONG_FORMAT = "InvalidPort"; public static final String DEFAULT = "default"; Integer port; String domain = DEFAULT; String path = DEFAULT; Integer sourcePort; public LoadBalancerTargetPortSpec() { } public LoadBalancerTargetPortSpec(LoadBalancerTargetPortSpec that) { this.port = that.port; this.domain = that.domain; this.path = that.path; this.sourcePort = that.sourcePort; } public LoadBalancerTargetPortSpec(String input) { Matcher m = PATTERN.matcher(input); if (isOldStyle(input, m)) { convertPortsOldStyle(input, m); } else { convertPortsNewStyle(input); } } protected boolean isOldStyle(String input, Matcher m) { if (!m.matches()) { return false; } // if input is a number, we assume its the new style targetPort try { Integer.valueOf(input); } catch (NumberFormatException ex) { return true; } return false; } protected void convertPortsOldStyle(String input, Matcher m) { setPort(m); setHostAndDomain(m); } protected void convertPortsNewStyle(String input) { String targetPort = null; String domain = null; String path = null; String sourcePort = null; if (input.isEmpty()) { return; } if (input.split("=").length > 2 || input.split(":").length > 2) { throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, WRONG_FORMAT); } try { // target port assignment String[] splittedByEqual = input.split("="); if (splittedByEqual.length > 1) { targetPort = splittedByEqual[1]; input = splittedByEqual[0]; } else { try { Integer.valueOf(splittedByEqual[0]); targetPort = splittedByEqual[0]; return; } catch (NumberFormatException ex) { } } // path assignment if (input.startsWith("/")) { path = input; return; } String[] splittedBySlash = StringUtils.split(input, "/", 2); if (splittedBySlash.length > 1) { path = "/" + splittedBySlash[1]; input = splittedBySlash[0]; } // domain name assignment String[] splittedByColon = StringUtils.split(input, ":"); if (splittedByColon.length > 1) { domain = splittedByColon[0]; sourcePort = splittedByColon[1]; } else { try { Integer.valueOf(splittedByColon[0]); sourcePort = splittedByColon[0]; } catch (NumberFormatException ex) { domain = splittedByColon[0]; } } } finally { if (!StringUtils.isEmpty(domain)) { this.domain = domain; } if (!StringUtils.isEmpty(path)) { this.path = path; } if (!StringUtils.isEmpty(targetPort)) { this.port = validatePort(targetPort); } if (!StringUtils.isEmpty(sourcePort)) { this.sourcePort = validatePort(sourcePort); } } } protected void setHostAndDomain(Matcher m) { String domainPath = m.group(3) != null ? m.group(3) : ""; if (domainPath.length() > 0) { int slashIndex = domainPath.indexOf("/"); if (slashIndex == -1) { this.domain = domainPath; } else if (slashIndex == 0) { this.path = domainPath; } else { this.domain = domainPath.substring(0, slashIndex); this.path = domainPath.substring(slashIndex, domainPath.length()); } } } protected void setPort(Matcher m) { Integer port = Integer.parseInt(m.group(1)); if (port != null && (port <= 0 || port > 65535)) { throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, WRONG_FORMAT); } this.port = port; } protected Integer validatePort(String portStr) { Integer port = null; try { port = Integer.valueOf(portStr); } catch (NumberFormatException ex) { throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, WRONG_FORMAT); } if (port != null && (port <= 0 || port > 65535)) { throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, WRONG_FORMAT); } return port; } public LoadBalancerTargetPortSpec(int targetPort, int sourcePort) { this.port = targetPort; this.sourcePort = sourcePort; } public Integer getPort() { return port; } public void setPort(Integer port) { this.port = port; } public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public Integer getSourcePort() { return sourcePort; } public void setSourcePort(int sourcePort) { this.sourcePort = sourcePort; } }