+++ /dev/null
-/*\r
- * Copyright (C) 2001, 2002 The Mir-coders group\r
- *\r
- * This file is part of Mir.\r
- *\r
- * Mir is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * Mir is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with Mir; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- *\r
- * In addition, as a special exception, The Mir-coders gives permission to link\r
- * the code of this program with any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two. You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries. If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mircoders.localizer.basic.filters;\r
-\r
-import mircoders.localizer.basic.MirBasicAntiAbuseFilterTypes;\r
-import mircoders.entity.EntityComment;\r
-\r
-import java.util.*;\r
-\r
-import mir.util.StringRoutines;\r
-import mir.entity.Entity;\r
-import mir.session.Request;\r
-\r
-/**\r
- * A ip-based throttling filter.\r
- *\r
- * <p>\r
- * Expressions have the form <time in minutes>:<posting limit>\r
- */\r
-public class ThrottleFilter extends MirBasicAntiAbuseFilterTypes.BasicFilterType {\r
- private long overallHorizon;\r
-\r
- private ThrottleManager throttleManager;\r
-\r
- public ThrottleFilter(String aName, long anOverallHorizon) {\r
- super(aName);\r
-\r
- overallHorizon = anOverallHorizon;\r
- throttleManager = new ThrottleManager(overallHorizon);\r
- }\r
-\r
- /** * {@inheritDoc} */\r
- public boolean validate(String anExpression) {\r
- List parts = StringRoutines.splitString(anExpression.trim(), ":");\r
-\r
- try {\r
- if (parts.size()==2) {\r
- Integer.parseInt((String) parts.get(0));\r
- Integer.parseInt((String) parts.get(1));\r
-\r
- return true;\r
- }\r
- }\r
- catch (Throwable t) {\r
- }\r
-\r
- return false;\r
- }\r
-\r
- /**\r
- *\r
- */\r
- public boolean test(String anExpression, Entity anEntity, Request aRequest) {\r
- String ip = aRequest.getHeader("ip");\r
- int limit;\r
- long period;\r
-\r
- List parts = StringRoutines.splitString(anExpression, ":");\r
-\r
- try {\r
- period = Integer.parseInt((String) parts.get(0))*1000*60;\r
- limit = Integer.parseInt((String) parts.get(1));\r
- }\r
- catch (Throwable t) {\r
- return false;\r
- }\r
-\r
- return throttleManager.addMessage(ip, anEntity, limit, period);\r
- };\r
-\r
- private class ThrottleManager {\r
- private Map throttles;\r
- private long overallHorizon;\r
- private Thread cleanUpThread;\r
-\r
- public ThrottleManager(long anOverallHorizon) {\r
- throttles = new HashMap();\r
- overallHorizon = anOverallHorizon;\r
-\r
- cleanUpThread = new Thread() {\r
- public void run() {\r
- while (true) {\r
- synchronized(throttles) {\r
- List toDelete = new ArrayList();\r
- Iterator i = throttles.entrySet().iterator();\r
-\r
- while (i.hasNext()) {\r
- Map.Entry entry = (Map.Entry) i.next();\r
- try {\r
- if (((Throttle) entry.getValue()).flush()) {\r
- toDelete.add(entry.getKey());\r
- }\r
- }\r
- catch (Throwable t) {\r
- toDelete.add(entry.getKey());\r
- }\r
- }\r
-\r
- i = toDelete.iterator();\r
- while (i.hasNext()) {\r
- throttles.remove(i.next());\r
- }\r
- }\r
- try {\r
- Thread.sleep(60*10*1000);\r
- }\r
- catch (InterruptedException e) {\r
- break;\r
- }\r
- }\r
- }\r
- };\r
-\r
- cleanUpThread.setDaemon(true);\r
- cleanUpThread.start();\r
- }\r
-\r
- public boolean addMessage(String anIP, Entity anEntity, int aLimit, long aPeriod) {\r
- synchronized (throttles) {\r
- Throttle throttle = (Throttle) throttles.get(anIP);\r
-\r
- if (throttle==null) {\r
- throttle = new Throttle(overallHorizon);\r
- throttles.put(anIP, throttle);\r
- }\r
- return throttle.addMessage(anEntity, aLimit, aPeriod);\r
- }\r
- }\r
-\r
- private class Throttle {\r
- private List messages;\r
- private long horizon;\r
-\r
- public Throttle(long aHorizon) {\r
- messages = new ArrayList();\r
- horizon = aHorizon;\r
- }\r
-\r
- public boolean flush() {\r
- long limit = System.currentTimeMillis() - horizon;\r
-\r
- while (messages.size()>0 && ((Message) messages.get(0)).getTime()<=limit) {\r
- messages.remove(0);\r
- }\r
-\r
- return messages.size()==0;\r
- }\r
-\r
- public boolean addMessage(Entity anEntity, int aLimit, long aPeriod) {\r
- Message lastMessage=null;\r
- if (messages.size()>0) {\r
- lastMessage = (Message) messages.get(messages.size()-1);\r
- }\r
-\r
- Message newMessage = new Message(anEntity.getId(),\r
- anEntity instanceof EntityComment, System.currentTimeMillis());\r
-\r
- if (!newMessage.equals(lastMessage))\r
- messages.add(newMessage);\r
-\r
- if (messages.size()>=aLimit) {\r
- Message message = (Message) messages.get(messages.size()-aLimit);\r
- return (System.currentTimeMillis()-message.getTime())<aPeriod;\r
- }\r
-\r
- return false;\r
- }\r
-\r
- private class Message {\r
- private String id;\r
- private boolean isComment;\r
- private long time;\r
-\r
- public Message(String anId, boolean anIsComment, long aTime) {\r
- id = anId;\r
- isComment = anIsComment;\r
- time = aTime;\r
- }\r
-\r
- public String getId() {\r
- return id;\r
- }\r
-\r
- public boolean getIsComment() {\r
- return isComment;\r
- }\r
-\r
- public long getTime() {\r
- return time;\r
- }\r
-\r
- public int hashCode() {\r
- return getId().hashCode();\r
- }\r
-\r
- public boolean equals(Object anObject) {\r
- if (anObject instanceof Message) {\r
- Message that = (Message) anObject;\r
-\r
- if (that.getId().equals(getId()) && that.getIsComment() == getIsComment()) {\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
- }\r
- }\r
- }\r
- }\r
-}\r