/* * © 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.basic; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.cookie.BasicClientCookie; import com.ibm.commons.util.StringUtil; import com.ibm.commons.util.io.ByteStreamCache; import com.ibm.commons.util.io.ReaderInputStream; import com.ibm.commons.util.io.StreamUtil; import com.ibm.commons.util.io.TraceOutputStream; import com.ibm.commons.util.io.WriterOutputStream; import com.ibm.commons.util.io.base64.Base64; import com.ibm.commons.util.io.json.JsonGenerator; import com.ibm.commons.util.io.json.JsonJavaFactory; import com.ibm.commons.util.io.json.JsonJavaObject; import com.ibm.commons.util.profiler.Profiler; import com.ibm.commons.util.profiler.ProfilerAggregator; import com.ibm.commons.util.profiler.ProfilerType; import com.ibm.sbt.service.debug.DebugProxyHook; import com.ibm.sbt.service.debug.DebugServiceHookFactory; import com.ibm.sbt.service.debug.DebugServiceHookFactory.Type; /** * Basic proxy. * <p> * This is the base class handling proxy requests. It has to be instanciated and called * from a servlet, or from a proxy handler from the library. * </p> * @author Dan Dumont * @author Philippe Riand */ public class ProxyService { /// TODO: use a group here... private static boolean TRACE = false; private static final ProfilerType profilerRequest = new ProfilerType("Proxy request, "); //$NON-NLS-1$ /** * The wrapper for cookie domain and path. These are stored in the cookie value * when the cookie is passed to the browser. So that the proxy domain and path * can be used when the cookie is passed back to the browser. */ private static final String PASSTHRUID = "sbtsdkck"; private DebugProxyHook debugHook; public ProxyService() { } public DebugProxyHook getDebugHook() { return debugHook; } public int getSocketReadTimeout() { return 120; // default, in seconds } protected DefaultHttpClient getClient(HttpServletRequest request, int timeout) { // Should we manage a connection pool here? //BasicHttpParams params = new BasicHttpParams(); //params.setRedirecting(params, false); //DefaultHttpClient httpClient = new DefaultHttpClient(params); Object timedObject = ProxyProfiler.getTimedObject(); DefaultHttpClient httpClient = new DefaultHttpClient(); ProxyProfiler.profileTimedRequest(timedObject, "httpclient creation"); return httpClient; } // // Security options - defensive mode by default // protected void checkRequestAllowed(HttpServletRequest request) throws ServletException { Object timedObject = ProxyProfiler.getTimedObject(); String method = request.getMethod(); if(!isMethodAllowed(method)) { throw new ServletException(StringUtil.format("Invalid request method {0}",method)); } ProxyProfiler.profileTimedRequest(timedObject, "checkRequestAllowed"); } protected boolean isMethodAllowed(String method) throws ServletException { return false; } protected boolean forwardHeaders(HttpRequestBase method, HttpServletRequest request) { return true; } protected boolean isHeaderAllowed(String headerName) throws ServletException { // content-length header will be automatically added by the HTTP client // host header causes request failures when it does not match the proxy host see x-forwaded-for comment above // Origin is added by chrome / safari in post/put/delete same-origin requests. if(StringUtil.equalsIgnoreCase(headerName, "content-length") || StringUtil.equalsIgnoreCase(headerName, "host") || StringUtil.equalsIgnoreCase(headerName, "origin")) { return false; } return true; } protected boolean forwardCookies(HttpRequestBase method, HttpServletRequest request) { return true; } protected boolean isCookieAllowed(String cookieName) throws ServletException { //if(cookieName.equalsIgnoreCase("JSESSIONID")) { // return false; //} return true; } protected boolean isMimeTypeAllowed(String cookieName) throws ServletException { return true; } public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object timedObject = ProxyProfiler.getTimedObject(); if (Profiler.isEnabled()) { StringBuffer b = request.getRequestURL(); String url = b.toString(); ProfilerAggregator agg = Profiler.startProfileBlock(profilerRequest, request.getMethod().toUpperCase() + " " + url); long ts = Profiler.getCurrentTime(); try { serviceProxy(request, response); } finally { Profiler.endProfileBlock(agg, ts); } } else { serviceProxy(request, response); } ProxyProfiler.profileTimedRequest(timedObject, "service request"); } protected void serviceProxy(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.debugHook = (DebugProxyHook)DebugServiceHookFactory.get().get(Type.PROXY,request,response); if(debugHook!=null) { request = debugHook.getRequestWrapper(); response = debugHook.getResponseWrapper(); } try { try { initProxy(request, response); try { checkRequestAllowed(request); String smethod = request.getMethod(); DefaultHttpClient client = getClient(request, getSocketReadTimeout()); URI url = getRequestURI(request); HttpRequestBase method = createMethod(smethod, url, request); if (prepareForwardingMethod(method, request, client)) { HttpResponse clientResponse = executeMethod(client, method); prepareResponse(method, request, response, clientResponse, true); } response.flushBuffer(); } catch (Exception e) { writeErrorResponse("Unexpected Exception", new String[] {"exception"},new String[] {e.toString()}, response, request); }finally { termProxy(request, response); } } catch (Exception e) { writeErrorResponse("Unexpected Exception", new String[] {"exception"},new String[] {e.toString()}, response, request); } } finally { if(debugHook!=null) { debugHook.terminate(); debugHook = null; } } } private HttpRequestBase prepareMethodWithUpdatedContent( HttpRequestBase method, HttpServletRequest request) throws ServletException { // PHIL, 2/28/2013 // We should use the length when available, for HTTP 1.1 // -> it optimizes with HTTP 1.1 // -> it prevents the HTTP client to use Transfert-Encoding: chunked, which doesn't // seem to work will all HTTP servers (ex: Domino) // A browser should anyway provide the length. long length = -1; String slength = request.getHeader("Content-Length"); if(StringUtil.isNotEmpty(slength)) { length = Long.parseLong(slength); } try { // When no length is specified, the HTTP client core forces Transfert-Encoding: chunked // The code bellow shows a workaround, although we should avoid that if(false) { if(length<0) { ByteStreamCache bs = new ByteStreamCache(); bs.copyFrom(request.getInputStream()); HttpEntity payloadEntity = new InputStreamEntity(bs.getInputStream(), bs.getLength()); ((HttpEntityEnclosingRequest) method).setEntity(payloadEntity); return method; } } // Regular code HttpEntity payloadEntity = new InputStreamEntity(request.getInputStream(), length); ((HttpEntityEnclosingRequest) method).setEntity(payloadEntity); }catch(Exception e){ throw new ServletException("Error while parsing the payload"); } return method; } protected void initProxy(HttpServletRequest request, HttpServletResponse response) throws ServletException { } protected void termProxy(HttpServletRequest request, HttpServletResponse response) throws ServletException { } protected HttpRequestBase createMethod(String smethod, URI uri,HttpServletRequest request) throws ServletException { Object timedObject = ProxyProfiler.getTimedObject(); if(getDebugHook()!=null) { getDebugHook().getDumpRequest().setMethod(smethod); getDebugHook().getDumpRequest().setUrl(uri.toString()); } if (smethod.equalsIgnoreCase("get")) { HttpGet method = new HttpGet(uri); ProxyProfiler.profileTimedRequest(timedObject, "create HttpGet"); return method; } else if (smethod.equalsIgnoreCase("put")) { HttpPut method = new HttpPut(uri); method = (HttpPut) prepareMethodWithUpdatedContent(method, request); ProxyProfiler.profileTimedRequest(timedObject, "create HttpPut"); return method; } else if (smethod.equalsIgnoreCase("post")) { HttpPost method = new HttpPost(uri); method = (HttpPost) prepareMethodWithUpdatedContent(method, request); ProxyProfiler.profileTimedRequest(timedObject, "create HttpPost"); return method; } else if (smethod.equalsIgnoreCase("delete")) { HttpDelete method = new HttpDelete(uri); ProxyProfiler.profileTimedRequest(timedObject, "create HttpDelete"); return method; } else if (smethod.equalsIgnoreCase("head")) { HttpHead method = new HttpHead(uri); ProxyProfiler.profileTimedRequest(timedObject, "create HttpHead"); return method; } else if (smethod.equalsIgnoreCase("options")) { HttpOptions method = new HttpOptions(uri); ProxyProfiler.profileTimedRequest(timedObject, "create HttpOptions"); return method; } else { ProxyProfiler.profileTimedRequest(timedObject, "failed creating method"); throw new ServletException("Illegal method, should be GET, PUT, POST, DELETE or HEAD"); } } protected boolean prepareForwardingMethod(HttpRequestBase method, HttpServletRequest request, DefaultHttpClient client) throws ServletException { boolean retval = (!forwardCookies(method, request) || prepareForwardingCookies(method, request, client)) && (!forwardHeaders(method, request) || prepareForwardingHeaders(method, request)); return retval; } protected boolean prepareForwardingCookies(HttpRequestBase method, HttpServletRequest request, DefaultHttpClient httpClient) throws ServletException { Object timedObject = ProxyProfiler.getTimedObject(); Cookie[] cookies = request.getCookies(); BasicCookieStore cs = new BasicCookieStore(); httpClient.setCookieStore(cs); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie != null) { String cookiename = cookie.getName(); if(StringUtil.isNotEmpty(cookiename)) { String cookieval = cookie.getValue(); if (cookiename.startsWith(PASSTHRUID)) { cookiename = cookiename.substring(PASSTHRUID.length()); if(isCookieAllowed(cookiename)) { String[] parts = decodeCookieNameAndPath(cookiename); if (parts!=null && parts.length==3) { cookiename = parts[0]; String path = parts[1]; String domain = parts[2]; // Got stored domain now see if it matches destination BasicClientCookie methodcookie = new BasicClientCookie(cookiename,cookieval); methodcookie.setDomain(domain); methodcookie.setPath(path); cs.addCookie(methodcookie); if(getDebugHook()!=null) { getDebugHook().getDumpRequest().addCookie(methodcookie.getName(), methodcookie.toString()); } } } } else if(isCookieAllowed(cookiename)) { BasicClientCookie methodcookie = new BasicClientCookie(cookiename,cookieval); String domain = cookie.getDomain(); if (domain == null) { try { domain = method.getURI().getHost(); domain = domain.substring(domain.indexOf('.')); } catch (Exception e) { domain = ""; } } methodcookie.setDomain(domain); String path = cookie.getPath(); if (path == null) { path = "/"; } methodcookie.setPath(path); cs.addCookie(methodcookie); if(getDebugHook()!=null) { getDebugHook().getDumpRequest().addCookie(methodcookie.getName(), methodcookie.toString()); } } } } } } ProxyProfiler.profileTimedRequest(timedObject, "perpareForwardingCookie"); return true; } @SuppressWarnings("unchecked") protected boolean prepareForwardingHeaders(HttpRequestBase method, HttpServletRequest request) throws ServletException { Object timedObject = ProxyProfiler.getTimedObject(); // Forward any headers that should be forwarded. Except cookies. StringBuffer xForwardedForHeader = new StringBuffer(); for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements();) { String headerName = e.nextElement(); // Ignore cookie - treat them separately if (headerName.equalsIgnoreCase("cookie")) { // $NON-NLS-1$ continue; } String headerValue = request.getHeader(headerName); // This is to be investigated - Should the X-Forwarded-For being passed? Ryan. // if(headerName.equalsIgnoreCase("X-Forwarded-For") || headerName.equalsIgnoreCase("host")) { // addXForwardedForHeader(method, headerValue, xForwardedForHeader); // continue; // } // Ensure that the header is allowed if(isHeaderAllowed(headerName)) { method.addHeader(headerName, headerValue); if(getDebugHook()!=null) { getDebugHook().getDumpRequest().addHeader(headerName, headerValue); } } } String xForward = xForwardedForHeader.toString(); if(StringUtil.isNotEmpty(xForward)) { method.addHeader("X-Forwarded-For", xForward); if(getDebugHook()!=null) { getDebugHook().getDumpRequest().addHeader("X-Forwarded-For", xForward); } } ProxyProfiler.profileTimedRequest(timedObject, "prepareForwardingHeaders"); return true; } /** * Adds a host to the x-Forwarded-For header. This method is called a host or * x-Forwarded-For header is encountered on the proxied request. * @param method The request being made by the proxy. * @param headerValue The header value from the proxied request. * @param xForwardedForHeader The current valye of the x-Forward-For header that will be * added to the request made by the proxy. */ protected void addXForwardedForHeader(HttpRequestBase method, String headerValue, StringBuffer xForwardedForHeader) { String[] forwards = headerValue.trim().split(","); for (String forward : forwards) { String host = forward.trim(); if(!host.equals("")) { if(xForwardedForHeader.length() == 0) { xForwardedForHeader.append(host); } else { xForwardedForHeader.append("," + host); } } } } public HttpResponse executeMethod(HttpClient client, HttpRequestBase method) throws ServletException { try { Object timedObject = ProxyProfiler.getTimedObject(); HttpResponse response = client.execute(method); ProxyProfiler.profileTimedRequest(timedObject, "remote call"); return response; } catch(IOException ex) { throw new ServletException(ex); } } public void prepareResponse(HttpRequestBase method, HttpServletRequest request, HttpServletResponse response, HttpResponse clientResponse, boolean isCopy) throws ServletException { Object timedObject = ProxyProfiler.getTimedObject(); try { int statusCode = clientResponse.getStatusLine().getStatusCode(); if(statusCode == 401 || statusCode == 403){ clientResponse.setHeader("WWW-Authenticate", ""); } response.setStatus(statusCode); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().setStatus(statusCode); } // Passed back all heads, but process cookies differently. Header[] headers = clientResponse.getAllHeaders(); for (Header header : headers) { String headername = header.getName(); if (headername.equalsIgnoreCase("Set-Cookie") ) { // $NON-NLS-1$ if(forwardCookies(method, request)) { // If cookie, have to rewrite domain/path for browser. String setcookieval = header.getValue(); if (setcookieval != null) { String thisserver = request.getServerName(); String thisdomain; if (thisserver.indexOf('.') == -1) { thisdomain = ""; } else { thisdomain = thisserver.substring(thisserver.indexOf('.')); } String domain = null; // path info = /protocol/server/path-on-server //Matcher m = cookiePathPattern.matcher(request.getPathInfo()); String thispath = request.getContextPath() + request.getServletPath(); String path = null; String[][] cookparams = getCookieStrings(setcookieval); for (int j = 1; j < cookparams.length; j++) { if ("domain".equalsIgnoreCase(cookparams[j][0])) { // $NON-NLS-1$ domain = cookparams[j][1]; cookparams[j][1] = null; } else if ("path".equalsIgnoreCase(cookparams[j][0])) { // $NON-NLS-1$ path = cookparams[j][1]; cookparams[j][1] = null; } } if (domain == null) { domain = method.getURI().getHost(); } // Set cookie name String encoded = encodeCookieNameAndPath(cookparams[0][0], path, domain); if(encoded!=null) { String newcookiename = PASSTHRUID + encoded; StringBuilder newset = new StringBuilder(newcookiename); newset.append('='); newset.append(cookparams[0][1]); for (int j = 1; j < cookparams.length; j++) { String settingname = cookparams[j][0]; String settingvalue = cookparams[j][1]; if (settingvalue != null) { newset.append("; ").append(settingname); // $NON-NLS-1$ newset.append('=').append(settingvalue); // $NON-NLS-1$ } } newset.append("; domain=").append(thisdomain); // $NON-NLS-1$ newset.append("; path=").append(thispath); // $NON-NLS-1$ String newsetcookieval = newset.toString(); // this implementation of HttpServletRequest seems to have issues... setHeader works as I would // expect addHeader to. response.setHeader(headername, newsetcookieval); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().addCookie(headername, newsetcookieval); } } } } } else if (!headername.equalsIgnoreCase("Transfer-Encoding")) { // $NON-NLS-1$ String headerval = header.getValue(); if (headername.equalsIgnoreCase("content-type")) { int loc = headerval.indexOf(';'); String type; if (loc > 0) { type = headerval.substring(0, loc).trim(); } else { type = headerval; } if (!isMimeTypeAllowed(type)) { isCopy = false; break; } else { response.setHeader(headername, headerval); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().addHeader(headername, headerval); } } } else if ( (statusCode == 401 || statusCode == 403) && headername.equalsIgnoreCase("WWW-Authenticate")) { // $NON-NLS-1$ if (headerval.indexOf("Basic") != -1) { // $NON-NLS-1$ String pathInfo = request.getPathInfo(); String[] pathParts = (pathInfo.startsWith("/") ? pathInfo.substring(1) : pathInfo).split("/"); if (pathParts.length > 1) { StringBuilder strb = new StringBuilder("Basic realm=\""); // $NON-NLS-1$ strb.append(request.getContextPath()); strb.append(request.getServletPath()); strb.append('/'); strb.append(pathParts[0]); strb.append('/'); strb.append(pathParts[1]); strb.append('"'); headerval = strb.toString(); response.setHeader(headername, headerval); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().addHeader(headername, headerval); } } } } else { response.setHeader(headername, headerval); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().addHeader(headername, headerval); } } } } // Need to move response body over too if(statusCode == HttpServletResponse.SC_NO_CONTENT || statusCode == HttpServletResponse.SC_NOT_MODIFIED) { response.setHeader("Content-Length", "0"); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().addHeader("Content-Length", "0"); } } else if(isCopy) { HttpEntity entity = clientResponse.getEntity(); InputStream inStream = entity.getContent(); if (inStream != null) { OutputStream os = response.getOutputStream(); if(TRACE) { OutputStream tos = new TraceOutputStream(os, System.out, false); os = tos; } StreamUtil.copyStream(inStream, os); os.flush(); } else { response.setHeader("Content-Length", "0"); if(getDebugHook()!=null) { getDebugHook().getDumpResponse().addHeader("Content-Length", "0"); } } } } catch(IOException ex) { throw new ServletException(ex); } ProxyProfiler.profileTimedRequest(timedObject, "prepareResponse"); } protected void writeErrorResponse(String errorMessage, String[] parameters, String[] values, HttpServletResponse response, HttpServletRequest request) throws ServletException { writeErrorResponse(404, errorMessage, parameters, values, response, request); } public static void writeErrorResponse(int httpstatus, String errorMessage, String[] parameters, String[]values, HttpServletResponse response, HttpServletRequest request) throws ServletException { JsonJavaObject o = new JsonJavaObject(); o.putString("Message", errorMessage); List<JsonJavaObject> params = new ArrayList<JsonJavaObject>(); if (parameters != null && parameters.length > 0) { for (int i = 0; i < parameters.length; i++) { JsonJavaObject e = new JsonJavaObject(); e.putString(parameters[i],values[i]); params.add(e); } } o.putObject("Parameters", params); try { response.setStatus(httpstatus); //response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.addHeader("content-type", "application/json"); // $NON-NLS-1$ $NON-NLS-2$ response.addHeader("Server", "SBT"); // $NON-NLS-1$ $NON-NLS-2$ response.addHeader("Connection", "close"); // $NON-NLS-1$ $NON-NLS-2$ response.addDateHeader("Date", System.currentTimeMillis()); // $NON-NLS-1$ response.getOutputStream().print(JsonGenerator.toJson(JsonJavaFactory.instanceEx, o)); }catch (Exception e) {} } private String[][] getCookieStrings(String set_cookie) { String[] pairs = set_cookie.split(";"); String[][] ret = new String[pairs.length][]; for (int i = 0; i < pairs.length; i++) { String p = pairs[i]; ret[i] = new String[2]; int eqloc = p.indexOf('='); if (eqloc < 0) { ret[i][0] = p; ret[i][1] = null; } else { ret[i][0] = p.substring(0, eqloc).trim(); ret[i][1] = p.substring(eqloc + 1).trim(); } } return ret; } protected URI getRequestURI(HttpServletRequest request) throws ServletException { try { Object timedObject = ProxyProfiler.getTimedObject(); String orgUrl = getRequestURIPath(request); String queryargs = getRequestURLQueryString(request); if(StringUtil.isNotEmpty(queryargs)) { orgUrl += '?' + queryargs; } URI url = new URI(orgUrl); ProxyProfiler.profileTimedRequest(timedObject, "get request uri"); return url; } catch (URISyntaxException ex) { throw new ServletException(ex); } } protected String getRequestURIPath(HttpServletRequest request) throws ServletException { String pathinfo = request.getPathInfo(); int pos = pathinfo.indexOf("/http/"); // $NON-NLS-1$ if (pos == -1) { pos = pathinfo.indexOf("/https/"); // $NON-NLS-1$ } if (pos > 0) { pathinfo = pathinfo.substring(pos); } String orgUrl = pathinfo.substring(1).replaceFirst("\\/", "://"); return orgUrl; } protected String getRequestURLQueryString(HttpServletRequest request) throws ServletException { String queryargs = request.getQueryString(); return queryargs; } private static String encodeBase64(byte[] b) { try { StringWriter sw = new StringWriter(); Base64.OutputStream b64 = new Base64.OutputStream(new WriterOutputStream(sw)); int len = b.length; for( int i=0; i<len; i++) { int c = b[i]; b64.write(c); } b64.flushBuffer(); return sw.toString(); } catch(IOException ex) { ex.printStackTrace(); return null; } } private static byte[] decodeBase64(String s) { try { Base64.InputStream b64 = new Base64.InputStream(new ReaderInputStream(new StringReader(s))); ByteBuffer bb = ByteBuffer.allocate(1024*4); // max cookie size int byt; while( (byt = b64.read()) >= 0) { bb.put((byte) (byt&0xFF)); } return bb.array(); } catch(IOException ex) { ex.printStackTrace(); return null; } } protected static String encodeCookieNameAndPath(String name, String path, String domain) throws ServletException { try { String s = new StringBuilder(name) .append(';') .append(path) .append(';') .append(domain) .toString(); String encoded = URLEncoder.encode(s, "UTF-8"); return encoded; } catch (UnsupportedEncodingException e) { return null; } } protected static String[] decodeCookieNameAndPath(String encoded) throws ServletException { try { String s = URLDecoder.decode(encoded, "UTF-8"); return StringUtil.splitString(s, ';'); } catch (UnsupportedEncodingException e) { return null; } } // protected static String encodeCookieNameAndPath(String name, String path, String domain) throws ServletException { // final ByteBuffer bb = ByteBuffer.allocate(1024*4); // max cookie size // final byte[] buffer = new byte[512]; // final Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true); // String ret = null; // try { // // Join name and path strings with ';' and get the UTF-8 bytes. // byte[] in = new StringBuilder(name) // .append(';') // .append(path) // .append(';') // .append(domain) // .toString().getBytes("UTF-8"); // deflater.setInput(in); // deflater.finish(); // int written = 0; // // // Deflate the byte array into out // while ( (written = deflater.deflate(buffer)) == buffer.length ) { // bb.put(buffer, bb.position(), written); // } // bb.put(buffer, bb.position(), written); // byte[] out = new byte[bb.position()]; // System.arraycopy(bb.array(), 0, out, 0, out.length); // // // Base64Encode the out byte array and replace unsafe characters. // // Replace padding '=' with a single number of how many padding chars there were. // ret = encodeBase64(out).replaceAll("\\s", "").replaceAll("[/]", "_").replaceAll("[+]", "-"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ // int i = ret.indexOf('='); // if (i < 0) // i = ret.length(); // int len = ret.length() - i; // ret = ret.substring(0, i); // ret = ret + len; // } catch (Throwable t) {} // return ret; // } // protected static String[] decodeCookieNameAndPath(String encoded) throws ServletException { // final Inflater inflater = new Inflater(true); // final ByteBuffer bb = ByteBuffer.allocate(1024*4); // max cookie size // final byte[] buffer = new byte[512]; // // String[] ret = null; // try { // // Replace the safe characters with the proper Base64 alphabet characters. // encoded = encoded.replaceAll("[_]", "/").replaceAll("[-]", "_"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ // // // Replace the padding digit with the correct number of padding characters. // int len = 0; // try { // len = Integer.parseInt(encoded.substring(encoded.length() - 1)); // encoded = encoded.substring(0, encoded.length() - 1); // } catch (Exception e) { // } // final String padding = "==="; // $NON-NLS-1$ // encoded = encoded + padding.substring(0, len); // // // Base64Decode the string into a byte array 'in'. // byte[] in = decodeBase64(encoded); // inflater.setInput(in); // // // Inflate 'in' into the byte buffer. // int written = 0; // while ( (written = inflater.inflate(buffer)) == buffer.length ) { // bb.put(buffer, bb.position(), written); // } // bb.put(buffer, bb.position(), written); // // // Make a new string from the inflated bytebuffer, using UTF-8 charset // String namepath = new String(bb.array(), 0, bb.position(), "UTF-8"); // // // split the name/path pair into the return array value. // ret = namepath.split(";"); // } catch (Throwable t) {} // return ret; // } }