package org.browsermob.proxy.bricks; import com.google.inject.Inject; import com.google.inject.name.Named; import com.google.sitebricks.At; import com.google.sitebricks.client.transport.Json; import com.google.sitebricks.headless.Reply; import com.google.sitebricks.headless.Request; import com.google.sitebricks.headless.Service; import com.google.sitebricks.http.Delete; import com.google.sitebricks.http.Get; import com.google.sitebricks.http.Post; import com.google.sitebricks.http.Put; import org.browsermob.core.har.Har; import org.browsermob.proxy.ProxyManager; import org.browsermob.proxy.ProxyServer; import org.browsermob.proxy.http.BrowserMobHttpRequest; import org.browsermob.proxy.http.BrowserMobHttpResponse; import org.browsermob.proxy.http.RequestInterceptor; import org.browsermob.proxy.http.ResponseInterceptor; import org.browsermob.proxy.util.Log; import org.java_bandwidthlimiter.StreamManager; import javax.script.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; @At("/proxy") @Service public class ProxyResource { private static final Log LOG = new Log(); private ProxyManager proxyManager; @Inject public ProxyResource(ProxyManager proxyManager) { this.proxyManager = proxyManager; } @Post public Reply<ProxyDescriptor> newProxy(Request request) throws Exception { String systemProxyHost = System.getProperty("http.proxyHost"); String systemProxyPort = System.getProperty("http.proxyPort"); String httpProxy = request.param("httpProxy"); Hashtable<String, String> options = new Hashtable<String, String>(); // If the upstream proxy is specified via query params that should override any default system level proxy. if (httpProxy != null) { options.put("httpProxy", httpProxy); } else if ((systemProxyHost != null) && (systemProxyPort != null)) { options.put("httpProxy", String.format("%s:%s", systemProxyHost, systemProxyPort)); } String paramPort = request.param("port"); int port = 0; if (paramPort != null) { port = Integer.parseInt(paramPort); ProxyServer proxy = proxyManager.create(options, port); } else { ProxyServer proxy = proxyManager.create(options); port = proxy.getPort(); } return Reply.with(new ProxyDescriptor(port)).as(Json.class); } @Get @At("/:port/har") public Reply<Har> getHar(@Named("port") int port) { ProxyServer proxy = proxyManager.get(port); Har har = proxy.getHar(); return Reply.with(har).as(Json.class); } @Put @At("/:port/har") public Reply<?> newHar(@Named("port") int port, Request request) { String initialPageRef = request.param("initialPageRef"); ProxyServer proxy = proxyManager.get(port); Har oldHar = proxy.newHar(initialPageRef); String captureHeaders = request.param("captureHeaders"); String captureContent = request.param("captureContent"); String captureBinaryContent = request.param("captureBinaryContent"); proxy.setCaptureHeaders(Boolean.parseBoolean(captureHeaders)); proxy.setCaptureContent(Boolean.parseBoolean(captureContent)); proxy.setCaptureBinaryContent(Boolean.parseBoolean(captureBinaryContent)); if (oldHar != null) { return Reply.with(oldHar).as(Json.class); } else { return Reply.saying().noContent(); } } @Put @At("/:port/har/pageRef") public Reply<?> setPage(@Named("port") int port, Request request) { String pageRef = request.param("pageRef"); ProxyServer proxy = proxyManager.get(port); proxy.newPage(pageRef); return Reply.saying().ok(); } @Put @At("/:port/blacklist") public Reply<?> blacklist(@Named("port") int port, Request request) { String blacklist = request.param("regex"); int responseCode = parseResponseCode(request.param("status")); ProxyServer proxy = proxyManager.get(port); proxy.blacklistRequests(blacklist, responseCode); return Reply.saying().ok(); } @Put @At("/:port/whitelist") public Reply<?> whitelist(@Named("port") int port, Request request) { String regex = request.param("regex"); int responseCode = parseResponseCode(request.param("status")); ProxyServer proxy = proxyManager.get(port); proxy.whitelistRequests(regex.split(","), responseCode); return Reply.saying().ok(); } @Post @At("/:port/auth/basic/:domain") public Reply<?> autoBasicAuth(@Named("port") int port, @Named("domain") String domain, Request request) { Map<String, String> credentials = request.read(HashMap.class).as(Json.class); ProxyServer proxy = proxyManager.get(port); proxy.autoBasicAuthorization(domain, credentials.get("username"), credentials.get("password")); return Reply.saying().ok(); } @Post @At("/:port/headers") public Reply<?> updateHeaders(@Named("port") int port, Request request) { ProxyServer proxy = proxyManager.get(port); Map<String, String> headers = request.read(Map.class).as(Json.class); for (Map.Entry<String, String> entry : headers.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); proxy.addHeader(key, value); } return Reply.saying().ok(); } @Post @At("/:port/interceptor/response") public Reply<?> addResponseInterceptor(@Named("port") int port, Request request) throws IOException, ScriptException { ProxyServer proxy = proxyManager.get(port); ByteArrayOutputStream baos = new ByteArrayOutputStream(); request.readTo(baos); ScriptEngineManager mgr = new ScriptEngineManager(); final ScriptEngine engine = mgr.getEngineByName("JavaScript"); Compilable compilable = (Compilable) engine; final CompiledScript script = compilable.compile(baos.toString()); proxy.addResponseInterceptor(new ResponseInterceptor() { @Override public void process(BrowserMobHttpResponse response) { Bindings bindings = engine.createBindings(); bindings.put("response", response); bindings.put("log", LOG); try { script.eval(bindings); } catch (ScriptException e) { LOG.severe("Could not execute JS-based response interceptor", e); } } }); return Reply.saying().ok(); } @Post @At("/:port/interceptor/request") public Reply<?> addRequestInterceptor(@Named("port") int port, Request request) throws IOException, ScriptException { ProxyServer proxy = proxyManager.get(port); ByteArrayOutputStream baos = new ByteArrayOutputStream(); request.readTo(baos); ScriptEngineManager mgr = new ScriptEngineManager(); final ScriptEngine engine = mgr.getEngineByName("JavaScript"); Compilable compilable = (Compilable) engine; final CompiledScript script = compilable.compile(baos.toString()); proxy.addRequestInterceptor(new RequestInterceptor() { @Override public void process(BrowserMobHttpRequest request) { Bindings bindings = engine.createBindings(); bindings.put("request", request); bindings.put("log", LOG); try { script.eval(bindings); } catch (ScriptException e) { LOG.severe("Could not execute JS-based response interceptor", e); } } }); return Reply.saying().ok(); } @Put @At("/:port/limit") public Reply<?> limit(@Named("port") int port, Request request) { ProxyServer proxy = proxyManager.get(port); StreamManager streamManager = proxy.getStreamManager(); String upstreamKbps = request.param("upstreamKbps"); if (upstreamKbps != null) { try { streamManager.setUpstreamKbps(Integer.parseInt(upstreamKbps)); streamManager.enable(); } catch (NumberFormatException e) { } } String downstreamKbps = request.param("downstreamKbps"); if (downstreamKbps != null) { try { streamManager.setDownstreamKbps(Integer.parseInt(downstreamKbps)); streamManager.enable(); } catch (NumberFormatException e) { } } String latency = request.param("latency"); if (latency != null) { try { streamManager.setLatency(Integer.parseInt(latency)); streamManager.enable(); } catch (NumberFormatException e) { } } String payloadPercentage = request.param("payloadPercentage"); if (payloadPercentage != null) { try { streamManager.setPayloadPercentage(Integer.parseInt(payloadPercentage)); } catch (NumberFormatException e) { } } String maxBitsPerSecond = request.param("maxBitsPerSecond"); if (maxBitsPerSecond != null) { try { streamManager.setMaxBitsPerSecondThreshold(Integer.parseInt(maxBitsPerSecond)); } catch (NumberFormatException e) { } } String enable = request.param("enable"); if (enable != null) { if( Boolean.parseBoolean(enable) ) { streamManager.enable(); } else { streamManager.disable(); } } return Reply.saying().ok(); } @Put @At("/:port/timeout") public Reply<?> timeout(@Named("port") int port, Request request) { ProxyServer proxy = proxyManager.get(port); String requestTimeout = request.param("requestTimeout"); if (requestTimeout != null) { try { proxy.setRequestTimeout(Integer.parseInt(requestTimeout)); } catch (NumberFormatException e) { } } String readTimeout = request.param("readTimeout"); if (readTimeout != null) { try { proxy.setSocketOperationTimeout(Integer.parseInt(readTimeout)); } catch (NumberFormatException e) { } } String connectionTimeout = request.param("connectionTimeout"); if (connectionTimeout != null) { try { proxy.setConnectionTimeout(Integer.parseInt(connectionTimeout)); } catch (NumberFormatException e) { } } String dnsCacheTimeout = request.param("dnsCacheTimeout"); if (dnsCacheTimeout != null) { try { proxy.setDNSCacheTimeout(Integer.parseInt(dnsCacheTimeout)); } catch (NumberFormatException e) { } } return Reply.saying().ok(); } @Delete @At("/:port") public Reply<?> delete(@Named("port") int port) throws Exception { proxyManager.delete(port); return Reply.saying().ok(); } @Post @At("/:port/hosts") public Reply<?> remapHosts(@Named("port") int port, Request request) { ProxyServer proxy = proxyManager.get(port); @SuppressWarnings("unchecked") Map<String, String> headers = request.read(Map.class).as(Json.class); for (Map.Entry<String, String> entry : headers.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); proxy.remapHost(key, value); proxy.setDNSCacheTimeout(0); proxy.clearDNSCache(); } return Reply.saying().ok(); } @Put @At("/:port/wait") public Reply<?> wait(@Named("port") int port, Request request) { String quietPeriodInMs = request.param("quietPeriodInMs"); String timeoutInMs = request.param("timeoutInMs"); ProxyServer proxy = proxyManager.get(port); proxy.waitForNetworkTrafficToStop(Integer.parseInt(quietPeriodInMs), Integer.parseInt(timeoutInMs)); return Reply.saying().ok(); } @Delete @At("/:port/dns/cache") public Reply<?> clearDnsCache(@Named("port") int port) throws Exception { ProxyServer proxy = proxyManager.get(port); proxy.clearDNSCache(); return Reply.saying().ok(); } @Put @At("/:port/rewrite") public Reply<?> rewriteUrl(@Named("port") int port, Request request) { String match = request.param("matchRegex"); String replace = request.param("replace"); ProxyServer proxy = proxyManager.get(port); proxy.rewriteUrl(match, replace); return Reply.saying().ok(); } @Put @At("/:port/retry") public Reply<?> retryCount(@Named("port") int port, Request request) { String count = request.param("retrycount"); ProxyServer proxy = proxyManager.get(port); proxy.setRetryCount(Integer.parseInt(count)); return Reply.saying().ok(); } private int parseResponseCode(String response) { int responseCode = 200; if (response != null) { try { responseCode = Integer.parseInt(response); } catch (NumberFormatException e) { } } return responseCode; } public static class ProxyDescriptor { private int port; public ProxyDescriptor() { } public ProxyDescriptor(int port) { this.port = port; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } } }