diff --git a/bubble-server/src/main/java/bubble/resources/stream/FilterHttpResource.java b/bubble-server/src/main/java/bubble/resources/stream/FilterHttpResource.java index 6341ae05..e95c05e5 100644 --- a/bubble-server/src/main/java/bubble/resources/stream/FilterHttpResource.java +++ b/bubble-server/src/main/java/bubble/resources/stream/FilterHttpResource.java @@ -274,7 +274,7 @@ public class FilterHttpResource { } final boolean isLast = last != null && last; - return ruleEngine.applyRulesToChunkAndSendResponse(request, encoding, contentLength, filterRequest, isLast); + return ruleEngine.applyRulesToChunkAndSendResponse(request, encoding, contentLength, contentType, filterRequest, isLast); } public Response passthru(@Context ContainerRequest request) { return ruleEngine.passthru(request); } diff --git a/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java b/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java index 469fd80c..f8781064 100644 --- a/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java +++ b/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java @@ -13,10 +13,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.github.jknack.handlebars.Handlebars; import lombok.Getter; import lombok.Setter; +import org.cobbzilla.util.http.HttpContentTypeAndCharset; import org.cobbzilla.util.system.Bytes; import org.cobbzilla.wizard.cache.redis.RedisService; import org.springframework.beans.factory.annotation.Autowired; +import static org.cobbzilla.util.http.HttpContentTypes.TEXT_HTML; + public abstract class AbstractAppRuleDriver implements AppRuleDriver { public static final int RESPONSE_BUFSIZ = (int) (64 * Bytes.KB); @@ -48,6 +51,11 @@ public abstract class AbstractAppRuleDriver implements AppRuleDriver { protected String getDataId(String requestId) { return getDataId(requestId, matcher); } public static String getDataId(String requestId, AppMatcher matcher) { return requestId+"/"+matcher.getUuid(); } + public boolean isHtml (String contentType) { + final HttpContentTypeAndCharset type = new HttpContentTypeAndCharset(contentType); + return type.isContentType(TEXT_HTML); + } + @Override public void init(JsonNode config, JsonNode userConfig, AppRule rule, diff --git a/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java b/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java index 8dc432cb..321d8f3a 100644 --- a/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java +++ b/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java @@ -49,12 +49,12 @@ public interface AppRuleDriver { default InputStream doFilterRequest(InputStream in) { return in; } - default InputStream filterResponse(String requestId, String[] filters, InputStream in) { - if (hasNext()) return doFilterResponse(requestId, filters, getNext().filterResponse(requestId, filters, in)); - return doFilterResponse(requestId, filters, in); + default InputStream filterResponse(String requestId, String contentType, String[] filters, InputStream in) { + if (hasNext()) return doFilterResponse(requestId, contentType, filters, getNext().filterResponse(requestId, contentType, filters, in)); + return doFilterResponse(requestId, contentType, filters, in); } - default InputStream doFilterResponse(String requestId, String[] filters, InputStream in) { return in; } + default InputStream doFilterResponse(String requestId, String contentType, String[] filters, InputStream in) { return in; } default String resolveResource(String res, Map ctx) { final String resource = locateResource(res); diff --git a/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlock.java b/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlock.java index 6e799865..ef8a39af 100644 --- a/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlock.java +++ b/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlock.java @@ -88,8 +88,10 @@ public class BubbleBlock extends TrafficAnalytics { } } - @Override public InputStream doFilterResponse(String requestId, String[] filters, InputStream in) { - if (empty(filters)) return in; + @Override public InputStream doFilterResponse(String requestId, String contentType, String[] filters, InputStream in) { + + if (empty(filters) || !isHtml(contentType)) return in; + final String replacement = ""; final RegexReplacementFilter filter = new RegexReplacementFilter("", replacement); final RegexFilterReader reader = new RegexFilterReader(new InputStreamReader(in), filter).setMaxMatches(1); diff --git a/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlocker.java b/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlocker.java index 9b961f3c..9c3b1753 100644 --- a/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlocker.java +++ b/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlocker.java @@ -27,7 +27,9 @@ public class JsUserBlocker extends AbstractAppRuleDriver { public static final String CTX_APPLY_BLOCKS_JS = "APPLY_BLOCKS_JS"; - @Override public InputStream doFilterResponse(String requestId, String[] filters, InputStream in) { + @Override public InputStream doFilterResponse(String requestId, String contentType, String[] filters, InputStream in) { + if (!isHtml(contentType)) return in; + final String replacement = ""; final RegexReplacementFilter filter = new RegexReplacementFilter("", replacement); final RegexFilterReader reader = new RegexFilterReader(new InputStreamReader(in), filter).setMaxMatches(1); diff --git a/bubble-server/src/main/java/bubble/rule/social/block/UserBlocker.java b/bubble-server/src/main/java/bubble/rule/social/block/UserBlocker.java index 77811b3b..ea20bfa3 100644 --- a/bubble-server/src/main/java/bubble/rule/social/block/UserBlocker.java +++ b/bubble-server/src/main/java/bubble/rule/social/block/UserBlocker.java @@ -47,7 +47,9 @@ public class UserBlocker extends AbstractAppRuleDriver { protected UserBlockerConfig configObject() { return json(getFullConfig(), UserBlockerConfig.class); } - @Override public InputStream doFilterResponse(String requestId, String[] filters, InputStream in) { + @Override public InputStream doFilterResponse(String requestId, String contentType, String[] filters, InputStream in) { + if (!isHtml(contentType)) return in; + final UserBlockerStreamFilter filter = new UserBlockerStreamFilter(requestId, matcher, rule, configuration.getHttp().getBaseUri()); filter.configure(getFullConfig()); filter.setDataDAO(appDataDAO); diff --git a/bubble-server/src/main/java/bubble/service/stream/RuleEngineService.java b/bubble-server/src/main/java/bubble/service/stream/RuleEngineService.java index c477b7fc..0681d559 100644 --- a/bubble-server/src/main/java/bubble/service/stream/RuleEngineService.java +++ b/bubble-server/src/main/java/bubble/service/stream/RuleEngineService.java @@ -58,6 +58,7 @@ import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.MINUTES; import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH; import static org.apache.commons.lang3.ArrayUtils.EMPTY_BYTE_ARRAY; +import static org.apache.http.HttpHeaders.CONTENT_TYPE; import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.daemon.ZillaRuntime.hashOf; import static org.cobbzilla.util.http.HttpStatusCodes.OK; @@ -127,7 +128,9 @@ public class RuleEngineService { final CloseableHttpResponse proxyResponse = httpClient.execute(get); // filter response. when stream is closed, close http client - final InputStream responseEntity = firstRule.getDriver().filterResponse(filterRequest.getId(), filterRequest.getFilters(), new HttpClosingFilterInputStream(httpClient, proxyResponse)); + final Header contentTypeHeader = proxyResponse.getFirstHeader(CONTENT_TYPE); + final String contentType = contentTypeHeader == null ? null : contentTypeHeader.getValue(); + final InputStream responseEntity = firstRule.getDriver().filterResponse(filterRequest.getId(), contentType, filterRequest.getFilters(), new HttpClosingFilterInputStream(httpClient, proxyResponse)); // send response return sendResponse(responseEntity, proxyResponse); @@ -146,6 +149,7 @@ public class RuleEngineService { public Response applyRulesToChunkAndSendResponse(ContainerRequest request, HttpContentEncodingType contentEncoding, Integer contentLength, + String contentType, FilterHttpRequest filterRequest, boolean last) throws IOException { @@ -153,7 +157,8 @@ public class RuleEngineService { // have we seen this request before? final ActiveStreamState state = activeProcessors.computeIfAbsent(filterRequest.getId(), - k -> new ActiveStreamState(k, contentEncoding, filterRequest.getFilters(), initRules(filterRequest.getAccount(), filterRequest.getDevice(), filterRequest.getMatchers()))); + k -> new ActiveStreamState(k, contentEncoding, contentType, filterRequest.getFilters(), + initRules(filterRequest.getAccount(), filterRequest.getDevice(), filterRequest.getMatchers()))); final byte[] chunk = toBytes(request.getEntityStream(), contentLength); if (last) { if (log.isDebugEnabled()) log.debug("applyRulesToChunkAndSendResponse: adding LAST stream"); @@ -258,6 +263,7 @@ public class RuleEngineService { private String requestId; private HttpContentEncodingType encoding; + private String contentType; private String[] filters; private MultiStream multiStream; private AppRuleHarness firstRule; @@ -267,10 +273,12 @@ public class RuleEngineService { public ActiveStreamState(String requestId, HttpContentEncodingType encoding, + String contentType, String[] filters, List rules) { this.requestId = requestId; this.encoding = encoding; + this.contentType = contentType; this.filters = filters; this.firstRule = rules.get(0); } @@ -280,7 +288,7 @@ public class RuleEngineService { totalBytesWritten += chunk.length; if (multiStream == null) { multiStream = new MultiStream(new ByteArrayInputStream(chunk)); - output = outputStream(firstRule.getDriver().filterResponse(requestId, filters, inputStream(multiStream))); + output = outputStream(firstRule.getDriver().filterResponse(requestId, contentType, filters, inputStream(multiStream))); } else { multiStream.addStream(new ByteArrayInputStream(chunk)); } @@ -291,7 +299,7 @@ public class RuleEngineService { totalBytesWritten += chunk.length; if (multiStream == null) { multiStream = new MultiStream(new ByteArrayInputStream(chunk), true); - output = outputStream(firstRule.getDriver().filterResponse(requestId, filters, inputStream(multiStream))); + output = outputStream(firstRule.getDriver().filterResponse(requestId, contentType, filters, inputStream(multiStream))); } else { multiStream.addLastStream(new ByteArrayInputStream(chunk)); } diff --git a/utils/cobbzilla-utils b/utils/cobbzilla-utils index a1785021..44730182 160000 --- a/utils/cobbzilla-utils +++ b/utils/cobbzilla-utils @@ -1 +1 @@ -Subproject commit a17850215a54359929b83a9c5b061fd608090444 +Subproject commit 44730182976085dd171cf7035fae5953a8841368