1 package org.jsoup.integration.servlets; 2 3 import org.eclipse.jetty.client.api.Response; 4 import org.eclipse.jetty.proxy.AsyncProxyServlet; 5 import org.eclipse.jetty.proxy.ConnectHandler; 6 import org.eclipse.jetty.server.Handler; 7 import org.eclipse.jetty.servlet.FilterHolder; 8 import org.eclipse.jetty.servlet.FilterMapping; 9 import org.eclipse.jetty.servlet.ServletHandler; 10 import org.eclipse.jetty.servlet.ServletHolder; 11 import org.jsoup.integration.TestServer; 12 13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletResponse; 15 16 import static org.jsoup.integration.servlets.AuthFilter.ProxyRealm; 17 18 public class ProxyServlet extends AsyncProxyServlet { 19 public static TestServer.ProxySettings ProxySettings = TestServer.proxySettings(); 20 public static String Via = "1.1 jsoup test proxy"; 21 22 static { 23 System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); 24 // removes Basic, which is otherwise excluded from auth for CONNECT tunnels 25 } 26 createHandler(boolean alwaysAuth)27 public static Handler createHandler(boolean alwaysAuth) { 28 // ConnectHandler wraps this ProxyServlet and handles CONNECT, which sets up a tunnel for HTTPS requests and is 29 // opaque to the proxy. The ProxyServlet handles simple HTTP requests. 30 AuthFilter authFilter = new AuthFilter(alwaysAuth, true); 31 ConnectHandler connectHandler = new ConnectProxy(authFilter); 32 ServletHandler proxyHandler = new ServletHandler(); 33 proxyHandler.addFilterWithMapping(new FilterHolder(authFilter), "/*", FilterMapping.ALL); // auth for HTTP proxy 34 ServletHolder proxyServletHolder = new ServletHolder(ProxyServlet.class); // Holder wraps as it requires maxThreads initialization 35 proxyServletHolder.setAsyncSupported(true); 36 proxyServletHolder.setInitParameter("maxThreads", "8"); 37 proxyHandler.addServletWithMapping(proxyServletHolder, "/*"); 38 connectHandler.setHandler(proxyHandler); 39 40 return connectHandler; 41 } 42 43 @Override onServerResponseHeaders(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Response serverResponse)44 protected void onServerResponseHeaders(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Response serverResponse) { 45 super.onServerResponseHeaders(clientRequest, proxyResponse, serverResponse); 46 proxyResponse.addHeader("Via", Via); 47 } 48 49 /** Supports CONNECT tunnels */ 50 static class ConnectProxy extends ConnectHandler { 51 final AuthFilter authFilter; 52 ConnectProxy(AuthFilter authFilter)53 public ConnectProxy(AuthFilter authFilter) { 54 this.authFilter = authFilter; 55 } 56 57 @Override handleAuthentication(HttpServletRequest req, HttpServletResponse res, String address)58 protected boolean handleAuthentication(HttpServletRequest req, HttpServletResponse res, String address) { 59 boolean accessGranted = authFilter.checkAuth(req); 60 //System.err.println("CONNECT AUTH: " + accessGranted); 61 62 // need to add the desired auth header if not granted. Returning false here will also send 407 header 63 if (!accessGranted) { 64 res.setHeader("Proxy-Authenticate", "Basic realm=\"" + ProxyRealm + "\""); 65 } 66 return accessGranted; 67 } 68 } 69 } 70