diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index b287fc917e..d5dcd2d7db 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -77,6 +77,7 @@ import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.IOUtils; import com.alibaba.druid.util.JMXUtils; import com.alibaba.druid.util.JdbcUtils; +import com.alibaba.druid.wall.WallFilter; /** * @author ljw @@ -1440,8 +1441,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat ref.add(new StringRefAddr("instanceKey", instanceKey)); ref.add(new StringRefAddr("url", this.getUrl())); ref.add(new StringRefAddr("username", this.getUsername())); - ref.add(new StringRefAddr("password",this.getPassword())); - //TODO ADD OTHER PROPERTIES + ref.add(new StringRefAddr("password", this.getPassword())); + // TODO ADD OTHER PROPERTIES return ref; } @@ -1946,6 +1947,17 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return this.getDataSourceStat().getSqlStatMap(); } + public Map getWallStatMap() { + for (Filter filter : this.filters) { + if (filter instanceof WallFilter) { + WallFilter wallFilter = (WallFilter) filter; + return wallFilter.getProvider().getStatsMap(); + } + } + + return null; + } + public Lock getLock() { return lock; } diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java index 671cd68690..9e59eb0d35 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java @@ -21,6 +21,7 @@ import java.sql.DriverManager; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -135,17 +136,17 @@ public final class DruidStatManagerFacade { public List> getSqlStatDataList(Integer dataSourceId) { Set dataSources = getDruidDataSourceInstances(); - + if (dataSourceId == null) { List> sqlList = new ArrayList>(); - + for (Object datasource : dataSources) { sqlList.addAll(getSqlStatDataList(datasource)); } - + return sqlList; } - + for (Object datasource : dataSources) { if (dataSourceId != null && dataSourceId.intValue() != System.identityHashCode(datasource)) { continue; @@ -157,6 +158,62 @@ public final class DruidStatManagerFacade { return new ArrayList>(); } + public Map getWallStatMap(Integer dataSourceId) { + Set dataSources = getDruidDataSourceInstances(); + + if (dataSourceId == null) { + List> sqlList = new ArrayList>(); + + Map map = new HashMap(); + + for (Object datasource : dataSources) { + Map wallStat = DruidDataSourceUtils.getWallStatMap(datasource); + map = mergWallStat(map, wallStat); + } + + return map; + } + + for (Object datasource : dataSources) { + if (dataSourceId != null && dataSourceId.intValue() != System.identityHashCode(datasource)) { + continue; + } + + return DruidDataSourceUtils.getWallStatMap(datasource); + } + + return new HashMap(); + // + } + + static Map mergWallStat(Map mapA, Map mapB) { + if (mapA.size() == 0) { + return mapB; + } + + if (mapB.size() == 0) { + return mapA; + } + + for (Object item : mapB.entrySet()) { + Map.Entry entry = (Map.Entry) item; + String key = (String) entry.getKey(); + Object valueB = entry.getValue(); + Object valueA = mapA.get(key); + + if (valueA == null) { + mapA.put(key, valueB); + } else { + if (valueA instanceof Map && valueB instanceof Map) { + Object newValue = mergWallStat((Map)valueA, (Map)valueB); + mapA.put(key, newValue); + } + } + } + + return null; + } + public List> getSqlStatDataList(Object datasource) { List> result = new ArrayList>(); Map sqlStatMap = DruidDataSourceUtils.getSqlStatMap(datasource); diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatService.java b/src/main/java/com/alibaba/druid/stat/DruidStatService.java index 4494694218..c866280956 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatService.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatService.java @@ -36,6 +36,7 @@ import com.alibaba.druid.support.json.JSONUtils; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.support.spring.stat.SpringStatManager; +import com.alibaba.druid.util.DruidDataSourceUtils; import com.alibaba.druid.util.MapComparator; import com.alibaba.druid.util.StringUtils; @@ -256,6 +257,17 @@ public final class DruidStatService implements DruidStatServiceMBean { List> sortedArray = comparatorOrderBy(array, parameters); return sortedArray; } + + public Map getWallStatMap(Map parameters) { + Integer dataSourceId = null; + + String dataSourceIdParam = parameters.get("dataSourceId"); + if (dataSourceIdParam != null && dataSourceIdParam.length() > 0) { + dataSourceId = Integer.parseInt(dataSourceIdParam); + } + + return statManagerFacade.getWallStatMap(dataSourceId); + } private String getSqlStat(Integer id) { Map map = statManagerFacade.getSqlStatData(id); diff --git a/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java b/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java index fd9a5cceba..b0b27fc6a0 100644 --- a/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java +++ b/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java @@ -167,6 +167,22 @@ public class DruidDataSourceUtils { } } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static Map getWallStatMap(Object druidDatasource) { + if (druidDatasource.getClass() == DruidDataSource.class) { + return ((DruidDataSource) druidDatasource).getWallStatMap(); + } + + try { + Method method = druidDatasource.getClass().getMethod("getWallStatMap"); + Object obj = method.invoke(druidDatasource); + return (Map) obj; + } catch (Exception e) { + LOG.error("getWallStatMap error", e); + return null; + } + } + @SuppressWarnings("unchecked") public static List> getPoolingConnectionInfo(Object druidDatasource) { if (druidDatasource.getClass() == DruidDataSource.class) { diff --git a/src/main/java/com/alibaba/druid/wall/WallContext.java b/src/main/java/com/alibaba/druid/wall/WallContext.java index 7aabe333e2..d0cf3e3910 100644 --- a/src/main/java/com/alibaba/druid/wall/WallContext.java +++ b/src/main/java/com/alibaba/druid/wall/WallContext.java @@ -24,12 +24,33 @@ public class WallContext { private WallSqlStat sqlState; private Map tableStats; + private Map functionStats; private final String dbType; public WallContext(String dbType){ this.dbType = dbType; } + public void incrementFunctionInvoke(String tableName) { + if (functionStats == null) { + functionStats = new HashMap(); + } + + String lowerCaseName = tableName.toLowerCase(); + + WallSqlFunctionStat stat = functionStats.get(lowerCaseName); + if (stat == null) { + if (functionStats.size() > 100) { + return; + } + + stat = new WallSqlFunctionStat(); + functionStats.put(tableName, stat); + } + + stat.incrementInvokeCount(); + } + public WallSqlTableStat getTableStat(String tableName) { if (tableStats == null) { tableStats = new HashMap(2); @@ -39,7 +60,7 @@ public class WallContext { WallSqlTableStat stat = tableStats.get(lowerCaseName); if (stat == null) { - if (tableStats.size() > 10000) { + if (tableStats.size() > 100) { return null; } @@ -84,6 +105,10 @@ public class WallContext { return tableStats; } + public Map getFunctionStats() { + return functionStats; + } + public String getDbType() { return dbType; } diff --git a/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java b/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java new file mode 100644 index 0000000000..0999480bf0 --- /dev/null +++ b/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding 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. + */ +package com.alibaba.druid.wall; + +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + +public class WallFunctionStat { + + private volatile long invokeCount; + final static AtomicLongFieldUpdater invokeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallFunctionStat.class, + "invokeCount"); + + public long getInvokeCount() { + return invokeCount; + } + + public void incrementInvokeCount() { + this.invokeCount++; + } + + public void addSqlFunctionStat(WallSqlFunctionStat sqlFunctionStat) { + this.invokeCount += sqlFunctionStat.getInvokeCount(); + } + +} diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index fac2c61759..b38bb74e41 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -16,8 +16,11 @@ package com.alibaba.druid.wall; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -40,36 +43,33 @@ import com.alibaba.druid.wall.violation.SyntaxErrorViolation; public abstract class WallProvider { - private LRUCache whiteList; + private LRUCache whiteList; - private int MAX_SQL_SIZE = 2048; // 1k + private int MAX_SQL_LENGTH = 2048; // 1k - private int whiteSqlMaxLength = 1024; // 1k + private int whiteSqlMaxSize = 1000; // 1k - private LRUCache blackList; + private LRUCache blackList; - private int blackSqlMaxLength = 1024; // 1k + private int blackSqlMaxSize = 1000; // 1k - protected final WallConfig config; + protected final WallConfig config; - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - private static final ThreadLocal privileged = new ThreadLocal(); + private static final ThreadLocal privileged = new ThreadLocal(); - private final ConcurrentMap deniedTables = new ConcurrentHashMap(); - private final ConcurrentMap deniedFunctions = new ConcurrentHashMap(); - private final ConcurrentMap deniedSchemas = new ConcurrentHashMap(); + private final ConcurrentMap functionStats = new ConcurrentHashMap(); + private final ConcurrentMap tableStats = new ConcurrentHashMap(); - private final ConcurrentMap tableStats = new ConcurrentHashMap(); + public final WallDenyStat commentDeniedStat = new WallDenyStat(); - public final WallDenyStat commentDeniedStat = new WallDenyStat(); - - protected String dbType = null; - protected AtomicLong checkCount = new AtomicLong(); - protected AtomicLong whiteListHitCount = new AtomicLong(); - protected AtomicLong blackListHitCount = new AtomicLong(); - protected AtomicLong syntaxErrrorCount = new AtomicLong(); - protected AtomicLong violationCount = new AtomicLong(); + protected String dbType = null; + protected final AtomicLong checkCount = new AtomicLong(); + protected final AtomicLong whiteListHitCount = new AtomicLong(); + protected final AtomicLong blackListHitCount = new AtomicLong(); + protected final AtomicLong syntaxErrrorCount = new AtomicLong(); + protected final AtomicLong violationCount = new AtomicLong(); public WallProvider(WallConfig config){ this.config = config; @@ -82,9 +82,7 @@ public abstract class WallProvider { public void reset() { this.clearWhiteList(); - this.deniedTables.clear(); - this.deniedFunctions.clear(); - this.deniedSchemas.clear(); + this.functionStats.clear(); this.tableStats.clear(); } @@ -96,7 +94,7 @@ public abstract class WallProvider { String lowerCaseName = tableName.toLowerCase(); return getTableStatWithLowerName(lowerCaseName); } - + public WallTableStat getTableStatWithLowerName(String lowerCaseName) { WallTableStat stat = tableStats.get(lowerCaseName); if (stat == null) { @@ -110,20 +108,39 @@ public abstract class WallProvider { return stat; } + public WallFunctionStat getFunctionStat(String functionName) { + String lowerCaseName = functionName.toLowerCase(); + return getFunctionStatWithLowerName(lowerCaseName); + } + + public WallFunctionStat getFunctionStatWithLowerName(String lowerCaseName) { + WallFunctionStat stat = functionStats.get(lowerCaseName); + if (stat == null) { + if (functionStats.size() > 10000) { + return null; + } + + functionStats.putIfAbsent(lowerCaseName, new WallFunctionStat()); + stat = functionStats.get(lowerCaseName); + } + return stat; + } + public WallConfig getConfig() { return config; } - public WallSqlStat addWhiteSql(String sql, Map tableStats) { + public WallSqlStat addWhiteSql(String sql, Map tableStats, + Map functionStats) { lock.writeLock().lock(); try { if (whiteList == null) { - whiteList = new LRUCache(whiteSqlMaxLength); + whiteList = new LRUCache(whiteSqlMaxSize); } WallSqlStat wallStat = whiteList.get(sql); if (wallStat == null) { - wallStat = new WallSqlStat(tableStats); + wallStat = new WallSqlStat(tableStats, functionStats); whiteList.put(sql, wallStat); } @@ -133,16 +150,17 @@ public abstract class WallProvider { } } - public WallSqlStat addBlackSql(String sql, Map tableStats, List violations) { + public WallSqlStat addBlackSql(String sql, Map tableStats, + Map functionStats, List violations) { lock.writeLock().lock(); try { if (blackList == null) { - blackList = new LRUCache(blackSqlMaxLength); + blackList = new LRUCache(blackSqlMaxSize); } WallSqlStat wallStat = blackList.get(sql); if (wallStat == null) { - wallStat = new WallSqlStat(tableStats, violations); + wallStat = new WallSqlStat(tableStats, functionStats, violations); blackList.put(sql, wallStat); } @@ -256,13 +274,8 @@ public abstract class WallProvider { } functionName = functionName.toLowerCase(); + if (getConfig().getDenyFunctions().contains(functionName)) { - WallDenyStat denyStat = this.deniedFunctions.get(functionName); - if (denyStat == null) { - this.deniedFunctions.putIfAbsent(functionName, new WallDenyStat()); - denyStat = this.deniedFunctions.get(functionName); - } - denyStat.incrementAndGetDenyCount(); return false; } @@ -276,12 +289,6 @@ public abstract class WallProvider { schemaName = schemaName.toLowerCase(); if (getConfig().getDenySchemas().contains(schemaName)) { - WallDenyStat denyStat = this.deniedSchemas.get(schemaName); - if (denyStat == null) { - this.deniedSchemas.putIfAbsent(schemaName, new WallDenyStat()); - denyStat = this.deniedSchemas.get(schemaName); - } - denyStat.incrementAndGetDenyCount(); return false; } @@ -295,12 +302,6 @@ public abstract class WallProvider { tableName = WallVisitorUtils.form(tableName); if (getConfig().getDenyTables().contains(tableName)) { - WallDenyStat denyStat = this.deniedTables.get(tableName); - if (denyStat == null) { - this.deniedTables.putIfAbsent(tableName, new WallDenyStat()); - denyStat = this.deniedTables.get(tableName); - } - denyStat.incrementAndGetDenyCount(); return false; } @@ -314,36 +315,12 @@ public abstract class WallProvider { tableName = WallVisitorUtils.form(tableName); if (getConfig().isReadOnly(tableName)) { - WallDenyStat denyStat = this.deniedTables.get(tableName); - if (denyStat == null) { - this.deniedTables.putIfAbsent(tableName, new WallDenyStat()); - denyStat = this.deniedTables.get(tableName); - } - denyStat.incrementAndGetDenyCount(); return false; } return true; } - public WallDenyStat getDenniedTableStat(String tableName) { - if (tableName == null) { - return null; - } - - String formName = WallVisitorUtils.form(tableName); - return deniedTables.get(formName); - } - - public WallDenyStat getDenniedSchemaStat(String schemaName) { - if (schemaName == null) { - return null; - } - - String formName = WallVisitorUtils.form(schemaName); - return deniedSchemas.get(formName); - } - public WallDenyStat getCommentDenyStat() { return this.commentDeniedStat; } @@ -384,16 +361,7 @@ public abstract class WallProvider { whiteListHitCount.incrementAndGet(); sqlStat.incrementAndGetExecuteCount(); - if (sqlStat.getTableStats() != null) { - for (Map.Entry entry : sqlStat.getTableStats().entrySet()) { - String tableName = entry.getKey(); - WallSqlTableStat sqlTableStat = entry.getValue(); - WallTableStat tableStat = getTableStatWithLowerName(tableName); - if (tableStat != null) { - tableStat.addSqlTableStat(sqlTableStat); - } - } - } + recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); return result; } } @@ -403,18 +371,7 @@ public abstract class WallProvider { if (sqlStat != null) { blackListHitCount.incrementAndGet(); sqlStat.incrementAndGetExecuteCount(); - - if (sqlStat.getTableStats() != null) { - for (Map.Entry entry : sqlStat.getTableStats().entrySet()) { - String tableName = entry.getKey(); - WallSqlTableStat sqlTableStat = entry.getValue(); - WallTableStat tableStat = getTableStat(tableName); - if (tableStat != null) { - tableStat.addSqlTableStat(sqlTableStat); - } - } - } - + recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); List blackViolations = sqlStat.getViolations(); result.getViolations().addAll(blackViolations); @@ -471,17 +428,25 @@ public abstract class WallProvider { if (result.getViolations().size() > 0) { violationCount.incrementAndGet(); - if (sql.length() < MAX_SQL_SIZE) { - addBlackSql(sql, context.getTableStats(), result.getViolations()); + if (sql.length() < MAX_SQL_LENGTH) { + addBlackSql(sql, context.getTableStats(), context.getFunctionStats(), result.getViolations()); } } else { - if (sql.length() < MAX_SQL_SIZE) { - addWhiteSql(sql, context.getTableStats()); + if (sql.length() < MAX_SQL_LENGTH) { + addWhiteSql(sql, context.getTableStats(), context.getFunctionStats()); } } - if (context != null && context.getTableStats() != null) { - for (Map.Entry entry : context.getTableStats().entrySet()) { + if (context != null) { + recordStats(context.getTableStats(), context.getFunctionStats()); + } + + return result; + } + + void recordStats(Map tableStats, Map functionStats) { + if (tableStats != null) { + for (Map.Entry entry : tableStats.entrySet()) { String tableName = entry.getKey(); WallSqlTableStat sqlTableStat = entry.getValue(); WallTableStat tableStat = getTableStat(tableName); @@ -490,8 +455,16 @@ public abstract class WallProvider { } } } - - return result; + if (functionStats != null) { + for (Map.Entry entry : functionStats.entrySet()) { + String tableName = entry.getKey(); + WallSqlFunctionStat sqlTableStat = entry.getValue(); + WallFunctionStat functionStat = getFunctionStatWithLowerName(tableName); + if (functionStat != null) { + functionStat.addSqlFunctionStat(sqlTableStat); + } + } + } } public static boolean ispPivileged() { @@ -541,8 +514,9 @@ public abstract class WallProvider { public long getViolationCount() { return violationCount.get(); } - + public static class WallCommentHandler implements Lexer.CommentHandler { + public final static WallCommentHandler instance = new WallCommentHandler(); @Override @@ -550,7 +524,7 @@ public abstract class WallProvider { if (lastToken == null) { return false; } - + switch (lastToken) { case SELECT: case INSERT: @@ -565,9 +539,42 @@ public abstract class WallProvider { default: break; } - + return false; } - + } + + public Map getStatsMap() { + Map info = new LinkedHashMap(); + + info.put("checkCount", this.getCheckCount()); + info.put("violationCount", this.getViolationCount()); + info.put("blackListHitCount", this.getBlackListHitCount()); + info.put("blackListSize", this.getBlackList().size()); + info.put("whiteListHitCount", this.getWhiteListHitCount()); + info.put("whiteListSize", this.getWhiteList().size()); + info.put("syntaxErrrorCount", this.getSyntaxErrorCount()); + + { + List> tables = new ArrayList>(); + for (Map.Entry entry : this.tableStats.entrySet()) { + Map stat = new LinkedHashMap(); + stat.put("name", entry.getKey()); + entry.getValue().toMap(stat); + tables.add(stat); + } + info.put("tables", tables); + } + { + List> functions = new ArrayList>(); + for (Map.Entry entry : this.functionStats.entrySet()) { + Map stat = new HashMap(); + stat.put("name", entry.getValue()); + stat.put("invokeCount", entry.getValue().getInvokeCount()); + functions.add(stat); + } + info.put("functions", functions); + } + return info; } } diff --git a/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java b/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java new file mode 100644 index 0000000000..02754a0ac0 --- /dev/null +++ b/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding 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. + */ +package com.alibaba.druid.wall; + +public class WallSqlFunctionStat { + + private int invokeCount; + + public int getInvokeCount() { + return invokeCount; + } + + public void incrementInvokeCount() { + this.invokeCount++; + } + +} diff --git a/src/main/java/com/alibaba/druid/wall/WallSqlStat.java b/src/main/java/com/alibaba/druid/wall/WallSqlStat.java index 52030a5925..6441df38fe 100644 --- a/src/main/java/com/alibaba/druid/wall/WallSqlStat.java +++ b/src/main/java/com/alibaba/druid/wall/WallSqlStat.java @@ -30,13 +30,17 @@ public class WallSqlStat { private final List violations; - public WallSqlStat(Map tableStats){ - this(tableStats, Collections. emptyList()); + private final Map functionStats; + + public WallSqlStat(Map tableStats, Map functionStats){ + this(tableStats, functionStats, Collections. emptyList()); } - public WallSqlStat(Map tableStats, List violations){ + public WallSqlStat(Map tableStats, Map functionStats, + List violations){ this.violations = violations; this.tableStats = tableStats; + this.functionStats = functionStats; } public long incrementAndGetExecuteCount() { @@ -50,6 +54,10 @@ public class WallSqlStat { public Map getTableStats() { return tableStats; } + + public Map getFunctionStats() { + return functionStats; + } public List getViolations() { return violations; diff --git a/src/main/java/com/alibaba/druid/wall/WallTableStat.java b/src/main/java/com/alibaba/druid/wall/WallTableStat.java index c6621f406c..5eafe5eac7 100644 --- a/src/main/java/com/alibaba/druid/wall/WallTableStat.java +++ b/src/main/java/com/alibaba/druid/wall/WallTableStat.java @@ -1,6 +1,6 @@ package com.alibaba.druid.wall; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLongFieldUpdater; @@ -151,7 +151,17 @@ public class WallTableStat { public String toString() { - Map map = new HashMap(); + Map map = toMap(); + + return JSONUtils.toJSONString(map); + } + + public Map toMap() { + Map map = new LinkedHashMap(); + return toMap(map); + } + + public Map toMap(Map map) { if (selectCount > 0) { map.put("selectCount", selectCount); } @@ -176,7 +186,6 @@ public class WallTableStat { if (truncateCount > 0) { map.put("truncateCount", truncateCount); } - - return JSONUtils.toJSONString(map); + return map; } } diff --git a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java index 751a9ccd09..4905e47773 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -799,6 +799,11 @@ public class WallVisitorUtils { } String methodName = x.getMethodName(); + + WallContext context = WallContext.current(); + if (context != null) { + context.incrementFunctionInvoke(methodName); + } if (!visitor.getProvider().checkDenyFunction(methodName)) { addViolation(visitor, "deny function : " + methodName, x); diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenySchemaTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenySchemaTest.java index 89dc026d83..846426a250 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenySchemaTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenySchemaTest.java @@ -23,16 +23,14 @@ import com.alibaba.druid.wall.spi.OracleWallProvider; /** * @author wenshao - * */ public class WallDenySchemaTest extends TestCase { public void testORACLE() throws Exception { String sql = "SELECT F1, F2 FROM ALL_ALL_TABLES"; - + OracleWallProvider provider = new OracleWallProvider(); Assert.assertFalse(provider.checkValid(sql)); - - Assert.assertEquals(1, provider.getDenniedTableStat("ALL_ALL_TABLES").getDenyCount()); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenyTableTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenyTableTest.java index 985fd51cb8..c93ed910a2 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenyTableTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDenyTableTest.java @@ -23,16 +23,14 @@ import com.alibaba.druid.wall.spi.OracleWallProvider; /** * @author wenshao - * */ public class WallDenyTableTest extends TestCase { public void testORACLE() throws Exception { String sql = "SELECT F1, F2 FROM SYS.ABC"; - + OracleWallProvider provider = new OracleWallProvider(); Assert.assertFalse(provider.checkValid(sql)); - - Assert.assertEquals(1, provider.getDenniedSchemaStat("SYS").getDenyCount()); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallReadOnlyTest2.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallReadOnlyTest2.java index 7c189e049f..cc8c844341 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallReadOnlyTest2.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallReadOnlyTest2.java @@ -25,16 +25,18 @@ import com.alibaba.druid.wall.spi.OracleWallProvider; /** * 这个场景,检测可疑的Having条件 + * * @author wenshao - * */ public class WallReadOnlyTest2 extends TestCase { + private WallConfig config = new WallConfig(); - + protected void setUp() throws Exception { config.addReadOnlyTable("members"); } - private String sql = "SELECT F1, F2 members"; + + private String sql = "SELECT F1, F2 members"; private String insert_sql = "INSERT INTO members (FID, FNAME) VALUES (?, ?)"; private String update_sql = "UPDATE members SET FNAME = ? WHERe FID = ?"; private String delete_sql = "DELETE members WHERE FID = ?"; @@ -42,28 +44,20 @@ public class WallReadOnlyTest2 extends TestCase { public void testMySql() throws Exception { MySqlWallProvider provider = new MySqlWallProvider(config); Assert.assertTrue(provider.checkValid(sql)); - - Assert.assertNull(provider.getDenniedTableStat("members")); - + Assert.assertFalse(provider.checkValid(insert_sql)); Assert.assertFalse(provider.checkValid(update_sql)); Assert.assertFalse(provider.checkValid(delete_sql)); - - Assert.assertEquals(3, provider.getDenniedTableStat("members").getDenyCount()); - Assert.assertEquals(3, provider.getDenniedTableStat("Members").getDenyCount()); + } - + public void testORACLE() throws Exception { OracleWallProvider provider = new OracleWallProvider(config); Assert.assertTrue(provider.checkValid(sql)); - - Assert.assertNull(provider.getDenniedTableStat("members")); - + Assert.assertFalse(provider.checkValid(insert_sql)); Assert.assertFalse(provider.checkValid(update_sql)); Assert.assertFalse(provider.checkValid(delete_sql)); - - Assert.assertEquals(3, provider.getDenniedTableStat("members").getDenyCount()); - Assert.assertEquals(3, provider.getDenniedTableStat("Members").getDenyCount()); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java new file mode 100644 index 0000000000..ee404dc669 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java @@ -0,0 +1,38 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.wall.WallContext; +import com.alibaba.druid.wall.WallProvider; +import com.alibaba.druid.wall.WallTableStat; +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +public class WallStatTest_WhiteList extends TestCase { + + protected void setUp() throws Exception { + WallContext.clearContext(); + } + + protected void tearDown() throws Exception { + WallContext.clearContext(); + } + + public void testMySql() throws Exception { + WallProvider provider = new MySqlWallProvider(); + + for (int i = 0; i < 1001; ++i) { + String sql = "select * from t where id = " + i; + Assert.assertTrue(provider.checkValid(sql)); + } + + WallTableStat tableStat = provider.getTableStat("t"); + Assert.assertEquals(1001, tableStat.getSelectCount()); + Assert.assertEquals(0, provider.getBlackListHitCount()); + Assert.assertEquals(0, provider.getWhiteListHitCount()); + Assert.assertEquals(1000, provider.getWhiteList().size()); + Assert.assertEquals(1001, provider.getCheckCount()); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_blackList_1.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_blackList_1.java new file mode 100644 index 0000000000..5a194d5d59 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_blackList_1.java @@ -0,0 +1,39 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.wall.WallContext; +import com.alibaba.druid.wall.WallProvider; +import com.alibaba.druid.wall.WallTableStat; +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +public class WallStatTest_blackList_1 extends TestCase { + + protected void setUp() throws Exception { + WallContext.clearContext(); + } + + protected void tearDown() throws Exception { + WallContext.clearContext(); + } + + public void testMySql() throws Exception { + WallProvider provider = new MySqlWallProvider(); + + for (int i = 0; i < 1001; ++i) { + String sql = "select * from t where id = " + i + " OR 1 = 1"; + Assert.assertFalse(provider.checkValid(sql)); + } + + WallTableStat tableStat = provider.getTableStat("t"); + Assert.assertEquals(1001, tableStat.getSelectCount()); + Assert.assertEquals(0, provider.getBlackListHitCount()); + Assert.assertEquals(0, provider.getWhiteListHitCount()); + Assert.assertEquals(0, provider.getWhiteList().size()); + Assert.assertEquals(1000, provider.getBlackList().size()); + Assert.assertEquals(1001, provider.getCheckCount()); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_function_stats.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_function_stats.java new file mode 100644 index 0000000000..2a12cf9363 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_function_stats.java @@ -0,0 +1,48 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.wall.WallContext; +import com.alibaba.druid.wall.WallFunctionStat; +import com.alibaba.druid.wall.WallProvider; +import com.alibaba.druid.wall.WallTableStat; +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +public class WallStatTest_function_stats extends TestCase { + + private String sql = "select len(fname), len(fdesc) from t"; + + protected void setUp() throws Exception { + WallContext.clearContext(); + } + + protected void tearDown() throws Exception { + WallContext.clearContext(); + } + + public void testMySql() throws Exception { + WallProvider provider = new MySqlWallProvider(); + Assert.assertTrue(provider.checkValid(sql)); + { + WallTableStat tableStat = provider.getTableStat("t"); + Assert.assertEquals(1, tableStat.getSelectCount()); + } + { + WallFunctionStat functionStat = provider.getFunctionStat("len"); + Assert.assertEquals(2, functionStat.getInvokeCount()); + } + Assert.assertTrue(provider.checkValid(sql)); + { + WallTableStat tableStat = provider.getTableStat("t"); + Assert.assertEquals(2, tableStat.getSelectCount()); + } + { + WallFunctionStat functionStat = provider.getFunctionStat("len"); + Assert.assertEquals(4, functionStat.getInvokeCount()); + } + } + + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/SpringIbatisFilterTest.java b/src/test/java/com/alibaba/druid/bvt/pool/SpringIbatisFilterTest.java index b93b3b3335..2d630d5e5e 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/SpringIbatisFilterTest.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/SpringIbatisFilterTest.java @@ -18,6 +18,8 @@ package com.alibaba.druid.bvt.pool; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import java.util.Collections; +import java.util.Map; import java.util.Properties; import java.util.concurrent.atomic.AtomicLong; @@ -34,6 +36,8 @@ import com.alibaba.druid.proxy.jdbc.ConnectionProxy; import com.alibaba.druid.spring.IUserService; import com.alibaba.druid.spring.User; import com.alibaba.druid.stat.DruidDataSourceStatManager; +import com.alibaba.druid.stat.DruidStatService; +import com.alibaba.druid.support.json.JSONUtils; public class SpringIbatisFilterTest extends TestCase { @@ -101,6 +105,11 @@ public class SpringIbatisFilterTest extends TestCase { conn.close(); } + Assert.assertEquals(1, DruidDataSourceStatManager.getInstance().getDataSourceList().size()); + + Map wallStats = DruidStatService.getInstance().getWallStatMap(Collections.emptyMap()); + + System.out.println("wall-stats : " + JSONUtils.toJSONString(wallStats)); context.close();