@@ -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); } | |||
@@ -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, | |||
@@ -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<String, Object> ctx) { | |||
final String resource = locateResource(res); | |||
@@ -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 = "<head><script>" + getBubbleJs(requestId, filters) + "</script>"; | |||
final RegexReplacementFilter filter = new RegexReplacementFilter("<head>", replacement); | |||
final RegexFilterReader reader = new RegexFilterReader(new InputStreamReader(in), filter).setMaxMatches(1); | |||
@@ -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 = "<head><script>" + getBubbleJs(requestId) + "</script>"; | |||
final RegexReplacementFilter filter = new RegexReplacementFilter("<head>", replacement); | |||
final RegexFilterReader reader = new RegexFilterReader(new InputStreamReader(in), filter).setMaxMatches(1); | |||
@@ -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); | |||
@@ -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<AppRuleHarness> 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)); | |||
} | |||
@@ -1 +1 @@ | |||
Subproject commit a17850215a54359929b83a9c5b061fd608090444 | |||
Subproject commit 44730182976085dd171cf7035fae5953a8841368 |