/* * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. * * 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 org.jboss.errai.tools.proxy; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.util.*; import java.util.logging.Logger; /** * @author Greg Murray * @author Heiko Braun */ public class XmlHttpProxy { public static String GET = "GET"; public static String POST = "POST"; public static String DELETE = "DELETE"; public static String PUT = "PUT"; private String userName = null; private String password = null; private static Logger logger; private String proxyHost = ""; int proxyPort = -1; private Object config; private static String USAGE = "Usage: -url service_URL -id service_key [-url or -id required] -xslurl xsl_url [optional] -format json|xml [optional] -callback[optional] -config [optional] -resources base_directory_containing XSL stylesheets [optional]"; public XmlHttpProxy() { } private Map<String, Cookie> cookies = new HashMap<String, Cookie>(); public interface CookieCallback { Map<String, Cookie> getCookies(); } public XmlHttpProxy(String proxyHost, int proxyPort) { this.proxyHost = proxyHost; this.proxyPort = proxyPort; } public XmlHttpProxy(String proxyHost, int proxyPort, String userName, String password) { this.proxyHost = proxyHost; this.proxyPort = proxyPort; this.userName = userName; this.password = password; } /** * This method will go out and make the call and it will apply an XSLT Transformation with the * set of parameters provided. * * @param urlString - The URL which you are looking up * @param out - The OutputStream to which the resulting document is written * @param xslInputStream - An input Stream to an XSL style sheet that is provided to the XSLT processor. If set to null there will be no transformation * @param paramsMap - A Map of parameters that are feed to the XSLT Processor. These params may be used when generating content. This may be set to null if no parameters are necessary. * @param method - The HTTP method used. */ public void processRequest(String urlString, OutputStream out, InputStream xslInputStream, Map paramsMap, Map headers, String method, String userName, String password) throws IOException, MalformedURLException { doProcess(urlString, out, xslInputStream, paramsMap, headers, method, null, null, userName, password); } /** * This method will go out and make the call and it will apply an XSLT Transformation with the * set of parameters provided. * * @param urlString - The URL which you are looking up * @param out - The OutputStream to which the resulting document is written */ public void doPost(String urlString, OutputStream out, InputStream xslInputStream, Map paramsMap, Map headers, String postData, String postContentType, String userName, String password) throws IOException, MalformedURLException { doProcess(urlString, out, xslInputStream, paramsMap, headers, XmlHttpProxy.POST, postData, postContentType, userName, password); } /** * This method will go out and make the call and it will apply an XSLT Transformation with the * set of parameters provided. * * @param urlString - The URL which you are looking up * @param out - The OutputStream to which the resulting document is written * @param xslInputStream - An input Stream to an XSL style sheet that is provided to the XSLT processor. If set to null there will be no transformation * @param paramsMap - A Map of parameters that are feed to the XSLT Processor. These params may be used when generating content. This may be set to null if no parameters are necessary. * @param method - the HTTP method used. * @param postData - A String of the bodyContent to be posted. A doPost will be used if this is parameter is not null. * @param postContentType - The request contentType used when posting data. Will not be set if this parameter is null. * @param userName - userName used for basic authorization * @param password - password used for basic authorization */ public void doProcess(String urlString, OutputStream out, InputStream xslInputStream, Map paramsMap, Map headers, String method, String postData, String postContentType, String userName, String password) throws IOException, MalformedURLException { if (paramsMap == null) { paramsMap = new HashMap(); } String format = (String) paramsMap.get("format"); if (format == null) { format = "xml"; } InputStream in = null; BufferedOutputStream os = null; HttpClient httpclient = null; CookieCallback callback = new CookieCallback() { public Map<String, Cookie> getCookies() { return accessCookies(); } }; if (userName != null && password != null) { httpclient = new HttpClient(proxyHost, proxyPort, urlString, headers, method, userName, password, callback); } else { httpclient = new HttpClient(proxyHost, proxyPort, urlString, headers, method, callback); } // post data determines whether we are going to do a get or a post if (postData == null) { in = httpclient.getInputStream(); } else { in = httpclient.doPost(postData, postContentType); } // Set-Cookie header if (httpclient.getSetCookieHeader() != null) { String cookie = httpclient.getSetCookieHeader(); System.out.println("'Set-Cookie' header: " + cookie); String[] values = cookie.split(";"); Cookie c = new Cookie(); for (String v : values) { String[] tuple = v.split("="); if ("Path".equals(tuple[0].trim())) c.path = tuple[1]; else { c.name = tuple[0].trim(); c.value = tuple[1]; } } List<String> toBeRemoved = new ArrayList<String>(); Iterator it = cookies.keySet().iterator(); while (it.hasNext()) { Cookie exists = cookies.get(it.next()); if (exists.name.equals(c.name)) { String msg = exists.value.equals(c.value) ? "Replace with same value: " + exists.value : "Replace with different value: " + exists.value + "->" + c.value; System.out.println("Cookie '" + exists.name + "' exists: " + msg); // avoid doubles toBeRemoved.add(exists.name); } } // clean up for (String s : toBeRemoved) { cookies.remove(s); } cookies.put(c.name, c); } if (null == in) { throw new IOException("Failed to open input stream"); } // read the encoding from the incoming document and default to UTF-8 // if an encoding is not provided String ce = httpclient.getContentEncoding(); if (ce == null) { String ct = httpclient.getContentType(); if (ct != null) { int idx = ct.lastIndexOf("charset="); if (idx >= 0) { ce = ct.substring(idx + 8); } else { ce = "UTF-8"; } } else { ce = "UTF-8"; } } // get the content type String cType = null; // write out the content type //http://www.ietf.org/rfc/rfc4627.txt if (format.equals("json")) { cType = "application/json;charset=" + ce; } else { cType = "text/xml;charset=" + ce; } try { byte[] buffer = new byte[1024]; int read = 0; if (xslInputStream == null) { while (true) { read = in.read(buffer); if (read <= 0) break; out.write(buffer, 0, read); } } else { transform(in, xslInputStream, paramsMap, out, ce); } } catch (Exception e) { getLogger().severe("XmlHttpProxy transformation error: " + e); } finally { try { if (in != null) { in.close(); } if (out != null) { out.flush(); out.close(); } } catch (Exception e) { // do nothing } } } private Map<String, Cookie> accessCookies() { return cookies; } /** * Do the XSLT transformation */ public void transform(InputStream xmlIS, InputStream xslIS, Map params, OutputStream result, String encoding) { try { TransformerFactory trFac = TransformerFactory.newInstance(); Transformer transformer = trFac.newTransformer(new StreamSource(xslIS)); Iterator it = params.keySet().iterator(); while (it.hasNext()) { String key = (String) it.next(); transformer.setParameter(key, (String) params.get(key)); } transformer.setOutputProperty("encoding", encoding); transformer.transform(new StreamSource(xmlIS), new StreamResult(result)); } catch (Exception e) { getLogger().severe("XmlHttpProxy: Exception with xslt " + e); } } /** * CLI to the XmlHttpProxy */ /* public static void main(String[] args) throws IOException, MalformedURLException { getLogger().info("XmlHttpProxy 1.8"); XmlHttpProxy xhp = new XmlHttpProxy(); if (args.length == 0) { System.out.println(USAGE); } String method = XmlHttpProxy.GET; InputStream xslInputStream = null; String serviceKey = null; String urlString = null; String xslURLString = null; String format = "xml"; String callback = null; String urlParams = null; String configURLString = "xhp.json"; String resourceBase = "file:src/conf/META-INF/resources/xsl/"; String username = null; String password = null; // read in the arguments int index = 0; while (index < args.length) { if (args[index].toLowerCase().equals("-url") && index + 1 < args.length) { urlString = args[++index]; } else if (args[index].toLowerCase().equals("-key") && index + 1 < args.length) { serviceKey = args[++index]; } else if (args[index].toLowerCase().equals("-id") && index + 1 < args.length) { serviceKey = args[++index]; } else if (args[index].toLowerCase().equals("-callback") && index + 1 < args.length) { callback = args[++index]; } else if (args[index].toLowerCase().equals("-xslurl") && index + 1 < args.length) { xslURLString = args[++index]; } else if (args[index].toLowerCase().equals("-method") && index + 1 < args.length) { method = args[++index]; } else if (args[index].toLowerCase().equals("-username") && index + 1 < args.length) { username = args[++index]; } else if (args[index].toLowerCase().equals("-password") && index + 1 < args.length) { password = args[++index]; } else if (args[index].toLowerCase().equals("-urlparams") && index + 1 < args.length) { urlParams = args[++index]; } else if (args[index].toLowerCase().equals("-config") && index + 1 < args.length) { configURLString = args[++index]; } else if (args[index].toLowerCase().equals("-resources") && index + 1 < args.length) { resourceBase = args[++index]; } index++; } if (serviceKey != null) { try { InputStream is = (new URL(configURLString)).openStream(); JSONObject services = loadServices(is); JSONObject service = services.getJSONObject(serviceKey); // default to the service default if no url parameters are specified if (urlParams == null && service.has("defaultURLParams")) { urlParams = service.getString("defaultURLParams"); } String serviceURL = service.getString("url"); // build the URL properly if (urlParams != null && serviceURL.indexOf("?") == -1){ serviceURL += "?"; } else if (urlParams != null){ serviceURL += "&"; } String apiKey = ""; if (service.has("apikey")) apiKey = service.getString("apikey"); urlString = serviceURL + apiKey + "&" + urlParams; if (service.has("xslStyleSheet")) { xslURLString = service.getString("xslStyleSheet"); // check if the url is correct of if to load from the classpath } } catch (Exception ex) { getLogger().severe("XmlHttpProxy Error loading service: " + ex); System.exit(1); } } else if (urlString == null) { System.out.println(USAGE); System.exit(1); } // The parameters are feed to the XSL Stylsheet during transformation. // These parameters can provided data or conditional information. Map paramsMap = new HashMap(); if (format != null) { paramsMap.put("format", format); } if (callback != null) { paramsMap.put("callback", callback); } if (xslURLString != null) { URL xslURL = new URL(xslURLString); if (xslURL != null) { xslInputStream = xslURL.openStream(); } else { getLogger().severe("Error: Unable to locate XSL at URL " + xslURLString); } } xhp.processRequest(urlString, System.out, xslInputStream, paramsMap, null, method, username, password); } */ public static Logger getLogger() { if (logger == null) { logger = Logger.getLogger(XmlHttpProxy.class.getName()); } return logger; } public static ProxyConfig loadServices(InputStream is) { return ProxyConfig.parse(is); } public class Cookie { String name; String value; String path; } }