/** * Copyright (c) 2014-2017 by the respective copyright holders. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.ui.internal.proxy; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Iterator; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.util.InputStreamResponseListener; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A blocking version of the proxy servlet that complies with Servlet API 2.4. * * @author Kai Kreuzer - Initial contribution and API * @author Svilen Valkanov - Replaced Apache HttpClient with Jetty * @author John Cocula - refactored to support alternate implementation */ public class BlockingProxyServlet extends HttpServlet { private final Logger logger = LoggerFactory.getLogger(BlockingProxyServlet.class); private static final long serialVersionUID = -4716754591953017794L; private final ProxyServletService service; private static HttpClient httpClient = new HttpClient(new SslContextFactory()); /** Timeout for HTTP requests in ms */ private static final int TIMEOUT = 15000; BlockingProxyServlet(ProxyServletService service) { super(); this.service = service; if (!httpClient.isStarted()) { try { httpClient.start(); } catch (Exception e) { logger.warn("Cannot start HttpClient!", e); } } } @Override public String getServletInfo() { return "Proxy (blocking)"; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { URI uri = service.uriFromRequest(request); if (uri == null) { service.sendError(request, response); } else { Request httpRequest = httpClient.newRequest(uri); service.maybeAppendAuthHeader(uri, httpRequest); InputStreamResponseListener listener = new InputStreamResponseListener(); // do the client request try { httpRequest.send(listener); // wait for the response headers to arrive or the timeout to expire Response httpResponse = listener.get(TIMEOUT, TimeUnit.MILLISECONDS); // get response headers HttpFields headers = httpResponse.getHeaders(); Iterator<HttpField> iterator = headers.iterator(); // copy all headers while (iterator.hasNext()) { HttpField header = iterator.next(); response.setHeader(header.getName(), header.getValue()); } } catch (Exception e) { if (e instanceof TimeoutException) { logger.warn("Proxy servlet failed to stream content due to a timeout"); response.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT); } else { logger.warn("Proxy servlet failed to stream content: {}", e.getMessage()); response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); } return; } // now copy/stream the body content try (InputStream responseContent = listener.getInputStream()) { IOUtils.copy(responseContent, response.getOutputStream()); } } } }