add path overlapping check

This commit is contained in:
Mengyi Zhou 2016-04-01 16:21:29 +08:00
parent c9138d7eb2
commit edcdd1e42d
3 changed files with 225 additions and 24 deletions

View file

@ -10,12 +10,11 @@ import com.ctrip.zeus.service.model.PathRewriteParser;
import com.ctrip.zeus.service.model.handler.GroupServerValidator;
import com.ctrip.zeus.service.model.handler.GroupValidator;
import com.ctrip.zeus.service.model.handler.VirtualServerValidator;
import com.ctrip.zeus.util.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* Created by zhoumy on 2015/6/29.
@ -78,31 +77,51 @@ public class DefaultGroupValidator implements GroupValidator {
throw new ValidationException("No virtual server is found bound to this group.");
if (groupId == null)
groupId = 0L;
Set<Long> virtualServerIds = new HashSet<>();
Set<String> groupPaths = new HashSet<>();
for (GroupVirtualServer groupVirtualServer : groupVirtualServers) {
if (groupVirtualServer.getRewrite() != null && !groupVirtualServer.getRewrite().isEmpty())
if (!PathRewriteParser.validate(groupVirtualServer.getRewrite()))
Map<Long, String> paths = new HashMap<>();
for (GroupVirtualServer gvs : groupVirtualServers) {
if (gvs.getRewrite() != null && !gvs.getRewrite().isEmpty()) {
if (!PathRewriteParser.validate(gvs.getRewrite())) {
throw new ValidationException("Invalid rewrite value.");
VirtualServer vs = groupVirtualServer.getVirtualServer();
if (!virtualServerModelValidator.exists(vs.getId()))
throw new ValidationException("Virtual Server with id " + vs.getId() + " does not exist.");
else {
if (virtualServerIds.contains(vs.getId()))
throw new ValidationException("Group-VirtualServer is an unique combination.");
else
virtualServerIds.add(vs.getId());
}
}
if (groupPaths.contains(vs.getId() + groupVirtualServer.getPath()))
throw new ValidationException("Duplicate path \"" + groupVirtualServer.getPath() + "\" is found on virtual server " + vs.getId() + " from post entity.");
else
groupPaths.add(vs.getId() + groupVirtualServer.getPath());
VirtualServer vs = gvs.getVirtualServer();
if (!virtualServerModelValidator.exists(vs.getId())) {
throw new ValidationException("Virtual server with id " + vs.getId() + " does not exist.");
}
if (paths.containsKey(vs.getId())) {
throw new ValidationException("Group and virtual server is an unique combination.");
}
String path = gvs.getPath();
path = path.substring(path.indexOf('/'));
paths.put(vs.getId(), path);
}
for (RelGroupVsDo relGroupVsDo : rGroupVsDao.findAllByVses(virtualServerIds.toArray(new Long[virtualServerIds.size()]), RGroupVsEntity.READSET_FULL)) {
if (groupId.equals(relGroupVsDo.getGroupId()))
List<RelGroupVsDo> retained = new ArrayList<>();
for (RelGroupVsDo d : rGroupVsDao.findAllByVses(paths.keySet().toArray(new Long[paths.size()]), RGroupVsEntity.READSET_FULL)) {
if (groupId.equals(d.getGroupId()))
continue;
if (groupPaths.contains(relGroupVsDo.getVsId() + relGroupVsDo.getPath()))
throw new ValidationException("Duplicate path \"" + relGroupVsDo.getPath() + "\" is found on virtual server " + relGroupVsDo.getVsId() + " from existing entities.");
int i = 0;
String value = d.getPath();
while (i < value.length()) {
char next = value.charAt(i);
if (next == '/') {
if (StringUtils.prefixOverlapped(paths.get(d.getVsId()), value.substring(i))) retained.add(d);
break;
} else {
i++;
}
}
}
if (retained.size() > 0) {
StringBuilder sb = new StringBuilder();
for (RelGroupVsDo d : retained) {
sb.append(d.getVsId() + "/" + d.getPath());
}
throw new ValidationException("Path is prefix-overlapped across virtual server " + sb.toString());
}
}

View file

@ -0,0 +1,17 @@
package com.ctrip.zeus.util;
/**
* Created by zhoumy on 2016/3/30.
*/
public class StringUtils {
public static boolean prefixOverlapped(String string1, String string2) {
int i = 0;
while (i < string1.length() && i < string2.length()) {
if (string1.charAt(i) == string2.charAt(i) || Character.toLowerCase(string1.charAt(i)) == Character.toLowerCase(string2.charAt(i))) {
i++;
continue;
} else return false;
}
return true;
}
}

View file

@ -0,0 +1,165 @@
package com.ctrip.zeus.service.model;
import com.ctrip.zeus.AbstractServerTest;
import com.ctrip.zeus.dal.core.RGroupVsDao;
import com.ctrip.zeus.dal.core.RelGroupVsDo;
import com.ctrip.zeus.exceptions.ValidationException;
import com.ctrip.zeus.model.entity.*;
import com.ctrip.zeus.service.model.handler.GroupValidator;
import com.ctrip.zeus.util.StringUtils;
import com.google.common.collect.Sets;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Created by zhoumy on 2016/3/31.
*/
public class PathValidationTest extends AbstractServerTest {
@Resource
private SlbRepository slbRepository;
@Resource
private RGroupVsDao rGroupVsDao;
@Resource
private GroupValidator groupModelValidator;
@Test
public void testStringUtils() {
String s1 = "abcdefg";
String s2 = "abc";
String s3 = "ABCDefghij";
String s4 = "我爱中国";
String s5 = "";
String s6 = "我爱中国中国爱我";
String s7 = "bcdef";
String s8 = "";
Assert.assertTrue(StringUtils.prefixOverlapped(s1, s2));
Assert.assertTrue(StringUtils.prefixOverlapped(s2, s3));
Assert.assertTrue(StringUtils.prefixOverlapped(s3, s1));
Assert.assertTrue(StringUtils.prefixOverlapped(s4, s5));
Assert.assertTrue(StringUtils.prefixOverlapped(s5, s6));
Assert.assertTrue(StringUtils.prefixOverlapped(s6, s4));
Assert.assertFalse(StringUtils.prefixOverlapped(s1, s7));
Assert.assertFalse(StringUtils.prefixOverlapped(s4, s8));
Assert.assertFalse(StringUtils.prefixOverlapped(s1, s4));
}
@Test
public void testAddExistingPath() {
String path = "~* ^/linkservice($|/|\\?)";
List<GroupVirtualServer> array = new ArrayList<>();
array.add(new GroupVirtualServer().setPath(path).setVirtualServer(new VirtualServer().setId(1L)));
try {
groupModelValidator.validateGroupVirtualServers(100L, array);
Assert.assertTrue(false);
} catch (Exception e) {
Assert.assertTrue(e instanceof ValidationException);
}
}
@Test
public void testAddOverlappingPath() {
String path = "~* ^/linkservice/config($|/|\\?)";
List<GroupVirtualServer> array = new ArrayList<>();
array.add(new GroupVirtualServer().setPath(path).setVirtualServer(new VirtualServer().setId(1L)));
try {
groupModelValidator.validateGroupVirtualServers(100L, array);
Assert.assertTrue(false);
} catch (Exception e) {
Assert.assertTrue(e instanceof ValidationException);
}
}
@Test
public void testUpdatePath() {
String path = "~* ^/baike($|/|\\?)";
List<GroupVirtualServer> array = new ArrayList<>();
array.add(new GroupVirtualServer().setPath(path).setVirtualServer(new VirtualServer().setId(1L)));
try {
groupModelValidator.validateGroupVirtualServers(10L, array);
} catch (Exception e) {
Assert.assertTrue(false);
}
}
@Test
public void testAddUpperCasePath() {
String path = "~* ^/BAIKE/CONFIG($|/|\\?)";
List<GroupVirtualServer> array = new ArrayList<>();
array.add(new GroupVirtualServer().setPath(path).setVirtualServer(new VirtualServer().setId(1L)));
try {
groupModelValidator.validateGroupVirtualServers(100L, array);
Assert.assertTrue(false);
} catch (Exception e) {
Assert.assertTrue(e instanceof ValidationException);
}
}
@Test
public void testUnconventionalPath() {
String root = "/";
String startWith = "^/CommentAdmin";
String noStart = "baike";
List<GroupVirtualServer> array = new ArrayList<>();
array.add(new GroupVirtualServer().setPath(root).setVirtualServer(new VirtualServer().setId(1L)));
try {
groupModelValidator.validateGroupVirtualServers(100L, array);
Assert.assertTrue(false);
} catch (Exception e) {
Assert.assertTrue(e instanceof ValidationException);
}
try {
array.get(0).setPath(startWith);
groupModelValidator.validateGroupVirtualServers(100L, array);
Assert.assertTrue(false);
} catch (Exception e) {
Assert.assertTrue(e instanceof ValidationException);
}
try {
array.get(0).setPath(noStart);
groupModelValidator.validateGroupVirtualServers(100L, array);
Assert.assertTrue(false);
} catch (Exception e) {
Assert.assertTrue(e instanceof ValidationException);
}
}
@Before
public void check() throws Exception {
Slb slb = slbRepository.getById(1L);
Set<String> existingPaths = Sets.newHashSet("~* /", "~* ^/CommentAdmin/", "~* ^/baike($|/|\\?)",
"~* ^/linkservice($|/|\\?)", "~* ^/linkservice/link($|/|\\?)",
"~* ^/tour-marketingservice($|/|\\?)", "~* ^/tour-MarketingServiceConfig($|/|\\?)",
"~* ^/cruise-interface-costa($|/|\\?)", "~* ^/Cruise-Product-WCFService($|/|\\?)", "~* ^/Cruise-Product-OctopusJob($|/|\\?)");
if (slb == null) {
slb = new Slb().setName("default").setStatus("TEST")
.addVip(new Vip().setIp("10.2.25.93"))
.addSlbServer(new SlbServer().setIp("10.2.25.93").setHostName("uat0358"))
.addVirtualServer(new VirtualServer().setName("defaultSlbVs1").setSsl(false).setPort("80")
.addDomain(new Domain().setName("defaultSlbVs1.ctrip.com")));
slbRepository.add(slb);
for (String path : existingPaths) {
for (int i = 0; i < existingPaths.size(); i++) {
rGroupVsDao.insert(new RelGroupVsDo().setGroupId(10).setVsId(1).setPath(path));
}
}
}
}
}