1 19 20 package com.sslexplorer.replacementproxy; 21 22 import java.io.InputStream ; 23 import java.net.MalformedURLException ; 24 import java.net.URL ; 25 import java.net.URLDecoder ; 26 import java.text.SimpleDateFormat ; 27 import java.util.ArrayList ; 28 import java.util.Date ; 29 import java.util.Enumeration ; 30 import java.util.List ; 31 import java.util.StringTokenizer ; 32 import java.util.zip.GZIPInputStream ; 33 34 import org.apache.commons.logging.Log; 35 import org.apache.commons.logging.LogFactory; 36 37 import com.maverick.http.HttpResponse; 38 import com.sslexplorer.boot.CaseInsensitiveMap; 39 import com.sslexplorer.boot.HttpConstants; 40 import com.sslexplorer.boot.Util; 41 import com.sslexplorer.core.CookieItem; 42 import com.sslexplorer.core.CookieMap; 43 import com.sslexplorer.policyframework.LaunchSession; 44 45 48 public class ProxiedResponseProcessor { 49 final static Log log = LogFactory.getLog(ProxiedResponseProcessor.class); 50 51 private ProxiedRequestDispatcher requestDispatcher; 52 private int maxAge; 53 private ContentCache cache; 54 private SimpleDateFormat sdf; 55 private RequestProcessor requestProcessor; 56 private Date expiryDate; 58 private CookieMap cookieMap; 59 private String contentType; 60 private int contentLength; 61 private List headers; 62 private boolean cacheable; 63 private InputStream serverIn; 64 private String charset; 65 static CaseInsensitiveMap ignoreHeaders = new CaseInsensitiveMap(); 66 67 static { 68 ignoreHeaders.put(HttpConstants.HDR_PROXY_CONNECTION, Boolean.TRUE); 69 ignoreHeaders.put(HttpConstants.HDR_ACCEPT_ENCODING, Boolean.TRUE); 70 ignoreHeaders.put(HttpConstants.HDR_TRANSFER_ENCODING, Boolean.TRUE); 71 ignoreHeaders.put(HttpConstants.HDR_TE, Boolean.TRUE); 72 ignoreHeaders.put(HttpConstants.HDR_TRAILER, Boolean.TRUE); 73 ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHORIZATION, Boolean.TRUE); 74 ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHENTICATE, Boolean.TRUE); 75 ignoreHeaders.put(HttpConstants.HDR_UPGRADE, Boolean.TRUE); 76 ignoreHeaders.put(HttpConstants.HDR_CONTENT_ENCODING, Boolean.TRUE); 77 } 78 79 82 public ProxiedResponseProcessor(RequestProcessor requestProcessor, ProxiedRequestDispatcher requestDispatcher, int maxAge, 83 ContentCache cache, CookieMap cookieMap) { 84 this.requestDispatcher = requestDispatcher; 85 this.requestProcessor = requestProcessor; 86 this.maxAge = maxAge; 87 this.cache = cache; 88 this.cookieMap = cookieMap; 89 sdf = new SimpleDateFormat ("EEEE, dd-MMM-yy HH:mm:ss zzz"); 91 } 92 93 public ProxiedRequestDispatcher getRequestDispatcher() { 94 return requestDispatcher; 95 } 96 97 public void processResponse() throws Exception { 98 99 HttpResponse serverResponse = requestDispatcher.getServerResponse(); 100 headers = new ArrayList (); 101 102 expiryDate = maxAge == 0 ? null : new Date (System.currentTimeMillis() + maxAge); 104 cacheable = false; 105 if (cache != null && HttpConstants.METHOD_GET.equals(requestProcessor.getRequestMethod()) 106 && requestDispatcher.getResponseCode() == HttpConstants.RESP_200_OK) { 107 cacheable = true; 108 109 String cacheControl = serverResponse.getHeaderField(HttpConstants.HDR_PRAGMA); 111 if (cacheControl != null && cacheControl.equalsIgnoreCase("no-cache")) { 112 if (log.isDebugEnabled()) 113 log.debug("Not caching as server explicitly requested not to."); 114 cacheable = false; 115 } else { 116 String expires = serverResponse.getHeaderField(HttpConstants.HDR_EXPIRES); 117 if (expires != null) { 118 try { 119 expiryDate = sdf.parse(expires); 120 } catch (Exception e2) { 121 } 122 } 123 } 124 125 if (cacheable) { 127 cacheControl = serverResponse.getHeaderField(HttpConstants.HDR_CACHE_CONTROL); 128 if (cacheControl != null) { 129 StringTokenizer tok = new StringTokenizer (cacheControl, ";"); 130 while (tok.hasMoreTokens()) { 131 String t = tok.nextToken().trim(); 132 String tl = t.toLowerCase(); 133 if (t.startsWith("no-cache") || t.startsWith("no-store")) { 134 cacheable = false; 135 if (log.isDebugEnabled()) 136 log.debug("Not caching as server explicitly requested not to."); 137 } else if (tl.startsWith("max-age")) { 138 try { 139 expiryDate.setTime(expiryDate.getTime() - (Integer.parseInt(Util.valueOfNameValuePair(tl)))); 140 } catch (Exception e2) { 141 } 142 } 143 } 144 } 145 } 146 } 147 148 String contentEncoding = serverResponse.getHeaderField(HttpConstants.HDR_CONTENT_ENCODING); 149 serverIn = serverResponse.getInputStream(); 150 151 if ("gzip".equals(contentEncoding)) { 152 serverIn = new GZIPInputStream (serverIn); 153 } else if ("identity".equals(contentEncoding) || contentEncoding == null) { 154 } else { 156 throw new Exception ("Invalid content encoding " + serverResponse.getHeaderField(HttpConstants.HDR_CONTENT_ENCODING)); 157 } 158 159 String [] challenges = serverResponse.getHeaderFields("www-authenticate"); 160 161 if (challenges != null) { 162 serverResponse.removeFields("www-authenticate"); 163 164 for (int i = 0; i < challenges.length; i++) { 165 if (challenges[i].toLowerCase().startsWith("basic") || challenges[i].toLowerCase().startsWith("digest") 166 || challenges[i].toLowerCase().startsWith("ntlm")) { 167 if(i==0) 168 serverResponse.setHeaderField("WWW-Authenticate", challenges[i]); 169 else 170 serverResponse.addHeaderField("WWW-Authenticate", challenges[i]); 171 } 172 } 173 } 174 175 178 serverResponse.removeFields("Server"); 179 serverResponse.removeFields("Date"); 180 181 for (Enumeration e = serverResponse.getHeaderFieldNames(); e.hasMoreElements();) { 182 String hdr = (String ) e.nextElement(); 183 if (log.isDebugEnabled()) 184 log.debug("Received header " + hdr); 185 String [] val = serverResponse.getHeaderFields(hdr); 186 187 for (int i = 0; i < val.length; i++) { 188 189 if (hdr.equalsIgnoreCase("Content-Type")) { 190 191 StringTokenizer tok = new StringTokenizer (val[i], ";"); 192 while (tok.hasMoreTokens()) { 193 String t = tok.nextToken().trim(); 194 String tl = t.toLowerCase(); 195 if (tl.startsWith("charset=")) { 196 charset = Util.valueOfNameValuePair(t); 197 } else { 198 contentType = Util.valueOfNameValuePair(t); 199 } 200 } 201 202 contentType = val[i]; 203 if (log.isDebugEnabled()) 204 log.debug("Received content type " + contentType + " (charset = " + charset + ")"); 205 } else if (hdr.equalsIgnoreCase("Content-Length")) { 206 try { 207 contentLength = Integer.parseInt(val[i]); 208 } catch (Exception ex) { 209 210 } 211 if (log.isDebugEnabled()) 212 log.debug("Received content length " + contentLength); 213 } else { 214 if (hdr.equalsIgnoreCase("Location")) { 215 216 if(log.isDebugEnabled()) 217 log.debug("Processing Location header value '" + val[i] + "'"); 218 219 URL actual; 220 try { 221 actual = new URL (Util.urlDecode(val[i])); 222 } catch(MalformedURLException ex) { 223 actual = new URL (requestProcessor.getRequestParameters().getProxiedURLBase(), Util.urlDecode(val[i])); 224 } 225 226 cache.clear(actual.toExternalForm()); 227 URL newVal = new URL (requestProcessor.getRequestBaseURL(), "/replacementProxyEngine?" + LaunchSession.LONG_LAUNCH_ID 228 + "=" 229 + requestProcessor.getLaunchId() 230 + "&sslex_url=" 231 + Util.urlEncode(actual.toExternalForm())); 232 if (log.isDebugEnabled()) 233 log.debug("Found location of header " + val[i] 234 + " changing to " 235 + newVal 236 + " ( removed " 237 + actual.toExternalForm() 238 + " from cache"); 239 val[i] = newVal.toExternalForm(); 240 } else if (hdr.equalsIgnoreCase("Set-Cookie")) { 241 val[i] = parseCookie(val[i]); 242 } 243 if (log.isDebugEnabled()) 244 log.debug("Adding header " + hdr + " = " + val[i]); 245 headers.add(new Header(hdr, val[i])); 246 } 247 248 } 249 } 250 251 } 252 253 public List getHeaders() { 254 return headers; 255 } 256 257 260 public String getContentType() { 261 return contentType; 262 } 263 264 public String getCharset() { 265 return charset; 266 } 267 268 public int getContentLength() { 269 return contentLength; 270 } 271 272 275 public boolean isCacheable() { 276 return cacheable; 277 } 278 279 public InputStream getProxiedInputStream() { 280 return serverIn; 281 } 282 283 286 public Date getCacheExpiryDate() { 287 return expiryDate; 288 } 289 290 String parseCookie(String val) { 291 StringBuffer newVal = new StringBuffer (); 292 StringTokenizer t = new StringTokenizer (val, ";"); 293 String elementName = null; 294 String elementValue = null; 295 296 try { 297 while (t.hasMoreTokens()) { 298 299 String name = Util.trimBoth(t.nextToken()); 300 int idx = name.indexOf('='); 301 if (idx > -1) { 302 elementValue = name.substring(idx + 1); 303 elementName = name.substring(0, idx); 304 } else { 305 elementName = name; 306 elementValue = ""; 307 } 308 309 310 311 if (elementName.equalsIgnoreCase("path") || elementName.equalsIgnoreCase("domain")) { 312 } else if (elementName.equalsIgnoreCase("expires") || 314 elementName.equalsIgnoreCase("max-age") || 315 elementName.equalsIgnoreCase("secure") || 316 elementName.equalsIgnoreCase("version") || 317 elementName.equalsIgnoreCase("comment") ) { 318 if(newVal.length() > 0) { 320 newVal.append("; "); 321 } 322 newVal.append(elementName); 323 if(!elementValue.equals("")) { 324 newVal.append("="); 325 newVal.append(elementValue); 326 } 327 } else { 328 String fakeCookieName = Math.abs((requestProcessor.getRequestParameters().getProxiedURL().getProtocol() 330 + ":" 331 + requestProcessor.getRequestParameters().getProxiedURL().getHost()).hashCode()) + "_" + elementName; 332 CookieItem cookieItem = new CookieItem(elementName, fakeCookieName); 333 cookieMap.put(cookieItem); 334 if(newVal.length() > 0) { 335 newVal.append("; "); 336 } 337 newVal.append(fakeCookieName); 338 if(!elementValue.equals("")) { 339 newVal.append("="); 340 newVal.append(Util.urlEncode(elementValue)); 341 } 342 } 343 } 344 } catch (Exception ex) { 345 log.warn("Invalid cookie.", ex); 346 } 347 return newVal.toString(); 348 } 349 350 351 352 } 353 | Popular Tags |