forked from Archives/Athou_commafeed
cannot loop forever
This commit is contained in:
@@ -1,12 +1,20 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import org.apache.commons.jexl2.Expression;
|
|
||||||
import org.apache.commons.jexl2.JexlContext;
|
import org.apache.commons.jexl2.JexlContext;
|
||||||
import org.apache.commons.jexl2.JexlEngine;
|
import org.apache.commons.jexl2.JexlEngine;
|
||||||
|
import org.apache.commons.jexl2.JexlException;
|
||||||
import org.apache.commons.jexl2.JexlInfo;
|
import org.apache.commons.jexl2.JexlInfo;
|
||||||
import org.apache.commons.jexl2.MapContext;
|
import org.apache.commons.jexl2.MapContext;
|
||||||
|
import org.apache.commons.jexl2.Script;
|
||||||
import org.apache.commons.jexl2.introspection.JexlMethod;
|
import org.apache.commons.jexl2.introspection.JexlMethod;
|
||||||
import org.apache.commons.jexl2.introspection.JexlPropertyGet;
|
import org.apache.commons.jexl2.introspection.JexlPropertyGet;
|
||||||
import org.apache.commons.jexl2.introspection.Uberspect;
|
import org.apache.commons.jexl2.introspection.Uberspect;
|
||||||
@@ -63,12 +71,17 @@ public class FeedEntryFilter {
|
|||||||
|
|
||||||
private final String filter;
|
private final String filter;
|
||||||
|
|
||||||
public boolean matchesEntry(FeedEntry entry) {
|
public boolean matchesEntry(FeedEntry entry) throws FeedEntryFilterException {
|
||||||
if (StringUtils.isBlank(filter)) {
|
if (StringUtils.isBlank(filter)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression expression = ENGINE.createExpression(filter);
|
Script script = null;
|
||||||
|
try {
|
||||||
|
script = ENGINE.createScript(filter);
|
||||||
|
} catch (JexlException e) {
|
||||||
|
throw new FeedEntryFilterException("Exception while parsing expression " + filter, e);
|
||||||
|
}
|
||||||
|
|
||||||
JexlContext context = new MapContext();
|
JexlContext context = new MapContext();
|
||||||
context.set("title", Jsoup.parse(entry.getContent().getTitle()).text().toLowerCase());
|
context.set("title", Jsoup.parse(entry.getContent().getTitle()).text().toLowerCase());
|
||||||
@@ -76,6 +89,25 @@ public class FeedEntryFilter {
|
|||||||
context.set("content", Jsoup.parse(entry.getContent().getContent()).text().toLowerCase());
|
context.set("content", Jsoup.parse(entry.getContent().getContent()).text().toLowerCase());
|
||||||
context.set("url", entry.getUrl().toLowerCase());
|
context.set("url", entry.getUrl().toLowerCase());
|
||||||
|
|
||||||
return (boolean) expression.evaluate(context);
|
Callable<Object> callable = script.callable(context);
|
||||||
|
Future<Object> future = Executors.newFixedThreadPool(1).submit(callable);
|
||||||
|
Object result = null;
|
||||||
|
try {
|
||||||
|
result = future.get(500, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new FeedEntryFilterException("interrupted while evaluating expression " + filter, e);
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw new FeedEntryFilterException("Exception while evaluating expression " + filter, e);
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
throw new FeedEntryFilterException("Took too long evaluating expression " + filter, e);
|
||||||
|
}
|
||||||
|
return (boolean) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public static class FeedEntryFilterException extends Exception {
|
||||||
|
public FeedEntryFilterException(String message, Throwable t) {
|
||||||
|
super(message, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.apache.commons.codec.digest.DigestUtils;
|
|||||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter;
|
import com.commafeed.backend.feed.FeedEntryFilter;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryFilter.FeedEntryFilterException;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryContent;
|
import com.commafeed.backend.model.FeedEntryContent;
|
||||||
@@ -52,7 +53,7 @@ public class FeedUpdateService {
|
|||||||
boolean matches = true;
|
boolean matches = true;
|
||||||
try {
|
try {
|
||||||
matches = filter.matchesEntry(entry);
|
matches = filter.matchesEntry(entry);
|
||||||
} catch (Exception e) {
|
} catch (FeedEntryFilterException e) {
|
||||||
log.error("could not evaluate filter {}", sub.getFilter(), e);
|
log.error("could not evaluate filter {}", sub.getFilter(), e);
|
||||||
}
|
}
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.commafeed.backend.dao.FeedCategoryDAO;
|
|||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter;
|
import com.commafeed.backend.feed.FeedEntryFilter;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryFilter.FeedEntryFilterException;
|
||||||
import com.commafeed.backend.feed.FeedFetcher;
|
import com.commafeed.backend.feed.FeedFetcher;
|
||||||
import com.commafeed.backend.feed.FeedQueues;
|
import com.commafeed.backend.feed.FeedQueues;
|
||||||
import com.commafeed.backend.feed.FeedUtils;
|
import com.commafeed.backend.feed.FeedUtils;
|
||||||
@@ -437,7 +438,7 @@ public class FeedREST {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
new FeedEntryFilter(req.getFilter()).matchesEntry(TEST_ENTRY);
|
new FeedEntryFilter(req.getFilter()).matchesEntry(TEST_ENTRY);
|
||||||
} catch (Exception e) {
|
} catch (FeedEntryFilterException e) {
|
||||||
Throwable root = Throwables.getRootCause(e);
|
Throwable root = Throwables.getRootCause(e);
|
||||||
return Response.status(Status.BAD_REQUEST).entity(root.getMessage()).build();
|
return Response.status(Status.BAD_REQUEST).entity(root.getMessage()).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import org.apache.commons.jexl2.JexlException;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.commafeed.backend.feed.FeedEntryFilter.FeedEntryFilterException;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryContent;
|
import com.commafeed.backend.model.FeedEntryContent;
|
||||||
|
|
||||||
@@ -27,39 +27,45 @@ public class FeedEntryFilterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void emptyFilterMatchesFilter() {
|
public void emptyFilterMatchesFilter() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter(null);
|
FeedEntryFilter filter = new FeedEntryFilter(null);
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
Assert.assertTrue(filter.matchesEntry(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blankFilterMatchesFilter() {
|
public void blankFilterMatchesFilter() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("");
|
FeedEntryFilter filter = new FeedEntryFilter("");
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
Assert.assertTrue(filter.matchesEntry(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleExpression() {
|
public void simpleExpression() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("author eq 'athou'");
|
FeedEntryFilter filter = new FeedEntryFilter("author eq 'athou'");
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
Assert.assertTrue(filter.matchesEntry(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = JexlException.class)
|
@Test(expected = FeedEntryFilterException.class)
|
||||||
public void newIsDisabled() {
|
public void newIsDisabled() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("null eq new ('java.lang.String', 'athou')");
|
FeedEntryFilter filter = new FeedEntryFilter("null eq new ('java.lang.String', 'athou')");
|
||||||
filter.matchesEntry(entry);
|
filter.matchesEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = JexlException.class)
|
@Test(expected = FeedEntryFilterException.class)
|
||||||
public void getClassMethodIsDisabled() {
|
public void getClassMethodIsDisabled() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("null eq ''.getClass()");
|
FeedEntryFilter filter = new FeedEntryFilter("null eq ''.getClass()");
|
||||||
filter.matchesEntry(entry);
|
filter.matchesEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dotClassIsDisabled() {
|
public void dotClassIsDisabled() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("null eq ''.class");
|
FeedEntryFilter filter = new FeedEntryFilter("null eq ''.class");
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
Assert.assertTrue(filter.matchesEntry(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FeedEntryFilterException.class)
|
||||||
|
public void cannotLoopForever() throws FeedEntryFilterException {
|
||||||
|
FeedEntryFilter filter = new FeedEntryFilter("while(true) {}");
|
||||||
|
filter.matchesEntry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user