mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improve WallFilter
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
public class WallContext {
|
||||
|
||||
private final static ThreadLocal<WallContext> contextLocal = new ThreadLocal<WallContext>();
|
||||
|
||||
private WallSqlStat sqlState;
|
||||
|
||||
public static WallContext createIfNotExists() {
|
||||
WallContext context = contextLocal.get();
|
||||
if (context == null) {
|
||||
context = new WallContext();
|
||||
contextLocal.set(context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public static WallContext current() {
|
||||
return contextLocal.get();
|
||||
}
|
||||
|
||||
public static void clearContext() {
|
||||
contextLocal.remove();
|
||||
}
|
||||
|
||||
public WallSqlStat getSqlState() {
|
||||
return sqlState;
|
||||
}
|
||||
|
||||
public void setSqlState(WallSqlStat sqlState) {
|
||||
this.sqlState = sqlState;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -159,139 +159,235 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
|
||||
@Override
|
||||
public void statement_addBatch(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||
sql = check(sql);
|
||||
chain.statement_addBatch(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
chain.statement_addBatch(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int autoGeneratedKeys) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int resultSetType, int resultSetConcurrency,
|
||||
int resultSetHoldability) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int[] columnIndexes) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnIndexes);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnIndexes);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, String[] columnNames) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnNames);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnNames);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
|
||||
int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
|
||||
int resultSetType, int resultSetConcurrency,
|
||||
int resultSetHoldability) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, autoGeneratedKeys);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, autoGeneratedKeys);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnIndexes);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnIndexes);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnNames);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnNames);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeQuery(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeQuery(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnIndexes);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnIndexes);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnNames);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnNames);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
public String check(String sql) throws SQLException {
|
||||
@@ -355,7 +451,7 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
if (isLogViolation()) {
|
||||
LOG.error("not support method : Connection.getMetdataData");
|
||||
}
|
||||
|
||||
|
||||
if (throwException) {
|
||||
throw new WallSQLException("not support method : Connection.getMetdataData");
|
||||
} else {
|
||||
@@ -369,4 +465,16 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
public long getViolationCount() {
|
||||
return this.violationCount.get();
|
||||
}
|
||||
|
||||
public void resetViolationCount() {
|
||||
this.violationCount.set(0);
|
||||
}
|
||||
|
||||
public void clearWhiteList() {
|
||||
this.provider.clearCache();
|
||||
}
|
||||
|
||||
public boolean checkValid(String sql) {
|
||||
return provider.checkValid(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,10 @@ public interface WallFilterMBean {
|
||||
String check(String sql) throws SQLException;
|
||||
|
||||
long getViolationCount();
|
||||
|
||||
void resetViolationCount();
|
||||
|
||||
void clearWhiteList();
|
||||
|
||||
boolean checkValid(String sql);
|
||||
}
|
||||
|
||||
@@ -32,20 +32,17 @@ import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
|
||||
|
||||
public abstract class WallProvider {
|
||||
|
||||
// Dummy value to associate with an Object in the backing Map
|
||||
private static final Object PRESENT = new Object();
|
||||
private LinkedHashMap<String, WallSqlStat> whiteList;
|
||||
|
||||
private LinkedHashMap<String, Object> whiteList;
|
||||
private int whileListMaxSize = 1024;
|
||||
|
||||
private int whileListMaxSize = 1024;
|
||||
private int whiteSqlMaxLength = 1024; // 1k
|
||||
|
||||
private int whiteSqlMaxLength = 1024; // 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<Boolean> privileged = new ThreadLocal<Boolean>();
|
||||
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
|
||||
|
||||
public WallProvider(WallConfig config){
|
||||
this.config = config;
|
||||
@@ -59,10 +56,10 @@ public abstract class WallProvider {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (whiteList == null) {
|
||||
whiteList = new LRUCache<String, Object>(whileListMaxSize);
|
||||
whiteList = new LRUCache<String, WallSqlStat>(whileListMaxSize);
|
||||
}
|
||||
|
||||
whiteList.put(sql, PRESENT);
|
||||
whiteList.put(sql, new WallSqlStat());
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
@@ -81,8 +78,12 @@ public abstract class WallProvider {
|
||||
|
||||
return hashSet;
|
||||
}
|
||||
|
||||
|
||||
public void clearCache() {
|
||||
clearWhiteList();
|
||||
}
|
||||
|
||||
public void clearWhiteList() {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (whiteList != null) {
|
||||
@@ -92,20 +93,24 @@ public abstract class WallProvider {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean whiteContains(String sql) {
|
||||
|
||||
public WallSqlStat getWhiteSql(String sql) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
if (whiteList == null) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
return whiteList.get(sql) != null;
|
||||
|
||||
return whiteList.get(sql);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean whiteContains(String sql) {
|
||||
return getWhiteSql(sql) != null;
|
||||
}
|
||||
|
||||
public abstract SQLStatementParser createParser(String sql);
|
||||
|
||||
public abstract WallVisitor createWallVisitor();
|
||||
@@ -113,7 +118,8 @@ public abstract class WallProvider {
|
||||
public abstract ExportParameterVisitor createExportParameterVisitor();
|
||||
|
||||
public boolean checkValid(String sql) {
|
||||
return check(sql).getViolations().isEmpty();
|
||||
WallCheckResult result = check(sql);
|
||||
return result.getViolations().isEmpty();
|
||||
}
|
||||
|
||||
public WallCheckResult check(String sql) {
|
||||
@@ -124,8 +130,9 @@ public abstract class WallProvider {
|
||||
}
|
||||
|
||||
// first step, check whiteList
|
||||
boolean isWhite = whiteContains(sql);
|
||||
if (isWhite) {
|
||||
WallSqlStat sqlStat = getWhiteSql(sql);
|
||||
if (sqlStat != null) {
|
||||
sqlStat.incrementAndGetExecuteCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -176,13 +183,13 @@ public abstract class WallProvider {
|
||||
result.getViolations().addAll(visitor.getViolations());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static boolean ispPivileged() {
|
||||
Boolean value = privileged.get();
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return value.booleanValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
public class WallSqlStat {
|
||||
|
||||
private volatile long executeCount;
|
||||
|
||||
final static AtomicLongFieldUpdater<WallSqlStat> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
|
||||
"executeCount");
|
||||
|
||||
public long incrementAndGetExecuteCount() {
|
||||
return executeCountUpdater.incrementAndGet(this);
|
||||
}
|
||||
|
||||
public long getExecuteCount() {
|
||||
return executeCount;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user