datarouter-prov code clean - remove tabs
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / ProxyServlet.java
index 2db1ce4..6564e17 100644 (file)
-/*******************************************************************************\r
- * ============LICENSE_START==================================================\r
- * * org.onap.dmaap\r
- * * ===========================================================================\r
- * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
- * * ===========================================================================\r
- * * Licensed under the Apache License, Version 2.0 (the "License");\r
- * * you may not use this file except in compliance with the License.\r
- * * You may obtain a copy of the License at\r
- * * \r
- *  *      http://www.apache.org/licenses/LICENSE-2.0\r
- * * \r
- *  * Unless required by applicable law or agreed to in writing, software\r
- * * distributed under the License is distributed on an "AS IS" BASIS,\r
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * * See the License for the specific language governing permissions and\r
- * * limitations under the License.\r
- * * ============LICENSE_END====================================================\r
- * *\r
- * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
- * *\r
- ******************************************************************************/\r
-\r
-\r
-package org.onap.dmaap.datarouter.provisioning;\r
-\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileNotFoundException;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.net.URI;\r
-import java.security.KeyStore;\r
-import java.security.KeyStoreException;\r
-import java.util.Collections;\r
-import java.util.List;\r
-import java.util.Properties;\r
-\r
-import javax.servlet.ServletConfig;\r
-import javax.servlet.ServletException;\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpServletResponse;\r
-\r
-import org.apache.commons.io.IOUtils;\r
-import org.apache.http.Header;\r
-import org.apache.http.HttpEntity;\r
-import org.apache.http.HttpResponse;\r
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;\r
-import org.apache.http.client.methods.HttpGet;\r
-import org.apache.http.client.methods.HttpRequestBase;\r
-import org.apache.http.conn.scheme.Scheme;\r
-import org.apache.http.conn.ssl.SSLSocketFactory;\r
-import org.apache.http.entity.BasicHttpEntity;\r
-import org.apache.http.impl.client.AbstractHttpClient;\r
-import org.apache.http.impl.client.DefaultHttpClient;\r
-import org.onap.dmaap.datarouter.provisioning.utils.DB;\r
-import org.onap.dmaap.datarouter.provisioning.utils.URLUtilities;\r
-\r
-/**\r
- * This class is the base class for those servlets that need to proxy their requests from the\r
- * standby to active server.  Its methods perform the proxy function to the active server. If the\r
- * active server is not reachable, a 503 (SC_SERVICE_UNAVAILABLE) is returned.  Only\r
- * DELETE/GET/PUT/POST are supported.\r
- *\r
- * @author Robert Eby\r
- * @version $Id: ProxyServlet.java,v 1.3 2014/03/24 18:47:10 eby Exp $\r
- */\r
-@SuppressWarnings("serial")\r
-public class ProxyServlet extends BaseServlet {\r
-       private boolean inited = false;\r
-       private Scheme sch;\r
-\r
-       /**\r
-        * Initialize this servlet, by setting up SSL.\r
-        */\r
-       @SuppressWarnings("deprecation")\r
-       @Override\r
-       public void init(ServletConfig config) throws ServletException {\r
-               super.init(config);\r
-               try {\r
-                       // Set up keystore\r
-                       Properties props = (new DB()).getProperties();\r
-                       String type  = props.getProperty(Main.KEYSTORE_TYPE_PROPERTY, "jks");\r
-                       String store = props.getProperty(Main.KEYSTORE_PATH_PROPERTY);\r
-                       String pass  = props.getProperty(Main.KEYSTORE_PASSWORD_PROPERTY);\r
-                       KeyStore keyStore = readStore(store, pass, type);\r
-\r
-                       store = props.getProperty(Main.TRUSTSTORE_PATH_PROPERTY);\r
-                       pass  = props.getProperty(Main.TRUSTSTORE_PASSWORD_PROPERTY);\r
-                       if (store == null || store.length() == 0) {\r
-                               store = Main.DEFAULT_TRUSTSTORE;\r
-                               pass = "changeit";\r
-                       }\r
-                       KeyStore trustStore = readStore(store, pass, KeyStore.getDefaultType());\r
-\r
-                       // We are connecting with the node name, but the certificate will have the CNAME\r
-                       // So we need to accept a non-matching certificate name\r
-                       SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, "changeit", trustStore);\r
-                       socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);\r
-                       sch = new Scheme("https", 443, socketFactory);\r
-                       inited = true;\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               intlogger.info("ProxyServlet: inited = "+inited);\r
-       }\r
-       private KeyStore readStore(String store, String pass, String type) throws KeyStoreException, FileNotFoundException {\r
-               KeyStore ks = KeyStore.getInstance(type);\r
-               FileInputStream instream = new FileInputStream(new File(store));\r
-               try {\r
-                   ks.load(instream, pass.toCharArray());\r
-               } catch (Exception x) {\r
-                       System.err.println("READING TRUSTSTORE: "+x);\r
-               } finally {\r
-                   try { instream.close(); } catch (Exception ignore) {}\r
-               }\r
-               return ks;\r
-       }\r
-       /**\r
-        * Return <i>true</i> if the requester has NOT set the <i>noproxy</i> CGI variable.\r
-        * If they have, this indicates they want to forcibly turn the proxy off.\r
-        * @param req the HTTP request\r
-        * @return true or false\r
-        */\r
-       protected boolean isProxyOK(final HttpServletRequest req) {\r
-               String t = req.getQueryString();\r
-               if (t != null) {\r
-                       t = t.replaceAll("&amp;", "&");\r
-                       for (String s : t.split("&")) {\r
-                               if (s.equals("noproxy") || s.startsWith("noproxy="))\r
-                                       return false;\r
-                       }\r
-               }\r
-               return true;\r
-       }\r
-       /**\r
-        * Is this the standby server?  If it is, the proxy functions can be used.\r
-        * If not, the proxy functions should not be called, and will send a response of 500\r
-        * (Internal Server Error).\r
-        * @return true if this server is the standby (and hence a proxy server).\r
-        */\r
-       public boolean isProxyServer() {\r
-               SynchronizerTask st = SynchronizerTask.getSynchronizer();\r
-               return st.getState() == SynchronizerTask.STANDBY;\r
-       }\r
-       /**\r
-        * Issue a proxy DELETE to the active provisioning server.\r
-        */\r
-       @Override\r
-       public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               doProxy(req, resp, "DELETE");\r
-       }\r
-       /**\r
-        * Issue a proxy GET to the active provisioning server.\r
-        */\r
-       @Override\r
-       public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               doProxy(req, resp, "GET");\r
-       }\r
-       /**\r
-        * Issue a proxy PUT to the active provisioning server.\r
-        */\r
-       @Override\r
-       public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               doProxy(req, resp, "PUT");\r
-       }\r
-       /**\r
-        * Issue a proxy POST to the active provisioning server.\r
-        */\r
-       @Override\r
-       public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               doProxy(req, resp, "POST");\r
-       }\r
-       /**\r
-        * Issue a proxy GET to the active provisioning server.  Unlike doGet() above,\r
-        * this method will allow the caller to fall back to other code if the remote server is unreachable.\r
-        * @return true if the proxy succeeded\r
-        */\r
-       public boolean doGetWithFallback(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               boolean rv = false;\r
-               if (inited) {\r
-                       String url = buildUrl(req);\r
-                       intlogger.info("ProxyServlet: proxying with fallback GET "+url);\r
-                       AbstractHttpClient httpclient = new DefaultHttpClient();\r
-                       HttpRequestBase proxy = new HttpGet(url);\r
-                       try {\r
-                               httpclient.getConnectionManager().getSchemeRegistry().register(sch);\r
-\r
-                               // Copy request headers and request body\r
-                               copyRequestHeaders(req, proxy);\r
-\r
-                               // Execute the request\r
-                               HttpResponse pxy_response = httpclient.execute(proxy);\r
-\r
-                               // Get response headers and body\r
-                               int code = pxy_response.getStatusLine().getStatusCode();\r
-                               resp.setStatus(code);\r
-                               copyResponseHeaders(pxy_response, resp);\r
-\r
-                               HttpEntity entity = pxy_response.getEntity();\r
-                               if (entity != null) {\r
-                                       InputStream in = entity.getContent();\r
-                                       IOUtils.copy(in, resp.getOutputStream());\r
-                                       in.close();\r
-                               }\r
-                               rv = true;\r
-                       } catch (IOException e) {\r
-                               System.err.println("ProxyServlet: "+e);\r
-                               e.printStackTrace();\r
-                       } finally {\r
-                               proxy.releaseConnection();\r
-                               httpclient.getConnectionManager().shutdown();\r
-                       }\r
-               } else {\r
-                       intlogger.warn("ProxyServlet: proxy disabled");\r
-               }\r
-               return rv;\r
-       }\r
-       private void doProxy(HttpServletRequest req, HttpServletResponse resp, final String method) throws IOException {\r
-               if (inited && isProxyServer()) {\r
-                       String url = buildUrl(req);\r
-                       intlogger.info("ProxyServlet: proxying "+method + " "+url);\r
-                       AbstractHttpClient httpclient = new DefaultHttpClient();\r
-                       ProxyHttpRequest proxy = new ProxyHttpRequest(method, url);\r
-                       try {\r
-                               httpclient.getConnectionManager().getSchemeRegistry().register(sch);\r
-\r
-                               // Copy request headers and request body\r
-                               copyRequestHeaders(req, proxy);\r
-                               if (method.equals("POST") || method.equals("PUT")){\r
-                                       BasicHttpEntity body = new BasicHttpEntity();\r
-                                       body.setContent(req.getInputStream());\r
-                                       body.setContentLength(-1);      // -1 = unknown\r
-                                       proxy.setEntity(body);\r
-                               }\r
-\r
-                               // Execute the request\r
-                               HttpResponse pxy_response = httpclient.execute(proxy);\r
-\r
-                               // Get response headers and body\r
-                               int code = pxy_response.getStatusLine().getStatusCode();\r
-                               resp.setStatus(code);\r
-                               copyResponseHeaders(pxy_response, resp);\r
-\r
-                               HttpEntity entity = pxy_response.getEntity();\r
-                               if (entity != null) {\r
-                                       InputStream in = entity.getContent();\r
-                                       IOUtils.copy(in, resp.getOutputStream());\r
-                                       in.close();\r
-                               }\r
-                       } catch (IOException e) {\r
-                               intlogger.warn("ProxyServlet: "+e);\r
-                               resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);\r
-                               e.printStackTrace();\r
-                       } finally {\r
-                               proxy.releaseConnection();\r
-                               httpclient.getConnectionManager().shutdown();\r
-                       }\r
-               } else {\r
-                       intlogger.warn("ProxyServlet: proxy disabled");\r
-                       resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
-               }\r
-       }\r
-       private String buildUrl(HttpServletRequest req) {\r
-               StringBuilder sb = new StringBuilder("https://");\r
-               sb.append(URLUtilities.getPeerPodName());\r
-               sb.append(req.getRequestURI());\r
-               String q = req.getQueryString();\r
-               if (q != null)\r
-                       sb.append("?").append(q);\r
-               return sb.toString();\r
-       }\r
-       private void copyRequestHeaders(HttpServletRequest from, HttpRequestBase to) {\r
-               @SuppressWarnings("unchecked")\r
-               List<String> list = Collections.list(from.getHeaderNames());\r
-               for (String name : list) {\r
-                       // Proxy code will add this one\r
-                       if (!name.equalsIgnoreCase("Content-Length"))\r
-                               to.addHeader(name, from.getHeader(name));\r
-               }\r
-       }\r
-       private void copyResponseHeaders(HttpResponse from, HttpServletResponse to) {\r
-               for (Header hdr : from.getAllHeaders()) {\r
-                       // Don't copy Date: our Jetty will add another Date header\r
-                       if (!hdr.getName().equals("Date"))\r
-                               to.addHeader(hdr.getName(), hdr.getValue());\r
-               }\r
-       }\r
-\r
-       public class ProxyHttpRequest extends HttpEntityEnclosingRequestBase {\r
-               private final String method;\r
-\r
-               public ProxyHttpRequest(final String method, final String uri) {\r
-                       super();\r
-                       this.method = method;\r
-               setURI(URI.create(uri));\r
-               }\r
-               @Override\r
-               public String getMethod() {\r
-                       return method;\r
-               }\r
-       }\r
-}\r
+/*******************************************************************************
+ * ============LICENSE_START==================================================
+ * * org.onap.dmaap
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * ===========================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ *  *      http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ *  * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+
+
+package org.onap.dmaap.datarouter.provisioning;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.BasicHttpEntity;
+import org.apache.http.impl.client.AbstractHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.onap.dmaap.datarouter.provisioning.utils.DB;
+import org.onap.dmaap.datarouter.provisioning.utils.URLUtilities;
+
+/**
+ * This class is the base class for those servlets that need to proxy their requests from the
+ * standby to active server.  Its methods perform the proxy function to the active server. If the
+ * active server is not reachable, a 503 (SC_SERVICE_UNAVAILABLE) is returned.  Only
+ * DELETE/GET/PUT/POST are supported.
+ *
+ * @author Robert Eby
+ * @version $Id: ProxyServlet.java,v 1.3 2014/03/24 18:47:10 eby Exp $
+ */
+@SuppressWarnings("serial")
+public class ProxyServlet extends BaseServlet {
+    private boolean inited = false;
+    private Scheme sch;
+
+    /**
+     * Initialize this servlet, by setting up SSL.
+     */
+    @SuppressWarnings("deprecation")
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+        try {
+            // Set up keystore
+            Properties props = (new DB()).getProperties();
+            String type  = props.getProperty(Main.KEYSTORE_TYPE_PROPERTY, "jks");
+            String store = props.getProperty(Main.KEYSTORE_PATH_PROPERTY);
+            String pass  = props.getProperty(Main.KEYSTORE_PASSWORD_PROPERTY);
+            KeyStore keyStore = readStore(store, pass, type);
+
+            store = props.getProperty(Main.TRUSTSTORE_PATH_PROPERTY);
+            pass  = props.getProperty(Main.TRUSTSTORE_PASSWORD_PROPERTY);
+            if (store == null || store.length() == 0) {
+                store = Main.DEFAULT_TRUSTSTORE;
+                pass = "changeit";
+            }
+            KeyStore trustStore = readStore(store, pass, KeyStore.getDefaultType());
+
+            // We are connecting with the node name, but the certificate will have the CNAME
+            // So we need to accept a non-matching certificate name
+            SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, "changeit", trustStore);
+            socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+            sch = new Scheme("https", 443, socketFactory);
+            inited = true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        intlogger.info("ProxyServlet: inited = "+inited);
+    }
+    private KeyStore readStore(String store, String pass, String type) throws KeyStoreException, FileNotFoundException {
+        KeyStore ks = KeyStore.getInstance(type);
+        FileInputStream instream = new FileInputStream(new File(store));
+        try {
+            ks.load(instream, pass.toCharArray());
+        } catch (Exception x) {
+            System.err.println("READING TRUSTSTORE: "+x);
+        } finally {
+            try { instream.close(); } catch (Exception ignore) {}
+        }
+        return ks;
+    }
+    /**
+     * Return <i>true</i> if the requester has NOT set the <i>noproxy</i> CGI variable.
+     * If they have, this indicates they want to forcibly turn the proxy off.
+     * @param req the HTTP request
+     * @return true or false
+     */
+    protected boolean isProxyOK(final HttpServletRequest req) {
+        String t = req.getQueryString();
+        if (t != null) {
+            t = t.replaceAll("&amp;", "&");
+            for (String s : t.split("&")) {
+                if (s.equals("noproxy") || s.startsWith("noproxy="))
+                    return false;
+            }
+        }
+        return true;
+    }
+    /**
+     * Is this the standby server?  If it is, the proxy functions can be used.
+     * If not, the proxy functions should not be called, and will send a response of 500
+     * (Internal Server Error).
+     * @return true if this server is the standby (and hence a proxy server).
+     */
+    public boolean isProxyServer() {
+        SynchronizerTask st = SynchronizerTask.getSynchronizer();
+        return st.getState() == SynchronizerTask.STANDBY;
+    }
+    /**
+     * Issue a proxy DELETE to the active provisioning server.
+     */
+    @Override
+    public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        doProxy(req, resp, "DELETE");
+    }
+    /**
+     * Issue a proxy GET to the active provisioning server.
+     */
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        doProxy(req, resp, "GET");
+    }
+    /**
+     * Issue a proxy PUT to the active provisioning server.
+     */
+    @Override
+    public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        doProxy(req, resp, "PUT");
+    }
+    /**
+     * Issue a proxy POST to the active provisioning server.
+     */
+    @Override
+    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        doProxy(req, resp, "POST");
+    }
+    /**
+     * Issue a proxy GET to the active provisioning server.  Unlike doGet() above,
+     * this method will allow the caller to fall back to other code if the remote server is unreachable.
+     * @return true if the proxy succeeded
+     */
+    public boolean doGetWithFallback(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        boolean rv = false;
+        if (inited) {
+            String url = buildUrl(req);
+            intlogger.info("ProxyServlet: proxying with fallback GET "+url);
+            AbstractHttpClient httpclient = new DefaultHttpClient();
+            HttpRequestBase proxy = new HttpGet(url);
+            try {
+                httpclient.getConnectionManager().getSchemeRegistry().register(sch);
+
+                // Copy request headers and request body
+                copyRequestHeaders(req, proxy);
+
+                // Execute the request
+                HttpResponse pxy_response = httpclient.execute(proxy);
+
+                // Get response headers and body
+                int code = pxy_response.getStatusLine().getStatusCode();
+                resp.setStatus(code);
+                copyResponseHeaders(pxy_response, resp);
+
+                HttpEntity entity = pxy_response.getEntity();
+                if (entity != null) {
+                    InputStream in = entity.getContent();
+                    IOUtils.copy(in, resp.getOutputStream());
+                    in.close();
+                }
+                rv = true;
+            } catch (IOException e) {
+                System.err.println("ProxyServlet: "+e);
+                e.printStackTrace();
+            } finally {
+                proxy.releaseConnection();
+                httpclient.getConnectionManager().shutdown();
+            }
+        } else {
+            intlogger.warn("ProxyServlet: proxy disabled");
+        }
+        return rv;
+    }
+    private void doProxy(HttpServletRequest req, HttpServletResponse resp, final String method) throws IOException {
+        if (inited && isProxyServer()) {
+            String url = buildUrl(req);
+            intlogger.info("ProxyServlet: proxying "+method + " "+url);
+            AbstractHttpClient httpclient = new DefaultHttpClient();
+            ProxyHttpRequest proxy = new ProxyHttpRequest(method, url);
+            try {
+                httpclient.getConnectionManager().getSchemeRegistry().register(sch);
+
+                // Copy request headers and request body
+                copyRequestHeaders(req, proxy);
+                if (method.equals("POST") || method.equals("PUT")){
+                    BasicHttpEntity body = new BasicHttpEntity();
+                    body.setContent(req.getInputStream());
+                    body.setContentLength(-1);    // -1 = unknown
+                    proxy.setEntity(body);
+                }
+
+                // Execute the request
+                HttpResponse pxy_response = httpclient.execute(proxy);
+
+                // Get response headers and body
+                int code = pxy_response.getStatusLine().getStatusCode();
+                resp.setStatus(code);
+                copyResponseHeaders(pxy_response, resp);
+
+                HttpEntity entity = pxy_response.getEntity();
+                if (entity != null) {
+                    InputStream in = entity.getContent();
+                    IOUtils.copy(in, resp.getOutputStream());
+                    in.close();
+                }
+            } catch (IOException e) {
+                intlogger.warn("ProxyServlet: "+e);
+                resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                e.printStackTrace();
+            } finally {
+                proxy.releaseConnection();
+                httpclient.getConnectionManager().shutdown();
+            }
+        } else {
+            intlogger.warn("ProxyServlet: proxy disabled");
+            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+        }
+    }
+    private String buildUrl(HttpServletRequest req) {
+        StringBuilder sb = new StringBuilder("https://");
+        sb.append(URLUtilities.getPeerPodName());
+        sb.append(req.getRequestURI());
+        String q = req.getQueryString();
+        if (q != null)
+            sb.append("?").append(q);
+        return sb.toString();
+    }
+    private void copyRequestHeaders(HttpServletRequest from, HttpRequestBase to) {
+        @SuppressWarnings("unchecked")
+        List<String> list = Collections.list(from.getHeaderNames());
+        for (String name : list) {
+            // Proxy code will add this one
+            if (!name.equalsIgnoreCase("Content-Length"))
+                to.addHeader(name, from.getHeader(name));
+        }
+    }
+    private void copyResponseHeaders(HttpResponse from, HttpServletResponse to) {
+        for (Header hdr : from.getAllHeaders()) {
+            // Don't copy Date: our Jetty will add another Date header
+            if (!hdr.getName().equals("Date"))
+                to.addHeader(hdr.getName(), hdr.getValue());
+        }
+    }
+
+    public class ProxyHttpRequest extends HttpEntityEnclosingRequestBase {
+        private final String method;
+
+        public ProxyHttpRequest(final String method, final String uri) {
+            super();
+            this.method = method;
+            setURI(URI.create(uri));
+        }
+        @Override
+        public String getMethod() {
+            return method;
+        }
+    }
+}