/* * © Copyright IBM Corp. 2012 * * 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. */ package com.ibm.sbt.service.core.servlet; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * This is a simple proxy class provided as an example. Prefer the @see:ProxyServlet class. * * Proxy for transferring HTTP GET requests to the specified target URL. The result * returned by the target is transferred back to the original request initiator. */ public class SimpleProxyServlet extends HttpServlet implements Servlet { /** The name of the original request parameter specifying target URL */ private static final String PARAM_URL = "url"; /** * Comment for <code>serialVersionUID</code> */ private static final long serialVersionUID = 1L; /** * Constructs and sends HTTP GET request to the target URL. The content received * in a response is then returned to the original request initiator * * @param request the original request, specifies target URL as a value of the * parameter named {@link #PARAM_URL}. * @param response the response payload contains the content received from the * target URL */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String pathInfo = request.getPathInfo(); String contextPath = request.getContextPath(); String servletPath = request.getServletPath(); String uri = request.getRequestURI(); // Retrieve target URL printRequest(request); String url = uri.substring(servletPath.length()+contextPath.length()+1); if(url.startsWith("http/")) { url = "http://"+url.substring(5); } else if(url.startsWith("https/")) { url = "https://"+url.substring(6); } else { sendError(HttpServletResponse.SC_BAD_REQUEST, response, "Invalid protocol for proxied url"); } String qs = request.getQueryString(); if(qs!=null && qs.length()>0) { url = url + '?' + qs; //URLDecoder.decode(qs); } log("Target URL = '" + url + "'"); // Establish HTTP connection to the target HttpURLConnection httpCon = connect(url, request, response); if (httpCon == null) { return; } try { setResponseContent(httpCon, response); } finally { httpCon.disconnect(); } } /** * Opens HTTP connection to the target URL * * @param url the target URL * @param response is used for sending error reply * @return the connection if succeeded to connect; <code>null</code> otherwise. * In case of failure the error reply is sent to the original request * initiator */ private HttpURLConnection connect(final String url, HttpServletRequest request, HttpServletResponse response) { try { URL targetUrl = new URL(url); URLConnection con = targetUrl.openConnection(); if (!(con instanceof HttpURLConnection)) { sendError(HttpServletResponse.SC_BAD_REQUEST, response, "Unexpected URL protocol"); return null; } HttpURLConnection httpCon = (HttpURLConnection)con; // Authentication test // sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder(); // String userpassword = "priand@us.ibm.com" + ":" + "xxx"; // String encodedAuthorization = enc.encode( userpassword.getBytes() ); // httpCon.setRequestProperty("Authorization", "Basic "+ encodedAuthorization); // Copy the headers if(false) { for (Enumeration<String> e = (Enumeration<String>) request.getHeaderNames(); e.hasMoreElements();) { String headerName = (String) e.nextElement(); // Ignore cookie - treat them separately if (headerName.equalsIgnoreCase("cookie")) { // $NON-NLS-1$ continue; } // Ensure that the header is allowed if(true/*isHeaderAllowed(headerName)*/) { String headerValue = request.getHeader(headerName); httpCon.addRequestProperty(headerName, headerValue); } } } httpCon.connect(); log("Connection to the target URL is established"); return httpCon; } catch (MalformedURLException ex) { sendError(HttpServletResponse.SC_BAD_REQUEST, response, "Invalid URL", ex); } catch (Exception ex) { sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response, "Failed to establish connection to the target URL '" + url + "'", ex); } return null; } /** * Copies the content from the HTTP connection to the response payload, sets the * response content length and type. If failed to read the target content, error * is sent to the original request initiator * * @param con * @param response the response to be sent to the original request initiator * @param contentType the type of the response content * @exception IOException if failed to write the response content */ private void setResponseContent(HttpURLConnection con, HttpServletResponse response) throws IOException { int count = 0; ByteArrayOutputStream out = null; try { int len = con.getContentLength(); log("Target content length=" + len); if(len>0) { // First put content into temporary buffer to check the length. Sometimes // the target content length is unknown (-1), so we just need to read // until EOF is reached. Otherwise read at most len bytes InputStream in = con.getInputStream(); out = new ByteArrayOutputStream(); int next = in.read(); while ((len < 0 || count < len) && next != -1) { out.write(next); count++; next = in.read(); } } } catch (IOException ex) { sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response, "Failed to retrieve the target content", ex); return; } response.setStatus(con.getResponseCode()); response.setContentType(con.getContentType()); response.setContentLength(count); if(count>0) { response.getOutputStream().write(out.toByteArray()); } } /** * Prints exception details to the log and sends error response. Exception * details are not included into the response. * * @param status the status code to use * @param response the HttpServletResponse object to use for sending the response * @param msg the message to send * @param ex the exception that occurred */ private void sendError(final int status, final HttpServletResponse response, final String msg, final Exception ex) { log("Failed to handle request", ex); sendError(status, response, msg); } /** * Sends given status and message to the client; if failed to send, prints * failure details to log and rethrows the exception * * @param status the HTTP status code to send * @param response the HttpServletResponse object to use for sending the response. * @param msg the message to send */ private void sendError(final int status, final HttpServletResponse response, final String msg) { try { log("ERROR (" + status + "): " + msg); response.sendError(status, msg); } catch (IOException ex) { log("Failed to send error response", ex); } } /** * Prints values of all request headers to the servlet log file. * * @param request the request */ private void printRequest(HttpServletRequest request) { StringBuffer buf = new StringBuffer( "\n***********************************************************\n" + request.getMethod() + " " + request.getRequestURL().toString() + "\n\nParameters:\n"); // Print all request parameters Map.Entry param; Iterator iter = request.getParameterMap().entrySet().iterator(); while (iter.hasNext()) { param = (Map.Entry)iter.next(); buf.append(param.getKey() + " = " + ((String[])param.getValue())[0] + "\n"); } // Print request headers buf.append("\nHeaders:\n"); Enumeration<String> headers = request.getHeaderNames(); String name; while (headers.hasMoreElements()) { name = (String)headers.nextElement(); buf.append(name + ": " + request.getHeader(name) + "\n"); } buf.append("***********************************************************\n"); log("Original HTTP request " + buf.toString()); } }